# Testing for nondeterminism in plunit

Suppose I have the following. `naive_member/2` is nondeterministic on the last member, and I want to make the plunit tests fail if that occurs (both on “single tests” and on “all” tests).

How to do that?

``````naive_member(X,[X|_]).
naive_member(X,[_|R]) :- naive_member(X,R).

:- begin_tests(member_determinacy).

% option "nondet" suppresses warning "Test succeeded with choicepoint"
% (it is not a test failure if the test succeeds with a choicepoint)

test(one_nondet)    :- naive_member(1,[1,2,3]).  % generates a warning
test(one,[nondet])    :- naive_member(1,[1,2,3]).
test(two,[nondet])    :- naive_member(1,[1,1,3]).
test(three,[nondet])  :- naive_member(1,[1,1,1]).
test(five,fail)       :- naive_member(3,[1,1,2]).

% I want four_a to fail - How?

test(four_a,[nondet]) :- naive_member(2,[1,1,2]).  % nondeterministic on last member
test(four_b)          :- member(2,[1,1,2]).        % deterministic on last member, needs no option

% Always work, indistinguishable from member/2, but what if I want four_all_a to fail if it leaves a
% choicepoint open?

test(one_all_a  ,all(M=[1]))     :- naive_member(M,[1,2,3]),M=1.
test(two_all_a  ,all(M=[1,1]))   :- naive_member(M,[1,1,3]),M=1.
test(three_all_a,all(M=[1,1,1])) :- naive_member(M,[1,1,1]),M=1.
test(four_all_a ,all(M=[2]))     :- naive_member(M,[1,1,2]),M=2.

% Always work

test(one_all_b  ,all(M=[1]))     :- member(M,[1,2,3]),M=1.
test(two_all_b  ,all(M=[1,1]))   :- member(M,[1,1,3]),M=1.
test(three_all_b,all(M=[1,1,1])) :- member(M,[1,1,1]),M=1.
test(four_all_b ,all(M=[2]))     :- member(M,[1,1,2]),M=2.

:- end_tests(member_determinacy).

rt :- run_tests(member_determinacy).
``````

The first set is what this is all intended to do.

I see no reason why would want to verify that a predicate succeeds and leaves a choice point (but no second answer). If you want to know whether it can produce multiple answers use the `all` recipe.

In the very unlikely case you want to test success is `nondet`, do

``````    call_cleanup(test_supposed_to_be_nondet, Det=true),
assertion(var(Det)).
``````

The `all` tests are supposed to run findall/3, so no non-determinism will be left.

2 Likes