diff --git a/lab04/data1.txt b/lab04/data1.txt new file mode 100644 index 0000000..f9f3ad0 --- /dev/null +++ b/lab04/data1.txt @@ -0,0 +1,5 @@ +homer simpson 25 # bad at nuclear engineering + ned flanders 12 !! valid + waylon smithers 100 ! high score + gary chalmers 5 +monty burns diff --git a/lab04/data2.txt b/lab04/data2.txt new file mode 100644 index 0000000..3bef19d --- /dev/null +++ b/lab04/data2.txt @@ -0,0 +1 @@ +monty burns diff --git a/lab04/records.ml b/lab04/records.ml index 6c02ff7..8744d71 100644 --- a/lab04/records.ml +++ b/lab04/records.ml @@ -1,7 +1,19 @@ +(** [record] of a person with a first name, last name, and score *) type record = {firstname: string; lastname: string; score: int};; +(** [new_records f l s] creates a new record with the given firstname [f], + * lastname [l] and score [s] *) let new_record f l s = {firstname = f; lastname = l; score = s};; +(**/**) +let test_new_record () = + assert (new_record "a" "b" 1 = {firstname = "a"; lastname = "b"; score = 1}); + assert (new_record "b" "a" 2 = {firstname = "b"; lastname = "a"; score = 2}); + assert (new_record "c" "d" 3 = {firstname = "c"; lastname = "d"; score = 3}) +(**/**) + +(** [print_records r] takes a list of records [r] and prints + * each record neatly to the console *) let rec print_records r = match r with | [] -> () @@ -15,12 +27,59 @@ let rec records_insert x l = | y :: ys when x.score < y.score -> y :: records_insert x ys | _ -> x :: l +(**/**) +let test_records_insert () = + assert (records_insert + {firstname = "a"; lastname = "b"; score = 1} [] = + [{firstname = "a"; lastname = "b"; score = 1}] + ); + assert (records_insert + {firstname = "a"; lastname = "b"; score = 1} + [{firstname = "c"; lastname = "d"; score = 2}] = + [ + {firstname = "c"; lastname = "d"; score = 2}; + {firstname = "a"; lastname = "b"; score = 1} + ]); + assert (records_insert + {firstname = "e"; lastname = "f"; score = 2} + [ + {firstname = "c"; lastname = "d"; score = 3}; + {firstname = "a"; lastname = "b"; score = 1} + ] = + [ + {firstname = "c"; lastname = "d"; score = 3}; + {firstname = "e"; lastname = "f"; score = 2}; + {firstname = "a"; lastname = "b"; score = 1} + ]) +(**/**) + (** [records_insertion_sort l] sorts list of records [l] in ascending order *) -let rec records_insertion_sort l = +let rec sort_records l = match l with | [] -> [] - | x :: xs -> records_insert x (records_insertion_sort xs) + | x :: xs -> records_insert x (sort_records xs) +(**/**) +let test_sort_records () = + assert (sort_records [] = []); + assert (sort_records + [{firstname = "a"; lastname = "b"; score = 1}] = + [{firstname = "a"; lastname = "b"; score = 1}]); + + assert (sort_records [ + {firstname = "c"; lastname = "d"; score = 3}; + {firstname = "a"; lastname = "b"; score = 1}; + {firstname = "e"; lastname = "f"; score = 2}; + ] = [ + {firstname = "c"; lastname = "d"; score = 3}; + {firstname = "e"; lastname = "f"; score = 2}; + {firstname = "a"; lastname = "b"; score = 1}; + ]) +(**/**) + +(** [parse l] takes in a line [l] and parses the line to extract + * firstname, lastname, and score, returning Some record if successful + * or None if the input line [l] contains bad data *) let rec parse l = try Scanf.sscanf l " %s %s %s" (fun f l s -> @@ -31,6 +90,21 @@ let rec parse l = with | Scanf.Scan_failure _ -> None +(**/**) +let test_parse () = + assert (parse "" = None); + assert (parse "Bart simpson 5abc" = None); + assert (parse "Lisa simpson 130" = None); + assert (parse "Homer Simpson -5" = None); + assert (parse "Homer Simpson 5" = + Some {firstname = "Homer"; lastname = "Simpson"; score = 5}); + assert (parse "Homer Simpson 5 blah blah blah" = + Some {firstname = "Homer"; lastname = "Simpson"; score = 5}) +(**/**) + +(** [read_file acc ic] takes in an accumulator [acc] and an input channel [ic] + * and oterates over it input channel [ic] to parse each line and store the + * parsed result into the accumulator [acc] *) let rec read_file acc ic = try match parse @@ input_line ic with @@ -39,9 +113,35 @@ let rec read_file acc ic = with | End_of_file -> close_in ic; acc +(**/**) +let test_read_file () = + assert (read_file [] @@ open_in "data.txt" = [ + {firstname = "gary"; lastname = "chalmers"; score = 5}; + {firstname = "waylon"; lastname = "smithers"; score = 100}; + {firstname = "homer"; lastname = "simpson"; score = 25}; + ]); + assert (read_file [] @@ open_in "data1.txt" = [ + {firstname = "gary"; lastname = "chalmers"; score = 5}; + {firstname = "waylon"; lastname = "smithers"; score = 100}; + {firstname = "ned"; lastname = "flanders"; score = 12}; + {firstname = "homer"; lastname = "simpson"; score = 25}; + ]); + assert (read_file [] @@ open_in "data2.txt" = []) +(**/**) + +(**/**) +let run_all_tests () = + test_new_record(); + test_parse(); + test_read_file(); + test_records_insert(); + test_sort_records() +(**/**) + +(** main program entry from cli *) let () = if Array.length Sys.argv = 1 then Printf.printf "%s: expects 1 file input.\nUsage: \"%s \"\n" Sys.argv.(0) Sys.argv.(0) else let ic = open_in Sys.argv.(1) in - print_records @@ records_insertion_sort @@ read_file [] ic;; + print_records @@ sort_records @@ read_file [] ic;;