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