123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710 |
- ;;;; list.test --- tests guile's lists -*- scheme -*-
- ;;;; Copyright (C) 2000, 2001, 2006, 2011 Free Software Foundation, Inc.
- ;;;;
- ;;;; This library is free software; you can redistribute it and/or
- ;;;; modify it under the terms of the GNU Lesser General Public
- ;;;; License as published by the Free Software Foundation; either
- ;;;; version 3 of the License, or (at your option) any later version.
- ;;;;
- ;;;; This library 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
- ;;;; Lesser General Public License for more details.
- ;;;;
- ;;;; You should have received a copy of the GNU Lesser General Public
- ;;;; License along with this library; if not, write to the Free Software
- ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- (use-modules (test-suite lib)
- (ice-9 documentation))
- ;;;
- ;;; miscellaneous
- ;;;
- (define (documented? object)
- (not (not (object-documentation object))))
- ;;
- ;; This unique tag is reserved for the unroll and diff-unrolled functions.
- ;;
- (define circle-indicator
- (cons 'circle 'indicator))
- ;;
- ;; Extract every single scheme object that is contained within OBJ into a new
- ;; data structure. That means, if OBJ somewhere contains a pair, the newly
- ;; created structure holds a reference to the pair as well as references to
- ;; the car and cdr of that pair. For vectors, the newly created structure
- ;; holds a reference to that vector as well as references to every element of
- ;; that vector. Since this is done recursively, the original data structure
- ;; is deeply unrolled. If there are circles within the original data
- ;; structures, every reference that points backwards into the data structure
- ;; is denoted by storing the circle-indicator tag as well as the object the
- ;; circular reference points to.
- ;;
- (define (unroll obj)
- (let unroll* ((objct obj)
- (hist '()))
- (reverse!
- (let loop ((object objct)
- (histry hist)
- (result '()))
- (if (memq object histry)
- (cons (cons circle-indicator object) result)
- (let ((history (cons object histry)))
- (cond ((pair? object)
- (loop (cdr object) history
- (cons (cons object (unroll* (car object) history))
- result)))
- ((vector? object)
- (cons (cons object
- (map (lambda (x)
- (unroll* x history))
- (vector->list object)))
- result))
- (else (cons object result)))))))))
- ;;
- ;; Compare two data-structures that were generated with unroll. If any of the
- ;; elements found not to be eq?, return a pair that holds the position of the
- ;; first found differences of the two data structures. If all elements are
- ;; found to be eq?, #f is returned.
- ;;
- (define (diff-unrolled a b)
- (cond ;; has everything been compared already?
- ((and (null? a) (null? b))
- #f)
- ;; do both structures still contain elements?
- ((and (pair? a) (pair? b))
- (cond ;; are the next elements both plain objects?
- ((and (not (pair? (car a))) (not (pair? (car b))))
- (if (eq? (car a) (car b))
- (diff-unrolled (cdr a) (cdr b))
- (cons a b)))
- ;; are the next elements both container objects?
- ((and (pair? (car a)) (pair? (car b)))
- (if (eq? (caar a) (caar b))
- (cond ;; do both objects close a circular structure?
- ((eq? circle-indicator (caar a))
- (if (eq? (cdar a) (cdar b))
- (diff-unrolled (cdr a) (cdr b))
- (cons a b)))
- ;; do both objects hold a vector?
- ((vector? (caar a))
- (or (let loop ((a1 (cdar a)) (b1 (cdar b)))
- (cond
- ((and (null? a1) (null? b1))
- #f)
- ((and (pair? a1) (pair? b1))
- (or (diff-unrolled (car a1) (car b1))
- (loop (cdr a1) (cdr b1))))
- (else
- (cons a1 b1))))
- (diff-unrolled (cdr a) (cdr b))))
- ;; do both objects hold a pair?
- (else
- (or (diff-unrolled (cdar a) (cdar b))
- (diff-unrolled (cdr a) (cdr b)))))
- (cons a b)))
- (else
- (cons a b))))
- (else
- (cons a b))))
- ;;; list
- (with-test-prefix "list"
- (pass-if "documented?"
- (documented? list))
- ;; in guile 1.6.7 and earlier `list' called using `apply' didn't make a
- ;; new list, it just returned the given list
- (pass-if "apply gets fresh list"
- (let* ((x '(1 2 3))
- (y (apply list x)))
- (not (eq? x y)))))
- ;;; make-list
- (with-test-prefix "make-list"
- (pass-if "documented?"
- (documented? make-list))
- (with-test-prefix "no init"
- (pass-if "0"
- (equal? '() (make-list 0)))
- (pass-if "1"
- (equal? '(()) (make-list 1)))
- (pass-if "2"
- (equal? '(() ()) (make-list 2)))
- (pass-if "3"
- (equal? '(() () ()) (make-list 3))))
- (with-test-prefix "with init"
- (pass-if "0"
- (equal? '() (make-list 0 'foo)))
- (pass-if "1"
- (equal? '(foo) (make-list 1 'foo)))
- (pass-if "2"
- (equal? '(foo foo) (make-list 2 'foo)))
- (pass-if "3"
- (equal? '(foo foo foo) (make-list 3 'foo)))))
- ;;; cons*
- (with-test-prefix "cons*"
- (pass-if "documented?"
- (documented? list))
- (with-test-prefix "one arg"
- (pass-if "empty list"
- (eq? '() (cons* '())))
- (pass-if "one elem list"
- (let* ((lst '(1)))
- (eq? lst (cons* lst))))
- (pass-if "two elem list"
- (let* ((lst '(1 2)))
- (eq? lst (cons* lst)))))
- (with-test-prefix "two args"
- (pass-if "empty list"
- (equal? '(1) (cons* 1 '())))
- (pass-if "one elem list"
- (let* ((lst '(1))
- (ret (cons* 2 lst)))
- (and (equal? '(2 1) ret)
- (eq? lst (cdr ret)))))
- (pass-if "two elem list"
- (let* ((lst '(1 2))
- (ret (cons* 3 lst)))
- (and (equal? '(3 1 2) ret)
- (eq? lst (cdr ret))))))
- (with-test-prefix "three args"
- (pass-if "empty list"
- (equal? '(1 2) (cons* 1 2 '())))
- (pass-if "one elem list"
- (let* ((lst '(1))
- (ret (cons* 2 3 lst)))
- (and (equal? '(2 3 1) ret)
- (eq? lst (cddr ret)))))
- (pass-if "two elem list"
- (let* ((lst '(1 2))
- (ret (cons* 3 4 lst)))
- (and (equal? '(3 4 1 2) ret)
- (eq? lst (cddr ret))))))
- ;; in guile 1.6.7 and earlier `cons*' called using `apply' modified its
- ;; list argument
- (pass-if "apply list unchanged"
- (let* ((lst '(1 2 (3 4)))
- (ret (apply cons* lst)))
- (and (equal? lst '(1 2 (3 4)))
- (equal? ret '(1 2 3 4))))))
- ;;; null?
- ;;; list?
- ;;; length
- ;;; append
- ;;;
- ;;; append!
- ;;;
- (with-test-prefix "append!"
- (pass-if "documented?"
- (documented? append!))
- ;; Is the handling of empty lists as arguments correct?
- (pass-if "no arguments"
- (eq? (append!)
- '()))
- (pass-if "empty list argument"
- (eq? (append! '())
- '()))
- (pass-if "some empty list arguments"
- (eq? (append! '() '() '())
- '()))
- ;; Does the last non-empty-list argument remain unchanged?
- (pass-if "some empty lists with non-empty list"
- (let* ((foo (list 1 2))
- (foo-unrolled (unroll foo))
- (tst (append! '() '() '() foo))
- (tst-unrolled (unroll tst)))
- (and (eq? tst foo)
- (not (diff-unrolled foo-unrolled tst-unrolled)))))
- (pass-if "some empty lists with improper list"
- (let* ((foo (cons 1 2))
- (foo-unrolled (unroll foo))
- (tst (append! '() '() '() foo))
- (tst-unrolled (unroll tst)))
- (and (eq? tst foo)
- (not (diff-unrolled foo-unrolled tst-unrolled)))))
- (pass-if "some empty lists with circular list"
- (let ((foo (list 1 2)))
- (set-cdr! (cdr foo) (cdr foo))
- (let* ((foo-unrolled (unroll foo))
- (tst (append! '() '() '() foo))
- (tst-unrolled (unroll tst)))
- (and (eq? tst foo)
- (not (diff-unrolled foo-unrolled tst-unrolled))))))
- (pass-if "some empty lists with non list object"
- (let* ((foo (vector 1 2 3))
- (foo-unrolled (unroll foo))
- (tst (append! '() '() '() foo))
- (tst-unrolled (unroll tst)))
- (and (eq? tst foo)
- (not (diff-unrolled foo-unrolled tst-unrolled)))))
- (pass-if "non-empty list between empty lists"
- (let* ((foo (list 1 2))
- (foo-unrolled (unroll foo))
- (tst (append! '() '() '() foo '() '() '()))
- (tst-unrolled (unroll tst)))
- (and (eq? tst foo)
- (not (diff-unrolled foo-unrolled tst-unrolled)))))
- ;; Are arbitrary lists append!ed correctly?
- (pass-if "two one-element lists"
- (let* ((foo (list 1))
- (foo-unrolled (unroll foo))
- (bar (list 2))
- (bar-unrolled (unroll bar))
- (tst (append! foo bar))
- (tst-unrolled (unroll tst))
- (diff-foo-tst (diff-unrolled foo-unrolled tst-unrolled)))
- (and (equal? tst '(1 2))
- (not (diff-unrolled (car diff-foo-tst) (unroll '())))
- (not (diff-unrolled bar-unrolled (cdr diff-foo-tst))))))
- (pass-if "three one-element lists"
- (let* ((foo (list 1))
- (foo-unrolled (unroll foo))
- (bar (list 2))
- (bar-unrolled (unroll bar))
- (baz (list 3))
- (baz-unrolled (unroll baz))
- (tst (append! foo bar baz))
- (tst-unrolled (unroll tst))
- (diff-foo-tst (diff-unrolled foo-unrolled tst-unrolled)))
- (and (equal? tst '(1 2 3))
- (not (diff-unrolled (car diff-foo-tst) (unroll '())))
- (let* ((tst-unrolled-2 (cdr diff-foo-tst))
- (diff-foo-bar (diff-unrolled bar-unrolled tst-unrolled-2)))
- (and (not (diff-unrolled (car diff-foo-bar) (unroll '())))
- (not (diff-unrolled baz-unrolled (cdr diff-foo-bar))))))))
- (pass-if "two two-element lists"
- (let* ((foo (list 1 2))
- (foo-unrolled (unroll foo))
- (bar (list 3 4))
- (bar-unrolled (unroll bar))
- (tst (append! foo bar))
- (tst-unrolled (unroll tst))
- (diff-foo-tst (diff-unrolled foo-unrolled tst-unrolled)))
- (and (equal? tst '(1 2 3 4))
- (not (diff-unrolled (car diff-foo-tst) (unroll '())))
- (not (diff-unrolled bar-unrolled (cdr diff-foo-tst))))))
-
- (pass-if "three two-element lists"
- (let* ((foo (list 1 2))
- (foo-unrolled (unroll foo))
- (bar (list 3 4))
- (bar-unrolled (unroll bar))
- (baz (list 5 6))
- (baz-unrolled (unroll baz))
- (tst (append! foo bar baz))
- (tst-unrolled (unroll tst))
- (diff-foo-tst (diff-unrolled foo-unrolled tst-unrolled)))
- (and (equal? tst '(1 2 3 4 5 6))
- (not (diff-unrolled (car diff-foo-tst) (unroll '())))
- (let* ((tst-unrolled-2 (cdr diff-foo-tst))
- (diff-foo-bar (diff-unrolled bar-unrolled tst-unrolled-2)))
- (and (not (diff-unrolled (car diff-foo-bar) (unroll '())))
- (not (diff-unrolled baz-unrolled (cdr diff-foo-bar))))))))
- (pass-if "empty list between non-empty lists"
- (let* ((foo (list 1 2))
- (foo-unrolled (unroll foo))
- (bar (list 3 4))
- (bar-unrolled (unroll bar))
- (baz (list 5 6))
- (baz-unrolled (unroll baz))
- (tst (append! foo '() bar '() '() baz '() '() '()))
- (tst-unrolled (unroll tst))
- (diff-foo-tst (diff-unrolled foo-unrolled tst-unrolled)))
- (and (equal? tst '(1 2 3 4 5 6))
- (not (diff-unrolled (car diff-foo-tst) (unroll '())))
- (let* ((tst-unrolled-2 (cdr diff-foo-tst))
- (diff-foo-bar (diff-unrolled bar-unrolled tst-unrolled-2)))
- (and (not (diff-unrolled (car diff-foo-bar) (unroll '())))
- (not (diff-unrolled baz-unrolled (cdr diff-foo-bar))))))))
- (pass-if "list and improper list"
- (let* ((foo (list 1 2))
- (foo-unrolled (unroll foo))
- (bar (cons 3 4))
- (bar-unrolled (unroll bar))
- (tst (append! foo bar))
- (tst-unrolled (unroll tst))
- (diff-foo-tst (diff-unrolled foo-unrolled tst-unrolled)))
- (and (equal? tst '(1 2 3 . 4))
- (not (diff-unrolled (car diff-foo-tst) (unroll '())))
- (not (diff-unrolled bar-unrolled (cdr diff-foo-tst))))))
- (pass-if "list and circular list"
- (let* ((foo (list 1 2))
- (foo-unrolled (unroll foo))
- (bar (list 3 4 5)))
- (set-cdr! (cddr bar) (cdr bar))
- (let* ((bar-unrolled (unroll bar))
- (tst (append! foo bar))
- (tst-unrolled (unroll tst))
- (diff-foo-tst (diff-unrolled foo-unrolled tst-unrolled)))
- (and (equal? (map (lambda (n x) (eqv? (list-ref tst n) x))
- (iota 9)
- '(1 2 3 4 5 4 5 4 5))
- '(#t #t #t #t #t #t #t #t #t))
- (not (diff-unrolled (car diff-foo-tst) (unroll '())))
- (not (diff-unrolled bar-unrolled (cdr diff-foo-tst)))))))
- (pass-if "list and non list object"
- (let* ((foo (list 1 2))
- (foo-unrolled (unroll foo))
- (bar (vector 3 4))
- (bar-unrolled (unroll bar))
- (tst (append! foo bar))
- (tst-unrolled (unroll tst))
- (diff-foo-tst (diff-unrolled foo-unrolled tst-unrolled)))
- (and (equal? tst '(1 2 . #(3 4)))
- (not (diff-unrolled (car diff-foo-tst) (unroll '())))
- (not (diff-unrolled bar-unrolled (cdr diff-foo-tst))))))
- (pass-if "several arbitrary lists"
- (equal? (append! (list 1 2)
- (list (list 3) 4)
- (list (list 5) (list 6))
- (list 7 (cons 8 9))
- (list 10 11)
- (list (cons 12 13) 14)
- (list (list)))
- (list 1 2
- (list 3) 4
- (list 5) (list 6)
- 7 (cons 8 9)
- 10 11
- (cons 12 13)
- 14 (list))))
- (pass-if "list to itself"
- (let* ((foo (list 1 2))
- (foo-unrolled (unroll foo))
- (tst (append! foo foo))
- (tst-unrolled (unroll tst))
- (diff-foo-tst (diff-unrolled foo-unrolled tst-unrolled)))
- (and (equal? (map (lambda (n x) (eqv? (list-ref tst n) x))
- (iota 6)
- '(1 2 1 2 1 2))
- '(#t #t #t #t #t #t))
- (not (diff-unrolled (car diff-foo-tst) (unroll '())))
- (eq? (caar (cdr diff-foo-tst)) circle-indicator)
- (eq? (cdar (cdr diff-foo-tst)) foo))))
- ;; Are wrong type arguments detected correctly?
- (with-test-prefix "wrong argument"
- (pass-if-exception "improper list and empty list"
- exception:wrong-type-arg
- (append! (cons 1 2) '()))
- (pass-if-exception "improper list and list"
- exception:wrong-type-arg
- (append! (cons 1 2) (list 3 4)))
- (pass-if-exception "list, improper list and list"
- exception:wrong-type-arg
- (append! (list 1 2) (cons 3 4) (list 5 6)))
- (expect-fail "circular list and empty list"
- (let ((foo (list 1 2 3)))
- (set-cdr! (cddr foo) (cdr foo))
- (catch #t
- (lambda ()
- (catch 'wrong-type-arg
- (lambda ()
- (append! foo '())
- #f)
- (lambda (key . args)
- #t)))
- (lambda (key . args)
- #f))))
- (expect-fail "circular list and list"
- (let ((foo (list 1 2 3)))
- (set-cdr! (cddr foo) (cdr foo))
- (catch #t
- (lambda ()
- (catch 'wrong-type-arg
- (lambda ()
- (append! foo (list 4 5))
- #f)
- (lambda (key . args)
- #t)))
- (lambda (key . args)
- #f))))
- (expect-fail "list, circular list and list"
- (let ((foo (list 3 4 5)))
- (set-cdr! (cddr foo) (cdr foo))
- (catch #t
- (lambda ()
- (catch 'wrong-type-arg
- (lambda ()
- (append! (list 1 2) foo (list 6 7))
- #f)
- (lambda (key . args)
- #t)))
- (lambda (key . args)
- #f))))))
- ;;; last-pair
- ;;; reverse
- ;;; reverse!
- ;;; list-ref
- (with-test-prefix "list-ref"
- (pass-if "documented?"
- (documented? list-ref))
- (with-test-prefix "argument error"
-
- (with-test-prefix "non list argument"
- #t)
- (with-test-prefix "improper list argument"
- #t)
- (with-test-prefix "non integer index"
- #t)
- (with-test-prefix "index out of range"
- (with-test-prefix "empty list"
- (pass-if-exception "index 0"
- exception:out-of-range
- (list-ref '() 0))
- (pass-if-exception "index > 0"
- exception:out-of-range
- (list-ref '() 1))
- (pass-if-exception "index < 0"
- exception:out-of-range
- (list-ref '() -1)))
- (with-test-prefix "non-empty list"
- (pass-if-exception "index > length"
- exception:out-of-range
- (list-ref '(1) 1))
- (pass-if-exception "index < 0"
- exception:out-of-range
- (list-ref '(1) -1))))))
- ;;; list-set!
- (with-test-prefix "list-set!"
- (pass-if "documented?"
- (documented? list-set!))
- (with-test-prefix "argument error"
-
- (with-test-prefix "non list argument"
- #t)
- (with-test-prefix "improper list argument"
- #t)
- (with-test-prefix "read-only list argument"
- #t)
- (with-test-prefix "non integer index"
- #t)
- (with-test-prefix "index out of range"
- (with-test-prefix "empty list"
- (pass-if-exception "index 0"
- exception:out-of-range
- (list-set! (list) 0 #t))
- (pass-if-exception "index > 0"
- exception:out-of-range
- (list-set! (list) 1 #t))
- (pass-if-exception "index < 0"
- exception:out-of-range
- (list-set! (list) -1 #t)))
- (with-test-prefix "non-empty list"
- (pass-if-exception "index > length"
- exception:out-of-range
- (list-set! (list 1) 1 #t))
- (pass-if-exception "index < 0"
- exception:out-of-range
- (list-set! (list 1) -1 #t))))))
- ;;; list-cdr-ref
- ;;; list-tail
- ;;; list-cdr-set!
- (with-test-prefix "list-cdr-set!"
- (pass-if "documented?"
- (documented? list-cdr-set!))
- (with-test-prefix "argument error"
-
- (with-test-prefix "non list argument"
- #t)
- (with-test-prefix "improper list argument"
- #t)
- (with-test-prefix "read-only list argument"
- #t)
- (with-test-prefix "non integer index"
- #t)
- (with-test-prefix "index out of range"
- (with-test-prefix "empty list"
- (pass-if-exception "index 0"
- exception:out-of-range
- (list-cdr-set! (list) 0 #t))
- (pass-if-exception "index > 0"
- exception:out-of-range
- (list-cdr-set! (list) 1 #t))
- (pass-if-exception "index < 0"
- exception:out-of-range
- (list-cdr-set! (list) -1 #t)))
- (with-test-prefix "non-empty list"
- (pass-if-exception "index > length"
- exception:out-of-range
- (list-cdr-set! (list 1) 1 #t))
- (pass-if-exception "index < 0"
- exception:out-of-range
- (list-cdr-set! (list 1) -1 #t))))))
- ;;; list-head
- ;;; list-copy
- ;;; memq
- (with-test-prefix/c&e "memq"
- (pass-if "inline"
- ;; In this case `memq' is inlined and the loop is unrolled.
- (equal? '(b c d) (memq 'b '(a b c d))))
- (pass-if "non inline"
- ;; In this case a real function call is generated.
- (equal? '(b c d) (memq 'b (list 'a 'b 'c 'd)))))
- ;;; memv
- (with-test-prefix/c&e "memv"
- (pass-if "inline"
- ;; In this case `memv' is inlined and the loop is unrolled.
- (equal? '(b c d) (memv 'b '(a b c d))))
- (pass-if "non inline"
- ;; In this case a real function call is generated.
- (equal? '(b c d) (memv 'b (list 'a 'b 'c 'd)))))
- ;;; member
- ;;; delq!
- ;;; delv!
- ;;; delete!
- ;;; delq
- ;;; delv
- ;;; delete
- ;;; delq1!
- ;;; delv1!
- ;;; delete1!
|