package prolog.logic import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.RepeatedTest import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import prolog.ast.terms.Integer import prolog.ast.terms.Term import prolog.ast.terms.Variable class ArithmeticTests { @Test fun `1_between_0_and_2`() { val result = between(Integer(0), Integer(2), Integer(1)) assertTrue(result.any(), "Expected 1 to be between 0 and 2") assertEquals(emptyMap(), result.first(), "Expected no substitutions") } @Test fun `3_not_between_0_and_2`() { val result = between(Integer(0), Integer(2), Integer(3)) assertTrue(result.none(), "Expected 3 not to be between 0 and 2") } @Test fun numbers_between_0_and_2() { val result = between(Integer(0), Integer(2), Variable("X")) val expectedResults = listOf( mapOf(Variable("X") to Integer(0)), mapOf(Variable("X") to Integer(1)), mapOf(Variable("X") to Integer(2)) ) val actualResults = result.toList() assertEquals(expectedResults.size, actualResults.size, "Expected 3 results") for ((expected, actual) in expectedResults.zip(actualResults)) { for ((key, value) in expected) { assertTrue(actual.containsKey(key), "Expected key $key to be present") assertTrue( equivalent(value, actual[key]!!), "Expected value $value for key $key, but got ${actual[key]}" ) } } } @Test fun `succ(0) is 1`() { val t1 = Integer(0) val expected = Integer(1) val result = succ(t1, expected, emptyMap()).toList() assertEquals(1, result.size, "Expected 0 + 1 to be equal to 1") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "Expected no substitutions") } @Test fun `succ(1) is 2`() { val t1 = Integer(1) val expected = Integer(2) val result = succ(t1, expected, emptyMap()).toList() assertEquals(1, result.size, "Expected 1 + 1 to be equal to 2") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "Expected no substitutions") } @Test fun `succ(1) is var`() { val t1 = Integer(1) val t2 = Variable("X") val expected = Integer(2) val result = succ(t1, t2, emptyMap()).toList() assertEquals(1, result.size, "Expected 1 + 1 to be equal to X") assertTrue(result[0].isSuccess, "Expected success") assertEquals(expected, result[0].getOrNull()!![t2], "Expected X to be equal to 2") } @Test fun `succ(bound-to-1-var) is 2`() { val t1 = Variable("X") val t2 = Integer(2) t1.bind(Integer(1)) val result = succ(t1, t2, emptyMap()).toList() assertEquals(1, result.size, "Expected X + 1 to be equal to 2") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "Expected no substitutions") } @Test fun `succ(bound-to-1-var) is 2 by map`() { val t1 = Variable("X") val t2 = Integer(2) val result = succ(t1, t2, mapOf(t1 to Integer(1))).toList() assertEquals(1, result.size, "Expected X + 1 to be equal to 2") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "Expected no substitutions") } @Test fun `succ(bound-to-1-var) is var`() { val t1 = Variable("X") val t2 = Variable("Y") t1.bind(Integer(1)) val result = succ(t1, t2, emptyMap()).toList() assertEquals(1, result.size, "Expected X + 1 to be equal to Y") assertTrue(result[0].isSuccess, "Expected success") assertEquals(Integer(2), result[0].getOrNull()!![t2], "Expected Y to be equal to 2") } @Test fun `succ(bound-to-1-var) is var by map`() { val t1 = Variable("X") val t2 = Variable("Y") val result = succ(t1, t2, mapOf(t1 to Integer(1))).toList() assertEquals(1, result.size, "Expected X + 1 to be equal to Y") assertTrue(result[0].isSuccess, "Expected success") assertEquals(Integer(2), result[0].getOrNull()!![t2], "Expected Y to be equal to 2") } @Test fun `succ(var, 0) fails silently`() { val t1 = Variable("X") val t2 = Integer(0) val result = succ(t1, t2, emptyMap()).toList() assertTrue(result.isEmpty(), "Expected X + 1 to fail") } @Test fun `1_plus_2_is_3`() { val t1 = Integer(1) val t2 = Integer(2) val t3 = Integer(3) val result = plus(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "1 + 2 should be equal to 3") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "1 + 2 should be equal to 3") } @Test fun `1_plus_2_is_not_4`() { val t1 = Integer(1) val t2 = Integer(2) val t3 = Integer(4) val result = plus(t1, t2, t3, emptyMap()) assertTrue(result.none(), "1 + 2 should not be equal to 4") } @Test fun `1_plus_2_is_variable`() { val t1 = Integer(1) val t2 = Integer(2) val t3 = Variable("X") val result = plus(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "1 + 2 should be equal to X") assertTrue(result[0].isSuccess, "Expected success") assertEquals(Integer(3), result[0].getOrNull()!![t3], "X should be equal to 3") } @Test fun `1_plus_variable_is_3`() { val t1 = Integer(1) val t2 = Variable("X") val t3 = Integer(3) val result = plus(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "1 + X should be equal to 3") assertTrue(result[0].isSuccess, "Expected success") assertEquals(Integer(2), result[0].getOrNull()!![t2], "X should be equal to 2") } @Test fun variable_plus_2_is_3() { val t1 = Variable("X") val t2 = Integer(2) val t3 = Integer(3) val result = plus(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "X + 2 should be equal to 3") assertTrue(result[0].isSuccess, "Expected success") assertEquals(Integer(1), result[0].getOrNull()!![t1], "X should be equal to 1") } @Test fun `1 plus 2 is bound-to-3-var`() { val t1 = Integer(1) val t2 = Integer(2) val t3 = Variable("X") t3.bind(Integer(3)) val result = plus(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "1 + 2 should be equal to X") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "t3 should not be rebound") } @Test fun `1 plus 2 is bound-to-3-var by map`() { val t1 = Integer(1) val t2 = Integer(2) val t3 = Variable("X") val result = plus(t1, t2, t3, mapOf(Variable("X") to Integer(3))).toList() assertEquals(1, result.size, "1 + 2 should be equal to X") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "t3 should not be rebound") } @Test fun `1 plus 2 is bound-to-4-var`() { val t1 = Integer(1) val t2 = Integer(2) val t3 = Variable("X") t3.bind(Integer(4)) val result = plus(t1, t2, t3, emptyMap()) assertTrue(result.none(), "1 + 2 should not be equal to X") } @Test fun `1 plus bound-to-2-var is 3`() { val t1 = Integer(1) val t2 = Variable("X") val t3 = Integer(3) t2.bind(Integer(2)) val result = plus(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "1 + X should be equal to 3") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "t2 should not be rebound") } @Test fun `1 plus bound-to-2-var is not 4`() { val t1 = Integer(1) val t2 = Variable("X") val t3 = Integer(4) t2.bind(Integer(2)) val result = plus(t1, t2, t3, emptyMap()) assertTrue(result.none(), "1 + X should not be equal to 4") } @Test fun `bound-to-1-var plus 2 is 3`() { val t1 = Variable("X") val t2 = Integer(2) val t3 = Integer(3) t1.bind(Integer(1)) val result = plus(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "X + 2 should be equal to 3") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.none(), "t1 should not be rebound") } @Test fun `bound-to-1-var plus 2 is not 4`() { val t1 = Variable("X") val t2 = Integer(2) val t3 = Integer(4) t1.bind(Integer(1)) val result = plus(t1, t2, t3, emptyMap()) assertTrue(result.none(), "X + 2 should not be equal to 4") } @Test fun `two unbound vars plus should throw`() { val t1 = Variable("X") val t2 = Variable("Y") val t3 = Integer(3) val result = plus(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "There should be one solution") assertTrue(result[0].isFailure, "Expected failure") assertTrue(result[0].exceptionOrNull() is IllegalArgumentException, "Expected IllegalArgumentException") } @Test fun `bound-to-1-var plus bound-to-2-var is variable`() { val t1 = Variable("X") val t2 = Variable("Y") val t3 = Variable("Z") t1.bind(Integer(1)) t2.bind(Integer(2)) val result = plus(t1, t2, t3, emptyMap()).toList() assertTrue(result.isNotEmpty(), "X + Y should be equal to Z") assertTrue(result[0].isSuccess, "Expected success") assertTrue(equivalent(result[0].getOrThrow()[t3]!!, Integer(3)), "Z should be equal to 3") } @Test fun `1 times 1 is 1`() { val t1 = Integer(1) val t2 = Integer(1) val t3 = Integer(1) val result = mul(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "There should be one solution") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "1 * 1 should already be equal to 1") } @Test fun `1 times 2 is 2`() { val t1 = Integer(1) val t2 = Integer(2) val t3 = Integer(2) val result = mul(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "There should be one solution") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "1 * 2 should already be equal to 2") } @Test fun `2 times 3 is 6`() { val t1 = Integer(2) val t2 = Integer(3) val t3 = Integer(6) val result = mul(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "There should be one solution") assertTrue(result[0].isSuccess, "Expected success") assertTrue(result[0].getOrNull()!!.isEmpty(), "2 * 3 should already be equal to 6") } @Test fun `2 times 3 is not 4`() { val t1 = Integer(2) val t2 = Integer(3) val t3 = Integer(4) val result = mul(t1, t2, t3, emptyMap()) assertTrue(result.none(), "2 * 3 should not be equal to 4") } @RepeatedTest(100) fun `random test for mul`() { val t1 = Integer((0..1000).random()) val t2 = Integer((0..1000).random()) val t3 = Variable("X") val result = mul(t1, t2, t3, emptyMap()).toList() assertEquals(1, result.size, "There should be one solution") assertTrue(result[0].isSuccess, "Expected success") assertEquals(Integer(t1.value * t2.value), result[0].getOrNull()!![t3], "X should be equal to ${t1.value * t2.value}") } }