;; drscheme-mp5-init.scm - compatibility file for DrScheme ;; by Mitch Wand and Dave Herman ;; 2004-12-19 ;; usage: (require "drscheme-mp5-init.scm") ;;; makes structs printable, and provides basic functionality for testing. ;;; revision history: ;;; 1.5 added provide make-parameter ;;; 1.4 1/25/05. changed pretty-print to pretty-display (module drscheme-mp5-init mzscheme (let ((version "plt360 2/25/07") (filename "drscheme-mp5-init.scm")) (printf "~a ~a~%" filename version)) ;; show the contents of define-datatype values (print-struct #t) (require (lib "pretty.ss")) (provide (all-from (lib "pretty.ss"))) (require (lib "trace.ss")) (provide (all-from (lib "trace.ss"))) (provide make-parameter) (provide run-experiment run-tests! stop-after-first-error ) (require (only mzscheme values let*-values)) ;; safely apply procedure fn to a list of args. ;; if successful, return (cons #t val) ;; if eopl:error is invoked, returns (cons #f string), where string is the ;; format string generated by eopl:error. If somebody manages to raise a ;; value other than an exception, then the raised value is reported. (define apply-safely (lambda (proc args) (with-handlers ([(lambda (exn) #t) ; catch any error (lambda (exn) ; evaluate to a failed test result (cons #f (if (exn? exn) (exn-message exn) exn)))]) (let ([actual (apply proc args)]) (cons #t actual))))) ;; Trace = [Listof b] | error ;; ;; run-experiment : ;; ((a ...) -> b) * (a ...) * Trace (b * b->bool) ;; -> (cons bool b) (cons bool [Listof b]) ;; usage: (run-experiment fn args correct-trace equal-answer?) ;; Applies fn to args. Compares the result to correct-trace. First value ;; returned holds (bool b) where bool indicates whether the trace is correct. ;; ;; Also, logs any output of fn (through logged:print). Compares logged output ;; to correct-trace using equal-answer?. The second value returned holds (bool ;; [Listof b]), where bool indicates whether the logged output matches ;; correct-trace. (define run-experiment (lambda (fn args correct-trace equal-answer?) (let* ( ;; init logged-stream (dummy1 (initialize-logged-stream!)) (result (apply-safely fn args)) ;; get the list of values given to logged:print (logged-prints (get-logged-stream)) ;; ans is either the answer or the args to eopl:error (error-thrown? (not (car result))) (ans (cdr result)) (correct-anwser? (if (eqv? correct-trace 'error) error-thrown? (correct-trace? correct-trace logged-prints equal-answer?)))) (values (cons correct-anwser? ans) (cons correct-anwser? logged-prints))))) ;; NumOrBool = Number | Boolean ;; Printval = (num-val n) | (bool-val b) ;; ;; correct-trace? : [Listof NumOrBool] [Listof Printval] ;; (Printval NumOrBool -> Boolean) -> Boolean | Error ;; ;; usage : (correct-trace? a e test) ;; produces : true if for all corresponding elements of a and e (test a e)=#t ;; false if one of (test a e) =#f and error if (test a e) = error (define correct-trace? (lambda (expected actual equal-answer?) (if (= (length actual) (length expected)) (andmap equal-answer? actual expected) (error 'correct-trace? "Trace mismatch. ~% actual trace = ~s ~% correct-trace = ~s ~%" actual expected)))) (define stop-after-first-error (make-parameter #f)) ;; run-tests! : (arg -> outcome) * (any * any -> bool) * (list-of test) ;; -> unspecified ;; where: ;; test ::= (name arg outcome) ;; outcome ::= ERROR | any ;; usage: (run-tests! run-fn equal-answer? tests) ;; for each item in tests, apply run-fn to the arg. Check to see if ;; the trace outcome is right, comparing values using equal-answer?. ;; ;; print a log of the tests. ;; at the end, print either "no bugs found" or the list of tests ;; failed. ;; Normally, run-tests! will recover from any error and continue to ;; the end of the test suite. This behavior can be altered by ;; setting (stop-after-first-error #t). (define (run-tests! run-fn equal-answer? tests) (let ((tests-failed '())) (for-each (lambda (test-item) (let ((name (car test-item)) (pgm (cadr test-item)) (correct-trace (caddr test-item))) (printf "test: ~a~%~a~%" name pgm) (let*-values (((result traces-result) (run-experiment run-fn (list pgm) correct-trace equal-answer? ))) (let ((correct? (car result)) (correct-trace? (car traces-result)) (actual-answer (cdr result)) (actual-trace (cdr traces-result))) ;;(printf "correct outcome: ~a~%" correct-answer) ;;(printf "actual outcome: ") ;;(pretty-display actual-answer) (printf "correct trace: ~a~%" correct-trace) (printf "actual trace: ~a~%" actual-trace) (if correct-trace? (printf "correct~%~%") (begin (printf "incorrect~%~%") ;; stop on first error if stop-after-first? is set: (if (stop-after-first-error) (error name "incorrect outcome detected")) (set! tests-failed (cons name tests-failed)))))))) tests) (if (null? tests-failed) (printf "no bugs found~%") (printf "incorrect answers on tests: ~a~%" (reverse tests-failed))))) ;;skotthe@ccs.neu.edu ;;Sat Mar 4 18:21:05 EST 2006 ;; ;; Provides logged:printf that can be used instead of eopl:printf. ;; logged:printf logs its arguments in logged-stream using mutation. The ;; functions initialize-logged-stream! reset the logged data and get-logged-stream ;; return the logged data as a scheme list. (provide logged:printf) ;; initialize-logged-stream! : -> void ;; produces : Sets logged-stream to '() (define initialize-logged-stream! (lambda () (set! logged-stream '()))) ;; get-logged-stream : -> [Listof Expval] ;; produces : returns the logged expvals printed tou stdout (define get-logged-stream (lambda () logged-stream)) (define logged-stream '()) ;; logged:printf : a1 a2 ... -> void ;; produces : Wrapper to eopl:printf. Logs the values passed to eopl:printf ;; excluding the format string (1st argument to eopl:printf). Then calls ;; eopl:printf. (define logged:printf (lambda args (let ((fstr (car args)) (vals (cdr args))) (begin (set! logged-stream (append logged-stream vals)) (apply printf args))))) )