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