utils.scm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
  4. ;;; Copyright © 2016 Mathieu Lirzin <mthl@gnu.org>
  5. ;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
  6. ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
  7. ;;;
  8. ;;; This file is part of GNU Guix.
  9. ;;;
  10. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  11. ;;; under the terms of the GNU General Public License as published by
  12. ;;; the Free Software Foundation; either version 3 of the License, or (at
  13. ;;; your option) any later version.
  14. ;;;
  15. ;;; GNU Guix is distributed in the hope that it will be useful, but
  16. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;;; GNU General Public License for more details.
  19. ;;;
  20. ;;; You should have received a copy of the GNU General Public License
  21. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  22. (define-module (test-utils)
  23. #:use-module ((guix config) #:select (%gzip))
  24. #:use-module (guix utils)
  25. #:use-module ((guix store) #:select (%store-prefix store-path-package-name))
  26. #:use-module ((guix search-paths) #:select (string-tokenize*))
  27. #:use-module (srfi srfi-1)
  28. #:use-module (srfi srfi-11)
  29. #:use-module (srfi srfi-64)
  30. #:use-module (rnrs bytevectors)
  31. #:use-module (rnrs io ports)
  32. #:use-module (ice-9 match)
  33. #:use-module (ice-9 vlist))
  34. (define temp-file
  35. (string-append "t-utils-" (number->string (getpid))))
  36. (test-begin "utils")
  37. (test-assert "gnu-triplet->nix-system"
  38. (let ((samples '(("i586-gnu0.3" "i686-gnu")
  39. ("x86_64-unknown-linux-gnu" "x86_64-linux")
  40. ("i386-pc-linux-gnu" "i686-linux")
  41. ("x86_64-unknown-freebsd8.2" "x86_64-freebsd")
  42. ("x86_64-apple-darwin10.8.0" "x86_64-darwin")
  43. ("i686-pc-cygwin" "i686-cygwin"))))
  44. (let-values (((gnu nix) (unzip2 samples)))
  45. (every (lambda (gnu nix)
  46. (equal? nix (gnu-triplet->nix-system gnu)))
  47. gnu nix))))
  48. (test-assert "package-name->name+version"
  49. (every (match-lambda
  50. ((name version)
  51. (let*-values (((full-name)
  52. (if version
  53. (string-append name "@" version)
  54. name))
  55. ((name* version*)
  56. (package-name->name+version full-name)))
  57. (and (equal? name* name)
  58. (equal? version* version)))))
  59. '(("foo" "0.9.1b")
  60. ("foo-14-bar" "320")
  61. ("foo-bar2" #f)
  62. ("guile" "2.0.6.65-134c9") ; as produced by `git-version-gen'
  63. ("nixpkgs" "1.0pre22125_a28fe19")
  64. ("gtk2" "2.38.0"))))
  65. (test-assert "guile-version>? 1.8"
  66. (guile-version>? "1.8"))
  67. (test-assert "guile-version>? 10.5"
  68. (not (guile-version>? "10.5")))
  69. (test-assert "version-prefix?"
  70. (and (version-prefix? "4.1" "4.1.2")
  71. (version-prefix? "4.1" "4.1")
  72. (not (version-prefix? "4.1" "4.16.2"))
  73. (not (version-prefix? "4.1" "4"))))
  74. (test-equal "version-unique-prefix"
  75. '("2" "2.2" "")
  76. (list (version-unique-prefix "2.0" '("3.0" "2.0"))
  77. (version-unique-prefix "2.2" '("3.0.5" "2.0.9" "2.2.7"))
  78. (version-unique-prefix "27.1" '("27.1"))))
  79. (test-equal "string-tokenize*"
  80. '(("foo")
  81. ("foo" "bar" "baz")
  82. ("foo" "bar" "")
  83. ("foo" "bar" "baz"))
  84. (list (string-tokenize* "foo" ":")
  85. (string-tokenize* "foo;bar;baz" ";")
  86. (string-tokenize* "foo!bar!" "!")
  87. (string-tokenize* "foo+-+bar+-+baz" "+-+")))
  88. (test-equal "string-replace-substring"
  89. '("foo BAR! baz"
  90. "/gnu/store/chbouib"
  91. "")
  92. (list (string-replace-substring "foo bar baz" "bar" "BAR!")
  93. (string-replace-substring "/nix/store/chbouib" "/nix/" "/gnu/")
  94. (string-replace-substring "" "foo" "bar")))
  95. (test-equal "strip-keyword-arguments"
  96. '(a #:b b #:c c)
  97. (strip-keyword-arguments '(#:foo #:bar #:baz)
  98. '(a #:foo 42 #:b b #:baz 3
  99. #:c c #:bar 4)))
  100. (test-equal "ensure-keyword-arguments"
  101. '((#:foo 2)
  102. (#:foo 2 #:bar 3)
  103. (#:foo 42 #:bar 3))
  104. (list (ensure-keyword-arguments '(#:foo 2) '(#:foo 2))
  105. (ensure-keyword-arguments '(#:foo 2) '(#:bar 3))
  106. (ensure-keyword-arguments '(#:foo 2) '(#:bar 3 #:foo 42))))
  107. (test-equal "default-keyword-arguments"
  108. '((#:foo 2)
  109. (#:foo 2)
  110. (#:foo 2 #:bar 3)
  111. (#:foo 2 #:bar 3)
  112. (#:foo 2 #:bar 3))
  113. (list (default-keyword-arguments '() '(#:foo 2))
  114. (default-keyword-arguments '(#:foo 2) '(#:foo 4))
  115. (default-keyword-arguments '() '(#:bar 3 #:foo 2))
  116. (default-keyword-arguments '(#:bar 3) '(#:foo 2))
  117. (default-keyword-arguments '(#:foo 2 #:bar 3) '(#:bar 6))))
  118. (test-equal "substitute-keyword-arguments"
  119. '((#:foo 3)
  120. (#:foo 3)
  121. (#:foo 3 #:bar (1 2))
  122. (#:bar (1 2) #:foo 3)
  123. (#:foo 3))
  124. (list (substitute-keyword-arguments '(#:foo 2)
  125. ((#:foo f) (1+ f)))
  126. (substitute-keyword-arguments '()
  127. ((#:foo f 2) (1+ f)))
  128. (substitute-keyword-arguments '(#:foo 2 #:bar (2))
  129. ((#:foo f) (1+ f))
  130. ((#:bar b) (cons 1 b)))
  131. (substitute-keyword-arguments '(#:foo 2)
  132. ((#:foo _) 3)
  133. ((#:bar b '(2)) (cons 1 b)))
  134. (substitute-keyword-arguments '(#:foo 2)
  135. ((#:foo f 1) (1+ f))
  136. ((#:bar b) (cons 42 b)))))
  137. (test-assert "filtered-port, file"
  138. (let* ((file (search-path %load-path "guix.scm"))
  139. (input (open-file file "r0b")))
  140. (let*-values (((compressed pids1)
  141. (filtered-port `(,%gzip "-c" "--fast") input))
  142. ((decompressed pids2)
  143. (filtered-port `(,%gzip "-d") compressed)))
  144. (and (every (compose zero? cdr waitpid)
  145. (append pids1 pids2))
  146. (equal? (get-bytevector-all decompressed)
  147. (call-with-input-file file get-bytevector-all))))))
  148. (test-assert "filtered-port, non-file"
  149. (let ((data (call-with-input-file (search-path %load-path "guix.scm")
  150. get-bytevector-all)))
  151. (let*-values (((compressed pids1)
  152. (filtered-port `(,%gzip "-c" "--fast")
  153. (open-bytevector-input-port data)))
  154. ((decompressed pids2)
  155. (filtered-port `(,%gzip "-d") compressed)))
  156. (and (pk (every (compose zero? cdr waitpid)
  157. (append pids1 pids2)))
  158. (equal? (get-bytevector-all decompressed) data)))))
  159. (test-assert "filtered-port, does not exist"
  160. (let* ((file (search-path %load-path "guix.scm"))
  161. (input (open-file file "r0b")))
  162. (let-values (((port pids)
  163. (filtered-port '("/does/not/exist") input)))
  164. (any (compose (negate zero?) cdr waitpid)
  165. pids))))
  166. (define (test-compression/decompression method run?)
  167. "Test METHOD, a symbol such as 'gzip. Call RUN? to determine whether to
  168. skip these tests."
  169. (unless (run?) (test-skip 1))
  170. (test-assert (format #f "compressed-port, decompressed-port, non-file [~a]"
  171. method)
  172. (let ((data (call-with-input-file (search-path %load-path "guix.scm")
  173. get-bytevector-all)))
  174. (call-with-temporary-output-file
  175. (lambda (output port)
  176. (close-port port)
  177. (let*-values (((compressed pids)
  178. ;; Note: 'compressed-output-port' only supports file
  179. ;; ports.
  180. (compressed-output-port method
  181. (open-file output "w0"))))
  182. (put-bytevector compressed data)
  183. (close-port compressed)
  184. (and (every (compose zero? cdr waitpid)
  185. (pk 'pids method pids))
  186. (let*-values (((decompressed pids)
  187. (decompressed-port method
  188. (open-bytevector-input-port
  189. (call-with-input-file output
  190. get-bytevector-all))))
  191. ((result)
  192. (get-bytevector-all decompressed)))
  193. (close-port decompressed)
  194. (pk 'len method
  195. (if (bytevector? result)
  196. (bytevector-length result)
  197. result)
  198. (bytevector-length data))
  199. (and (every (compose zero? cdr waitpid)
  200. (pk 'pids method pids))
  201. (equal? result data)))))))))
  202. (false-if-exception (delete-file temp-file))
  203. (unless (run?) (test-skip 1))
  204. (test-assert (format #f "compressed-output-port + decompressed-port [~a]"
  205. method)
  206. (let* ((file (search-path %load-path "guix/derivations.scm"))
  207. (data (call-with-input-file file get-bytevector-all))
  208. (port (open-file temp-file "w0b")))
  209. (call-with-compressed-output-port method port
  210. (lambda (compressed)
  211. (put-bytevector compressed data)))
  212. (close-port port)
  213. (bytevector=? data
  214. (call-with-decompressed-port method (open-file temp-file "r0b")
  215. get-bytevector-all)))))
  216. (for-each test-compression/decompression
  217. `(gzip xz lzip zstd)
  218. (list (const #t) (const #t) (const #t)
  219. (lambda ()
  220. (resolve-module '(zstd) #t #f #:ensure #f))))
  221. ;; This is actually in (guix store).
  222. (test-equal "store-path-package-name"
  223. "bash-4.2-p24"
  224. (store-path-package-name
  225. (string-append (%store-prefix)
  226. "/qvs2rj2ia5vci3wsdb7qvydrmacig4pg-bash-4.2-p24")))
  227. (test-equal "canonical-newline-port"
  228. "This is a journey\nInto the sound\nA journey ...\n"
  229. (let ((port (open-string-input-port
  230. "This is a journey\r\nInto the sound\r\nA journey ...\n")))
  231. (get-string-all (canonical-newline-port port))))
  232. (test-equal "canonical-newline-port-1024"
  233. (string-concatenate (make-list 100 "0123456789abcde\n"))
  234. (let ((port (open-string-input-port
  235. (string-concatenate
  236. (make-list 100 "0123456789abcde\r\n")))))
  237. (get-string-all (canonical-newline-port port))))
  238. (test-equal "edit-expression"
  239. "(display \"GNU Guix\")\n(newline)\n"
  240. (begin
  241. (call-with-output-file temp-file
  242. (lambda (port)
  243. (display "(display \"xiuG UNG\")\n(newline)\n" port)))
  244. (edit-expression `((filename . ,temp-file)
  245. (line . 0)
  246. (column . 9))
  247. string-reverse)
  248. (call-with-input-file temp-file get-string-all)))
  249. (test-equal "string-distance"
  250. '(0 1 1 5 5)
  251. (list
  252. (string-distance "hello" "hello")
  253. (string-distance "hello" "helo")
  254. (string-distance "helo" "hello")
  255. (string-distance "" "hello")
  256. (string-distance "hello" "")))
  257. (test-equal "string-closest"
  258. '("hello" "hello" "helo" #f)
  259. (list
  260. (string-closest "hello" '("hello"))
  261. (string-closest "hello" '("helo" "hello" "halo"))
  262. (string-closest "hello" '("kikoo" "helo" "hihihi" "halo"))
  263. (string-closest "hello" '("aaaaa" "12345" "hellohello" "h"))))
  264. (test-equal "target-linux?"
  265. '(#t #f #f #t)
  266. (map target-linux?
  267. '("i686-linux-gnu" "i686-w64-mingw32"
  268. ;; Checking that "gnu" is present is not sufficient,
  269. ;; as GNU/Hurd exists.
  270. "i686-pc-gnu"
  271. ;; Some targets have a suffix.
  272. "arm-linux-gnueabihf")))
  273. (test-equal "target-mingw?"
  274. '(#f #f #t)
  275. (map target-mingw?
  276. '("i686-linux-gnu" "i686-pc-gnu"
  277. "i686-w64-mingw32")))
  278. (test-equal "target-x86-32?"
  279. '(#f #f #f #t #t #t #t #f)
  280. ;; These are (according to Wikipedia) two RISC architectures
  281. ;; by Intel and presumably not compatible with the x86-32 series.
  282. (map target-x86-32?
  283. '("i860-gnu" "i960-gnu"
  284. ;; This is a 16-bit architecture
  285. "i286-gnu"
  286. ;; These are part of the x86-32 series.
  287. "i386-gnu" "i486-gnu" "i586-gnu" "i686-gnu"
  288. ;; Maybe this one will exist some day, but not yet.
  289. "i786-gnu")))
  290. (test-equal "target-x86-64?"
  291. '(#t #f #f #f)
  292. (map target-x86-64?
  293. `("x86_64-linux-gnu" "i386-linux-gnu"
  294. ;; Just because it includes "64" doesn't make it 64-bit.
  295. "aarch64-linux-gnu"
  296. ;; Note that (expt 2 109) in decimal notation starts with 64.
  297. ;; However, it isn't 32-bit.
  298. ,(format #f "x86_~a-linux-gnu" (expt 2 109)))))
  299. (test-end)
  300. (false-if-exception (delete-file temp-file))