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(GMP, GMQ) :: {plain_spec,
binary(),
metamon@transform:transform(GMP),
metamon@relation:relation(GMQ)} |
{equivariant_spec,
binary(),
metamon@transform:transform(GMP),
metamon@transform:transform(GMQ),
metamon@relation:relation(GMQ)}.
-type step(GMR) :: continue | {stop, binary()} | {gleam_phantom, GMR}.
-type outcome() :: done | {halted, binary()}.
-type evaluation(GMS) :: {evaluation, binary(), GMS, GMS, boolean()}.
-file("src/metamon/internal/runner.gleam", 48).
?DOC(false).
-spec plain(
binary(),
metamon@transform:transform(GMT),
metamon@relation:relation(GMV)
) -> morph_spec(GMT, GMV).
plain(Name, Transform, Relation) ->
{plain_spec, Name, Transform, Relation}.
-file("src/metamon/internal/runner.gleam", 58).
?DOC(false).
-spec equivariant(
binary(),
metamon@transform:transform(GMZ),
metamon@transform:transform(GNB),
metamon@relation:relation(GNB)
) -> morph_spec(GMZ, GNB).
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(GOR)),
fun((GOR) -> GOU),
GOR
) -> list(GOU).
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(GOW)),
metamon@relation:relation_n(GOZ),
integer(),
GOW,
metamon@internal@report:input_source(),
list(GOZ)
) -> 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(GPL),
integer(),
fun((GPL, metamon@internal@report:input_source(), integer()) -> step(GPL))
) -> 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(GPO),
integer(),
integer(),
metamon@generator@seed:seed(),
fun((GPO, metamon@internal@report:input_source(), integer()) -> step(GPO))
) -> 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(GPR),
fun((GPR) -> boolean()),
integer(),
GPR,
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(GPT, GPU), fun((GPT) -> GPU), GPT) -> evaluation(GPU).
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(GQQ, GQR),
GQQ,
evaluation(GQR),
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(GRA),
morph_spec(GRA, GRC),
fun((GRA) -> GRC),
GRA,
integer(),
integer()
) -> {GRA, 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(GQV),
morph_spec(GQV, GQX),
fun((GQV) -> GQX),
GQV,
metamon@internal@report:input_source()
) -> {GQV, 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(GQK),
morph_spec(GQK, GQM),
fun((GQK) -> GQM),
integer(),
GQK,
metamon@internal@report:input_source(),
evaluation(GQM)
) -> 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(GOH, GOI), fun((GOH) -> GOI), GOH) -> 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(GRG), integer()) -> list(GRG).
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(GPI),
fun((GPI, metamon@internal@report:input_source(), integer()) -> step(GPI))
) -> 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(GOL),
list(metamon@transform:transform(GOL)),
metamon@relation:relation_n(GOP),
fun((GOL) -> GOP)
) -> 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(GPC),
list(morph_spec(GPC, GPE)),
fun((GPC) -> GPE)
) -> 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(GRW), integer()) -> gleam@option:option(GRW).
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(GRU),
metamon@internal@regression:entry()
) -> GRU.
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(GRL),
list(metamon@internal@regression:entry()),
fun((GRL) -> 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(GRO),
morph_spec(GRO, GRQ),
fun((GRO) -> GRQ),
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(GNO),
fun((GNO) -> boolean()),
GNO,
metamon@internal@report:input_source(),
integer()
) -> step(GNO).
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(GNM),
fun((GNM) -> 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(GNK),
fun((GNK) -> 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(GOB),
morph_spec(GOB, GOD),
fun((GOB) -> GOD),
GOB,
metamon@internal@report:input_source(),
integer()
) -> step(GOB).
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(GNW),
morph_spec(GNW, GNY),
fun((GNW) -> GNY)
) -> 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(GNR),
morph_spec(GNR, GNT),
fun((GNR) -> GNT)
) -> 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.