From f4ea9caad7b1880139eba121d27a8e47b4426836 Mon Sep 17 00:00:00 2001 From: christian-byrne Date: Thu, 19 Sep 2024 22:30:11 -0700 Subject: [PATCH] Add assignment 4 and tests --- src/ica05/ica5.sml | 8 ++-- tests/test_ica5.sml | 66 ++++++++++++++--------------- tests/utils.sml | 100 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 129 insertions(+), 45 deletions(-) diff --git a/src/ica05/ica5.sml b/src/ica05/ica5.sml index 0162a6a..f3da44b 100644 --- a/src/ica05/ica5.sml +++ b/src/ica05/ica5.sml @@ -19,7 +19,7 @@ fun countZeros([]) = 0 (* Question 5 *) fun orList([]) = false - | orList(boolList) = orList(tl(boolList)) orelse hd(boolList); + | orList(boolList) = hd(boolList) orelse orList(tl(boolList)); (* Question 6 *) fun andList([]) = true @@ -43,6 +43,6 @@ fun removeZeros([]) = [] (* Question 10 *) fun combineLists([], [], operator) = [] - | combineLists([], li2, operator) = operator(hd(li2)) :: combineLists([], tl(li2), operator) - | combineLists(li1, [], operator) = operator(hd(li1)) :: combineLists(tl(li1), [], operator) - | combineLists(li1, li2, operator) = operator(hd(li1) + hd(li2)) :: combineLists(tl(li1), tl(li2), operator); + | combineLists([], li2, operator) = hd(li2) :: combineLists([], tl(li2), operator) + | combineLists(li1, [], operator) = hd(li1) :: combineLists(tl(li1), [], operator) + | combineLists(li1, li2, operator) = operator(hd(li1), hd(li2)) :: combineLists(tl(li1), tl(li2), operator); diff --git a/tests/test_ica5.sml b/tests/test_ica5.sml index ba49231..e239845 100644 --- a/tests/test_ica5.sml +++ b/tests/test_ica5.sml @@ -15,7 +15,7 @@ val testCasesLog2 = [ (log2, 128, 7), (* 2^7 = 128 *) (log2, 256, 8) (* 2^8 = 256 *) ]; -runTestCases(testCasesLog2); +runTestCasesIntInt(testCasesLog2); val testCasesFactorial = [ (factorial, 0, 1), (* 0! = 1 *) @@ -29,7 +29,7 @@ val testCasesFactorial = [ (factorial, 8, 40320), (* 8! = 40320 *) (factorial, 10, 3628800) (* 10! = 3628800 *) ]; -runTestCases(testCasesFactorial); +runTestCasesIntInt(testCasesFactorial); val testCasesFib = [ (* a_n = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55} *) @@ -45,7 +45,7 @@ val testCasesFib = [ (fib, 9, 34), (fib, 10, 55) ]; -runTestCases(testCasesFib); +runTestCasesIntInt(testCasesFib); val testCasesCountZeros = [ (countZeros, [0, 1, 0, 1, 0], 3), @@ -58,7 +58,7 @@ val testCasesCountZeros = [ (countZeros, [1, 0, 1, 0, 1], 2), (countZeros, [0, 0, 1, 0, 0, 0], 5) ]; -runTestCases(testCasesCountZeros); +runTestCasesIntListInt(testCasesCountZeros); val testCasesOrList = [ (orList, [true, true, true], true), @@ -72,7 +72,7 @@ val testCasesOrList = [ (orList, [false], false), (* Single false element *) (orList, [true], true) (* Single true element *) ]; -runTestCases(testCasesOrList); +runTestCasesBoolListBool(testCasesOrList); val testCasesAndList = [ (andList, [true, true, true], true), @@ -82,7 +82,7 @@ val testCasesAndList = [ (andList, [true], true), (andList, [false], false) ]; -runTestCases(testCasesAndList); +runTestCasesBoolListBool(testCasesAndList); val testCasesAddLists = [ (addLists, ([1, 2, 3], [4, 5, 6]), [5, 7, 9]), @@ -93,7 +93,7 @@ val testCasesAddLists = [ (addLists, ([1, 2, 3], [4, 5, 6, 7]), [5, 7, 9, 7]), (addLists, ([1, 2, 3, 4, 5], [4, 5, 6]), [5, 7, 9, 4, 5]) ]; -runTestCases(testCasesAddLists); +runTestCasesIntListIntList(testCasesAddLists); val testCasesReverseList = [ (reverseList, [1, 2, 3], [3, 2, 1]), @@ -105,7 +105,7 @@ val testCasesReverseList = [ (reverseList, [1, 0, 0, 1, 0], [0, 1, 0, 0, 1]), (reverseList, [0, 0, 0], [0, 0, 0]) ]; -runTestCases(testCasesReverseList); +runTestCasesIntListIntList(testCasesReverseList); fun removeZeros([]) = [] | removeZeros(li) = @@ -122,33 +122,33 @@ val testCasesRemoveZeros = [ (removeZeros, [0, 0, 0, 1, 0], [1]), (removeZeros, [1, 0, 1, 0, 1], [1, 1, 1]) ]; -runTestCases(testCasesRemoveZeros); +runTestCasesIntListIntList(testCasesRemoveZeros); -fun add(x, y) = x + y; -fun subtract(x, y) = x - y; -fun multiply(x, y) = x * y; +fun mockAdd(x, y) = x + y; +fun mockModulus(x, y) = x mod y; +fun mockDiv(x, y) = x div y; fun doNothing(x, y) = x; val testCasesCombineLists = [ - (combineLists, ([1, 2, 3], [4, 5, 6], add), [5, 7, 9]), - (combineLists, ([1, 2], [4, 5, 6], add), [5, 7, 6]), - (combineLists, ([1, 2, 3], [], add), [1, 2, 3]), - (combineLists, ([], [4, 5, 6], add), [4, 5, 6]), - (combineLists, ([], [], add), []), - (combineLists, ([1, 2, 3], [4, 5, 6], subtract), [-3, -3, -3]), - (combineLists, ([1, 2], [4, 5, 6], subtract), [-3, -3, 6]), - (combineLists, ([1, 2, 3], [], subtract), [1, 2, 3]), - (combineLists, ([], [4, 5, 6], subtract), [-4, -5, -6]), - (combineLists, ([], [], subtract), []), - (combineLists, ([1, 2, 3], [4, 5, 6], multiply), [4, 10, 18]), - (combineLists, ([1, 2], [4, 5, 6], multiply), [4, 10, 6]), - (combineLists, ([1, 2, 3], [], multiply), [1, 2, 3]), - (combineLists, ([], [4, 5, 6], multiply), [4, 5, 6]), - (combineLists, ([], [], multiply), []), - (combineLists, ([1, 2, 3], [4, 5, 6], doNothing), [5, 7, 9]), - (combineLists, ([1, 2], [4, 5, 6], doNothing), [5, 7, 6]), - (combineLists, ([1, 2, 3], [], doNothing), [1, 2, 3]), - (combineLists, ([], [4, 5, 6], doNothing), [4, 5, 6]), - (combineLists, ([], [], doNothing), []) + (combineLists, [1, 2, 3], [4, 5, 6], mockAdd, [5, 7, 9]), + (combineLists, [1, 2], [4, 5, 6], mockAdd, [5, 7, 6]), + (combineLists, [1, 2, 3], [], mockAdd, [1, 2, 3]), + (combineLists, [], [4, 5, 6], mockAdd, [4, 5, 6]), + (combineLists, [], [], mockAdd, []), + (combineLists, [1, 2, 3], [4, 5, 6], mockModulus, [1, 2, 3]), + (combineLists, [1, 2], [4, 5, 6], mockModulus, [1, 2, 6]), + (combineLists, [1, 2, 3], [], mockModulus, [1, 2, 3]), + (combineLists, [], [4, 5, 6], mockModulus, [4, 5, 6]), + (combineLists, [], [], mockModulus, []), + (combineLists, [1, 2, 3], [4, 5, 6], mockDiv, [0, 0, 0]), + (combineLists, [1, 2], [4, 5, 6], mockDiv, [0, 0, 6]), + (combineLists, [1, 2, 3], [], mockDiv, [1, 2, 3]), + (combineLists, [], [4, 5, 6], mockDiv, [4, 5, 6]), + (combineLists, [], [], mockDiv, []), + (combineLists, [1, 2, 3], [4, 5, 6], doNothing, [1, 2, 3]), + (combineLists, [1, 2], [4, 5, 6], doNothing, [1, 2, 6]), + (combineLists, [1, 2, 3], [], doNothing, [1, 2, 3]), + (combineLists, [], [4, 5, 6], doNothing, [4, 5, 6]), + (combineLists, [], [], doNothing, []) ]; -runTestCases(testCasesCombineLists); +runTestCasesIntListIntListOperatorToIntList(testCasesCombineLists); diff --git a/tests/utils.sml b/tests/utils.sml index aa513ec..c13c62f 100644 --- a/tests/utils.sml +++ b/tests/utils.sml @@ -1,25 +1,109 @@ +(* Function to convert int to string *) +fun valueToStringInt(n: int) = Int.toString(n); + +(* Function to convert bool to string *) +fun valueToStringBool(true) = "true" + | valueToStringBool(false) = "false"; + +(* Function to convert int list to string (example) *) +fun valueToStringIntList([]) = "[]" + | valueToStringIntList(lst) = "[" ^ String.concatWith ", " (List.map Int.toString lst) ^ "]"; (* Function to color the output in the terminal *) fun red(s) = "\027[31m" ^ s ^ "\027[0m" -fun green(s) = "\027[32m" ^ s ^ "\027[0m" +fun green(s) = "\027[32m" ^ s ^ "\027[0m"; +(* Generic test runner for int -> int functions *) +fun runTestCasesIntInt([]) = () + | runTestCasesIntInt(testCaseList) = + let + val (f, param, expected) = hd(testCaseList); + val result = f(param); + val testMessage = + if result <> expected then + red("Test failed\n") ^ + "Expected: " ^ valueToStringInt(expected) ^ "\n" ^ + "Actual: " ^ valueToStringInt(result) ^ "\n\n" + else + green("Test passed\n"); + in + print(testMessage); + (* Error code so GH actions can detect if a test failed *) + if result <> expected then raise Fail("Test failed") else runTestCasesIntInt(tl(testCaseList)) + end; -(* Enhanced test case runner with more visual indicators *) -fun runTestCases([]) = () - | runTestCases(testCaseList) = +(* Generic test runner for bool list -> bool functions *) +fun runTestCasesBoolListBool([]) = () + | runTestCasesBoolListBool(testCaseList) = let val (f, param, expected) = hd(testCaseList); val result = f(param); val testMessage = if result <> expected then red("Test failed\n") ^ - "Expected: " ^ Int.toString(expected) ^ "\n" ^ - "Actual: " ^ Int.toString(result) ^ "\n\n" + "Expected: " ^ valueToStringBool(expected) ^ "\n" ^ + "Actual: " ^ valueToStringBool(result) ^ "\n\n" + else + green("Test passed\n"); + in + print(testMessage); + (* Error code so GH actions can detect if a test failed *) + if result <> expected then raise Fail("Test failed") else runTestCasesBoolListBool(tl(testCaseList)) + end; + +fun runTestCasesIntListInt([]) = () +(* going from int list to a single int *) + | runTestCasesIntListInt(testCaseList) = + let + val (f, param, expected) = hd(testCaseList); + val result = f(param); + val testMessage = + if result <> expected then + red("Test failed\n") ^ + "Expected: " ^ valueToStringInt(expected) ^ "\n" ^ + "Actual: " ^ valueToStringInt(result) ^ "\n\n" + else + green("Test passed\n"); + in + print(testMessage); + (* Error code so GH actions can detect if a test failed *) + if result <> expected then raise Fail("Test failed") else runTestCasesIntListInt(tl(testCaseList)) + end; + +(* Generic test runner for int list -> int list functions *) + +fun runTestCasesIntListIntList([]) = () + | runTestCasesIntListIntList(testCaseList) = + let + val (f, param, expected) = hd(testCaseList); + val result = f(param); + val testMessage = + if result <> expected then + red("Test failed\n") ^ + "Expected: " ^ valueToStringIntList(expected) ^ "\n" ^ + "Actual: " ^ valueToStringIntList(result) ^ "\n\n" + else + green("Test passed\n"); + in + print(testMessage); + (* Error code so GH actions can detect if a test failed *) + if result <> expected then raise Fail("Test failed") else runTestCasesIntListIntList(tl(testCaseList)) + end; + +(* Generic test runner for functions *) +fun runTestCasesIntListIntListOperatorToIntList([]) = () + | runTestCasesIntListIntListOperatorToIntList(testCaseList) = + let + val (f, param1, param2, operator, expected) = hd(testCaseList); + val result = f(param1, param2, operator); + val testMessage = + if result <> expected then + red("Test failed\n") ^ "Expected: " ^ valueToStringIntList(expected) ^ "\n" ^ + "Actual: " ^ valueToStringIntList(result) ^ "\n\n" else green("Test passed\n"); in print(testMessage); (* Error code so GH actions can detect if a test failed *) - if result <> expected then raise Fail("Test failed") else runTestCases(tl(testCaseList)) - (* runTestCases(tl(testCaseList)) *) + if result <> expected then raise Fail("Test failed") else runTestCasesIntListIntListOperatorToIntList(tl(testCaseList)) end;