%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2019. All Rights Reserved.
%%
%% 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.
%%
%% %CopyrightEnd%
%%
-module(small_SUITE).
-export([all/0, suite/0]).
-export([edge_cases/1]).
-include_lib("common_test/include/ct.hrl").
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap, {minutes, 1}}].
all() ->
[edge_cases].
edge_cases(Config) when is_list(Config) ->
{MinSmall, MaxSmall} = Limits = determine_small_limits(0),
ct:pal("Limits = ~p", [Limits]),
true = (MaxSmall + 1) =:= MaxSmall + id(1),
true = (MinSmall - 1) =:= MinSmall - id(1),
true = (MaxSmall + 1) > id(MaxSmall),
true = (MinSmall - 1) < id(MinSmall),
-1 = MinSmall + id(MaxSmall),
-1 = MaxSmall + id(MinSmall),
false = is_small(MinSmall * -1),
false = is_small(MinSmall - id(1)),
false = is_small(MinSmall - 1),
false = is_small(MaxSmall + id(1)),
Lower = lists:seq(MinSmall, MinSmall + 128),
Upper = lists:seq(MaxSmall, MaxSmall - 128, -1),
Pow2 = seq_pow2(MinSmall, MaxSmall),
NearZero = lists:seq(-128, 128),
ok = test_combinations([Lower, Upper, Pow2, NearZero], MinSmall, MaxSmall),
ok.
test_combinations([As | Rest]=TestVectors, MinS, MaxS) ->
[begin
_ = [arith_test(A, B, MinS, MaxS) || B <- Bs]
end || A <- As, Bs <- TestVectors],
test_combinations(Rest, MinS, MaxS);
test_combinations([], _MinS, _MaxS) ->
ok.
%% Builds a sequence of all powers of 2 between MinSmall and MaxSmall
seq_pow2(MinSmall, MaxSmall) ->
sp2_1(MinSmall, MinSmall, MaxSmall).
sp2_1(N, _MinS, MaxS) when N >= MaxS ->
[];
sp2_1(-1, MinS, MaxS) ->
[-1 | sp2_1(1, MinS, MaxS)];
sp2_1(N, MinS, MaxS) when N < 0 ->
[N | sp2_1(N bsr 1, MinS, MaxS)];
sp2_1(N, MinS, MaxS) when N > 0 ->
[N | sp2_1(N bsl 1, MinS, MaxS)].
arith_test(A, B, MinS, MaxS) ->
verify_kind(A + B, MinS, MaxS),
verify_kind(B + A, MinS, MaxS),
verify_kind(A - B, MinS, MaxS),
verify_kind(B - A, MinS, MaxS),
verify_kind(A * B, MinS, MaxS),
verify_kind(B * A, MinS, MaxS),
true = A + B =:= apply(erlang, id('+'), [A, B]),
true = A - B =:= apply(erlang, id('-'), [A, B]),
true = A * B =:= apply(erlang, id('*'), [A, B]),
true = A + B =:= B + id(A),
true = A - B =:= A + id(-B),
true = B - A =:= B + id(-A),
true = A * B =:= B * id(A),
true = B =:= 0 orelse ((A * B) div id(B) =:= A),
true = A =:= 0 orelse ((B * A) div id(A) =:= B),
ok.
%% Verifies that N is a small when it should be
verify_kind(N, MinS, MaxS) ->
true = is_small(N) =:= (N >= MinS andalso N =< MaxS).
is_small(N) when is_integer(N) ->
0 =:= erts_debug:flat_size(N).
determine_small_limits(N) ->
case is_small(-1 bsl N) of
true -> determine_small_limits(N + 1);
false -> {-1 bsl (N - 1), (1 bsl (N - 1)) - 1}
end.
id(I) -> I.