tests.lisp - clic - Clic is an command line interactive client for gopher written in Common LISP (HTM) git clone git://bitreich.org/clic/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/clic/ (DIR) Log (DIR) Files (DIR) Refs (DIR) Tags (DIR) README (DIR) LICENSE --- tests.lisp (12989B) --- 1 ;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*- 2 3 (defpackage :split-sequence/tests 4 (:use :common-lisp :split-sequence :fiveam)) 5 6 (in-package :split-sequence/tests) 7 8 (in-suite* :split-sequence) 9 10 ;;; UNIT TESTS 11 12 (defmacro define-test (name (&key input output index) &body forms) 13 ;; This macro automatically generates test code for testing vector and list input. 14 ;; Vector input and output is automatically coerced into list form for the list tests. 15 ;; (DEFINE-TEST FOO ...) generates FIVEAM tests FOO.VECTOR and FOO.LIST. 16 (check-type name symbol) 17 (check-type input (cons symbol (cons vector null))) 18 (check-type output (cons symbol (cons list null))) 19 (check-type index (cons symbol (cons unsigned-byte null))) 20 (let* ((input-symbol (first input)) (vector-input (second input)) 21 (output-symbol (first output)) (vector-output (second output)) 22 (index-symbol (first index)) (index-value (second index)) 23 (list-input (coerce vector-input 'list)) 24 (list-output (mapcar (lambda (x) (coerce x 'list)) vector-output)) 25 (vector-name (intern (concatenate 'string (symbol-name name) ".VECTOR"))) 26 (list-name (intern (concatenate 'string (symbol-name name) ".LIST")))) 27 `(progn 28 (test (,vector-name :compile-at :definition-time) 29 (let ((,input-symbol ',vector-input) 30 (,output-symbol ',vector-output) 31 (,index-symbol ,index-value)) 32 ,@forms)) 33 (test (,list-name :compile-at :definition-time) 34 (let ((,input-symbol ',list-input) 35 (,output-symbol ',list-output) 36 (,index-symbol ,index-value)) 37 ,@forms))))) 38 39 (define-test split-sequence.0 (:input (input "") 40 :output (output ("")) 41 :index (index 0)) 42 (is (equalp (split-sequence #\; input) 43 (values output index)))) 44 45 (define-test split-sequence.1 (:input (input "a;;b;c") 46 :output (output ("a" "" "b" "c")) 47 :index (index 6)) 48 (is (equalp (split-sequence #\; input) 49 (values output index)))) 50 51 (define-test split-sequence.2 (:input (input "a;;b;c") 52 :output (output ("a" "" "b" "c")) 53 :index (index 0)) 54 (is (equalp (split-sequence #\; input :from-end t) 55 (values output index)))) 56 57 (define-test split-sequence.3 (:input (input "a;;b;c") 58 :output (output ("c")) 59 :index (index 4)) 60 (is (equalp (split-sequence #\; input :from-end t :count 1) 61 (values output index)))) 62 63 (define-test split-sequence.4 (:input (input "a;;b;c") 64 :output (output ("a" "b" "c")) 65 :index (index 6)) 66 (is (equalp (split-sequence #\; input :remove-empty-subseqs t) 67 (values output index)))) 68 69 (define-test split-sequence.5 (:input (input ";oo;bar;ba;") 70 :output (output ("oo" "bar" "b")) 71 :index (index 9)) 72 (is (equalp (split-sequence #\; input :start 1 :end 9) 73 (values output index)))) 74 75 (define-test split-sequence.6 (:input (input "abracadabra") 76 :output (output ("" "br" "c" "d" "br" "")) 77 :index (index 11)) 78 (is (equalp (split-sequence #\A input :key #'char-upcase) 79 (values output index)))) 80 81 (define-test split-sequence.7 (:input (input "abracadabra") 82 :output (output ("r" "c" "d")) 83 :index (index 7)) 84 (is (equalp (split-sequence #\A input :key #'char-upcase :start 2 :end 7) 85 (values output index)))) 86 87 (define-test split-sequence.8 (:input (input "abracadabra") 88 :output (output ("r" "c" "d")) 89 :index (index 2)) 90 (is (equalp (split-sequence #\A input :key #'char-upcase :start 2 :end 7 :from-end t) 91 (values output index)))) 92 93 (define-test split-sequence.9 (:input (input #(1 2 0)) 94 :output (output (#(1 2) #())) 95 :index (index 0)) 96 (is (equalp (split-sequence 0 input :from-end t) 97 (values output index)))) 98 99 (define-test split-sequence.10 (:input (input #(2 0 0 2 3 2 0 1 0 3)) 100 :output (output ()) 101 :index (index 8)) 102 (is (equalp (split-sequence 0 input :start 8 :end 9 :from-end t :count 0 :remove-empty-subseqs t) 103 (values output index)))) 104 105 (define-test split-sequence.11 (:input (input #(0 1 3 0 3 1 2 2 1 0)) 106 :output (output ()) 107 :index (index 0)) 108 (is (equalp (split-sequence 0 input :start 0 :end 0 :remove-empty-subseqs t) 109 (values output index)))) 110 111 (define-test split-sequence.12 (:input (input #(3 0 0 0 3 3 0 3 1 0)) 112 :output (output ()) 113 :index (index 10)) 114 (is (equalp (split-sequence 0 input :start 9 :end 10 :from-end t :count 0) 115 (values output index)))) 116 117 (define-test split-sequence.13 (:input (input #(3 3 3 3 0 2 0 0 1 2)) 118 :output (output (#(1))) 119 :index (index 6)) 120 (is (equalp (split-sequence 0 input :start 6 :end 9 :from-end t :count 1 :remove-empty-subseqs t) 121 (values output index)))) 122 123 (define-test split-sequence.14 (:input (input #(1 0)) 124 :output (output (#(1))) 125 :index (index 0)) 126 (is (equalp (split-sequence 0 input :from-end t :count 1 :remove-empty-subseqs t) 127 (values output index)))) 128 129 (define-test split-sequence.15 (:input (input #(0 0)) 130 :output (output ()) 131 :index (index 1)) 132 (is (equalp (split-sequence 0 input :start 0 :end 1 :count 0 :remove-empty-subseqs t) 133 (values output index)))) 134 135 (define-test split-sequence.16 (:input (input "a;;b;c") 136 :output (output ("" ";;" ";" "")) 137 :index (index 6)) 138 (is (equalp (split-sequence #\; input :test-not #'eql) 139 (values output index)))) 140 141 (define-test split-sequence.17 (:input (input "a;;b;c") 142 :output (output ("" ";;" ";" "")) 143 :index (index 0)) 144 (is (equalp (split-sequence #\; input :from-end t :test-not #'eql) 145 (values output index)))) 146 147 (define-test split-sequence.18 (:input (input #(1 0 2 0 3 0 4)) 148 :output (output (#(1) #(2) #(3))) 149 :index (index 6)) 150 (is (equalp (split-sequence 0 input :count 3) 151 (values output index)))) 152 153 (define-test split-sequence-if.1 (:input (input "abracadabra") 154 :output (output ("" "" "r" "c" "d" "" "r" "")) 155 :index (index 11)) 156 (is (equalp (split-sequence-if (lambda (x) (member x '(#\a #\b))) input) 157 (values output index)))) 158 159 (define-test split-sequence-if.2 (:input (input "123456") 160 :output (output ("1" "3" "5")) 161 :index (index 6)) 162 (is (equalp (split-sequence-if (lambda (x) (evenp (parse-integer (string x)))) input 163 :remove-empty-subseqs t) 164 (values output index)))) 165 166 (define-test split-sequence-if.3 (:input (input "123456") 167 :output (output ("1" "3" "5" "")) 168 :index (index 6)) 169 (is (equalp (split-sequence-if (lambda (x) (evenp (parse-integer (string x)))) input) 170 (values output index)))) 171 172 (define-test split-sequence-if-not.1 (:input (input "abracadabra") 173 :output (output ("ab" "a" "a" "ab" "a")) 174 :index (index 11)) 175 (is (equalp (split-sequence-if-not (lambda (x) (member x '(#\a #\b))) input) 176 (values output index)))) 177 178 (test split-sequence.start-end-error 179 (signals error (split-sequence 0 #(0 1 2 3) :start nil)) 180 (signals error (split-sequence 0 #(0 1 2 3) :end '#:end)) 181 (signals error (split-sequence 0 #(0 1 2 3) :start 0 :end 8)) 182 (signals error (split-sequence 0 #(0 1 2 3) :start 2 :end 0))) 183 184 (test split-sequence.test-provided 185 ;; Neither provided 186 (is (equal '((1) (3)) (split-sequence 2 '(1 2 3)))) 187 ;; Either provided 188 (is (equal '((1) (3)) (split-sequence 2 '(1 2 3) :test #'eql))) 189 (is (equal '(() (2) ()) (split-sequence 2 '(1 2 3) :test-not #'eql))) 190 (signals type-error (split-sequence 2 '(1 2 3) :test nil)) 191 (signals type-error (split-sequence 2 '(1 2 3) :test-not nil)) 192 ;; Both provided 193 (signals program-error (split-sequence 2 '(1 2 3) :test #'eql :test-not nil)) 194 (signals program-error (split-sequence 2 '(1 2 3) :test nil :test-not #'eql)) 195 (signals program-error (split-sequence 2 '(1 2 3) :test #'eql :test-not #'eql)) 196 (signals program-error (split-sequence 2 '(1 2 3) :test nil :test-not nil))) 197 198 ;;; FUZZ TEST 199 200 (test split-sequence.fuzz 201 (fuzz :verbose nil :fiveamp t)) 202 203 (defun fuzz (&key (max-length 100) (repetitions 1000000) (verbose t) (print-every 10000) (fiveamp nil)) 204 (flet ((random-vector (n) 205 (let ((vector (make-array n :element-type '(unsigned-byte 2)))) 206 (dotimes (i n) (setf (aref vector i) (random 4))) 207 vector)) 208 (random-boolean () (if (= 0 (random 2)) t nil)) 209 (fuzz-failure (vector start end from-end count remove-empty-subseqs 210 expected-splits expected-index actual-splits actual-index) 211 (format nil "Fuzz failure: 212 \(MULTIPLE-VALUE-CALL #'VALUES 213 (SPLIT-SEQUENCE 0 ~S 214 :START ~S :END ~S :FROM-END ~S :COUNT ~S :REMOVE-EMPTY-SUBSEQS ~S) 215 (SPLIT-SEQUENCE 0 (COERCE ~S 'LIST) 216 :START ~S :END ~S :FROM-END ~S :COUNT ~S :REMOVE-EMPTY-SUBSEQS ~S)) 217 ~S~%~S~%~S~%~S" 218 vector start end from-end count remove-empty-subseqs 219 vector start end from-end count remove-empty-subseqs 220 expected-splits expected-index actual-splits actual-index))) 221 (let ((failure-string nil) 222 (predicate (lambda (x) (= x 0))) 223 (predicate-not (lambda (x) (/= x 0)))) 224 (dotimes (i repetitions) 225 (when (and verbose (= 0 (mod (1+ i) print-every))) 226 (format t "Fuzz: Pass ~D passed.~%" (1+ i))) 227 (let* ((length (1+ (random max-length))) 228 (vector (random-vector length)) 229 (list (coerce vector 'list)) 230 (remove-empty-subseqs (random-boolean)) 231 (start 0) end from-end count) 232 (case (random 5) 233 (0) 234 (1 (setf start (random length))) 235 (2 (setf start (random length) 236 end (+ start (random (1+ (- length start)))))) 237 (3 (setf start (random length) 238 end (+ start (random (1+ (- length start)))) 239 from-end t)) 240 (4 (setf start (random length) 241 end (+ start (random (1+ (- length start)))) 242 from-end t 243 count (random (1+ (- end start)))))) 244 (let ((args (list :start start :end end :from-end from-end :count count 245 :remove-empty-subseqs remove-empty-subseqs))) 246 (multiple-value-bind (expected-splits expected-index) 247 (case (random 3) 248 (0 (apply #'split-sequence 0 vector args)) 249 (1 (apply #'split-sequence-if predicate vector args)) 250 (2 (apply #'split-sequence-if-not predicate-not vector args))) 251 (multiple-value-bind (actual-splits actual-index) 252 (case (random 3) 253 (0 (apply #'split-sequence 0 list args)) 254 (1 (apply #'split-sequence-if predicate list args)) 255 (2 (apply #'split-sequence-if-not predicate-not list args))) 256 (let* ((expected-splits (mapcar (lambda (x) (coerce x 'list)) expected-splits)) 257 (result (and (equal actual-splits expected-splits) 258 (= expected-index actual-index)))) 259 (unless result 260 (let ((string (fuzz-failure 261 vector start end from-end count remove-empty-subseqs 262 expected-splits expected-index actual-splits actual-index))) 263 (cond (fiveamp 264 (setf failure-string string) 265 (return)) 266 (t (assert result () string))))))))))) 267 (when fiveamp 268 (is (not failure-string) failure-string)))))