Checkpoint

This commit is contained in:
Tibo De Peuter 2025-05-01 21:16:48 +02:00
parent 9db1c66781
commit 724e911a6f
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
17 changed files with 288 additions and 95 deletions

View file

@ -2,11 +2,13 @@
# This script is expected to be run from the root of the project.
WATCH_ALONG=0
# Paths to the two implementations
GPL="src/gpl"
SPL="swipl"
GPL_FLAGS=("--debug")
GPL_FLAGS=("--error")
SPL_FLAGS=("--quiet" "-t" "'true'")
# Directory containing test files
@ -14,7 +16,11 @@ TEST_DIR="examples"
# Temporary files for storing outputs
GPL_OUT=$(mktemp)
GPL_ERR=$(mktemp)
SPL_OUT=$(mktemp)
SPL_ERR=$(mktemp)
touch "$GPL_OUT" "$GPL_ERR" "$SPL_OUT" "$SPL_ERR"
# Flag to track if all tests pass
PASSED=0
@ -22,27 +28,43 @@ 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")
files=(
"examples/program.pl"
"examples/basics/disjunction.pl"
"examples/basics/fraternity.pl"
"examples/basics/unification.pl"
"examples/basics/write.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
"${SPL}" "${SPL_FLAGS[@]}" "$TESTFILE" > "${SPL_OUT}" 2> "${SPL_ERR}"
"${GPL}" "${GPL_FLAGS[@]}" -s "$TESTFILE" > "${GPL_OUT}" 2> "${GPL_ERR}"
# 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")"
was_different="$(
diff -q "$SPL_OUT" "$GPL_OUT" > /dev/null
echo $?
)"
if [[ "${was_different}" -ne 0 || "${WATCH_ALONG}" -eq 1 ]]; then
if [ "${was_different}" -ne 0 ]; then
message="TEST FAILED"
fi
printf "%s for %s\n" "${message:="Result"}" "${TESTFILE}"
printf "\nTest:\n%s\n" "$(cat "${TESTFILE}")"
printf "\nExpected:\n%s\n" "$(cat "${SPL_OUT}" && cat "${SPL_ERR}")"
printf "\nGot:\n%s\n" "$(cat "${GPL_OUT}" && cat "${GPL_ERR}")"
echo "-----------------------------------------"
fi
if [ "${was_different}" -ne 0 ]; then
FAILED=$((FAILED + 1))
else
PASSED=$((PASSED + 1))
fi
done
# Clean up temporary files
rm "$SPL_OUT" "$GPL_OUT"
rm "$SPL_OUT" "$GPL_OUT" "$SPL_ERR" "$GPL_ERR"
# Final result, summary
if [ $FAILED -eq 0 ]; then

46
tests/e2e/Examples.kt Normal file
View file

@ -0,0 +1,46 @@
package e2e
import interpreter.FileLoader
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import prolog.Program
import java.io.ByteArrayOutputStream
import java.io.PrintStream
class Examples {
private val loader = FileLoader()
@BeforeEach
fun setup() {
Program.reset()
}
@Test
fun fraternity() {
val inputFile = "examples/basics/fraternity.pl"
loader.load(inputFile)
}
@Test
fun unification() {
val inputFile = "examples/basics/unification.pl"
loader.load(inputFile)
}
@Test
fun write() {
val expected = "gpl zegt: dag(wereld)\n"
val outStream = ByteArrayOutputStream()
System.setOut(PrintStream(outStream))
val inputFile = "examples/basics/write.pl"
// Compare the stdio output with the expected output
loader.load(inputFile)
assertEquals(expected, outStream.toString())
}
}

View file

@ -1,4 +0,0 @@
package e2e
class myClass {
}

View file

@ -1,5 +1,6 @@
package parser
import com.github.h0tk3y.betterParse.combinators.use
import com.github.h0tk3y.betterParse.grammar.Grammar
import com.github.h0tk3y.betterParse.grammar.parseToEnd
import com.github.h0tk3y.betterParse.parser.Parser
@ -13,7 +14,7 @@ import prolog.ast.terms.Structure
class OperatorParserTests {
class OperatorParser: TermsGrammar() {
override val rootParser: Parser<CompoundTerm> by operator
override val rootParser: Parser<CompoundTerm> by body use { this as CompoundTerm }
}
private var parser = OperatorParser() as Grammar<CompoundTerm>

View file

@ -40,7 +40,7 @@ class LogicGrammarTests {
assertEquals(1, result.size, "Expected 1 fact")
assertTrue(result[0] is Fact, "Expected a fact")
assertEquals(input, "${result[0].toString()}.", "Expected fact to be '$input'")
assertEquals(input, "${result[0]}.", "Expected fact to be '$input'")
}
@ParameterizedTest
@ -125,9 +125,12 @@ class LogicGrammarTests {
assertEquals(1, result.size, "Expected 1 rule")
val rule = result[0] as Rule
assertInstanceOf(CompoundTerm::class.java, rule.body, "Expected body to be a conjunction")
val conjunction = rule.body as CompoundTerm
assertEquals("invited/2", (conjunction.arguments[0] as CompoundTerm).functor, "Expected functor 'invited/2'")
assertEquals("guest/2", rule.head.functor, "Expected functor 'guest/2'")
assertEquals(",/2", (rule.body as CompoundTerm).functor, "Expected functor ',/2'")
val l1 = (rule.body as CompoundTerm).arguments[0] as CompoundTerm
assertEquals(",/2", l1.functor, "Expected functor ',/2'")
val l2 = l1.arguments[0] as CompoundTerm
assertEquals("invited/2", l2.functor, "Expected functor 'invited/2'")
}
@Test

View file

@ -2,10 +2,11 @@ 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.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.params.ParameterizedTest
@ -17,7 +18,6 @@ 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>
@ -32,7 +32,7 @@ class TermsGrammarTests {
fun `parse atom`(name: String) {
val result = parser.parseToEnd(name)
Assertions.assertEquals(Atom(name), result, "Expected atom '$name'")
assertEquals(Atom(name), result, "Expected atom '$name'")
}
@ParameterizedTest
@ -52,7 +52,7 @@ class TermsGrammarTests {
val expected = input.substring(1, input.length - 1)
Assertions.assertEquals(Atom(expected), result, "Expected atom")
assertEquals(Atom(expected), result, "Expected atom")
}
@ParameterizedTest
@ -60,7 +60,7 @@ class TermsGrammarTests {
fun `parse variable`(name: String) {
val result = parser.parseToEnd(name)
Assertions.assertEquals(Variable(name), result, "Expected atom '$name'")
assertEquals(Variable(name), result, "Expected atom '$name'")
}
@Test
@ -69,10 +69,7 @@ class TermsGrammarTests {
val result = parser.parseToEnd(input)
Assertions.assertTrue(
equivalent(Structure(Atom("f"), emptyList()), result, emptyMap()),
"Expected atom 'f'"
)
assertEquals(Structure(Atom("f"), emptyList()), result, "Expected atom 'f'")
}
@Test
@ -81,10 +78,7 @@ class TermsGrammarTests {
val result = parser.parseToEnd(input)
Assertions.assertTrue(
equivalent(Structure(Atom("f"), listOf(Atom("a"))), result, emptyMap()),
"Expected atom 'f(a)'"
)
assertEquals(Structure(Atom("f"), listOf(Atom("a"))), result, "Expected atom 'f(a)'")
}
@Test
@ -93,8 +87,9 @@ class TermsGrammarTests {
val result = parser.parseToEnd(input)
Assertions.assertTrue(
equivalent(Structure(Atom("f"), listOf(Atom("a"), Atom("b"))), result, emptyMap()),
assertEquals(
Structure(Atom("f"), listOf(Atom("a"), Atom("b"))),
result,
"Expected atom 'f(a, b)'"
)
}
@ -105,7 +100,7 @@ class TermsGrammarTests {
val result = parser.parseToEnd(input)
Assertions.assertTrue(
assertTrue(
equivalent(Structure(Atom("f"), listOf(Atom("a"), Variable("X"))), result, emptyMap()),
"Expected atom 'f(a, X)'"
)
@ -179,4 +174,59 @@ class TermsGrammarTests {
fun `parse unification`(input: String) {
assertDoesNotThrow { parser.parseToEnd(input) }
}
@Nested
class `Operator precedence` {
private lateinit var parser: Grammar<Term>
@BeforeEach
fun setup() {
parser = TermsGrammar() as Grammar<Term>
}
@Test
fun `parse addition and multiplication`() {
val input = "1 + 2 * 3"
val result = parser.parseToEnd(input)
assertEquals(
Structure(Atom("+"), listOf(Integer(1), Structure(Atom("*"), listOf(Integer(2), Integer(3))))),
result,
"Expected addition and multiplication"
)
}
@Test
fun `parse multiplication and addition`() {
val input = "1 * 2 + 3"
val result = parser.parseToEnd(input)
assertEquals(
Structure(Atom("+"), listOf(Structure(Atom("*"), listOf(Integer(1), Integer(2))), Integer(3))),
result,
"Expected multiplication and addition"
)
}
@Test
fun `complex expression`() {
val input = "1 + 2 * 3 - 4 / 5"
val result = parser.parseToEnd(input)
assertEquals(
Structure(
Atom("-"),
listOf(
Structure(Atom("+"), listOf(Integer(1), Structure(Atom("*"), listOf(Integer(2), Integer(3))))),
Structure(Atom("/"), listOf(Integer(4), Integer(5)))
)
),
result,
"Expected complex expression"
)
}
}
}

View file

@ -390,5 +390,27 @@ class EvaluationTests {
assertEquals(1, subs5.size, "Expected 1 substitution, especially without 'Person'")
assertEquals(Atom("bob"), subs5[Variable("X")], "Expected bob")
}
@Test
fun `likes_italian_food(Person)`() {
val result = Program.query(Structure(Atom("likes_italian_food"), listOf(Variable("Person")))).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")
assertEquals(Atom("alice"), subs3[Variable("Person")], "Expected alice")
assertTrue(result[1].isSuccess, "Expected success")
val subs4 = result[1].getOrNull()!!
assertEquals(1, subs4.size, "Expected 1 substitution")
assertEquals(Atom("alice"), subs4[Variable("Person")], "Expected alice")
assertTrue(result[2].isSuccess, "Expected success")
val subs5 = result[2].getOrNull()!!
assertEquals(1, subs5.size, "Expected 1 substitution")
assertEquals(Atom("bob"), subs5[Variable("Person")], "Expected bob")
}
}
}

View file

@ -1,21 +1,18 @@
package prolog.builtins
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertInstanceOf
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
import prolog.ast.arithmetic.Float
import prolog.ast.arithmetic.Integer
import prolog.ast.terms.Atom
import prolog.ast.terms.CompoundTerm
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import prolog.ast.arithmetic.Integer
import prolog.ast.terms.Variable
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.PrintStream
class IoOperatorsTests {
private var outStream = ByteArrayOutputStream()