Current section
Files
Jump to
Current section
Files
src/testbldr.erl
-module(testbldr).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([named/2, include_passing_tests_in_output/2, output_results_to_file/2, output_results_to_stdout/1, display_test_outcome_using/2, display_ratio_using/2, run/2, test_runner_default/0]).
-export_type([test/0, test_outcome/0, test_runner/0, verbosity/0, output_destination/0, test_stats/0]).
-type test() :: {test, binary(), fun(() -> test_outcome())}.
-type test_outcome() :: pass | {fail, binary()}.
-opaque test_runner() :: {test_runner,
verbosity(),
gleam@set:set(output_destination()),
gleam@option:option(fun((binary(), test_outcome()) -> binary())),
gleam@option:option(fun((integer(), integer()) -> binary()))}.
-type verbosity() :: normal | verbose.
-type output_destination() :: stdout | {file, binary()}.
-type test_stats() :: {test_stats,
integer(),
integer(),
integer(),
integer(),
list({binary(), test_outcome()})}.
-spec named(binary(), fun(() -> test_outcome())) -> test().
named(Name, New_test) ->
{test, Name, New_test}.
-spec include_passing_tests_in_output(test_runner(), boolean()) -> test_runner().
include_passing_tests_in_output(Runner, Input) ->
Verbosity = case Input of
true ->
verbose;
false ->
normal
end,
erlang:setelement(2, Runner, Verbosity).
-spec output_results_to_file(test_runner(), binary()) -> test_runner().
output_results_to_file(Runner, Path) ->
erlang:setelement(
3,
Runner,
gleam@set:insert(erlang:element(3, Runner), {file, Path})
).
-spec output_results_to_stdout(test_runner()) -> test_runner().
output_results_to_stdout(Runner) ->
erlang:setelement(
3,
Runner,
gleam@set:insert(erlang:element(3, Runner), stdout)
).
-spec display_test_outcome_using(
test_runner(),
fun((binary(), test_outcome()) -> binary())
) -> test_runner().
display_test_outcome_using(Runner, Printer) ->
erlang:setelement(4, Runner, {some, Printer}).
-spec display_ratio_using(
test_runner(),
fun((integer(), integer()) -> binary())
) -> test_runner().
display_ratio_using(Runner, Printer) ->
erlang:setelement(5, Runner, {some, Printer}).
-spec write_stats_to_file(test_runner(), test_stats(), binary()) -> {ok, nil} |
{error, simplifile:file_error()}.
write_stats_to_file(Runner, Stats, Path) ->
Individual = (gleam@list:fold(
erlang:element(6, Stats),
<<""/utf8>>,
fun(Acc, _use1) ->
{Name, Outcome} = _use1,
case erlang:element(4, Runner) of
{some, Printer} ->
<<<<Acc/binary, (Printer(Name, Outcome))/binary>>/binary,
"\n"/utf8>>;
none ->
Acc
end
end
)),
Ratio = case erlang:element(5, Runner) of
{some, Printer@1} ->
Printer@1(erlang:element(3, Stats), erlang:element(2, Stats));
none ->
<<""/utf8>>
end,
simplifile:write(
Path,
<<<<Individual/binary, "\n"/utf8>>/binary, Ratio/binary>>
).
-spec write_stats_to_stdout(test_runner(), test_stats()) -> nil.
write_stats_to_stdout(Runner, Stats) ->
(gleam@list:each(
erlang:element(6, Stats),
fun(_use0) ->
{Name, Outcome} = _use0,
case erlang:element(4, Runner) of
{some, Printer} ->
_pipe = Printer(Name, Outcome),
gleam@io:println(_pipe);
none ->
nil
end
end
)),
gleam@io:println(<<""/utf8>>),
case erlang:element(5, Runner) of
{some, Printer@1} ->
_pipe@1 = Printer@1(
erlang:element(3, Stats),
erlang:element(2, Stats)
),
gleam@io:println(_pipe@1);
none ->
nil
end.
-spec run(test_runner(), list(test())) -> nil.
run(Runner, Tests) ->
Test_stats = (gleam@list:fold(
Tests,
{test_stats, 0, 0, 0, 0, []},
fun(Acc, _use1) ->
{test, Name, Test_function} = _use1,
case gleam_erlang_ffi:rescue(Test_function) of
{ok, pass} ->
{test_stats,
erlang:element(2, Acc) + 1,
erlang:element(3, Acc) + 1,
erlang:element(4, Acc),
erlang:element(5, Acc),
[{Name, pass} | erlang:element(6, Acc)]};
{ok, {fail, Msg}} ->
{test_stats,
erlang:element(2, Acc) + 1,
erlang:element(3, Acc),
erlang:element(4, Acc) + 1,
erlang:element(5, Acc),
[{Name, {fail, Msg}} | erlang:element(6, Acc)]};
{error, _} ->
{test_stats,
erlang:element(2, Acc) + 1,
erlang:element(3, Acc),
erlang:element(4, Acc),
erlang:element(5, Acc) + 1,
[{Name, {fail, <<"Test Panicked!"/utf8>>}} |
erlang:element(6, Acc)]}
end
end
)),
Filter = case erlang:element(2, Runner) of
normal ->
fun(X) -> case erlang:element(2, X) of
pass ->
false;
{fail, _} ->
true
end end;
verbose ->
fun(_) -> true end
end,
Filtered_stats = erlang:setelement(
6,
Test_stats,
gleam@list:filter(erlang:element(6, Test_stats), Filter)
),
(gleam@list:each(
gleam@set:to_list(erlang:element(3, Runner)),
fun(Dest) -> case Dest of
stdout ->
write_stats_to_stdout(Runner, Filtered_stats);
{file, Path} ->
_assert_subject = write_stats_to_file(
Runner,
Filtered_stats,
Path
),
{ok, _} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"testbldr"/utf8>>,
function => <<"run"/utf8>>,
line => 172})
end,
nil
end end
)).
-spec outcome_to_string(binary(), test_outcome()) -> binary().
outcome_to_string(Name, Outcome) ->
case Outcome of
pass ->
<<"✅ "/utf8, Name/binary>>;
{fail, Msg} ->
<<<<<<<<"❌ "/utf8, Name/binary>>/binary, ": Failed ("/utf8>>/binary,
Msg/binary>>/binary,
")"/utf8>>
end.
-spec ratio_to_string(integer(), integer()) -> binary().
ratio_to_string(Passed, Total) ->
Prefix_emoji = case Passed =:= Total of
true ->
<<"✅"/utf8>>;
false ->
<<"❌"/utf8>>
end,
<<<<<<<<<<Prefix_emoji/binary, " "/utf8>>/binary,
(gleam@int:to_string(Passed))/binary>>/binary,
"/"/utf8>>/binary,
(gleam@int:to_string(Total))/binary>>/binary,
" tests passed"/utf8>>.
-spec test_runner_default() -> test_runner().
test_runner_default() ->
{test_runner,
normal,
gleam@set:from_list([stdout]),
{some, fun outcome_to_string/2},
{some, fun ratio_to_string/2}}.