;; adapted from the reference implementation (define-library (srfi 113 test) (import (scheme base) (scheme char) (srfi 113) (srfi 128) (chibi test)) (export run-tests) (begin (define equal-comparator (make-equal-comparator)) (define eqv-comparator (make-eqv-comparator)) (define eq-comparator (make-eq-comparator)) (define number-comparator (make-comparator real? = < (lambda (x . o) (exact (abs (round x)))))) (define char-comparator (make-comparator char? char=? char x 5)) (test-group "sets/simple" (define nums (set number-comparator)) ;; nums is now {} (define syms (set eq-comparator 'a 'b 'c 'd)) ;; syms is now {a, b, c, d} (define nums2 (set-copy nums)) ;; nums2 is now {} (define syms2 (set-copy syms)) ;; syms2 is now {a, b, c, d} (define esyms (set eq-comparator)) ;; esyms is now {} (define total 0) (test-assert (set-empty? esyms)) (test-assert (set? nums)) (test-assert (set? syms)) (test-assert (set? nums2)) (test-assert (set? syms2)) (test-assert (not (set? 'a))) (set! nums (set-adjoin! nums 2)) (set! nums (set-adjoin! nums 3)) (set! nums (set-adjoin! nums 4)) (set! nums (set-adjoin! nums 4)) ;; nums is now {2, 3, 4} (test 4 (set-size (set-adjoin nums 5))) (test 3 (set-size nums)) (test 3 (set-size (set-delete syms 'd))) (test 2 (set-size (set-delete-all syms '(c d)))) (test 4 (set-size syms)) (set! syms (set-adjoin! syms 'e 'f)) ;; syms is now {a, b, c, d, e, f} (test 4 (set-size (set-delete-all! syms '(e f)))) ;; syms is now {a, b, c, d} (test 0 (set-size nums2)) (test 4 (set-size syms2)) (set! nums (set-delete! nums 2)) ;; nums is now {3, 4} (test 2 (set-size nums)) (set! nums (set-delete! nums 1)) (test-assert (set-contains? nums 3)) (test 2 (set-size nums)) (set! nums2 (set-map number-comparator (lambda (x) (* 10 x)) nums)) ;; nums2 is now {30, 40} (test-assert (set-contains? nums2 30)) (test-assert (not (set-contains? nums2 3))) (set-for-each (lambda (x) (set! total (+ total x))) nums2) (test 70 total) (test 10 (set-fold + 3 nums)) (set! nums (set eqv-comparator 10 20 30 40 50)) ;; nums is now {10, 20, 30, 40, 50} (test-assert (set=? nums (set-unfold eqv-comparator (lambda (i) (= i 0)) (lambda (i) (* i 10)) (lambda (i) (- i 1)) 5))) (test '(a) (set->list (set eq-comparator 'a))) (set! syms2 (list->set eq-comparator '(e f))) ;; syms2 is now {e, f} (test 2 (set-size syms2)) (test-assert (set-contains? syms2 'e)) (test-assert (set-contains? syms2 'f)) (test 4 (set-size (list->set! syms2 '(a b)))) ) (test-group "sets/search" (define yam (set char-comparator #\y #\a #\m)) (define (failure/insert insert ignore) (insert 1)) (define (failure/ignore insert ignore) (ignore 2)) (define (success/update element update remove) (update #\b 3)) (define (success/remove element update remove) (remove 4)) (define yam! (set char-comparator #\y #\a #\m #\!)) (define bam (set char-comparator #\b #\a #\m)) (define ym (set char-comparator #\y #\m)) (define-values (set1 obj1) (set-search! (set-copy yam) #\! failure/insert error)) (define-values (set2 obj2) (set-search! (set-copy yam) #\! failure/ignore error)) (define-values (set3 obj3) (set-search! (set-copy yam) #\y error success/update)) (define-values (set4 obj4) (set-search! (set-copy yam) #\a error success/remove)) (test-assert (set=? yam! set1)) (test 1 obj1) (test-assert (set=? yam set2)) (test 2 obj2) (test-assert (set=? bam set3)) (test 3 obj3) (test-assert (set=? ym set4)) (test 4 obj4) ) (test-group "sets/subsets" (define set2 (set number-comparator 1 2)) (define other-set2 (set number-comparator 1 2)) (define set3 (set number-comparator 1 2 3)) (define set4 (set number-comparator 1 2 3 4)) (define setx (set number-comparator 10 20 30 40)) (test-assert (set=? set2 other-set2)) (test-assert (not (set=? set2 set3))) (test-assert (not (set=? set2 set3 other-set2))) (test-assert (set? set4 set3 set2)) (test-assert (not (set>? set2 other-set2))) (test-assert (set>=? set3 other-set2 set2)) (test-assert (not (set>=? other-set2 set3 set2))) ) (test-group "sets/ops" ;; Potentially mutable (define abcd (set eq-comparator 'a 'b 'c 'd)) (define efgh (set eq-comparator 'e 'f 'g 'h)) (define abgh (set eq-comparator 'a 'b 'g 'h)) ;; Never get a chance to be mutated (define other-abcd (set eq-comparator 'a 'b 'c 'd)) (define other-efgh (set eq-comparator 'e 'f 'g 'h)) (define other-abgh (set eq-comparator 'a 'b 'g 'h)) (define all (set eq-comparator 'a 'b 'c 'd 'e 'f 'g 'h)) (define none (set eq-comparator)) (define ab (set eq-comparator 'a 'b)) (define cd (set eq-comparator 'c 'd)) (define ef (set eq-comparator 'e 'f)) (define gh (set eq-comparator 'g 'h)) (define cdgh (set eq-comparator 'c 'd 'g 'h)) (define abcdgh (set eq-comparator 'a 'b 'c 'd 'g 'h)) (define abefgh (set eq-comparator 'a 'b 'e 'f 'g 'h)) (test-assert (set-disjoint? abcd efgh)) (test-assert (not (set-disjoint? abcd ab))) (parameterize ((current-test-comparator set=?)) (test abcd (set-union abcd)) (test all (set-union abcd efgh)) (test abcdgh (set-union abcd abgh)) (test abefgh (set-union efgh abgh)) (let ((efgh2 (set-copy efgh))) (set-union! efgh2) (test efgh efgh2) (set-union! efgh2 abgh) (test abefgh efgh2)) (test abcd (set-intersection abcd)) (test none (set-intersection abcd efgh)) ;; (let ((abcd2 (set-copy abcd))) ;; (set-intersection! abcd2) ;; (test abcd abcd2) ;; (set-intersection! abcd2 efgh) ;; (test none abcd2)) (test ab (set-intersection abcd abgh)) (test ab (set-intersection abgh abcd)) (test abcd (set-difference abcd)) (test cd (set-difference abcd ab)) (test abcd (set-difference abcd gh)) (test none (set-difference abcd abcd)) ;; (let ((abcd3 (set-copy abcd))) ;; (set-difference! abcd3) ;; (test abcd abcd3) ;; (set-difference! abcd3 abcd) ;; (test none abcd3)) (test cdgh (set-xor abcd abgh)) (test all (set-xor abcd efgh)) (test none (set-xor abcd other-abcd)) ;; don't test xor! effect (test none (set-xor! (set-copy abcd) other-abcd)) (test "abcd smashed?" other-abcd abcd) (test "efgh smashed?" other-efgh efgh) (test "abgh smashed?" other-abgh abgh)) ) (test-group "sets/mismatch" (define nums (set number-comparator 1 2 3)) (define syms (set eq-comparator 'a 'b 'c)) (test-error (set=? nums syms)) (test-error (set? nums syms)) (test-error (set>=? nums syms)) (test-error (set-union nums syms)) (test-error (set-intersection nums syms)) (test-error (set-difference nums syms)) (test-error (set-xor nums syms)) (test-error (set-union! nums syms)) (test-error (set-intersection! nums syms)) (test-error (set-difference! nums syms)) (test-error (set-xor! nums syms)) ) (test-group "sets/whole" (define whole (set eqv-comparator 1 2 3 4 5 6 7 8 9 10)) (define whole2 (set-copy whole)) (define whole3 (set-copy whole)) (define whole4 (set-copy whole)) (define bottom (set eqv-comparator 1 2 3 4 5)) (define top (set eqv-comparator 6 7 8 9 10)) (define-values (topx bottomx) (set-partition big whole)) ;; (set-partition! big whole4) (parameterize ((current-test-comparator set=?)) (test top (set-filter big whole)) (test bottom (set-remove big whole)) ;; (set-filter! big whole2) ;; (test-assert (not (set-contains? whole2 1))) ;; (set-remove! big whole3) ;; (test-assert (not (set-contains? whole3 10))) ;; (test top topx) ;; (test bottom bottomx) ;; (test top whole4) ) (test 5 (set-count big whole)) (let ((hetero (set eqv-comparator 1 2 'a 3 4)) (homo (set eqv-comparator 1 2 3 4 5))) (test 'a (set-find symbol? hetero (lambda () (error "wrong")))) (test-error (set-find symbol? homo (lambda () (error "wrong")))) (test-assert (set-any? symbol? hetero)) (test-assert (set-any? number? hetero)) (test-assert (not (set-every? symbol? hetero))) (test-assert (not (set-every? number? hetero))) (test-assert (not (set-any? symbol? homo))) (test-assert (set-every? number? homo))) ) (test-group "sets/lowlevel" (define bucket (set string-ci-comparator "abc" "def")) (define nums (set number-comparator 1 2 3)) ;; nums is now {1, 2, 3} (define nums2 (set-replace nums 2.0)) ;; nums2 is now {1, 2.0, 3} (test string-ci-comparator (set-element-comparator bucket)) (test-assert (set-contains? bucket "abc")) (test-assert (set-contains? bucket "ABC")) (test "def" (set-member bucket "DEF" "fqz")) (test "fqz" (set-member bucket "lmn" "fqz")) (test-assert (set-any? inexact? nums2)) (set! nums (set-replace! nums 2.0)) ;; nums is now {1, 2.0, 3} (test-assert (set-any? inexact? nums)) (let ((sos (set set-comparator (set equal-comparator '(2 . 1) '(1 . 1) '(0 . 2) '(0 . 0)) (set equal-comparator '(2 . 1) '(1 . 1) '(0 . 0) '(0 . 2))))) (test 1 (set-size sos))) ) (test-group "bags/simple" (define nums (bag number-comparator)) ;; nums is now {} (define syms (bag eq-comparator 'a 'b 'c 'd)) ;; syms is now {a, b, c, d} (define nums2 (bag-copy nums)) ;; nums2 is now {} (define syms2 (bag-copy syms)) ;; syms2 is now {a, b, c, d} (define esyms (bag eq-comparator)) ;; esyms is now {} (test-assert (bag-empty? esyms)) (test-assert (bag? nums)) (test-assert (bag? syms)) (test-assert (bag? nums2)) (test-assert (bag? syms2)) (test-assert (not (bag? 'a))) (bag-adjoin! nums 2) (bag-adjoin! nums 3) (bag-adjoin! nums 4) ;; nums is now {2, 3, 4} (test 4 (bag-size (bag-adjoin nums 5))) (test 3 (bag-size nums)) (test 3 (bag-size (bag-delete syms 'd))) (test 2 (bag-size (bag-delete-all syms '(c d)))) (test 4 (bag-size syms)) (bag-adjoin! syms 'e 'f) ;; syms is now {a, b, c, d, e, f} (test 4 (bag-size (bag-delete-all! syms '(e f)))) ;; syms is now {a, b, c, d} (test 3 (bag-size nums)) (bag-delete! nums 1) (test 3 (bag-size nums)) (set! nums2 (bag-map number-comparator (lambda (x) (* 10 x)) nums)) ;; nums2 is now {20, 30, 40} (test-assert (bag-contains? nums2 30)) (test-assert (not (bag-contains? nums2 3))) (let ((total 0)) (bag-for-each (lambda (x) (set! total (+ total x))) nums2) (test 90 total)) (test 12 (bag-fold + 3 nums)) (set! nums (bag eqv-comparator 10 20 30 40 50)) ;; nums is now {10, 20, 30, 40, 50} (test-assert (bag=? nums (bag-unfold eqv-comparator (lambda (i) (= i 0)) (lambda (i) (* i 10)) (lambda (i) (- i 1)) 5))) (test '(a) (bag->list (bag eq-comparator 'a))) (set! syms2 (list->bag eq-comparator '(e f))) ;; syms2 is now {e, f} (test 2 (bag-size syms2)) (test-assert (bag-contains? syms2 'e)) (test-assert (bag-contains? syms2 'f)) (list->bag! syms2 '(e f)) ;; syms2 is now {e, e, f, f} (test 4 (bag-size syms2)) ) (test-group "bags/search" (define yam (bag char-comparator #\y #\a #\m)) (define (failure/insert insert ignore) (insert 1)) (define (failure/ignore insert ignore) (ignore 2)) (define (success/update element update remove) (update #\b 3)) (define (success/remove element update remove) (remove 4)) (define yam! (bag char-comparator #\y #\a #\m #\!)) (define bam (bag char-comparator #\b #\a #\m)) (define ym (bag char-comparator #\y #\m)) (define-values (bag1 obj1) (bag-search! (bag-copy yam) #\! failure/insert error)) (define-values (bag2 obj2) (bag-search! (bag-copy yam) #\! failure/ignore error)) (define-values (bag3 obj3) (bag-search! (bag-copy yam) #\y error success/update)) (define-values (bag4 obj4) (bag-search! (bag-copy yam) #\a error success/remove)) (test-assert (bag=? yam! bag1)) (test 1 obj1) (test-assert (bag=? yam bag2)) (test 2 obj2) (test-assert (bag=? bam bag3)) (test 3 obj3) (test-assert (bag=? ym bag4)) (test 4 obj4) ) (test-group "bags/elemcount" (define mybag (bag eqv-comparator 1 1 1 1 1 2 2)) (test 5 (bag-element-count mybag 1)) (test 0 (bag-element-count mybag 3))) (test-group "bags/subbags" (define bag2 (bag number-comparator 1 2)) (define other-bag2 (bag number-comparator 1 2)) (define bag3 (bag number-comparator 1 2 3)) (define bag4 (bag number-comparator 1 2 3 4)) (define bagx (bag number-comparator 10 20 30 40)) (test-assert (bag=? bag2 other-bag2)) (test-assert (not (bag=? bag2 bag3))) (test-assert (not (bag=? bag2 bag3 other-bag2))) (test-assert (bag? bag4 bag3 bag2)) (test-assert (not (bag>? bag2 other-bag2))) (test-assert (bag>=? bag3 other-bag2 bag2)) (test-assert (not (bag>=? other-bag2 bag3 bag2)))) (test-group "bags/multi" (define one (bag eqv-comparator 10)) (define two (bag eqv-comparator 10 10)) (test-assert (not (bag=? one two))) (test-assert (bag? one two))) (test-assert (bag<=? one two)) (test-assert (not (bag>? one two))) (test-assert (bag=? two two)) (test-assert (not (bag? two two))) (test-assert (bag<=? two two)) (test-assert (bag>=? two two)) (test '((10 . 2)) (let ((result '())) (bag-for-each-unique (lambda (x y) (set! result (cons (cons x y) result))) two) result)) (test 25 (bag-fold + 5 two)) (test 12 (bag-fold-unique (lambda (k n r) (+ k n r)) 0 two))) (test-group "bags/ops" ;; Potentially mutable (define abcd (bag eq-comparator 'a 'b 'c 'd)) (define efgh (bag eq-comparator 'e 'f 'g 'h)) (define abgh (bag eq-comparator 'a 'b 'g 'h)) ;; Never get a chance to be mutated (define other-abcd (bag eq-comparator 'a 'b 'c 'd)) (define other-efgh (bag eq-comparator 'e 'f 'g 'h)) (define other-abgh (bag eq-comparator 'a 'b 'g 'h)) (define all (bag eq-comparator 'a 'b 'c 'd 'e 'f 'g 'h)) (define none (bag eq-comparator)) (define ab (bag eq-comparator 'a 'b)) (define cd (bag eq-comparator 'c 'd)) (define ef (bag eq-comparator 'e 'f)) (define gh (bag eq-comparator 'g 'h)) (define cdgh (bag eq-comparator 'c 'd 'g 'h)) (define abcdgh (bag eq-comparator 'a 'b 'c 'd 'g 'h)) (define abefgh (bag eq-comparator 'a 'b 'e 'f 'g 'h)) (test-assert (bag-disjoint? abcd efgh)) (test-assert (not (bag-disjoint? abcd ab))) (parameterize ((current-test-comparator bag=?)) (test abcd (bag-union abcd)) (test all (bag-union abcd efgh)) (test abcdgh (bag-union abcd abgh)) (test abefgh (bag-union efgh abgh)) (let ((efgh2 (bag-copy efgh))) (bag-union! efgh2) (test efgh efgh2) (bag-union! efgh2 abgh) (test abefgh efgh2)) (test abcd (bag-intersection abcd)) (test none (bag-intersection abcd efgh)) (let ((abcd2 (bag-copy abcd))) (bag-intersection! abcd2) (test abcd abcd2) (bag-intersection! abcd2 efgh) (test none abcd2)) (test ab (bag-intersection abcd abgh)) (test ab (bag-intersection abgh abcd)) (test abcd (bag-difference abcd)) (test cd (bag-difference abcd ab)) (test abcd (bag-difference abcd gh)) (test none (bag-difference abcd abcd)) (let ((abcd3 (bag-copy abcd))) (bag-difference! abcd3) (test abcd abcd3) (bag-difference! abcd3 abcd) (test none abcd3)) (test cdgh (bag-xor abcd abgh)) (test all (bag-xor abcd efgh)) (test none (bag-xor abcd other-abcd)) (test none (bag-xor! (bag-copy abcd) other-abcd)) (let ((abab (bag eq-comparator 'a 'b 'a 'b)) (ab2 (bag-copy ab))) (test ab (bag-sum ab)) (test ab (bag-sum! ab2)) (test abab (bag-sum! ab2 ab)) (test abab ab2) (test abab (bag-product 2 ab)) (let ((ab3 (bag-copy ab))) (bag-product! 2 ab3) (test abab ab3))) (test "abcd smashed?" other-abcd abcd) (test "abcd smashed?" other-abcd abcd) (test "efgh smashed?" other-efgh efgh) (test "abgh smashed?" other-abgh abgh))) (test-group "bags/mismatch" (define nums (bag number-comparator 1 2 3)) (define syms (bag eq-comparator 'a 'b 'c)) (test-error (bag=? nums syms)) (test-error (bag? nums syms)) (test-error (bag>=? nums syms)) (test-error (bag-union nums syms)) (test-error (bag-intersection nums syms)) (test-error (bag-difference nums syms)) (test-error (bag-xor nums syms)) (test-error (bag-union! nums syms)) (test-error (bag-intersection! nums syms)) (test-error (bag-difference! nums syms))) (test-group "bags/whole" (define whole (bag eqv-comparator 1 2 3 4 5 6 7 8 9 10)) (define whole2 (bag-copy whole)) (define whole3 (bag-copy whole)) (define whole4 (bag-copy whole)) (define bottom (bag eqv-comparator 1 2 3 4 5)) (define top (bag eqv-comparator 6 7 8 9 10)) (define-values (topx bottomx) (bag-partition big whole)) (call-with-values (lambda () (bag-partition! big whole4)) (lambda (pass fail) (set! whole4 pass))) (parameterize ((current-test-comparator bag=?)) (test top (bag-filter big whole)) (test bottom (bag-remove big whole)) (set! whole2 (bag-filter! big whole2)) (test-assert (not (bag-contains? whole2 1))) (set! whole3 (bag-remove! big whole3)) (test-assert (not (bag-contains? whole3 10))) (test top topx) (test bottom bottomx) (test top whole4)) (test 5 (bag-count big whole)) (let ((hetero (bag eqv-comparator 1 2 'a 3 4)) (homo (bag eqv-comparator 1 2 3 4 5))) (test 'a (bag-find symbol? hetero (lambda () (error "wrong")))) (test-error (bag-find symbol? homo (lambda () (error "wrong")))) (test-assert (bag-any? symbol? hetero)) (test-assert (bag-any? number? hetero)) (test-assert (not (bag-every? symbol? hetero))) (test-assert (not (bag-every? number? hetero))) (test-assert (not (bag-any? symbol? homo))) (test-assert (bag-every? number? homo)))) (test-group "bags/lowlevel" (define bucket (bag string-ci-comparator "abc" "def")) (define nums (bag number-comparator 1 2 3)) ;; nums is now {1, 2, 3} (define nums2 (bag-replace nums 2.0)) ;; nums2 is now {1, 2.0, 3} (test string-ci-comparator (bag-element-comparator bucket)) (test-assert (bag-contains? bucket "abc")) (test-assert (bag-contains? bucket "ABC")) (test "def" (bag-member bucket "DEF" "fqz")) (test "fqz" (bag-member bucket "lmn" "fqz")) (test-assert (bag-any? inexact? nums2)) (bag-replace! nums 2.0) ;; nums is now {1, 2.0, 3} (test-assert (bag-any? inexact? nums)) (let ((bob (bag bag-comparator (bag eqv-comparator 1 2) (bag eqv-comparator 1 2)))) (test 2 (bag-size bob)))) (test-group "bags/semantics" (define mybag (bag number-comparator 1 2)) ;; mybag is {1, 2} (test 2 (bag-size mybag)) (bag-adjoin! mybag 1) ;; mybag is {1, 1, 2} (test 3 (bag-size mybag)) (test 2 (bag-unique-size mybag)) (bag-delete! mybag 2) ;; mybag is {1, 1} (bag-delete! mybag 2) (test 2 (bag-size mybag)) (bag-increment! mybag 1 3) ;; mybag is {1, 1, 1, 1, 1} (test 5 (bag-size mybag)) (test-assert (bag-decrement! mybag 1 2)) ;; mybag is {1, 1, 1} (test 3 (bag-size mybag)) (bag-decrement! mybag 1 5) ;; mybag is {} (test 0 (bag-size mybag))) (test-group "bags/convert" (define multi (bag eqv-comparator 1 2 2 3 3 3)) (define single (bag eqv-comparator 1 2 3)) (define singleset (set eqv-comparator 1 2 3)) (define minibag (bag eqv-comparator 'a 'a)) (define alist '((a . 2))) (test alist (bag->alist minibag)) (test-assert (bag=? minibag (alist->bag eqv-comparator alist))) (test-assert (set=? singleset (bag->set single))) (test-assert (set=? singleset (bag->set multi))) (test-assert (bag=? single (set->bag singleset))) (test-assert (not (bag=? multi (set->bag singleset)))) (set->bag! minibag singleset) ;; minibag is now {a, a, a, a, 1, 2, 3} (test-assert (bag-contains? minibag 1))) (test-group "bags/sumprod" (define abb (bag eq-comparator 'a 'b 'b)) (define aab (bag eq-comparator 'a 'a 'b)) (define total (bag-sum abb aab)) (test 3 (bag-count (lambda (x) (eqv? x 'a)) total)) (test 3 (bag-count (lambda (x) (eqv? x 'b)) total)) (test 12 (bag-size (bag-product 2 total))) (let ((bag1 (bag eqv-comparator 1))) (bag-sum! bag1 bag1) (test 2 (bag-size bag1)) (bag-product! 2 bag1) (test 4 (bag-size bag1))) ) (test-group "comparators" (define a (set number-comparator 1 2 3)) (define b (set number-comparator 1 2 4)) (define aa (bag number-comparator 1 2 3)) (define bb (bag number-comparator 1 2 4)) (test-assert (not (=? set-comparator a b))) (test-assert (=? set-comparator a (set-copy a))) ;;(test-error (