Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
5681-Improve-the-lists-merge-family-of-function...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 5681-Improve-the-lists-merge-family-of-functions.patch of Package erlang
From 126ef4f4830624eec10518875a851223d4f7054f Mon Sep 17 00:00:00 2001 From: Maria Scott <maria-12648430@hnc-agency.org> Date: Wed, 15 Feb 2023 17:15:17 +0100 Subject: [PATCH] Improve the lists:merge family of functions The merge functions no longer accept non-list arguments for merging. Before, non-list arguments were accepted and returned if they were the first argument and the second (and third, where applicable, ie in merge3/3 and umerge3/3) arguments were empty lists. For merge/1 and umerge/1, non-list arguments were accepted if they were the only element in a list of otherwise empty lists. The merge functions now also return the second (or third, where applicable) list immediately and unchanged if the other lists are empty. Before, this was only done for the first argument, if the second (and third, where applicable) list was empty. In all other cases, the merging process would be performed, unnecessarily. The same applies for the undocumented reverse-merge functions like rmerge/2,3, rumerge/2,3 etc. Co-authored-by: Jan Uhlig <juhlig@hnc-agency.org> --- lib/stdlib/src/lists.erl | 340 +++++++++++------- lib/stdlib/test/lists_SUITE.erl | 242 +++++++++++++ lib/stdlib/test/lists_property_test_SUITE.erl | 50 ++- lib/stdlib/test/property_test/lists_prop.erl | 131 +++++++ 4 files changed, 633 insertions(+), 130 deletions(-) diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl index c5eda49253..b1be8e1c2d 100644 --- a/lib/stdlib/src/lists.erl +++ b/lib/stdlib/src/lists.erl @@ -701,24 +701,44 @@ merge(L) -> Y :: term(), Z :: term(). -merge3(L1, [], L3) -> - merge(L1, L3); -merge3(L1, L2, []) -> - merge(L1, L2); -merge3(L1, [H2 | T2], [H3 | T3]) -> - lists:reverse(merge3_1(L1, [], H2, T2, H3, T3), []). +merge3([_|_]=L1, [H2 | T2], [H3 | T3]) -> + lists:reverse(merge3_1(L1, [], H2, T2, H3, T3), []); +merge3([_|_]=L1, [_|_]=L2, []) -> + merge(L1, L2); +merge3([_|_]=L1, [], [_|_]=L3) -> + merge(L1, L3); +merge3([_|_]=L1, [], []) -> + L1; +merge3([], [_|_]=L2, [_|_]=L3) -> + merge(L2, L3); +merge3([], [_|_]=L2, []) -> + L2; +merge3([], [], [_|_]=L3) -> + L3; +merge3([], [], []) -> + []. %% rmerge3(X, Y, Z) -> L %% merges three reversed sorted lists X, Y and Z -spec rmerge3([X], [Y], [Z]) -> [(X | Y | Z)]. -rmerge3(L1, [], L3) -> - rmerge(L1, L3); -rmerge3(L1, L2, []) -> - rmerge(L1, L2); -rmerge3(L1, [H2 | T2], [H3 | T3]) -> - lists:reverse(rmerge3_1(L1, [], H2, T2, H3, T3), []). +rmerge3([_|_]=L1, [H2 | T2], [H3 | T3]) -> + lists:reverse(rmerge3_1(L1, [], H2, T2, H3, T3), []); +rmerge3([_|_]=L1, [_|_]=L2, []) -> + rmerge(L1, L2); +rmerge3([_|_]=L1, [], [_|_]=L3) -> + rmerge(L1, L3); +rmerge3([_|_]=L1, [], []) -> + L1; +rmerge3([], [_|_]=L2, [_|_]=L3) -> + rmerge(L2, L3); +rmerge3([], [_|_]=L2, []) -> + L2; +rmerge3([], [], [_|_]=L3) -> + L3; +rmerge3([], [], []) -> + []. %% merge(X, Y) -> L %% merges two sorted lists X and Y @@ -730,10 +750,14 @@ rmerge3(L1, [H2 | T2], [H3 | T3]) -> X :: term(), Y :: term(). -merge(T1, []) -> - T1; -merge(T1, [H2 | T2]) -> - lists:reverse(merge2_1(T1, H2, T2, []), []). +merge([_|_]=T1, [H2 | T2]) -> + lists:reverse(merge2_1(T1, H2, T2, []), []); +merge([_|_]=L1, []) -> + L1; +merge([], [_|_]=L2) -> + L2; +merge([], []) -> + []. %% rmerge(X, Y) -> L %% merges two reversed sorted lists X and Y @@ -742,10 +766,14 @@ merge(T1, [H2 | T2]) -> -spec rmerge([X], [Y]) -> [(X | Y)]. -rmerge(T1, []) -> - T1; -rmerge(T1, [H2 | T2]) -> - lists:reverse(rmerge2_1(T1, H2, T2, []), []). +rmerge([_|_]=T1, [H2 | T2]) -> + lists:reverse(rmerge2_1(T1, H2, T2, []), []); +rmerge([_|_]=L1, []) -> + L1; +rmerge([], [_|_]=L2) -> + L2; +rmerge([], []) -> + []. %% concat(L) concatenate the list representation of the elements %% in L - the elements in L can be atoms, numbers of strings. @@ -971,30 +999,38 @@ keysort_1(_I, X, _EX, [], R) -> T2 :: Tuple, Tuple :: tuple(). -keymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> - case L2 of - [] -> - T1; - [H2 | T2] -> - E2 = element(Index, H2), - M = keymerge2_1(Index, T1, E2, H2, T2, []), - lists:reverse(M, []) - end. +keymerge(Index, L1, L2) when is_integer(Index), Index > 0 -> + keymerge_1(Index, L1, L2). + +keymerge_1(Index, [_|_]=T1, [H2 | T2]) -> + E2 = element(Index, H2), + M = keymerge2_1(Index, T1, E2, H2, T2, []), + lists:reverse(M, []); +keymerge_1(_Index, [_|_]=L1, []) -> + L1; +keymerge_1(_Index, [], [_|_]=L2) -> + L2; +keymerge_1(_Index, [], []) -> + []. %% reverse(rkeymerge(I,reverse(A),reverse(B))) is equal to keymerge(I,A,B). -spec rkeymerge(pos_integer(), [X], [Y]) -> [R] when X :: tuple(), Y :: tuple(), R :: tuple(). -rkeymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> - case L2 of - [] -> - T1; - [H2 | T2] -> - E2 = element(Index, H2), - M = rkeymerge2_1(Index, T1, E2, H2, T2, []), - lists:reverse(M, []) - end. +rkeymerge(Index, L1, L2) when is_integer(Index), Index > 0 -> + rkeymerge_1(Index, L1, L2). + +rkeymerge_1(Index, [_|_]=T1, [H2 | T2]) -> + E2 = element(Index, H2), + M = rkeymerge2_1(Index, T1, E2, H2, T2, []), + lists:reverse(M, []); +rkeymerge_1(_Index, [_|_]=L1, []) -> + L1; +rkeymerge_1(_Index, [], [_|_]=L2) -> + L2; +rkeymerge_1(_Index, [], []) -> + []. -spec ukeysort(N, TupleList1) -> TupleList2 when N :: pos_integer(), @@ -1074,30 +1110,38 @@ ukeysort_1(_I, X, _EX, []) -> T2 :: Tuple, Tuple :: tuple(). -ukeymerge(Index, L1, T2) when is_integer(Index), Index > 0 -> - case L1 of - [] -> - T2; - [H1 | T1] -> - E1 = element(Index, H1), - M = ukeymerge2_2(Index, T1, E1, H1, T2, []), - lists:reverse(M, []) - end. +ukeymerge(Index, L1, L2) when is_integer(Index), Index > 0 -> + ukeymerge_1(Index, L1, L2). + +ukeymerge_1(Index, [H1 | T1], [_|_]=T2) -> + E1 = element(Index, H1), + M = ukeymerge2_2(Index, T1, E1, H1, T2, []), + lists:reverse(M, []); +ukeymerge_1(_Index, [_|_]=L1, []) -> + L1; +ukeymerge_1(_Index, [], [_|_]=L2) -> + L2; +ukeymerge_1(_Index, [], []) -> + []. %% reverse(rukeymerge(I,reverse(A),reverse(B))) is equal to ukeymerge(I,A,B). -spec rukeymerge(pos_integer(), [X], [Y]) -> [(X | Y)] when X :: tuple(), Y :: tuple(). -rukeymerge(Index, T1, L2) when is_integer(Index), Index > 0 -> - case L2 of - [] -> - T1; - [H2 | T2] -> - E2 = element(Index, H2), - M = rukeymerge2_1(Index, T1, E2, T2, [], H2), - lists:reverse(M, []) - end. +rukeymerge(Index, L1, L2) when is_integer(Index), Index > 0 -> + rukeymerge_1(Index, L1, L2). + +rukeymerge_1(Index, [_|_]=T1, [H2 | T2]) -> + E2 = element(Index, H2), + M = rukeymerge2_1(Index, T1, E2, T2, [], H2), + lists:reverse(M, []); +rukeymerge_1(_Index, [_|_]=L1, []) -> + L1; +rukeymerge_1(_Index, [], [_|_]=L2) -> + L2; +rukeymerge_1(_Index, [], []) -> + []. -spec keymap(Fun, N, TupleList1) -> TupleList2 when Fun :: fun((Term1 :: term()) -> Term2 :: term()), @@ -1160,19 +1204,33 @@ sort(Fun, [X, Y | T]) -> A :: term(), B :: term(). -merge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) -> +merge(Fun, L1, L2) when is_function(Fun, 2) -> + merge_1(Fun, L1, L2). + +merge_1(Fun, [_|_]=T1, [H2 | T2]) -> lists:reverse(fmerge2_1(T1, H2, Fun, T2, []), []); -merge(Fun, T1, []) when is_function(Fun, 2) -> - T1. +merge_1(_Fun, [_|_]=L1, []) -> + L1; +merge_1(_Fun, [], [_|_]=L2) -> + L2; +merge_1(_Fun, [], []) -> + []. %% reverse(rmerge(F,reverse(A),reverse(B))) is equal to merge(F,A,B). -spec rmerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)]. -rmerge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) -> +rmerge(Fun, L1, L2) when is_function(Fun, 2) -> + rmerge_1(Fun, L1, L2). + +rmerge_1(Fun, [_|_]=T1, [H2 | T2]) -> lists:reverse(rfmerge2_1(T1, H2, Fun, T2, []), []); -rmerge(Fun, T1, []) when is_function(Fun, 2) -> - T1. +rmerge_1(_Fun, [_|_]=L1, []) -> + L1; +rmerge_1(_Fun, [], [_|_]=L2) -> + L2; +rmerge_1(_Fun, [], []) -> + []. -spec usort(Fun, List1) -> List2 when Fun :: fun((T, T) -> boolean()), @@ -1213,19 +1271,33 @@ usort_1(Fun, X, [Y | L]) -> A :: term(), B :: term(). -umerge(Fun, [], T2) when is_function(Fun, 2) -> - T2; -umerge(Fun, [H1 | T1], T2) when is_function(Fun, 2) -> - lists:reverse(ufmerge2_2(H1, T1, Fun, T2, []), []). +umerge(Fun, L1, L2) when is_function(Fun, 2) -> + umerge_1(Fun, L1, L2). + +umerge_1(Fun, [H1 | T1], [_|_]=T2) -> + lists:reverse(ufmerge2_2(H1, T1, Fun, T2, []), []); +umerge_1(_Fun, [_|_]=L1, []) -> + L1; +umerge_1(_Fun, [], [_|_]=L2) -> + L2; +umerge_1(_Fun, [], []) -> + []. %% reverse(rumerge(F,reverse(A),reverse(B))) is equal to umerge(F,A,B). -spec rumerge(fun((X, Y) -> boolean()), [X], [Y]) -> [(X | Y)]. -rumerge(Fun, T1, []) when is_function(Fun, 2) -> - T1; -rumerge(Fun, T1, [H2 | T2]) when is_function(Fun, 2) -> - lists:reverse(rufmerge2_1(T1, H2, Fun, T2, []), []). +rumerge(Fun, L1, L2) when is_function(Fun, 2) -> + rumerge_1(Fun, L1, L2). + +rumerge_1(Fun, [_|_]=T1, [H2 | T2]) -> + lists:reverse(rufmerge2_1(T1, H2, Fun, T2, []), []); +rumerge_1(_Fun, [_|_]=L1, []) -> + L1; +rumerge_1(_Fun, [], [_|_]=L2) -> + L2; +rumerge_1(_Fun, [], []) -> + []. %% usort(List) -> L %% sorts the list L, removes duplicates @@ -1310,12 +1382,22 @@ umerge(L) -> Y :: term(), Z :: term(). -umerge3(L1, [], L3) -> - umerge(L1, L3); -umerge3(L1, L2, []) -> - umerge(L1, L2); -umerge3(L1, [H2 | T2], [H3 | T3]) -> - lists:reverse(umerge3_1(L1, [H2 | H3], T2, H2, [], T3, H3), []). +umerge3([_|_]=L1, [H2 | T2], [H3 | T3]) -> + lists:reverse(umerge3_1(L1, [H2 | H3], T2, H2, [], T3, H3), []); +umerge3([_|_]=L1, [_|_]=L2, []) -> + umerge(L1, L2); +umerge3([_|_]=L1, [], [_|_]=L3) -> + umerge(L1, L3); +umerge3([_|_]=L1, [], []) -> + L1; +umerge3([], [_|_]=L2, [_|_]=L3) -> + umerge(L2, L3); +umerge3([], [_|_]=L2, []) -> + L2; +umerge3([], [], [_|_]=L3) -> + L3; +umerge3([], [], []) -> + []. %% rumerge3(X, Y, Z) -> L %% merges three reversed sorted lists X, Y and Z without duplicates, @@ -1323,12 +1405,22 @@ umerge3(L1, [H2 | T2], [H3 | T3]) -> -spec rumerge3([X], [Y], [Z]) -> [(X | Y | Z)]. -rumerge3(L1, [], L3) -> - rumerge(L1, L3); -rumerge3(L1, L2, []) -> - rumerge(L1, L2); -rumerge3(L1, [H2 | T2], [H3 | T3]) -> - lists:reverse(rumerge3_1(L1, T2, H2, [], T3, H3),[]). +rumerge3([_|_]=L1, [H2 | T2], [H3 | T3]) -> + lists:reverse(rumerge3_1(L1, T2, H2, [], T3, H3),[]); +rumerge3([_|_]=L1, [_|_]=L2, []) -> + rumerge(L1, L2); +rumerge3([_|_]=L1, [], [_|_]=L3) -> + rumerge(L1, L3); +rumerge3([_|_]=L1, [], []) -> + L1; +rumerge3([], [_|_]=L2, [_|_]=L3) -> + rumerge(L2, L3); +rumerge3([], [_|_]=L2, []) -> + L2; +rumerge3([], [], [_|_]=L3) -> + L3; +rumerge3([], [], []) -> + []. %% umerge(X, Y) -> L %% merges two sorted lists X and Y without duplicates, removes duplicates @@ -1340,10 +1432,14 @@ rumerge3(L1, [H2 | T2], [H3 | T3]) -> X :: term(), Y :: term(). -umerge([], T2) -> - T2; -umerge([H1 | T1], T2) -> - lists:reverse(umerge2_2(T1, T2, [], H1), []). +umerge([H1 | T1], [_|_]=T2) -> + lists:reverse(umerge2_2(T1, T2, [], H1), []); +umerge([_|_]=L1, []) -> + L1; +umerge([], [_|_]=L2) -> + L2; +umerge([], []) -> + []. %% rumerge(X, Y) -> L %% merges two reversed sorted lists X and Y without duplicates, @@ -1353,10 +1449,14 @@ umerge([H1 | T1], T2) -> -spec rumerge([X], [Y]) -> [(X | Y)]. -rumerge(T1, []) -> - T1; -rumerge(T1, [H2 | T2]) -> - lists:reverse(rumerge2_1(T1, T2, [], H2), []). +rumerge([_|_]=T1, [H2 | T2]) -> + lists:reverse(rumerge2_1(T1, T2, [], H2), []); +rumerge([_|_]=L1, []) -> + L1; +rumerge([], [_|_]=L2) -> + L2; +rumerge([], []) -> + []. %% all(Predicate, List) %% any(Predicate, List) @@ -1789,24 +1889,24 @@ split_2_1(X, Y, [], R, Rs, S) -> %% merge/1 -mergel([[] | L], Acc) -> - mergel(L, Acc); -mergel([T1, [H2 | T2], [H3 | T3] | L], Acc) -> - mergel(L, [merge3_1(T1, [], H2, T2, H3, T3) | Acc]); -mergel([T1, [H2 | T2]], Acc) -> - rmergel([merge2_1(T1, H2, T2, []) | Acc], []); -mergel([L], []) -> - L; -mergel([L], Acc) -> - rmergel([lists:reverse(L, []) | Acc], []); mergel([], []) -> []; +mergel([[_|_]=L], []) -> + L; mergel([], Acc) -> rmergel(Acc, []); -mergel([A, [] | L], Acc) -> +mergel([[] | L], Acc) -> + mergel(L, Acc); +mergel([[_|_]=L], Acc) -> + rmergel([lists:reverse(L, []) | Acc], []); +mergel([[_|_]=A, [] | L], Acc) -> mergel([A | L], Acc); -mergel([A, B, [] | L], Acc) -> - mergel([A, B | L], Acc). +mergel([[_|_]=A, [_|_]=B, [] | L], Acc) -> + mergel([A, B | L], Acc); +mergel([[_|_]=T1, [H2 | T2], [H3 | T3] | L], Acc) -> + mergel(L, [merge3_1(T1, [], H2, T2, H3, T3) | Acc]); +mergel([[_|_]=T1, [H2 | T2]], Acc) -> + rmergel([merge2_1(T1, H2, T2, []) | Acc], []). rmergel([[H3 | T3], [H2 | T2], T1 | L], Acc) -> rmergel(L, [rmerge3_1(T1, [], H2, T2, H3, T3) | Acc]); @@ -2022,28 +2122,28 @@ usplit_2_1(X, Y, [], R, Rs, S) -> umergel(L) -> umergel(L, [], asc). +umergel([], [], _O) -> + []; +umergel([[_|_]=L], [], _O) -> + L; +umergel([], Acc, O) -> + rumergel(Acc, [], O); +umergel([[_|_]=L], Acc, O) -> + rumergel([lists:reverse(L, []) | Acc], [], O); umergel([[] | L], Acc, O) -> umergel(L, Acc, O); -umergel([T1, [H2 | T2], [H3 | T3] | L], Acc, asc) -> - umergel(L, [umerge3_1(T1, [H2 | H3], T2, H2, [], T3, H3) | Acc], asc); -umergel([[H3 | T3], [H2 | T2], T1 | L], Acc, desc) -> - umergel(L, [umerge3_1(T1, [H2 | H3], T2, H2, [], T3, H3) | Acc], desc); -umergel([A, [] | L], Acc, O) -> +umergel([[_|_]=A, [] | L], Acc, O) -> umergel([A | L], Acc, O); -umergel([A, B, [] | L], Acc, O) -> +umergel([[_|_]=A, [_|_]=B, [] | L], Acc, O) -> umergel([A, B | L], Acc, O); -umergel([[H1 | T1], T2 | L], Acc, asc) -> +umergel([[_|_]=T1, [H2 | T2], [H3 | T3] | L], Acc, asc) -> + umergel(L, [umerge3_1(T1, [H2 | H3], T2, H2, [], T3, H3) | Acc], asc); +umergel([[H3 | T3], [H2 | T2], [_|_]=T1 | L], Acc, desc) -> + umergel(L, [umerge3_1(T1, [H2 | H3], T2, H2, [], T3, H3) | Acc], desc); +umergel([[H1 | T1], [_|_]=T2 | L], Acc, asc) -> umergel(L, [umerge2_2(T1, T2, [], H1) | Acc], asc); -umergel([T2, [H1 | T1] | L], Acc, desc) -> - umergel(L, [umerge2_2(T1, T2, [], H1) | Acc], desc); -umergel([L], [], _O) -> - L; -umergel([L], Acc, O) -> - rumergel([lists:reverse(L, []) | Acc], [], O); -umergel([], [], _O) -> - []; -umergel([], Acc, O) -> - rumergel(Acc, [], O). +umergel([[_|_]=T2, [H1 | T1] | L], Acc, desc) -> + umergel(L, [umerge2_2(T1, T2, [], H1) | Acc], desc). rumergel([[H3 | T3], [H2 | T2], T1 | L], Acc, asc) -> rumergel(L, [rumerge3_1(T1, T2, H2, [], T3, H3) | Acc], asc); diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl index b5cbcd98c7..792a94702a 100644 --- a/lib/stdlib/test/lists_SUITE.erl +++ b/lib/stdlib/test/lists_SUITE.erl @@ -441,6 +441,8 @@ keyreplace(Config) when is_list(Config) -> merge(Config) when is_list(Config) -> + Singleton = id([a, b, c]), + %% merge list of lists [] = lists:merge([]), [] = lists:merge([[]]), @@ -463,6 +465,33 @@ merge(Config) when is_list(Config) -> Seq = lists:seq(1,100), true = Seq == lists:merge(lists:map(fun(E) -> [E] end, Seq)), + true = erts_debug:same(Singleton, lists:merge([Singleton])), + true = erts_debug:same(Singleton, lists:merge([Singleton, []])), + true = erts_debug:same(Singleton, lists:merge([[], Singleton])), + true = erts_debug:same(Singleton, lists:merge([Singleton, [], []])), + true = erts_debug:same(Singleton, lists:merge([[], Singleton, []])), + true = erts_debug:same(Singleton, lists:merge([[], [], Singleton])), + + {'EXIT', _} = (catch lists:merge([a])), + {'EXIT', _} = (catch lists:merge([a, b])), + {'EXIT', _} = (catch lists:merge([a, []])), + {'EXIT', _} = (catch lists:merge([[], b])), + {'EXIT', _} = (catch lists:merge([a, [1, 2, 3]])), + {'EXIT', _} = (catch lists:merge([[1, 2, 3], b])), + {'EXIT', _} = (catch lists:merge([a, b, c])), + {'EXIT', _} = (catch lists:merge([a, b, []])), + {'EXIT', _} = (catch lists:merge([a, [], c])), + {'EXIT', _} = (catch lists:merge([a, [], []])), + {'EXIT', _} = (catch lists:merge([[], b, c])), + {'EXIT', _} = (catch lists:merge([[], b, []])), + {'EXIT', _} = (catch lists:merge([[], [], c])), + {'EXIT', _} = (catch lists:merge([a, b, [1, 2, 3]])), + {'EXIT', _} = (catch lists:merge([a, [1, 2, 3], c])), + {'EXIT', _} = (catch lists:merge([a, [1, 2, 3], [4, 5, 6]])), + {'EXIT', _} = (catch lists:merge([[1, 2, 3], b, c])), + {'EXIT', _} = (catch lists:merge([[1, 2, 3], b, [4, 5, 6]])), + {'EXIT', _} = (catch lists:merge([[1, 2, 3], [4, 5, 6], c])), + Two = [1,2], Six = [1,2,3,4,5,6], @@ -482,6 +511,15 @@ merge(Config) when is_list(Config) -> [1,2,3,4,5,7] = lists:merge([2,4], [1,3,5,7]), [1,2,3,4,5,6,7] = lists:merge([2,4,6], [1,3,5,7]), + true = erts_debug:same(Singleton, lists:merge([], Singleton)), + true = erts_debug:same(Singleton, lists:merge(Singleton, [])), + + {'EXIT', _} = (catch lists:merge(a, b)), + {'EXIT', _} = (catch lists:merge(a, [])), + {'EXIT', _} = (catch lists:merge([], b)), + {'EXIT', _} = (catch lists:merge(a, [1, 2, 3])), + {'EXIT', _} = (catch lists:merge([1, 2, 3], b)), + %% 3-way merge [] = lists:merge3([], [], []), Two = lists:merge3([], [], Two), @@ -498,11 +536,28 @@ merge(Config) when is_list(Config) -> Nine = lists:merge3([7,8,9],[4,5,6],[1,2,3]), Nine = lists:merge3([4,5,6],[7,8,9],[1,2,3]), + true = erts_debug:same(Singleton, lists:merge3([], [], Singleton)), + true = erts_debug:same(Singleton, lists:merge3([], Singleton, [])), + true = erts_debug:same(Singleton, lists:merge3(Singleton, [], [])), + + {'EXIT', _} = (catch lists:merge3(a, b, c)), + {'EXIT', _} = (catch lists:merge3(a, b, [])), + {'EXIT', _} = (catch lists:merge3(a, [], c)), + {'EXIT', _} = (catch lists:merge3(a, [], [])), + {'EXIT', _} = (catch lists:merge3([], b, [])), + {'EXIT', _} = (catch lists:merge3([], [], c)), + {'EXIT', _} = (catch lists:merge3(a, b, [1, 2, 3])), + {'EXIT', _} = (catch lists:merge3(a, [1, 2, 3], c)), + {'EXIT', _} = (catch lists:merge3(a, [1, 2, 3], [4, 5, 6])), + {'EXIT', _} = (catch lists:merge3([1, 2, 3], b, [4, 5, 6])), + {'EXIT', _} = (catch lists:merge3([1, 2, 3], [4, 5, 6], c)), + ok. %% reverse merge functions rmerge(Config) when is_list(Config) -> + Singleton = id([a, b, c]), Two = [2,1], Six = [6,5,4,3,2,1], @@ -522,6 +577,15 @@ rmerge(Config) when is_list(Config) -> [7,5,4,3,2,1] = lists:rmerge([4,2], [7,5,3,1]), [7,6,5,4,3,2,1] = lists:rmerge([6,4,2], [7,5,3,1]), + true = erts_debug:same(Singleton, lists:rmerge([], Singleton)), + true = erts_debug:same(Singleton, lists:rmerge(Singleton, [])), + + {'EXIT', _} = (catch lists:rmerge(a, b)), + {'EXIT', _} = (catch lists:rmerge(a, [])), + {'EXIT', _} = (catch lists:rmerge([], b)), + {'EXIT', _} = (catch lists:rmerge(a, [1, 2, 3])), + {'EXIT', _} = (catch lists:rmerge([1, 2, 3], b)), + Nine = [9,8,7,6,5,4,3,2,1], %% 3-way reversed merge @@ -540,6 +604,22 @@ rmerge(Config) when is_list(Config) -> Nine = lists:rmerge3([9,8,7],[6,5,4],[3,2,1]), Nine = lists:rmerge3([6,5,4],[9,8,7],[3,2,1]), + true = erts_debug:same(Singleton, lists:rmerge3([], [], Singleton)), + true = erts_debug:same(Singleton, lists:rmerge3([], Singleton, [])), + true = erts_debug:same(Singleton, lists:rmerge3(Singleton, [], [])), + + {'EXIT', _} = (catch lists:rmerge3(a, b, c)), + {'EXIT', _} = (catch lists:rmerge3(a, b, [])), + {'EXIT', _} = (catch lists:rmerge3(a, [], c)), + {'EXIT', _} = (catch lists:rmerge3(a, [], [])), + {'EXIT', _} = (catch lists:rmerge3([], b, [])), + {'EXIT', _} = (catch lists:rmerge3([], [], c)), + {'EXIT', _} = (catch lists:rmerge3(a, b, [1, 2, 3])), + {'EXIT', _} = (catch lists:rmerge3(a, [1, 2, 3], c)), + {'EXIT', _} = (catch lists:rmerge3(a, [1, 2, 3], [4, 5, 6])), + {'EXIT', _} = (catch lists:rmerge3([1, 2, 3], b, [4, 5, 6])), + {'EXIT', _} = (catch lists:rmerge3([1, 2, 3], [4, 5, 6], c)), + ok. sort_1(Config) when is_list(Config) -> @@ -640,6 +720,8 @@ usort_1(Conf) when is_list(Conf) -> ok. umerge(Conf) when is_list(Conf) -> + Singleton = id([a, b, c]), + %% merge list of lists [] = lists:umerge([]), [] = lists:umerge([[]]), @@ -663,6 +745,33 @@ umerge(Conf) when is_list(Conf) -> Seq = lists:seq(1,100), true = Seq == lists:umerge(lists:map(fun(E) -> [E] end, Seq)), + true = erts_debug:same(Singleton, lists:umerge([Singleton])), + true = erts_debug:same(Singleton, lists:umerge([Singleton, []])), + true = erts_debug:same(Singleton, lists:umerge([[], Singleton])), + true = erts_debug:same(Singleton, lists:umerge([Singleton, [], []])), + true = erts_debug:same(Singleton, lists:umerge([[], Singleton, []])), + true = erts_debug:same(Singleton, lists:umerge([[], [], Singleton])), + + {'EXIT', _} = (catch lists:umerge([a])), + {'EXIT', _} = (catch lists:umerge([a, b])), + {'EXIT', _} = (catch lists:umerge([a, []])), + {'EXIT', _} = (catch lists:umerge([[], b])), + {'EXIT', _} = (catch lists:umerge([a, [1, 2, 3]])), + {'EXIT', _} = (catch lists:umerge([[1, 2, 3], b])), + {'EXIT', _} = (catch lists:umerge([a, b, c])), + {'EXIT', _} = (catch lists:umerge([a, b, []])), + {'EXIT', _} = (catch lists:umerge([a, [], c])), + {'EXIT', _} = (catch lists:umerge([a, [], []])), + {'EXIT', _} = (catch lists:umerge([[], b, c])), + {'EXIT', _} = (catch lists:umerge([[], b, []])), + {'EXIT', _} = (catch lists:umerge([[], [], c])), + {'EXIT', _} = (catch lists:umerge([a, b, [1, 2, 3]])), + {'EXIT', _} = (catch lists:umerge([a, [1, 2, 3], c])), + {'EXIT', _} = (catch lists:umerge([a, [1, 2, 3], [4, 5, 6]])), + {'EXIT', _} = (catch lists:umerge([[1, 2, 3], b, c])), + {'EXIT', _} = (catch lists:umerge([[1, 2, 3], b, [4, 5, 6]])), + {'EXIT', _} = (catch lists:umerge([[1, 2, 3], [4, 5, 6], c])), + Two = [1,2], Six = [1,2,3,4,5,6], @@ -689,6 +798,15 @@ umerge(Conf) when is_list(Conf) -> [1,2,3,4,5,7] = lists:umerge([2,4], [1,2,3,4,5,7]), [1,2,3,4,5,6,7] = lists:umerge([2,4,6], [1,2,3,4,5,6,7]), + true = erts_debug:same(Singleton, lists:umerge([], Singleton)), + true = erts_debug:same(Singleton, lists:umerge(Singleton, [])), + + {'EXIT', _} = (catch lists:umerge(a, b)), + {'EXIT', _} = (catch lists:umerge(a, [])), + {'EXIT', _} = (catch lists:umerge([], b)), + {'EXIT', _} = (catch lists:umerge(a, [1, 2, 3])), + {'EXIT', _} = (catch lists:umerge([1, 2, 3], b)), + %% 3-way unique merge [] = lists:umerge3([], [], []), Two = lists:umerge3([], [], Two), @@ -710,9 +828,27 @@ umerge(Conf) when is_list(Conf) -> [1,2,3] = lists:umerge3([1,2,3],[2,3],[1,2,3]), [1,2,3,4] = lists:umerge3([2,3,4],[3,4],[1,2,3]), + true = erts_debug:same(Singleton, lists:umerge3([], [], Singleton)), + true = erts_debug:same(Singleton, lists:umerge3([], Singleton, [])), + true = erts_debug:same(Singleton, lists:umerge3(Singleton, [], [])), + + {'EXIT', _} = (catch lists:umerge3(a, b, c)), + {'EXIT', _} = (catch lists:umerge3(a, b, [])), + {'EXIT', _} = (catch lists:umerge3(a, [], c)), + {'EXIT', _} = (catch lists:umerge3(a, [], [])), + {'EXIT', _} = (catch lists:umerge3([], b, [])), + {'EXIT', _} = (catch lists:umerge3([], [], c)), + {'EXIT', _} = (catch lists:umerge3(a, b, [1, 2, 3])), + {'EXIT', _} = (catch lists:umerge3(a, [1, 2, 3], c)), + {'EXIT', _} = (catch lists:umerge3(a, [1, 2, 3], [4, 5, 6])), + {'EXIT', _} = (catch lists:umerge3([1, 2, 3], b, [4, 5, 6])), + {'EXIT', _} = (catch lists:umerge3([1, 2, 3], [4, 5, 6], c)), + ok. rumerge(Conf) when is_list(Conf) -> + Singleton = id([a, b, c]), + Two = [2,1], Six = [6,5,4,3,2,1], @@ -739,6 +875,15 @@ rumerge(Conf) when is_list(Conf) -> [7,5,4,3,2,1] = lists:rumerge([4,2], [7,5,4,3,2,1]), [7,6,5,4,3,2,1] = lists:rumerge([6,4,2], [7,6,5,4,3,2,1]), + true = erts_debug:same(Singleton, lists:rumerge([], Singleton)), + true = erts_debug:same(Singleton, lists:rumerge(Singleton, [])), + + {'EXIT', _} = (catch lists:rumerge(a, b)), + {'EXIT', _} = (catch lists:rumerge(a, [])), + {'EXIT', _} = (catch lists:rumerge([], b)), + {'EXIT', _} = (catch lists:rumerge(a, [1, 2, 3])), + {'EXIT', _} = (catch lists:rumerge([1, 2, 3], b)), + Nine = [9,8,7,6,5,4,3,2,1], %% 3-way reversed unique merge @@ -767,6 +912,23 @@ rumerge(Conf) when is_list(Conf) -> true = lists:umerge(L1, L2) == lists:reverse(lists:rumerge(lists:reverse(L1), lists:reverse(L2))), + + true = erts_debug:same(Singleton, lists:rumerge3([], [], Singleton)), + true = erts_debug:same(Singleton, lists:rumerge3([], Singleton, [])), + true = erts_debug:same(Singleton, lists:rumerge3(Singleton, [], [])), + + {'EXIT', _} = (catch lists:rumerge3(a, b, c)), + {'EXIT', _} = (catch lists:rumerge3(a, b, [])), + {'EXIT', _} = (catch lists:rumerge3(a, [], c)), + {'EXIT', _} = (catch lists:rumerge3(a, [], [])), + {'EXIT', _} = (catch lists:rumerge3([], b, [])), + {'EXIT', _} = (catch lists:rumerge3([], [], c)), + {'EXIT', _} = (catch lists:rumerge3(a, b, [1, 2, 3])), + {'EXIT', _} = (catch lists:rumerge3(a, [1, 2, 3], c)), + {'EXIT', _} = (catch lists:rumerge3(a, [1, 2, 3], [4, 5, 6])), + {'EXIT', _} = (catch lists:rumerge3([1, 2, 3], b, [4, 5, 6])), + {'EXIT', _} = (catch lists:rumerge3([1, 2, 3], [4, 5, 6], c)), + ok. %% usort/1 on big randomized lists. @@ -823,6 +985,7 @@ ucheck_stability(L) -> %% Key merge two lists. keymerge(Config) when is_list(Config) -> + Singleton = id([{1, a}, {2, b}, {3, c}]), Two = [{1,a},{2,b}], Six = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}], @@ -851,11 +1014,21 @@ keymerge(Config) when is_list(Config) -> [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] = lists:keymerge(1,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]), + true = erts_debug:same(Singleton, lists:keymerge(1, Singleton, [])), + true = erts_debug:same(Singleton, lists:keymerge(1, [], Singleton)), + + {'EXIT', _} = (catch lists:keymerge(1, a, b)), + {'EXIT', _} = (catch lists:keymerge(1, a, [])), + {'EXIT', _} = (catch lists:keymerge(1, [], b)), + {'EXIT', _} = (catch lists:keymerge(1, a, [{1, a}, {2, b}, {3, c}])), + {'EXIT', _} = (catch lists:keymerge(1, [{1, a}, {2, b}, {3, c}], b)), + ok. %% Reverse key merge two lists. rkeymerge(Config) when is_list(Config) -> + Singleton = id([{1, a}, {2, b}, {3, c}]), Two = [{2,b},{1,a}], Six = [{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}], @@ -888,6 +1061,15 @@ rkeymerge(Config) when is_list(Config) -> lists:reverse(lists:rkeymerge(1,lists:reverse(L1), lists:reverse(L2))), + true = erts_debug:same(Singleton, lists:rkeymerge(1, Singleton, [])), + true = erts_debug:same(Singleton, lists:rkeymerge(1, [], Singleton)), + + {'EXIT', _} = (catch lists:rkeymerge(1, a, b)), + {'EXIT', _} = (catch lists:rkeymerge(1, a, [])), + {'EXIT', _} = (catch lists:rkeymerge(1, [], b)), + {'EXIT', _} = (catch lists:rkeymerge(1, a, [{1, a}, {2, b}, {3, c}])), + {'EXIT', _} = (catch lists:rkeymerge(1, [{1, a}, {2, b}, {3, c}], b)), + ok. keysort_1(Config) when is_list(Config) -> @@ -1006,6 +1188,7 @@ keycompare(I, J, A, B) when element(I, A) == element(I, B), %% Merge two lists while removing duplicates. ukeymerge(Conf) when is_list(Conf) -> + Singleton = id([{1, a}, {2, b}, {3, c}]), Two = [{1,a},{2,b}], Six = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}], @@ -1055,11 +1238,21 @@ ukeymerge(Conf) when is_list(Conf) -> L2 = [{b,1},{b,3},{b,5},{b,7}], L1 = lists:ukeymerge(2, L1, L2), + true = erts_debug:same(Singleton, lists:ukeymerge(1, Singleton, [])), + true = erts_debug:same(Singleton, lists:ukeymerge(1, [], Singleton)), + + {'EXIT', _} = (catch lists:ukeymerge(1, a, b)), + {'EXIT', _} = (catch lists:ukeymerge(1, a, [])), + {'EXIT', _} = (catch lists:ukeymerge(1, [], b)), + {'EXIT', _} = (catch lists:ukeymerge(1, a, [{1, a}, {2, b}, {3, c}])), + {'EXIT', _} = (catch lists:ukeymerge(1, [{1, a}, {2, b}, {3, c}], b)), + ok. %% Reverse merge two lists while removing duplicates. rukeymerge(Conf) when is_list(Conf) -> + Singleton = id([{1, a}, {2, b}, {3, c}]), Two = [{2,b},{1,a}], Six = [{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}], @@ -1109,6 +1302,15 @@ rukeymerge(Conf) when is_list(Conf) -> lists:reverse(lists:rukeymerge(2, lists:reverse(L1), lists:reverse(L2))), + true = erts_debug:same(Singleton, lists:rukeymerge(1, Singleton, [])), + true = erts_debug:same(Singleton, lists:rukeymerge(1, [], Singleton)), + + {'EXIT', _} = (catch lists:rukeymerge(1, a, b)), + {'EXIT', _} = (catch lists:rukeymerge(1, a, [])), + {'EXIT', _} = (catch lists:rukeymerge(1, [], b)), + {'EXIT', _} = (catch lists:rukeymerge(1, a, [{1, a}, {2, b}, {3, c}])), + {'EXIT', _} = (catch lists:rukeymerge(1, [{1, a}, {2, b}, {3, c}], b)), + ok. ukeysort_1(Config) when is_list(Config) -> @@ -1286,6 +1488,7 @@ ukeycompare(I, J, A, B) when A =/= B, %% Merge two lists using a fun. funmerge(Config) when is_list(Config) -> + Singleton = id([a, b, c]), Two = [1,2], Six = [1,2,3,4,5,6], F = fun(X, Y) -> X =< Y end, @@ -1310,11 +1513,21 @@ funmerge(Config) when is_list(Config) -> [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] = lists:merge(F2,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]), + true = erts_debug:same(Singleton, lists:merge(F, Singleton, [])), + true = erts_debug:same(Singleton, lists:merge(F, [], Singleton)), + + {'EXIT', _} = (catch lists:merge(F, a, b)), + {'EXIT', _} = (catch lists:merge(F, a, [])), + {'EXIT', _} = (catch lists:merge(F, [], b)), + {'EXIT', _} = (catch lists:merge(F, a, [1, 2, 3])), + {'EXIT', _} = (catch lists:merge(F, [1, 2, 3], b)), + ok. %% Reverse merge two lists using a fun. rfunmerge(Config) when is_list(Config) -> + Singleton = id([a, b, c]), Two = [2,1], Six = [6,5,4,3,2,1], F = fun(X, Y) -> X =< Y end, @@ -1342,6 +1555,15 @@ rfunmerge(Config) when is_list(Config) -> lists:merge(F2, L1, L2) == lists:reverse(lists:rmerge(F2,lists:reverse(L1), lists:reverse(L2))), + true = erts_debug:same(Singleton, lists:rmerge(F, Singleton, [])), + true = erts_debug:same(Singleton, lists:rmerge(F, [], Singleton)), + + {'EXIT', _} = (catch lists:rmerge(F, a, b)), + {'EXIT', _} = (catch lists:rmerge(F, a, [])), + {'EXIT', _} = (catch lists:rmerge(F, [], b)), + {'EXIT', _} = (catch lists:rmerge(F, a, [1, 2, 3])), + {'EXIT', _} = (catch lists:rmerge(F, [1, 2, 3], b)), + ok. @@ -1411,6 +1633,7 @@ funsort_check(I, Input, Expected) -> %% Merge two lists while removing duplicates using a fun. ufunmerge(Conf) when is_list(Conf) -> + Singleton = id([a, b, c]), Two = [1,2], Six = [1,2,3,4,5,6], F = fun(X, Y) -> X =< Y end, @@ -1445,10 +1668,20 @@ ufunmerge(Conf) when is_list(Conf) -> [{b,2},{e,5},{c,11},{c,12},{c,21},{c,22}] = lists:umerge(F2, [{e,5},{c,11},{c,12}], [{b,2},{c,21},{c,22}]), + true = erts_debug:same(Singleton, lists:umerge(F, Singleton, [])), + true = erts_debug:same(Singleton, lists:umerge(F, [], Singleton)), + + {'EXIT', _} = (catch lists:umerge(F, a, b)), + {'EXIT', _} = (catch lists:umerge(F, a, [])), + {'EXIT', _} = (catch lists:umerge(F, [], b)), + {'EXIT', _} = (catch lists:umerge(F, a, [1, 2, 3])), + {'EXIT', _} = (catch lists:umerge(F, [1, 2, 3], b)), + ok. %% Reverse merge two lists while removing duplicates using a fun. rufunmerge(Conf) when is_list(Conf) -> + Singleton = id([a, b, c]), Two = [2,1], Six = [6,5,4,3,2,1], F = fun(X, Y) -> X =< Y end, @@ -1488,6 +1721,15 @@ rufunmerge(Conf) when is_list(Conf) -> lists:umerge(F2, L3, L4) == lists:reverse(lists:rumerge(F2,lists:reverse(L3), lists:reverse(L4))), + true = erts_debug:same(Singleton, lists:rumerge(F, Singleton, [])), + true = erts_debug:same(Singleton, lists:rumerge(F, [], Singleton)), + + {'EXIT', _} = (catch lists:rumerge(F, a, b)), + {'EXIT', _} = (catch lists:rumerge(F, a, [])), + {'EXIT', _} = (catch lists:rumerge(F, [], b)), + {'EXIT', _} = (catch lists:rumerge(F, a, [1, 2, 3])), + {'EXIT', _} = (catch lists:rumerge(F, [1, 2, 3], b)), + ok. ufunsort_1(Config) when is_list(Config) -> diff --git a/lib/stdlib/test/lists_property_test_SUITE.erl b/lib/stdlib/test/lists_property_test_SUITE.erl index 617fed6af8..4b366d730a 100644 --- a/lib/stdlib/test/lists_property_test_SUITE.erl +++ b/lib/stdlib/test/lists_property_test_SUITE.erl @@ -49,7 +49,7 @@ all() -> keyfind_case, keyfind_absent_case, keymap_case, keymember_case, keymember_absent_case, - keymerge_case, + keymerge_case, keymerge_invalid_case, keyreplace_case, keyreplace_absent_case, keysearch_case, keysearch_absent_case, keysort_case, @@ -61,10 +61,10 @@ all() -> mapfoldr_case, max_case, member_case, member_absent_case, - merge_1_case, - merge_2_case, - merge_3_case, - merge3_case, + merge_1_case, merge_1_invalid_case, + merge_2_case, merge_2_invalid_case, + merge_3_case, merge_3_invalid_case, + merge3_case, merge3_invalid_case, min_case, nth_case, nth_outofrange_case, nthtail_case, nthtail_outofrange_case, @@ -85,12 +85,12 @@ all() -> suffix_case, sum_case, takewhile_case, - ukeymerge_case, + ukeymerge_case, ukeymerge_invalid_case, ukeysort_case, - umerge_1_case, - umerge_2_case, - umerge_3_case, - umerge3_case, + umerge_1_case, umerge_1_invalid_case, + umerge_2_case, umerge_2_invalid_case, + umerge_3_case, umerge_3_invalid_case, + umerge3_case, umerge3_invalid_case, uniq_1_case, uniq_2_case, unzip_case, @@ -213,6 +213,9 @@ keymember_absent_case(Config) -> keymerge_case(Config) -> do_proptest(prop_keymerge, Config). +keymerge_invalid_case(Config) -> + do_proptest(prop_keymerge_invalid, Config). + keyreplace_case(Config) -> do_proptest(prop_keyreplace, Config). @@ -264,15 +267,27 @@ member_absent_case(Config) -> merge_1_case(Config) -> do_proptest(prop_merge_1, Config). +merge_1_invalid_case(Config) -> + do_proptest(prop_merge_1_invalid, Config). + merge_2_case(Config) -> do_proptest(prop_merge_2, Config). +merge_2_invalid_case(Config) -> + do_proptest(prop_merge_2_invalid, Config). + merge_3_case(Config) -> do_proptest(prop_merge_3, Config). +merge_3_invalid_case(Config) -> + do_proptest(prop_merge_3_invalid, Config). + merge3_case(Config) -> do_proptest(prop_merge3, Config). +merge3_invalid_case(Config) -> + do_proptest(prop_merge3_invalid, Config). + min_case(Config) -> do_proptest(prop_min, Config). @@ -348,21 +363,36 @@ takewhile_case(Config) -> ukeymerge_case(Config) -> do_proptest(prop_ukeymerge, Config). +ukeymerge_invalid_case(Config) -> + do_proptest(prop_ukeymerge_invalid, Config). + ukeysort_case(Config) -> do_proptest(prop_ukeysort, Config). umerge_1_case(Config) -> do_proptest(prop_umerge_1, Config). +umerge_1_invalid_case(Config) -> + do_proptest(prop_umerge_1_invalid, Config). + umerge_2_case(Config) -> do_proptest(prop_umerge_2, Config). +umerge_2_invalid_case(Config) -> + do_proptest(prop_umerge_2_invalid, Config). + umerge_3_case(Config) -> do_proptest(prop_umerge_3, Config). +umerge_3_invalid_case(Config) -> + do_proptest(prop_umerge_3_invalid, Config). + umerge3_case(Config) -> do_proptest(prop_umerge3, Config). +umerge3_invalid_case(Config) -> + do_proptest(prop_umerge3_invalid, Config). + uniq_1_case(Config) -> do_proptest(prop_uniq_1, Config). diff --git a/lib/stdlib/test/property_test/lists_prop.erl b/lib/stdlib/test/property_test/lists_prop.erl index 4d5809b262..00b518ff83 100644 --- a/lib/stdlib/test/property_test/lists_prop.erl +++ b/lib/stdlib/test/property_test/lists_prop.erl @@ -513,6 +513,23 @@ prop_keymerge() -> ) ). +prop_keymerge_invalid() -> + ?FORALL( + {N, InList, X, Y}, + ?LET( + N, + range(1, 5), + ?LET( + {L, X, Y}, + {list(gen_tuple(N, N+3)), non_list(), non_list()}, + {N, L, X, Y} + ) + ), + expect_error(fun lists:keymerge/3, [N, InList, Y]) andalso + expect_error(fun lists:keymerge/3, [N, X, InList]) andalso + expect_error(fun lists:keymerge/3, [N, X, Y]) + ). + %% keyreplace/4 prop_keyreplace() -> ?FORALL( @@ -745,6 +762,17 @@ prop_merge_1() -> check_merged(fun erlang:'=<'/2, InLists, lists:merge(InLists)) ). +prop_merge_1_invalid() -> + ?FORALL( + InLists, + ?LET( + {L1, X, L2}, + {list(oneof([non_list(), gen_list()])), non_list(), list(oneof([non_list(), gen_list()]))}, + L1 ++ [X|L2] + ), + expect_error(fun lists:merge/1, [InLists]) + ). + %% merge/2 prop_merge_2() -> ?FORALL( @@ -757,6 +785,15 @@ prop_merge_2() -> check_merged(fun erlang:'=<'/2, [InList1, InList2], lists:merge(InList1, InList2)) ). +prop_merge_2_invalid() -> + ?FORALL( + {InList, X, Y}, + {gen_list(), non_list(), non_list()}, + expect_error(fun lists:merge/2, [InList, X]) andalso + expect_error(fun lists:merge/2, [X, InList]) andalso + expect_error(fun lists:merge/2, [X, Y]) + ). + %% merge/3 prop_merge_3() -> ?FORALL( @@ -769,6 +806,15 @@ prop_merge_3() -> check_merged(SortFn, [InList1, InList2], lists:merge(SortFn, InList1, InList2)) ). +prop_merge_3_invalid() -> + ?FORALL( + {SortFn, InList, X, Y}, + {gen_ordering_fun(), gen_list(), non_list(), non_list()}, + expect_error(fun lists:merge/3, [SortFn, InList, Y]) andalso + expect_error(fun lists:merge/3, [SortFn, X, InList]) andalso + expect_error(fun lists:merge/3, [SortFn, X, Y]) + ). + %% merge3/3 prop_merge3() -> ?FORALL( @@ -781,6 +827,18 @@ prop_merge3() -> check_merged(fun erlang:'=<'/2, [InList1, InList2, InList3], lists:merge3(InList1, InList2, InList3)) ). +prop_merge3_invalid() -> + ?FORALL( + {InList, X, Y, Z}, + {gen_list(), non_list(), non_list(), non_list()}, + expect_error(fun lists:merge/3, [InList, InList, Z]) andalso + expect_error(fun lists:merge/3, [InList, Y, InList]) andalso + expect_error(fun lists:merge/3, [InList, Y, Z]) andalso + expect_error(fun lists:merge/3, [X, InList, Z]) andalso + expect_error(fun lists:merge/3, [X, Y, InList]) andalso + expect_error(fun lists:merge/3, [X, Y, Z]) + ). + %% min/1 prop_min() -> ?FORALL( @@ -1132,6 +1190,23 @@ prop_ukeymerge() -> ) ). +prop_ukeymerge_invalid() -> + ?FORALL( + {N, InList, X, Y}, + ?LET( + N, + range(1, 5), + ?LET( + {L, X, Y}, + {list(gen_tuple(N, N+3)), non_list(), non_list()}, + {N, L, X, Y} + ) + ), + expect_error(fun lists:ukeymerge/3, [N, InList, Y]) andalso + expect_error(fun lists:ukeymerge/3, [N, X, InList]) andalso + expect_error(fun lists:ukeymerge/3, [N, X, Y]) + ). + %% ukeysort/2 prop_ukeysort() -> ?FORALL( @@ -1156,6 +1231,17 @@ prop_umerge_1() -> check_umerged(InLists, lists:umerge(InLists)) ). +prop_umerge_1_invalid() -> + ?FORALL( + InList, + ?LET( + {L1, X, L2}, + {list(oneof([non_list(), gen_list()])), non_list(), list(oneof([non_list(), gen_list()]))}, + L1 ++ [X|L2] + ), + expect_error(fun lists:umerge/1, [InList]) + ). + %% umerge/2 prop_umerge_2() -> ?FORALL( @@ -1168,6 +1254,15 @@ prop_umerge_2() -> check_umerged([InList1, InList2], lists:umerge(InList1, InList2)) ). +prop_umerge_2_invalid() -> + ?FORALL( + {InList, X, Y}, + {gen_list(), non_list(), non_list()}, + expect_error(fun lists:umerge/2, [InList, Y]) andalso + expect_error(fun lists:umerge/2, [X, InList]) andalso + expect_error(fun lists:umerge/2, [X, Y]) + ). + %% umerge/3 prop_umerge_3() -> ?FORALL( @@ -1180,6 +1275,15 @@ prop_umerge_3() -> check_umerged(SortFn, [InList1, InList2], lists:umerge(SortFn, InList1, InList2)) ). +prop_umerge_3_invalid() -> + ?FORALL( + {SortFn, InList, X, Y}, + {gen_ordering_fun(), gen_list(), non_list(), non_list()}, + expect_error(fun lists:umerge/3, [SortFn, InList, Y]) andalso + expect_error(fun lists:umerge/3, [SortFn, X, InList]) andalso + expect_error(fun lists:umerge/3, [SortFn, X, Y]) + ). + %% umerge3/3 prop_umerge3() -> ?FORALL( @@ -1192,6 +1296,19 @@ prop_umerge3() -> check_umerged([InList1, InList2, InList3], lists:umerge3(InList1, InList2, InList3)) ). +prop_umerge3_invalid() -> + ?FORALL( + {InList, X, Y, Z}, + {gen_list(), non_list(), non_list(), non_list()}, + expect_error(fun lists:umerge3/3, [InList, InList, Z]) andalso + expect_error(fun lists:umerge3/3, [InList, Y, InList]) andalso + expect_error(fun lists:umerge3/3, [InList, Y, Z]) andalso + expect_error(fun lists:umerge3/3, [X, InList, InList]) andalso + expect_error(fun lists:umerge3/3, [X, InList, Z]) andalso + expect_error(fun lists:umerge3/3, [X, Y, InList]) andalso + expect_error(fun lists:umerge3/3, [X, Y, Z]) + ). + %% uniq/1 prop_uniq_1() -> ?FORALL( @@ -1530,6 +1647,9 @@ prop_zipwith3_5() -> %%% Generators %%% %%%%%%%%%%%%%%%%%% +non_list() -> + ?SUCHTHAT(NonList, gen_any(), not is_list(NonList)). + %% Generator for lists of the given type, folding the given function %% over values on the top level as they are generated. The first generated %% value serves as the initial accumulator. @@ -1739,6 +1859,17 @@ gen_ordering_fun() -> %%% Helpers %%% %%%%%%%%%%%%%%% +%% -------------------------------------------------------------------- +expect_error(Fn, Args) when is_function(Fn, length(Args))-> + try + erlang:apply(Fn, Args) + of + _ -> false + catch + error:_ -> true; + _:_ -> false + end. + %% -------------------------------------------------------------------- check_appended([], []) -> true; -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor