BDD for Prolog
Juli 21, 2009 at 7:38 nachmittags 1 Kommentar
During my experiments with Prolog I needed a test framework. I startet with the unit test framework written by Ken Egozi. Over time I tried to migrate it to a more BDD like style. I named the result “ProSpec”. Here is the code (Open-Source-License):
it(Spec_Desc/Spec):-
current_fixture(Fixture),
retractall(spec_def(Fixture/Spec_Desc/Spec)),
assert(spec_def(Fixture/Spec_Desc/Spec)).
describe(Fixture) :-
retractall(spec_def(Fixture/_/_)),
assert(current_fixture(Fixture)).
end_describe:-
retractall(current_fixture(_)).
run_one_spec(Pred/Name) :-
spec_def(Pred/Name/Spec),
setup_spec,
call(Spec).
run_specs :-
dynamic(setup_spec/0),
dynamic(specs_stats/2),
write('Run Specs '), nl,
bagof(Fixture/Specs, bagof((Spec_Desc/Spec), spec_def(Fixture/Spec_Desc/Spec), Specs), SpecsPerPredicate),
run_specs(SpecsPerPredicate, Passed/Failed),
write_specs_summary(Passed/Failed).
run_specs(SpecsSpecsPerPredicate, TotalPassed/TotalFailed) :-
run_specs(SpecsSpecsPerPredicate, 0/0, TotalPassed/TotalFailed).
run_specs([], Passed/Failed, Passed/Failed):-!.
run_specs([Fixture/Specs|Rest], Passed/Failed, TotalPassed/TotalFailed):-
nl, write(Fixture), write('...'), nl,
foreach_spec(Specs, PassedInPredicate/FailedInPredicate),
write('Passed:'), write(PassedInPredicate),
(FailedInPredicate > 0, write(' Failed:'), write(FailedInPredicate) ; true),
nl,
Passed1 is Passed + PassedInPredicate,
Failed1 is Failed + FailedInPredicate,
run_specs(Rest, Passed1/Failed1, TotalPassed/TotalFailed).
foreach_spec(Specs, Passed/Failed):-
foreach_spec(Specs, 0/0, Passed/Failed).
foreach_spec([], Passed/Failed, Passed/Failed):-!.
foreach_spec([Spec_Desc/Spec|Rest], Passed/Failed, NewPassed/NewFailed):-
(
setup_spec, call(Spec), !,
NextPassed is Passed + 1,
NextFailed is Failed,
write('...'), write(Spec_Desc), write(' (passed)'), nl
;
NextFailed is Failed + 1,
NextPassed is Passed,
write('...'), write(Spec_Desc), write(' (FAILED)'), nl
),
foreach_spec(Rest, NextPassed/NextFailed, NewPassed/NewFailed).
write_specs_summary(Passed/0) :- !,
nl,
write(Passed), write(' specs passed'),
nl.
write_specs_summary(Passed/Failed) :-
nl,
write(Passed), write(' specs passed,'), nl,
write(Failed), write(' specs failed'),
nl.
reset_all_specs:-
retractall(spec_def(_/_/_)).
run_spec(Spec) :-
call(Spec),!,
specs_passed(X),
retract(specs_passed(X)),
NewX is X + 1,
assert(specs_passed(NewX)).
run_spec(Spec) :-
failing_specs(X),
retract(failing_specs(X)),
NewX = [Spec|X],
assert(failing_specs(NewX)).
% Asserts
assert_that(Actual, equals:Expected) :-
Actual \= Expected, nl, write('Expected '), write(Expected), write(' equal to '), write(Actual), nl, fail;
Actual == Expected.
assert_that(Actual, not_equals:Expected) :-
Actual == Expected, nl, write('Expected '), write(Expected), write(' not equal to '), write(Actual), nl, fail;
Actual \= Expected.
assert_that(Actual, is_true) :-
Actual;
nl, write('Expected '), write(Actual), write(' to be true '), nl, fail.
assert_that(Actual, is_false) :-
Actual, !, nl, write('Expected '), write(Actual), write(' to be false '), nl, fail;
true.
assert_that(Actual, fails) :-
assert_that(Actual, is_false).
assert_that(Actual, is_empty) :-
Actual \= [], nl, write('Expected '), write(Actual), write(' to be empty '), nl, fail;
Actual == [].
assert_that(Actual, has_member:Member) :-
not(member(Member, Actual)), nl, write('Expected '), write(Actual), write(' to has member '), write(Member), nl, fail;
member(Member, Actual).
assert_that(Actual, has_no_member:Member) :-
member(Member, Actual), nl, write('Expected '), write(Actual), write(' to has no member '), write(Member), nl, fail;
not(member(Member, Actual)).
assert_that(Actual, contains_all:Sublist) :-
not(contains_all(Actual, Sublist)), nl, write('Expected '), write(Actual), write(' to contain all members of '), write(Sublist), nl, fail;
contains_all(Actual, Sublist).
contains_all(_, []) :- true.
contains_all(List, [Member]) :- member(Member, List).
contains_all(List, [Member|Rest]) :- member(Member, List), contains_all(List, Rest).
The whole ProSpec can be downloaded from github.
1 Kommentar Add your own
Kommentar verfassen
Trackback this post | Subscribe to the comments via RSS Feed
1.
BDD for Prolog: How To « Stefan Roock | Juli 27, 2009 um 5:05 nachmittags
[...] 27, 2009 ProSpec is a RSpec (http://rspec.info) inspired BDD framework for Prolog. I created it during my [...]