(* Utility functions for Assignment 2 auto-tester. *) (* Exception raised by undefined functions. *) exception Undefined; (* Total grade and accumulator for student's grade. *) val total = ref 0.0; val grade = ref 0.0; (* Conversion functions used to print inputs and outputs -- declared here to avoid clutter of "autoloading" messages during testing. *) fun string2string x = "\"" ^ x ^ "\""; val int2string = Int.toString; val bigint2string = LargeInt.toString; val real2string = Real.toString; local fun list2string L = "[" ^ String.concatWith "," L ^ "]" in val stringlist2string = list2string o (map string2string) val intlist2string = list2string o (map int2string) end; (* Returns true iff x = y, within tolerance epsilon. *) fun real_equal (epsilon:real) (x,y) = abs(x-y) <= epsilon; val real_eq = real_equal 1E~12; (* Reverse a string. *) val string_rev = implode o rev o explode; (* Run and display a single test case for one function, where func = function to test, name = name of function (for printing), input = input value to test, strin = function to convert input values to strings, output = expected output value, strout = function to convert output values to strings, comp = function to compare input and output values, desc = description of test case, grade = reference to grade (whose value is to be updated), worth = value of this test. *) fun test func name input strin output strout comp desc grade (worth:real) = ( print (" ..." ^ name ^ " " ^ strin input ^ " = " ^ strout output ^ " " ^ desc ^ "\n--> "); if comp (func input, output) handle _ => false then (print (real2string worth ^ "\n"); grade := !grade + worth) else print ("0.0 -- unexpected output: " ^ ("'" ^ strout (func input) ^ "'" handle Undefined => "UNDEFINED" | _ => "EXCEPTION") ^ "\n") ); (* Run and display a "suite" of related test cases for one function -- related in that they all have the same input and output types, where total = reference to total worth of all tests in the suite (whose value is to be computed), grade = reference to grade (whose value is to be updated), func = function to test, name = name of function (for printing), strin = function to convert input values to strings, strout = function to convert output values to strings, comp = function to compare input and output values, and the last argument is a list of test cases of the form (input,output,desc,worth), where input = input value to test, output = expected output value, desc = description of test case, worth = value of this test. *) fun runtests total grade func name strin strout comp nil = () | runtests total grade func name strin strout comp ((input,output,desc,worth:real)::rest) = ( test func name input strin output strout comp desc grade worth; total := !total + worth; runtests total grade func name strin strout comp rest ); (* Exit cleanly from the interpreter. *) fun exit x = Unix.exit (Word8.fromInt x);