definition module iTasks.Testing.Unit

from Data.Either import :: Either
from Data.GenDefault import generic gDefault
from Data.GenEq import generic gEq
from Testing.TestEvents import :: EndEventType
from Text.GenJSON import :: JSONNode, generic JSONEncode, generic JSONDecode
from Text.GenPrint import :: PrintState, class PrintOutput, generic gPrint

from iTasks.Internal.Generic.Visualization import :: TextFormat, generic gText
from iTasks.Internal.TaskIO import :: TaskOutputMessage
from iTasks.UI.Editor import :: Editor, :: EditorReport
from iTasks.UI.Editor.Generic import generic gEditor, :: EditorPurpose
from iTasks.WF.Definition import :: Event, :: Task, class iTask

:: UnitTest =
	{ name :: !String
	, test :: !*World -> *(EndEventType,*World)
	}

derive JSONEncode UnitTest
derive JSONDecode UnitTest
derive gEq UnitTest
derive gEditor UnitTest
derive gText UnitTest
derive gDefault UnitTest

assert :: !String !(a -> Bool) a -> UnitTest

assertEqual :: !String a a -> UnitTest | gEq{|*|} a & gPrint{|*|} a

assertWorld :: !String !(a -> Bool) !(*World -> *(a,*World)) -> UnitTest

assertEqualWorld :: !String !a !(*World -> *(a,*World)) -> UnitTest | gEq{|*|} a & gPrint{|*|} a

checkEqual :: !a !a -> EndEventType | gEq{|*|} a & gPrint{|*|} a
checkEqualWith :: !(a a -> Bool) a a -> EndEventType | gPrint{|*|} a

pass :: !String -> UnitTest

fail :: !String -> UnitTest

skip :: !UnitTest -> UnitTest

/**
 * Create a task instance, evaluate it, and verify its output.
 *
 * @param A name for the test case.
 * @param The task.
 * @param A list of input events. `Right` is used to indicate time in seconds
 *   between events.
 * @param The expected output messages.
 * @param A function to check the expected output messages (e.g. `checkEqual`).
 */
testTaskOutput :: !String !(Task a) ![Either Event Int] ![TaskOutputMessage] !([TaskOutputMessage] [TaskOutputMessage] -> EndEventType) -> UnitTest | iTask a

/**
 * Create a task instance, evaluate it, and verify the result value.
 * The task is evaluated until it reaches a stable value. If it throws an
 * exception, the test fails.
 *
 * @param A name for the test case.
 * @param The task.
 * @param A list of input events. `Right` is used to indicate time in seconds
 *   between events.
 * @param The expected result.
 * @param A function to check the result (e.g. `checkEqual`).
 */
testTaskResult :: !String !(Task a) ![Either Event Int] a !(a a -> EndEventType) -> UnitTest | iTask a

//* Filter test suites based on the name of a test.
filterTestsByName :: !String ![UnitTest] -> [UnitTest]

//* Runs the unit tests from the test suites and prints test results to stdout.
runUnitTests :: ![UnitTest] !*World -> *World
