File 1892-Test-invalid-patterns-in-property-based-tests-for-th.patch of Package erlang
From dab01006a63edb23274f17c3b72b73f5ba752d46 Mon Sep 17 00:00:00 2001
From: Jan Uhlig <juhlig@hnc-agency.org>
Date: Mon, 4 Sep 2023 17:35:18 +0200
Subject: [PATCH 2/4] Test invalid patterns in property-based tests for the
binary module
---
.../test/binary_property_test_SUITE.erl | 136 ++++++++++++------
lib/stdlib/test/property_test/binary_prop.erl | 132 ++++++++++++++---
2 files changed, 206 insertions(+), 62 deletions(-)
diff --git a/lib/stdlib/test/binary_property_test_SUITE.erl b/lib/stdlib/test/binary_property_test_SUITE.erl
index 87740a0dc5..ad713b8e74 100644
--- a/lib/stdlib/test/binary_property_test_SUITE.erl
+++ b/lib/stdlib/test/binary_property_test_SUITE.erl
@@ -22,29 +22,55 @@
-compile([export_all, nowarn_export_all]).
all() ->
- [at_case, at_invalid_case,
- bin_to_list_1_case,
- bin_to_list_2_3_case, bin_to_list_2_3_invalid_case,
- compile_pattern_case, compile_pattern_invalid_case,
- copy_case, copy_2_invalid_case,
- decode_hex_case, decode_hex_invalid_case,
+ [{group, valid_input}, {group, invalid_input}].
+
+valid_input_tests() ->
+ [at_case,
+ bin_to_list_1_case, bin_to_list_2_3_case,
+ compile_pattern_case,
+ copy_case,
+ decode_hex_case,
decode_unsigned_case,
encode_hex_case,
- encode_unsigned_case, encode_unsigned_invalid_case,
+ encode_unsigned_case,
first_case,
last_case,
- list_to_bin_case, list_to_bin_invalid_case,
+ list_to_bin_case,
longest_common_prefix_case,
longest_common_suffix_case,
- match_2_case,
- match_3_case, match_3_invalid_case,
- matches_2_case,
- matches_3_case, matches_3_invalid_case,
- part_case, part_invalid_case,
- replace_3_case,
- replace_4_case, replace_4_invalid1_case, replace_4_invalid2_case,
- split_2_case,
- split_3_case, split_3_invalid_case].
+ match_2_case, match_3_case,
+ matches_2_case, matches_3_case,
+ part_case,
+ replace_3_case, replace_4_case,
+ split_2_case, split_3_case].
+
+out_of_binary_tests() ->
+ [at_invalid_index_case,
+ bin_to_list_2_3_invalid_range_case,
+ match_3_invalid_scope_case,
+ matches_3_invalid_scope_case,
+ part_invalid_range_case,
+ replace_4_invalid_scope_case, replace_4_invalid_insert_replaced_case,
+ split_3_invalid_scope_case].
+
+invalid_pattern_tests() ->
+ [compile_pattern_invalid_pattern_case,
+ match_2_invalid_pattern_case, match_3_invalid_pattern_case,
+ matches_2_invalid_pattern_case, matches_3_invalid_pattern_case,
+ replace_3_invalid_pattern_case, replace_4_invalid_pattern_case,
+ split_2_invalid_pattern_case, split_3_invalid_pattern_case].
+
+misc_invalid_input_tests() ->
+ [copy_2_invalid_n_case,
+ decode_hex_invalid_chars_case,
+ encode_unsigned_invalid_integer_case,
+ list_to_bin_invalid_bytes_case].
+
+groups() ->
+ [{valid_input, [], valid_input_tests()},
+ {invalid_input, [], [{out_of_binary, [], out_of_binary_tests()},
+ {invalid_patterns, [], invalid_pattern_tests()},
+ {misc_invalid, [], misc_invalid_input_tests()}]}].
init_per_suite(Config) ->
ct_property_test:init_per_suite(Config).
@@ -58,8 +84,8 @@ do_proptest(Prop, Config) ->
at_case(Config) ->
do_proptest(prop_at, Config).
-at_invalid_case(Config) ->
- do_proptest(prop_at_invalid, Config).
+at_invalid_index_case(Config) ->
+ do_proptest(prop_at_invalid_index, Config).
bin_to_list_1_case(Config) ->
do_proptest(prop_bin_to_list_1, Config).
@@ -67,26 +93,26 @@ bin_to_list_1_case(Config) ->
bin_to_list_2_3_case(Config) ->
do_proptest(prop_bin_to_list_2_3, Config).
-bin_to_list_2_3_invalid_case(Config) ->
- do_proptest(prop_bin_to_list_2_3_invalid, Config).
+bin_to_list_2_3_invalid_range_case(Config) ->
+ do_proptest(prop_bin_to_list_2_3_invalid_range, Config).
compile_pattern_case(Config) ->
do_proptest(prop_compile_pattern, Config).
-compile_pattern_invalid_case(Config) ->
- do_proptest(prop_compile_pattern_invalid, Config).
+compile_pattern_invalid_pattern_case(Config) ->
+ do_proptest(prop_compile_pattern_invalid_pattern, Config).
copy_case(Config) ->
do_proptest(prop_copy, Config).
-copy_2_invalid_case(Config) ->
- do_proptest(prop_copy_2_invalid, Config).
+copy_2_invalid_n_case(Config) ->
+ do_proptest(prop_copy_2_invalid_n, Config).
decode_hex_case(Config) ->
do_proptest(prop_decode_hex, Config).
-decode_hex_invalid_case(Config) ->
- do_proptest(prop_decode_hex_invalid, Config).
+decode_hex_invalid_chars_case(Config) ->
+ do_proptest(prop_decode_hex_invalid_chars, Config).
decode_unsigned_case(Config) ->
do_proptest(prop_decode_unsigned, Config).
@@ -97,8 +123,8 @@ encode_hex_case(Config) ->
encode_unsigned_case(Config) ->
do_proptest(prop_encode_unsigned, Config).
-encode_unsigned_invalid_case(Config) ->
- do_proptest(prop_encode_unsigned_invalid, Config).
+encode_unsigned_invalid_integer_case(Config) ->
+ do_proptest(prop_encode_unsigned_invalid_integer, Config).
first_case(Config) ->
do_proptest(prop_first, Config).
@@ -109,8 +135,8 @@ last_case(Config) ->
list_to_bin_case(Config) ->
do_proptest(prop_list_to_bin, Config).
-list_to_bin_invalid_case(Config) ->
- do_proptest(prop_list_to_bin_invalid, Config).
+list_to_bin_invalid_bytes_case(Config) ->
+ do_proptest(prop_list_to_bin_invalid_bytes, Config).
longest_common_prefix_case(Config) ->
do_proptest(prop_longest_common_prefix, Config).
@@ -121,45 +147,69 @@ longest_common_suffix_case(Config) ->
match_2_case(Config) ->
do_proptest(prop_match_2, Config).
+match_2_invalid_pattern_case(Config) ->
+ do_proptest(prop_match_2_invalid_pattern, Config).
+
match_3_case(Config) ->
do_proptest(prop_match_3, Config).
-match_3_invalid_case(Config) ->
- do_proptest(prop_match_3_invalid, Config).
+match_3_invalid_scope_case(Config) ->
+ do_proptest(prop_match_3_invalid_scope, Config).
+
+match_3_invalid_pattern_case(Config) ->
+ do_proptest(prop_match_3_invalid_pattern, Config).
matches_2_case(Config) ->
do_proptest(prop_matches_2, Config).
+matches_2_invalid_pattern_case(Config) ->
+ do_proptest(prop_matches_2_invalid_pattern, Config).
+
matches_3_case(Config) ->
do_proptest(prop_matches_3, Config).
-matches_3_invalid_case(Config) ->
- do_proptest(prop_matches_3_invalid, Config).
+matches_3_invalid_scope_case(Config) ->
+ do_proptest(prop_matches_3_invalid_scope, Config).
+
+matches_3_invalid_pattern_case(Config) ->
+ do_proptest(prop_matches_3_invalid_pattern, Config).
part_case(Config) ->
do_proptest(prop_part, Config).
-part_invalid_case(Config) ->
- do_proptest(prop_part_invalid, Config).
+part_invalid_range_case(Config) ->
+ do_proptest(prop_part_invalid_range, Config).
replace_3_case(Config) ->
do_proptest(prop_replace_3, Config).
+replace_3_invalid_pattern_case(Config) ->
+ do_proptest(prop_replace_3_invalid_pattern, Config).
+
replace_4_case(Config) ->
do_proptest(prop_replace_4, Config).
-replace_4_invalid1_case(Config) ->
- do_proptest(prop_replace_4_invalid1, Config).
+replace_4_invalid_scope_case(Config) ->
+ do_proptest(prop_replace_4_invalid_scope, Config).
+
+replace_4_invalid_insert_replaced_case(Config) ->
+ do_proptest(prop_replace_4_invalid_insert_replaced, Config).
-replace_4_invalid2_case(Config) ->
- do_proptest(prop_replace_4_invalid2, Config).
+replace_4_invalid_pattern_case(Config) ->
+ do_proptest(prop_replace_4_invalid_pattern, Config).
split_2_case(Config) ->
do_proptest(prop_split_2, Config).
+split_2_invalid_pattern_case(Config) ->
+ do_proptest(prop_split_2_invalid_pattern, Config).
+
split_3_case(Config) ->
do_proptest(prop_split_3, Config).
-split_3_invalid_case(Config) ->
- do_proptest(prop_split_3_invalid, Config).
+split_3_invalid_scope_case(Config) ->
+ do_proptest(prop_split_3_invalid_scope, Config).
+
+split_3_invalid_pattern_case(Config) ->
+ do_proptest(prop_split_3_invalid_pattern, Config).
diff --git a/lib/stdlib/test/property_test/binary_prop.erl b/lib/stdlib/test/property_test/binary_prop.erl
index b07cf13f43..80235d49e2 100644
--- a/lib/stdlib/test/property_test/binary_prop.erl
+++ b/lib/stdlib/test/property_test/binary_prop.erl
@@ -37,7 +37,7 @@ prop_at() ->
Byte =:= binary:at(Bin, Pos)
).
-prop_at_invalid() ->
+prop_at_invalid_index() ->
?FORALL(
{Bin, Pos},
?LET(
@@ -73,7 +73,7 @@ prop_bin_to_list_2_3() ->
List =:= binary:bin_to_list(Bin, Pos, Len)
).
-prop_bin_to_list_2_3_invalid() ->
+prop_bin_to_list_2_3_invalid_range() ->
?FORALL(
{Bin, {Pos, Len}=PosLen},
?LET(
@@ -93,7 +93,7 @@ prop_compile_pattern() ->
is_tuple(binary:compile_pattern(P))
).
-prop_compile_pattern_invalid() ->
+prop_compile_pattern_invalid_pattern() ->
?FORALL(
P,
oneof([
@@ -128,7 +128,7 @@ prop_copy() ->
end
).
-prop_copy_2_invalid() ->
+prop_copy_2_invalid_n() ->
?FORALL(
{Bin, N},
{binary(), neg_integer()},
@@ -161,7 +161,7 @@ prop_decode_hex() ->
BR =:= binary:decode_hex(BE)
).
-prop_decode_hex_invalid() ->
+prop_decode_hex_invalid_chars() ->
?FORALL(
Bin,
?SUCHTHAT(B, binary(), not is_hex_bin(B)),
@@ -213,7 +213,7 @@ prop_encode_unsigned() ->
end
).
-prop_encode_unsigned_invalid() ->
+prop_encode_unsigned_invalid_integer() ->
?FORALL(
I,
neg_integer(),
@@ -258,7 +258,7 @@ prop_list_to_bin() ->
Bin =:= binary:list_to_bin(List)
).
-prop_list_to_bin_invalid() ->
+prop_list_to_bin_invalid_bytes() ->
?FORALL(
List,
?SUCHTHAT(
@@ -309,6 +309,13 @@ prop_match_2() ->
end
).
+prop_match_2_invalid_pattern() ->
+ ?FORALL(
+ {Bin, Pattern},
+ {binary(), gen_patterns_invalid()},
+ expect_error(fun binary:match/2, [Bin, Pattern])
+ ).
+
%% --- match/3 --------------------------------------------------------
prop_match_3() ->
?FORALL(
@@ -325,7 +332,7 @@ prop_match_3() ->
end
).
-prop_match_3_invalid() ->
+prop_match_3_invalid_scope() ->
?FORALL(
{Bin, Pattern, Opts},
?LET(
@@ -337,6 +344,17 @@ prop_match_3_invalid() ->
expect_error(fun binary:match/3, [Bin, binary:compile_pattern(Pattern), Opts])
).
+prop_match_3_invalid_pattern() ->
+ ?FORALL(
+ {Bin, Pattern, Opts},
+ ?LET(
+ B,
+ binary(),
+ {B, gen_patterns_invalid(), gen_opts([], [gen_scope_opt(B)])}
+ ),
+ expect_error(fun binary:match/3, [Bin, Pattern, Opts])
+ ).
+
%% --- matches/2 ------------------------------------------------------
prop_matches_2() ->
?FORALL(
@@ -353,6 +371,13 @@ prop_matches_2() ->
end
).
+prop_matches_2_invalid_pattern() ->
+ ?FORALL(
+ {Bin, Pattern},
+ {binary(), gen_patterns_invalid()},
+ expect_error(fun binary:matches/2, [Bin, Pattern])
+ ).
+
%% --- matches/3 ------------------------------------------------------
prop_matches_3() ->
?FORALL(
@@ -369,7 +394,7 @@ prop_matches_3() ->
end
).
-prop_matches_3_invalid() ->
+prop_matches_3_invalid_scope() ->
?FORALL(
{Bin, Pattern, Opts},
?LET(
@@ -381,6 +406,17 @@ prop_matches_3_invalid() ->
expect_error(fun binary:matches/3, [Bin, binary:compile_pattern(Pattern), Opts])
).
+prop_matches_3_invalid_pattern() ->
+ ?FORALL(
+ {Bin, Pattern, Opts},
+ ?LET(
+ B,
+ binary(),
+ {B, gen_patterns_invalid(), gen_opts([], [gen_scope_opt(B)])}
+ ),
+ expect_error(fun binary:matches/3, [Bin, Pattern, Opts])
+ ).
+
%% --- part/2,3 -------------------------------------------------------
prop_part() ->
?FORALL(
@@ -399,7 +435,7 @@ prop_part() ->
end
).
-prop_part_invalid() ->
+prop_part_invalid_range() ->
?FORALL(
{Bin, {Pos, Len}=PosLen},
?LET(
@@ -427,6 +463,13 @@ prop_replace_3() ->
end
).
+prop_replace_3_invalid_pattern() ->
+ ?FORALL(
+ {Bin, Pattern, Replacement},
+ {binary(), gen_patterns_invalid(), oneof([binary(), function1(binary())])},
+ expect_error(fun binary:replace/3, [Bin, Pattern, Replacement])
+ ).
+
%% --- replace/4 ------------------------------------------------------
prop_replace_4() ->
?FORALL(
@@ -443,7 +486,7 @@ prop_replace_4() ->
end
).
-prop_replace_4_invalid1() ->
+prop_replace_4_invalid_scope() ->
?FORALL(
{Bin, Pattern, Replacement, Opts},
?LET(
@@ -455,7 +498,7 @@ prop_replace_4_invalid1() ->
expect_error(fun binary:replace/4, [Bin, binary:compile_pattern(Pattern), Replacement, Opts])
).
-prop_replace_4_invalid2() ->
+prop_replace_4_invalid_insert_replaced() ->
?FORALL(
{Bin, Pattern, Replacement, Opts},
?LET(
@@ -467,6 +510,17 @@ prop_replace_4_invalid2() ->
expect_error(fun binary:replace/4, [Bin, binary:compile_pattern(Pattern), Replacement, Opts])
).
+prop_replace_4_invalid_pattern() ->
+ ?FORALL(
+ {Bin, Pattern, Replacement, Opts},
+ ?LET(
+ {B, R},
+ {binary(), oneof([binary(), function1(binary())])},
+ {B, gen_patterns_invalid(), R, gen_opts([], [global, gen_scope_opt(B), gen_insert_replaced_opt(R)])}
+ ),
+ expect_error(fun binary:replace/4, [Bin, Pattern, Replacement, Opts])
+ ).
+
%% --- split/2 --------------------------------------------------------
prop_split_2() ->
?FORALL(
@@ -483,6 +537,13 @@ prop_split_2() ->
end
).
+prop_split_2_invalid_pattern() ->
+ ?FORALL(
+ {Bin, Pattern},
+ {binary(), gen_patterns_invalid()},
+ expect_error(fun binary:split/2, [Bin, Pattern])
+ ).
+
%% --- split/3 --------------------------------------------------------
prop_split_3() ->
?FORALL(
@@ -499,7 +560,7 @@ prop_split_3() ->
end
).
-prop_split_3_invalid() ->
+prop_split_3_invalid_scope() ->
?FORALL(
{Bin, Pattern, Opts},
?LET(
@@ -511,6 +572,17 @@ prop_split_3_invalid() ->
expect_error(fun binary:split/3, [Bin, binary:compile_pattern(Pattern), Opts])
).
+prop_split_3_invalid_pattern() ->
+ ?FORALL(
+ {Bin, Pattern, Opts},
+ ?LET(
+ B,
+ binary(),
+ {B, gen_patterns_invalid(), gen_opts([], [global, trim, trim_all, gen_scope_opt(B)])}
+ ),
+ expect_error(fun binary:split/3, [Bin, Pattern, Opts])
+ ).
+
%%%%%%%%%%%%%%%%%%
%%% Generators %%%
@@ -607,6 +679,28 @@ gen_pattern(Bin) ->
)
)]).
+%% Generator for invalid patterns.
+gen_patterns_invalid() ->
+ ?LET(
+ T,
+ oneof([?SUCHTHAT(T, gen_pattern_invalid(), not is_list(T)), list(oneof([gen_pattern(), gen_pattern_invalid()]))]),
+ case T of
+ [_|_] ->
+ case lists:all(fun(<<_, _/binary>>) -> true; (_) -> false end, T) of
+ true ->
+ [gen_pattern_invalid() | T];
+ false ->
+ T
+ end;
+ _ ->
+ T
+ end
+ ).
+
+%% Generator for a single invalid pattern.
+gen_pattern_invalid() ->
+ ?SUCHTHAT(T, ct_proper_ext:safe_any(), T =:= <<>> orelse not is_binary(T)).
+
%%%%%%%%%%%%%%%
%%% Helpers %%%
@@ -640,11 +734,11 @@ opts_to_scope_parts(Bin, Opts) ->
opts_to_trim(Opts) ->
case {lists:member(trim_all, Opts), lists:member(trim, Opts)} of
{true, _} ->
- all;
+ all;
{_, true} ->
- rear;
+ rear;
_ ->
- none
+ none
end.
%% Process a replacement based on the insert_replaced options specified in the given options list
@@ -660,7 +754,7 @@ opts_to_replacement(Replacement, Opts) ->
split_replacement(Positions, Replacement);
{insert_replaced, Position} ->
<<Front:Position/binary, Rear/binary>> = Replacement,
- [Front, Rear]
+ [Front, Rear]
end.
split_replacement(Inserts, Bin) ->
@@ -825,10 +919,10 @@ do_split(Bin, Patterns, Opts) ->
Splitted2 = lists:droplast(Splitted1) ++ [<<(lists:last(Splitted1))/binary, Rear/binary>>],
case Trim of
none ->
- Splitted2;
+ Splitted2;
all ->
lists:filter(fun(Part) -> Part =/= <<>> end, Splitted2);
- rear ->
+ rear ->
lists:reverse(lists:dropwhile(fun(Part) -> Part =:= <<>> end, lists:reverse(Splitted2)))
end.
--
2.35.3