bv-slice.scm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. ;; This file is part of scheme-GNUnet.
  2. ;; Copyright (C) 2021, 2022 GNUnet e.V.
  3. ;;
  4. ;; scheme-GNUnet is free software: you can redistribute it and/or modify it
  5. ;; under the terms of the GNU Affero General Public License as published
  6. ;; by the Free Software Foundation, either version 3 of the License,
  7. ;; or (at your option) any later version.
  8. ;;
  9. ;; scheme-GNUnet is distributed in the hope that it will be useful, but
  10. ;; WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;; Affero General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU Affero General Public License
  15. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ;;
  17. ;; SPDX-License-Identifier: AGPL-3.0-or-later
  18. (import (gnu gnunet utils bv-slice)
  19. (srfi srfi-26)
  20. (ice-9 match)
  21. (only (rnrs base) assert)
  22. (rnrs conditions)
  23. (rnrs control)
  24. (rnrs exceptions)
  25. (rnrs bytevectors))
  26. (test-begin "bv-slice")
  27. ;; slice-copy!
  28. (define-syntax-rule (test-missing-caps test-case what permitted required code)
  29. (test-equal test-case
  30. (list what permitted required)
  31. (guard (c ((missing-capabilities? c)
  32. (list (missing-capabilities-what c)
  33. (missing-capabilities-permitted c)
  34. (missing-capabilities-required c))))
  35. code)))
  36. (test-missing-caps
  37. "destination of slice-copy! must be writable"
  38. 'to
  39. CAP_READ
  40. CAP_WRITE
  41. (slice-copy! (make-slice/read-write 9)
  42. (slice/read-only (make-slice/read-write 9))))
  43. (test-missing-caps
  44. "source of slice-copy! must be readable"
  45. 'from
  46. CAP_WRITE
  47. CAP_READ
  48. (slice-copy! (slice/write-only (make-slice/read-write 9))
  49. (make-slice/read-write 9)))
  50. (test-error "lengths must match (1)"
  51. &assertion
  52. (slice-copy! (make-slice/read-write 9)
  53. (make-slice/read-write 0)))
  54. (test-error "lengths must match (2)"
  55. &assertion
  56. (slice-copy! (make-slice/read-write 0)
  57. (make-slice/read-write 9)))
  58. (test-equal "slice-copy! copies"
  59. #vu8(0 1 2 3)
  60. (let ((source (bv-slice/read-write #vu8(0 1 2 3)))
  61. (dest (make-slice/read-write 4)))
  62. (slice-copy! source dest)
  63. (slice-bv dest)))
  64. (test-equal "also if there's an offset in the source"
  65. #vu8(0 1 2 3)
  66. (let ((source (slice-slice (bv-slice/read-write #vu8(0 0 1 2 3)) 1))
  67. (dest (make-slice/read-write 4)))
  68. (slice-copy! source dest)
  69. (slice-bv dest)))
  70. (test-equal "also if the destination bv is long"
  71. #vu8(9 8 0 1 2 3)
  72. (let ((source (bv-slice/read-write #vu8(8 0 1 2)))
  73. (dest (slice-slice
  74. (bv-slice/read-write (bytevector-copy #vu8(9 7 7 7 7 3)))
  75. 1 4)))
  76. (slice-copy! source dest)
  77. (slice-bv dest)))
  78. (test-equal "slice-zero! writes zeros"
  79. #vu8(1 2 0 0 5 6 7 8)
  80. (let ((dest
  81. (slice-slice
  82. (bv-slice/read-write (bytevector-copy #vu8(1 2 3 4 5 6 7 8)))
  83. 2 2)))
  84. (slice-zero! dest)
  85. (slice-bv dest)))
  86. (test-missing-caps
  87. "slice-zero! requires writability"
  88. 'slice
  89. CAP_READ
  90. CAP_WRITE
  91. (slice-zero! (slice/read-only (make-slice/read-write 9))))
  92. (test-missing-caps
  93. "even if the length is zero"
  94. 'slice
  95. CAP_READ
  96. CAP_WRITE
  97. (slice-zero! (slice/read-only (make-slice/read-write 0))))
  98. (define (some-numbers N)
  99. (map (cut expt 2 <>) (iota N)))
  100. (define sizes/u `(#(16 ,slice-u16-ref ,slice-u16-set!)
  101. #(32 ,slice-u32-ref ,slice-u32-set!)
  102. #(64 ,slice-u64-ref ,slice-u64-set!)))
  103. (define sizes/s `(#(16 ,slice-s16-ref ,slice-s16-set!)
  104. #(32 ,slice-s32-ref ,slice-s32-set!)
  105. #(64 ,slice-s64-ref ,slice-s64-set!)))
  106. (for-each
  107. (match-lambda
  108. (#(bits ref set!)
  109. (test-equal
  110. (string-append "slice-u" (number->string bits) "-ref/set! round-trips")
  111. (some-numbers bits)
  112. (map (lambda (number)
  113. ;; #xde: filler that should be unused
  114. (define bv (make-bytevector (/ bits 8) #xde))
  115. (define sl (bv-slice/read-write bv))
  116. (set! sl 0 number (endianness little))
  117. (ref sl 0 (endianness little)))
  118. (some-numbers bits)))))
  119. sizes/u)
  120. (for-each
  121. (match-lambda
  122. (#(bits ref set!)
  123. (test-equal
  124. (string-append "slice-s" (number->string bits) "-ref/set! round-trips")
  125. (append (map - (some-numbers bits))
  126. ;; -1: avoid the sign bit
  127. (some-numbers (- bits 1)))
  128. (map (lambda (number)
  129. ;; #xde: filler that should be unused
  130. (define bv (make-bytevector (/ bits 8) #xde))
  131. (define sl (bv-slice/read-write bv))
  132. (set! sl 0 number (endianness little))
  133. (ref sl 0 (endianness little)))
  134. (append (map - (some-numbers bits))
  135. (some-numbers (- bits 1)))))))
  136. sizes/s)
  137. ;; Signed integer representations are used in some network messages,
  138. ;; so make sure they will be interpreted the same no matter the
  139. ;; architecture.
  140. (test-equal "two's complement is used"
  141. -128
  142. (slice-s8-ref (bv-slice/read-write #vu8(#b10000000)) 0))
  143. (test-equal "slice to string, read-write"
  144. "#<slice (CAP_READ | CAP_WRITE): 1 2 3>"
  145. (object->string (bv-slice/read-write #vu8(1 2 3))))
  146. (test-equal "slice to string, read-only"
  147. "#<slice (CAP_READ): 1 2 3>"
  148. (object->string
  149. (slice/read-only (bv-slice/read-write #vu8(1 2 3)))))
  150. ;; Make sure the lack of a read capability cannot be circumvented by
  151. ;; object->string.
  152. (test-equal "slice to string, write-only"
  153. "#<slice (CAP_WRITE) length: 3>"
  154. (object->string
  155. (slice/write-only (bv-slice/read-write #vu8(1 2 3)))))
  156. (test-missing-caps
  157. "source of slice-copy/read-write must be readable"
  158. 'original
  159. CAP_WRITE
  160. CAP_READ
  161. (slice-copy/read-write (slice/write-only (make-slice/read-write 9))))
  162. (test-missing-caps
  163. "even if the length is zero"
  164. 'original
  165. CAP_WRITE
  166. CAP_READ
  167. (slice-copy/read-write (slice/write-only (make-slice/read-write 0))))
  168. (test-assert "return value of slice-copy/read-write is read-write"
  169. (let ((copy (slice-copy/read-write (make-slice/read-write 9))))
  170. (and (slice-readable? copy) (slice-writable? copy))))
  171. (test-assert "return value of slice-copy/read-write is read-write, even if length is zero"
  172. (let ((copy (slice-copy/read-write (make-slice/read-write 0))))
  173. (and (slice-readable? copy) (slice-writable? copy))))
  174. (test-assert "return value of slice-copy/read-write independent of original"
  175. (let* ((original (make-slice/read-write 9))
  176. (copy (slice-copy/read-write original)))
  177. (slice-independent? original copy)))
  178. (test-assert "return value of slice-copy/read-write is fresh even if length is zero"
  179. (let* ((original (make-slice/read-write 0))
  180. (copy (slice-copy/read-write original)))
  181. (not (eq? original copy))))
  182. (test-equal "slice-copy/read-write returns something with the same contents (1)"
  183. #vu8(10 9 8 7 6 5)
  184. (let* ((original (bv-slice/read-write #vu8(11 10 9 8 7 6 5 4) 1 6))
  185. (copy (slice-copy/read-write original))
  186. (bv (make-bytevector 6)))
  187. (slice-copy! copy (bv-slice/read-write bv))
  188. bv))
  189. (test-equal "slice-copy/read-write returns something with the same contents (2)"
  190. #vu8(10 9 8 7 6 5)
  191. (let* ((original (slice/read-only
  192. (bv-slice/read-write #vu8(11 10 9 8 7 6 5 4) 1 6)))
  193. (copy (slice-copy/read-write original))
  194. (bv (make-bytevector 6)))
  195. (slice-copy! copy (bv-slice/read-write bv))
  196. bv))
  197. (test-missing-caps
  198. "source of slice-copy/read-only must be readable"
  199. 'original
  200. CAP_WRITE
  201. CAP_READ
  202. (slice-copy/read-only (slice/write-only (make-slice/read-write 9))))
  203. (test-missing-caps
  204. "even if the size is zero"
  205. 'original
  206. CAP_WRITE
  207. CAP_READ
  208. (slice-copy/read-only (slice/write-only (make-slice/read-write 0))))
  209. (test-assert "return value of slice-copy/read-only is read-only"
  210. (let ((copy (slice-copy/read-only (make-slice/read-write 9))))
  211. (and (slice-readable? copy) (not (slice-writable? copy)))))
  212. (test-assert "return value of slice-copy/read-only is read-only, even if length is zero"
  213. (let ((copy (slice-copy/read-only (make-slice/read-write 0))))
  214. (and (slice-readable? copy) (not (slice-writable? copy)))))
  215. (test-assert "return value of slice-copy/read-only independent of original"
  216. (let* ((original (make-slice/read-write 9))
  217. (copy (slice-copy/read-only original)))
  218. (slice-independent? original copy)))
  219. (test-assert "return value of slice-copy/read-only is fresh even if length is zero (1)"
  220. (let* ((original (make-slice/read-write 0))
  221. (copy (slice-copy/read-only original)))
  222. (not (eq? original copy))))
  223. (test-assert "return value of slice-copy/read-only is fresh even if length is zero (2)"
  224. (let* ((original (slice/read-only (make-slice/read-write 0)))
  225. (copy (slice-copy/read-only original)))
  226. (not (eq? original copy))))
  227. (test-equal "slice-copy/read-only returns something with the same contents (1)"
  228. #vu8(10 9 8 7 6 5)
  229. (let* ((original (bv-slice/read-write #vu8(11 10 9 8 7 6 5 4) 1 6))
  230. (copy (slice-copy/read-only original))
  231. (bv (make-bytevector 6)))
  232. (slice-copy! copy (bv-slice/read-write bv))
  233. bv))
  234. (test-equal "slice-copy/read-only returns something with the same contents (2)"
  235. #vu8(10 9 8 7 6 5)
  236. (let* ((original (slice/read-only
  237. (bv-slice/read-write #vu8(11 10 9 8 7 6 5 4) 1 6)))
  238. (copy (slice-copy/read-only original))
  239. (bv (make-bytevector 6)))
  240. (slice-copy! copy (bv-slice/read-write bv))
  241. bv))
  242. (test-assert "empty slices are independent"
  243. (slice-independent? (make-slice/read-write 0) (make-slice/read-write 0)))
  244. (test-assert "empty slices are independent, even if using the same bytevector"
  245. (let ((bv #vu8()))
  246. (slice-independent? (bv-slice/read-write bv) (bv-slice/read-write bv))))
  247. (test-assert "empty slices are independent, even when using offsets (1)"
  248. (let ((bv #vu8(0 1 2 3)))
  249. (slice-independent? (bv-slice/read-write bv 1 0)
  250. (bv-slice/read-write bv 2 0))))
  251. (test-assert "empty slices are independent, even when using offsets (2)"
  252. (let ((bv #vu8(0 1 2 3)))
  253. (slice-independent? (bv-slice/read-write bv 2 0)
  254. (bv-slice/read-write bv 1 0))))
  255. (test-assert "empty slices are independent, even if eq?"
  256. (let ((s (bv-slice/read-write #vu8())))
  257. (slice-independent? s s)))
  258. (test-assert "slice-independent? is irreflexive (assuming non-empty) and ignores capabilities (1)"
  259. (let ((s (make-slice/read-write 99)))
  260. (not (slice-independent? (slice/write-only s) (slice/read-only s)))))
  261. (test-assert "slice-independent? is irreflexive (assuming non-empty) and ignores capabilities (2)"
  262. (let ((s (make-slice/read-write 1)))
  263. (not (slice-independent? (slice/write-only s) (slice/read-only s)))))
  264. (test-assert "empty slice is independent, even if inside the other slice"
  265. (let ((bv #vu8(0 1 2 3 4 5 6 7 8 9)))
  266. (do ((offset-x 0 (+ 1 offset-x)))
  267. ((> offset-x (bytevector-length bv)) #true)
  268. (do ((length-x 0 (+ 1 length-x)))
  269. ((>= length-x (- (bytevector-length bv) offset-x)))
  270. (let ((x (bv-slice/read-write bv offset-x length-x)))
  271. (do ((offset 0 (+ 1 offset)))
  272. ((>= offset (bytevector-length bv)) (values))
  273. (let ((y (bv-slice/read-write bv offset 0)))
  274. (assert (slice-independent? x y))
  275. (assert (slice-independent? y x)))))))))
  276. (test-assert "non-overlapping ranges are independent"
  277. (let ((bv #vu8(0 1 2 3 4 5 6 7 8 9)))
  278. (do ((offset-x 0 (+ 1 offset-x)))
  279. ((> offset-x (bytevector-length bv)) #true)
  280. (do ((length-x 0 (+ 1 length-x)))
  281. ((>= length-x (- (bytevector-length bv) offset-x)))
  282. (let ((x (bv-slice/read-write bv offset-x length-x)))
  283. ;; Make a slice on the left
  284. (do ((offset-y 0 (+ 1 offset-y)))
  285. ((> offset-y offset-x))
  286. (do ((length-y 0 (+ 1 length-y)))
  287. ((>= (+ length-y offset-y) offset-x))
  288. (let ((y (bv-slice/read-write bv offset-y length-y)))
  289. (assert (slice-independent? x y))
  290. (assert (slice-independent? y x)))))
  291. ;; And a slice on the right
  292. (do ((offset-y (+ offset-x length-x) (+ 1 offset-y)))
  293. ((> offset-y (bytevector-length bv)))
  294. (do ((length-y 0 (+ 1 length-y)))
  295. ((>= (+ length-y offset-y) (bytevector-length bv)))
  296. (let ((y (bv-slice/read-write bv offset-y length-y)))
  297. (assert (slice-independent? x y))
  298. (assert (slice-independent? y x))))))))))
  299. (test-assert "overlapping ranges are dependent"
  300. (let ((bv #vu8(0 1 2 3 4 5 6 7 8 9)))
  301. (do ((offset-x 0 (+ 1 offset-x)))
  302. ;; - 1 to make sure 'x' is non-empty
  303. ((> offset-x (- (bytevector-length bv) 1)) #true)
  304. (do ((length-x 1 (+ 1 length-x)))
  305. ((>= length-x (- (bytevector-length bv) offset-x)))
  306. (let ((x (bv-slice/read-write bv offset-x length-x)))
  307. ;; Choose a start coordinate inside x or left of x
  308. (do ((offset-y 0 (+ 1 offset-y)))
  309. ((>= offset-y (+ offset-x length-x) -1))
  310. ;; Choose a (non-empty) length
  311. (do ((length-y (if (< offset-y offset-x)
  312. (- offset-x offset-y -1)
  313. 1)
  314. (+ 1 length-y)))
  315. ((>= (+ offset-y length-y) (bytevector-length bv)))
  316. (let ((y (bv-slice/read-write bv offset-y length-y)))
  317. (assert (not (slice-independent? x y)))
  318. (assert (not (slice-independent? y x)))))))))
  319. #true))
  320. (test-end "bv-slice")
  321. ;; ^ TODO: test other procedures