Skip to content

Commit

Permalink
Fix failing proper test
Browse files Browse the repository at this point in the history
  • Loading branch information
Laszlo Toth authored and Laszlo Toth committed Jun 6, 2020
1 parent bc982c1 commit f3a99b2
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 11 deletions.
10 changes: 7 additions & 3 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@

{project_plugins, [rebar3_lint, rebar3_proper]}.

{alias, [{test, [eunit, cover, dialyzer,
{ct, "--cover"},
xref, lint, edoc]}]}.
{alias, [{test, [eunit,
dialyzer,
cover,
proper,
xref,
lint,
edoc]}]}.

{erl_opts, [warn_unused_vars,
warn_export_all,
Expand Down
56 changes: 54 additions & 2 deletions src/maps_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
]).

%% exported for eunit only
-export([get_val/2]).
-export([get_val/2,
sort_remove_operators/1]).

-type op() :: move | rename | remove | add.
-type path_el() :: {Key :: term(), list | map}.
Expand Down Expand Up @@ -144,7 +145,8 @@ update(Key, Map, New, UpdateFun) ->
Data :: term(),
Diff :: list(diff_operator()),
Res :: term().
apply_diff(Data, Diff) ->
apply_diff(Data, Diff0) ->
Diff = sort_remove_operators(Diff0),
lists:foldl(fun apply_op/2, Data, Diff).

%%==============================================================================
Expand All @@ -164,10 +166,60 @@ get_val(Lst, [{Idx, list} | T]) when is_list(Lst) ->
get_val(Map, [{Key, map} | T]) when is_map(Map) ->
get_val(maps:get(Key, Map), T).

-spec sort_remove_operators(Diff) -> Res when
Diff :: list(diff_operator()),
Res :: list(diff_operator()).
sort_remove_operators(Diff) ->
filtered_sort(Diff, fun is_remove_operator/1,
fun compare_remove_operators/2).

%%==============================================================================
%% Internal functions
%%==============================================================================

%%
%% Sort only filtered elements of the list. FilterFun is used to select
%% some matching elements. Those selected elements will be sorted. Order
%% of other elements will remain the same. For example sort only positive numbers:
%% filtered_sort([0, 2, 0, 1, 0, 3],
%% fun(A) -> A > 0 end,
%% fun(A, B) -> A < B end) ->
%% [0, 1, 0, 2, 0, 3]
%%
-spec filtered_sort(List, FilterFun, SortFun) -> Res when
List :: list(),
FilterFun :: fun((term()) -> boolean()),
SortFun :: fun((term(), term()) -> boolean()),
Res :: list().
filtered_sort(Lst, FilterFun, SortFun) ->
Length = length(Lst),
IndexedLst = lists:zip(lists:seq(1, Length), Lst),
Filtered = lists:filter(fun({_Idx, El}) -> FilterFun(El) end,
IndexedLst),
{FilteredIdxs, FilteredEls} = lists:unzip(Filtered),
Sorted = lists:sort(SortFun, FilteredEls),
FilteredWithIdxs = lists:zip(FilteredIdxs, Sorted),
Remaining = IndexedLst -- Filtered,
AllSorted = lists:sort(fun({Idx1, _}, {Idx2, _}) -> Idx1 < Idx2 end,
FilteredWithIdxs ++ Remaining),
{_, Result} = lists:unzip(AllSorted),
Result.

-spec is_remove_operator(Op) -> Res when
Op :: diff_operator(),
Res :: boolean().
is_remove_operator(#{op := remove}) ->
true;
is_remove_operator(_Op) ->
false.

-spec compare_remove_operators(Op1, Op2) -> Res when
Op1 :: diff_operator(),
Op2 :: diff_operator(),
Res :: boolean().
compare_remove_operators(#{path := Path1}, #{path := Path2}) ->
Path1 > Path2.

-spec apply_op(Diff, Data) -> Res when
Diff :: diff_operator(),
Data :: term(),
Expand Down
18 changes: 18 additions & 0 deletions test/maps_utils_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,24 @@ get_val_test() ->
?assertEqual(1, maps_utils:get_val([[1, 2], [3, 4]],
[{0, list}, {0, list}])).

sort_operators_test() ->
?assertEqual(
[
#{op => add, path => [{1, list}]},
#{op => remove, path => [{0, list}, {2, list}]},
#{op => remove, path => [{0, list}, {1, list}]},
#{op => add, path => [{2, list}]},
#{op => remove, path => [{0, list}, {0, list}]}
],
maps_utils:sort_remove_operators(
[
#{op => add, path => [{1, list}]},
#{op => remove, path => [{0, list}, {0, list}]},
#{op => remove, path => [{0, list}, {2, list}]},
#{op => add, path => [{2, list}]},
#{op => remove, path => [{0, list}, {1, list}]}
])).

%%==============================================================================
%% Performance tests
%%==============================================================================
Expand Down
15 changes: 9 additions & 6 deletions test/prop_maps_utils_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
%% Properties
%%==============================================================================

%%------------------------------------------------------------------------------
%% prop_diff_and_apply_diff
%%------------------------------------------------------------------------------
prop_diff_and_apply_diff(doc) ->
"Test if Diff = diff(D1, D2), D2 == apply_diff(D1, Diff) is true";
"Test whether Diff = diff(D1, D2), D2 == apply_diff(D1, Diff) is always true";
prop_diff_and_apply_diff(opts) ->
[{numtests, 10000}].
[{numtests, 1000}].

prop_diff_and_apply_diff() ->
?FORALL({D1, D2}, {map_like_data(), map_like_data()},
Expand All @@ -44,7 +47,7 @@ prop_diff_and_apply_diff() ->

-spec map_like_data() -> proplists:proplist().
map_like_data() ->
?LET(List, ?SIZED(Size, map_like_data(Size div 3)),
?LET(List, ?SIZED(Size, map_like_data(Size div 5)),
unique_keys(List, [], [], 1)).

%%==============================================================================
Expand All @@ -57,8 +60,8 @@ map_like_data(0) ->
map_like_data(Size) ->
list(
frequency([
{8, {key(), oneof([1, 2, 3])}},
{2, {key(), list(integer())}},
{9, {key(), oneof([1, 2, 3])}},
{4, {key(), list(integer())}},
{1, {key(), map_like_data(Size - 1)}}
])).

Expand All @@ -76,7 +79,7 @@ unique_keys([{_Key, Value} | T], Acc, Path, Index) ->
unique_key(Path, Index) ->
PostFix = string:join(
[integer_to_list(El) || El <- lists:reverse([Index | Path])], "_"),
list_to_atom("key_" ++ PostFix).
list_to_binary("key_" ++ PostFix).

key() ->
oneof([key1, key2, key3, key4, key5, key6]).
Expand Down

0 comments on commit f3a99b2

Please sign in to comment.