Current section
Files
Jump to
Current section
Files
src/metamon@internal@report.erl
-module(metamon@internal@report).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/metamon/internal/report.gleam").
-export([format_config_seed/2, render_json/1, render/1]).
-export_type([input_source/0, morph_mode/0, failure_report/0]).
-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).
-type input_source() :: {edge_source, integer()} |
{random_source, integer(), integer()}.
-type morph_mode() :: {plain, binary()} | {equivariant, binary(), binary()}.
-type failure_report() :: {failure_report,
binary(),
binary(),
integer(),
gleam@option:option(integer()),
integer(),
integer(),
integer(),
boolean(),
gleam@option:option(morph_mode()),
binary(),
binary(),
binary(),
binary(),
binary(),
input_source(),
boolean(),
list(binary()),
list(binary()),
gleam@option:option(metamon@coverage:snapshot())}.
-file("src/metamon/internal/report.gleam", 66).
?DOC(false).
-spec format_config_seed(integer(), gleam@option:option(integer())) -> binary().
format_config_seed(State, Original) ->
case Original of
none ->
erlang:integer_to_binary(State);
{some, N} ->
case N =:= State of
true ->
erlang:integer_to_binary(State);
false ->
<<<<<<(erlang:integer_to_binary(State))/binary,
" (originally seed("/utf8>>/binary,
(erlang:integer_to_binary(N))/binary>>/binary,
"))"/utf8>>
end
end.
-file("src/metamon/internal/report.gleam", 144).
?DOC(false).
-spec coverage_to_json(metamon@coverage:snapshot()) -> gleam@json:json().
coverage_to_json(Snap) ->
gleam@json:object(
[{<<"total"/utf8>>, gleam@json:int(erlang:element(2, Snap))},
{<<"requirements"/utf8>>,
gleam@json:array(
metamon@coverage:requirements_of(Snap),
fun(Req) ->
gleam@json:object(
[{<<"label"/utf8>>,
gleam@json:string(erlang:element(2, Req))},
{<<"target_pct"/utf8>>,
gleam@json:float(
metamon@coverage:target_pct_of(
Req,
erlang:element(2, Snap)
)
)},
{<<"hits"/utf8>>,
gleam@json:int(erlang:element(4, Req))},
{<<"actual_pct"/utf8>>,
gleam@json:float(
metamon@coverage:actual_pct(
erlang:element(4, Req),
erlang:element(2, Snap)
)
)}]
)
end
)},
{<<"collected"/utf8>>,
gleam@json:array(
maps:to_list(metamon@coverage:collected_of(Snap)),
fun(Pair) ->
gleam@json:object(
[{<<"label"/utf8>>,
gleam@json:string(erlang:element(1, Pair))},
{<<"count"/utf8>>,
gleam@json:int(erlang:element(2, Pair))}]
)
end
)}]
).
-file("src/metamon/internal/report.gleam", 85).
?DOC(false).
-spec render_json(failure_report()) -> binary().
render_json(Report) ->
Mode = case erlang:element(10, Report) of
none ->
gleam@json:string(<<"plain"/utf8>>);
{some, {plain, T}} ->
gleam@json:object(
[{<<"kind"/utf8>>, gleam@json:string(<<"plain"/utf8>>)},
{<<"transform"/utf8>>, gleam@json:string(T)}]
);
{some, {equivariant, Input_t, Output_t}} ->
gleam@json:object(
[{<<"kind"/utf8>>, gleam@json:string(<<"equivariant"/utf8>>)},
{<<"input_transform"/utf8>>, gleam@json:string(Input_t)},
{<<"output_transform"/utf8>>, gleam@json:string(Output_t)}]
)
end,
Source = case erlang:element(16, Report) of
{edge_source, I} ->
gleam@json:object(
[{<<"kind"/utf8>>, gleam@json:string(<<"edge"/utf8>>)},
{<<"index"/utf8>>, gleam@json:int(I)}]
);
{random_source, Seed_value, Size} ->
gleam@json:object(
[{<<"kind"/utf8>>, gleam@json:string(<<"random"/utf8>>)},
{<<"seed"/utf8>>, gleam@json:int(Seed_value)},
{<<"size"/utf8>>, gleam@json:int(Size)}]
)
end,
Coverage_field = case erlang:element(20, Report) of
none ->
gleam@json:null();
{some, Snap} ->
coverage_to_json(Snap)
end,
Config_seed_original_field = case erlang:element(5, Report) of
none ->
gleam@json:null();
{some, N} ->
gleam@json:int(N)
end,
_pipe = gleam@json:object(
[{<<"mr_name"/utf8>>, gleam@json:string(erlang:element(2, Report))},
{<<"test_name"/utf8>>, gleam@json:string(erlang:element(3, Report))},
{<<"config_seed"/utf8>>, gleam@json:int(erlang:element(4, Report))},
{<<"config_seed_original"/utf8>>, Config_seed_original_field},
{<<"runs_done"/utf8>>, gleam@json:int(erlang:element(6, Report))},
{<<"runs_total"/utf8>>, gleam@json:int(erlang:element(7, Report))},
{<<"shrinks_done"/utf8>>, gleam@json:int(erlang:element(8, Report))},
{<<"shrink_capped"/utf8>>,
gleam@json:bool(erlang:element(9, Report))},
{<<"source"/utf8>>, Source},
{<<"morph_mode"/utf8>>, Mode},
{<<"relation"/utf8>>, gleam@json:string(erlang:element(11, Report))},
{<<"source_input"/utf8>>,
gleam@json:string(erlang:element(12, Report))},
{<<"followup_input"/utf8>>,
gleam@json:string(erlang:element(13, Report))},
{<<"source_output"/utf8>>,
gleam@json:string(erlang:element(14, Report))},
{<<"followup_output"/utf8>>,
gleam@json:string(erlang:element(15, Report))},
{<<"annotations"/utf8>>,
gleam@json:array(
erlang:element(18, Report),
fun gleam@json:string/1
)},
{<<"footnotes"/utf8>>,
gleam@json:array(
erlang:element(19, Report),
fun gleam@json:string/1
)},
{<<"coverage"/utf8>>, Coverage_field}]
),
gleam@json:to_string(_pipe).
-file("src/metamon/internal/report.gleam", 183).
?DOC(false).
-spec header_lines(failure_report()) -> list(binary()).
header_lines(Report) ->
Title = case erlang:element(10, Report) of
none ->
<<"× property failed"/utf8>>;
{some, _} ->
<<<<"× metamorphic relation `"/utf8,
(erlang:element(2, Report))/binary>>/binary,
"` failed"/utf8>>
end,
Source = case erlang:element(16, Report) of
{edge_source, Idx} ->
<<<<"edge("/utf8, (erlang:integer_to_binary(Idx))/binary>>/binary,
")"/utf8>>;
{random_source, Seed_value, Size} ->
<<<<<<<<"random(seed="/utf8,
(erlang:integer_to_binary(Seed_value))/binary>>/binary,
", size="/utf8>>/binary,
(erlang:integer_to_binary(Size))/binary>>/binary,
")"/utf8>>
end,
Shrinks_label = case erlang:element(9, Report) of
true ->
<<(erlang:integer_to_binary(erlang:element(8, Report)))/binary,
"+ (limit reached)"/utf8>>;
false ->
erlang:integer_to_binary(erlang:element(8, Report))
end,
[Title,
<<" test: "/utf8, (erlang:element(3, Report))/binary>>,
<<" source: "/utf8, Source/binary>>,
<<" config seed: "/utf8,
(format_config_seed(
erlang:element(4, Report),
erlang:element(5, Report)
))/binary>>,
<<<<<<" runs: "/utf8,
(erlang:integer_to_binary(erlang:element(6, Report)))/binary>>/binary,
" / "/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(7, Report)))/binary>>,
<<" shrinks: "/utf8, Shrinks_label/binary>>].
-file("src/metamon/internal/report.gleam", 254).
?DOC(false).
-spec list_join_block(list(binary())) -> list(binary()).
list_join_block(Lines) ->
case Lines of
[] ->
[];
Items ->
[gleam@string:join(Items, <<"\n"/utf8>>)]
end.
-file("src/metamon/internal/report.gleam", 287).
?DOC(false).
-spec coverage_lines(metamon@coverage:snapshot()) -> list(binary()).
coverage_lines(Snap) ->
Total = erlang:element(2, Snap),
Req_lines = gleam@list:map(
metamon@coverage:requirements_of(Snap),
fun(Req) ->
Pct = metamon@coverage:actual_pct(erlang:element(4, Req), Total),
<<<<<<<<<<<<<<<<<<<<" "/utf8, (erlang:element(2, Req))/binary>>/binary,
": "/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(4, Req)
))/binary>>/binary,
"/"/utf8>>/binary,
(erlang:integer_to_binary(Total))/binary>>/binary,
" ("/utf8>>/binary,
(gleam_stdlib:float_to_string(Pct))/binary>>/binary,
"%) target≥"/utf8>>/binary,
(gleam_stdlib:float_to_string(
metamon@coverage:target_pct_of(Req, Total)
))/binary>>/binary,
"%"/utf8>>
end
),
Collected = metamon@coverage:collected_of(Snap),
Collected_lines = begin
_pipe = maps:to_list(Collected),
gleam@list:map(
_pipe,
fun(Pair) ->
<<<<<<" "/utf8, (erlang:element(1, Pair))/binary>>/binary,
": "/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(2, Pair)))/binary>>
end
)
end,
lists:append(Req_lines, Collected_lines).
-file("src/metamon/internal/report.gleam", 261).
?DOC(false).
-spec extras_lines(failure_report()) -> list(binary()).
extras_lines(Report) ->
Annotations_block = case erlang:element(18, Report) of
[] ->
[];
Items ->
[<<" annotations:\n"/utf8,
(gleam@string:join(
gleam@list:map(
Items,
fun(A) -> <<" - "/utf8, A/binary>> end
),
<<"\n"/utf8>>
))/binary>>]
end,
Footnotes_block = case erlang:element(19, Report) of
[] ->
[];
Items@1 ->
[<<" footnotes:\n"/utf8,
(gleam@string:join(
gleam@list:map(
Items@1,
fun(F) -> <<" - "/utf8, F/binary>> end
),
<<"\n"/utf8>>
))/binary>>]
end,
Coverage_block = case erlang:element(20, Report) of
none ->
[];
{some, Snap} ->
case coverage_lines(Snap) of
[] ->
[];
Lines ->
[<<" coverage:\n"/utf8,
(gleam@string:join(Lines, <<"\n"/utf8>>))/binary>>]
end
end,
lists:append([Annotations_block, Footnotes_block, Coverage_block]).
-file("src/metamon/internal/report.gleam", 311).
?DOC(false).
-spec reproduce_lines(failure_report()) -> list(binary()).
reproduce_lines(Report) ->
case erlang:element(10, Report) of
none ->
[<<" reproduce (paste into a test):"/utf8>>,
<<" // The property failed for this input. To pin it as a"/utf8>>,
<<" // regression, store it explicitly and assert directly."/utf8>>,
<<" let input = "/utf8, (erlang:element(12, Report))/binary>>,
<<" should.be_true(property(input))"/utf8>>];
{some, _} ->
[<<" reproduce (paste into a test):"/utf8>>,
<<" // The MR failed for this input. To pin it as a regression,"/utf8>>,
<<" // call assert_morph with the shrunk input and the same MR."/utf8>>,
<<" let input = "/utf8, (erlang:element(12, Report))/binary>>,
<<" metamon.assert_morph(input, mr, f)"/utf8>>]
end.
-file("src/metamon/internal/report.gleam", 334).
?DOC(false).
-spec indent(binary(), binary()) -> binary().
indent(Block, Prefix) ->
_pipe = gleam@string:split(Block, <<"\n"/utf8>>),
_pipe@1 = gleam@list:map(
_pipe,
fun(Line) -> <<Prefix/binary, Line/binary>> end
),
gleam@string:join(_pipe@1, <<"\n"/utf8>>).
-file("src/metamon/internal/report.gleam", 215).
?DOC(false).
-spec body_lines(failure_report()) -> list(binary()).
body_lines(Report) ->
Transform_block = case erlang:element(10, Report) of
none ->
[];
{some, {plain, T}} ->
[<<<<" transform: `"/utf8, T/binary>>/binary, "`"/utf8>>];
{some, {equivariant, Input_t, Output_t}} ->
[<<<<" input: `"/utf8, Input_t/binary>>/binary, "`"/utf8>>,
<<<<" output: `"/utf8, Output_t/binary>>/binary,
"`"/utf8>>]
end,
Relation_block = case erlang:element(10, Report) of
none ->
[];
{some, _} ->
[<<<<" relation: `"/utf8, (erlang:element(11, Report))/binary>>/binary,
"`"/utf8>>]
end,
Inputs = case erlang:element(10, Report) of
none ->
[<<" source input (shrunk):\n "/utf8,
(erlang:element(12, Report))/binary>>];
{some, _} ->
[<<" source input (shrunk):\n "/utf8,
(erlang:element(12, Report))/binary>>,
<<" follow-up input (= transform(source)):\n "/utf8,
(erlang:element(13, Report))/binary>>,
<<" source output:\n "/utf8,
(erlang:element(14, Report))/binary>>,
<<" follow-up output:\n "/utf8,
(erlang:element(15, Report))/binary>>]
end,
Diff_block = case {erlang:element(17, Report), erlang:element(10, Report)} of
{true, {some, _}} ->
[<<" diff (source_output vs follow-up_output):\n"/utf8,
(indent(
metamon@diff:render(
metamon@diff:diff(
erlang:element(14, Report),
erlang:element(15, Report)
)
),
<<" "/utf8>>
))/binary>>];
{_, _} ->
[]
end,
lists:append(
[list_join_block(lists:append(Transform_block, Relation_block)),
Inputs,
Diff_block]
).
-file("src/metamon/internal/report.gleam", 172).
?DOC(false).
-spec render(failure_report()) -> binary().
render(Report) ->
Header_block = begin
_pipe = header_lines(Report),
gleam@string:join(_pipe, <<"\n"/utf8>>)
end,
Body_block = begin
_pipe@1 = body_lines(Report),
gleam@string:join(_pipe@1, <<"\n\n"/utf8>>)
end,
Extras_block = begin
_pipe@2 = extras_lines(Report),
gleam@string:join(_pipe@2, <<"\n\n"/utf8>>)
end,
Reproduce_block = begin
_pipe@3 = reproduce_lines(Report),
gleam@string:join(_pipe@3, <<"\n"/utf8>>)
end,
Blocks = begin
_pipe@4 = [Header_block, Body_block, Extras_block, Reproduce_block],
gleam@list:filter(_pipe@4, fun(B) -> B /= <<""/utf8>> end)
end,
gleam@string:join(Blocks, <<"\n\n"/utf8>>).