1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-02 04:40:29 +02:00
guile/test-suite/tests/srfi-1.test
2004-12-06 00:41:41 +00:00

926 lines
24 KiB
Scheme

;;;; srfi-1.test --- Test suite for Guile's SRFI-1 functions. -*- scheme -*-
;;;;
;;;; Copyright 2003, 2004 Free Software Foundation, Inc.
;;;;
;;;; This program is free software; you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation; either version 2, or (at your option)
;;;; any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this software; see the file COPYING. If not, write to
;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
;;;; Boston, MA 02111-1307 USA
(use-modules (srfi srfi-1)
(test-suite lib))
(define (ref-delete x lst . proc)
"Reference implemenation of srfi-1 `delete'."
(set! proc (if (null? proc) equal? (car proc)))
(do ((ret '())
(lst lst (cdr lst)))
((null? lst)
(reverse! ret))
(if (not (proc x (car lst)))
(set! ret (cons (car lst) ret)))))
(define (ref-delete-duplicates lst . proc)
"Reference implemenation of srfi-1 `delete-duplicates'."
(set! proc (if (null? proc) equal? (car proc)))
(if (null? lst)
'()
(do ((keep '()))
((null? lst)
(reverse! keep))
(let ((elem (car lst)))
(set! keep (cons elem keep))
(set! lst (ref-delete elem lst proc))))))
;;
;; alist-copy
;;
(with-test-prefix "alist-copy"
;; return a list which is the pairs making up alist A, the spine and cells
(define (alist-pairs a)
(let more ((a a)
(result a))
(if (pair? a)
(more (cdr a) (cons a result))
result)))
;; return a list of the elements common to lists X and Y, compared with eq?
(define (common-elements x y)
(if (null? x)
'()
(if (memq (car x) y)
(cons (car x) (common-elements (cdr x) y))
(common-elements (cdr x) y))))
;; validate an alist-copy of OLD to NEW
;; lists must be equal, and must comprise new pairs
(define (valid-alist-copy? old new)
(and (equal? old new)
(null? (common-elements old new))))
(pass-if-exception "too few args" exception:wrong-num-args
(alist-copy))
(pass-if-exception "too many args" exception:wrong-num-args
(alist-copy '() '()))
(let ((old '()))
(pass-if old (valid-alist-copy? old (alist-copy old))))
(let ((old '((1 . 2))))
(pass-if old (valid-alist-copy? old (alist-copy old))))
(let ((old '((1 . 2) (3 . 4))))
(pass-if old (valid-alist-copy? old (alist-copy old))))
(let ((old '((1 . 2) (3 . 4) (5 . 6))))
(pass-if old (valid-alist-copy? old (alist-copy old)))))
;;
;; alist-delete
;;
(with-test-prefix "alist-delete"
(pass-if "equality call arg order"
(let ((good #f))
(alist-delete 'k '((ak . 123))
(lambda (k ak)
(if (and (eq? k 'k) (eq? ak 'ak))
(set! good #t))))
good))
(pass-if "delete keys greater than 5"
(equal? '((4 . x) (5 . y))
(alist-delete 5 '((4 . x) (5 . y) (6 . z)) <)))
(pass-if "empty"
(equal? '() (alist-delete 'x '())))
(pass-if "(y)"
(equal? '() (alist-delete 'y '((y . 1)))))
(pass-if "(n)"
(equal? '((n . 1)) (alist-delete 'y '((n . 1)))))
(pass-if "(y y)"
(equal? '() (alist-delete 'y '((y . 1) (y . 2)))))
(pass-if "(n y)"
(equal? '((n . 1)) (alist-delete 'y '((n . 1) (y . 2)))))
(pass-if "(y n)"
(equal? '((n . 2)) (alist-delete 'y '((y . 1) (n . 2)))))
(pass-if "(n n)"
(equal? '((n . 1) (n . 2)) (alist-delete 'y '((n . 1) (n . 2)))))
(pass-if "(y y y)"
(equal? '() (alist-delete 'y '((y . 1) (y . 2) (y . 3)))))
(pass-if "(n y y)"
(equal? '((n . 1)) (alist-delete 'y '((n . 1) (y . 2) (y . 3)))))
(pass-if "(y n y)"
(equal? '((n . 2)) (alist-delete 'y '((y . 1) (n . 2) (y . 3)))))
(pass-if "(n n y)"
(equal? '((n . 1) (n . 2)) (alist-delete 'y '((n . 1) (n . 2) (y . 3)))))
(pass-if "(y y n)"
(equal? '( (n . 3)) (alist-delete 'y '((y . 1) (y . 2) (n . 3)))))
(pass-if "(n y n)"
(equal? '((n . 1) (n . 3)) (alist-delete 'y '((n . 1) (y . 2) (n . 3)))))
(pass-if "(y n n)"
(equal? '((n . 2) (n . 3)) (alist-delete 'y '((y . 1) (n . 2) (n . 3)))))
(pass-if "(n n n)"
(equal? '((n . 1) (n . 2) (n . 3)) (alist-delete 'y '((n . 1) (n . 2) (n . 3))))))
;;
;; append-map
;;
(with-test-prefix "append-map"
(with-test-prefix "one list"
(pass-if "()"
(equal? '() (append-map noop '(()))))
(pass-if "(1)"
(equal? '(1) (append-map noop '((1)))))
(pass-if "(1 2)"
(equal? '(1 2) (append-map noop '((1 2)))))
(pass-if "() ()"
(equal? '() (append-map noop '(() ()))))
(pass-if "() (1)"
(equal? '(1) (append-map noop '(() (1)))))
(pass-if "() (1 2)"
(equal? '(1 2) (append-map noop '(() (1 2)))))
(pass-if "(1) (2)"
(equal? '(1 2) (append-map noop '((1) (2)))))
(pass-if "(1 2) ()"
(equal? '(1 2) (append-map noop '(() (1 2))))))
(with-test-prefix "two lists"
(pass-if "() / 9"
(equal? '() (append-map noop '(()) '(9))))
(pass-if "(1) / 9"
(equal? '(1) (append-map noop '((1)) '(9))))
(pass-if "() () / 9 9"
(equal? '() (append-map noop '(() ()) '(9 9))))
(pass-if "(1) (2) / 9"
(equal? '(1) (append-map noop '((1) (2)) '(9))))
(pass-if "(1) (2) / 9 9"
(equal? '(1 2) (append-map noop '((1) (2)) '(9 9))))))
;;
;; break
;;
(with-test-prefix "break"
(define (test-break lst want-v1 want-v2)
(call-with-values
(lambda ()
(break negative? lst))
(lambda (got-v1 got-v2)
(and (equal? got-v1 want-v1)
(equal? got-v2 want-v2)))))
(pass-if "empty"
(test-break '() '() '()))
(pass-if "y"
(test-break '(1) '(1) '()))
(pass-if "n"
(test-break '(-1) '() '(-1)))
(pass-if "yy"
(test-break '(1 2) '(1 2) '()))
(pass-if "ny"
(test-break '(-1 1) '() '(-1 1)))
(pass-if "yn"
(test-break '(1 -1) '(1) '(-1)))
(pass-if "nn"
(test-break '(-1 -2) '() '(-1 -2)))
(pass-if "yyy"
(test-break '(1 2 3) '(1 2 3) '()))
(pass-if "nyy"
(test-break '(-1 1 2) '() '(-1 1 2)))
(pass-if "yny"
(test-break '(1 -1 2) '(1) '(-1 2)))
(pass-if "nny"
(test-break '(-1 -2 1) '() '(-1 -2 1)))
(pass-if "yyn"
(test-break '(1 2 -1) '(1 2) '(-1)))
(pass-if "nyn"
(test-break '(-1 1 -2) '() '(-1 1 -2)))
(pass-if "ynn"
(test-break '(1 -1 -2) '(1) '(-1 -2)))
(pass-if "nnn"
(test-break '(-1 -2 -3) '() '(-1 -2 -3))))
;;
;; concatenate and concatenate!
;;
(let ()
(define (common-tests concatenate-proc unmodified?)
(define (try lstlst want)
(let ((lstlst-copy (copy-tree lstlst))
(got (concatenate-proc lstlst)))
(if unmodified?
(if (not (equal? lstlst lstlst-copy))
(error "input lists modified")))
(equal? got want)))
(pass-if-exception "too few args" exception:wrong-num-args
(concatenate-proc))
(pass-if-exception "too many args" exception:wrong-num-args
(concatenate-proc '() '()))
(pass-if "no lists"
(try '() '()))
(pass-if (try '((1)) '(1)))
(pass-if (try '((1 2)) '(1 2)))
(pass-if (try '(() (1)) '(1)))
(pass-if (try '(() () (1)) '(1)))
(pass-if (try '((1) (2)) '(1 2)))
(pass-if (try '(() (1 2)) '(1 2)))
(pass-if (try '((1) 2) '(1 . 2)))
(pass-if (try '((1) (2) 3) '(1 2 . 3)))
(pass-if (try '((1) (2) (3 . 4)) '(1 2 3 . 4)))
)
(with-test-prefix "concatenate"
(common-tests concatenate #t))
(with-test-prefix "concatenate!"
(common-tests concatenate! #f)))
;;
;; count
;;
(with-test-prefix "count"
(pass-if-exception "no args" exception:wrong-num-args
(count))
(pass-if-exception "one arg" exception:wrong-num-args
(count noop))
(with-test-prefix "one list"
(define (or1 x)
x)
(pass-if "empty list" (= 0 (count or1 '())))
(pass-if-exception "pred arg count 0" exception:wrong-type-arg
(count (lambda () x) '(1 2 3)))
(pass-if-exception "pred arg count 2" exception:wrong-type-arg
(count (lambda (x y) x) '(1 2 3)))
(pass-if-exception "improper 1" exception:wrong-type-arg
(count or1 1))
(pass-if-exception "improper 2" exception:wrong-type-arg
(count or1 '(1 . 2)))
(pass-if-exception "improper 3" exception:wrong-type-arg
(count or1 '(1 2 . 3)))
(pass-if (= 0 (count or1 '(#f))))
(pass-if (= 1 (count or1 '(#t))))
(pass-if (= 0 (count or1 '(#f #f))))
(pass-if (= 1 (count or1 '(#f #t))))
(pass-if (= 1 (count or1 '(#t #f))))
(pass-if (= 2 (count or1 '(#t #t))))
(pass-if (= 0 (count or1 '(#f #f #f))))
(pass-if (= 1 (count or1 '(#f #f #t))))
(pass-if (= 1 (count or1 '(#t #f #f))))
(pass-if (= 2 (count or1 '(#t #f #t))))
(pass-if (= 3 (count or1 '(#t #t #t)))))
(with-test-prefix "two lists"
(define (or2 x y)
(or x y))
(pass-if "arg order"
(= 1 (count (lambda (x y)
(and (= 1 x)
(= 2 y)))
'(1) '(2))))
(pass-if "empty lists" (= 0 (count or2 '() '())))
(pass-if-exception "pred arg count 0" exception:wrong-type-arg
(count (lambda () #t) '(1 2 3) '(1 2 3)))
(pass-if-exception "pred arg count 1" exception:wrong-type-arg
(count (lambda (x) x) '(1 2 3) '(1 2 3)))
(pass-if-exception "pred arg count 3" exception:wrong-type-arg
(count (lambda (x y z) x) '(1 2 3) '(1 2 3)))
(pass-if-exception "improper first 1" exception:wrong-type-arg
(count or2 1 '(1 2 3)))
(pass-if-exception "improper first 2" exception:wrong-type-arg
(count or2 '(1 . 2) '(1 2 3)))
(pass-if-exception "improper first 3" exception:wrong-type-arg
(count or2 '(1 2 . 3) '(1 2 3)))
(pass-if-exception "improper second 1" exception:wrong-type-arg
(count or2 '(1 2 3) 1))
(pass-if-exception "improper second 2" exception:wrong-type-arg
(count or2 '(1 2 3) '(1 . 2)))
(pass-if-exception "improper second 3" exception:wrong-type-arg
(count or2 '(1 2 3) '(1 2 . 3)))
(pass-if (= 0 (count or2 '(#f) '(#f))))
(pass-if (= 1 (count or2 '(#t) '(#f))))
(pass-if (= 1 (count or2 '(#f) '(#t))))
(pass-if (= 0 (count or2 '(#f #f) '(#f #f))))
(pass-if (= 1 (count or2 '(#t #f) '(#t #f))))
(pass-if (= 2 (count or2 '(#t #t) '(#f #f))))
(pass-if (= 2 (count or2 '(#t #f) '(#f #t))))
(with-test-prefix "stop shortest"
(pass-if (= 2 (count or2 '(#t #f #t) '(#f #t))))
(pass-if (= 2 (count or2 '(#t #f #t #t) '(#f #t))))
(pass-if (= 2 (count or2 '(#t #f) '(#f #t #t))))
(pass-if (= 2 (count or2 '(#t #f) '(#f #t #t #t))))))
(with-test-prefix "three lists"
(define (or3 x y z)
(or x y z))
(pass-if "arg order"
(= 1 (count (lambda (x y z)
(and (= 1 x)
(= 2 y)
(= 3 z)))
'(1) '(2) '(3))))
(pass-if "empty lists" (= 0 (count or3 '() '() '())))
;; currently bad pred argument gives wrong-num-args when 3 or more
;; lists, as opposed to wrong-type-arg for 1 or 2 lists
(pass-if-exception "pred arg count 0" exception:wrong-num-args
(count (lambda () #t) '(1 2 3) '(1 2 3) '(1 2 3)))
(pass-if-exception "pred arg count 2" exception:wrong-num-args
(count (lambda (x y) x) '(1 2 3) '(1 2 3)'(1 2 3) ))
(pass-if-exception "pred arg count 4" exception:wrong-num-args
(count (lambda (w x y z) x) '(1 2 3) '(1 2 3) '(1 2 3)))
(pass-if-exception "improper first 1" exception:wrong-type-arg
(count or3 1 '(1 2 3) '(1 2 3)))
(pass-if-exception "improper first 2" exception:wrong-type-arg
(count or3 '(1 . 2) '(1 2 3) '(1 2 3)))
(pass-if-exception "improper first 3" exception:wrong-type-arg
(count or3 '(1 2 . 3) '(1 2 3) '(1 2 3)))
(pass-if-exception "improper second 1" exception:wrong-type-arg
(count or3 '(1 2 3) 1 '(1 2 3)))
(pass-if-exception "improper second 2" exception:wrong-type-arg
(count or3 '(1 2 3) '(1 . 2) '(1 2 3)))
(pass-if-exception "improper second 3" exception:wrong-type-arg
(count or3 '(1 2 3) '(1 2 . 3) '(1 2 3)))
(pass-if-exception "improper third 1" exception:wrong-type-arg
(count or3 '(1 2 3) '(1 2 3) 1))
(pass-if-exception "improper third 2" exception:wrong-type-arg
(count or3 '(1 2 3) '(1 2 3) '(1 . 2)))
(pass-if-exception "improper third 3" exception:wrong-type-arg
(count or3 '(1 2 3) '(1 2 3) '(1 2 . 3)))
(pass-if (= 0 (count or3 '(#f) '(#f) '(#f))))
(pass-if (= 1 (count or3 '(#t) '(#f) '(#f))))
(pass-if (= 1 (count or3 '(#f) '(#t) '(#f))))
(pass-if (= 1 (count or3 '(#f) '(#f) '(#t))))
(pass-if (= 0 (count or3 '(#f #f) '(#f #f) '(#f #f))))
(pass-if (= 1 (count or3 '(#t #f) '(#f #f) '(#f #f))))
(pass-if (= 1 (count or3 '(#f #t) '(#f #f) '(#f #f))))
(pass-if (= 1 (count or3 '(#f #f) '(#t #f) '(#f #f))))
(pass-if (= 1 (count or3 '(#f #f) '(#f #t) '(#f #f))))
(pass-if (= 1 (count or3 '(#f #f) '(#f #f) '(#t #f))))
(pass-if (= 1 (count or3 '(#f #f) '(#f #f) '(#f #t))))
(pass-if (= 2 (count or3 '(#t #t) '(#f #f) '(#f #f))))
(pass-if (= 2 (count or3 '(#f #f) '(#t #t) '(#f #f))))
(pass-if (= 2 (count or3 '(#f #f) '(#f #f) '(#t #t))))
(pass-if (= 2 (count or3 '(#f #f) '(#t #f) '(#f #t))))
(with-test-prefix "stop shortest"
(pass-if (= 0 (count or3 '() '(#t #t #t) '(#t #t))))
(pass-if (= 0 (count or3 '(#t #t #t) '() '(#t #t))))
(pass-if (= 0 (count or3 '(#t #t #t) '(#t #t) '())))
(pass-if (= 1 (count or3 '(#t) '(#t #t #t) '(#t #t))))
(pass-if (= 1 (count or3 '(#t #t #t) '(#t) '(#t #t))))
(pass-if (= 1 (count or3 '(#t #t #t) '(#t #t) '(#t)))))))
;;
;; delete and delete!
;;
(let ()
;; Call (PROC lst) for all lists of length up to 6, with all combinations
;; of elements to be retained or deleted. Elements to retain are numbers,
;; 0 upwards. Elements to be deleted are #f.
(define (test-lists proc)
(do ((n 0 (1+ n)))
((>= n 6))
(do ((limit (ash 1 n))
(i 0 (1+ i)))
((>= i limit))
(let ((lst '()))
(do ((bit 0 (1+ bit)))
((>= bit n))
(set! lst (cons (if (logbit? bit i) bit #f) lst)))
(proc lst)))))
(define (common-tests delete-proc)
(pass-if-exception "too few args" exception:wrong-num-args
(delete-proc 0))
(pass-if-exception "too many args" exception:wrong-num-args
(delete-proc 0 '() equal? 99))
(pass-if "empty"
(eq? '() (delete-proc 0 '())))
(pass-if "equal? (the default)"
(equal? '((1) (3))
(delete-proc '(2) '((1) (2) (3)))))
(pass-if "eq?"
(equal? '((1) (2) (3))
(delete-proc '(2) '((1) (2) (3)) eq?)))
(pass-if "called arg order"
(equal? '(1 2 3)
(delete-proc 3 '(1 2 3 4 5) <))))
(with-test-prefix "delete"
(common-tests delete)
(test-lists
(lambda (lst)
(let ((lst-copy (list-copy lst)))
(with-test-prefix lst-copy
(pass-if "result"
(equal? (delete #f lst)
(ref-delete #f lst)))
(pass-if "non-destructive"
(equal? lst-copy lst)))))))
(with-test-prefix "delete!"
(common-tests delete!)
(test-lists
(lambda (lst)
(pass-if lst
(equal? (delete! #f lst)
(ref-delete #f lst)))))))
;;
;; delete-duplicates and delete-duplicates!
;;
(let ()
;; Call (PROC lst) for all lists of length 1 <= n <= 4, with all
;; combinations of numbers 1 to n in the elements
(define (test-lists proc)
(do ((n 1 (1+ n)))
((> n 4))
(do ((limit (integer-expt n n))
(i 0 (1+ i)))
((>= i limit))
(let ((lst '()))
(do ((j 0 (1+ j))
(rem i (quotient rem n)))
((>= j n))
(set! lst (cons (remainder rem n) lst)))
(proc lst)))))
(define (common-tests delete-duplicates-proc)
(pass-if-exception "too few args" exception:wrong-num-args
(delete-duplicates-proc))
(pass-if-exception "too many args" exception:wrong-num-args
(delete-duplicates-proc '() equal? 99))
(pass-if "empty"
(eq? '() (delete-duplicates-proc '())))
(pass-if "equal? (the default)"
(equal? '((2))
(delete-duplicates-proc '((2) (2) (2)))))
(pass-if "eq?"
(equal? '((2) (2) (2))
(delete-duplicates-proc '((2) (2) (2)) eq?)))
(pass-if "called arg order"
(let ((ok #t))
(delete-duplicates-proc '(1 2 3 4 5)
(lambda (x y)
(if (> x y)
(set! ok #f))
#f))
ok)))
(with-test-prefix "delete-duplicates"
(common-tests delete-duplicates)
(test-lists
(lambda (lst)
(let ((lst-copy (list-copy lst)))
(with-test-prefix lst-copy
(pass-if "result"
(equal? (delete-duplicates lst)
(ref-delete-duplicates lst)))
(pass-if "non-destructive"
(equal? lst-copy lst)))))))
(with-test-prefix "delete-duplicates!"
(common-tests delete-duplicates!)
(test-lists
(lambda (lst)
(pass-if lst
(equal? (delete-duplicates! lst)
(ref-delete-duplicates lst)))))))
;;
;; drop
;;
(with-test-prefix "drop"
(pass-if "'() 0"
(null? (drop '() 0)))
(pass-if "'(a) 0"
(let ((lst '(a)))
(eq? lst
(drop lst 0))))
(pass-if "'(a b) 0"
(let ((lst '(a b)))
(eq? lst
(drop lst 0))))
(pass-if "'(a) 1"
(let ((lst '(a)))
(eq? (cdr lst)
(drop lst 1))))
(pass-if "'(a b) 1"
(let ((lst '(a b)))
(eq? (cdr lst)
(drop lst 1))))
(pass-if "'(a b) 2"
(let ((lst '(a b)))
(eq? (cddr lst)
(drop lst 2))))
(pass-if "'(a b c) 1"
(let ((lst '(a b c)))
(eq? (cddr lst)
(drop lst 2))))
(pass-if "circular '(a) 0"
(let ((lst (circular-list 'a)))
(eq? lst
(drop lst 0))))
(pass-if "circular '(a) 1"
(let ((lst (circular-list 'a)))
(eq? lst
(drop lst 1))))
(pass-if "circular '(a) 2"
(let ((lst (circular-list 'a)))
(eq? lst
(drop lst 1))))
(pass-if "circular '(a b) 1"
(let ((lst (circular-list 'a)))
(eq? (cdr lst)
(drop lst 0))))
(pass-if "circular '(a b) 2"
(let ((lst (circular-list 'a)))
(eq? lst
(drop lst 1))))
(pass-if "circular '(a b) 5"
(let ((lst (circular-list 'a)))
(eq? (cdr lst)
(drop lst 5))))
(pass-if "'(a . b) 1"
(eq? 'b
(drop '(a . b) 1)))
(pass-if "'(a b . c) 1"
(equal? 'c
(drop '(a b . c) 2))))
;;
;; filter-map
;;
(with-test-prefix "filter-map"
(with-test-prefix "one list"
(pass-if "(1)"
(equal? '(1) (filter-map noop '(1))))
(pass-if "(#f)"
(equal? '() (filter-map noop '(#f))))
(pass-if "(1 2)"
(equal? '(1 2) (filter-map noop '(1 2))))
(pass-if "(#f 2)"
(equal? '(2) (filter-map noop '(#f 2))))
(pass-if "(#f #f)"
(equal? '() (filter-map noop '(#f #f))))
(pass-if "(1 2 3)"
(equal? '(1 2 3) (filter-map noop '(1 2 3))))
(pass-if "(#f 2 3)"
(equal? '(2 3) (filter-map noop '(#f 2 3))))
(pass-if "(1 #f 3)"
(equal? '(1 3) (filter-map noop '(1 #f 3))))
(pass-if "(1 2 #f)"
(equal? '(1 2) (filter-map noop '(1 2 #f)))))
(with-test-prefix "two lists"
(pass-if "(1 2 3) (4 5 6)"
(equal? '(1 2 3) (filter-map noop '(1 2 3) '(4 5 6))))
(pass-if "(#f 2 3) (4 5)"
(equal? '(2) (filter-map noop '(#f 2 3) '(4 5))))
(pass-if "(4 #f) (1 2 3)"
(equal? '(4) (filter-map noop '(4 #f) '(1 2 3))))))
;;
;; length+
;;
(with-test-prefix "length+"
(pass-if-exception "too few args" exception:wrong-num-args
(length+))
(pass-if-exception "too many args" exception:wrong-num-args
(length+ 123 456))
(pass-if (= 0 (length+ '())))
(pass-if (= 1 (length+ '(x))))
(pass-if (= 2 (length+ '(x y))))
(pass-if (= 3 (length+ '(x y z))))
(pass-if (not (length+ (circular-list 1))))
(pass-if (not (length+ (circular-list 1 2))))
(pass-if (not (length+ (circular-list 1 2 3)))))
;;
;; list-copy
;;
(with-test-prefix "list-copy"
(pass-if (equal? '() (list-copy '())))
(pass-if (equal? '(1 2) (list-copy '(1 2))))
(pass-if (equal? '(1 2 3) (list-copy '(1 2 3))))
(pass-if (equal? '(1 2 3 4) (list-copy '(1 2 3 4))))
(pass-if (equal? '(1 2 3 4 5) (list-copy '(1 2 3 4 5))))
;; improper lists can be copied
(pass-if (equal? 1 (list-copy 1)))
(pass-if (equal? '(1 . 2) (list-copy '(1 . 2))))
(pass-if (equal? '(1 2 . 3) (list-copy '(1 2 . 3))))
(pass-if (equal? '(1 2 3 . 4) (list-copy '(1 2 3 . 4))))
(pass-if (equal? '(1 2 3 4 . 5) (list-copy '(1 2 3 4 . 5)))))
;;
;; take
;;
(with-test-prefix "take"
(pass-if "'() 0"
(null? (take '() 0)))
(pass-if "'(a) 0"
(null? (take '(a) 0)))
(pass-if "'(a b) 0"
(null? (take '() 0)))
(pass-if "'(a b c) 0"
(null? (take '() 0)))
(pass-if "'(a) 1"
(let* ((lst '(a))
(got (take lst 1)))
(and (equal? '(a) got)
(not (eq? lst got)))))
(pass-if "'(a b) 1"
(equal? '(a)
(take '(a b) 1)))
(pass-if "'(a b c) 1"
(equal? '(a)
(take '(a b c) 1)))
(pass-if "'(a b) 2"
(let* ((lst '(a b))
(got (take lst 2)))
(and (equal? '(a b) got)
(not (eq? lst got)))))
(pass-if "'(a b c) 2"
(equal? '(a b)
(take '(a b c) 2)))
(pass-if "circular '(a) 0"
(equal? '()
(take (circular-list 'a) 0)))
(pass-if "circular '(a) 1"
(equal? '(a)
(take (circular-list 'a) 1)))
(pass-if "circular '(a) 2"
(equal? '(a a)
(take (circular-list 'a) 2)))
(pass-if "circular '(a b) 5"
(equal? '(a b a b a)
(take (circular-list 'a 'b) 5)))
(pass-if "'(a . b) 1"
(equal? '(a)
(take '(a . b) 1)))
(pass-if "'(a b . c) 1"
(equal? '(a)
(take '(a b . c) 1)))
(pass-if "'(a b . c) 2"
(equal? '(a b)
(take '(a b . c) 2))))
;;
;; partition
;;
(define (test-partition pred list kept-good dropped-good)
(call-with-values (lambda ()
(partition pred list))
(lambda (kept dropped)
(and (equal? kept kept-good)
(equal? dropped dropped-good)))))
(with-test-prefix "partition"
(pass-if "with dropped tail"
(test-partition even? '(1 2 3 4 5 6 7)
'(2 4 6) '(1 3 5 7)))
(pass-if "with kept tail"
(test-partition even? '(1 2 3 4 5 6)
'(2 4 6) '(1 3 5)))
(pass-if "with everything dropped"
(test-partition even? '(1 3 5 7)
'() '(1 3 5 7)))
(pass-if "with everything kept"
(test-partition even? '(2 4 6)
'(2 4 6) '()))
(pass-if "with empty list"
(test-partition even? '()
'() '()))
(pass-if "with reasonably long list"
;; the old implementation from SRFI-1 reference implementation
;; would signal a stack-overflow for a list of only 500 elements!
(call-with-values (lambda ()
(partition even?
(make-list 10000 1)))
(lambda (even odd)
(and (= (length odd) 10000)
(= (length even) 0))))))
;;
;; span
;;
(with-test-prefix "span"
(define (test-span lst want-v1 want-v2)
(call-with-values
(lambda ()
(span positive? lst))
(lambda (got-v1 got-v2)
(and (equal? got-v1 want-v1)
(equal? got-v2 want-v2)))))
(pass-if "empty"
(test-span '() '() '()))
(pass-if "y"
(test-span '(1) '(1) '()))
(pass-if "n"
(test-span '(-1) '() '(-1)))
(pass-if "yy"
(test-span '(1 2) '(1 2) '()))
(pass-if "ny"
(test-span '(-1 1) '() '(-1 1)))
(pass-if "yn"
(test-span '(1 -1) '(1) '(-1)))
(pass-if "nn"
(test-span '(-1 -2) '() '(-1 -2)))
(pass-if "yyy"
(test-span '(1 2 3) '(1 2 3) '()))
(pass-if "nyy"
(test-span '(-1 1 2) '() '(-1 1 2)))
(pass-if "yny"
(test-span '(1 -1 2) '(1) '(-1 2)))
(pass-if "nny"
(test-span '(-1 -2 1) '() '(-1 -2 1)))
(pass-if "yyn"
(test-span '(1 2 -1) '(1 2) '(-1)))
(pass-if "nyn"
(test-span '(-1 1 -2) '() '(-1 1 -2)))
(pass-if "ynn"
(test-span '(1 -1 -2) '(1) '(-1 -2)))
(pass-if "nnn"
(test-span '(-1 -2 -3) '() '(-1 -2 -3))))