% Copyright (C) 2003-2019 Olivier Boudeville
%
% This file is part of the Ceylan-Myriad library.
%
% This library is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License or
% the GNU General Public License, as they are published by the Free Software
% Foundation, either version 3 of these Licenses, or (at your option)
% any later version.
% You can also redistribute it and/or modify it under the terms of the
% Mozilla Public License, version 1.1 or later.
%
% This library is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU Lesser General Public License and the GNU General Public License
% for more details.
%
% You should have received a copy of the GNU Lesser General Public
% License, of the GNU General Public License and of the Mozilla Public License
% along with this library.
% If not, see and
% .
%
% Author: Olivier Boudeville [olivier (dot) boudeville (at) esperide (dot) com]
% Unit tests for the list management utilities.
%
% See the list_utils.erl tested module.
%
-module(list_utils_test).
% For run/0 export and al:
-include("test_facilities.hrl").
-spec run() -> no_return().
run() ->
test_facilities:start( ?MODULE ),
% Testing list management:
L = [ 12, 4, 13, 2, 56, 0 ],
GetIndex = 3,
GetValue = list_utils:get_element_at( L, GetIndex ),
test_facilities:display( "Getting item #~B of list ~w: ~B.",
[ GetIndex, L, GetValue ] ),
13 = GetValue,
%OutOfBoundsIndex = 0,
%OutOfBoundsIndex = 100,
%test_facilities:display( " Getting item #~B of list ~w: ~B.",
% [ OutOfBoundsIndex, L,
% list_utils:get_element_at( L, OutOfBoundsIndex ) ] ),
{ a, [] } = list_utils:extract_element_at( [ a ], 1 ),
{ b, [ a, c ] } = list_utils:extract_element_at( [ a, b, c ], 2 ),
RemoveIndex = 3,
ShortenList = list_utils:remove_element_at( L, RemoveIndex ),
test_facilities:display(
"List obtained after having removed item #~B of list ~w: ~w.",
[ RemoveIndex, L, ShortenList ] ),
% Hardcoded for checking:
CorrectShortenList = [ 12, 4, 2, 56, 0 ],
ShortenList = CorrectShortenList,
[ 12, 4, 2, 56 ] = list_utils:remove_last_element( CorrectShortenList ),
{ 0, [ 12, 4, 13, 2, 56 ] } = list_utils:extract_last_element( L ),
1 = list_utils:get_index_of( 12, CorrectShortenList ),
2 = list_utils:get_index_of( 4, CorrectShortenList ),
5 = list_utils:get_index_of( 0, CorrectShortenList ),
try
list_utils:get_index_of( 42, CorrectShortenList ),
throw( { test_failed, get_index_of, 42 } )
catch { non_existing_element, 42 } ->
ok
end,
%OutOfBoundsIndex = 0,
%OutOfBoundsIndex = 100,
%test_facilities:display( " List obtained after having removed item #~B
% of list ~w: "
% " ~w.", [ OutOfBoundsIndex, L,
% list_utils:remove_element_at( L, OutOfBoundsIndex ) ] ),
L1 = [ 1, 2, 3, 4, 2 ],
L2 = [ 2, 3 ],
Subtracted = list_utils:subtract_all_duplicates( L1, L2 ),
test_facilities:display( "Displaying the subtraction with "
"duplicates removal of ~w by ~w: ~w.", [ L1, L2, Subtracted ] ),
[ 1, 4 ] = Subtracted,
%list_utils:delete_existing( non_existing, L1 ),
% Checks order, removal of first matching only:
[ 1, 3, 4, 2 ] = list_utils:delete_existing( 2, L1 ),
L3 = [ a, b, c, b, b, d, e ],
[ a, c, b, b, d, e ] = list_utils:delete_if_existing( b, L3 ),
not_found = list_utils:delete_if_existing( not_existing, L3 ),
% Checks order, removal of all matching elements:
[ 1, 3, 4 ] = list_utils:delete_all_in( 2, L1 ),
true = list_utils:is_list_of_integers( [ 1, 2, 3 ] ),
true = list_utils:is_list_of_integers( [] ),
true = list_utils:is_list_of_integers( "This is a trap!" ),
false = list_utils:is_list_of_integers( [ 1, 2, 3.0 ] ),
false = list_utils:is_list_of_integers( a ),
true = list_utils:unordered_compare( [], [] ),
true = list_utils:unordered_compare( [a,b], [a,b] ),
true = list_utils:unordered_compare( [a,b], [b,a] ),
false = list_utils:unordered_compare( [a,b], [a,c] ),
false = list_utils:unordered_compare( [a,b], [a] ),
[ a, b, [ c, d ], e ] = list_utils:flatten_once(
[ [ a ], [ b, [ c, d ] ], [ e ] ] ),
[ a, b, c ] = list_utils:filter_out_undefined(
[ undefined, a, b, undefined, c, undefined ] ),
{ 3, 2 } = list_utils:determine_tuple_info(
[ { a, 1 }, { b, 1 }, { c, 2 } ] ),
{ 2, 3 } = list_utils:determine_tuple_info(
[ { a, 1, 3 }, { b, 1, 0 } ] ),
{ [], [ a, b, c, d, e ] } = list_utils:split_at( [ a, b, c, d, e ], 0 ),
{ [ c, b, a ], [ d, e] } = list_utils:split_at( [ a, b, c, d, e ], 3 ),
{ [ e, d, c, b, a ], [] } = list_utils:split_at( [ a, b, c, d, e ], 100 ),
Uniquified = list_utils:uniquify( L1 ),
test_facilities:display( "Displaying a uniquified version of ~w: ~w.",
[ L1, Uniquified ] ),
% Supposedly the order will be consistent, although this is not requested:
[ 3, 2, 1, 4 ] = Uniquified,
false = list_utils:has_duplicates( [] ),
false = list_utils:has_duplicates( [ 1, 2 ] ),
true = list_utils:has_duplicates( [ 1, 2, 1 ] ),
DupList1 = [],
Dup1 = list_utils:get_duplicates( DupList1 ),
io:format( "Duplicates in ~w are ~w.~n", [ DupList1, Dup1 ] ),
[] = Dup1,
false = list_utils:has_duplicates( DupList1 ),
DupList2 = [ a, b, c ],
Dup2 = list_utils:get_duplicates( DupList2 ),
io:format( "Duplicates in ~w are ~w.~n", [ DupList2, Dup2 ] ),
[] = Dup2,
false = list_utils:has_duplicates( DupList2 ),
DupList3 = [ a, a, b, b, b, c, c, c ],
Dup3 = list_utils:get_duplicates( DupList3 ),
io:format( "Duplicates in ~w are ~w.~n", [ DupList3, Dup3 ] ),
[ {b,3}, {c,3}, {a,2} ] = Dup3,
true = list_utils:has_duplicates( DupList3 ),
DupList4 = [ a, b, a, a, c ],
Dup4 = list_utils:get_duplicates( DupList4 ),
io:format( "Duplicates in ~w are ~w.~n", [ DupList4, Dup4 ] ),
[ {a,3} ] = Dup4,
true = list_utils:has_duplicates( DupList4 ),
DupList5 = [ a, b, c, d, b, d, a, b, e, f, f ],
Dup5 = list_utils:get_duplicates( DupList5 ),
io:format( "Duplicates in ~w are ~w.~n", [ DupList5, Dup5 ] ),
[ {d,2}, {b,3}, {f,2}, {a,2} ] = Dup5,
true = list_utils:has_duplicates( DupList5 ),
List1 = [ a, b, 1, c, 14 ],
List2 = [ 14, d, b ],
ExpectedList = lists:sort( [ 14, b ] ),
ResultList = list_utils:intersection( List1, List2 ),
test_facilities:display( "Displaying the intersection of ~p and ~p: ~p.",
[ List1, List2, ResultList ] ),
ExpectedList = lists:sort( ResultList ),
TupleList = [ { 1, 2, 3 }, { 4, 5, 6 } ],
FlattenedList = [ 1, 2, 3, 4, 5, 6 ],
FlattenedList = list_utils:flatten_tuples( TupleList ),
TupleList = list_utils:reconstruct_tuples( FlattenedList, _TupleSize=3 ),
DrawCount = 3,
test_facilities:display( "Drawing ~B elements from ~w: ~w.",
[ DrawCount, L, list_utils:draw_elements_from( List1, DrawCount ) ] ),
ASeed = { 113, 798, 8914 },
random_utils:reset_random_source( ASeed ),
Lpermuted = list_utils:random_permute( L ),
test_facilities:display(
"List obtained after having uniformly permuted list ~w: ~w.",
[ L, Lpermuted ] ),
test_facilities:display(
"List obtained after having uniformly permuted list ~w (again): ~w.",
[ L, list_utils:random_permute( Lpermuted ) ] ),
random_utils:reset_random_source( ASeed ),
Lreciprocal = list_utils:random_permute_reciprocal( Lpermuted ),
test_facilities:display( "List obtained after having restored the random "
"state and performed a reciprocal permutation on "
"~w: ~w.",
[ Lpermuted, Lreciprocal ] ),
% Must match:
L = Lreciprocal,
DrawList = [ {first,1}, {second,2}, {third,1} ],
test_facilities:display( "Drawing an element from ~w, got: '~w'.",
[ DrawList, list_utils:draw_element_weighted( DrawList ) ] ),
test_facilities:display( "Drawing an element from ~w, got: '~w'.",
[ DrawList, list_utils:draw_element_weighted( DrawList ) ] ),
test_facilities:display( "Drawing an element from ~w, got: '~w'.",
[ DrawList, list_utils:draw_element_weighted( DrawList ) ] ),
%ProbabilityCount = 2000,
ProbabilityCount = 50,
FirstProbabilityList = [ {first,1}, {second,0}, {third,1} ],
NoSecondList = [ list_utils:draw_element_weighted( FirstProbabilityList )
|| _X <- lists:seq( 1, ProbabilityCount ) ],
test_facilities:display(
"List obtained after ~B drawings in following probability table: ~w "
"is ~w; frequency dispatching: ~w.",
[ ProbabilityCount, FirstProbabilityList, NoSecondList,
list_utils:get_duplicates( NoSecondList ) ] ),
SecondProbabilityList = [ {first,1}, {second,2}, {third,1} ],
SecondTwiceList = [ list_utils:draw_element_weighted(
SecondProbabilityList ) || _X <- lists:seq( 1, ProbabilityCount ) ],
test_facilities:display(
"List obtained after ~B drawings in following probability table: ~w "
"is ~w; frequency dispatching: ~w.",
[ ProbabilityCount, SecondProbabilityList, SecondTwiceList,
list_utils:get_duplicates( SecondTwiceList ) ] ),
test_facilities:stop().