minetest.scm 15 KB

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