minetest.scm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
  3. ;;;
  4. ;;; This file is part of GNU Guix.
  5. ;;;
  6. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  7. ;;; under the terms of the GNU General Public License as published by
  8. ;;; the Free Software Foundation; either version 3 of the License, or (at
  9. ;;; your option) any later version.
  10. ;;;
  11. ;;; GNU Guix is distributed in the hope that it will be useful, but
  12. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;;; GNU General Public License for more details.
  15. ;;;
  16. ;;; You should have received a copy of the GNU General Public License
  17. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  18. (define-module (test-minetest)
  19. #:use-module (guix memoization)
  20. #:use-module (guix import minetest)
  21. #:use-module (guix import utils)
  22. #:use-module (guix tests)
  23. #:use-module (json)
  24. #:use-module (ice-9 match)
  25. #:use-module (srfi srfi-1)
  26. #:use-module (srfi srfi-26)
  27. #:use-module (srfi srfi-34)
  28. #:use-module (srfi srfi-64))
  29. ;; Some procedures for populating a ‘fake’ ContentDB server.
  30. (define* (make-package-sexp #:key
  31. (guix-name "minetest-foo")
  32. (home-page "https://example.org/foo")
  33. (repo "https://example.org/foo.git")
  34. (synopsis "synopsis")
  35. (guix-description "description")
  36. (guix-license
  37. '(list license:cc-by-sa4.0 license:lgpl3+))
  38. (inputs '())
  39. (upstream-name "Author/foo")
  40. #:allow-other-keys)
  41. `(package
  42. (name ,guix-name)
  43. ;; This is not a proper version number but ContentDB does not include
  44. ;; version numbers.
  45. (version "2021-07-25")
  46. (source
  47. (origin
  48. (method git-fetch)
  49. (uri (git-reference
  50. (url ,(and (not (eq? repo 'null)) repo))
  51. (commit #f)))
  52. (sha256
  53. (base32 #f))
  54. (file-name (git-file-name name version))))
  55. (build-system minetest-mod-build-system)
  56. ,@(maybe-propagated-inputs inputs)
  57. (home-page ,home-page)
  58. (synopsis ,synopsis)
  59. (description ,guix-description)
  60. (license ,guix-license)
  61. (properties
  62. ,(list 'quasiquote
  63. `((upstream-name . ,upstream-name))))))
  64. (define* (make-package-json #:key
  65. (author "Author")
  66. (name "foo")
  67. (media-license "CC-BY-SA-4.0")
  68. (license "LGPL-3.0-or-later")
  69. (short-description "synopsis")
  70. (long-description "description")
  71. (repo "https://example.org/foo.git")
  72. (website "https://example.org/foo")
  73. (forums 321)
  74. (score 987.654)
  75. (downloads 123)
  76. (type "mod")
  77. #:allow-other-keys)
  78. `(("author" . ,author)
  79. ("content_warnings" . #())
  80. ("created_at" . "2018-05-23T19:58:07.422108")
  81. ("downloads" . ,downloads)
  82. ("forums" . ,forums)
  83. ("issue_tracker" . "https://example.org/foo/issues")
  84. ("license" . ,license)
  85. ("long_description" . ,long-description)
  86. ("maintainers" . #("maintainer"))
  87. ("media_license" . ,media-license)
  88. ("name" . ,name)
  89. ("provides" . #("stuff"))
  90. ("release" . 456)
  91. ("repo" . ,repo)
  92. ("score" . ,score)
  93. ("screenshots" . #())
  94. ("short_description" . ,short-description)
  95. ("state" . "APPROVED")
  96. ("tags" . #("some" "tags"))
  97. ("thumbnail" . null)
  98. ("title" . "The name")
  99. ("type" . ,type)
  100. ("url" . ,(string-append "https://content.minetest.net/packages/"
  101. author "/" name "/download/"))
  102. ("website" . ,website)))
  103. (define* (make-releases-json #:key (commit #f) (title "") #:allow-other-keys)
  104. `#((("commit" . ,commit)
  105. ("downloads" . 469)
  106. ("id" . 8614)
  107. ("max_minetest_version" . null)
  108. ("min_minetest_version" . null)
  109. ("release_date" . "2021-07-25T01:10:23.207584")
  110. ("title" . "2021-07-25"))))
  111. (define* (make-dependencies-json #:key (author "Author")
  112. (name "foo")
  113. (requirements '(("default" #f ())))
  114. #:allow-other-keys)
  115. `((,(string-append author "/" name)
  116. . ,(list->vector
  117. (map (match-lambda
  118. ((symbolic-name optional? implementations)
  119. `(("is_optional" . ,optional?)
  120. ("name" . ,symbolic-name)
  121. ("packages" . ,(list->vector implementations)))))
  122. requirements)))
  123. ("something/else" . #())))
  124. (define* (make-packages-keys-json #:key (author "Author")
  125. (name "Name")
  126. (type "mod"))
  127. `(("author" . ,author)
  128. ("name" . ,name)
  129. ("type" . ,type)))
  130. (define (call-with-packages thunk . argument-lists)
  131. ;; Don't reuse results from previous tests.
  132. (invalidate-memoization! contentdb-fetch)
  133. (invalidate-memoization! minetest->guix-package)
  134. (define (scm->json-port scm)
  135. (open-input-string (scm->json-string scm)))
  136. (define (handle-package url requested-author requested-name . rest)
  137. (define relevant-argument-list
  138. (any (lambda (argument-list)
  139. (apply (lambda* (#:key (author "Author") (name "foo")
  140. #:allow-other-keys)
  141. (and (equal? requested-author author)
  142. (equal? requested-name name)
  143. argument-list))
  144. argument-list))
  145. argument-lists))
  146. (when (not relevant-argument-list)
  147. (error "the package ~a/~a should be irrelevant, but ~a is fetched"
  148. requested-author requested-name url))
  149. (scm->json-port
  150. (apply (match rest
  151. (("") make-package-json)
  152. (("dependencies" "") make-dependencies-json)
  153. (("releases" "") make-releases-json)
  154. (_ (error "TODO ~a" rest)))
  155. relevant-argument-list)))
  156. (define (handle-mod-search sort)
  157. ;; Produce search results, sorted by SORT in descending order.
  158. (define arguments->key
  159. (match sort
  160. ("score" (lambda* (#:key (score 987.654) #:allow-other-keys)
  161. score))
  162. ("downloads" (lambda* (#:key (downloads 123) #:allow-other-keys)
  163. downloads))))
  164. (define argument-list->key (cut apply arguments->key <>))
  165. (define (greater x y)
  166. (> (argument-list->key x) (argument-list->key y)))
  167. (define sorted-argument-lists (sort-list argument-lists greater))
  168. (define* (arguments->json #:key (author "Author") (name "Foo") (type "mod")
  169. #:allow-other-keys)
  170. (and (string=? type "mod")
  171. `(("author" . ,author)
  172. ("name" . ,name)
  173. ("type" . ,type))))
  174. (define argument-list->json (cut apply arguments->json <>))
  175. (scm->json-port
  176. (list->vector (filter-map argument-list->json sorted-argument-lists))))
  177. (mock ((guix http-client) http-fetch
  178. (lambda* (url #:key headers)
  179. (unless (string-prefix? "mock://api/packages/" url)
  180. (error "the URL ~a should not be used" url))
  181. (define resource
  182. (substring url (string-length "mock://api/packages/")))
  183. (define components (string-split resource #\/))
  184. (match components
  185. ((author name . rest)
  186. (apply handle-package url author name rest))
  187. (((? (cut string-prefix? "?type=mod&q=" <>) query))
  188. (handle-mod-search
  189. (cond ((string-contains query "sort=score") "score")
  190. ((string-contains query "sort=downloads") "downloads")
  191. (#t (error "search query ~a has unknown sort key"
  192. query)))))
  193. (_
  194. (error "the URL ~a should have an author and name component"
  195. url)))))
  196. (parameterize ((%contentdb-api "mock://api/"))
  197. (thunk))))
  198. (define* (minetest->guix-package* #:key (author "Author") (name "foo")
  199. (sort %default-sort-key)
  200. #:allow-other-keys)
  201. (minetest->guix-package (string-append author "/" name) #:sort sort))
  202. (define (imported-package-sexp* primary-arguments . secondary-arguments)
  203. "Ask the importer to import a package specified by PRIMARY-ARGUMENTS,
  204. during a dynamic where that package and the packages specified by
  205. SECONDARY-ARGUMENTS are available on ContentDB."
  206. (apply call-with-packages
  207. (lambda ()
  208. ;; The memoization cache is reset by call-with-packages
  209. (apply minetest->guix-package* primary-arguments))
  210. primary-arguments
  211. secondary-arguments))
  212. (define (imported-package-sexp . extra-arguments)
  213. "Ask the importer to import a package specified by EXTRA-ARGUMENTS,
  214. during a dynamic extent where that package is available on ContentDB."
  215. (imported-package-sexp* extra-arguments))
  216. (define-syntax-rule (test-package test-case . extra-arguments)
  217. (test-equal test-case
  218. (make-package-sexp . extra-arguments)
  219. (imported-package-sexp . extra-arguments)))
  220. (define-syntax-rule (test-package* test-case primary-arguments extra-arguments
  221. ...)
  222. (test-equal test-case
  223. (apply make-package-sexp primary-arguments)
  224. (imported-package-sexp* primary-arguments extra-arguments ...)))
  225. (test-begin "minetest")
  226. ;; Package names
  227. (test-package "minetest->guix-package")
  228. (test-package "minetest->guix-package, _ → - in package name"
  229. #:name "foo_bar"
  230. #:guix-name "minetest-foo-bar"
  231. #:upstream-name "Author/foo_bar")
  232. (test-equal "elaborate names, unambigious"
  233. "Jeija/mesecons"
  234. (call-with-packages
  235. (cut elaborate-contentdb-name "mesecons")
  236. '(#:name "mesecons" #:author "Jeija")
  237. '(#:name "something" #:author "else")))
  238. (test-equal "elaborate name, ambigious (highest score)"
  239. "Jeija/mesecons"
  240. (call-with-packages
  241. ;; #:sort "score" is the default
  242. (cut elaborate-contentdb-name "mesecons")
  243. '(#:name "mesecons" #:author "Jeijc" #:score 777)
  244. '(#:name "mesecons" #:author "Jeijb" #:score 888)
  245. '(#:name "mesecons" #:author "Jeija" #:score 999)))
  246. (test-equal "elaborate name, ambigious (most downloads)"
  247. "Jeija/mesecons"
  248. (call-with-packages
  249. (cut elaborate-contentdb-name "mesecons" #:sort "downloads")
  250. '(#:name "mesecons" #:author "Jeijc" #:downloads 777)
  251. '(#:name "mesecons" #:author "Jeijb" #:downloads 888)
  252. '(#:name "mesecons" #:author "Jeija" #:downloads 999)))
  253. ;; Determining the home page
  254. (test-package "minetest->guix-package, website is used as home page"
  255. #:home-page "web://site"
  256. #:website "web://site")
  257. (test-package "minetest->guix-package, if absent, the forum is used"
  258. #:home-page '(minetest-topic 628)
  259. #:forums 628
  260. #:website 'null)
  261. (test-package "minetest->guix-package, if absent, the git repo is used"
  262. #:home-page "https://github.com/minetest-mods/mesecons"
  263. #:forums 'null
  264. #:website 'null
  265. #:repo "https://github.com/minetest-mods/mesecons")
  266. (test-package "minetest->guix-package, all home page information absent"
  267. #:home-page #f
  268. #:forums 'null
  269. #:website 'null
  270. #:repo 'null)
  271. ;; Dependencies
  272. (test-package* "minetest->guix-package, unambigious dependency"
  273. (list #:requirements '(("mesecons" #f
  274. ("Jeija/mesecons"
  275. "some-modpack/containing-mese")))
  276. #:inputs '("minetest-mesecons"))
  277. (list #:author "Jeija" #:name "mesecons")
  278. (list #:author "some-modpack" #:name "containing-mese" #:type "modpack"))
  279. (test-package* "minetest->guix-package, ambigious dependency (highest score)"
  280. (list #:name "frobnicate"
  281. #:guix-name "minetest-frobnicate"
  282. #:upstream-name "Author/frobnicate"
  283. #:requirements '(("frob" #f
  284. ("Author/foo" "Author/bar")))
  285. ;; #:sort "score" is the default
  286. #:inputs '("minetest-bar"))
  287. (list #:author "Author" #:name "foo" #:score 0)
  288. (list #:author "Author" #:name "bar" #:score 9999))
  289. (test-package* "minetest->guix-package, ambigious dependency (most downloads)"
  290. (list #:name "frobnicate"
  291. #:guix-name "minetest-frobnicate"
  292. #:upstream-name "Author/frobnicate"
  293. #:requirements '(("frob" #f
  294. ("Author/foo" "Author/bar")))
  295. #:inputs '("minetest-bar")
  296. #:sort "downloads")
  297. (list #:author "Author" #:name "foo" #:downloads 0)
  298. (list #:author "Author" #:name "bar" #:downloads 9999))
  299. (test-package "minetest->guix-package, optional dependency"
  300. #:requirements '(("mesecons" #t
  301. ("Jeija/mesecons"
  302. "some-modpack/containing-mese")))
  303. #:inputs '())
  304. ;; License
  305. (test-package "minetest->guix-package, identical licenses"
  306. #:guix-license 'license:lgpl3+
  307. #:license "LGPL-3.0-or-later"
  308. #:media-license "LGPL-3.0-or-later")
  309. ;; Sorting
  310. (let* ((make-package
  311. (lambda arguments
  312. (json->package (apply make-package-json arguments))))
  313. (x (make-package #:score 0))
  314. (y (make-package #:score 1))
  315. (z (make-package #:score 2)))
  316. (test-equal "sort-packages, already sorted"
  317. (list z y x)
  318. (sort-packages (list z y x)))
  319. (test-equal "sort-packages, reverse"
  320. (list z y x)
  321. (sort-packages (list x y z))))
  322. (test-end "minetest")