test.scm 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. (import (except (rnrs base) let-values map)
  2. (rnrs exceptions (6))
  3. (only (guile)
  4. lambda* λ
  5. string=?)
  6. (ice-9 exceptions)
  7. (srfi srfi-1) ; list utils
  8. (srfi srfi-64) ; unit testing
  9. (srfi srfi-43) ; vectors
  10. ;; modules under test
  11. (ck-base)
  12. (rename (ck-extra) (<?> <?>))
  13. (contract)
  14. (exceptions))
  15. (test-begin "test")
  16. (test-group "ck-base"
  17. (test-equal "c-cons conses a number onto every sublist"
  18. '((10 1) (10 2))
  19. (ck ()
  20. (c-quote
  21. (c-map '(c-cons '10)
  22. '((1) (2))))))
  23. (test-equal "c-cons conses a + onto every sublist"
  24. '((+ 1) (+ 2))
  25. (ck ()
  26. (c-quote
  27. (c-map '(c-cons '+)
  28. '((1) (2))))))
  29. (test-eqv "c-cons conses a function onto a list to make a function call"
  30. 3
  31. (ck () (c-cons '+ '(1 2))))
  32. (test-equal "c-map maps to all elements of a list - 1"
  33. '((10 1) (10 2))
  34. (ck ()
  35. (c-quote
  36. (c-map '(c-cons '10)
  37. '((1) (2))))))
  38. (test-equal "c-map maps to all elements of a list - 2"
  39. '((+ 1) (+ 2))
  40. (ck ()
  41. (c-quote
  42. (c-map '(c-cons '+)
  43. '((1) (2))))))
  44. (test-equal "c-map maps to all elements of a list - 3"
  45. '(((lambda (elem) (+ elem 1)) 1)
  46. ((lambda (elem) (+ elem 1)) 2))
  47. (ck ()
  48. (c-quote
  49. (c-map
  50. ;; cons an immediately applied function
  51. '(c-cons '(lambda (elem) (+ elem 1)))
  52. '((1) (2))))))
  53. (test-equal "c-apply applies procedure to list of arguments - 1"
  54. 5
  55. (ck ()
  56. (c-apply '+
  57. (c-map '(c-cons '(lambda (elem) (+ elem 1)))
  58. '((1) (2))))))
  59. (test-equal "c-apply applies procedure to list of arguments - 2"
  60. 6
  61. (let ([result 3])
  62. (ck ()
  63. (c-replace-placeholder 'result
  64. '(apply + (list 1 2 <?>))))))
  65. (test-equal "c-quote quotes things"
  66. '((anything 1) (anything 2))
  67. (ck ()
  68. (c-quote
  69. (c-map '(c-cons 'anything)
  70. '((1) (2))))))
  71. (test-equal "c-unquote unquotes things"
  72. 'x
  73. (ck () (c-unquote ''x))))
  74. (test-group "ck-extra"
  75. ;; Cannot use test-error here, because test-error has a
  76. ;; bug, which causes the test to pass, even if the wrong
  77. ;; exception is raised.
  78. (test-assert "c-and-raise raises a contract violation for a trivial case."
  79. (guard (exn
  80. [(and (contract-violated-exception? exn)
  81. (exception-with-message? exn)
  82. (exception-with-origin? exn)
  83. (string=? (exception-origin exn)
  84. "unknown origin")
  85. (exception-with-irritants? exn))
  86. #t])
  87. (ck ()
  88. (c-and-raise
  89. (quote "unknown origin")
  90. (quote (list (= 1 1)
  91. ;; Here something wrong ...
  92. (= 2 3)))))))
  93. (test-assert "c-and-raise does not raise an exception when all expressions are true."
  94. (ck ()
  95. (c-and-raise
  96. (quote "unknown origin")
  97. (quote (list (= 1 1))))))
  98. (test-eqv "c-replace-placeholder replaces the placeholder in a simple expression"
  99. 6
  100. (let ([result 3])
  101. (ck ()
  102. (c-replace-placeholder
  103. (quote result)
  104. (quote (+ 1 2 <?>))))))
  105. (test-equal "c-replace-placeholder replaces the placeholder in a list"
  106. '(1 2 3)
  107. (let ([result 3])
  108. (ck ()
  109. (c-replace-placeholder
  110. (quote result)
  111. (quote (list 1 2 <?>))))))
  112. (test-equal "c-replace-placeholder replaces the placeholder in a compound expression"
  113. '(1 2 3)
  114. (let ([result 7])
  115. (ck ()
  116. (c-replace-placeholder
  117. (quote result)
  118. (quote
  119. (list 1
  120. 2
  121. (vector-index (λ (elem) (= elem <?>))
  122. (vector 4 5 6 7 8))))))))
  123. (test-equal "c-replace-placeholder replaces the placeholder multiple times in a compound expression"
  124. '(1 2 7 3)
  125. (let ([result 7])
  126. (ck ()
  127. (c-replace-placeholder
  128. (quote result)
  129. (quote
  130. (list 1
  131. 2
  132. <?>
  133. (vector-index (λ (elem) (= elem <?>))
  134. (vector 4 5 6 7 8))))))))
  135. (test-equal "c-list->vector converts a list to a vector - 1"
  136. (vector 1 2 3)
  137. (ck ()
  138. (c-list->vector '(list 1 2 3))))
  139. (test-equal "c-list->vector converts a list to a vector - 2"
  140. (vector 1 2 3)
  141. (ck ()
  142. (c-list->vector ''(1 2 3))))
  143. (test-equal "c-vector->list converts a vector to a list - 1"
  144. (list 1 2 3)
  145. (ck ()
  146. (c-vector->list '(vector 1 2 3))))
  147. (test-equal "c-vector->list converts a vector to a list - 2"
  148. (list 1 2 3)
  149. (ck ()
  150. (c-vector->list '#(1 2 3)))))
  151. (test-group "contract"
  152. (test-group "lambda*-with-contract"
  153. (test-equal "lambda*-with-contract - contract does not raise an exception when not violated"
  154. "00234"
  155. ((lambda*-with-contract
  156. (require (integer? num)
  157. (char? padding-char)
  158. (integer? padding-length)
  159. (or (positive? padding-length)
  160. (zero? padding-length)))
  161. (ensure (string? <?>)
  162. (>= (string-length <?>) padding-length))
  163. (num padding-char padding-length)
  164. (let* ([num-as-str (number->string num)]
  165. [len-diff (- padding-length
  166. (string-length num-as-str))])
  167. (cond
  168. [(positive? len-diff)
  169. (call-with-output-string
  170. (λ (port)
  171. (let iter ([counter 0])
  172. (cond
  173. [(< counter len-diff)
  174. (display padding-char port)
  175. (iter (+ counter 1))]
  176. [else
  177. (display num-as-str port)]))))]
  178. [else num-as-str]))) 234 #\0 5))
  179. (test-assert "lambda*-with-contract - raises when requirement violated"
  180. (guard (exn
  181. [(and (contract-violated-exception? exn)
  182. ;; check message
  183. (exception-with-message? exn)
  184. (string=? (exception-message exn)
  185. "contract violated")
  186. ;; check origin
  187. (exception-with-origin? exn)
  188. (string=? (exception-origin exn)
  189. "unknown origin")
  190. ;; check irritants
  191. (exception-with-irritants? exn)
  192. (equal? '(integer? num)
  193. (exception-irritants exn)))
  194. #t])
  195. ((lambda*-with-contract
  196. (require (integer? num)
  197. (char? padding-char)
  198. (integer? padding-length)
  199. (or (positive? padding-length)
  200. (zero? padding-length)))
  201. (ensure (string? <?>)
  202. (>= (string-length <?>) padding-length))
  203. (num padding-char padding-length)
  204. (let* ([num-as-str (number->string num)]
  205. [len-diff (- padding-length
  206. (string-length num-as-str))])
  207. (cond
  208. [(positive? len-diff)
  209. (call-with-output-string
  210. (λ (port)
  211. (let iter ([counter 0])
  212. (cond
  213. [(< counter len-diff)
  214. (display padding-char port)
  215. (iter (+ counter 1))]
  216. [else
  217. (display num-as-str port)]))))]
  218. [else num-as-str]))) "234" #\0 5)))
  219. (test-assert "lambda*-with-contract - raises when ensure violated"
  220. (guard (exn [(and (contract-violated-exception? exn)
  221. ;; check message
  222. (exception-with-message? exn)
  223. (string=? (exception-message exn)
  224. "contract violated")
  225. ;; check origin
  226. (exception-with-origin? exn)
  227. (string=? (exception-origin exn)
  228. "unknown origin")
  229. ;; check irritants
  230. (exception-with-irritants? exn)
  231. (equal? '(>= (string-length result)
  232. padding-length)
  233. (exception-irritants exn)))
  234. #t])
  235. ((lambda*-with-contract
  236. (require (integer? num)
  237. (char? padding-char)
  238. (integer? padding-length)
  239. (or (positive? padding-length)
  240. (zero? padding-length)))
  241. (ensure (string? <?>)
  242. (>= (string-length <?>) padding-length))
  243. (num padding-char padding-length)
  244. (let* ([num-as-str (number->string num)]
  245. [len-diff (- padding-length
  246. (string-length num-as-str))])
  247. (cond
  248. [(positive? len-diff)
  249. (call-with-output-string
  250. (λ (port)
  251. (let iter ([counter 0])
  252. ;; Making a mistake here by using <=
  253. ;; instead of <, in order to fail the
  254. ;; ensure.
  255. (when (<= counter len-diff)
  256. (display padding-char port)
  257. (iter (+ counter 1)))
  258. (display num-as-str port))))]
  259. [else num-as-str]))) 234 #\0 5)))
  260. (test-assert "lambda*-with-contract - works with optional args"
  261. (guard (exn [(and (contract-violated-exception? exn)
  262. ;; check message
  263. (exception-with-message? exn)
  264. (string=? (exception-message exn)
  265. "contract violated")
  266. ;; check origin
  267. (exception-with-origin? exn)
  268. (string=? (exception-origin exn)
  269. "unknown origin")
  270. ;; check irritants
  271. (exception-with-irritants? exn)
  272. (equal? '(char? padding-char)
  273. (exception-irritants exn)))
  274. #t])
  275. ((lambda*-with-contract
  276. (require (integer? num)
  277. (char? padding-char)
  278. (integer? padding-length)
  279. (or (positive? padding-length)
  280. (zero? padding-length)))
  281. (ensure (string? <?>)
  282. (>= (string-length <?>) padding-length))
  283. (num padding-length #:optional (padding-char #\0))
  284. (let* ([num-as-str (number->string num)]
  285. [len-diff (- padding-length
  286. (string-length num-as-str))])
  287. (cond
  288. [(positive? len-diff)
  289. (call-with-output-string
  290. (λ (port)
  291. (let iter ([counter 0])
  292. (when (< counter len-diff)
  293. (display padding-char port)
  294. (iter (+ counter 1)))
  295. (display num-as-str port))))]
  296. [else num-as-str]))) 234 5 "9")))
  297. (test-assert "lambda*-with-contract - works with keyword args"
  298. (guard (exn [(and (contract-violated-exception? exn)
  299. ;; check message
  300. (exception-with-message? exn)
  301. (string=? (exception-message exn)
  302. "contract violated")
  303. ;; check origin
  304. (exception-with-origin? exn)
  305. (string=? (exception-origin exn)
  306. "unknown origin")
  307. ;; check irritants
  308. (exception-with-irritants? exn)
  309. (equal? '(char? padding-char)
  310. (exception-irritants exn)))
  311. #t])
  312. ((lambda*-with-contract
  313. (require (integer? num)
  314. (char? padding-char)
  315. (integer? padding-length)
  316. (or (positive? padding-length)
  317. (zero? padding-length)))
  318. (ensure (string? <?>)
  319. (>= (string-length <?>) padding-length))
  320. (num padding-length #:key (padding-char #\0))
  321. (let* ([num-as-str (number->string num)]
  322. [len-diff (- padding-length
  323. (string-length num-as-str))])
  324. (cond
  325. [(positive? len-diff)
  326. (call-with-output-string
  327. (λ (port)
  328. (let iter ([counter 0])
  329. (when (< counter len-diff)
  330. (display padding-char port)
  331. (iter (+ counter 1)))
  332. (display num-as-str port))))]
  333. [else num-as-str]))) 234 5 #:padding-char "9"))))
  334. (test-group "lambda-with-contract"
  335. (test-eqv "lambda-with-contract - contract does not raise an exception when not violated"
  336. 7
  337. ((lambda-with-contract
  338. (require
  339. ;; The amount withdrawn needs to be less or equal to
  340. ;; the amount on the account.
  341. (<= amount account-balance)
  342. ;; The amount withdrawn needs to be greater or equal
  343. ;; to zero.
  344. (>= amount 0))
  345. (ensure
  346. ;; Make sure, that the amount on the account after
  347. ;; withdrawing an amount is greater or equal to
  348. ;; zero.
  349. (>= <?> 0))
  350. (amount account-balance)
  351. (- account-balance amount))
  352. ;; Try to withdraw 5 from the account.
  353. 5
  354. ;; The account has 12.
  355. 12))
  356. (test-assert "lambda-with-contract - simple number contract works"
  357. (guard (exn
  358. [(and (contract-violated-exception? exn)
  359. ;; check message
  360. (exception-with-message? exn)
  361. (string=? (exception-message exn)
  362. "contract violated")
  363. ;; check origin
  364. (exception-with-origin? exn)
  365. (string=? (exception-origin exn)
  366. "unknown origin")
  367. ;; check irritants
  368. (exception-with-irritants? exn)
  369. (equal? '(<= amount account-balance)
  370. (exception-irritants exn)))
  371. #t])
  372. ((lambda-with-contract
  373. (require (<= amount account-balance)
  374. (>= amount 0))
  375. (ensure (>= <?> 0))
  376. (amount account-balance)
  377. (- account-balance amount)) 100 90)))
  378. (test-assert "lambda-with-contract - simple number contract works with negative numbers"
  379. (guard (exn
  380. [(and (contract-violated-exception? exn)
  381. ;; check message
  382. (exception-with-message? exn)
  383. (string=? (exception-message exn)
  384. "contract violated")
  385. ;; check origin
  386. (exception-with-origin? exn)
  387. (string=? (exception-origin exn)
  388. "unknown origin")
  389. ;; check irritants
  390. (exception-with-irritants? exn)
  391. (equal? '(>= amount 0)
  392. (exception-irritants exn)))
  393. #t])
  394. ((lambda-with-contract
  395. (require (<= amount account-balance)
  396. (>= amount 0))
  397. (ensure (>= <?> 0))
  398. (amount account-balance)
  399. (- account-balance amount)) -15 -10))))
  400. (test-group "define-with-contract"
  401. (test-eqv "define-with-contract - does not raise an exception when not violated"
  402. 7
  403. (begin
  404. (define-with-contract account-withdraw
  405. (require (<= amount account-balance)
  406. (>= amount 0))
  407. (ensure (>= <?> 0))
  408. (λ (amount account-balance)
  409. (- account-balance amount)))
  410. (account-withdraw 5 12)))
  411. (test-assert "define-with-contract - simple number contract works"
  412. (guard (exn
  413. [(and (contract-violated-exception? exn)
  414. ;; check message
  415. (exception-with-message? exn)
  416. (string=? (exception-message exn)
  417. "contract violated")
  418. ;; check origin
  419. (exception-with-origin? exn)
  420. (eq? (exception-origin exn)
  421. 'account-withdraw)
  422. ;; check irritants
  423. (exception-with-irritants? exn)
  424. (equal? '(<= amount account-balance)
  425. (exception-irritants exn)))
  426. #t])
  427. (begin
  428. (define-with-contract account-withdraw
  429. (require (<= amount account-balance)
  430. (>= amount 0))
  431. (ensure (>= <?> 0))
  432. (λ (amount account-balance)
  433. (- account-balance amount)))
  434. (account-withdraw 100 90))))
  435. (test-assert "define-with-contract - simple number contract works with negative numbers"
  436. (guard (exn
  437. [(and (contract-violated-exception? exn)
  438. ;; check message
  439. (exception-with-message? exn)
  440. (string=? (exception-message exn)
  441. "contract violated")
  442. ;; check origin
  443. (exception-with-origin? exn)
  444. (eq? (exception-origin exn)
  445. 'account-withdraw)
  446. ;; check irritants
  447. (exception-with-irritants? exn)
  448. (equal? '(>= amount 0)
  449. (exception-irritants exn)))
  450. #t])
  451. (begin
  452. (define-with-contract account-withdraw
  453. (require (<= amount account-balance)
  454. (>= amount 0))
  455. (ensure (>= <?> 0))
  456. (λ (amount account-balance)
  457. (- account-balance amount)))
  458. (account-withdraw -15 -10)))))
  459. (test-group "define*-with-contract"
  460. (test-eqv "define*-with-contract - does not raise an exception when not violated - long form"
  461. 55
  462. (begin
  463. (define*-with-contract account-withdraw
  464. (require (<= amount account-balance)
  465. (>= amount 0))
  466. (ensure (>= <?> 0))
  467. (amount account-balance #:optional (fee 0) #:key (tip 10))
  468. (- account-balance
  469. amount
  470. fee
  471. tip))
  472. (account-withdraw 50 120 5 #:tip 10)))
  473. (test-eqv "define*-with-contract - does not raise an exception when not violated - short form"
  474. 55
  475. (begin
  476. (define*-with-contract (account-withdraw amount
  477. account-balance
  478. #:optional (fee 0)
  479. #:key (tip 10))
  480. (require (<= amount account-balance)
  481. (>= amount 0))
  482. (ensure (>= <?> 0))
  483. (- account-balance
  484. amount
  485. fee
  486. tip))
  487. (account-withdraw 50 120 5 #:tip 10)))
  488. (test-assert "define*-with-contract - simple number contract works"
  489. (guard (exn
  490. [(and (contract-violated-exception? exn)
  491. ;; check message
  492. (exception-with-message? exn)
  493. (string=? (exception-message exn)
  494. "contract violated")
  495. ;; check origin
  496. (exception-with-origin? exn)
  497. (eq? (exception-origin exn)
  498. 'account-withdraw-extra)
  499. ;; check irritants
  500. (exception-with-irritants? exn)
  501. (equal? '(>= result 0)
  502. (exception-irritants exn)))
  503. #t])
  504. (begin
  505. (define*-with-contract account-withdraw-extra
  506. (require (<= amount account-balance)
  507. (>= amount 0))
  508. (ensure (>= <?> 0))
  509. (amount account-balance #:optional (fee 0) #:key (tip 10))
  510. (- account-balance
  511. amount
  512. fee
  513. tip))
  514. (account-withdraw-extra 50 90 30 #:tip 15))))
  515. (test-assert "define*-with-contract - number contract works with negative numbers"
  516. (guard (exn
  517. [(and (contract-violated-exception? exn)
  518. ;; check message
  519. (exception-with-message? exn)
  520. (string=? (exception-message exn)
  521. "contract violated")
  522. ;; check origin
  523. (exception-with-origin? exn)
  524. (eq? (exception-origin exn)
  525. 'account-withdraw-extra)
  526. ;; check irritants
  527. (exception-with-irritants? exn)
  528. (equal? '(>= result 0)
  529. (exception-irritants exn)))
  530. #t])
  531. (begin
  532. (define*-with-contract account-withdraw-extra
  533. (require (<= amount account-balance))
  534. (ensure (>= <?> 0))
  535. (amount account-balance #:optional (fee 0) #:key (tip 10))
  536. (- account-balance
  537. amount
  538. fee
  539. tip))
  540. (account-withdraw-extra -20 10 30 #:tip 1)))))
  541. (test-group "lambda-aliases"
  542. (test-equal "λ*-with-contract - contract does not raise an exception when not violated"
  543. "00234"
  544. ((λ*-with-contract
  545. (require (integer? num)
  546. (char? padding-char)
  547. (integer? padding-length)
  548. (or (positive? padding-length)
  549. (zero? padding-length)))
  550. (ensure (string? <?>)
  551. (>= (string-length <?>) padding-length))
  552. (num padding-char padding-length)
  553. (let* ([num-as-str (number->string num)]
  554. [len-diff (- padding-length
  555. (string-length num-as-str))])
  556. (cond
  557. [(positive? len-diff)
  558. (call-with-output-string
  559. (λ (port)
  560. (let iter ([counter 0])
  561. (cond
  562. [(< counter len-diff)
  563. (display padding-char port)
  564. (iter (+ counter 1))]
  565. [else
  566. (display num-as-str port)]))))]
  567. [else num-as-str]))) 234 #\0 5))
  568. (test-eqv "λ-with-contract - contract does not raise an exception when not violated"
  569. 7
  570. ((λ-with-contract
  571. (require (<= amount account-balance)
  572. (>= amount 0))
  573. (ensure (>= <?> 0))
  574. (amount account-balance)
  575. (- account-balance amount)) 5 12)))
  576. (test-group "rest-argument-definitions"
  577. (test-equal "define-with-contract - with rest args - contract does not raise an exception when not violated"
  578. 5
  579. (begin
  580. (define-with-contract account-withdraw
  581. (require (<= amount account-balance)
  582. (fold (λ (current accumulated)
  583. (and accumulated current))
  584. #t
  585. (map positive? other-fees)))
  586. (ensure (>= <?> 0))
  587. (amount account-balance . other-fees)
  588. (apply - account-balance amount other-fees))
  589. (account-withdraw 40 100 50 5)))
  590. (test-equal "define*-with-contract - with rest args - contract does not raise an exception when not violated"
  591. 10
  592. (begin
  593. (define*-with-contract account-withdraw
  594. (require (<= amount account-balance)
  595. (fold (λ (current accumulated)
  596. (and accumulated current))
  597. #t
  598. (map positive? other-fees)))
  599. (ensure (>= <?> 0))
  600. (amount account-balance #:optional (fee1 5) #:key (fee2 10) . other-fees)
  601. (apply -
  602. account-balance
  603. amount
  604. fee1
  605. fee2
  606. other-fees))
  607. (account-withdraw 40 100 30 1 2 3 4)))
  608. (test-assert "define*-with-contract - with rest args - raises for require violation"
  609. (guard (exn
  610. [(and (contract-violated-exception? exn)
  611. ;; check message
  612. (exception-with-message? exn)
  613. (string=? (exception-message exn)
  614. "contract violated")
  615. ;; check origin
  616. (exception-with-origin? exn)
  617. (eq? (exception-origin exn)
  618. 'account-withdraw)
  619. ;; check irritants
  620. (exception-with-irritants? exn)
  621. (equal? '(<= amount account-balance)
  622. (exception-irritants exn)))
  623. #t])
  624. (begin
  625. (define*-with-contract account-withdraw
  626. (require (<= amount account-balance)
  627. (fold (λ (current accumulated)
  628. (and accumulated current))
  629. #t
  630. (map positive? other-fees)))
  631. (ensure (>= <?> 0))
  632. (amount account-balance #:optional (fee1 5) #:key (fee2 10) . other-fees)
  633. (apply -
  634. account-balance
  635. amount
  636. fee1
  637. fee2
  638. other-fees))
  639. (account-withdraw 400 100))))
  640. (test-assert "define*-with-contract - with rest args - raises for ensure violation"
  641. (guard (exn
  642. [(and (contract-violated-exception? exn)
  643. ;; check message
  644. (exception-with-message? exn)
  645. (string=? (exception-message exn)
  646. "contract violated")
  647. ;; check origin
  648. (exception-with-origin? exn)
  649. (eq? (exception-origin exn)
  650. 'account-withdraw)
  651. ;; check irritants
  652. (exception-with-irritants? exn)
  653. (equal? '(>= result 0)
  654. (exception-irritants exn)))
  655. #t])
  656. (begin
  657. (define*-with-contract account-withdraw
  658. (require (<= amount account-balance)
  659. (fold (λ (current accumulated)
  660. (and accumulated current))
  661. #t
  662. (map positive? other-fees)))
  663. (ensure (>= <?> 0))
  664. (amount account-balance #:optional (fee1 5) #:key (fee2 10) . other-fees)
  665. (apply -
  666. account-balance
  667. amount
  668. fee1
  669. fee2
  670. 200
  671. other-fees))
  672. (account-withdraw 50 100))))
  673. (test-assert "define*-with-contract - with rest args - raises for violation of rest args"
  674. (guard (exn
  675. [(and (contract-violated-exception? exn)
  676. ;; check message
  677. (exception-with-message? exn)
  678. (string=? (exception-message exn)
  679. "contract violated")
  680. ;; check origin
  681. (exception-with-origin? exn)
  682. (eq? (exception-origin exn)
  683. 'account-withdraw)
  684. ;; check irritants
  685. (exception-with-irritants? exn)
  686. (equal? '(fold (λ (current accumulated)
  687. (and accumulated current))
  688. #t
  689. (map positive? other-fees))
  690. (exception-irritants exn)))
  691. #t])
  692. (begin
  693. (define*-with-contract account-withdraw
  694. (require (<= amount account-balance)
  695. (fold (λ (current accumulated)
  696. (and accumulated current))
  697. #t
  698. (map positive? other-fees)))
  699. (ensure (>= <?> 0))
  700. (amount account-balance #:optional (fee1 5) #:key (fee2 10) . other-fees)
  701. (apply -
  702. account-balance
  703. amount
  704. fee1
  705. fee2
  706. 200
  707. other-fees))
  708. (account-withdraw 50 100 1 2 3 4 -5))))
  709. (test-assert "lambda*-with-contract - with rest args - works"
  710. (guard (exn
  711. [(and (contract-violated-exception? exn)
  712. ;; check message
  713. (exception-with-message? exn)
  714. (string=? (exception-message exn)
  715. "contract violated")
  716. ;; check origin
  717. (exception-with-origin? exn)
  718. (eq? (exception-origin exn)
  719. "unknown origin")
  720. ;; check irritants
  721. (exception-with-irritants? exn)
  722. (equal? '(fold (λ (current accumulated)
  723. (and accumulated current))
  724. #t
  725. (map positive? other-fees))
  726. (exception-irritants exn)))
  727. #t])
  728. ((lambda*-with-contract
  729. (require (<= amount account-balance)
  730. (fold (λ (current accumulated)
  731. (and accumulated current))
  732. #t
  733. (map positive? other-fees)))
  734. (ensure (>= <?> 0))
  735. (amount account-balance #:optional (fee1 5) #:key (fee2 10) . other-fees)
  736. (apply -
  737. account-balance
  738. amount
  739. other-fees)) 50 100 1 2 3 4 -5)))))
  740. (test-end "test")
  741. ;; ====================
  742. ;; c-list->vector usage
  743. ;; ====================
  744. ;; (ck ()
  745. ;; (c-list->vector ''(a b c)))
  746. ;; (ck ()
  747. ;; (c-list->vector '(list 1 2 3)))