package alice.tuprolog;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import alice.tuprolog.event.OutputEvent;
import alice.tuprolog.event.OutputListener;
/*
* This class gathers tests for tuProlog bugs that have not been tested
* in any other more fine-grained way (e.g. through a unit test) and that
* the ISO standard tests alone were not able to catch. It is a messy
* melting-pot, probably in need of a proper reorganization.
*
* Waiting for that reorganization, new tests are inserted at the beginning.
*/
public class BugsTest {
Prolog engine;
String output;
@Before
public void setUp() {
engine = new Prolog();
output = "";
}
@Test public void renamingInUnification() throws PrologException {
String goal = "functor(TERM, foo, 2), TERM =.. [H|T].";
SolveInfo solution = engine.solve(goal);
assertTrue(solution.isSuccess());
Struct t = (Struct) solution.getTerm("T");
Term first = t.getArg(0);
Term second = ((Struct) t.getArg(1)).getArg(0);
assertNotSame(first, second);
}
@Test public void numberUnification() throws PrologException {
String[] goals = new String[] {"0.0 = 0.", "0.9 = 0.", "0 = 0.9."};
for (String goal : goals) {
SolveInfo solution = engine.solve(goal);
assertFalse(solution.isSuccess());
}
}
@Test public void numberComparison() throws PrologException {
String[] goals = new String[] {"1.0 == 1.", "1 == 1.0."};
for (String goal : goals) {
SolveInfo solution = engine.solve(goal);
assertFalse(solution.isSuccess());
}
}
@Test public void expandingSubgoals() throws PrologException {
engine.setTheory(new Theory(
"a.\n" +
"p((a,fail)).\n" +
"p((a))."));
SolveInfo solution = engine.solve("p(X), X.");
assertTrue(solution.isSuccess());
assertEquals(new Struct("a"), solution.getTerm("X"));
}
@Test public void arithmeticOperations() throws PrologException {
SolveInfo solution = engine.solve("X is 1169658768269 - 531550800000.");
assertTrue(solution.isSuccess());
assertEquals(new alice.tuprolog.Long(638107968269L), solution.getTerm("X"));
solution = engine.solve("X is -2147475543 - 9000.");
assertTrue(solution.isSuccess());
assertEquals(new alice.tuprolog.Long(-2147484543L), solution.getTerm("X"));
solution = engine.solve("X is 1169658768269 + 531550800000.");
assertTrue(solution.isSuccess());
assertEquals(new alice.tuprolog.Long(1701209568269L), solution.getTerm("X"));
solution = engine.solve("X is 2147483543 + 8000.");
assertTrue(solution.isSuccess());
assertEquals(new alice.tuprolog.Long(2147491543L), solution.getTerm("X"));
solution = engine.solve("X is 1474845 * 3634.");
assertTrue(solution.isSuccess());
assertEquals(new alice.tuprolog.Long(5359586730L), solution.getTerm("X"));
solution = engine.solve("X is 4651880372 / -1.");
assertTrue(solution.isSuccess());
assertEquals(new alice.tuprolog.Long(-4651880372L), solution.getTerm("X"));
solution = engine.solve("X is 4651880372 // -1.");
assertTrue(solution.isSuccess());
assertEquals(new alice.tuprolog.Long(-4651880372L), solution.getTerm("X"));
}
@Test public void metaInterpretation() throws PrologException {
Theory t = new Theory("search(E, [E|_]).\n" +
"search(E, [_|T]) :- search(E, T).\n" +
"solve(true).\n" +
"solve((A, B)) :- !, solve(A), solve(B).\n" +
"solve(G) :- clause(G, B), solve(B).");
engine.setTheory(t);
SolveInfo solution = engine.solve("solve(search(X, [1,2,3,1])).");
assertTrue(solution.isSuccess());
assertEquals(new Int(1), solution.getTerm("X"));
solution = engine.solveNext();
assertTrue(solution.isSuccess());
assertEquals(new Int(2), solution.getTerm("X"));
solution = engine.solveNext();
assertTrue(solution.isSuccess());
assertEquals(new Int(3), solution.getTerm("X"));
solution = engine.solveNext();
assertTrue(solution.isSuccess());
assertEquals(new Int(1), solution.getTerm("X"));
solution = engine.solveNext();
assertFalse(solution.isSuccess());
}
/* =../2 (univ) bugs */
@Test public void buildListFromAtom() throws PrologException {
SolveInfo solution = engine.solve("a =.. L.");
assertTrue(solution.isSuccess());
Struct result = new Struct(new Term[] {new Struct("a")});
assertEquals(result, solution.getTerm("L"));
}
@Test public void buildListFromNumber() throws PrologException {
SolveInfo solution = engine.solve("3 =.. L.");
assertTrue(solution.isSuccess());
Struct result = new Struct(new Term[] {new Int(3)});
assertEquals(result, solution.getTerm("L"));
}
@Test public void fillOneElementListWithAtom() throws PrologException {
SolveInfo solution = engine.solve("a =.. [X].");
assertTrue(solution.isSuccess());
Struct result = new Struct("a");
assertEquals(result, solution.getTerm("X"));
}
/* Operator Management */
@Test public void verifySimpleOperatorExistence() throws PrologException {
SolveInfo solution = engine.solve("current_op(_, _, '+').");
assertTrue(solution.isSuccess());
}
@Test public void defineListOfOperators() throws PrologException {
SolveInfo solution = engine.solve("op(10, yfx, ['@', ':']), current_op(10, yfx, Op).");
assertTrue(solution.isSuccess());
assertEquals(new Struct(":"), solution.getTerm("Op"));
solution = engine.solveNext();
assertTrue(solution.isSuccess());
assertEquals(new Struct("@"), solution.getTerm("Op"));
}
/* Functor Identification */
@Test public void isTriggersConstructedFunctorEvaluation() throws PrologException {
SolveInfo solution = engine.solve("X is 5, Y =.. ['+', X, 2], K is Y.");
assertTrue(solution.isSuccess());
assertEquals(new Int(5), solution.getTerm("X"));
Struct sum = new Struct("+", new Int(5), new Int(2));
assertEquals(sum, solution.getTerm("Y"));
assertEquals(new Int(7), solution.getTerm("K"));
}
@Test public void comparisonOperatorTriggersConstructedFunctorEvaluation() throws PrologException {
SolveInfo solution = engine.solve("X is 5, Y =.. ['+', X, 2], 10 > Y.");
assertTrue(solution.isSuccess());
assertEquals(new Int(5), solution.getTerm("X"));
Struct sum = new Struct("+", new Int(5), new Int(2));
assertEquals(sum, solution.getTerm("Y"));
}
/* Asserting/Retracting Clauses */
@Test public void assertionsWithBindings() throws PrologException {
engine.setTheory(new Theory("ops(s).\nops(y).\nops(z)."));
SolveInfo assertion = engine.solve("ops(A), assert(ops_result(A)).");
assertTrue(assertion.isSuccess());
assertion = engine.solveNext();
assertTrue(assertion.isSuccess());
assertion = engine.solveNext();
assertTrue(assertion.isSuccess());
SolveInfo queryAssertionResults = engine.solve("ops_result(X).");
assertTrue(queryAssertionResults.isSuccess());
assertEquals(new Struct("s"), queryAssertionResults.getTerm("X"));
queryAssertionResults = engine.solveNext();
assertTrue(queryAssertionResults.isSuccess());
assertEquals(new Struct("y"), queryAssertionResults.getTerm("X"));
queryAssertionResults = engine.solveNext();
assertTrue(queryAssertionResults.isSuccess());
assertEquals(new Struct("z"), queryAssertionResults.getTerm("X"));
}
@Test public void retractallRemovesFactsAndRules() throws PrologException {
engine.setTheory(new Theory("p(0) :- !.\np(1)."));
SolveInfo removal = engine.solve("retractall(p(X)).");
assertTrue(removal.isSuccess());
SolveInfo query = engine.solve("p(X).");
assertFalse(query.isSuccess());
}
/* Call Conjunction */
@Test public void simpleCallConjunction() throws PrologException {
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
String goal = "write(1), X = ','(write(a), write(b)), X, write(2), write(3).";
SolveInfo solution = engine.solve(goal);
assertTrue(solution.isSuccess());
assertEquals("1ab23", output);
}
@Test public void callConjunctionOnTheory() throws PrologException {
engine.setTheory(new Theory("b :- write(b1).\nb :- write(b2).\nb :- write(b3)."));
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
String goal = "X = ','(write(b0), b), X, write(after), fail.";
SolveInfo solution = engine.solve(goal);
assertFalse(solution.isSuccess());
assertEquals("b0b1afterb2afterb3after", output);
}
/* Cuts on the correct level */
@Test public void exclusiveClauses() throws PrologException {
engine.setTheory(new Theory("ops :- fail.\nops :- !,fail.\nops :- true."));
SolveInfo solution = engine.solve("ops.");
assertFalse(solution.isSuccess());
}
@Test public void cutInIfThenElse() throws PrologException {
engine.setTheory(new Theory("p :- a, (a -> write(a) ; write(b)), fail.\na.\na."));
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("p.");
assertFalse(solution.isSuccess());
assertEquals("aa", output);
}
@Test public void cutInDoubleDisjunctionOnTheSameLevel() throws PrologException {
engine.setTheory(new Theory("a :- ';'((b, c, ';'((write(cut), !, fail), true)), fail).\n" +
"a :- write(a).\n" +
"b :- write(b1).\n" +
"b :- write(b2).\n" +
"c :- write(c1).\n" +
"c :- write(c2)."));
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("a.");
assertFalse(solution.isSuccess());
assertEquals("b1c1cut", output);
}
@Test public void cutInDoubleDisjunctionOnDifferentLevels() throws PrologException {
engine.setTheory(new Theory("x :- ';'((y, z), fail).\n" +
"x :- write(x).\n" +
"y :- write(y1).\n" +
"y :- write(y2).\n" +
"z :- ';'((write(cut), !, fail), true).\n" +
"z :- write(z)."));
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("x.");
assertTrue(solution.isSuccess());
assertEquals("y1cuty2cutx", output);
}
@Test public void cutInMetaCall() throws PrologException {
engine.setTheory(new Theory("go :- fail.\n" +
// X meta-call
"go :- write(1), X = ','(write(cut), !), X, write(2), fail.\n" +
"go :- write(3)."));
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo metaCallX = engine.solve("go.");
assertTrue(metaCallX.isSuccess());
assertEquals("1cut23", output);
engine.setTheory(new Theory("go :- fail.\n" +
// call(X) meta-call
"go :- write(1), X = ','(write(cut), !), call(X), write(2), fail.\n" +
"go :- write(3)."));
output = "";
SolveInfo metaCallCallX = engine.solve("go.");
assertTrue(metaCallCallX.isSuccess());
assertEquals("1cut23", output);
}
/*
* The following are additional tests on the interaction between cut
* and ->/2 or ;/2, written in the process of fixing SourceForge bug
* #1675798. Not sure about their usefulness, though.
*/
@Test public void additionalCutTest0() throws PrologException {
Theory t = new Theory("a(a).\n" +
"a(b).\n" +
"a(c).\n" +
"go :- print(ingo), nl, a(X),\n" +
" (print(X), nl -> fail ; print(ingoalt), nl), fail ;\n" +
" print(altouter), nl, fail.\n" +
"go :- print(ingo2),nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("go.");
assertTrue(solution.isSuccess());
String result = "ingo\n" +
"a\n" +
"b\n" +
"c\n" +
"altouter\n" +
"ingo2\n";
assertEquals(result, output);
}
@Test public void additionalCutTest1() throws PrologException {
Theory t = new Theory("a(a).\n" +
"a(b).\n" +
"a(c).\n" +
"goa :- print(ingoX), nl, a(X), print(X), print('X'), nl, !, fail ;\n" +
" print(ingoaltX), nl, fail.\n" +
"goa :- print(ingo2X), nl.\n" +
"goa :- print(ingo3X), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("goa.");
assertFalse(solution.isSuccess());
String result = "ingoX\naX\n";
assertEquals(result, output);
}
@Test public void additionalCutTest2() throws PrologException {
Theory t = new Theory("gob :- print(ingoX), nl, (print(Y), print('X'), nl, !, fail ;\n" +
" print(ingoaltX), nl), fail.\n" +
"gob :- print(ingo2X), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("gob.");
assertFalse(solution.isSuccess());
String result = "ingoX\nY_e1X\n";
assertEquals(result, output);
}
@Test public void additionalCutTest3() throws PrologException {
Theory t = new Theory("a(a).\n" +
"a(b).\n" +
"a(c).\n" +
"b(bbb).\n" +
"goc :- print(aaa), nl, a(X),\n" +
" (print(hasAA_), print(X), nl -> b(B),\n" +
" print(hasBB_), print(B), nl, fail ; print(altern))\n" +
" ; print(alternate), nl, fail.\n" +
"goc :- print(a222), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("goc.");
assertTrue(solution.isSuccess());
String result = "aaa\n" +
"hasAA_a\n" +
"hasBB_bbb\n" +
"hasAA_b\n" +
"hasBB_bbb\n" +
"hasAA_c\n" +
"hasBB_bbb\n" +
"alternate\n" +
"a222\n";
assertEquals(result, output);
}
@Test public void additionalCutTest4() throws PrologException {
Theory t = new Theory("a(a).\n" +
"a(b).\n" +
"a(c).\n" +
"goe :- print(ingoX), nl, a(X), (print(X), print('X'), nl -> fail ;\n" +
" print(ingoaltX), nl), fail.\n" +
"goe :- print(ingo2X), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("goe.");
assertTrue(solution.isSuccess());
String result = "ingoX\naX\nbX\ncX\ningo2X\n";
assertEquals(result, output);
}
@Test public void additionalCutTest5() throws PrologException {
Theory t = new Theory("a(a).\n" +
"a(b).\n" +
"a(c).\n" +
"b(bbb).\n" +
"gof :- print(aaa), nl, a(X),\n" +
" (print(hasAA_), print(X), nl, !,\n" +
" b(B), print(hasBB_), print(B), nl, fail ; print(altern)) ;\n" +
" print(alternate), nl, fail.\n" +
"gof :- print(a222), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("gof.");
assertFalse(solution.isSuccess());
String result = "aaa\nhasAA_a\nhasBB_bbb\n";
assertEquals(result, output);
}
@Test public void additionalCutTest6() throws PrologException {
Theory t = new Theory("a(a).\n" +
"a(b).\n" +
"a(c).\n" +
"b(bbb).\n" +
"gog :- print(aaa), nl, a(X),\n" +
" (print(hasAA_), print(X), nl, b(B),\n" +
" print(hasBB_), print(B), nl, fail ;\n" +
" print(altern), nl, fail) ;\n" +
" print(alternate), nl, fail.\n" +
"gog :- print(a222), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("gog.");
assertTrue(solution.isSuccess());
String result = "aaa\n" +
"hasAA_a\n" +
"hasBB_bbb\n" +
"altern\n" +
"hasAA_b\n" +
"hasBB_bbb\n" +
"altern\n" +
"hasAA_c\n" +
"hasBB_bbb\n" +
"altern\n" +
"alternate\n" +
"a222\n";
assertEquals(result, output);
}
@Test public void additionalCutTest7() throws PrologException {
Theory t = new Theory("a(a).\n" +
"a(b).\n" +
"a(c).\n" +
"goh :- print(ingoX), nl,\n" +
" (a(X), print(X), print('X'), nl -> print(good)\n" +
" ; a(X), print(why_), print(X), nl, fail), fail.\n" +
"goh :- print(ingo2X), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("goh.");
assertTrue(solution.isSuccess());
String result = "ingoX\naX\ngoodingo2X\n";
assertEquals(result, output);
}
@Test public void additionalCutTest8() throws PrologException {
Theory t = new Theory("a(a).\n" +
"a(b).\n" +
"a(c).\n" +
"goi :- print(ingoi), nl, a(X), print(X), nl ->\n" +
" (print(gotit), nl ; print(again), nl, fail).\n" +
"goi :- print(ingoi222), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("goi.");
assertTrue(solution.isSuccess());
String result = "ingoi\na\ngotit\n";
assertEquals(result, output);
output = "";
solution = engine.solveNext();
assertTrue(solution.isSuccess());
result = "again\ningoi222\n";
assertEquals(result, output);
}
@Test public void additionalCutTest9() throws PrologException {
Theory t = new Theory("a(a).\n" +
"a(b).\n" +
"a(c).\n" +
"goj :- print(ingoj), nl, !, (a(X), print(X), nl ->\n" +
" (print(gotit), nl ; print(again), nl), fail).\n" +
"goj :- print(ingoj222), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("goj.");
assertFalse(solution.isSuccess());
String result = "ingoj\na\ngotit\nagain\n";
assertEquals(result, output);
}
@Test public void additionalCutTest10() throws PrologException {
Theory t = new Theory("a(a).\n" +
"a(b).\n" +
"a(c).\n" +
"gok :- print(ingok), nl, !," +
" (a(X), print(X), nl, (print(gotit), nl ; print(again), nl), fail).\n" +
"gok :- print(ingok222), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("gok.");
assertFalse(solution.isSuccess());
String result = "ingok\n" +
"a\n" +
"gotit\n" +
"again\n" +
"b\n" +
"gotit\n" +
"again\n" +
"c\n" +
"gotit\n" +
"again\n";
assertEquals(result, output);
}
@Test public void additionalCutTest11() throws PrologException {
Theory t = new Theory("gol :- goll.\n" +
"gol :- print(golc2), nl.\n" +
"goll :- print(first), nl, gocp, fail ; print(ingol), nl, gocp, fail ;\n" +
" (print(lc), nl -> fail ; print(howdidwegethere1)), nl ;\n" +
" print(howhow), nl, fail.\n" +
"goll :- print(howdidwegethere2), nl.\n" +
"gocp :- print(gocpa), nl ; print(gocpb), nl.");
engine.setTheory(t);
engine.addOutputListener(new OutputListener() {
@Override
public void onOutput(OutputEvent e) {
output += e.getMsg();
}
});
SolveInfo solution = engine.solve("gol.");
assertTrue(solution.isSuccess());
String result = "first\n" +
"gocpa\n" +
"gocpb\n" +
"ingol\n" +
"gocpa\n" +
"gocpb\n" +
"lc\n" +
"howhow\n" +
"howdidwegethere2\n";
assertEquals(result, output);
output = "";
solution = engine.solveNext();
assertTrue(solution.isSuccess());
result = "golc2\n";
assertEquals(result, output);
}
}