1

I'm writing tests using SWI-Prolog's PlUnit and would like to provide a better error message, perhaps by diffing what I've got from what I was expecting.

The following minimal working example (MWE) exemplifies what I'm after:

:- module(mwe, [parse_int/2]).

parse_int(Str, Num) :- number_string(Num, Str):

:- begin_tests(mwe).
:- use_module(mwe).

testcase("1", 1).
testcase("10", 10).
testcase("100000000000", 10000000000). % Oops
test("parse int", [forall(testcase(Text, Want))]) :-
  parse_int(Text, Got),
  assertion(Got = Want).

:- end_tests(mwe).

The output is:

% PL-Unit: mwe ..
ERROR: /home/bkim/Projects/swifun/mwe.pl:11:
    test parse int (forall bindings = ["100000000000",10000000000]): assertion failed
    Assertion: 100000000000=10000000000
false.

A differ, similar to go-cmp, could present this result like:

- 100000000000
+ 10000000000

Which is easier to compare at a glance.

I couldn't find anything that performs this type of check for general Prolog terms, the closer being an example of edit distance between lists.

false
  • 10,264
  • 13
  • 101
  • 209
Bruno Kim
  • 2,300
  • 4
  • 17
  • 27
  • `assertion(Got = Want).` is using unification. You want comparison with `==`. After seeing that I didn't look for more problems. – Guy Coder Dec 22 '21 at 07:32
  • I would write a full answer but in checking to see if you either accept previous answers to your [questions](https://stackoverflow.com/users/946814/bruno-kim?tab=questions) or give feedback as to why you are not accepting answers I see that you are not always doing this. – Guy Coder Dec 22 '21 at 07:42
  • 1
    Guy Coder, the question is about using a better lib for comparing terms instead of = or ==. I do want unification because I can use anonymous vars in `Want` to ignore pieces of `Got` thatdon't interest me. Thanks for the heads-up regarding accepting answers, I went back and accepted some that I had ignored. – Bruno Kim Dec 22 '21 at 11:09
  • 1
    Most of what you seek should be derivable from this, [Adding some color to your text messages](https://swi-prolog.discourse.group/t/adding-some-color-to-your-text-messages/2002). If so then post your own answer and get some points. If not then I can post a full answer. Let me know if you need more. – Guy Coder Dec 22 '21 at 13:44

1 Answers1

1

You should move the comparison into the test rule's head:

test("parse int", [forall(testcase(Text, Want)), Got = Want]) :-
    parse_int(Text, Got).

This way it's more explicit what you want the test to express. And it allows PlUnit to give more informative output:

ERROR: /home/isabelle/foo.pl:11:
    test parse int (forall bindings = ["100000000000",10000000000]): wrong answer (compared using =)
ERROR:     Expected: 10000000000
ERROR:     Got:      100000000000
Isabelle Newbie
  • 9,258
  • 1
  • 20
  • 32
  • That's a better error message! I changed the question's title to focus more on messaging and less on diffing. If you're reading this in the future, I'd still like to know about a diffing library, tho :) – Bruno Kim Dec 23 '21 at 12:17
  • Maybe a few more examples would help. For this particular example you might as well just define `eq(X, Y) :- ( X = Y -> true ; format('expected: ~w~ngot: ~w~n', [X, Y]) ).` I imagine that you want something more sophisticated, – Isabelle Newbie Dec 23 '21 at 18:59
  • Yes, in Go I rely heavily on go-cmp to compare complex data structures. My project in Prolog is a programming language parser, so I'd like to diff parse trees and spot just what changes if a test fails – Bruno Kim Dec 23 '21 at 19:23
  • You could start with an implementation of unification like the one at https://stackoverflow.com/a/64666286/4391743 and report a mismatch at the first place where it fails (i.e., no rule applies). Then maybe extend that to a sort of minimum edit distance computation on trees if you wish. – Isabelle Newbie Dec 23 '21 at 23:47