
% ------------------------------------------------------------------------------------------------------
% Test process join
% This test is based on prova-examples/process_join.prova 
% ------------------------------------------------------------------------------------------------------

testcase("processJoinTestCase.prova").

%-----------------------------------------------------------------------
% Imported libraries
%-----------------------------------------------------------------------
:-eval(consult('./ContractLog/list_math.prova')).
:-eval(consult('./ContractLog/math.prova')).
:-eval(consult('./ContractLog/list.prova')).
:-eval(consult('./ContractLog/datetime.prova')).
:-eval(consult('./ContractLog/testcase.prova')).
:-eval(consult('./ContractLog/utils.prova')).
:-eval(consult('./ContractLog/update.prova')).

			process_join() :-
				println(['==========process_join==========']),
				iam(Me),
				% A more or less useless message to signal the start of the conversation. It may do something useful in a real application. 
				sendMsg(XID,self,Me,start,[]),
				% The result of the above is that we now have the conversation-id XID initialised.
				% Create a join predicate join_1 with the list of required input patterns in the last argument.
				init_join(XID,join_1,[c(_),b(_)]),
				% This will create two parallel processing streams.
				% Note that Prova does not run them in separate threads but they are independent and can communicate
				%    with other agents asynchronously effectively allowing for parallel processing.
				fork_a_b(Me,XID).

			fork_a_b(Me,XID) :-
				sendMsg(XID,self,Me,reply,a(1),corr_a),
				rcvMsg(XID,self,Me,reply,a(1),corr_a),
				fork_c_d(Me,XID).
			fork_a_b(Me,XID) :-
				sendMsg(XID,self,Me,reply,b(1),corr_b),
				rcvMsg(XID,self,Me,reply,b(1),corr_b),
				% Tell the join join_1 that a new pattern is ready
				join(Me,XID,join_1,b(1)).

			fork_c_d(Me,XID) :-
				sendMsg(XID,self,Me,reply,c(1),corr_c),
				rcvMsg(XID,self,Me,reply,c(1),corr_c),
				% Tell the join join_1 that a new pattern is ready
				join(Me,XID,join_1,c(1)).
			fork_c_d(Me) :-
				sendMsg(XID,self,Me,reply,d(1),corr_d),
				rcvMsg(XID,self,Me,reply,d(1),corr_d).

			% The following rule will be invoked by join once all the inputs are assembled.
			join_1(Me,XID,Inputs) :-
				println(['Joined for XID=',XID,' with inputs: ',Inputs]),
				assert(inputs(Inputs)),
				sendMsg(XID,self,Me,ready).

% A testing harness for printing all incoming 'reply' messages.
rcvMsg(XID,Protocol,From,reply,[X|Xs]|Extra) :-
	println(['reply for conversation-id ',XID,': ',[X|Xs],','|Extra]).

:-eval(process_join()).

% ------------------------------------------------------------------------------------------------------
% (Meta) test rules
% ------------------------------------------------------------------------------------------------------

:-eval(
	add(
		"processJoinTestCase",
		"
			process_join(Inputs) :-
				inputs(Inputs).
		"
	)
).

% ------------------------------------------------------------------------------------------------------
% Test facts
% ------------------------------------------------------------------------------------------------------

% No facts used in this test

% ------------------------------------------------------------------------------------------------------
% Tests
% ------------------------------------------------------------------------------------------------------

testSuccess("process join Test 1","Test 1 succeeded: process branches joined successfully") :-
	rcvMsg(XID,self,Me,ready),
	testcase("processJoinTestCase.prova"),
%	testResultsOrder(process_join(Inputs),Inputs,[[b,1],[c,1]]). 
	testNumberOfResults(process_join(Inputs),Inputs,1). 
testFailure("process join Test 1","Incorrect results in process_join(Inputs)") :-
	not(testSuccess("process join Test 1",Message)).

runTest("processJoinTestCase.prova") :-
	testSuccess("process join Test 1",Message).

% ------------------------------------------------------------------------------------------------------
% Test Coverage
% ------------------------------------------------------------------------------------------------------

testCoverage(LP,CoveredClauses,NotCoveredClauses,OverAll,NotCovered,Covered,CoverageLevel):-
 	partial(metaLP(LP),"processJoinTestCase"), 
  	coverage(
  		[a(1,1),a(2,2)],
  		LP,	 						
  		CoveredClauses,
  		NotCoveredClauses,	
  		CoverageLevel),
  		size(LP,OverAll),
  		size(NotCoveredClauses,NotCovered),
  		size(CoveredClauses,Covered).
