#lang s-exp "../../lang/base.rkt" (require "testing.rkt") (require (for-syntax racket/base)) (test (list 1 2 3 4) foldl cons '() (list 4 3 2 1)) (test (list 1 2 3 4) foldr cons '() (list 1 2 3 4)) (test (list (list 5 6) (list 3 4) (list 1 2)) foldl (lambda (x y sofar) (cons (list x y) sofar)) '() (list 1 3 5) (list 2 4 6)) (test (list (list 1 2) (list 3 4) (list 5 6)) foldr (lambda (x y sofar) (cons (list x y) sofar)) '() (list 1 3 5) (list 2 4 6)) (arity-test foldl 3 -1) (arity-test foldr 3 -1) (err/rt-test (foldl 'list 0 10)) (err/rt-test (foldl list 0 10)) (err/rt-test (foldl add1 0 '())) (err/rt-test (foldl cons 0 '() '())) (err/rt-test (foldl list 0 '() 10)) (err/rt-test (foldl list 0 '() '() 10)) (err/rt-test (let/cc k (foldl k 0 '(1 2) '(1 2 3)))) (err/rt-test (let/cc k (foldl k 0 '(1 2) '(1 2) '(1 2 3)))) (err/rt-test (foldr 'list 0 10)) (err/rt-test (foldr list 0 10)) (err/rt-test (foldr add1 0 '())) (err/rt-test (foldr cons 0 '() '())) (err/rt-test (foldr list 0 '() 10)) (err/rt-test (foldr list 0 '() '() 10)) (err/rt-test (let/cc k (foldr k 0 '(1 2) '(1 2 3)))) (err/rt-test (let/cc k (foldr k 0 '(1 2) '(1 2) '(1 2 3)))) (test '(0 1 2) memf add1 '(0 1 2)) (test '(2 (c 17)) memf number? '((a 1) (0 x) (1 w) 2 (c 17))) (test '("ok" (2 .7) c) memf string? '((a 0) (0 a) (1 w) "ok" (2 .7) c)) (err/rt-test (memf cons '((1) (2) (3)))) (err/rt-test (memf string? '((1) (2) (3) . 4)) exn:application:mismatch?) #| dyoo: missing assf (err/rt-test (assf add1 '(0 1 2)) exn:application:mismatch?) (test '(0 x) assf number? '((a 1) (0 x) (1 w) (2 r) (c 17))) (test '("ok" . 10) assf string? '((a 0) (0 a) (1 w) ("ok" . 10) (2 .7) c)) (err/rt-test (assf cons '((1) (2) (3)))) (err/rt-test (assf string? '((1) (2) (3) . 4)) exn:application:mismatch?) |# #| dyoo: missing last ;; ---------- last, last-pair ---------- (let () (test 3 last '(1 2 3)) (test '(3) last-pair '(1 2 3)) (err/rt-test (last '(1 2 3 . 4))) (test '(3 . 4) last-pair '(1 2 3 . 4)) (err/rt-test (last '())) (err/rt-test (last 1)) (err/rt-test (last-pair '())) (err/rt-test (last-pair 1))) |# ;; ---------- sort ---------- (test '("a" "b" "c" "c" "d" "e" "f") sort '("d" "f" "e" "c" "a" "c" "b") string<?) (let () (define (car< x y) (< (car x) (car y))) (define (random-list n range) (let loop ([n n] [r '()]) (if (zero? n) r (loop (sub1 n) (cons (list (random range)) r))))) (define (sort* lst) (let ([s1 (sort lst car<)] [s2 (sort lst < #:key car)] [s3 (sort lst < #:key car #:cache-keys? #t)]) (test #t andmap eq? s1 s2) (test #t andmap eq? s1 s3) s1)) (define (test-sort len times) (or (zero? times) (and (let* ([rand (random-list len (if (even? times) 1000000 10))] [orig< (lambda (x y) (memq y (cdr (memq x rand))))] [sorted (sort* rand)] [l1 (reverse (cdr (reverse sorted)))] [l2 (cdr sorted)]) (and (= (length sorted) (length rand)) (andmap (lambda (x1 x2) (and (not (car< x2 x1)) ; sorted? (or (car< x1 x2) (orig< x1 x2)))) ; stable? l1 l2))) (test-sort len (sub1 times))))) (test #t test-sort 1 10) (test #t test-sort 2 20) (test #t test-sort 3 60) (test #t test-sort 4 100) (test #t test-sort 5 100) (test #t test-sort 10 100) (test #t test-sort 100 100) (test #t test-sort 1000 100) ;; test stability (test '((1) (2) (3 a) (3 b) (3 c)) sort* '((3 a) (1) (3 b) (2) (3 c))) ;; test short lists (+ stable) (test '() sort* '()) (test '((1 1)) sort* '((1 1))) (test '((1 2) (1 1)) sort* '((1 2) (1 1))) (test '((1) (2)) sort* '((2) (1))) (for-each (lambda (l) (test '((0 3) (1 1) (1 2)) sort* l)) '(((1 1) (1 2) (0 3)) ((1 1) (0 3) (1 2)) ((0 3) (1 1) (1 2)))) (for-each (lambda (l) (test '((0 2) (0 3) (1 1)) sort* l)) '(((1 1) (0 2) (0 3)) ((0 2) (1 1) (0 3)) ((0 2) (0 3) (1 1)))) ;; exhaustive tests for 2 and 3 item lists (for-each (lambda (l) (test '((1 x) (2 y)) sort* l)) '(((1 x) (2 y)) ((2 y) (1 x)))) (for-each (lambda (l) (test '((1 x) (2 y) (3 z)) sort* l)) '(((1 x) (2 y) (3 z)) ((2 y) (1 x) (3 z)) ((2 y) (3 z) (1 x)) ((3 z) (2 y) (1 x)) ((3 z) (1 x) (2 y)) ((1 x) (3 z) (2 y))))) ;; test #:key and #:cache-keys? (let () (define l '((0) (9) (1) (8) (2) (7) (3) (6) (4) (5))) (define sorted '((0) (1) (2) (3) (4) (5) (6) (7) (8) (9))) (test sorted sort l < #:key car) (let ([c1 0] [c2 0] [touched '()]) (test sorted sort l (lambda (x y) (set! c1 (add1 c1)) (< x y)) #:key (lambda (x) (set! c2 (add1 c2)) (set! touched (cons x touched)) (car x))) ;; test that the number of key uses is half the number of comparisons (test #t = (* 2 c1) c2) ;; and that this is larger than the number of items in the list (test #t < (length l) c2) ;; and that every item was touched ;; dyoo: missing remove* #;(test null remove* touched l)) (let ([c 0] [touched '()]) ;; now cache the keys (test sorted sort l < #:key (lambda (x) (set! c (add1 c)) (set! touched (cons x touched)) (car x)) #:cache-keys? #t) ;; test that the number of key uses is the same as the list length (test #t = c (length l)) ;; and that every item was touched ;; dyoo: missing remove* #;(test null remove* touched l)) (let* ([c 0] [getkey (lambda (x) (set! c (add1 c)) x)]) ;; either way, we never use the key proc on no arguments (test '() sort '() < #:key getkey #:cache-keys? #f) (test '() sort '() < #:key getkey #:cache-keys? #t) (test #t = c 0) ;; we also don't use it for 1-arg lists (test '(1) sort '(1) < #:key getkey #:cache-keys? #f) (test #t = c 0) ;; but we do use it once if caching happens (it's a consistent interface) (test '(1) sort '(1) < #:key getkey #:cache-keys? #t) (test #t = c 1) ;; check a few other short lists (test '(1 2) sort '(2 1) < #:key getkey #:cache-keys? #t) (test '(1 2 3) sort '(2 3 1) < #:key getkey #:cache-keys? #t) (test '(1 2 3 4) sort '(4 2 3 1) < #:key getkey #:cache-keys? #t) (test #t = c 10))) ;; ---------- make-list ---------- ;; dyoo: missing make-list #;(let () (test '() make-list 0 'x) (test '(x) make-list 1 'x) (test '(x x) make-list 2 'x) (err/rt-test (make-list -3 'x))) ;; ---------- take/drop[-right] ---------- #| (let () (define-syntax vals-list (syntax-rules () [(_ expr) (call-with-values (lambda () expr) list)])) ;; dyoo: missing split-at (define (split-at* l n) (vals-list (split-at l n))) (define (split-at-right* l n) (vals-list (split-at-right l n))) (define funs (list take drop take-right drop-right split-at* split-at-right*)) (define tests ;; -----args------ --take--- --drop--- --take-r--- --drop-r- '([((a b c d) 2) (a b) (c d) (c d) (a b) ] [((a b c d) 0) () (a b c d) () (a b c d)] [((a b c d) 4) (a b c d) () (a b c d) () ] [((a b c . d) 1) (a) (b c . d) (c . d) (a b) ] [((a b c . d) 3) (a b c) d (a b c . d) () ] [(99 0) () 99 99 () ])) (for ([t tests] #:when #t [expect `(,@(cdr t) ,(list (list-ref t 1) (list-ref t 2)) ,(list (list-ref t 4) (list-ref t 3)))] [fun funs]) (apply test expect fun (car t))) (for ([fun funs]) (arity-test fun 2 2) (err/rt-test (fun 1 1) exn:application:mismatch?) (err/rt-test (fun '(1 2 3) 2.0)) (err/rt-test (fun '(1) '(1))) (err/rt-test (fun '(1) -1)) (err/rt-test (fun '(1) 2) exn:application:mismatch?) (err/rt-test (fun '(1 2 . 3) 3) exn:application:mismatch?))) |# ;; dyoo: missing append* #| ;; ---------- append* ---------- (let () (test '() append* '()) (test '() append* '(())) (test '() append* '(() ())) (test '(0 1 2 3) append* '((0 1 2 3))) (test '(0 1 2 3) append* '(0 1 2 3) '()) (test '(0 1 2 3) append* '(0 1 2 3) '(())) (test '(0 1 2 3) append* '(0 1 2 3) '(() ())) (test '(0 1 2 3) append* '(0 1) '((2) (3))) (test '(0 1 0 2 0 3) append* (map (lambda (x) (list 0 x)) '(1 2 3))) (test '(1 2 3 4 5 6 7 8 9) append* '(1 2 3) '(4 5) '((6 7 8) (9)))) |# ;; ---------- flatten ---------- ;; dyoo: missing for*/list #| (let () (define (all-sexps n) (if (zero? n) '(x ()) (let ([r (all-sexps (sub1 n))]) (append r (for*/list ([x r] [y r]) (cons x y)))))) (define sexps (all-sexps 3)) ; can use 4 on fast machines (define (flat? x) (and (list? x) (andmap (lambda (x) (eq? 'x x)) x))) (for ([x sexps]) (test #t flat? (flatten x)))) |# ;; ---------- add-between ---------- ;; dyoo: missing add-between #| (let () (test '() add-between '() 1) (test '(9) add-between '(9) 1) (test '(9 1 8 1 7) add-between '(9 8 7) 1) (test '(9 (1) 8) add-between '(9 8) '(1))) |# ;; ---------- remove-duplicates ---------- #| dyoo: missing remove-duplicates (let () (define rd remove-duplicates) ;; basic 'naive tests (test '() rd '()) (test '(a) rd '(a a a a)) (test '(a b) rd '(a b)) (test '(a b) rd '(a b a b a b)) (test '(a b) rd '(a a a b b b)) (test '(a b) rd '(a b b a)) ; keeps first occurrences (test '("a" "b") rd '("a" "A" "b" "B" "a") #:key string-downcase) (let ([long (for/list ([i (in-range 300)]) i)]) (test long rd long) (test long rd (append long long)) (test long rd (append long (reverse long))) ; keeps first (test long rd (append* (map (lambda (x) (list x x)) long))) (test long rd (append long (map (lambda (x) (- x)) long)) #:key abs) (test long rd (append long (map (lambda (x) (- x)) long)) = #:key abs))) |# #| ;; dyoo: missing filter-not ;; ---------- filter and filter-not ---------- (let () (define f filter) (define fn filter-not) (test '() f number? '()) (test '() fn number? '()) (test '(1 2 3) f number? '(1 a 2 b 3 c d)) (test '(a b c d) fn number? '(1 a 2 b 3 c d)) (test '() f string? '(1 a 2 b 3 c d)) (test '(1 a 2 b 3 c d) fn string? '(1 a 2 b 3 c d)) (err/rt-test (f string? '(1 2 3 . 4)) exn:application:mismatch?) (err/rt-test (fn string? '(1 2 3 . 4)) exn:application:mismatch?) (err/rt-test (f 2 '(1 2 3))) (err/rt-test (fn 2 '(1 2 3))) (err/rt-test (f cons '(1 2 3))) (err/rt-test (fn cons '(1 2 3))) (arity-test f 2 2) (arity-test fn 2 2)) |# #| dyoo: missin gpartition ;; ---------- partition ---------- (let () (define (p pred l) (call-with-values (lambda () (partition pred l)) list)) (test '(() ()) p (lambda (_) #t) '()) (test '(() ()) p (lambda (_) #f) '()) (test '((1 2 3 4) ()) p (lambda (_) #t) '(1 2 3 4)) (test '(() (1 2 3 4)) p (lambda (_) #f) '(1 2 3 4)) (test '((2 4) (1 3)) p even? '(1 2 3 4)) (test '((1 3) (2 4)) p odd? '(1 2 3 4))) |# #| dyoo: missing filter-map ;; ---------- filter-map ---------- (let () (define fm filter-map) (test '() fm values '()) (test '(1 2 3) fm values '(1 2 3)) (test '() fm values '(#f #f #f)) (test '(1 2 3) fm values '(#f 1 #f 2 #f 3 #f)) (test '(4 8 12) fm (lambda (x) (and (even? x) (* x 2))) '(1 2 3 4 5 6))) |# #| dyoo: missing count ;; ---------- count ---------- (let () (test 0 count even? '()) (test 4 count even? '(0 2 4 6)) (test 0 count even? '(1 3 5 7)) (test 2 count even? '(1 2 3 4)) (test 2 count < '(1 2 3 4) '(4 3 2 1))) |# #| dyoo: missing append-map ;; ---------- append-map ---------- (let () (define am append-map) (test '() am list '()) (test '(1 2 3) am list '(1 2 3)) (test '(1 1 2 2 3 3) am (lambda (x) (list x x)) '(1 2 3))) |# #| dyoo: missing regexps ;; ---------- argmin & argmax ---------- (let () (define ((check-regs . regexps) exn) (and (exn:fail? exn) (andmap (λ (reg) (regexp-match reg (exn-message exn))) regexps))) (test 'argmin object-name argmin) (test 1 argmin (lambda (x) 0) (list 1)) (test 1 argmin (lambda (x) x) (list 1 2 3)) (test 1 argmin (lambda (x) 1) (list 1 2 3)) (test 3 'argmin-makes-right-number-of-calls (let ([c 0]) (argmin (lambda (x) (set! c (+ c 1)) 0) (list 1 2 3)) c)) (test '(1 banana) argmin car '((3 pears) (1 banana) (2 apples))) (err/rt-test (argmin 1 (list 1)) (check-regs #rx"argmin" #rx"procedure")) (err/rt-test (argmin (lambda (x) x) 3) (check-regs #rx"argmin" #rx"list")) (err/rt-test (argmin (lambda (x) x) (list 1 #f)) (check-regs #rx"argmin" #rx"procedure that returns real numbers")) (err/rt-test (argmin (lambda (x) x) (list #f)) (check-regs #rx"argmin" #rx"procedure that returns real numbers")) (err/rt-test (argmin (lambda (x) x) (list +i)) (check-regs #rx"argmin" #rx"procedure that returns real numbers")) (err/rt-test (argmin (lambda (x) x) (list)) (check-regs #rx"argmin" #rx"non-empty list")) (test 'argmax object-name argmax) (test 1 argmax (lambda (x) 0) (list 1)) (test 3 argmax (lambda (x) x) (list 1 2 3)) (test 1 argmax (lambda (x) 1) (list 1 2 3)) (test 3 'argmax-makes-right-number-of-calls (let ([c 0]) (argmax (lambda (x) (set! c (+ c 1)) 0) (list 1 2 3)) c)) (test '(3 pears) argmax car '((3 pears) (1 banana) (2 apples))) (err/rt-test (argmax 1 (list 1)) (check-regs #rx"argmax" #rx"procedure")) (err/rt-test (argmax (lambda (x) x) 3) (check-regs #rx"argmax" #rx"list")) (err/rt-test (argmax (lambda (x) x) (list 1 #f)) (check-regs #rx"argmax" #rx"procedure that returns real numbers")) (err/rt-test (argmax (lambda (x) x) (list #f)) (check-regs #rx"argmax" #rx"procedure that returns real numbers")) (err/rt-test (argmax (lambda (x) x) (list +i)) (check-regs #rx"argmax" #rx"procedure that returns real numbers")) (err/rt-test (argmax (lambda (x) x) (list)) (check-regs #rx"argmax" #rx"non-empty list"))) |# ;; ---------- check no collisions with srfi/1 ---------- #;(test (void) eval '(module foo scheme/base (require scheme/base srfi/1/list)) (make-base-namespace)) (report-errs) "list.rkt end"