blob: 612499c4d40423178bdaff1b7ebff03bcda7cedc [file] [log] [blame]
% Licensed under the Apache License, Version 2.0 (the "License"); you may not
% use this file except in compliance with the License. You may obtain a copy of
% the License at
%
% http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
% License for the specific language governing permissions and limitations under
% the License.
-module(mem3_ring_prop_tests).
-ifdef(WITH_PROPER).
-include_lib("couch/include/couch_eunit_proper.hrl").
property_test_() ->
?EUNIT_QUICKCHECK(60).
% Properties
prop_get_ring_with_connected_intervals() ->
?FORALL(
{Start, End},
oneof(ranges()),
?FORALL(
Intervals,
g_connected_intervals(Start, End),
mem3_util:get_ring(Intervals, Start, End) =:= lists:sort(Intervals)
)
).
prop_get_ring_connected_plus_random_intervals() ->
?FORALL(
{Intervals, Extra},
{g_connected_intervals(1, 100), g_random_intervals(1, 100)},
?IMPLIES(
sets:is_disjoint(endpoints(Intervals), endpoints(Extra)),
begin
AllInts = Intervals ++ Extra,
Ring = mem3_util:get_ring(AllInts, 1, 100),
Ring =:= lists:sort(Intervals)
end
)
).
prop_get_ring_connected_with_sub_intervals() ->
?FORALL(
Intervals,
g_connected_intervals(1, 100),
?FORALL(
SubIntervals,
g_subintervals(Intervals),
begin
AllInts = Intervals ++ SubIntervals,
Ring = mem3_util:get_ring(AllInts, 1, 100),
Ring =:= lists:sort(Intervals)
end
)
).
prop_get_ring_with_disconnected_intervals() ->
?FORALL(
{Start, End},
oneof(ranges()),
?FORALL(
Intervals,
g_disconnected_intervals(Start, End),
mem3_util:get_ring(Intervals, Start, End) =:= []
)
).
% Generators
ranges() ->
[{1, 10}, {0, 2 bsl 31 - 1}, {2 bsl 31 - 10, 2 bsl 31 - 1}].
g_connected_intervals(Begin, End) ->
?SIZED(Size, g_connected_intervals(Begin, End, 5 * Size)).
g_connected_intervals(Begin, End, Split) when Begin =< End ->
?LET(
N,
choose(0, Split),
begin
if
N == 0 ->
[{Begin, End}];
N > 0 ->
Ns = lists:seq(1, N - 1),
Bs = lists:usort([rand_range(Begin, End) || _ <- Ns]),
Es = [B - 1 || B <- Bs],
test_util:shuffle(lists:zip([Begin] ++ Bs, Es ++ [End]))
end
end
).
g_non_trivial_connected_intervals(Begin, End, Split) ->
?SUCHTHAT(
Connected,
g_connected_intervals(Begin, End, Split),
length(Connected) > 1
).
g_disconnected_intervals(Begin, End) ->
?SIZED(Size, g_disconnected_intervals(Begin, End, Size)).
g_disconnected_intervals(Begin, End, Split) when Begin =< End ->
?LET(
Connected,
g_non_trivial_connected_intervals(Begin, End, Split),
begin
I = rand:uniform(length(Connected)) - 1,
{Before, [_ | After]} = lists:split(I, Connected),
Before ++ After
end
).
g_subintervals(Intervals) ->
lists:foldl(fun(R, Acc) -> split_interval(R) ++ Acc end, [], Intervals).
split_interval({B, E}) when E - B >= 2 ->
E1 = rand_range(B, E) - 1,
B1 = E1 + 1,
[{B, E1}, {B1, E}];
split_interval(_Range) ->
[].
g_random_intervals(Start, End) ->
?LET(
N,
choose(1, 10),
begin
[
begin
B = rand_range(Start, End),
E = rand_range(B, End),
{B, E}
end
|| _ <- lists:seq(1, N)
]
end
).
rand_range(B, B) ->
B;
rand_range(B, E) ->
B + rand:uniform(E - B).
endpoints(Ranges) ->
{Begins, Ends} = lists:unzip(Ranges),
sets:from_list(Begins ++ Ends).
-endif.