Hey damiazz94,
Saw your question about property-based testing in SWI-Prolog and thought I’d share some tricks on how you might simulate QuickCheck-style testing with plunit
. It’s not out-of-the-box, but with a little creativity, you can get pretty close.
Testing List Reversal
Let’s say you want to check that reversing a list twice gets you back to the original. Here’s a snippet showing how you could do this with plunit
:
:- begin_tests(list_reversal).
my_reverse([], []).
my_reverse([H|T], Reversed) :-
my_reverse(T, RevT),
append(RevT, [H], Reversed).
test(reverse_twice, [nondet]) :-
generate_random_list(10, List),
my_reverse(List, RevList),
my_reverse(RevList, DoubleRevList),
assertion(List == DoubleRevList).
:- end_tests(list_reversal).
generate_random_list(0, []).
generate_random_list(N, [H|T]) :-
N > 0, M is N - 1, H is random(100), % pick your range
generate_random_list(M, T).
Determinism Check
Or say you want to make sure a predicate, like is_prime/1
, behaves deterministically across a range. You might write a test like this:
:- begin_tests(prime_check).
is_prime(2).
is_prime(3).
is_prime(X) :- X > 3, X mod 2 =\= 0, \+ has_factor(X,3).
has_factor(N,L) :- N mod L =:= 0.
has_factor(N,L) :- L * L < N, L2 is L + 2, has_factor(N,L2).
test(prime_determinism, [forall(between(2, 100, X)), nondet]) :-
findall(1, is_prime(X), Results),
length(Results, Length),
assertion(Length == 1).
:- end_tests(prime_check).
What’s cool here is using plunit
to roll your own property-based tests. You generate inputs (like random lists or a range of numbers) and then check properties (like “reversing twice gets me back where I started” or “my predicate only succeeds once for any given input”).
It’s a bit more manual than having QuickCheck do the heavy lifting, but it’s a neat way to get broader coverage than just example-based tests. Plus, it’s pretty fun to see what kind of weird edge cases you can catch this way.
Hope this helps spark some ideas for your testing
Cheers