Packages

Property-based testing and metamorphic testing combinator library for Gleam

Current section

Files

Jump to
metamon src metamon@generator@edges.erl
Raw

src/metamon@generator@edges.erl

-module(metamon@generator@edges).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/metamon/generator/edges.gleam").
-export([strings_ascii/0, ints_in/2, floats_in/2, strings_unicode/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(
" Default edge values for the built-in generators. These are the\n"
" \"must-try\" boundary inputs that the runner consumes before falling\n"
" back to random generation. Curating a good edge set is the single\n"
" biggest win for property-based testing on real-world code, so each\n"
" builder here is documented with the rationale.\n"
).
-file("src/metamon/generator/edges.gleam", 50).
?DOC(
" Edge ASCII strings.\n"
"\n"
" Empty, single-space, single-tab, single-newline, common short\n"
" fragments that frequently break tokenisers and Gleam-identifier\n"
" generators (keywords, leading digit, plus/minus prefix).\n"
).
-spec strings_ascii() -> list(binary()).
strings_ascii() ->
[<<""/utf8>>,
<<" "/utf8>>,
<<"\t"/utf8>>,
<<"\n"/utf8>>,
<<"0"/utf8>>,
<<"a"/utf8>>,
<<"A"/utf8>>,
<<"_"/utf8>>,
<<"+1"/utf8>>,
<<"-1"/utf8>>,
<<"Type"/utf8>>,
<<"case"/utf8>>,
<<"fn"/utf8>>,
<<"OAuth2Token"/utf8>>,
<<"256sha"/utf8>>,
<<"ipv4"/utf8>>,
<<"null"/utf8>>].
-file("src/metamon/generator/edges.gleam", 88).
-spec filter_in_range(list(integer()), integer(), integer()) -> list(integer()).
filter_in_range(Items, Lo, Hi) ->
case Items of
[] ->
[];
[First | Rest] ->
case (First >= Lo) andalso (First =< Hi) of
true ->
[First | filter_in_range(Rest, Lo, Hi)];
false ->
filter_in_range(Rest, Lo, Hi)
end
end.
-file("src/metamon/generator/edges.gleam", 99).
-spec filter_floats_in_range(list(float()), float(), float()) -> list(float()).
filter_floats_in_range(Items, Lo, Hi) ->
case Items of
[] ->
[];
[First | Rest] ->
case (First >= Lo) andalso (First =< Hi) of
true ->
[First | filter_floats_in_range(Rest, Lo, Hi)];
false ->
filter_floats_in_range(Rest, Lo, Hi)
end
end.
-file("src/metamon/generator/edges.gleam", 148).
-spec contains(list(integer()), integer()) -> boolean().
contains(Items, Needle) ->
case Items of
[] ->
false;
[First | Rest] ->
case First =:= Needle of
true ->
true;
false ->
contains(Rest, Needle)
end
end.
-file("src/metamon/generator/edges.gleam", 159).
-spec contains_float(list(float()), float()) -> boolean().
contains_float(Items, Needle) ->
case Items of
[] ->
false;
[First | Rest] ->
case First =:= Needle of
true ->
true;
false ->
contains_float(Rest, Needle)
end
end.
-file("src/metamon/generator/edges.gleam", 174).
-spec reverse_into(list(ECV), list(ECV)) -> list(ECV).
reverse_into(Items, Acc) ->
case Items of
[] ->
Acc;
[First | Rest] ->
reverse_into(Rest, [First | Acc])
end.
-file("src/metamon/generator/edges.gleam", 170).
-spec reverse(list(ECS)) -> list(ECS).
reverse(Items) ->
reverse_into(Items, []).
-file("src/metamon/generator/edges.gleam", 118).
-spec dedupe_loop(list(integer()), list(integer()), list(integer())) -> list(integer()).
dedupe_loop(Items, Seen, Acc) ->
case Items of
[] ->
reverse(Acc);
[First | Rest] ->
case contains(Seen, First) of
true ->
dedupe_loop(Rest, Seen, Acc);
false ->
dedupe_loop(Rest, [First | Seen], [First | Acc])
end
end.
-file("src/metamon/generator/edges.gleam", 114).
-spec dedupe(list(integer())) -> list(integer()).
dedupe(Items) ->
dedupe_loop(Items, [], []).
-file("src/metamon/generator/edges.gleam", 12).
?DOC(
" Edge ints in the closed interval `[lo, hi]`.\n"
"\n"
" Always-tried candidates: `0`, `1`, `-1`, `lo`, `hi`. We also include\n"
" \"common bug magnets\" (`Int.max`, `Int.min`, neighbouring values\n"
" around 0) when they fall inside the range.\n"
).
-spec ints_in(integer(), integer()) -> list(integer()).
ints_in(Lo, Hi) ->
Candidates = [0,
1,
-1,
Lo,
Hi,
Lo + 1,
Hi - 1,
9007199254740991,
-9007199254740991],
_pipe = Candidates,
_pipe@1 = filter_in_range(_pipe, Lo, Hi),
dedupe(_pipe@1).
-file("src/metamon/generator/edges.gleam", 133).
-spec dedupe_floats_loop(list(float()), list(float()), list(float())) -> list(float()).
dedupe_floats_loop(Items, Seen, Acc) ->
case Items of
[] ->
reverse(Acc);
[First | Rest] ->
case contains_float(Seen, First) of
true ->
dedupe_floats_loop(Rest, Seen, Acc);
false ->
dedupe_floats_loop(Rest, [First | Seen], [First | Acc])
end
end.
-file("src/metamon/generator/edges.gleam", 129).
-spec dedupe_floats(list(float())) -> list(float()).
dedupe_floats(Items) ->
dedupe_floats_loop(Items, [], []).
-file("src/metamon/generator/edges.gleam", 38).
?DOC(
" Edge floats in `[lo, hi]`.\n"
"\n"
" Includes `lo`, `hi`, `0.0`, plus IEEE-754 bug magnets where\n"
" representable: smallest positive subnormal-ish constants are not\n"
" emitted to keep behaviour identical across BEAM and JS targets.\n"
).
-spec floats_in(float(), float()) -> list(float()).
floats_in(Lo, Hi) ->
Candidates = [Lo, Hi, +0.0, 1.0, -1.0],
_pipe = Candidates,
_pipe@1 = filter_floats_in_range(_pipe, Lo, Hi),
dedupe_floats(_pipe@1).
-file("src/metamon/generator/edges.gleam", 181).
-spec list_append(list(ECZ), list(ECZ)) -> list(ECZ).
list_append(Left, Right) ->
case Left of
[] ->
Right;
[First | Rest] ->
[First | list_append(Rest, Right)]
end.
-file("src/metamon/generator/edges.gleam", 77).
?DOC(
" Edge Unicode-aware strings.\n"
"\n"
" Adds RTL/BiDi, an emoji, and U+0000 (NUL) which routinely breaks\n"
" C-FFI bridges. Surrogate halves are intentionally not emitted —\n"
" they are not valid Gleam strings.\n"
).
-spec strings_unicode() -> list(binary()).
strings_unicode() ->
Extras = [<<"\x{0000}"/utf8>>,
<<"\x{200E}helloworld"/utf8>>,
<<"héllo"/utf8>>,
<<"𝕏 unicode"/utf8>>,
<<"🦊"/utf8>>],
list_append(strings_ascii(), Extras).