37
38:- module(plunit,
39 [ set_test_options/1, 40 begin_tests/1, 41 begin_tests/2, 42 end_tests/1, 43 run_tests/0, 44 run_tests/1, 45 load_test_files/1, 46 running_tests/0, 47 current_test/5, 48 test_report/1 49 ]).
57:- autoload(library(apply), [maplist/3,include/3]). 58:- autoload(library(lists), [member/2,append/2]). 59:- autoload(library(option), [option/3,option/2]). 60:- autoload(library(ordsets), [ord_intersection/3]). 61:- autoload(library(pairs), [group_pairs_by_key/2,pairs_values/2]). 62:- autoload(library(error), [must_be/2]). 63:- autoload(library(thread), [concurrent_forall/2]). 64
65:- meta_predicate valid_options(+, 1). 66
67
68 71
72:- discontiguous
73 user:term_expansion/2. 74
75:- dynamic
76 include_code/1. 77
78including :-
79 include_code(X),
80 !,
81 X == true.
82including.
83
84if_expansion((:- if(G)), []) :-
85 ( including
86 -> ( catch(G, E, (print_message(error, E), fail))
87 -> asserta(include_code(true))
88 ; asserta(include_code(false))
89 )
90 ; asserta(include_code(else_false))
91 ).
92if_expansion((:- else), []) :-
93 ( retract(include_code(X))
94 -> ( X == true
95 -> X2 = false
96 ; X == false
97 -> X2 = true
98 ; X2 = X
99 ),
100 asserta(include_code(X2))
101 ; throw_error(context_error(no_if),_)
102 ).
103if_expansion((:- endif), []) :-
104 retract(include_code(_)),
105 !.
106
107if_expansion(_, []) :-
108 \+ including.
109
110user:term_expansion(In, Out) :-
111 prolog_load_context(module, plunit),
112 if_expansion(In, Out).
113
114swi :- catch(current_prolog_flag(dialect, swi), _, fail), !.
115swi :- catch(current_prolog_flag(dialect, yap), _, fail).
116sicstus :- catch(current_prolog_flag(system_type, _), _, fail).
117
118
119:- if(swi). 120throw_error(Error_term,Impldef) :-
121 throw(error(Error_term,context(Impldef,_))).
122
123:- set_prolog_flag(generate_debug_info, false). 124current_test_flag(Name, Value) :-
125 current_prolog_flag(Name, Value).
126
127set_test_flag(Name, Value) :-
128 create_prolog_flag(Name, Value, []).
129
131goal_expansion(forall(C,A),
132 \+ (C, \+ A)).
133goal_expansion(current_module(Module,File),
134 module_property(Module, file(File))).
135
136:- if(current_prolog_flag(dialect, yap)). 137
138'$set_predicate_attribute'(_, _, _).
139
140:- endif. 141:- endif. 142
143:- if(sicstus). 144throw_error(Error_term,Impldef) :-
145 throw(error(Error_term,i(Impldef))). 146
148:- op(700, xfx, =@=). 149
150'$set_source_module'(_, _).
157:- dynamic test_flag/2. 158
159current_test_flag(optimise, Val) :-
160 current_prolog_flag(compiling, Compiling),
161 ( Compiling == debugcode ; true 162 -> Val = false
163 ; Val = true
164 ).
165current_test_flag(Name, Val) :-
166 test_flag(Name, Val).
171set_test_flag(Name, Val) :-
172 var(Name),
173 !,
174 throw_error(instantiation_error, set_test_flag(Name,Val)).
175set_test_flag( Name, Val ) :-
176 retractall(test_flag(Name,_)),
177 asserta(test_flag(Name, Val)).
178
179:- op(1150, fx, thread_local). 180
181user:term_expansion((:- thread_local(PI)), (:- dynamic(PI))) :-
182 prolog_load_context(module, plunit).
183
184:- endif. 185
186 189
190:- initialization
191 ( current_test_flag(test_options, _)
192 -> true
193 ; set_test_flag(test_options,
194 [ run(make), 195 sto(false)
196 ])
197 ).
233set_test_options(Options) :-
234 valid_options(Options, global_test_option),
235 set_test_flag(test_options, Options).
236
237global_test_option(load(Load)) :-
238 must_be(oneof([never,always,normal]), Load).
239global_test_option(run(When)) :-
240 must_be(oneof([manual,make,make(all)]), When).
241global_test_option(silent(Bool)) :-
242 must_be(boolean, Bool).
243global_test_option(sto(Bool)) :-
244 must_be(boolean, Bool).
245global_test_option(cleanup(Bool)) :-
246 must_be(boolean, Bool).
247global_test_option(concurrent(Bool)) :-
248 must_be(boolean, Bool).
255loading_tests :-
256 current_test_flag(test_options, Options),
257 option(load(Load), Options, normal),
258 ( Load == always
259 -> true
260 ; Load == normal,
261 \+ current_test_flag(optimise, true)
262 ).
263
264 267
268:- dynamic
269 loading_unit/4, 270 current_unit/4, 271 test_file_for/2.
279begin_tests(Unit) :-
280 begin_tests(Unit, []).
281
282begin_tests(Unit, Options) :-
283 must_be(atom, Unit),
284 valid_options(Options, test_set_option),
285 make_unit_module(Unit, Name),
286 source_location(File, Line),
287 begin_tests(Unit, Name, File:Line, Options).
288
289:- if(swi). 290begin_tests(Unit, Name, File:Line, Options) :-
291 loading_tests,
292 !,
293 '$set_source_module'(Context, Context),
294 ( current_unit(Unit, Name, Context, Options)
295 -> true
296 ; retractall(current_unit(Unit, Name, _, _)),
297 assert(current_unit(Unit, Name, Context, Options))
298 ),
299 '$set_source_module'(Old, Name),
300 '$declare_module'(Name, test, Context, File, Line, false),
301 discontiguous(Name:'unit test'/4),
302 '$set_predicate_attribute'(Name:'unit test'/4, trace, false),
303 discontiguous(Name:'unit body'/2),
304 asserta(loading_unit(Unit, Name, File, Old)).
305begin_tests(Unit, Name, File:_Line, _Options) :-
306 '$set_source_module'(Old, Old),
307 asserta(loading_unit(Unit, Name, File, Old)).
308
309:- else. 310
312
313user:term_expansion((:- begin_tests(Set)),
314 [ (:- begin_tests(Set)),
315 (:- discontiguous(test/2)),
316 (:- discontiguous('unit body'/2)),
317 (:- discontiguous('unit test'/4))
318 ]).
319
320begin_tests(Unit, Name, File:_Line, Options) :-
321 loading_tests,
322 !,
323 ( current_unit(Unit, Name, _, Options)
324 -> true
325 ; retractall(current_unit(Unit, Name, _, _)),
326 assert(current_unit(Unit, Name, -, Options))
327 ),
328 asserta(loading_unit(Unit, Name, File, -)).
329begin_tests(Unit, Name, File:_Line, _Options) :-
330 asserta(loading_unit(Unit, Name, File, -)).
331
332:- endif.
341end_tests(Unit) :-
342 loading_unit(StartUnit, _, _, _),
343 !,
344 ( Unit == StartUnit
345 -> once(retract(loading_unit(StartUnit, _, _, Old))),
346 '$set_source_module'(_, Old)
347 ; throw_error(context_error(plunit_close(Unit, StartUnit)), _)
348 ).
349end_tests(Unit) :-
350 throw_error(context_error(plunit_close(Unit, -)), _).
355:- if(swi). 356
357unit_module(Unit, Module) :-
358 atom_concat('plunit_', Unit, Module).
359
360make_unit_module(Unit, Module) :-
361 unit_module(Unit, Module),
362 ( current_module(Module),
363 \+ current_unit(_, Module, _, _),
364 predicate_property(Module:H, _P),
365 \+ predicate_property(Module:H, imported_from(_M))
366 -> throw_error(permission_error(create, plunit, Unit),
367 'Existing module')
368 ; true
369 ).
370
371:- else. 372
373:- dynamic
374 unit_module_store/2. 375
376unit_module(Unit, Module) :-
377 unit_module_store(Unit, Module),
378 !.
379
380make_unit_module(Unit, Module) :-
381 prolog_load_context(module, Module),
382 assert(unit_module_store(Unit, Module)).
383
384:- endif. 385
386
395expand_test(Name, Options0, Body,
396 [ 'unit test'(Name, Line, Options, Module:'unit body'(Id, Vars)),
397 ('unit body'(Id, Vars) :- !, Body)
398 ]) :-
399 source_location(_File, Line),
400 prolog_load_context(module, Module),
401 atomic_list_concat([Name, '@line ', Line], Id),
402 term_variables(Options0, OptionVars0), sort(OptionVars0, OptionVars),
403 term_variables(Body, BodyVars0), sort(BodyVars0, BodyVars),
404 ord_intersection(OptionVars, BodyVars, VarList),
405 Vars =.. [vars|VarList],
406 ( is_list(Options0) 407 -> Options1 = Options0
408 ; Options1 = [Options0]
409 ),
410 maplist(expand_option, Options1, Options2),
411 valid_options(Options2, test_option),
412 valid_test_mode(Options2, Options).
413
414expand_option(Var, _) :-
415 var(Var),
416 !,
417 throw_error(instantiation_error,_).
418expand_option(A == B, true(A==B)) :- !.
419expand_option(A = B, true(A=B)) :- !.
420expand_option(A =@= B, true(A=@=B)) :- !.
421expand_option(A =:= B, true(A=:=B)) :- !.
422expand_option(error(X), throws(error(X, _))) :- !.
423expand_option(exception(X), throws(X)) :- !. 424expand_option(error(F,C), throws(error(F,C))) :- !. 425expand_option(true, true(true)) :- !.
426expand_option(O, O).
427
428valid_test_mode(Options0, Options) :-
429 include(test_mode, Options0, Tests),
430 ( Tests == []
431 -> Options = [true(true)|Options0]
432 ; Tests = [_]
433 -> Options = Options0
434 ; throw_error(plunit(incompatible_options, Tests), _)
435 ).
436
437test_mode(true(_)).
438test_mode(all(_)).
439test_mode(set(_)).
440test_mode(fail).
441test_mode(throws(_)).
446expand(end_of_file, _) :-
447 loading_unit(Unit, _, _, _),
448 !,
449 end_tests(Unit), 450 fail.
451expand((:-end_tests(_)), _) :-
452 !,
453 fail.
454expand(_Term, []) :-
455 \+ loading_tests.
456expand((test(Name) :- Body), Clauses) :-
457 !,
458 expand_test(Name, [], Body, Clauses).
459expand((test(Name, Options) :- Body), Clauses) :-
460 !,
461 expand_test(Name, Options, Body, Clauses).
462expand(test(Name), _) :-
463 !,
464 throw_error(existence_error(body, test(Name)), _).
465expand(test(Name, _Options), _) :-
466 !,
467 throw_error(existence_error(body, test(Name)), _).
468
469:- if(swi). 470:- multifile
471 system:term_expansion/2. 472:- endif. 473
474system:term_expansion(Term, Expanded) :-
475 ( loading_unit(_, _, File, _)
476 -> source_location(File, _),
477 expand(Term, Expanded)
478 ).
479
480
481 484
485:- if(swi). 486:- else. 487must_be(list, X) :-
488 !,
489 ( is_list(X)
490 -> true
491 ; is_not(list, X)
492 ).
493must_be(Type, X) :-
494 ( call(Type, X)
495 -> true
496 ; is_not(Type, X)
497 ).
498
499is_not(Type, X) :-
500 ( ground(X)
501 -> throw_error(type_error(Type, X), _)
502 ; throw_error(instantiation_error, _)
503 ).
504:- endif.
513valid_options(Options, Pred) :-
514 must_be(list, Options),
515 verify_options(Options, Pred).
516
517verify_options([], _).
518verify_options([H|T], Pred) :-
519 ( call(Pred, H)
520 -> verify_options(T, Pred)
521 ; throw_error(domain_error(Pred, H), _)
522 ).
529test_option(Option) :-
530 test_set_option(Option),
531 !.
532test_option(true(_)).
533test_option(fail).
534test_option(throws(_)).
535test_option(all(_)).
536test_option(set(_)).
537test_option(nondet).
538test_option(fixme(_)).
539test_option(forall(X)) :-
540 must_be(callable, X).
547test_set_option(blocked(X)) :-
548 must_be(ground, X).
549test_set_option(condition(X)) :-
550 must_be(callable, X).
551test_set_option(setup(X)) :-
552 must_be(callable, X).
553test_set_option(cleanup(X)) :-
554 must_be(callable, X).
555test_set_option(sto(V)) :-
556 nonvar(V), member(V, [finite_trees, rational_trees]).
557test_set_option(concurrent(V)) :-
558 must_be(boolean, V).
559
560
561 564
565:- thread_local
566 passed/5, 567 failed/4, 568 failed_assertion/7, 569 blocked/4, 570 sto/4, 571 fixme/5. 572
573:- dynamic
574 running/5.
587run_tests :-
588 cleanup,
589 setup_call_cleanup(
590 setup_trap_assertions(Ref),
591 run_current_units,
592 report_and_cleanup(Ref)).
593
594run_current_units :-
595 forall(current_test_set(Set),
596 run_unit(Set)),
597 check_for_test_errors.
598
599report_and_cleanup(Ref) :-
600 cleanup_trap_assertions(Ref),
601 report,
602 cleanup_after_test.
603
604run_tests(Set) :-
605 cleanup,
606 setup_call_cleanup(
607 setup_trap_assertions(Ref),
608 run_unit_and_check_errors(Set),
609 report_and_cleanup(Ref)).
610
611run_unit_and_check_errors(Set) :-
612 run_unit(Set),
613 check_for_test_errors.
614
615run_unit([]) :- !.
616run_unit([H|T]) :-
617 !,
618 run_unit(H),
619 run_unit(T).
620run_unit(Spec) :-
621 unit_from_spec(Spec, Unit, Tests, Module, UnitOptions),
622 ( option(blocked(Reason), UnitOptions)
623 -> info(plunit(blocked(unit(Unit, Reason))))
624 ; setup(Module, unit(Unit), UnitOptions)
625 -> info(plunit(begin(Spec))),
626 current_test_flag(test_options, GlobalOptions),
627 ( option(concurrent(true), GlobalOptions),
628 option(concurrent(true), UnitOptions, false)
629 -> concurrent_forall((Module:'unit test'(Name, Line, Options, Body),
630 matching_test(Name, Tests)),
631 run_test(Unit, Name, Line, Options, Body))
632 ; forall((Module:'unit test'(Name, Line, Options, Body),
633 matching_test(Name, Tests)),
634 run_test(Unit, Name, Line, Options, Body))),
635 info(plunit(end(Spec))),
636 ( message_level(silent)
637 -> true
638 ; format(user_error, '~N', [])
639 ),
640 cleanup(Module, UnitOptions)
641 ; true
642 ).
643
644unit_from_spec(Unit, Unit, _, Module, Options) :-
645 atom(Unit),
646 !,
647 ( current_unit(Unit, Module, _Supers, Options)
648 -> true
649 ; throw_error(existence_error(unit_test, Unit), _)
650 ).
651unit_from_spec(Unit:Tests, Unit, Tests, Module, Options) :-
652 atom(Unit),
653 !,
654 ( current_unit(Unit, Module, _Supers, Options)
655 -> true
656 ; throw_error(existence_error(unit_test, Unit), _)
657 ).
658
659
660matching_test(X, X) :- !.
661matching_test(Name, Set) :-
662 is_list(Set),
663 memberchk(Name, Set).
664
665cleanup :-
666 thread_self(Me),
667 retractall(passed(_, _, _, _, _)),
668 retractall(failed(_, _, _, _)),
669 retractall(failed_assertion(_, _, _, _, _, _, _)),
670 retractall(blocked(_, _, _, _)),
671 retractall(sto(_, _, _, _)),
672 retractall(fixme(_, _, _, _, _)),
673 retractall(running(_,_,_,_,Me)).
674
675cleanup_after_test :-
676 current_test_flag(test_options, Options),
677 option(cleanup(Cleanup), Options, false),
678 ( Cleanup == true
679 -> cleanup
680 ; true
681 ).
688run_tests_in_files(Files) :-
689 findall(Unit, unit_in_files(Files, Unit), Units),
690 ( Units == []
691 -> true
692 ; run_tests(Units)
693 ).
694
695unit_in_files(Files, Unit) :-
696 is_list(Files),
697 !,
698 member(F, Files),
699 absolute_file_name(F, Source,
700 [ file_type(prolog),
701 access(read),
702 file_errors(fail)
703 ]),
704 unit_file(Unit, Source).
705
706
707
715make_run_tests(Files) :-
716 current_test_flag(test_options, Options),
717 option(run(When), Options, manual),
718 ( When == make
719 -> run_tests_in_files(Files)
720 ; When == make(all)
721 -> run_tests
722 ; true
723 ).
724
725:- if(swi). 726
727unification_capability(sto_error_incomplete).
729unification_capability(rational_trees).
730unification_capability(finite_trees).
731
732set_unification_capability(Cap) :-
733 cap_to_flag(Cap, Flag),
734 set_prolog_flag(occurs_check, Flag).
735
736current_unification_capability(Cap) :-
737 current_prolog_flag(occurs_check, Flag),
738 cap_to_flag(Cap, Flag),
739 !.
740
741cap_to_flag(sto_error_incomplete, error).
742cap_to_flag(rational_trees, false).
743cap_to_flag(finite_trees, true).
744
745:- else. 746:- if(sicstus). 747
748unification_capability(rational_trees).
749set_unification_capability(rational_trees).
750current_unification_capability(rational_trees).
751
752:- else. 753
754unification_capability(_) :-
755 fail.
756
757:- endif. 758:- endif. 759
760 763
764:- if(swi). 765
766:- dynamic prolog:assertion_failed/2. 767
768setup_trap_assertions(Ref) :-
769 asserta((prolog:assertion_failed(Reason, Goal) :-
770 test_assertion_failed(Reason, Goal)),
771 Ref).
772
773cleanup_trap_assertions(Ref) :-
774 erase(Ref).
775
776test_assertion_failed(Reason, Goal) :-
777 thread_self(Me),
778 running(Unit, Test, Line, STO, Me),
779 ( catch(get_prolog_backtrace(10, Stack), _, fail),
780 assertion_location(Stack, AssertLoc)
781 -> true
782 ; AssertLoc = unknown
783 ),
784 current_test_flag(test_options, Options),
785 report_failed_assertion(Unit, Test, Line, AssertLoc,
786 STO, Reason, Goal, Options),
787 assert_cyclic(failed_assertion(Unit, Test, Line, AssertLoc,
788 STO, Reason, Goal)).
789
790assertion_location(Stack, File:Line) :-
791 append(_, [AssertFrame,CallerFrame|_], Stack),
792 prolog_stack_frame_property(AssertFrame,
793 predicate(prolog_debug:assertion/1)),
794 !,
795 prolog_stack_frame_property(CallerFrame, location(File:Line)).
796
797report_failed_assertion(Unit, Test, Line, AssertLoc,
798 STO, Reason, Goal, _Options) :-
799 print_message(
800 error,
801 plunit(failed_assertion(Unit, Test, Line, AssertLoc,
802 STO, Reason, Goal))).
803
804:- else. 805
806setup_trap_assertions(_).
807cleanup_trap_assertions(_).
808
809:- endif. 810
811
812
820run_test(Unit, Name, Line, Options, Body) :-
821 option(forall(Generator), Options),
822 !,
823 unit_module(Unit, Module),
824 term_variables(Generator, Vars),
825 forall(Module:Generator,
826 run_test_once(Unit, @(Name,Vars), Line, Options, Body)).
827run_test(Unit, Name, Line, Options, Body) :-
828 run_test_once(Unit, Name, Line, Options, Body).
829
830run_test_once(Unit, Name, Line, Options, Body) :-
831 current_test_flag(test_options, GlobalOptions),
832 option(sto(false), GlobalOptions, false),
833 !,
834 current_unification_capability(Type),
835 begin_test(Unit, Name, Line, Type),
836 run_test_6(Unit, Name, Line, Options, Body, Result),
837 end_test(Unit, Name, Line, Type),
838 report_result(Result, Options).
839run_test_once(Unit, Name, Line, Options, Body) :-
840 current_unit(Unit, _Module, _Supers, UnitOptions),
841 option(sto(Type), UnitOptions),
842 \+ option(sto(_), Options),
843 !,
844 current_unification_capability(Cap0),
845 call_cleanup(run_test_cap(Unit, Name, Line, [sto(Type)|Options], Body),
846 set_unification_capability(Cap0)).
847run_test_once(Unit, Name, Line, Options, Body) :-
848 current_unification_capability(Cap0),
849 call_cleanup(run_test_cap(Unit, Name, Line, Options, Body),
850 set_unification_capability(Cap0)).
851
852run_test_cap(Unit, Name, Line, Options, Body) :-
853 ( option(sto(Type), Options)
854 -> unification_capability(Type),
855 set_unification_capability(Type),
856 begin_test(Unit, Name, Line, Type),
857 run_test_6(Unit, Name, Line, Options, Body, Result),
858 end_test(Unit, Name, Line, Type),
859 report_result(Result, Options)
860 ; findall(Key-(Type+Result),
861 test_caps(Type, Unit, Name, Line, Options, Body, Result, Key),
862 Pairs),
863 group_pairs_by_key(Pairs, Keyed),
864 ( Keyed == []
865 -> true
866 ; Keyed = [_-Results]
867 -> Results = [_Type+Result|_],
868 report_result(Result, Options) 869 ; pairs_values(Pairs, ResultByType),
870 report_result(sto(Unit, Name, Line, ResultByType), Options)
871 )
872 ).
876test_caps(Type, Unit, Name, Line, Options, Body, Result, Key) :-
877 unification_capability(Type),
878 set_unification_capability(Type),
879 begin_test(Unit, Name, Line, Type),
880 run_test_6(Unit, Name, Line, Options, Body, Result),
881 end_test(Unit, Name, Line, Type),
882 result_to_key(Result, Key),
883 Key \== setup_failed.
884
885result_to_key(blocked(_, _, _, _), blocked).
886result_to_key(failure(_, _, _, How0), failure(How1)) :-
887 ( How0 = succeeded(_T) -> How1 = succeeded ; How0 = How1 ).
888result_to_key(success(_, _, _, Determinism, _), success(Determinism)).
889result_to_key(setup_failed(_,_,_), setup_failed).
890
891report_result(blocked(Unit, Name, Line, Reason), _) :-
892 !,
893 assert(blocked(Unit, Name, Line, Reason)).
894report_result(failure(Unit, Name, Line, How), Options) :-
895 !,
896 failure(Unit, Name, Line, How, Options).
897report_result(success(Unit, Name, Line, Determinism, Time), Options) :-
898 !,
899 success(Unit, Name, Line, Determinism, Time, Options).
900report_result(setup_failed(_Unit, _Name, _Line), _Options).
901report_result(sto(Unit, Name, Line, ResultByType), Options) :-
902 assert(sto(Unit, Name, Line, ResultByType)),
903 print_message(error, plunit(sto(Unit, Name, Line))),
904 report_sto_results(ResultByType, Options).
905
906report_sto_results([], _).
907report_sto_results([Type+Result|T], Options) :-
908 print_message(error, plunit(sto(Type, Result))),
909 report_sto_results(T, Options).
921run_test_6(Unit, Name, Line, Options, _Body,
922 blocked(Unit, Name, Line, Reason)) :-
923 option(blocked(Reason), Options),
924 !.
925run_test_6(Unit, Name, Line, Options, Body, Result) :-
926 option(all(Answer), Options), 927 !,
928 nondet_test(all(Answer), Unit, Name, Line, Options, Body, Result).
929run_test_6(Unit, Name, Line, Options, Body, Result) :-
930 option(set(Answer), Options), 931 !,
932 nondet_test(set(Answer), Unit, Name, Line, Options, Body, Result).
933run_test_6(Unit, Name, Line, Options, Body, Result) :-
934 option(fail, Options), 935 !,
936 unit_module(Unit, Module),
937 ( setup(Module, test(Unit,Name,Line), Options)
938 -> statistics(runtime, [T0,_]),
939 ( catch(Module:Body, E, true)
940 -> ( var(E)
941 -> statistics(runtime, [T1,_]),
942 Time is (T1 - T0)/1000.0,
943 Result = failure(Unit, Name, Line, succeeded(Time)),
944 cleanup(Module, Options)
945 ; Result = failure(Unit, Name, Line, E),
946 cleanup(Module, Options)
947 )
948 ; statistics(runtime, [T1,_]),
949 Time is (T1 - T0)/1000.0,
950 Result = success(Unit, Name, Line, true, Time),
951 cleanup(Module, Options)
952 )
953 ; Result = setup_failed(Unit, Name, Line)
954 ).
955run_test_6(Unit, Name, Line, Options, Body, Result) :-
956 option(true(Cmp), Options),
957 !,
958 unit_module(Unit, Module),
959 ( setup(Module, test(Unit,Name,Line), Options) 960 -> statistics(runtime, [T0,_]),
961 ( catch(call_det(Module:Body, Det), E, true)
962 -> ( var(E)
963 -> statistics(runtime, [T1,_]),
964 Time is (T1 - T0)/1000.0,
965 ( catch(Module:Cmp, E, true)
966 -> ( var(E)
967 -> Result = success(Unit, Name, Line, Det, Time)
968 ; Result = failure(Unit, Name, Line, cmp_error(Cmp, E))
969 )
970 ; Result = failure(Unit, Name, Line, wrong_answer(Cmp))
971 ),
972 cleanup(Module, Options)
973 ; Result = failure(Unit, Name, Line, E),
974 cleanup(Module, Options)
975 )
976 ; Result = failure(Unit, Name, Line, failed),
977 cleanup(Module, Options)
978 )
979 ; Result = setup_failed(Unit, Name, Line)
980 ).
981run_test_6(Unit, Name, Line, Options, Body, Result) :-
982 option(throws(Expect), Options),
983 !,
984 unit_module(Unit, Module),
985 ( setup(Module, test(Unit,Name,Line), Options)
986 -> statistics(runtime, [T0,_]),
987 ( catch(Module:Body, E, true)
988 -> ( var(E)
989 -> Result = failure(Unit, Name, Line, no_exception),
990 cleanup(Module, Options)
991 ; statistics(runtime, [T1,_]),
992 Time is (T1 - T0)/1000.0,
993 ( match_error(Expect, E)
994 -> Result = success(Unit, Name, Line, true, Time)
995 ; Result = failure(Unit, Name, Line, wrong_error(Expect, E))
996 ),
997 cleanup(Module, Options)
998 )
999 ; Result = failure(Unit, Name, Line, failed),
1000 cleanup(Module, Options)
1001 )
1002 ; Result = setup_failed(Unit, Name, Line)
1003 ).
1010nondet_test(Expected, Unit, Name, Line, Options, Body, Result) :-
1011 unit_module(Unit, Module),
1012 result_vars(Expected, Vars),
1013 statistics(runtime, [T0,_]),
1014 ( setup(Module, test(Unit,Name,Line), Options)
1015 -> ( catch(findall(Vars, Module:Body, Bindings), E, true)
1016 -> ( var(E)
1017 -> statistics(runtime, [T1,_]),
1018 Time is (T1 - T0)/1000.0,
1019 ( nondet_compare(Expected, Bindings, Unit, Name, Line)
1020 -> Result = success(Unit, Name, Line, true, Time)
1021 ; Result = failure(Unit, Name, Line, wrong_answer(Expected, Bindings))
1022 ),
1023 cleanup(Module, Options)
1024 ; Result = failure(Unit, Name, Line, E),
1025 cleanup(Module, Options)
1026 )
1027 )
1028 ; Result = setup_failed(Unit, Name, Line)
1029 ).
1037result_vars(Expected, Vars) :-
1038 arg(1, Expected, CmpOp),
1039 arg(1, CmpOp, Vars).
1049nondet_compare(all(Cmp), Bindings, _Unit, _Name, _Line) :-
1050 cmp(Cmp, _Vars, Op, Values),
1051 cmp_list(Values, Bindings, Op).
1052nondet_compare(set(Cmp), Bindings0, _Unit, _Name, _Line) :-
1053 cmp(Cmp, _Vars, Op, Values0),
1054 sort(Bindings0, Bindings),
1055 sort(Values0, Values),
1056 cmp_list(Values, Bindings, Op).
1057
1058cmp_list([], [], _Op).
1059cmp_list([E0|ET], [V0|VT], Op) :-
1060 call(Op, E0, V0),
1061 cmp_list(ET, VT, Op).
1065cmp(Var == Value, Var, ==, Value).
1066cmp(Var =:= Value, Var, =:=, Value).
1067cmp(Var = Value, Var, =, Value).
1068:- if(swi). 1069cmp(Var =@= Value, Var, =@=, Value).
1070:- else. 1071:- if(sicstus). 1072cmp(Var =@= Value, Var, variant, Value). 1073:- endif. 1074:- endif.
1082:- if((swi|sicstus)). 1083call_det(Goal, Det) :-
1084 call_cleanup(Goal,Det0=true),
1085 ( var(Det0) -> Det = false ; Det = true ).
1086:- else. 1087call_det(Goal, true) :-
1088 call(Goal).
1089:- endif.
1096match_error(Expect, Rec) :-
1097 subsumes_term(Expect, Rec).
1110setup(Module, Context, Options) :-
1111 option(condition(Condition), Options),
1112 option(setup(Setup), Options),
1113 !,
1114 setup(Module, Context, [condition(Condition)]),
1115 setup(Module, Context, [setup(Setup)]).
1116setup(Module, Context, Options) :-
1117 option(setup(Setup), Options),
1118 !,
1119 ( catch(call_ex(Module, Setup), E, true)
1120 -> ( var(E)
1121 -> true
1122 ; print_message(error, plunit(error(setup, Context, E))),
1123 fail
1124 )
1125 ; print_message(error, error(goal_failed(Setup), _)),
1126 fail
1127 ).
1128setup(Module, Context, Options) :-
1129 option(condition(Setup), Options),
1130 !,
1131 ( catch(call_ex(Module, Setup), E, true)
1132 -> ( var(E)
1133 -> true
1134 ; print_message(error, plunit(error(condition, Context, E))),
1135 fail
1136 )
1137 ; fail
1138 ).
1139setup(_,_,_).
1145call_ex(Module, Goal) :-
1146 Module:(expand_goal(Goal, GoalEx),
1147 GoalEx).
1154cleanup(Module, Options) :-
1155 option(cleanup(Cleanup), Options, true),
1156 ( catch(call_ex(Module, Cleanup), E, true)
1157 -> ( var(E)
1158 -> true
1159 ; print_message(warning, E)
1160 )
1161 ; print_message(warning, goal_failed(Cleanup, '(cleanup handler)'))
1162 ).
1163
1164success(Unit, Name, Line, Det, _Time, Options) :-
1165 memberchk(fixme(Reason), Options),
1166 !,
1167 ( ( Det == true
1168 ; memberchk(nondet, Options)
1169 )
1170 -> progress(Unit, Name, nondet),
1171 Ok = passed
1172 ; progress(Unit, Name, fixme),
1173 Ok = nondet
1174 ),
1175 flush_output(user_error),
1176 assert(fixme(Unit, Name, Line, Reason, Ok)).
1177success(Unit, Name, Line, _, _, Options) :-
1178 failed_assertion(Unit, Name, Line, _,_,_,_),
1179 !,
1180 failure(Unit, Name, Line, assertion, Options).
1181success(Unit, Name, Line, Det, Time, Options) :-
1182 assert(passed(Unit, Name, Line, Det, Time)),
1183 ( ( Det == true
1184 ; memberchk(nondet, Options)
1185 )
1186 -> progress(Unit, Name, passed)
1187 ; unit_file(Unit, File),
1188 print_message(warning, plunit(nondet(File, Line, Name)))
1189 ).
1190
1191failure(Unit, Name, Line, _, Options) :-
1192 memberchk(fixme(Reason), Options),
1193 !,
1194 progress(Unit, Name, failed),
1195 assert(fixme(Unit, Name, Line, Reason, failed)).
1196failure(Unit, Name, Line, E, Options) :-
1197 report_failure(Unit, Name, Line, E, Options),
1198 assert_cyclic(failed(Unit, Name, Line, E)).
1208:- if(swi). 1209assert_cyclic(Term) :-
1210 acyclic_term(Term),
1211 !,
1212 assert(Term).
1213assert_cyclic(Term) :-
1214 Term =.. [Functor|Args],
1215 recorda(cyclic, Args, Id),
1216 functor(Term, _, Arity),
1217 length(NewArgs, Arity),
1218 Head =.. [Functor|NewArgs],
1219 assert((Head :- recorded(_, Var, Id), Var = NewArgs)).
1220:- else. 1221:- if(sicstus). 1222:- endif. 1223assert_cyclic(Term) :-
1224 assert(Term).
1225:- endif. 1226
1227
1228
1243begin_test(Unit, Test, Line, STO) :-
1244 thread_self(Me),
1245 assert(running(Unit, Test, Line, STO, Me)),
1246 unit_file(Unit, File),
1247 print_message(silent, plunit(begin(Unit:Test, File:Line, STO))).
1248
1249end_test(Unit, Test, Line, STO) :-
1250 thread_self(Me),
1251 retractall(running(_,_,_,_,Me)),
1252 unit_file(Unit, File),
1253 print_message(silent, plunit(end(Unit:Test, File:Line, STO))).
1259running_tests :-
1260 running_tests(Running),
1261 print_message(informational, plunit(running(Running))).
1262
1263running_tests(Running) :-
1264 findall(running(Unit:Test, File:Line, STO, Thread),
1265 ( running(Unit, Test, Line, STO, Thread),
1266 unit_file(Unit, File)
1267 ), Running).
1274current_test(Unit, Test, Line, Body, Options) :-
1275 current_unit(Unit, Module, _Supers, _UnitOptions),
1276 Module:'unit test'(Test, Line, Options, Body).
1282check_for_test_errors :-
1283 number_of_clauses(failed/4, Failed),
1284 number_of_clauses(failed_assertion/7, FailedAssertion),
1285 number_of_clauses(sto/4, STO),
1286 Failed+FailedAssertion+STO =:= 0.
1293report :-
1294 number_of_clauses(passed/5, Passed),
1295 number_of_clauses(failed/4, Failed),
1296 number_of_clauses(failed_assertion/7, FailedAssertion),
1297 number_of_clauses(blocked/4, Blocked),
1298 number_of_clauses(sto/4, STO),
1299 print_message(silent,
1300 plunit(summary(plunit{passed:Passed,
1301 failed:Failed,
1302 failed_assertions:FailedAssertion,
1303 blocked:Blocked,
1304 sto:STO}))),
1305 ( Passed+Failed+FailedAssertion+Blocked+STO =:= 0
1306 -> info(plunit(no_tests))
1307 ; Failed+FailedAssertion+Blocked+STO =:= 0
1308 -> report_fixme,
1309 info(plunit(all_passed(Passed)))
1310 ; report_blocked,
1311 report_fixme,
1312 report_failed_assertions,
1313 report_failed,
1314 report_sto,
1315 info(plunit(passed(Passed)))
1316 ).
1317
1318number_of_clauses(F/A,N) :-
1319 ( current_predicate(F/A)
1320 -> functor(G,F,A),
1321 findall(t, G, Ts),
1322 length(Ts, N)
1323 ; N = 0
1324 ).
1325
1326report_blocked :-
1327 number_of_clauses(blocked/4,N),
1328 N > 0,
1329 !,
1330 info(plunit(blocked(N))),
1331 ( blocked(Unit, Name, Line, Reason),
1332 unit_file(Unit, File),
1333 print_message(informational,
1334 plunit(blocked(File:Line, Name, Reason))),
1335 fail ; true
1336 ).
1337report_blocked.
1338
1339report_failed :-
1340 number_of_clauses(failed/4, N),
1341 info(plunit(failed(N))).
1342
1343report_failed_assertions :-
1344 number_of_clauses(failed_assertion/7, N),
1345 info(plunit(failed_assertions(N))).
1346
1347report_sto :-
1348 number_of_clauses(sto/4, N),
1349 info(plunit(sto(N))).
1350
1351report_fixme :-
1352 report_fixme(_,_,_).
1353
1354report_fixme(TuplesF, TuplesP, TuplesN) :-
1355 fixme(failed, TuplesF, Failed),
1356 fixme(passed, TuplesP, Passed),
1357 fixme(nondet, TuplesN, Nondet),
1358 print_message(informational, plunit(fixme(Failed, Passed, Nondet))).
1359
1360
1361fixme(How, Tuples, Count) :-
1362 findall(fixme(Unit, Name, Line, Reason, How),
1363 fixme(Unit, Name, Line, Reason, How), Tuples),
1364 length(Tuples, Count).
1365
1366
1367report_failure(Unit, Name, _, assertion, _) :-
1368 !,
1369 progress(Unit, Name, assertion).
1370report_failure(Unit, Name, Line, Error, _Options) :-
1371 print_message(error, plunit(failed(Unit, Name, Line, Error))).
1378test_report(fixme) :-
1379 !,
1380 report_fixme(TuplesF, TuplesP, TuplesN),
1381 append([TuplesF, TuplesP, TuplesN], Tuples),
1382 print_message(informational, plunit(fixme(Tuples))).
1383test_report(What) :-
1384 throw_error(domain_error(report_class, What), _).
1385
1386
1387
1395current_test_set(Unit) :-
1396 current_unit(Unit, _Module, _Context, _Options).
1401unit_file(Unit, File) :-
1402 current_unit(Unit, Module, _Context, _Options),
1403 current_module(Module, File).
1404unit_file(Unit, PlFile) :-
1405 nonvar(PlFile),
1406 test_file_for(TestFile, PlFile),
1407 current_module(Module, TestFile),
1408 current_unit(Unit, Module, _Context, _Options).
1409
1410
1411
1419load_test_files(_Options) :-
1420 ( source_file(File),
1421 file_name_extension(Base, Old, File),
1422 Old \== plt,
1423 file_name_extension(Base, plt, TestFile),
1424 exists_file(TestFile),
1425 ( test_file_for(TestFile, File)
1426 -> true
1427 ; load_files(TestFile,
1428 [ if(changed),
1429 imports([])
1430 ]),
1431 asserta(test_file_for(TestFile, File))
1432 ),
1433 fail ; true
1434 ).
1435
1436
1437
1438
1447info(Term) :-
1448 message_level(Level),
1449 print_message(Level, Term).
1450
1451progress(Unit, Name, Result) :-
1452 print_message(information, plunit(progress(Unit, Name, Result))).
1453
1454message_level(Level) :-
1455 current_test_flag(test_options, Options),
1456 option(silent(Silent), Options, false),
1457 ( Silent == false
1458 -> Level = informational
1459 ; Level = silent
1460 ).
1461
1462locationprefix(File:Line) -->
1463 !,
1464 [ '~w:~d:\n\t'-[File,Line]].
1465locationprefix(test(Unit,_Test,Line)) -->
1466 !,
1467 { unit_file(Unit, File) },
1468 locationprefix(File:Line).
1469locationprefix(unit(Unit)) -->
1470 !,
1471 [ 'PL-Unit: unit ~w: '-[Unit] ].
1472locationprefix(FileLine) -->
1473 { throw_error(type_error(locationprefix,FileLine), _) }.
1474
1475:- discontiguous
1476 message//1. 1477:- '$hide'(message//1). 1478
1479message(error(context_error(plunit_close(Name, -)), _)) -->
1480 [ 'PL-Unit: cannot close unit ~w: no open unit'-[Name] ].
1481message(error(context_error(plunit_close(Name, Start)), _)) -->
1482 [ 'PL-Unit: cannot close unit ~w: current unit is ~w'-[Name, Start] ].
1483message(plunit(nondet(File, Line, Name))) -->
1484 locationprefix(File:Line),
1485 [ 'PL-Unit: Test ~w: Test succeeded with choicepoint'- [Name] ].
1486message(error(plunit(incompatible_options, Tests), _)) -->
1487 [ 'PL-Unit: incompatible test-options: ~p'-[Tests] ].
1488
1489 1490:- if(swi). 1491message(plunit(progress(_Unit, _Name, Result))) -->
1492 [ at_same_line ], result(Result), [flush].
1493message(plunit(begin(Unit))) -->
1494 [ 'PL-Unit: ~w '-[Unit], flush ].
1495message(plunit(end(_Unit))) -->
1496 [ at_same_line, ' done' ].
1497:- else. 1498message(plunit(begin(Unit))) -->
1499 [ 'PL-Unit: ~w '-[Unit]].
1500message(plunit(end(_Unit))) -->
1501 [ ' done'-[] ].
1502:- endif. 1503message(plunit(blocked(unit(Unit, Reason)))) -->
1504 [ 'PL-Unit: ~w blocked: ~w'-[Unit, Reason] ].
1505message(plunit(running([]))) -->
1506 !,
1507 [ 'PL-Unit: no tests running' ].
1508message(plunit(running([One]))) -->
1509 !,
1510 [ 'PL-Unit: running ' ],
1511 running(One).
1512message(plunit(running(More))) -->
1513 !,
1514 [ 'PL-Unit: running tests:', nl ],
1515 running(More).
1516message(plunit(fixme([]))) --> !.
1517message(plunit(fixme(Tuples))) -->
1518 !,
1519 fixme_message(Tuples).
1520
1521 1522message(plunit(blocked(1))) -->
1523 !,
1524 [ 'one test is blocked:'-[] ].
1525message(plunit(blocked(N))) -->
1526 [ '~D tests are blocked:'-[N] ].
1527message(plunit(blocked(Pos, Name, Reason))) -->
1528 locationprefix(Pos),
1529 test_name(Name),
1530 [ ': ~w'-[Reason] ].
1531
1532 1533message(plunit(no_tests)) -->
1534 !,
1535 [ 'No tests to run' ].
1536message(plunit(all_passed(1))) -->
1537 !,
1538 [ 'test passed' ].
1539message(plunit(all_passed(Count))) -->
1540 !,
1541 [ 'All ~D tests passed'-[Count] ].
1542message(plunit(passed(Count))) -->
1543 !,
1544 [ '~D tests passed'-[Count] ].
1545message(plunit(failed(0))) -->
1546 !,
1547 [].
1548message(plunit(failed(1))) -->
1549 !,
1550 [ '1 test failed'-[] ].
1551message(plunit(failed(N))) -->
1552 [ '~D tests failed'-[N] ].
1553message(plunit(failed_assertions(0))) -->
1554 !,
1555 [].
1556message(plunit(failed_assertions(1))) -->
1557 !,
1558 [ '1 assertion failed'-[] ].
1559message(plunit(failed_assertions(N))) -->
1560 [ '~D assertions failed'-[N] ].
1561message(plunit(sto(0))) -->
1562 !,
1563 [].
1564message(plunit(sto(N))) -->
1565 [ '~D test results depend on unification mode'-[N] ].
1566message(plunit(fixme(0,0,0))) -->
1567 [].
1568message(plunit(fixme(Failed,0,0))) -->
1569 !,
1570 [ 'all ~D tests flagged FIXME failed'-[Failed] ].
1571message(plunit(fixme(Failed,Passed,0))) -->
1572 [ 'FIXME: ~D failed; ~D passed'-[Failed, Passed] ].
1573message(plunit(fixme(Failed,Passed,Nondet))) -->
1574 { TotalPassed is Passed+Nondet },
1575 [ 'FIXME: ~D failed; ~D passed; (~D nondet)'-
1576 [Failed, TotalPassed, Nondet] ].
1577message(plunit(failed(Unit, Name, Line, Failure))) -->
1578 { unit_file(Unit, File) },
1579 locationprefix(File:Line),
1580 test_name(Name),
1581 [': '-[] ],
1582 failure(Failure).
1583:- if(swi). 1584message(plunit(failed_assertion(Unit, Name, Line, AssertLoc,
1585 _STO, Reason, Goal))) -->
1586 { unit_file(Unit, File) },
1587 locationprefix(File:Line),
1588 test_name(Name),
1589 [ ': assertion'-[] ],
1590 assertion_location(AssertLoc, File),
1591 assertion_reason(Reason), ['\n\t'],
1592 assertion_goal(Unit, Goal).
1593
1594assertion_location(File:Line, File) -->
1595 [ ' at line ~w'-[Line] ].
1596assertion_location(File:Line, _) -->
1597 [ ' at ~w:~w'-[File, Line] ].
1598assertion_location(unknown, _) -->
1599 [].
1600
1601assertion_reason(fail) -->
1602 !,
1603 [ ' failed'-[] ].
1604assertion_reason(Error) -->
1605 { message_to_string(Error, String) },
1606 [ ' raised "~w"'-[String] ].
1607
1608assertion_goal(Unit, Goal) -->
1609 { unit_module(Unit, Module),
1610 unqualify(Goal, Module, Plain)
1611 },
1612 [ 'Assertion: ~p'-[Plain] ].
1613
1614unqualify(Var, _, Var) :-
1615 var(Var),
1616 !.
1617unqualify(M:Goal, Unit, Goal) :-
1618 nonvar(M),
1619 unit_module(Unit, M),
1620 !.
1621unqualify(M:Goal, _, Goal) :-
1622 callable(Goal),
1623 predicate_property(M:Goal, imported_from(system)),
1624 !.
1625unqualify(Goal, _, Goal).
1626
1627result(passed) --> ['.'-[]].
1628result(nondet) --> ['+'-[]].
1629result(fixme) --> ['!'-[]].
1630result(failed) --> ['-'-[]].
1631result(assertion) --> ['A'-[]].
1632
1633:- endif. 1634 1635message(plunit(error(Where, Context, Exception))) -->
1636 locationprefix(Context),
1637 { message_to_string(Exception, String) },
1638 [ 'error in ~w: ~w'-[Where, String] ].
1639
1640 1641message(plunit(sto(Unit, Name, Line))) -->
1642 { unit_file(Unit, File) },
1643 locationprefix(File:Line),
1644 test_name(Name),
1645 [' is subject to occurs check (STO): '-[] ].
1646message(plunit(sto(Type, Result))) -->
1647 sto_type(Type),
1648 sto_result(Result).
1649
1650 1651:- if(swi). 1652message(interrupt(begin)) -->
1653 { thread_self(Me),
1654 running(Unit, Test, Line, STO, Me),
1655 !,
1656 unit_file(Unit, File)
1657 },
1658 [ 'Interrupted test '-[] ],
1659 running(running(Unit:Test, File:Line, STO, Me)),
1660 [nl],
1661 '$messages':prolog_message(interrupt(begin)).
1662message(interrupt(begin)) -->
1663 '$messages':prolog_message(interrupt(begin)).
1664:- endif. 1665
1666test_name(@(Name,Bindings)) -->
1667 !,
1668 [ 'test ~w (forall bindings = ~p)'-[Name, Bindings] ].
1669test_name(Name) -->
1670 !,
1671 [ 'test ~w'-[Name] ].
1672
1673sto_type(sto_error_incomplete) -->
1674 [ 'Finite trees (error checking): ' ].
1675sto_type(rational_trees) -->
1676 [ 'Rational trees: ' ].
1677sto_type(finite_trees) -->
1678 [ 'Finite trees: ' ].
1679
1680sto_result(success(_Unit, _Name, _Line, Det, Time)) -->
1681 det(Det),
1682 [ ' success in ~2f seconds'-[Time] ].
1683sto_result(failure(_Unit, _Name, _Line, How)) -->
1684 failure(How).
1685
1686det(true) -->
1687 [ 'deterministic' ].
1688det(false) -->
1689 [ 'non-deterministic' ].
1690
1691running(running(Unit:Test, File:Line, STO, Thread)) -->
1692 thread(Thread),
1693 [ '~q:~q at ~w:~d'-[Unit, Test, File, Line] ],
1694 current_sto(STO).
1695running([H|T]) -->
1696 ['\t'], running(H),
1697 ( {T == []}
1698 -> []
1699 ; [nl], running(T)
1700 ).
1701
1702thread(main) --> !.
1703thread(Other) -->
1704 [' [~w] '-[Other] ].
1705
1706current_sto(sto_error_incomplete) -->
1707 [ ' (STO: error checking)' ].
1708current_sto(rational_trees) -->
1709 [].
1710current_sto(finite_trees) -->
1711 [ ' (STO: occurs check enabled)' ].
1712
1713:- if(swi). 1714write_term(T, OPS) -->
1715 ['~@'-[write_term(T,OPS)]].
1716:- else. 1717write_term(T, _OPS) -->
1718 ['~q'-[T]].
1719:- endif. 1720
1721expected_got_ops_(Ex, E, OPS, Goals) -->
1722 [' Expected: '-[]], write_term(Ex, OPS), [nl],
1723 [' Got: '-[]], write_term(E, OPS), [nl],
1724 ( { Goals = [] } -> []
1725 ; [' with: '-[]], write_term(Goals, OPS), [nl]
1726 ).
1727
1728
1729failure(Var) -->
1730 { var(Var) },
1731 !,
1732 [ 'Unknown failure?' ].
1733failure(succeeded(Time)) -->
1734 !,
1735 [ 'must fail but succeeded in ~2f seconds~n'-[Time] ].
1736failure(wrong_error(Expected, Error)) -->
1737 !,
1738 { copy_term(Expected-Error, Ex-E, Goals),
1739 numbervars(Ex-E-Goals, 0, _),
1740 write_options(OPS)
1741 },
1742 [ 'wrong error'-[], nl ],
1743 expected_got_ops_(Ex, E, OPS, Goals).
1744failure(wrong_answer(Cmp)) -->
1745 { Cmp =.. [Op,Answer,Expected],
1746 !,
1747 copy_term(Expected-Answer, Ex-A, Goals),
1748 numbervars(Ex-A-Goals, 0, _),
1749 write_options(OPS)
1750 },
1751 [ 'wrong answer (compared using ~w)'-[Op], nl ],
1752 expected_got_ops_(Ex, A, OPS, Goals).
1753failure(wrong_answer(CmpExpected, Bindings)) -->
1754 { ( CmpExpected = all(Cmp)
1755 -> Cmp =.. [_Op1,_,Expected],
1756 Got = Bindings,
1757 Type = all
1758 ; CmpExpected = set(Cmp),
1759 Cmp =.. [_Op2,_,Expected0],
1760 sort(Expected0, Expected),
1761 sort(Bindings, Got),
1762 Type = set
1763 )
1764 },
1765 [ 'wrong "~w" answer:'-[Type] ],
1766 [ nl, ' Expected: ~q'-[Expected] ],
1767 [ nl, ' Found: ~q'-[Got] ].
1768:- if(swi). 1769failure(cmp_error(_Cmp, Error)) -->
1770 { message_to_string(Error, Message) },
1771 [ 'Comparison error: ~w'-[Message] ].
1772failure(Error) -->
1773 { Error = error(_,_),
1774 !,
1775 message_to_string(Error, Message)
1776 },
1777 [ 'received error: ~w'-[Message] ].
1778:- endif. 1779failure(Why) -->
1780 [ '~p~n'-[Why] ].
1781
1782fixme_message([]) --> [].
1783fixme_message([fixme(Unit, _Name, Line, Reason, How)|T]) -->
1784 { unit_file(Unit, File) },
1785 fixme_message(File:Line, Reason, How),
1786 ( {T == []}
1787 -> []
1788 ; [nl],
1789 fixme_message(T)
1790 ).
1791
1792fixme_message(Location, Reason, failed) -->
1793 [ 'FIXME: ~w: ~w'-[Location, Reason] ].
1794fixme_message(Location, Reason, passed) -->
1795 [ 'FIXME: ~w: passed ~w'-[Location, Reason] ].
1796fixme_message(Location, Reason, nondet) -->
1797 [ 'FIXME: ~w: passed (nondet) ~w'-[Location, Reason] ].
1798
1799
1800write_options([ numbervars(true),
1801 quoted(true),
1802 portray(true),
1803 max_depth(100),
1804 attributes(portray)
1805 ]).
1806
1807:- if(swi). 1808
1809:- multifile
1810 prolog:message/3,
1811 user:message_hook/3. 1812
1813prolog:message(Term) -->
1814 message(Term).
1815
1817
1818user:message_hook(make(done(Files)), _, _) :-
1819 make_run_tests(Files),
1820 fail. 1821
1822:- endif. 1823
1824:- if(sicstus). 1825
1826user:generate_message_hook(Message) -->
1827 message(Message),
1828 [nl].
1837user:message_hook(informational, plunit(begin(Unit)), _Lines) :-
1838 format(user_error, '% PL-Unit: ~w ', [Unit]),
1839 flush_output(user_error).
1840user:message_hook(informational, plunit(end(_Unit)), _Lines) :-
1841 format(user, ' done~n', []).
1842
1843:- endif.
Unit Testing
Unit testing environment for SWI-Prolog and SICStus Prolog. For usage, please visit http://www.swi-prolog.org/pldoc/package/plunit. */