package parser.grammars import com.github.h0tk3y.betterParse.grammar.Grammar import com.github.h0tk3y.betterParse.grammar.parseToEnd import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import prolog.ast.logic.Clause import prolog.ast.logic.Fact import prolog.ast.logic.Rule import prolog.ast.terms.CompoundTerm import prolog.ast.terms.Structure import prolog.ast.terms.Variable import prolog.builtins.Conjunction class LogicGrammarTests { private lateinit var parser: Grammar> @BeforeEach fun setup() { parser = LogicGrammar() as Grammar> } @ParameterizedTest @ValueSource(strings = [ "john.", "mary.", "jimmy.", "male(john).", "male(jimmy).", "female(mary).", "not(not(true)).", "not(a, not(b, c), d, not(not(a)))." ]) fun `parse simple fact`(input: String) { val result = parser.parseToEnd(input) Assertions.assertEquals(1, result.size, "Expected 1 fact") Assertions.assertTrue(result[0] is Fact, "Expected a fact") Assertions.assertEquals(input, "${result[0].toString()}.", "Expected fact to be '$input'") } @ParameterizedTest @ValueSource(strings = [ "john. mary.", "likes(john, mary). likes(mary, john).", "belgium. capital(belgium, brussels).", "plus(1, 2, 3). plus(3, 4, 7).", ]) fun `parse multiple facts`(input: String) { val result = parser.parseToEnd(input) Assertions.assertEquals(2, result.size, "Expected 2 facts") Assertions.assertTrue(result[0] is Fact, "Expected a fact") Assertions.assertTrue(result[1] is Fact, "Expected a fact") } @Test fun `simplest rule`() { val input = "a :- b." val result = parser.parseToEnd(input) Assertions.assertEquals(1, result.size, "Expected 1 rule") Assertions.assertTrue(result[0] is Rule, "Expected a rule") Assertions.assertEquals("a :- b", result[0].toString()) } @ParameterizedTest @ValueSource(strings = [ "parent(X, Y) :- father(X, Y).", "parent(X, Y) :- mother(X, Y)." ]) fun `parse simple rule`(input: String) { val result = parser.parseToEnd(input) Assertions.assertEquals(1, result.size, "Expected 1 rule") Assertions.assertTrue(result[0] is Rule, "Expected a rule") } @Test fun `parse rule with very verbose checks`() { val input = "parent(X, Y) :- father(X, Y)." val result = parser.parseToEnd(input) Assertions.assertEquals(1, result.size, "Expected 1 rule") Assertions.assertTrue(result[0] is Rule, "Expected a rule") val rule = result[0] as Rule Assertions.assertTrue(rule.head is Structure, "Expected head to be a structure") val head = rule.head as Structure Assertions.assertEquals("parent/2", head.functor, "Expected functor 'parent/2'") Assertions.assertEquals(Variable("X"), head.arguments[0], "Expected first argument 'X'") Assertions.assertEquals(Variable("Y"), head.arguments[1], "Expected second argument 'Y'") Assertions.assertTrue(rule.body is Structure, "Expected body to be a structure") val body = rule.body as Structure Assertions.assertEquals("father/2", body.functor, "Expected functor 'father/2'") Assertions.assertEquals(Variable("X"), body.arguments[0], "Expected first argument 'X'") Assertions.assertEquals(Variable("Y"), body.arguments[1], "Expected second argument 'Y'") } @Test fun `parse rule with conjunction`() { val input = "father(X, Y) :- parent(X, Y), male(X)." val result = parser.parseToEnd(input) Assertions.assertEquals(1, result.size, "Expected 1 rule") Assertions.assertInstanceOf(Rule::class.java, result[0], "Expected a rule") val rule = result[0] as Rule Assertions.assertInstanceOf(Conjunction::class.java, rule.body, "Expected body to be a conjunction") } @Test fun `parse rule with nested conjunction`() { val input = "guest(X, Y) :- invited(Y, X), has_time(X), not(sick(Y))." val result = parser.parseToEnd(input) Assertions.assertEquals(1, result.size, "Expected 1 rule") val rule = result[0] as Rule Assertions.assertTrue(rule.body is Conjunction, "Expected body to be a conjunction") val conjunction = rule.body as Conjunction Assertions.assertEquals("invited/2", (conjunction.left as CompoundTerm).functor, "Expected functor 'invited/2'") } }