1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2012, 2013 Cyril Roelandt <tipecaml@gmail.com>
3 ;;; Copyright © 2014, 2015, 2016 Eric Bavier <bavier@member.fsf.org>
4 ;;; Copyright © 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
5 ;;; Copyright © 2015, 2016 Mathieu Lirzin <mthl@gnu.org>
6 ;;; Copyright © 2016 Hartmut Goebel <h.goebel@crazy-compilers.com>
7 ;;; Copyright © 2017 Alex Kost <alezost@gmail.com>
9 ;;; This file is part of GNU Guix.
11 ;;; GNU Guix is free software; you can redistribute it and/or modify it
12 ;;; under the terms of the GNU General Public License as published by
13 ;;; the Free Software Foundation; either version 3 of the License, or (at
14 ;;; your option) any later version.
16 ;;; GNU Guix is distributed in the hope that it will be useful, but
17 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;;; GNU General Public License for more details.
21 ;;; You should have received a copy of the GNU General Public License
22 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
24 ;; Avoid interference.
25 (unsetenv "http_proxy")
27 (define-module (test-lint)
28 #:use-module (guix tests)
29 #:use-module (guix tests http)
30 #:use-module (guix download)
31 #:use-module (guix git-download)
32 #:use-module (guix build-system gnu)
33 #:use-module (guix packages)
34 #:use-module (guix scripts lint)
35 #:use-module (guix ui)
36 #:use-module (gnu packages)
37 #:use-module (gnu packages glib)
38 #:use-module (gnu packages pkg-config)
39 #:use-module (gnu packages python)
40 #:use-module (web server)
41 #:use-module (web server http)
42 #:use-module (web response)
43 #:use-module (ice-9 match)
44 #:use-module (srfi srfi-9 gnu)
45 #:use-module (srfi srfi-64))
49 ;; Avoid collisions with other tests.
50 (%http-server-port 9999)
53 ;; SHA256 of the empty string.
55 "0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73"))
58 (make-string 2000 #\a))
63 (define (call-with-warnings thunk)
64 (let ((port (open-output-string)))
65 (parameterize ((guix-warning-port port))
67 (get-output-string port)))
69 (define-syntax-rule (with-warnings body ...)
70 (call-with-warnings (lambda () body ...)))
72 (test-assert "description: not a string"
74 (string-contains (with-warnings
75 (let ((pkg (dummy-package "x"
76 (description 'foobar))))
77 (check-description-style pkg)))
78 "invalid description")))
80 (test-assert "description: not empty"
82 (string-contains (with-warnings
83 (let ((pkg (dummy-package "x"
85 (check-description-style pkg)))
86 "description should not be empty")))
88 (test-assert "description: valid Texinfo markup"
92 (check-description-style (dummy-package "x" (description "f{oo}b@r"))))
93 "Texinfo markup in description is invalid")))
95 (test-assert "description: does not start with an upper-case letter"
97 (string-contains (with-warnings
98 (let ((pkg (dummy-package "x"
99 (description "bad description."))))
100 (check-description-style pkg)))
101 "description should start with an upper-case letter")))
103 (test-assert "description: may start with a digit"
106 (let ((pkg (dummy-package "x"
107 (description "2-component library."))))
108 (check-description-style pkg)))))
110 (test-assert "description: may start with lower-case package name"
113 (let ((pkg (dummy-package "x"
114 (description "x is a dummy package."))))
115 (check-description-style pkg)))))
117 (test-assert "description: two spaces after end of sentence"
119 (string-contains (with-warnings
120 (let ((pkg (dummy-package "x"
121 (description "Bad. Quite bad."))))
122 (check-description-style pkg)))
123 "sentences in description should be followed by two spaces")))
125 (test-assert "description: end-of-sentence detection with abbreviations"
128 (let ((pkg (dummy-package "x"
130 "E.g. Foo, i.e. Bar resp. Baz (a.k.a. DVD)."))))
131 (check-description-style pkg)))))
133 (test-assert "description: may not contain trademark signs"
135 (string-contains (with-warnings
136 (let ((pkg (dummy-package "x"
137 (description "Does The Right Thing™"))))
138 (check-description-style pkg)))
139 "should not contain trademark sign"))
141 (string-contains (with-warnings
142 (let ((pkg (dummy-package "x"
143 (description "Works with Format®"))))
144 (check-description-style pkg)))
145 "should not contain trademark sign"))))
147 (test-assert "description: suggest ornament instead of quotes"
149 (string-contains (with-warnings
150 (let ((pkg (dummy-package "x"
151 (description "This is a 'quoted' thing."))))
152 (check-description-style pkg)))
155 (test-assert "synopsis: not a string"
157 (string-contains (with-warnings
158 (let ((pkg (dummy-package "x"
160 (check-synopsis-style pkg)))
161 "invalid synopsis")))
163 (test-assert "synopsis: not empty"
165 (string-contains (with-warnings
166 (let ((pkg (dummy-package "x"
168 (check-synopsis-style pkg)))
169 "synopsis should not be empty")))
171 (test-assert "synopsis: valid Texinfo markup"
175 (check-synopsis-style (dummy-package "x" (synopsis "Bad $@ texinfo"))))
176 "Texinfo markup in synopsis is invalid")))
178 (test-assert "synopsis: does not start with an upper-case letter"
180 (string-contains (with-warnings
181 (let ((pkg (dummy-package "x"
182 (synopsis "bad synopsis."))))
183 (check-synopsis-style pkg)))
184 "synopsis should start with an upper-case letter")))
186 (test-assert "synopsis: may start with a digit"
189 (let ((pkg (dummy-package "x"
190 (synopsis "5-dimensional frobnicator"))))
191 (check-synopsis-style pkg)))))
193 (test-assert "synopsis: ends with a period"
195 (string-contains (with-warnings
196 (let ((pkg (dummy-package "x"
197 (synopsis "Bad synopsis."))))
198 (check-synopsis-style pkg)))
199 "no period allowed at the end of the synopsis")))
201 (test-assert "synopsis: ends with 'etc.'"
202 (string-null? (with-warnings
203 (let ((pkg (dummy-package "x"
204 (synopsis "Foo, bar, etc."))))
205 (check-synopsis-style pkg)))))
207 (test-assert "synopsis: starts with 'A'"
209 (string-contains (with-warnings
210 (let ((pkg (dummy-package "x"
211 (synopsis "A bad synopŝis"))))
212 (check-synopsis-style pkg)))
213 "no article allowed at the beginning of the synopsis")))
215 (test-assert "synopsis: starts with 'An'"
217 (string-contains (with-warnings
218 (let ((pkg (dummy-package "x"
219 (synopsis "An awful synopsis"))))
220 (check-synopsis-style pkg)))
221 "no article allowed at the beginning of the synopsis")))
223 (test-assert "synopsis: starts with 'a'"
225 (string-contains (with-warnings
226 (let ((pkg (dummy-package "x"
227 (synopsis "a bad synopsis"))))
228 (check-synopsis-style pkg)))
229 "no article allowed at the beginning of the synopsis")))
231 (test-assert "synopsis: starts with 'an'"
233 (string-contains (with-warnings
234 (let ((pkg (dummy-package "x"
235 (synopsis "an awful synopsis"))))
236 (check-synopsis-style pkg)))
237 "no article allowed at the beginning of the synopsis")))
239 (test-assert "synopsis: too long"
241 (string-contains (with-warnings
242 (let ((pkg (dummy-package "x"
243 (synopsis (make-string 80 #\x)))))
244 (check-synopsis-style pkg)))
245 "synopsis should be less than 80 characters long")))
247 (test-assert "synopsis: start with package name"
249 (string-contains (with-warnings
250 (let ((pkg (dummy-package "x"
252 (synopsis "foo, a nice package"))))
253 (check-synopsis-style pkg)))
254 "synopsis should not start with the package name")))
256 (test-assert "synopsis: start with package name prefix"
259 (let ((pkg (dummy-package "arb"
260 (synopsis "Arbitrary precision"))))
261 (check-synopsis-style pkg)))))
263 (test-assert "synopsis: start with abbreviation"
266 (let ((pkg (dummy-package "uucp"
267 ;; Same problem with "APL interpreter", etc.
268 (synopsis "UUCP implementation")
269 (description "Imagine this is Taylor UUCP."))))
270 (check-synopsis-style pkg)))))
272 (test-assert "inputs: pkg-config is probably a native input"
276 (let ((pkg (dummy-package "x"
277 (inputs `(("pkg-config" ,pkg-config))))))
278 (check-inputs-should-be-native pkg)))
279 "'pkg-config' should probably be a native input")))
281 (test-assert "inputs: glib:bin is probably a native input"
285 (let ((pkg (dummy-package "x"
286 (inputs `(("glib" ,glib "bin"))))))
287 (check-inputs-should-be-native pkg)))
288 "'glib:bin' should probably be a native input")))
291 "inputs: python-setuptools should not be an input at all (input)"
295 (let ((pkg (dummy-package "x"
296 (inputs `(("python-setuptools" ,python-setuptools))))))
297 (check-inputs-should-not-be-an-input-at-all pkg)))
298 "'python-setuptools' should probably not be an input at all")))
301 "inputs: python-setuptools should not be an input at all (native-input)"
305 (let ((pkg (dummy-package "x"
307 `(("python-setuptools" ,python-setuptools))))))
308 (check-inputs-should-not-be-an-input-at-all pkg)))
309 "'python-setuptools' should probably not be an input at all")))
312 "inputs: python-setuptools should not be an input at all (propagated-input)"
316 (let ((pkg (dummy-package "x"
318 `(("python-setuptools" ,python-setuptools))))))
319 (check-inputs-should-not-be-an-input-at-all pkg)))
320 "'python-setuptools' should probably not be an input at all")))
322 (test-assert "patches: file names"
326 (let ((pkg (dummy-package "x"
329 (patches (list "/path/to/y.patch")))))))
330 (check-patch-file-names pkg)))
331 "file names of patches should start with the package name")))
333 (test-assert "patches: not found"
337 (let ((pkg (dummy-package "x"
341 (list (search-patch "this-patch-does-not-exist!"))))))))
342 (check-patch-file-names pkg)))
345 (test-assert "derivation: invalid arguments"
349 (let ((pkg (dummy-package "x"
351 '(#:imported-modules (invalid-module))))))
352 (check-derivation pkg)))
353 "failed to create derivation")))
355 (test-assert "license: invalid license"
358 (check-license (dummy-package "x" (license #f))))
361 (test-assert "home-page: wrong home-page"
366 (inherit (dummy-package "x"))
368 (check-home-page pkg)))
371 (test-assert "home-page: invalid URI"
376 (inherit (dummy-package "x"))
377 (home-page "foobar"))))
378 (check-home-page pkg)))
379 "invalid home page URL")))
381 (test-assert "home-page: host not found"
386 (inherit (dummy-package "x"))
387 (home-page "http://does-not-exist"))))
388 (check-home-page pkg)))
389 "domain not found")))
391 (test-skip (if (force %http-server-socket) 0 1))
392 (test-assert "home-page: Connection refused"
397 (inherit (dummy-package "x"))
398 (home-page (%local-url)))))
399 (check-home-page pkg)))
400 "Connection refused")))
402 (test-skip (if (force %http-server-socket) 0 1))
403 (test-equal "home-page: 200"
406 (with-http-server 200 %long-string
408 (inherit (dummy-package "x"))
409 (home-page (%local-url)))))
410 (check-home-page pkg)))))
412 (test-skip (if (force %http-server-socket) 0 1))
413 (test-assert "home-page: 200 but short length"
417 (with-http-server 200 "This is too small."
419 (inherit (dummy-package "x"))
420 (home-page (%local-url)))))
421 (check-home-page pkg))))
422 "suspiciously small")))
424 (test-skip (if (force %http-server-socket) 0 1))
425 (test-assert "home-page: 404"
429 (with-http-server 404 %long-string
431 (inherit (dummy-package "x"))
432 (home-page (%local-url)))))
433 (check-home-page pkg))))
434 "not reachable: 404")))
436 (test-assert "source-file-name"
440 (let ((pkg (dummy-package "x"
445 (uri "http://www.example.com/3.2.1.tar.gz")
446 (sha256 %null-sha256))))))
447 (check-source-file-name pkg)))
448 "file name should contain the package name")))
450 (test-assert "source-file-name: v prefix"
454 (let ((pkg (dummy-package "x"
459 (uri "http://www.example.com/v3.2.1.tar.gz")
460 (sha256 %null-sha256))))))
461 (check-source-file-name pkg)))
462 "file name should contain the package name")))
464 (test-assert "source-file-name: bad checkout"
468 (let ((pkg (dummy-package "x"
474 (url "http://www.example.com/x.git")
476 (sha256 %null-sha256))))))
477 (check-source-file-name pkg)))
478 "file name should contain the package name")))
480 (test-assert "source-file-name: good checkout"
485 (let ((pkg (dummy-package "x"
491 (url "http://git.example.com/x.git")
493 (file-name (string-append "x-" version))
494 (sha256 %null-sha256))))))
495 (check-source-file-name pkg)))
496 "file name should contain the package name"))))
498 (test-assert "source-file-name: valid"
503 (let ((pkg (dummy-package "x"
508 (uri "http://www.example.com/x-3.2.1.tar.gz")
509 (sha256 %null-sha256))))))
510 (check-source-file-name pkg)))
511 "file name should contain the package name"))))
513 (test-skip (if (force %http-server-socket) 0 1))
514 (test-equal "source: 200"
517 (with-http-server 200 %long-string
519 (inherit (dummy-package "x"))
523 (sha256 %null-sha256))))))
524 (check-source pkg)))))
526 (test-skip (if (force %http-server-socket) 0 1))
527 (test-assert "source: 200 but short length"
531 (with-http-server 200 "This is too small."
533 (inherit (dummy-package "x"))
537 (sha256 %null-sha256))))))
538 (check-source pkg))))
539 "suspiciously small")))
541 (test-skip (if (force %http-server-socket) 0 1))
542 (test-assert "source: 404"
546 (with-http-server 404 %long-string
548 (inherit (dummy-package "x"))
552 (sha256 %null-sha256))))))
553 (check-source pkg))))
554 "not reachable: 404")))
556 (test-assert "mirror-url"
559 (let ((source (origin
561 (uri "http://example.org/foo/bar.tar.gz")
562 (sha256 %null-sha256))))
563 (check-mirror-url (dummy-package "x" (source source)))))))
565 (test-assert "mirror-url: one suggestion"
568 (let ((source (origin
570 (uri "http://ftp.gnu.org/pub/gnu/foo/foo.tar.gz")
571 (sha256 %null-sha256))))
572 (check-mirror-url (dummy-package "x" (source source)))))
573 "mirror://gnu/foo/foo.tar.gz"))
576 (mock ((guix scripts lint) package-vulnerabilities (const '()))
578 (with-warnings (check-vulnerabilities (dummy-package "x"))))))
580 (test-assert "cve: one vulnerability"
581 (mock ((guix scripts lint) package-vulnerabilities
583 (list (make-struct (@@ (guix cve) <vulnerability>) 0
585 (list (cons (package-name package)
586 (package-version package)))))))
589 (check-vulnerabilities (dummy-package "pi" (version "3.14"))))
590 "vulnerable to CVE-2015-1234")))
592 (test-assert "cve: one patched vulnerability"
593 (mock ((guix scripts lint) package-vulnerabilities
595 (list (make-struct (@@ (guix cve) <vulnerability>) 0
597 (list (cons (package-name package)
598 (package-version package)))))))
601 (check-vulnerabilities
607 (list "/a/b/pi-CVE-2015-1234.patch"))))))))))
609 (test-assert "cve: vulnerability fixed in replacement version"
610 (mock ((guix scripts lint) package-vulnerabilities
612 (match (package-version package)
614 (list (make-struct (@@ (guix cve) <vulnerability>) 0
616 (list (cons (package-name package)
617 (package-version package))))))
620 (and (not (string-null?
622 (check-vulnerabilities
623 (dummy-package "foo" (version "0"))))))
626 (check-vulnerabilities
629 (replacement (dummy-package "foo" (version "1"))))))))))
631 (test-assert "cve: patched vulnerability in replacement"
632 (mock ((guix scripts lint) package-vulnerabilities
634 (list (make-struct (@@ (guix cve) <vulnerability>) 0
636 (list (cons (package-name package)
637 (package-version package)))))))
640 (check-vulnerabilities
642 "pi" (version "3.14") (source (dummy-origin))
643 (replacement (dummy-package
644 "pi" (version "3.14")
648 (list "/a/b/pi-CVE-2015-1234.patch"))))))))))))
650 (test-assert "formatting: lonely parentheses"
655 dummy-package "ugly as hell!"
660 (test-assert "formatting: tabulation"
663 (check-formatting (dummy-package "leave the tab here: ")))
666 (test-assert "formatting: trailing white space"
669 ;; Leave the trailing white space on the next line!
670 (check-formatting (dummy-package "x")))
671 "trailing white space"))
673 (test-assert "formatting: long line"
677 (dummy-package "x" ;here is a stupid comment just to make a long line
681 (test-assert "formatting: alright"
684 (check-formatting (dummy-package "x")))))
689 ;; eval: (put 'with-http-server 'scheme-indent-function 2)
690 ;; eval: (put 'with-warnings 'scheme-indent-function 0)