hash.test 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. ;;;; hash.test --- test guile hashing -*- scheme -*-
  2. ;;;;
  3. ;;;; Copyright (C) 2004, 2005, 2006, 2008, 2011, 2012,
  4. ;;;; 2014, 2020 Free Software Foundation, Inc.
  5. ;;;;
  6. ;;;; This library is free software; you can redistribute it and/or
  7. ;;;; modify it under the terms of the GNU Lesser General Public
  8. ;;;; License as published by the Free Software Foundation; either
  9. ;;;; version 3 of the License, or (at your option) any later version.
  10. ;;;;
  11. ;;;; This library is distributed in the hope that it will be useful,
  12. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. ;;;; Lesser General Public License for more details.
  15. ;;;;
  16. ;;;; You should have received a copy of the GNU Lesser General Public
  17. ;;;; License along with this library; if not, write to the Free Software
  18. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. (define-module (test-suite test-numbers)
  20. #:use-module (test-suite lib)
  21. #:use-module (ice-9 documentation)
  22. #:use-module (ice-9 hash-table))
  23. ;;;
  24. ;;; hash
  25. ;;;
  26. (with-test-prefix "hash"
  27. (pass-if (->bool (object-documentation hash)))
  28. (pass-if-exception "hash #t -1" exception:out-of-range
  29. (hash #t -1))
  30. (pass-if-exception "hash #t 0" exception:out-of-range
  31. (hash #t 0))
  32. (pass-if (= 0 (hash #t 1)))
  33. (pass-if (= 0 (hash #f 1)))
  34. (pass-if (= 0 (hash noop 1)))
  35. (pass-if (= 0 (hash +inf.0 1)))
  36. (pass-if (= 0 (hash -inf.0 1)))
  37. (pass-if (= 0 (hash +nan.0 1)))
  38. (pass-if (= 0 (hash '#() 1)))
  39. (with-test-prefix "keyword"
  40. (pass-if "equality"
  41. (= (hash #:foo most-positive-fixnum)
  42. (hash #:foo most-positive-fixnum)))
  43. (pass-if "inequality"
  44. ;; Inequality cannot be 100% guaranteed but should definitely be
  45. ;; met for such a case.
  46. (not (= (hash #:foo most-positive-fixnum)
  47. (hash #:bar most-positive-fixnum)))))
  48. (pass-if "cyclic vectors"
  49. (let ()
  50. (define (cyclic-vector n)
  51. (let ((v (make-vector n)))
  52. (vector-fill! v v)
  53. v))
  54. (and (= 0 (hash (cyclic-vector 3) 1))
  55. (= 0 (hash (cyclic-vector 10) 1))))))
  56. ;;;
  57. ;;; hashv
  58. ;;;
  59. (with-test-prefix "hashv"
  60. (pass-if (->bool (object-documentation hashv)))
  61. (pass-if-exception "hashv #t -1" exception:out-of-range
  62. (hashv #t -1))
  63. (pass-if-exception "hashv #t 0" exception:out-of-range
  64. (hashv #t 0))
  65. (pass-if (= 0 (hashv #t 1)))
  66. (pass-if (= 0 (hashv #f 1)))
  67. (pass-if (= 0 (hashv noop 1))))
  68. ;;;
  69. ;;; hashq
  70. ;;;
  71. (with-test-prefix "hashq"
  72. (pass-if (->bool (object-documentation hashq)))
  73. (pass-if-exception "hashq #t -1" exception:out-of-range
  74. (hashq #t -1))
  75. (pass-if-exception "hashq #t 0" exception:out-of-range
  76. (hashq #t 0))
  77. (pass-if (= 0 (hashq #t 1)))
  78. (pass-if (= 0 (hashq #f 1)))
  79. (pass-if (= 0 (hashq noop 1))))
  80. ;;;
  81. ;;; make-hash-table
  82. ;;;
  83. (with-test-prefix
  84. "make-hash-table, hash-table?"
  85. (pass-if-exception "make-hash-table -1" exception:out-of-range
  86. (make-hash-table -1))
  87. (pass-if (hash-table? (make-hash-table 0))) ;; default
  88. (pass-if (not (hash-table? 'not-a-hash-table)))
  89. (pass-if (string-suffix? " 0/113>"
  90. (with-output-to-string
  91. (lambda ()
  92. (write (make-hash-table 100)))))))
  93. ;;;
  94. ;;; alist->hash-table
  95. ;;;
  96. (with-test-prefix
  97. "alist conversion"
  98. (pass-if "alist->hash-table"
  99. (let ((table (alist->hash-table '(("foo" . 1)
  100. ("bar" . 2)
  101. ("foo" . 3)))))
  102. (and (= (hash-ref table "foo") 1)
  103. (= (hash-ref table "bar") 2))))
  104. (pass-if "alist->hashq-table"
  105. (let ((table (alist->hashq-table '((foo . 1)
  106. (bar . 2)
  107. (foo . 3)))))
  108. (and (= (hashq-ref table 'foo) 1)
  109. (= (hashq-ref table 'bar) 2))))
  110. (pass-if "alist->hashv-table"
  111. (let ((table (alist->hashv-table '((1 . 1)
  112. (2 . 2)
  113. (1 . 3)))))
  114. (and (= (hashv-ref table 1) 1)
  115. (= (hashv-ref table 2) 2))))
  116. (pass-if "alist->hashx-table"
  117. (let ((table (alist->hashx-table hash assoc '((foo . 1)
  118. (bar . 2)
  119. (foo . 3)))))
  120. (and (= (hashx-ref hash assoc table 'foo) 1)
  121. (= (hashx-ref hash assoc table 'bar) 2)))))
  122. ;;;
  123. ;;; usual set and reference
  124. ;;;
  125. (with-test-prefix
  126. "hash-set and hash-ref"
  127. ;; auto-resizing
  128. (pass-if (let ((table (make-hash-table 1))) ;;actually makes size 31
  129. (hash-set! table 'one 1)
  130. (hash-set! table 'two #t)
  131. (hash-set! table 'three #t)
  132. (hash-set! table 'four #t)
  133. (hash-set! table 'five #t)
  134. (hash-set! table 'six #t)
  135. (hash-set! table 'seven #t)
  136. (hash-set! table 'eight #t)
  137. (hash-set! table 'nine 9)
  138. (hash-set! table 'ten #t)
  139. (hash-set! table 'eleven #t)
  140. (hash-set! table 'twelve #t)
  141. (hash-set! table 'thirteen #t)
  142. (hash-set! table 'fourteen #t)
  143. (hash-set! table 'fifteen #t)
  144. (hash-set! table 'sixteen #t)
  145. (hash-set! table 'seventeen #t)
  146. (hash-set! table 18 #t)
  147. (hash-set! table 19 #t)
  148. (hash-set! table 20 #t)
  149. (hash-set! table 21 #t)
  150. (hash-set! table 22 #t)
  151. (hash-set! table 23 #t)
  152. (hash-set! table 24 #t)
  153. (hash-set! table 25 #t)
  154. (hash-set! table 26 #t)
  155. (hash-set! table 27 #t)
  156. (hash-set! table 28 #t)
  157. (hash-set! table 29 #t)
  158. (hash-set! table 30 'thirty)
  159. (hash-set! table 31 #t)
  160. (hash-set! table 32 #t)
  161. (hash-set! table 33 'thirty-three)
  162. (hash-set! table 34 #t)
  163. (hash-set! table 35 #t)
  164. (hash-set! table 'foo 'bar)
  165. (and (equal? 1 (hash-ref table 'one))
  166. (equal? 9 (hash-ref table 'nine))
  167. (equal? 'thirty (hash-ref table 30))
  168. (equal? 'thirty-three (hash-ref table 33))
  169. (equal? 'bar (hash-ref table 'foo))
  170. (string-suffix? " 36/61>"
  171. (with-output-to-string
  172. (lambda () (write table)))))))
  173. ;; 1 and 1 are equal? and eqv? (but not necessarily eq?)
  174. (pass-if (equal? 'foo
  175. (let ((table (make-hash-table)))
  176. (hash-set! table 1 'foo)
  177. (hash-ref table 1))))
  178. (pass-if (equal? 'foo
  179. (let ((table (make-hash-table)))
  180. (hashv-set! table 1 'foo)
  181. (hashv-ref table 1))))
  182. ;; 1/2 and 2/4 are equal? and eqv? (but not necessarily eq?)
  183. (pass-if (equal? 'foo
  184. (let ((table (make-hash-table)))
  185. (hash-set! table 1/2 'foo)
  186. (hash-ref table 2/4))))
  187. (pass-if (equal? 'foo
  188. (let ((table (make-hash-table)))
  189. (hashv-set! table 1/2 'foo)
  190. (hashv-ref table 2/4))))
  191. ;; (list 1 2) is equal? but not eqv? or eq? to another (list 1 2)
  192. (pass-if (equal? 'foo
  193. (let ((table (make-hash-table)))
  194. (hash-set! table (list 1 2) 'foo)
  195. (hash-ref table (list 1 2)))))
  196. (pass-if (equal? #f
  197. (let ((table (make-hash-table)))
  198. (hashv-set! table (list 1 2) 'foo)
  199. (hashv-ref table (list 1 2)))))
  200. (pass-if (equal? #f
  201. (let ((table (make-hash-table)))
  202. (hashq-set! table (list 1 2) 'foo)
  203. (hashq-ref table (list 1 2)))))
  204. ;; ref default argument
  205. (pass-if (equal? 'bar
  206. (let ((table (make-hash-table)))
  207. (hash-ref table 'foo 'bar))))
  208. (pass-if (equal? 'bar
  209. (let ((table (make-hash-table)))
  210. (hashv-ref table 'foo 'bar))))
  211. (pass-if (equal? 'bar
  212. (let ((table (make-hash-table)))
  213. (hashq-ref table 'foo 'bar))))
  214. (pass-if (equal? 'bar
  215. (let ((table (make-hash-table)))
  216. (hashx-ref hash equal? table 'foo 'bar))))
  217. ;; wrong type argument
  218. (pass-if-exception "(hash-ref 'not-a-table 'key)" exception:wrong-type-arg
  219. (hash-ref 'not-a-table 'key))
  220. )
  221. ;;;
  222. ;;; hashx
  223. ;;;
  224. (with-test-prefix
  225. "auto-resizing hashx"
  226. ;; auto-resizing
  227. (let ((table (make-hash-table 1))) ;;actually makes size 31
  228. (hashx-set! hash assoc table 1/2 'equal)
  229. (hashx-set! hash assoc table 1/3 'equal)
  230. (hashx-set! hash assoc table 4 'equal)
  231. (hashx-set! hash assoc table 1/5 'equal)
  232. (hashx-set! hash assoc table 1/6 'equal)
  233. (hashx-set! hash assoc table 7 'equal)
  234. (hashx-set! hash assoc table 1/8 'equal)
  235. (hashx-set! hash assoc table 1/9 'equal)
  236. (hashx-set! hash assoc table 10 'equal)
  237. (hashx-set! hash assoc table 1/11 'equal)
  238. (hashx-set! hash assoc table 1/12 'equal)
  239. (hashx-set! hash assoc table 13 'equal)
  240. (hashx-set! hash assoc table 1/14 'equal)
  241. (hashx-set! hash assoc table 1/15 'equal)
  242. (hashx-set! hash assoc table 16 'equal)
  243. (hashx-set! hash assoc table 1/17 'equal)
  244. (hashx-set! hash assoc table 1/18 'equal)
  245. (hashx-set! hash assoc table 19 'equal)
  246. (hashx-set! hash assoc table 1/20 'equal)
  247. (hashx-set! hash assoc table 1/21 'equal)
  248. (hashx-set! hash assoc table 22 'equal)
  249. (hashx-set! hash assoc table 1/23 'equal)
  250. (hashx-set! hash assoc table 1/24 'equal)
  251. (hashx-set! hash assoc table 25 'equal)
  252. (hashx-set! hash assoc table 1/26 'equal)
  253. (hashx-set! hash assoc table 1/27 'equal)
  254. (hashx-set! hash assoc table 28 'equal)
  255. (hashx-set! hash assoc table 1/29 'equal)
  256. (hashx-set! hash assoc table 1/30 'equal)
  257. (hashx-set! hash assoc table 31 'equal)
  258. (hashx-set! hash assoc table 1/32 'equal)
  259. (hashx-set! hash assoc table 1/33 'equal)
  260. (hashx-set! hash assoc table 34 'equal)
  261. (pass-if (equal? 'equal (hash-ref table 2/4)))
  262. (pass-if (equal? 'equal (hash-ref table 2/6)))
  263. (pass-if (equal? 'equal (hash-ref table 4)))
  264. (pass-if (equal? 'equal (hashx-ref hash assoc table 2/64)))
  265. (pass-if (equal? 'equal (hashx-ref hash assoc table 2/66)))
  266. (pass-if (equal? 'equal (hashx-ref hash assoc table 34)))
  267. (pass-if (string-suffix? " 33/61>"
  268. (with-output-to-string
  269. (lambda () (write table)))))))
  270. (with-test-prefix
  271. "hashx"
  272. (pass-if (let ((table (make-hash-table)))
  273. (hashx-set! (lambda (k v) 1)
  274. (lambda (k al) (assoc 'foo al))
  275. table 'foo 'bar)
  276. (equal?
  277. 'bar (hashx-ref (lambda (k v) 1)
  278. (lambda (k al) (assoc 'foo al))
  279. table 'baz))))
  280. (pass-if (let ((table (make-hash-table 31)))
  281. (hashx-set! (lambda (k v) 1) assoc table 'foo 'bar)
  282. (equal? #f
  283. (hashx-ref (lambda (k v) 2) assoc table 'foo))))
  284. (pass-if (let ((table (make-hash-table)))
  285. (hashx-set! hash assoc table 'foo 'bar)
  286. (equal? #f
  287. (hashx-ref hash (lambda (k al) #f) table 'foo))))
  288. (pass-if-exception
  289. "hashx-set! (lambda (k s) 1) equal? table 'foo 'bar"
  290. exception:wrong-type-arg ;; there must be a better exception than that...
  291. (hashx-set! (lambda (k s) 1) (lambda (k al) #t) (make-hash-table) 'foo 'bar))
  292. )
  293. ;;;
  294. ;;; hashx-remove!
  295. ;;;
  296. (with-test-prefix "hashx-remove!"
  297. (pass-if (->bool (object-documentation hashx-remove!)))
  298. (pass-if (let ((table (make-hash-table)))
  299. (hashx-set! hashq assq table 'x 123)
  300. (hashx-remove! hashq assq table 'x)
  301. (null? (hash-map->list noop table)))))
  302. ;;;
  303. ;;; hashx
  304. ;;;
  305. (with-test-prefix "hashx"
  306. (pass-if-exception
  307. "hashx-set! (lambda (k s) 1) (lambda (k al) #t) table 'foo 'bar"
  308. exception:wrong-type-arg
  309. (hashx-set! (lambda (k s) 1) (lambda (k al) #t) (make-hash-table) 'foo 'bar))
  310. )
  311. ;;;
  312. ;;; hash-count
  313. ;;;
  314. (with-test-prefix "hash-count"
  315. (let ((table (make-hash-table)))
  316. (hashq-set! table 'foo "bar")
  317. (hashq-set! table 'braz "zonk")
  318. (hashq-create-handle! table 'frob #f)
  319. (pass-if (equal? 3 (hash-count (const #t) table)))
  320. (pass-if (equal? 2 (hash-count (lambda (k v)
  321. (string? v)) table)))))
  322. ;;;
  323. ;;; weak key hash table
  324. ;;;
  325. (with-test-prefix "weak key hash table"
  326. (pass-if "hash-for-each after gc"
  327. (let ((table (make-weak-key-hash-table)))
  328. (hashq-set! table (list 'foo) 'bar)
  329. (gc)
  330. ;; Iterate over deleted weak ref without crashing.
  331. (unspecified? (hash-for-each (lambda (key value) key) table)))))