test.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 --- test.lisp (7810B) --- 1 (in-package :trivial-gray-streams-test) 2 3 ;;; assert-invoked - a tool to check that specified method with parameters has 4 ;;; been invoked during execution of a code body 5 6 (define-condition invoked () 7 ((method :type (or symbol cons) ;; cons is for (setf method) 8 :accessor method 9 :initarg :method 10 :initform (error ":method is required")) 11 (args :type list 12 :accessor args 13 :initarg :args 14 :initform nil))) 15 16 (defun assert-invoked-impl (method args body-fn) 17 (let ((expected-invocation (cons method args)) 18 (actual-invocations nil)) 19 (handler-bind ((invoked (lambda (i) 20 (let ((invocation (cons (method i) (args i)))) 21 (when (equalp invocation expected-invocation) 22 (return-from assert-invoked-impl nil)) 23 (push invocation actual-invocations))))) 24 (funcall body-fn)) 25 (let ((*package* (find-package :keyword))) ; ensures package prefixes are printed 26 (error "expected invocation: ~(~S~) actual: ~{~(~S~)~^, ~}" 27 expected-invocation (reverse actual-invocations))))) 28 29 (defmacro assert-invoked ((method &rest args) &body body) 30 "If during execution of the BODY the specified METHOD with ARGS 31 hasn't been invoked, signals an ERROR." 32 `(assert-invoked-impl (quote ,method) (list ,@args) (lambda () ,@body))) 33 34 (defun invoked (method &rest args) 35 (signal 'invoked :method method :args args)) 36 37 ;;; The tests. 38 39 #| 40 We will define a gray stream class, specialise 41 the gray generic function methods on it and test that the methods 42 are invoked when we call functions from common-lisp package 43 on that stream. 44 45 Some of the gray generic functions are only invoked by default 46 methods of other generic functions: 47 48 cl:format ~t or cl:pprint -> stream-advance-to-column -> stream-line-column 49 stream-write-char 50 cl:fresh-line -> stream-fresh-line -> stream-start-line-p -> stream-line-column 51 stream-terpri 52 53 54 If we define our methods for stream-advance-to-column and stream-fresh-line, 55 then stream-start-line-p, stream-terpri, stram-line-column are not invoked. 56 57 Therefore we define another gray stream class. The first class is used 58 for all lower level functions (stream-terpri). The second class 59 is used to test methods for higher level functions (stream-fresh-line). 60 |# 61 62 (defclass test-stream (fundamental-binary-input-stream 63 fundamental-binary-output-stream 64 fundamental-character-input-stream 65 fundamental-character-output-stream) 66 ()) 67 68 (defclass test-stream2 (test-stream) ()) 69 70 (defmethod stream-read-char ((stream test-stream)) 71 (invoked 'stream-read-char stream)) 72 73 (defmethod stream-unread-char ((stream test-stream) char) 74 (invoked 'stream-unread-char stream char)) 75 76 (defmethod stream-read-char-no-hang ((stream test-stream)) 77 (invoked 'stream-read-char-no-hang stream)) 78 79 (defmethod stream-peek-char ((stream test-stream)) 80 (invoked 'stream-peek-char stream)) 81 82 (defmethod stream-listen ((stream test-stream)) 83 (invoked 'stream-listen stream)) 84 85 (defmethod stream-read-line ((stream test-stream)) 86 (invoked 'stream-read-line stream)) 87 88 (defmethod stream-clear-input ((stream test-stream)) 89 (invoked 'stream-clear-input stream)) 90 91 (defmethod stream-write-char ((stream test-stream) char) 92 (invoked 'stream-write-char stream char)) 93 94 (defmethod stream-line-column ((stream test-stream)) 95 (invoked 'stream-line-column stream)) 96 97 (defmethod stream-start-line-p ((stream test-stream)) 98 (invoked 'stream-start-line-p stream)) 99 100 (defmethod stream-write-string ((stream test-stream) string &optional start end) 101 (invoked 'stream-write-string stream string start end)) 102 103 (defmethod stream-terpri ((stream test-stream)) 104 (invoked 'stream-terpri stream)) 105 106 (defmethod stream-fresh-line ((stream test-stream2)) 107 (invoked 'stream-fresh-line stream)) 108 109 (defmethod stream-finish-output ((stream test-stream)) 110 (invoked 'stream-finish-output stream)) 111 112 (defmethod stream-force-output ((stream test-stream)) 113 (invoked 'stream-force-output stream)) 114 115 (defmethod stream-clear-output ((stream test-stream)) 116 (invoked 'stream-clear-output stream)) 117 118 (defmethod stream-advance-to-column ((stream test-stream2) column) 119 (invoked 'stream-advance-to-column stream column)) 120 121 (defmethod stream-read-byte ((stream test-stream)) 122 (invoked 'stream-read-byte stream)) 123 124 (defmethod stream-write-byte ((stream test-stream) byte) 125 (invoked 'stream-write-byte stream byte)) 126 127 (defmethod stream-read-sequence ((s test-stream) seq start end &key) 128 (invoked 'stream-read-sequence s seq :start start :end end)) 129 130 (defmethod stream-write-sequence ((s test-stream) seq start end &key) 131 (invoked 'stream-write-sequence s seq :start start :end end)) 132 133 (defmethod stream-file-position ((s test-stream)) 134 (invoked 'stream-file-position s)) 135 136 (defmethod (setf stream-file-position) (newval (s test-stream)) 137 (invoked '(setf stream-file-position) newval s)) 138 139 ;; Convinience macro, used when we want to name 140 ;; the test case with the same name as of the gray streams method we test. 141 (defmacro test-invoked ((method &rest args) &body body) 142 `(test (,method) 143 (assert-invoked (,method ,@args) 144 ,@body))) 145 146 (defun run-tests () 147 (let ((s (make-instance 'test-stream)) 148 (s2 (make-instance 'test-stream2))) 149 (list 150 (test-invoked (stream-read-char s) 151 (read-char s)) 152 (test-invoked (stream-unread-char s #\a) 153 (unread-char #\a s)) 154 (test-invoked (stream-read-char-no-hang s) 155 (read-char-no-hang s)) 156 (test-invoked (stream-peek-char s) 157 (peek-char nil s)) 158 (test-invoked (stream-listen s) 159 (listen s)) 160 (test-invoked (stream-read-line s) 161 (read-line s)) 162 (test-invoked (stream-clear-input s) 163 (clear-input s)) 164 (test-invoked (stream-write-char s #\b) 165 (write-char #\b s)) 166 (test-invoked (stream-line-column s) 167 (format s "~10,t")) 168 (test-invoked (stream-start-line-p s) 169 (fresh-line s)) 170 (test-invoked (stream-write-string s "hello" 1 4) 171 (write-string "hello" s :start 1 :end 4)) 172 (test-invoked (stream-terpri s) 173 (fresh-line s)) 174 (test-invoked (stream-fresh-line s2) 175 (fresh-line s2)) 176 (test-invoked (stream-finish-output s) 177 (finish-output s)) 178 (test-invoked (stream-force-output s) 179 (force-output s)) 180 (test-invoked (stream-clear-output s) 181 (clear-output s)) 182 (test-invoked (stream-advance-to-column s2 10) 183 (format s2 "~10,t")) 184 (test-invoked (stream-read-byte s) 185 (read-byte s)) 186 (test-invoked (stream-write-byte s 1) 187 (write-byte 1 s)) 188 ;;; extensions 189 (let ((seq (vector 1 2))) 190 (test-invoked (stream-read-sequence s seq :start 0 :end 1) 191 (read-sequence seq s :start 0 :end 1)) 192 (test-invoked (stream-write-sequence s seq :start 0 :end 1) 193 (write-sequence seq s :start 0 :end 1))) 194 (test-invoked (stream-file-position s) 195 (file-position s)) 196 (test (setf-stream-file-position) 197 (assert-invoked ((setf stream-file-position) 9 s) 198 (file-position s 9)))))) 199 200 (defun failed-tests (results) 201 (remove-if-not #'failed-p results)) 202 203 (defun failed-test-names (results) 204 (mapcar (lambda (result) 205 (string-downcase (name result))) 206 (failed-tests results))) 207 208 #| 209 (failed-test-names (run-tests)) 210 211 (setf *allow-debugger* nil)) 212 213 |#