/* -*- Mode: Prolog -*- */

/* plunit_reporting.pl --
 * Extra test running and reporting predicates to ease automating
 * multiple tests of similar code.
 */

:- module(plunit2,
	  [ run_tests_and_report/1,
	    run_tests_and_report/2
	  ]).
:- use_module(library(plunit)).
:- add_import_module(plunit2, plunit, start).


%!  run_tests_and_report(-Report) is semidet.
%!  run_tests_and_report(+TestSet, -Report) is semidet.
%
%   Run tests and report about the results.  The predicate
%   run_tests_and_report/1 runs all known tests that are not
%   blocked. The predicate run_tests_and_report/2 takes a
%   specification of tests to run.  This is either a single
%   specification or a list of specifications. Each single
%   specification is either the name of a test-unit or a term
%   <test-unit>:<test>, denoting a single test within a unit.
%
%   The predicates always succeed (i.e., they do not fail if a test
%   fails) and instantiate the Report variable with a `report' term with
%   5 non negative integer arguments:
%
%       report(Passed, Failed, FailedAssertions, Blocked, STO)
%
%   In this way it it possible to use the predicates to post-process the
%   results of the test run.

/* The predicates report_and_cleanup2/2 and report2/5 are named so to
 * avoid, for the time being, issues with 'discontinuous' settings.
 */

run_tests_and_report(report(Passed,
			    Failed,
			    FailedAssertions,
			    Blocked,
			    STO)) :-
    cleanup,
    setup_call_cleanup(
        setup_trap_assertions(Ref),
        (   run_current_units2,
            %% writeln(">>> Current units running"), % Debug.
            true
        ),
        report_and_cleanup2(Ref,
			    report(Passed,
				   Failed,
				   FailedAssertions,
				   Blocked,
				   STO))).

run_tests_and_report(Set,
		     report(Passed,
			    Failed,
			    FailedAssertions,
			    Blocked,
			    STO)) :-
    cleanup,
    setup_call_cleanup(
        setup_trap_assertions(Ref),
        (
            %% format(">>> Current unit running ~w~n", [Set]),
            run_unit_and_check_errors2(Set),
            %% format(">>> Current unit run and errors checked ~w~n", [Set]),
            true
        ),
        report_and_cleanup2(Ref,
			    report(Passed,
				   Failed,
				   FailedAssertions,
				   Blocked,
				   STO))).


%!  run_current_units2/0
%
%   Predicate renamed from original version. It segues into
%   check_for_test_errors2/0 (which could probably be elided).

run_current_units2 :-
    forall(current_test_set(Set),
           run_unit(Set)),
    check_for_test_errors2.


%!  report_and_cleanup2/2
%
%   Renamed predicate from original.

report_and_cleanup2(Ref,
		    report(Passed,
			   Failed,
			   FailedAssertions,
			   Blocked,
			   STO)) :-
    cleanup_trap_assertions(Ref),
    %% format(">>> After trap cleanup ~w~n", [Ref]), % Debug.
    report2(Passed,
	    Failed,
	    FailedAssertions,
	    Blocked,
	    STO),
    /* Debug.
    format(">>> ~d ~d ~d ~d ~d~n",
           [Passed,
            Failed,
            FailedAssertions,
            Blocked,
            STO]),
    */
    cleanup_after_test2.                        % Can probably be elided.


%!  run_unit_and_check_errors2/1
%
%   Run a test and check for errors.
%   This predicate is just a renaming.

/* The check_for_test_errors2 can be elided. */

run_unit_and_check_errors2(Set) :-
    run_unit(Set),
    %% format(">>> RUCE ~w~n", [Set]), % Debug.
    check_for_test_errors2,
    %% format(">>> RUCE done~n"). % Debug; the following `true' is redundant.
    true.


%!  check_for_test_errors2/0
%
%   This check is always true, as we always want to report the the
%   `report' term.

check_for_test_errors2 :- true.


%!  report2/5
%
%   This predicate is true with Passed being equal to the numebr of
%   passed tests, Failed the number of failed tests, FailedAssertions
%   the number of failed assertions, Blocked the number of blocked
%   (not run) tests and STO the number of `sto' tests.

report2(Passed, Failed, FailedAssertion, Blocked, STO) :-
    number_of_clauses(passed/5, Passed),
    number_of_clauses(failed/4, Failed),
    number_of_clauses(failed_assertion/7, FailedAssertion),
    number_of_clauses(blocked/4, Blocked),
    number_of_clauses(sto/4, STO),
    (   Passed+Failed+FailedAssertion+Blocked+STO =:= 0
    ->  info(plunit(no_tests))
    ;   Failed+FailedAssertion+Blocked+STO =:= 0
    ->  report_fixme,
        info(plunit(all_passed(Passed)))
    ;   report_blocked,
        report_fixme,
        report_failed_assertions,
        report_failed,
        report_sto,
        info(plunit(passed(Passed)))
    ).


%!  cleanup_after_test2/0
%
%   Predicate renamed and patched w.r.t. the original one.

cleanup_after_test2 :-
    current_test_flag(test_options, Options),
    %% format(">>> Options ~w~n", [Options]),
    option(cleanup(Cleanup), Options, false),
    %% format(">>> Cleanup ~w~n", [Cleanup]),
    (   Cleanup == true
    ->  cleanup
    ;  (
           %%  writeln(">>> Not cleaning up"), % Debug.
            true
       )
    ).

/* end of file -- plunit_reporting.pl */
