Checkpoint
This commit is contained in:
parent
43b364044e
commit
9db1c66781
34 changed files with 746 additions and 194 deletions
53
tests/compare.sh
Normal file
53
tests/compare.sh
Normal file
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# This script is expected to be run from the root of the project.
|
||||
|
||||
# Paths to the two implementations
|
||||
GPL="src/gpl"
|
||||
SPL="swipl"
|
||||
|
||||
GPL_FLAGS=("--debug")
|
||||
SPL_FLAGS=("--quiet" "-t" "'true'")
|
||||
|
||||
# Directory containing test files
|
||||
TEST_DIR="examples"
|
||||
|
||||
# Temporary files for storing outputs
|
||||
GPL_OUT=$(mktemp)
|
||||
SPL_OUT=$(mktemp)
|
||||
|
||||
# Flag to track if all tests pass
|
||||
PASSED=0
|
||||
FAILED=0
|
||||
|
||||
# Iterate over all test files in the test directory
|
||||
#for TESTFILE in $(find ${TEST_DIR} -type f); do
|
||||
files=("examples/program.pl" "examples/basics/disjunction.pl" "examples/basics/fraternity.pl")
|
||||
for TESTFILE in "${files[@]}"; do
|
||||
# Run both programs with the test file
|
||||
"${SPL}" "${SPL_FLAGS[@]}" "$TESTFILE" > "${SPL_OUT}" 2>&1
|
||||
"${GPL}" "${GPL_FLAGS[@]}" -s "$TESTFILE" > "${GPL_OUT}" 2>&1
|
||||
|
||||
# Compare the outputs
|
||||
if diff -q "$SPL_OUT" "$GPL_OUT" > /dev/null; then
|
||||
PASSED=$((PASSED + 1))
|
||||
else
|
||||
echo "Test failed! Outputs differ for $TESTFILE"
|
||||
printf "\nTest:\n%s\n" "$(cat "$TESTFILE")"
|
||||
printf "\nExpected:\n%s\n" "$(cat "$SPL_OUT")"
|
||||
printf "\nGot:\n%s\n" "$(cat "$GPL_OUT")"
|
||||
echo "-----------------------------------------"
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
# Clean up temporary files
|
||||
rm "$SPL_OUT" "$GPL_OUT"
|
||||
|
||||
# Final result, summary
|
||||
if [ $FAILED -eq 0 ]; then
|
||||
echo "All tests passed!"
|
||||
else
|
||||
printf "Tests passed: %d\nTests failed: %d\n" "$PASSED" "$FAILED"
|
||||
exit 1
|
||||
fi
|
4
tests/e2e/myClass.kt
Normal file
4
tests/e2e/myClass.kt
Normal file
|
@ -0,0 +1,4 @@
|
|||
package e2e
|
||||
|
||||
class myClass {
|
||||
}
|
|
@ -12,8 +12,8 @@ import prolog.builtins.*
|
|||
|
||||
class PreprocessorTests {
|
||||
class OpenPreprocessor : Preprocessor() {
|
||||
public override fun preprocess(input: Term): Term {
|
||||
return super.preprocess(input)
|
||||
public override fun preprocess(term: Term, nested: Boolean): Term {
|
||||
return super.preprocess(term, nested)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,6 @@ class SourceFileReaderTests {
|
|||
val reader = FileLoader()
|
||||
|
||||
reader.readFile(inputFile)
|
||||
|
||||
println(Program.predicates)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -26,7 +24,5 @@ class SourceFileReaderTests {
|
|||
val reader = FileLoader()
|
||||
|
||||
reader.readFile(inputFile)
|
||||
|
||||
println(Program.predicates)
|
||||
}
|
||||
}
|
|
@ -26,4 +26,17 @@ class OperatorParserTests {
|
|||
|
||||
assertEquals(Structure(Atom(","), listOf(Atom("a"), Atom("b"))), result, "Expected atom 'a, b'")
|
||||
}
|
||||
|
||||
class BodyParser : TermsGrammar() {
|
||||
override val rootParser: Parser<Any> by body
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse equality`() {
|
||||
val input = "a = b"
|
||||
|
||||
val result = BodyParser().parseToEnd(input)
|
||||
|
||||
assertEquals(Structure(Atom("="), listOf(Atom("a"), Atom("b"))), result, "Expected atom 'a = b'")
|
||||
}
|
||||
}
|
|
@ -129,4 +129,16 @@ class LogicGrammarTests {
|
|||
val conjunction = rule.body as CompoundTerm
|
||||
assertEquals("invited/2", (conjunction.arguments[0] as CompoundTerm).functor, "Expected functor 'invited/2'")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse constraints`() {
|
||||
val input = ":- a."
|
||||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 rule")
|
||||
assertTrue(result[0] is Rule, "Expected a rule")
|
||||
val rule = result[0] as Rule
|
||||
assertEquals("/_", rule.head.functor, "Expected a constraint")
|
||||
}
|
||||
}
|
|
@ -2,9 +2,12 @@ package parser.grammars
|
|||
|
||||
import com.github.h0tk3y.betterParse.grammar.Grammar
|
||||
import com.github.h0tk3y.betterParse.grammar.parseToEnd
|
||||
import com.github.h0tk3y.betterParse.parser.Parser
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertDoesNotThrow
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import prolog.ast.arithmetic.Float
|
||||
|
@ -14,6 +17,7 @@ import prolog.ast.terms.Structure
|
|||
import prolog.ast.terms.Term
|
||||
import prolog.ast.terms.Variable
|
||||
import prolog.logic.equivalent
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class TermsGrammarTests {
|
||||
private lateinit var parser: Grammar<Term>
|
||||
|
@ -167,9 +171,12 @@ class TermsGrammarTests {
|
|||
|
||||
val result = parser.parseToEnd(input)
|
||||
|
||||
Assertions.assertTrue(
|
||||
equivalent(Float(-42.0f), result, emptyMap()),
|
||||
"Expected float '-42.0'"
|
||||
)
|
||||
assertEquals(Float(-42.0f), result, "Expected float '-42.0'")
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["got_an_a(Student)", "grade(Student, Grade)"])
|
||||
fun `parse unification`(input: String) {
|
||||
assertDoesNotThrow { parser.parseToEnd(input) }
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package prolog
|
|||
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import prolog.ast.logic.Fact
|
||||
import prolog.ast.logic.Rule
|
||||
|
@ -108,9 +109,9 @@ class EvaluationTests {
|
|||
val parent = Rule(
|
||||
Structure(Atom("parent"), listOf(variable1, variable2)),
|
||||
/* :- */ Disjunction(
|
||||
Structure(Atom("father"), listOf(variable1, variable2)),
|
||||
/* ; */
|
||||
Structure(Atom("mother"), listOf(variable1, variable2))
|
||||
Structure(Atom("father"), listOf(variable1, variable2)),
|
||||
/* ; */
|
||||
Structure(Atom("mother"), listOf(variable1, variable2))
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -212,7 +213,182 @@ class EvaluationTests {
|
|||
assertEquals(expectedResults.size, actualResults.size, "Number of results should match")
|
||||
for (i in expectedResults.indices) {
|
||||
assertEquals(expectedResults[i].size, actualResults[i].getOrNull()!!.size, "Substitution size should match")
|
||||
assertTrue(expectedResults[i].all { actualResults[i].getOrNull()!![it.key]?.let { it1 -> equivalent(it.value, it1, emptyMap()) } ?: false }, "Substitution values should match")
|
||||
assertTrue(expectedResults[i].all {
|
||||
actualResults[i].getOrNull()!![it.key]?.let { it1 ->
|
||||
equivalent(
|
||||
it.value,
|
||||
it1,
|
||||
emptyMap()
|
||||
)
|
||||
} ?: false
|
||||
}, "Substitution values should match")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `likes(alice, pizza)`() {
|
||||
val fact = Fact(Structure(Atom("likes"), listOf(Atom("alice"), Atom("pizza"))))
|
||||
val goal = Structure(Atom("likes"), listOf(Atom("alice"), Atom("pizza")))
|
||||
|
||||
Program.load(listOf(fact))
|
||||
|
||||
val result = Program.query(goal).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertEquals(0, subs.size, "Expected no substitutions")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `likes(Person, pizza)`() {
|
||||
val fact = Fact(Structure(Atom("likes"), listOf(Atom("alice"), Atom("pizza"))))
|
||||
val goal = Structure(Atom("likes"), listOf(Variable("Person"), Atom("pizza")))
|
||||
|
||||
Program.load(listOf(fact))
|
||||
|
||||
val result = Program.query(goal).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertEquals(1, subs.size, "Expected 1 substitution")
|
||||
assertEquals(Atom("alice"), subs[Variable("Person")], "Expected Person to be alice")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `likes_food(alice)`() {
|
||||
val fact = Fact(Structure(Atom("likes"), listOf(Atom("alice"), Atom("pizza"))))
|
||||
val rule = Rule(
|
||||
Structure(Atom("likes_food"), listOf(Variable("Person"))),
|
||||
Structure(Atom("likes"), listOf(Variable("Person"), Atom("pizza")))
|
||||
)
|
||||
|
||||
val goal = Structure(Atom("likes_food"), listOf(Atom("alice")))
|
||||
|
||||
Program.load(listOf(fact, rule))
|
||||
|
||||
val result = Program.query(goal).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertEquals(0, subs.size, "Expected no substitutions")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `likes_food(Person)`() {
|
||||
val fact = Fact(Structure(Atom("likes"), listOf(Atom("alice"), Atom("pizza"))))
|
||||
val rule = Rule(
|
||||
Structure(Atom("likes_food"), listOf(Variable("Person"))),
|
||||
Structure(Atom("likes"), listOf(Variable("Person"), Atom("pizza")))
|
||||
)
|
||||
|
||||
val goal = Structure(Atom("likes"), listOf(Variable("X"), Atom("pizza")))
|
||||
|
||||
Program.load(listOf(fact, rule))
|
||||
|
||||
val result = Program.query(goal).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertEquals(1, subs.size, "Expected 1 substitution")
|
||||
assertEquals(Atom("alice"), subs[Variable("X")], "Expected Person to be alice")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `requires querying exact`() {
|
||||
val fact1 = Fact(Atom("a"))
|
||||
val fact2 = Fact(Atom("b"))
|
||||
val rule1 = Rule(
|
||||
Atom("c"),
|
||||
Conjunction(
|
||||
Atom("a"),
|
||||
Atom("b")
|
||||
)
|
||||
)
|
||||
|
||||
Program.load(listOf(fact1, fact2, rule1))
|
||||
|
||||
val result = Program.query(Atom("c")).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `requires querying with variable`() {
|
||||
val fact1 = Fact(Atom("a"))
|
||||
val fact2 = Fact(Atom("b"))
|
||||
val rule1 = Rule(
|
||||
Structure(Atom("has fact"), listOf(Variable("X"))),
|
||||
Variable("X")
|
||||
)
|
||||
|
||||
Program.load(listOf(fact1, fact2, rule1))
|
||||
|
||||
val result = Program.query(Structure(Atom("has fact"), listOf(Atom("a")))).toList()
|
||||
|
||||
assertEquals(1, result.size, "Expected 1 result")
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs = result[0].getOrNull()!!
|
||||
assertEquals(0, subs.size, "Expected no substitutions")
|
||||
}
|
||||
|
||||
@Nested
|
||||
class `requires querying with filled variable` {
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
val fact1 = Fact(Structure(Atom("likes"), listOf(Atom("alice"), Atom("pizza"))))
|
||||
val fact2 = Fact(Structure(Atom("likes"), listOf(Atom("alice"), Atom("pasta"))))
|
||||
val fact3 = Fact(Structure(Atom("likes"), listOf(Atom("bob"), Atom("pasta"))))
|
||||
val rule1 = Rule(
|
||||
Structure(Atom("likes_italian_food"), listOf(Variable("Person"))),
|
||||
Disjunction(
|
||||
Structure(Atom("likes"), listOf(Variable("Person"), Atom("pizza"))),
|
||||
Structure(Atom("likes"), listOf(Variable("Person"), Atom("pasta")))
|
||||
)
|
||||
)
|
||||
|
||||
Program.clear()
|
||||
Program.load(listOf(fact1, fact2, fact3, rule1))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `likes_italian_food(alice)`() {
|
||||
val result = Program.query(Structure(Atom("likes_italian_food"), listOf(Atom("alice")))).toList()
|
||||
|
||||
assertEquals(2, result.size, "Expected 2 results")
|
||||
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs1 = result[0].getOrNull()!!
|
||||
assertEquals(0, subs1.size, "Expected no substitutions")
|
||||
|
||||
assertTrue(result[1].isSuccess, "Expected success")
|
||||
val subs2 = result[1].getOrNull()!!
|
||||
assertEquals(0, subs2.size, "Expected no substitutions")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `likes_italian_food(X)`() {
|
||||
val result = Program.query(Structure(Atom("likes_italian_food"), listOf(Variable("X")))).toList()
|
||||
|
||||
assertEquals(3, result.size, "Expected 3 results")
|
||||
|
||||
assertTrue(result[0].isSuccess, "Expected success")
|
||||
val subs3 = result[0].getOrNull()!!
|
||||
assertEquals(1, subs3.size, "Expected 1 substitution, especially without 'Person'")
|
||||
assertEquals(Atom("alice"), subs3[Variable("X")], "Expected alice")
|
||||
|
||||
assertTrue(result[1].isSuccess, "Expected success")
|
||||
val subs4 = result[1].getOrNull()!!
|
||||
assertEquals(1, subs4.size, "Expected 1 substitution, especially without 'Person'")
|
||||
assertEquals(Atom("alice"), subs4[Variable("X")], "Expected alice")
|
||||
|
||||
assertTrue(result[2].isSuccess, "Expected success")
|
||||
val subs5 = result[2].getOrNull()!!
|
||||
assertEquals(1, subs5.size, "Expected 1 substitution, especially without 'Person'")
|
||||
assertEquals(Atom("bob"), subs5[Variable("X")], "Expected bob")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
109
tests/prolog/logic/TermsTests.kt
Normal file
109
tests/prolog/logic/TermsTests.kt
Normal file
|
@ -0,0 +1,109 @@
|
|||
package prolog.logic
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import prolog.ast.terms.Atom
|
||||
import prolog.ast.terms.Structure
|
||||
import prolog.ast.terms.Variable
|
||||
|
||||
class TermsTests {
|
||||
@Test
|
||||
fun `rename vars in atom`() {
|
||||
val term = Atom("a")
|
||||
val start = 0
|
||||
|
||||
val (end, subs) = numbervars(term, start)
|
||||
|
||||
assertEquals(start, end, "Expected end to still be at start")
|
||||
assertTrue(subs.isEmpty(), "Expected no substitutions")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rename vars in var`() {
|
||||
val term = Variable("X")
|
||||
val start = 0
|
||||
|
||||
val (end, subs) = numbervars(term, start)
|
||||
|
||||
assertEquals(start + 1, end, "Expected end to be incremented by 1")
|
||||
assertEquals(1, subs.size, "Expected one substitution")
|
||||
assertTrue(subs.containsKey(term), "Expected subs to contain the original term")
|
||||
assertEquals(Variable("X($start)"), subs[term], "Expected subs to contain the new term")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rename vars in compound term without vars`() {
|
||||
val term = Structure(Atom("f"), listOf(Atom("a"), Atom("b")))
|
||||
val start = 0
|
||||
|
||||
val (end, subs) = numbervars(term, start)
|
||||
|
||||
assertEquals(start, end, "Expected end to still be at start")
|
||||
assertTrue(subs.isEmpty(), "Expected no substitutions")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `rename vars in compound term`() {
|
||||
val term = Structure(Atom("f"), listOf(Variable("X"), Variable("Y")))
|
||||
val start = 0
|
||||
|
||||
val (end, subs) = numbervars(term, start)
|
||||
|
||||
assertEquals(start + 2, end, "Expected end to be incremented by 2")
|
||||
assertEquals(2, subs.size, "Expected two substitutions")
|
||||
assertTrue(subs.containsKey(term.arguments[0]), "Expected subs to contain the first original term")
|
||||
assertEquals(Variable("X($start)"), subs[term.arguments[0]], "Expected subs to contain the new term")
|
||||
assertTrue(subs.containsKey(term.arguments[1]), "Expected subs to contain the second original term")
|
||||
assertEquals(Variable("Y(${start + 1})"), subs[term.arguments[1]], "Expected subs to contain the new term")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `renaming identical vars should keep the same name`() {
|
||||
val term = Structure(Atom("f"), listOf(Variable("X"), Variable("X")))
|
||||
val start = 0
|
||||
|
||||
val (end, subs) = numbervars(term, start)
|
||||
|
||||
assertEquals(start + 1, end, "Expected end to be incremented by 1")
|
||||
assertEquals(1, subs.size, "Expected one substitution")
|
||||
assertTrue(subs.containsKey(term.arguments[0]), "Expected subs to contain the first original term")
|
||||
assertEquals(Variable("X($start)"), subs[term.arguments[0]], "Expected subs to contain the new term")
|
||||
assertTrue(subs.containsKey(term.arguments[1]), "Expected subs to contain the second original term")
|
||||
assertEquals(Variable("X($start)"), subs[term.arguments[1]], "Expected subs to contain the new term")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `renaming identical vars should keep the same name in nested terms`() {
|
||||
val term = Structure(Atom("f"), listOf(Variable("X"), Structure(Atom("g"), listOf(Variable("X")))))
|
||||
val start = 0
|
||||
|
||||
val (end, subs) = numbervars(term, start)
|
||||
|
||||
assertEquals(start + 1, end, "Expected end to be incremented by 1")
|
||||
assertEquals(1, subs.size, "Expected one substitution")
|
||||
assertTrue(subs.containsKey(Variable("X")), "Expected subs to contain the variable")
|
||||
assertEquals(Variable("X($start)"), subs[term.arguments[0]], "Expected subs to contain the new term")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `renaming multiple times`() {
|
||||
val variable = Variable("X")
|
||||
val term = Structure(Atom("f"), listOf(variable))
|
||||
val start = 0
|
||||
|
||||
val (end1, subs1) = numbervars(term, start, emptyMap())
|
||||
|
||||
assertEquals(start + 1, end1, "Expected end to be incremented by 1")
|
||||
assertEquals(1, subs1.size, "Expected one substitution")
|
||||
assertTrue(subs1.containsKey(variable), "Expected subs to contain the variable")
|
||||
assertEquals(Variable("X($start)"), subs1[variable], "Expected subs to contain the new term")
|
||||
|
||||
val (end2, subs2) = numbervars(term, end1, subs1)
|
||||
|
||||
assertEquals(start + 2, end2, "Expected end to be incremented by 2")
|
||||
assertEquals(1, subs2.size, "Expected one substitution")
|
||||
assertTrue(subs2.containsKey(variable), "Expected subs to contain the variable")
|
||||
assertEquals(Variable("X($end1)"), subs2[variable], "Expected subs to contain the new term")
|
||||
}
|
||||
}
|
Reference in a new issue