package prolog.builtins import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import prolog.Program import prolog.ast.logic.Clause import prolog.ast.logic.Fact import prolog.ast.logic.Rule import prolog.ast.terms.Atom import prolog.ast.terms.Structure import prolog.ast.terms.Variable import kotlin.test.assertTrue class DatabaseOperatorsTests { abstract class AssertTestsBase { protected abstract fun createAssert(clause: Clause): Structure @BeforeEach fun setup() { Program.clear() } @ParameterizedTest @ValueSource(classes = [AssertA::class, AssertZ::class, Assert::class]) fun `assert(fact atom)`(assertKind: Class<*>) { val fact = Fact(Atom("a")) createAssert(fact).satisfy(emptyMap()) assertEquals(1, Program.internalDb.predicates.size, "Expected 1 predicate") assertEquals(fact, Program.internalDb.predicates["a/_"]!!.clauses[0]) } @Test fun `assert(fact structure)`() { val fact = Fact(Structure(Atom("a"), listOf(Atom("b")))) createAssert(fact).satisfy(emptyMap()) assertEquals(1, Program.internalDb.predicates.size, "Expected 1 predicate") assertEquals(fact, Program.internalDb.predicates["a/1"]!!.clauses[0]) } @Test fun `assert(rule)`() { val rule = Rule( Structure(Atom("a"), listOf(Atom("b"))), Atom("c") ) createAssert(rule).satisfy(emptyMap()) assertEquals(1, Program.internalDb.predicates.size, "Expected 1 predicate") assertEquals(rule, Program.internalDb.predicates["a/1"]!!.clauses[0]) } } @Nested class AssertTests : AssertTestsBase() { override fun createAssert(clause: Clause): Structure { return Assert(clause) } } @Nested class AssertATests : AssertTestsBase() { override fun createAssert(clause: Clause): Structure { return AssertA(clause) } @Test fun `asserta adds to the beginning`() { val rule1 = Rule( Structure(Atom("a"), listOf(Atom("b"))), Atom("c") ) val rule2 = Rule( Structure(Atom("a"), listOf(Atom("d"))), Atom("e") ) AssertA(rule1).satisfy(emptyMap()) AssertA(rule2).satisfy(emptyMap()) assertEquals(1, Program.internalDb.predicates.size, "Expected 1 predicate") assertEquals(rule2, Program.internalDb.predicates["a/1"]!!.clauses[0]) assertEquals(rule1, Program.internalDb.predicates["a/1"]!!.clauses[1]) } } @Nested class AssertZTests : AssertTestsBase() { override fun createAssert(clause: Clause): Structure { return AssertZ(clause) } @Test fun `assertz adds to the end`() { val rule1 = Rule( Structure(Atom("a"), listOf(Atom("b"))), Atom("c") ) val rule2 = Rule( Structure(Atom("a"), listOf(Atom("d"))), Atom("e") ) AssertZ(rule1).satisfy(emptyMap()) AssertZ(rule2).satisfy(emptyMap()) assertEquals(1, Program.internalDb.predicates.size, "Expected 1 predicate") assertEquals(rule1, Program.internalDb.predicates["a/1"]!!.clauses[0]) assertEquals(rule2, Program.internalDb.predicates["a/1"]!!.clauses[1]) } } @Test fun `custom example`() { var query = Structure(Atom("likes"), listOf(Atom("alice"), Atom("pizza"))) var result = Program.query(query).toList() assertEquals(0, result.size, "Expected 0 results") var assert: Structure = Assert(Fact(query)) assert.satisfy(emptyMap()) result = Program.query(query).toList() assertEquals(1, result.size, "Expected 1 result") assertTrue(result[0].getOrNull()!!.isEmpty()) assert = AssertZ(Fact(Structure(Atom("likes"), listOf(Atom("bob"), Atom("sushi"))))) assert.satisfy(emptyMap()) query = Structure(Atom("likes"), listOf(Atom("bob"), Variable("X"))) result = Program.query(query).toList() assertEquals(1, result.size, "Expected 1 result") assertTrue(result[0].isSuccess, "Expected success") assertEquals(Atom("sushi"), result[0].getOrNull()!![Variable("X")], "Expected sushi") query = Structure(Atom("likes"), listOf(Variable("X"), Variable("Y"))) result = Program.query(query).toList() assertEquals(2, result.size, "Expected 2 results") assertTrue(result[0].isSuccess, "Expected success") var result0 = result[0].getOrNull()!! assertEquals(Atom("alice"), result0[Variable("X")], "Expected alice") assertEquals(Atom("pizza"), result0[Variable("Y")], "Expected pizza") assertTrue(result[1].isSuccess, "Expected success") var result1 = result[1].getOrNull()!! assertEquals(Atom("bob"), result1[Variable("X")], "Expected bob") assertEquals(Atom("sushi"), result1[Variable("Y")], "Expected sushi") assert = AssertA(Rule( Structure(Atom("likes"), listOf(Variable("X"), Atom("italian"))), Structure(Atom("likes"), listOf(Variable("X"), Atom("pizza"))) )) assert.satisfy(emptyMap()) result = Program.query(query).toList() assertEquals(3, result.size, "Expected 3 results") assertTrue(result[0].isSuccess, "Expected success") result0 = result[0].getOrNull()!! assertEquals(Atom("alice"), result0[Variable("X")], "Expected alice") assertEquals(Atom("italian"), result0[Variable("Y")], "Expected italian") assertTrue(result[1].isSuccess, "Expected success") result1 = result[1].getOrNull()!! assertEquals(Atom("alice"), result1[Variable("X")], "Expected alice") assertEquals(Atom("pizza"), result1[Variable("Y")], "Expected pizza") assertTrue(result[2].isSuccess, "Expected success") val result2 = result[2].getOrNull()!! assertEquals(Atom("bob"), result2[Variable("X")], "Expected bob") assertEquals(Atom("sushi"), result2[Variable("Y")], "Expected sushi") } }