-module(erunit). -export([assert/2, assertEquals/2, assertEquals/3, test/2, run/1, fail/1]). test(Name, F) -> fun() -> Pid = spawn(test_process(Name, F, self())), receive {Pid, Message} -> Message end end. test_process(Name, F, P) -> fun() -> try F() of _ -> P ! {self(), {ok, Name}} catch throw:{assertionFailed, AssertionName} -> P ! {self(), {fail, {Name, AssertionName}}}; _:Type -> P ! {self(), {error, {Name, catch erlang:error(Type)}}} end end. assert(Name, Test) -> case Test of true -> {ok, Name}; _ -> fail(Name) end. assertEquals(Expected, Actual) -> Message = io_lib:format("Expected \"~p\". Got \"~p\"", [Expected, Actual]), if Expected == Actual -> {ok, Message}; true -> throw({assertionFailed, Message}) end. assertEquals(Name, A, B) -> if A == B -> {ok, Name}; true -> fail(Name) end. run(Test) when is_function(Test, 0) -> run([Test]); run(L) when is_list(L) -> run(L, ok, ""). run([], Answer, Output) -> io:format("~n~s", [Output]), Answer; run([{Module, Tests}|Rest], Answer, Output) when is_list(Tests) -> case length(Output) > 0 of true -> io:format("~n~s", [Output]); false -> ignore end, io:format("~n~p:~n\t", [Module]), run(Tests ++ Rest, Answer, ""); run([Test|Rest], Answer, Output) when is_function(Test, 0) -> case Test() of {ok, _} -> io:format("."), run(Rest, Answer, Output); {fail, {Name, Message}} -> io:format("F"), NextOutput = io_lib:format("-~p failed:~n\t~s~n", [Name, Message]), run(Rest, fail, string:concat(Output, NextOutput)); {error, {Name, Stacktrace}} -> io:format("E"), {'EXIT', {Type, [Method|_]}} = Stacktrace, NextOutput = io_lib:format("-~p had error:~n\terror:~s~n\t\t~p~n", [Name, Type, Method]), run(Rest, fail, string:concat(Output, NextOutput)) end. fail(Name) -> throw({assertionFailed, Name}).