Can't see my error on unit test, assertion dump is identical

ast:  ?- run_tests(buffer_tokenising:bulk_comments).
% PL-Unit: buffer_tokenising:bulk_comments 
ERROR: /home/sean/Documents/code/prolog/the-f-word-project/tokeniser.plt:118:
        test bulk_comments: wrong answer (compared using ==)
ERROR:     Expected: [com1((0,1,0),";line1"),o_list((7,2,0)),token((8,2,1),"HELLO"),c_list((13,2,6)),comn((14,2,7),"/* haha */"),o_map((24,2,17)),token((25,2,18),"WORLD"),c_map((30,2,23))]
ERROR:     Got:      [com1((0,1,0),";line1"),o_list((7,2,0)),token((8,2,1),"HELLO"),c_list((13,2,6)),comn((14,2,7),"/* haha */"),o_map((24,2,17)),token((25,2,18),"WORLD"),c_map((30,2,23))]
 done
% 1 test failed
% 0 tests passed

I have been scratching my head for hours now, here is the test, the tokeniser is “sound” as lots of the other tests are still passing fine but this one…

test(bulk_comments, [true(Out==Exp)]) :-
    Exp = [com1(  (0,1,0),   ";line1"),
           o_list((7,2,0)),
           token( (8,2,1),   "HELLO"),
           c_list((13,2,6)),
           comn(  (14,2,7),  "/* haha */"),
           o_map( (24,2,17)),
           token( (25,2,18), "WORLD"),
           c_map( (30,2,23))
          ],
    tokenise(`;line1\n[HELLO]/* haha */{WORLD}`, Out, []).

I have read and re-read the unit test notes but I just can’t see why it would be saying failed…
:frowning:

You are testing using == operator, which is only true if the Out and Exp point to the exact same structure in memory. You probably just want to compare using = instead.

All of my tests use ==/2 and most are fine…have I been incredibly lucky…!!! I will change it and see what happens!

The doc for ==/2 says:

True if Term1 is equivalent to Term2. A variable is only identical to a sharing variable.

That last term…is it possible that all my tests have ended up “sharing” a common internal structure if the expectation was the same as the output, would it be referencing the same internal memory with me being totally unaware???

Running the test with =/2 has made no difference to the result:

ERROR: /home/sean/Documents/code/prolog/the-f-word-project/tokeniser.plt:118:
        test bulk_comments: wrong answer (compared using =)
ERROR:     Expected: [com1((0,1,0),";line1"),o_list((7,2,0)),token((8,2,1),"HELLO"),c_list((13,2,6)),comn((14,2,7),"/* haha */"),o_map((24,2,17)),token((25,2,18),"WORLD"),c_map((30,2,23))]
ERROR:     Got:      [com1((0,1,0),";line1"),o_list((7,2,0)),token((8,2,1),"HELLO"),c_list((13,2,6)),comn((14,2,7),"/* haha */"),o_map((24,2,17)),token((25,2,18),"WORLD"),c_map((30,2,23))]

back t’drawing board…

No! Never compare with term unification unless you further test the bindings resulting from the unification. If you have a bug where a binding is missing, unification will succeed and will mask the bug.

3 Likes

That’s why I used ==/2, I read that in the docs somewhere last week

Not quite. =/2 is the same as ==/2 if there are no variables. You can see this the following, which succeeds even if the two arguments are not the same location in memory:

?- X =..[foo,bar], X == foo(bar).
X = foo(bar).

@emacstheviking - Do you perhaps have a portray that is confusing things? You might try outputting the two values using write_canonical.

3 Likes

yes, I think I have portray_test(true). in my load.pl file… I will comment it out and see what happens with a brand new session…

Maybe getting somewhere now! Now you can see a problem indeed… my expectation is using backticks but the tokensiation is producing lists of character codes…I think I git confused somewhere!

ERROR: /home/sean/Documents/code/prolog/the-f-word-project/tokeniser.plt:118:
        test bulk_comments: wrong answer (compared using =)
ERROR:     Expected: [com1((0,1,0),";line1"),o_list((7,2,0)),token((8,2,1),"HELLO"),c_list((13,2,6)),comn((14,2,7),"/* haha */"),o_map((24,2,17)),token((25,2,18),"WORLD"),c_map((30,2,23))]
ERROR:     Got:      [com1((0,1,0),[59,108,105,110,101,49]),o_list((7,2,0)),token((8,2,1),[72,69,76,76,79]),c_list((13,2,6)),comn((14,2,7),[47,42,32,104,97,104,97,32,42,47]),o_map((24,2,17)),token((25,2,18),[87,7

Not sure what happened, I feel a bit dazed and confused because not all the tests fail, in fact out of 92 I have 9 fails and mostly they are because of work in progress apart from this one…

I need to re-read about strings, character codes etc…I think that might be the reason but I still can’t understand (yet) why other tests pass!!

Gotta love computers…

OH NOOOO…I actually typed the "* in the test code, I just looked!!!

:rofl:

What the … ? that explains that one then…

ast:  ?- run_tests(buffer_tokenising:bulk_comments).
% PL-Unit: buffer_tokenising:bulk_comments . done
% test passed
true.

Thanks everybody, @peter.ludemann …the portray is staying off until further notice!
:+1:

The definition of ==/2 doesn’t care whether there’s any structure sharing or not.(*) If two things look the same using write_canonical and numbervars they are the same and there’s no way to tell them apart. Here’s an example (X==Y fails but X=Y succeeds):

?- X=f(A,B), Y=f(A,C), Both=[X,Y], numbervars(Both), write_canonical(Both).
[f('$VAR'(0),'$VAR'(1)),f('$VAR'(0),'$VAR'(2))]
1 Like

(I forgot to fill in my footnote)

(*) In the early days of Prolog implementation, there was debate about “structure sharing” and “structure copying”. Nowadays, almost all implementations use “structure copying”. However, it is completely opaque to the user which implementation is used, although speed and memory usage can be affected.

Prolog has no equivalent to Java’s “==” or Python’s “is”, both of which are essentially pointer equivalency tests. [JavaScript probably also has something similar with its “==”, “===”, “Object.is”, but JavaScript is such a hot mess of bad language and library design that I avoid it as much as possible.]

I agree about JavaScript…PHP also fits that bill!

SWI-Prolog has same_term/2, which is logically meaningless, but can help figuring out stuff related to destructive assignment such as using nb_setarg/3. Related it has both copy_term/2 and duplicate_term/2. Copy_term/2 merely guarantees that variables are fresh, i.e., it shares ground subterms while duplicate_term/2 really copies, regardless of groundness.