(* balanced-test.ml -- testing harness for balanced program *) (* val readIntList : string -> int list read a list of integers from a file; each line of file should consist of single OCaml integer numeral *) let readIntList file = let readInt chan = try Some(int_of_string(input_line chan)) with _ -> None in let chan = open_in file in let rec read xs = match readInt chan with None -> List.rev xs | Some n -> read(n :: xs) in read[] (* val outputIntList : int list -> unit *) let outputIntList xs = let rec out xs = match xs with [] -> () | [x] -> print_int x | (x :: xs) -> (print_int x; print_string " "; out xs) in if List.length xs = 0 then print_string " (empty list)" else if List.length xs <= 15 then (print_string " "; out xs) else print_string " (too many elements to print)" (* val outputIntLists : int list list -> unit *) let outputIntLists xss = let rec out xss = match xss with [] -> () | [xs] -> outputIntList xs | (xs :: xss) -> (outputIntList xs; print_string "\n"; out xss) in if List.length xss = 0 then print_string " (empty list of lists)" else if List.length xss <= 15 then out xss else print_string " (too many to lists to print)" (* val removeDups : 'a list -> 'a list remove duplicate entries in a list that is sorted in ascending (not necessarily strictly) order *) let rec removeDups xs = match xs with [] -> [] | [x] -> [x] | (x1 :: x2 :: xs) -> if x1 = x2 then removeDups(x2 :: xs) else x1 :: removeDups(x2 :: xs) (* val power : int -> 'a list -> 'a list if n >= 0, then power n xs appends xs to itself n times *) let power n xs = let rec pow(n, ys) = if n = 0 then ys else pow(n - 1, xs @ ys) in pow(n, []) (* val upDown : int -> int list *) let upDown n = power n [1] @ [-n] (* val steps : int -> int list if n >= 0, then steps n returns upDown 1 @ ... @ upDown n *) let rec steps n = if n = 0 then [] else steps(n - 1) @ upDown n (* val test : (int list -> 'a) -> (int list -> 'a) -> bool -> unit testing function -- call first with balanced function known to work, and then with one to test, and finally with bool saying whether to compensate for failure to make list of answers have no duplicates *) let test working = let tests = [("empty", []); ("zeros", [0;0;0]); ("from assignment", [1;1;-1;1]); ("no solutions", [1;3;-5;10]); ("only whole", [1;2;3;-1;-3;-2]); ("nested", [1;1;1;-1;-1;-1]); ("small", [-6;6;1;-3;-2;4;1;-2;0;5;2;-6]); ("repetition short", power 10 [1;2;3;-6]); ("steps small", steps 10); ("random1", readIntList "random1.txt"); ("steps medium", steps 25); ("repetition medium", power 100 [1;2;3;-6]); ("random2", readIntList "random2.txt"); ("only whole medium", upDown 999); ("no solutions medium", power 1000 [1]); ("steps long", steps 50); ("repetition long", power 1000 [1;2;3;-6]); ("random3", readIntList "random3.txt"); ("only whole long", upDown 5000); ("no solutions long", power 5000 [1])] in let tests = List.map (function (name, xs) -> (name, xs, working xs)) tests in function bal -> function rmDups -> let bal = if rmDups then (function x -> removeDups(bal x)) else bal in let initTime = Sys.time() in let rec loop ok tsts = match tsts with [] -> ok | (name, xs, yss) :: tsts -> let _ = print_string("starting test \"" ^ name ^ "\"") in let _ = print_newline() in match try Some(bal xs) with _ -> None with None -> (print_string "failure (exception)\n"; print_newline(); loop false tsts) | Some zss -> if zss = yss then (print_string "success\n"; print_newline(); loop ok tsts) else (print_string "failure\n"; print_string "returned:\n"; outputIntLists zss; print_newline(); print_string "should have returned:\n"; outputIntLists yss; print_newline(); loop false tsts) in let ok = loop true tests in let finalTime = Sys.time() in if ok then if rmDups then print_string "passed all tests (if duplicates removed manually)\n" else print_string "passed all tests\n" else if rmDups then print_string "failed some tests (even when duplicates removed manually)\n" else print_string "failed some tests\n"; print_string "processor time used: "; print_float(finalTime -. initTime); print_string " seconds"; print_newline()