comparison lisp/emacs-lisp/testcover.el @ 53196:b3327f1ed9e1

Ensure that forms marked with `1value' actually always return the same value.
author Jonathan Yavner <jyavner@member.fsf.org>
date Sun, 30 Nov 2003 06:56:28 +0000
parents 695cf19ef79e
children 71315b2afe5b
comparison
equal deleted inserted replaced
53195:49d5fa0b5a1c 53196:b3327f1ed9e1
169 169
170 ;;;========================================================================= 170 ;;;=========================================================================
171 ;;; Add instrumentation to your module 171 ;;; Add instrumentation to your module
172 ;;;========================================================================= 172 ;;;=========================================================================
173 173
174 ;;;###autoload
175 (defun testcover-start (filename &optional byte-compile) 174 (defun testcover-start (filename &optional byte-compile)
176 "Uses edebug to instrument all macros and functions in FILENAME, then 175 "Uses edebug to instrument all macros and functions in FILENAME, then
177 changes the instrumentation from edebug to testcover--much faster, no 176 changes the instrumentation from edebug to testcover--much faster, no
178 problems with type-ahead or post-command-hook, etc. If BYTE-COMPILE is 177 problems with type-ahead or post-command-hook, etc. If BYTE-COMPILE is
179 non-nil, byte-compiles each function after instrumenting." 178 non-nil, byte-compiles each function after instrumenting."
180 (interactive "f") 179 (interactive "f")
181 (let ((buf (find-file filename)) 180 (let ((buf (find-file filename))
182 (load-read-function 'testcover-read) 181 (load-read-function 'testcover-read)
183 (edebug-all-defs t)) 182 (edebug-all-defs t))
184 (setq edebug-form-data nil 183 (setq edebug-form-data nil
185 testcover-module-constants nil 184 testcover-module-constants nil
186 testcover-module-1value-functions nil) 185 testcover-module-1value-functions nil)
208 207
209 (defun testcover-reinstrument (form) 208 (defun testcover-reinstrument (form)
210 "Reinstruments FORM to use testcover instead of edebug. This function 209 "Reinstruments FORM to use testcover instead of edebug. This function
211 modifies the list that FORM points to. Result is non-nil if FORM will 210 modifies the list that FORM points to. Result is non-nil if FORM will
212 always return the same value." 211 always return the same value."
213 (let ((fun (car-safe form))) 212 (let ((fun (car-safe form))
213 id)
214 (cond 214 (cond
215 ((not fun) ;Atom 215 ((not fun) ;Atom
216 (or (not (symbolp form)) 216 (or (not (symbolp form))
217 (memq form testcover-constants) 217 (memq form testcover-constants)
218 (memq form testcover-module-constants))) 218 (memq form testcover-module-constants)))
232 ;;1-valued if first argument is 232 ;;1-valued if first argument is
233 (testcover-reinstrument-list (cddr form)) 233 (testcover-reinstrument-list (cddr form))
234 (testcover-reinstrument (cadr form))) 234 (testcover-reinstrument (cadr form)))
235 ((memq fun testcover-compose-functions) 235 ((memq fun testcover-compose-functions)
236 ;;1-valued if all arguments are 236 ;;1-valued if all arguments are
237 (setq fun t) 237 (setq id t)
238 (mapc #'(lambda (x) (setq fun (or (testcover-reinstrument x) fun))) 238 (mapc #'(lambda (x) (setq id (or (testcover-reinstrument x) id)))
239 (cdr form)) 239 (cdr form))
240 fun) 240 id)
241 ((eq fun 'edebug-enter) 241 ((eq fun 'edebug-enter)
242 ;;(edebug-enter 'SYM ARGS #'(lambda nil FORMS)) 242 ;;(edebug-enter 'SYM ARGS #'(lambda nil FORMS))
243 ;; => (testcover-enter 'SYM #'(lambda nil FORMS)) 243 ;; => (testcover-enter 'SYM #'(lambda nil FORMS))
244 (setcar form 'testcover-enter) 244 (setcar form 'testcover-enter)
245 (setcdr (nthcdr 1 form) (nthcdr 3 form)) 245 (setcdr (nthcdr 1 form) (nthcdr 3 form))
248 ((eq fun 'edebug-after) 248 ((eq fun 'edebug-after)
249 ;;(edebug-after (edebug-before XXX) YYY FORM) 249 ;;(edebug-after (edebug-before XXX) YYY FORM)
250 ;; => (testcover-after YYY FORM), mark XXX as ok-coverage 250 ;; => (testcover-after YYY FORM), mark XXX as ok-coverage
251 (unless (eq (cadr form) 0) 251 (unless (eq (cadr form) 0)
252 (aset testcover-vector (cadr (cadr form)) 'ok-coverage)) 252 (aset testcover-vector (cadr (cadr form)) 'ok-coverage))
253 (setq fun (nth 2 form)) 253 (setq id (nth 2 form))
254 (setcdr form (nthcdr 2 form)) 254 (setcdr form (nthcdr 2 form))
255 (if (not (memq (car-safe (nth 2 form)) testcover-noreturn-functions)) 255 (cond
256 (setcar form 'testcover-after) 256 ((memq (car-safe (nth 2 form)) testcover-noreturn-functions)
257 ;;This function won't return, so set the value in advance 257 ;;This function won't return, so set the value in advance
258 ;;(edebug-after (edebug-before XXX) YYY FORM) 258 ;;(edebug-after (edebug-before XXX) YYY FORM)
259 ;; => (progn (edebug-after YYY nil) FORM) 259 ;; => (progn (edebug-after YYY nil) FORM)
260 (setcar form 'progn) 260 (setcar form 'progn)
261 (setcar (cdr form) `(testcover-after ,fun nil))) 261 (setcar (cdr form) `(testcover-after ,id nil)))
262 ((eq (car-safe (nth 2 form)) '1value)
263 ;;This function is always supposed to return the same value
264 (setcar form 'testcover-1value))
265 (t
266 (setcar form 'testcover-after)))
262 (when (testcover-reinstrument (nth 2 form)) 267 (when (testcover-reinstrument (nth 2 form))
263 (aset testcover-vector fun '1value))) 268 (aset testcover-vector id '1value)))
264 ((eq fun 'defun) 269 ((eq fun 'defun)
265 (if (testcover-reinstrument-list (nthcdr 3 form)) 270 (if (testcover-reinstrument-list (nthcdr 3 form))
266 (push (cadr form) testcover-module-1value-functions))) 271 (push (cadr form) testcover-module-1value-functions)))
267 ((eq fun 'defconst) 272 ((eq fun 'defconst)
268 ;;Define this symbol as 1-valued 273 ;;Define this symbol as 1-valued
314 (testcover-reinstrument (cadr form)))) 319 (testcover-reinstrument (cadr form))))
315 ((memq fun '(1value noreturn)) 320 ((memq fun '(1value noreturn))
316 ;;Hack - pretend the arg is 1-valued here 321 ;;Hack - pretend the arg is 1-valued here
317 (if (symbolp (cadr form)) ;A pseudoconstant variable 322 (if (symbolp (cadr form)) ;A pseudoconstant variable
318 t 323 t
324 (if (eq (car (cadr form)) 'edebug-after)
325 (setq id (car (nth 3 (cadr form))))
326 (setq id (car (cadr form))))
319 (let ((testcover-1value-functions 327 (let ((testcover-1value-functions
320 (cons (car (cadr form)) testcover-1value-functions))) 328 (cons id testcover-1value-functions)))
321 (testcover-reinstrument (cadr form))))) 329 (testcover-reinstrument (cadr form)))))
322 (t ;Some other function or weird thing 330 (t ;Some other function or weird thing
323 (testcover-reinstrument-list (cdr form)) 331 (testcover-reinstrument-list (cdr form))
324 nil)))) 332 nil))))
325 333
346 "Turn off instrumentation of all macros and functions in FILENAME." 354 "Turn off instrumentation of all macros and functions in FILENAME."
347 (interactive "b") 355 (interactive "b")
348 (let ((buf (find-file-noselect buffer))) 356 (let ((buf (find-file-noselect buffer)))
349 (eval-buffer buf t))) 357 (eval-buffer buf t)))
350 358
351 (defmacro 1value (form)
352 "For coverage testing, indicate FORM should always have the same value."
353 form)
354
355 (defmacro noreturn (form)
356 "For coverage testing, indicate that FORM will never return."
357 `(prog1 ,form
358 (error "Form marked with `noreturn' did return")))
359
360 359
361 ;;;========================================================================= 360 ;;;=========================================================================
362 ;;; Accumulate coverage data 361 ;;; Accumulate coverage data
363 ;;;========================================================================= 362 ;;;=========================================================================
364 363
376 ((eq (aref testcover-vector idx) 'unknown) 375 ((eq (aref testcover-vector idx) 'unknown)
377 (aset testcover-vector idx val)) 376 (aset testcover-vector idx val))
378 ((not (equal (aref testcover-vector idx) val)) 377 ((not (equal (aref testcover-vector idx) val))
379 (aset testcover-vector idx 'ok-coverage))) 378 (aset testcover-vector idx 'ok-coverage)))
380 val) 379 val)
380
381 (defun testcover-1value (idx val)
382 "Internal function for coverage testing. Returns VAL after installing it in
383 `testcover-vector' at offset IDX. Error if FORM does not always return the
384 same value during coverage testing."
385 (cond
386 ((eq (aref testcover-vector idx) '1value)
387 (aset testcover-vector idx (cons '1value val)))
388 ((not (and (eq (car-safe (aref testcover-vector idx)) '1value)
389 (equal (cdr (aref testcover-vector idx)) val)))
390 (error "Value of form marked with `1value' does vary.")))
391 val)
392
381 393
382 394
383 ;;;========================================================================= 395 ;;;=========================================================================
384 ;;; Display the coverage data as color splotches on your code. 396 ;;; Display the coverage data as color splotches on your code.
385 ;;;========================================================================= 397 ;;;=========================================================================
409 (overlays-in def-mark (+ def-mark (aref points (1- len)) 1))) 421 (overlays-in def-mark (+ def-mark (aref points (1- len)) 1)))
410 (while (> len 0) 422 (while (> len 0)
411 (setq len (1- len) 423 (setq len (1- len)
412 data (aref coverage len)) 424 data (aref coverage len))
413 (when (and (not (eq data 'ok-coverage)) 425 (when (and (not (eq data 'ok-coverage))
426 (not (eq (car-safe data) '1value))
414 (setq j (+ def-mark (aref points len)))) 427 (setq j (+ def-mark (aref points len))))
415 (setq ov (make-overlay (1- j) j)) 428 (setq ov (make-overlay (1- j) j))
416 (overlay-put ov 'face 429 (overlay-put ov 'face
417 (if (memq data '(unknown 1value)) 430 (if (memq data '(unknown 1value))
418 'testcover-nohits-face 431 'testcover-nohits-face