Current section
Files
Jump to
Current section
Files
src/metamon@internal@runner.erl
-module(metamon@internal@runner).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/metamon/internal/runner.gleam").
-export([plain/3, equivariant/4, morph_name/1, run_assert_morph/4, run_forall_morph_n/6, run_forall_morphs/5, run_forall/4, run_forall_morph/5]).
-export_type([morph_spec/2, step/1, outcome/0, evaluation/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-opaque morph_spec(GLF, GLG) :: {plain_spec,
binary(),
metamon@transform:transform(GLF),
metamon@relation:relation(GLG)} |
{equivariant_spec,
binary(),
metamon@transform:transform(GLF),
metamon@transform:transform(GLG),
metamon@relation:relation(GLG)}.
-type step(GLH) :: continue | {stop, binary()} | {gleam_phantom, GLH}.
-type outcome() :: done | {halted, binary()}.
-type evaluation(GLI) :: {evaluation, binary(), GLI, GLI, boolean()}.
-file("src/metamon/internal/runner.gleam", 48).
?DOC(false).
-spec plain(
binary(),
metamon@transform:transform(GLJ),
metamon@relation:relation(GLL)
) -> morph_spec(GLJ, GLL).
plain(Name, Transform, Relation) ->
{plain_spec, Name, Transform, Relation}.
-file("src/metamon/internal/runner.gleam", 58).
?DOC(false).
-spec equivariant(
binary(),
metamon@transform:transform(GLP),
metamon@transform:transform(GLR),
metamon@relation:relation(GLR)
) -> morph_spec(GLP, GLR).
equivariant(Name, Input_transform, Output_transform, Relation) ->
{equivariant_spec, Name, Input_transform, Output_transform, Relation}.
-file("src/metamon/internal/runner.gleam", 216).
?DOC(false).
-spec render_for(
metamon@config:config(),
metamon@internal@report:failure_report()
) -> binary().
render_for(Cfg, Report) ->
case metamon@config:output_format(Cfg) of
text ->
metamon@internal@report:render(Report);
json ->
metamon@internal@report:render_json(Report)
end.
-file("src/metamon/internal/runner.gleam", 259).
?DOC(false).
-spec compute_n_outputs(
list(metamon@transform:transform(GNH)),
fun((GNH) -> GNK),
GNH
) -> list(GNK).
compute_n_outputs(Transforms, F, Input) ->
Source_output = F(Input),
Followups = gleam@list:map(
Transforms,
fun(T) -> F((erlang:element(3, T))(Input)) end
),
[Source_output | Followups].
-file("src/metamon/internal/runner.gleam", 270).
?DOC(false).
-spec morph_n_failure(
metamon@config:config(),
binary(),
list(metamon@transform:transform(GNM)),
metamon@relation:relation_n(GNP),
integer(),
GNM,
metamon@internal@report:input_source(),
list(GNP)
) -> binary().
morph_n_failure(
Cfg,
Test_name,
Transforms,
Rel,
Run_index,
Input,
Source,
Outputs
) ->
Transform_names = begin
_pipe = gleam@list:map(Transforms, fun(T) -> erlang:element(2, T) end),
gleam@string:join(_pipe, <<", "/utf8>>)
end,
Outputs_rendered = begin
_pipe@1 = gleam@list:index_map(
Outputs,
fun(Out, I) ->
<<<<<<" ["/utf8, (erlang:integer_to_binary(I))/binary>>/binary,
"] "/utf8>>/binary,
(gleam@string:inspect(Out))/binary>>
end
),
gleam@string:join(_pipe@1, <<"\n"/utf8>>)
end,
erlang:list_to_binary(
[<<"× n-ary metamorphic relation `"/utf8>>,
erlang:element(2, Rel),
<<"` failed\n test: "/utf8>>,
Test_name,
<<"\n config seed: "/utf8>>,
erlang:integer_to_binary(
metamon@generator@seed:state(metamon@config:seed(Cfg))
),
<<"\n runs: "/utf8>>,
erlang:integer_to_binary(Run_index),
<<" / "/utf8>>,
erlang:integer_to_binary(metamon@config:runs(Cfg)),
<<"\n source: "/utf8>>,
case Source of
{edge_source, I@1} ->
<<<<"edge("/utf8, (erlang:integer_to_binary(I@1))/binary>>/binary,
")"/utf8>>;
{random_source, S, Sz} ->
<<<<<<<<"random(seed="/utf8,
(erlang:integer_to_binary(S))/binary>>/binary,
", size="/utf8>>/binary,
(erlang:integer_to_binary(Sz))/binary>>/binary,
")"/utf8>>
end,
<<"\n transforms: "/utf8>>,
Transform_names,
<<"\n source input:\n "/utf8>>,
gleam@string:inspect(Input),
<<"\n outputs (source first, then each follow-up):\n"/utf8>>,
Outputs_rendered]
).
-file("src/metamon/internal/runner.gleam", 398).
?DOC(false).
-spec run_edges(
list(GOB),
integer(),
fun((GOB, metamon@internal@report:input_source(), integer()) -> step(GOB))
) -> outcome().
run_edges(Edges, Index, Body) ->
case Edges of
[] ->
done;
[First | Rest] ->
case Body(First, {edge_source, Index}, Index) of
continue ->
run_edges(Rest, Index + 1, Body);
{stop, Text} ->
{halted, Text}
end
end.
-file("src/metamon/internal/runner.gleam", 439).
?DOC(false).
-spec scaled_size(integer(), integer(), integer()) -> integer().
scaled_size(Index, Total, Max_size) ->
case Total =< 1 of
true ->
Max_size;
false ->
case (Total - 1) of
0 -> 0;
Gleam@denominator -> Index * Max_size div Gleam@denominator
end
end.
-file("src/metamon/internal/runner.gleam", 413).
?DOC(false).
-spec run_random(
metamon@config:config(),
metamon@generator:generator(GOE),
integer(),
integer(),
metamon@generator@seed:seed(),
fun((GOE, metamon@internal@report:input_source(), integer()) -> step(GOE))
) -> outcome().
run_random(Cfg, Gen, Start_index, Remaining, S, Body) ->
case Remaining =< 0 of
true ->
done;
false ->
{Here, Rest_seed} = metamon@generator@seed:split(S),
Size = scaled_size(
Start_index,
metamon@config:runs(Cfg),
metamon@config:max_size(Cfg)
),
Value = erlang:element(
2,
metamon@generator:generate(Gen, Here, Size)
),
case Body(
Value,
{random_source, metamon@generator@seed:state(Here), Size},
Start_index
) of
continue ->
run_random(
Cfg,
Gen,
Start_index + 1,
Remaining - 1,
Rest_seed,
Body
);
{stop, Text} ->
{halted, Text}
end
end.
-file("src/metamon/internal/runner.gleam", 448).
?DOC(false).
-spec forall_failure(
metamon@config:config(),
binary(),
metamon@generator:generator(GOH),
fun((GOH) -> boolean()),
integer(),
GOH,
metamon@internal@report:input_source()
) -> binary().
forall_failure(Cfg, Test_name, _, _, Run_index, Input, Source) ->
Report = {failure_report,
<<"(plain property)"/utf8>>,
Test_name,
metamon@generator@seed:state(metamon@config:seed(Cfg)),
Run_index,
metamon@config:runs(Cfg),
0,
false,
none,
<<""/utf8>>,
gleam@string:inspect(Input),
<<""/utf8>>,
<<""/utf8>>,
<<""/utf8>>,
Source,
false,
metamon@annotate:current_annotations(),
metamon@annotate:current_footnotes(),
{some, metamon@coverage:snapshot()}},
render_for(Cfg, Report).
-file("src/metamon/internal/runner.gleam", 485).
?DOC(false).
-spec evaluate_spec(morph_spec(GOJ, GOK), fun((GOJ) -> GOK), GOJ) -> evaluation(GOK).
evaluate_spec(Spec, F, Input) ->
case Spec of
{plain_spec, _, T, R} ->
Fol_in = (erlang:element(3, T))(Input),
Src_out = F(Input),
Fol_out = F(Fol_in),
{evaluation,
gleam@string:inspect(Fol_in),
Src_out,
Fol_out,
(erlang:element(3, R))(Src_out, Fol_out)};
{equivariant_spec, _, Ti, To, R@1} ->
Fol_in@1 = (erlang:element(3, Ti))(Input),
Raw_src_out = F(Input),
Src_out@1 = (erlang:element(3, To))(Raw_src_out),
Fol_out@1 = F(Fol_in@1),
{evaluation,
gleam@string:inspect(Fol_in@1),
Src_out@1,
Fol_out@1,
(erlang:element(3, R@1))(Src_out@1, Fol_out@1)}
end.
-file("src/metamon/internal/runner.gleam", 517).
?DOC(false).
-spec morph_mode_of(morph_spec(any(), any())) -> metamon@internal@report:morph_mode().
morph_mode_of(Spec) ->
case Spec of
{plain_spec, _, T, _} ->
{plain, erlang:element(2, T)};
{equivariant_spec, _, Ti, To, _} ->
{equivariant, erlang:element(2, Ti), erlang:element(2, To)}
end.
-file("src/metamon/internal/runner.gleam", 525).
?DOC(false).
-spec relation_name_of(morph_spec(any(), any())) -> binary().
relation_name_of(Spec) ->
case Spec of
{plain_spec, _, _, R} ->
erlang:element(2, R);
{equivariant_spec, _, _, _, R@1} ->
erlang:element(2, R@1)
end.
-file("src/metamon/internal/runner.gleam", 532).
?DOC(false).
-spec spec_name(morph_spec(any(), any())) -> binary().
spec_name(Spec) ->
case Spec of
{plain_spec, Name, _, _} ->
Name;
{equivariant_spec, Name@1, _, _, _} ->
Name@1
end.
-file("src/metamon/internal/runner.gleam", 73).
?DOC(false).
-spec morph_name(morph_spec(any(), any())) -> binary().
morph_name(Spec) ->
spec_name(Spec).
-file("src/metamon/internal/runner.gleam", 581).
?DOC(false).
-spec morph_failure_static(
binary(),
morph_spec(GPG, GPH),
GPG,
evaluation(GPH),
integer(),
integer()
) -> metamon@internal@report:failure_report().
morph_failure_static(
Test_name,
Spec,
Input,
Evaluation,
Run_index,
Config_seed_value
) ->
{failure_report,
spec_name(Spec),
Test_name,
Config_seed_value,
Run_index,
1,
0,
false,
{some, morph_mode_of(Spec)},
relation_name_of(Spec),
gleam@string:inspect(Input),
erlang:element(2, Evaluation),
gleam@string:inspect(erlang:element(3, Evaluation)),
gleam@string:inspect(erlang:element(4, Evaluation)),
{edge_source, 0},
true,
metamon@annotate:current_annotations(),
metamon@annotate:current_footnotes(),
none}.
-file("src/metamon/internal/runner.gleam", 631).
?DOC(false).
-spec shrink_loop(
metamon@generator@tree:tree(GPQ),
morph_spec(GPQ, GPS),
fun((GPQ) -> GPS),
GPQ,
integer(),
integer()
) -> {GPQ, integer(), boolean()}.
shrink_loop(Current_tree, Spec, F, Best, Budget, Done) ->
case Done >= Budget of
true ->
{Best, Done, true};
false ->
case metamon@generator@tree:shrinks_find(
erlang:element(3, Current_tree),
fun(Child) ->
Evaluation = evaluate_spec(
Spec,
F,
erlang:element(2, Child)
),
not erlang:element(5, Evaluation)
end
) of
{error, _} ->
{Best, Done, false};
{ok, Child@1} ->
shrink_loop(
Child@1,
Spec,
F,
erlang:element(2, Child@1),
Budget,
Done + 1
)
end
end.
-file("src/metamon/internal/runner.gleam", 613).
?DOC(false).
-spec shrink_morph_input(
metamon@config:config(),
metamon@generator:generator(GPL),
morph_spec(GPL, GPN),
fun((GPL) -> GPN),
GPL,
metamon@internal@report:input_source()
) -> {GPL, integer(), boolean()}.
shrink_morph_input(Cfg, Gen, Spec, F, Current, Source) ->
case Source of
{edge_source, _} ->
{Current, 0, false};
{random_source, Seed_value, Size} ->
Initial_tree = metamon@generator:generate(
Gen,
metamon@generator@seed:seed(Seed_value),
Size
),
shrink_loop(
Initial_tree,
Spec,
F,
Current,
metamon@config:shrink_limit(Cfg),
0
)
end.
-file("src/metamon/internal/runner.gleam", 539).
?DOC(false).
-spec morph_failure(
metamon@config:config(),
binary(),
metamon@generator:generator(GPA),
morph_spec(GPA, GPC),
fun((GPA) -> GPC),
integer(),
GPA,
metamon@internal@report:input_source(),
evaluation(GPC)
) -> binary().
morph_failure(
Cfg,
Test_name,
Gen,
Spec,
F,
Run_index,
Input,
Source,
Evaluation
) ->
{Shrunk_input, Shrinks_count, Capped} = shrink_morph_input(
Cfg,
Gen,
Spec,
F,
Input,
Source
),
Final_eval = evaluate_spec(Spec, F, Shrunk_input),
Report = {failure_report,
spec_name(Spec),
Test_name,
metamon@generator@seed:state(metamon@config:seed(Cfg)),
Run_index,
metamon@config:runs(Cfg),
Shrinks_count,
Capped,
{some, morph_mode_of(Spec)},
relation_name_of(Spec),
gleam@string:inspect(Shrunk_input),
erlang:element(2, Final_eval),
gleam@string:inspect(erlang:element(3, Final_eval)),
gleam@string:inspect(erlang:element(4, Final_eval)),
Source,
metamon@config:diff_enabled(Cfg),
metamon@annotate:current_annotations(),
metamon@annotate:current_footnotes(),
{some, metamon@coverage:snapshot()}},
_ = Evaluation,
render_for(Cfg, Report).
-file("src/metamon/internal/runner.gleam", 656).
?DOC(false).
-spec reset_state() -> nil.
reset_state() ->
metamon@annotate:reset(),
metamon@coverage:reset().
-file("src/metamon/internal/runner.gleam", 693).
?DOC(false).
-spec panic_with(binary()) -> nil.
panic_with(Message) ->
erlang:error(#{gleam_error => panic,
message => Message,
file => <<?FILEPATH/utf8>>,
module => <<"metamon/internal/runner"/utf8>>,
function => <<"panic_with"/utf8>>,
line => 694}).
-file("src/metamon/internal/runner.gleam", 198).
?DOC(false).
-spec run_assert_morph(binary(), morph_spec(GMX, GMY), fun((GMX) -> GMY), GMX) -> nil.
run_assert_morph(Test_name, Spec, F, Input) ->
reset_state(),
Evaluation = evaluate_spec(Spec, F, Input),
case erlang:element(5, Evaluation) of
true ->
nil;
false ->
Report = morph_failure_static(
Test_name,
Spec,
Input,
Evaluation,
0,
0
),
panic_with(render_for(metamon@config:default_config(), Report))
end.
-file("src/metamon/internal/runner.gleam", 661).
?DOC(false).
-spec finish_with_coverage_check(
metamon@config:config(),
binary(),
gleam@option:option(binary())
) -> nil.
finish_with_coverage_check(_, Test_name, Morph_name) ->
Snap = metamon@coverage:snapshot(),
case metamon@coverage:first_shortfall(Snap) of
none ->
nil;
{some, Req} ->
Prefix = case Morph_name of
none ->
<<<<"× property `"/utf8, Test_name/binary>>/binary,
"`"/utf8>>;
{some, Name} ->
<<<<<<<<"× metamorphic relation `"/utf8, Name/binary>>/binary,
"` ("/utf8>>/binary,
Test_name/binary>>/binary,
")"/utf8>>
end,
Message = <<<<<<<<<<<<<<<<<<<<<<Prefix/binary,
" passed but coverage shortfall: label `"/utf8>>/binary,
(erlang:element(2, Req))/binary>>/binary,
"` hit "/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(4, Req)
))/binary>>/binary,
"/"/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(2, Snap)
))/binary>>/binary,
" ("/utf8>>/binary,
(gleam_stdlib:float_to_string(
metamon@coverage:actual_pct(
erlang:element(4, Req),
erlang:element(2, Snap)
)
))/binary>>/binary,
"%, target≥"/utf8>>/binary,
(gleam_stdlib:float_to_string(
metamon@coverage:target_pct_of(
Req,
erlang:element(2, Snap)
)
))/binary>>/binary,
"%)"/utf8>>,
panic_with(Message)
end.
-file("src/metamon/internal/runner.gleam", 697).
?DOC(false).
-spec take_first(list(GPW), integer()) -> list(GPW).
take_first(Items, N) ->
case {N, Items} of
{N@1, _} when N@1 =< 0 ->
[];
{_, []} ->
[];
{N@2, [First | Rest]} ->
[First | take_first(Rest, N@2 - 1)]
end.
-file("src/metamon/internal/runner.gleam", 377).
?DOC(false).
-spec iterate_inputs(
metamon@config:config(),
metamon@generator:generator(GNY),
fun((GNY, metamon@internal@report:input_source(), integer()) -> step(GNY))
) -> outcome().
iterate_inputs(Cfg, Gen, Body) ->
Edges = begin
_pipe = metamon@generator:edges_of(Gen),
take_first(_pipe, metamon@config:max_edges(Cfg))
end,
Edge_count = erlang:length(Edges),
Run_total = metamon@config:runs(Cfg),
case run_edges(Edges, 0, Body) of
{halted, Text} ->
{halted, Text};
done ->
Remaining = Run_total - Edge_count,
case Remaining =< 0 of
true ->
done;
false ->
run_random(
Cfg,
Gen,
Edge_count,
Remaining,
metamon@config:seed(Cfg),
Body
)
end
end.
-file("src/metamon/internal/runner.gleam", 226).
?DOC(false).
-spec run_forall_morph_n(
metamon@config:config(),
binary(),
metamon@generator:generator(GNB),
list(metamon@transform:transform(GNB)),
metamon@relation:relation_n(GNF),
fun((GNB) -> GNF)
) -> nil.
run_forall_morph_n(Cfg, Test_name, Gen, Transforms, Rel, F) ->
reset_state(),
case iterate_inputs(
Cfg,
Gen,
fun(Input, Source, Run_index) ->
Outputs = compute_n_outputs(Transforms, F, Input),
case (erlang:element(3, Rel))(Outputs) of
true ->
continue;
false ->
{stop,
morph_n_failure(
Cfg,
Test_name,
Transforms,
Rel,
Run_index,
Input,
Source,
Outputs
)}
end
end
) of
done ->
finish_with_coverage_check(
Cfg,
Test_name,
{some, erlang:element(2, Rel)}
);
{halted, Text} ->
panic_with(Text)
end.
-file("src/metamon/internal/runner.gleam", 321).
?DOC(false).
-spec run_forall_morphs(
metamon@config:config(),
binary(),
metamon@generator:generator(GNS),
list(morph_spec(GNS, GNU)),
fun((GNS) -> GNU)
) -> nil.
run_forall_morphs(Cfg, Test_name, Gen, Specs, F) ->
Collected = gleam@list:fold(
Specs,
[],
fun(Reports, Spec) ->
reset_state(),
Outcome = iterate_inputs(
Cfg,
Gen,
fun(Input, Source, Run_index) ->
Evaluation = evaluate_spec(Spec, F, Input),
case erlang:element(5, Evaluation) of
true ->
continue;
false ->
{stop,
morph_failure(
Cfg,
Test_name,
Gen,
Spec,
F,
Run_index,
Input,
Source,
Evaluation
)}
end
end
),
case Outcome of
done ->
Reports;
{halted, Text} ->
[Text | Reports]
end
end
),
case Collected of
[] ->
nil;
Failures ->
panic_with(
<<"× one or more metamorphic relations failed\n\n"/utf8,
(gleam@string:join(
lists:reverse(Failures),
<<"\n\n---\n\n"/utf8>>
))/binary>>
)
end.
-file("src/metamon/internal/runner.gleam", 707).
?DOC(false).
-spec load_regression_for(metamon@config:config(), binary()) -> list(metamon@internal@regression:entry()).
load_regression_for(Cfg, Mr_name) ->
case metamon@config:regression_file(Cfg) of
none ->
[];
{some, Path} ->
case simplifile:read(Path) of
{ok, Content} ->
_pipe = metamon@internal@regression:parse(Content),
gleam@list:filter(
_pipe,
fun(Entry) -> erlang:element(2, Entry) =:= Mr_name end
);
{error, _} ->
[]
end
end.
-file("src/metamon/internal/runner.gleam", 830).
?DOC(false).
-spec list_at(list(GQM), integer()) -> gleam@option:option(GQM).
list_at(Items, Index) ->
case {Items, Index} of
{[], _} ->
none;
{[First | _], 0} ->
{some, First};
{[_ | Rest], I} ->
list_at(Rest, I - 1)
end.
-file("src/metamon/internal/runner.gleam", 808).
?DOC(false).
-spec reproduce_entry_value(
metamon@generator:generator(GQK),
metamon@internal@regression:entry()
) -> GQK.
reproduce_entry_value(Gen, Entry) ->
case erlang:element(6, Entry) of
{some, I} ->
case list_at(metamon@generator:edges_of(Gen), I) of
{some, Value} ->
Value;
none ->
erlang:element(
2,
metamon@generator:generate(
Gen,
metamon@generator@seed:seed(
erlang:element(3, Entry)
),
erlang:element(5, Entry)
)
)
end;
none ->
erlang:element(
2,
metamon@generator:generate(
Gen,
metamon@generator@seed:seed(erlang:element(3, Entry)),
erlang:element(5, Entry)
)
)
end.
-file("src/metamon/internal/runner.gleam", 838).
?DOC(false).
-spec replay_failure_message(
binary(),
metamon@internal@regression:entry(),
any()
) -> binary().
replay_failure_message(Mr_name, Entry, Value) ->
erlang:list_to_binary(
[<<"× regression replay for `"/utf8>>,
Mr_name,
<<"` failed\n recorded: "/utf8>>,
erlang:element(8, Entry),
<<"\n config_seed: "/utf8>>,
erlang:integer_to_binary(erlang:element(3, Entry)),
<<"\n run_index: "/utf8>>,
erlang:integer_to_binary(erlang:element(4, Entry)),
<<"\n size: "/utf8>>,
erlang:integer_to_binary(erlang:element(5, Entry)),
<<"\n reproduced input:\n "/utf8>>,
gleam@string:inspect(Value),
case erlang:element(7, Entry) of
{some, N} ->
<<"\n note:\n "/utf8, N/binary>>;
none ->
<<""/utf8>>
end]
).
-file("src/metamon/internal/runner.gleam", 771).
?DOC(false).
-spec replay_regression_for_forall(
metamon@generator:generator(GQB),
list(metamon@internal@regression:entry()),
fun((GQB) -> boolean())
) -> outcome().
replay_regression_for_forall(Gen, Entries, Property) ->
case Entries of
[] ->
done;
[Entry | Rest] ->
Value = reproduce_entry_value(Gen, Entry),
case Property(Value) of
true ->
replay_regression_for_forall(Gen, Rest, Property);
false ->
{halted,
replay_failure_message(
<<"(plain property)"/utf8>>,
Entry,
Value
)}
end
end.
-file("src/metamon/internal/runner.gleam", 789).
?DOC(false).
-spec replay_regression_for_morph(
metamon@generator:generator(GQE),
morph_spec(GQE, GQG),
fun((GQE) -> GQG),
list(metamon@internal@regression:entry())
) -> outcome().
replay_regression_for_morph(Gen, Spec, F, Entries) ->
case Entries of
[] ->
done;
[Entry | Rest] ->
Value = reproduce_entry_value(Gen, Entry),
Evaluation = evaluate_spec(Spec, F, Value),
case erlang:element(5, Evaluation) of
true ->
replay_regression_for_morph(Gen, Spec, F, Rest);
false ->
{halted,
replay_failure_message(spec_name(Spec), Entry, Value)}
end
end.
-file("src/metamon/internal/runner.gleam", 722).
?DOC(false).
-spec record_regression_for(
metamon@config:config(),
binary(),
metamon@internal@report:input_source(),
any()
) -> nil.
record_regression_for(Cfg, Mr_name, Source, Input) ->
case metamon@config:regression_file(Cfg) of
none ->
nil;
{some, Path} ->
Edge_index = case Source of
{edge_source, I} ->
{some, I};
{random_source, _, _} ->
none
end,
{Seed_value, Size} = case Source of
{edge_source, _} ->
{metamon@generator@seed:state(metamon@config:seed(Cfg)), 0};
{random_source, S, Sz} ->
{S, Sz}
end,
Run_index = case Source of
{edge_source, I@1} ->
I@1;
{random_source, _, _} ->
0
end,
Entry = {entry,
Mr_name,
Seed_value,
Run_index,
Size,
Edge_index,
{some, gleam@string:inspect(Input)},
erlang:integer_to_binary(metamon_ffi:now_microseconds())},
Existing = case simplifile:read(Path) of
{ok, C} ->
C;
{error, _} ->
<<""/utf8>>
end,
Separator = case Existing of
<<""/utf8>> ->
<<""/utf8>>;
_ ->
<<"\n"/utf8>>
end,
_ = simplifile:write(
Path,
<<<<Existing/binary, Separator/binary>>/binary,
(metamon@internal@regression:render(Entry))/binary>>
),
nil
end.
-file("src/metamon/internal/runner.gleam", 108).
?DOC(false).
-spec forall_step(
metamon@config:config(),
binary(),
metamon@generator:generator(GME),
fun((GME) -> boolean()),
GME,
metamon@internal@report:input_source(),
integer()
) -> step(GME).
forall_step(Cfg, Test_name, Gen, Property, Input, Source, Run_index) ->
case Property(Input) of
true ->
continue;
false ->
record_regression_for(
Cfg,
<<"(plain property)"/utf8>>,
Source,
Input
),
{stop,
forall_failure(
Cfg,
Test_name,
Gen,
Property,
Run_index,
Input,
Source
)}
end.
-file("src/metamon/internal/runner.gleam", 92).
?DOC(false).
-spec drive_forall(
metamon@config:config(),
binary(),
metamon@generator:generator(GMC),
fun((GMC) -> boolean())
) -> nil.
drive_forall(Cfg, Test_name, Gen, Property) ->
Outcome = iterate_inputs(
Cfg,
Gen,
fun(Input, Source, Run_index) ->
forall_step(Cfg, Test_name, Gen, Property, Input, Source, Run_index)
end
),
case Outcome of
done ->
finish_with_coverage_check(Cfg, Test_name, none);
{halted, Report_text} ->
panic_with(Report_text)
end.
-file("src/metamon/internal/runner.gleam", 78).
?DOC(false).
-spec run_forall(
metamon@config:config(),
binary(),
metamon@generator:generator(GMA),
fun((GMA) -> boolean())
) -> nil.
run_forall(Cfg, Test_name, Gen, Property) ->
reset_state(),
Regression_entries = load_regression_for(Cfg, <<"(plain property)"/utf8>>),
case replay_regression_for_forall(Gen, Regression_entries, Property) of
{halted, Text} ->
panic_with(Text);
done ->
drive_forall(Cfg, Test_name, Gen, Property)
end.
-file("src/metamon/internal/runner.gleam", 167).
?DOC(false).
-spec morph_step(
metamon@config:config(),
binary(),
metamon@generator:generator(GMR),
morph_spec(GMR, GMT),
fun((GMR) -> GMT),
GMR,
metamon@internal@report:input_source(),
integer()
) -> step(GMR).
morph_step(Cfg, Test_name, Gen, Spec, F, Input, Source, Run_index) ->
Evaluation = evaluate_spec(Spec, F, Input),
case erlang:element(5, Evaluation) of
true ->
continue;
false ->
record_regression_for(Cfg, spec_name(Spec), Source, Input),
{stop,
morph_failure(
Cfg,
Test_name,
Gen,
Spec,
F,
Run_index,
Input,
Source,
Evaluation
)}
end.
-file("src/metamon/internal/runner.gleam", 150).
?DOC(false).
-spec drive_morph(
metamon@config:config(),
binary(),
metamon@generator:generator(GMM),
morph_spec(GMM, GMO),
fun((GMM) -> GMO)
) -> nil.
drive_morph(Cfg, Test_name, Gen, Spec, F) ->
Outcome = iterate_inputs(
Cfg,
Gen,
fun(Input, Source, Run_index) ->
morph_step(Cfg, Test_name, Gen, Spec, F, Input, Source, Run_index)
end
),
case Outcome of
done ->
finish_with_coverage_check(Cfg, Test_name, {some, spec_name(Spec)});
{halted, Report_text} ->
panic_with(Report_text)
end.
-file("src/metamon/internal/runner.gleam", 135).
?DOC(false).
-spec run_forall_morph(
metamon@config:config(),
binary(),
metamon@generator:generator(GMH),
morph_spec(GMH, GMJ),
fun((GMH) -> GMJ)
) -> nil.
run_forall_morph(Cfg, Test_name, Gen, Spec, F) ->
reset_state(),
Entries = load_regression_for(Cfg, spec_name(Spec)),
case replay_regression_for_morph(Gen, Spec, F, Entries) of
{halted, Text} ->
panic_with(Text);
done ->
drive_morph(Cfg, Test_name, Gen, Spec, F)
end.