%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2017-2018. 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(iovec_SUITE). -export([all/0, suite/0, init_per_suite/1, end_per_suite/1]). -export([integer_lists/1, binary_lists/1, empty_lists/1, empty_binary_lists/1, mixed_lists/1, improper_lists/1, illegal_lists/1, cons_bomb/1, sub_binary_lists/1, iolist_to_iovec_idempotence/1, iolist_to_iovec_correctness/1, unaligned_sub_binaries/1, direct_binary_arg/1]). -include_lib("common_test/include/ct.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap, {minutes, 2}}]. all() -> [integer_lists, binary_lists, empty_lists, empty_binary_lists, mixed_lists, sub_binary_lists, illegal_lists, improper_lists, cons_bomb, iolist_to_iovec_idempotence, iolist_to_iovec_correctness, unaligned_sub_binaries, direct_binary_arg]. init_per_suite(Config) -> Config. end_per_suite(Config) -> application:stop(os_mon), Config. integer_lists(Config) when is_list(Config) -> Variations = gen_variations([I || I <- lists:seq(1, 255)]), equivalence_test(fun erlang:iolist_to_iovec/1, Variations). sub_binary_lists(Config) when is_list(Config) -> Parent = <<0:256/unit:8, "gazurka">>, <<0:196/unit:8, Child/binary>> = Parent, equivalence_test(fun erlang:iolist_to_iovec/1, gen_variations(Child)). binary_lists(Config) when is_list(Config) -> Variations = gen_variations([<> || I <- lists:seq(1, 255)]), equivalence_test(fun erlang:iolist_to_iovec/1, Variations). empty_lists(Config) when is_list(Config) -> Variations = gen_variations([[] || _ <- lists:seq(1, 256)]), equivalence_test(fun erlang:iolist_to_iovec/1, Variations), [] = erlang:iolist_to_iovec([]), ok. empty_binary_lists(Config) when is_list(Config) -> Variations = gen_variations([<<>> || _ <- lists:seq(1, 8192)]), equivalence_test(fun erlang:iolist_to_iovec/1, Variations), [] = erlang:iolist_to_iovec(Variations), ok. mixed_lists(Config) when is_list(Config) -> Variations = gen_variations([<<>>, lists:seq(1, 40), <<12, 45, 78>>]), equivalence_test(fun erlang:iolist_to_iovec/1, Variations). illegal_lists(Config) when is_list(Config) -> BitStrs = gen_variations(["gurka", <<1:1>>, "gaffel"]), BadInts = gen_variations(["gurka", 890, "gaffel"]), Atoms = gen_variations([gurka, "gaffel"]), BadTails = [["test" | 0], ["gurka" | gaffel], ["gaffel" | <<1:1>>]], Variations = BitStrs ++ BadInts ++ Atoms ++ BadTails, illegality_test(fun erlang:iolist_to_iovec/1, Variations). improper_lists(Config) when is_list(Config) -> Variations = [ [[[[1 | <<2>>] | <<3>>] | <<4>>] | <<5>>], [[<<1>>, 2] | <<3, 4, 5>>], [1, 2, 3 | <<4, 5>>] ], equivalence_test(fun erlang:iolist_to_iovec/1, Variations). cons_bomb(Config) when is_list(Config) -> IntBase = gen_variations([I || I <- lists:seq(1, 255)]), BinBase = gen_variations([<> || I <- lists:seq(1, 255)]), MixBase = gen_variations([<<12, 45, 78>>, lists:seq(1, 255)]), Variations = gen_variations([IntBase, BinBase, MixBase], 16), equivalence_test(fun erlang:iolist_to_iovec/1, Variations). iolist_to_iovec_idempotence(Config) when is_list(Config) -> IntVariations = gen_variations([I || I <- lists:seq(1, 255)]), BinVariations = gen_variations([<> || I <- lists:seq(1, 255)]), MixVariations = gen_variations([<<12, 45, 78>>, lists:seq(1, 255)]), Variations = [IntVariations, BinVariations, MixVariations], Optimized = erlang:iolist_to_iovec(Variations), true = Optimized =:= erlang:iolist_to_iovec(Optimized), ok. iolist_to_iovec_correctness(Config) when is_list(Config) -> IntVariations = gen_variations([I || I <- lists:seq(1, 255)]), BinVariations = gen_variations([<> || I <- lists:seq(1, 255)]), MixVariations = gen_variations([<<12, 45, 78>>, lists:seq(1, 255)]), Variations = [IntVariations, BinVariations, MixVariations], Optimized = erlang:iolist_to_iovec(Variations), true = is_iolist_equal(Optimized, Variations), ok. unaligned_sub_binaries(Config) when is_list(Config) -> UnalignedBins = [gen_unaligned_binary(I) || I <- lists:seq(32, 4 bsl 10, 512)], UnalignedVariations = gen_variations(UnalignedBins), Optimized = erlang:iolist_to_iovec(UnalignedVariations), true = is_iolist_equal(Optimized, UnalignedVariations), ok. direct_binary_arg(Config) when is_list(Config) -> {'EXIT',{badarg, _}} = (catch erlang:iolist_to_iovec(<<1:1>>)), [<<1>>] = erlang:iolist_to_iovec(<<1>>), [] = erlang:iolist_to_iovec(<<>>), ok. illegality_test(Fun, Variations) -> [{'EXIT',{badarg, _}} = (catch Fun(Variation)) || Variation <- Variations], ok. equivalence_test(Fun, [Head | _] = Variations) -> %% Check that each variation is equal to the others, and that the sum of %% them is equal to the input. Comparand = Fun(Head), [true = is_iolist_equal(Comparand, Fun(V)) || V <- Variations], true = is_iolist_equal(Variations, Fun(Variations)), ok. is_iolist_equal(A, B) -> iolist_to_binary(A) =:= iolist_to_binary(B). gen_unaligned_binary(Size) -> Bin0 = << <> || I <- lists:seq(1, Size) >>, <<0:3,Bin:Size/binary,31:5>> = id(<<0:3,Bin0/binary,31:5>>), Bin. id(I) -> I. %% Generates a bunch of lists whose contents will be equal to Base repeated a %% few times. The lists only differ by their structure, so their reduction to %% a simpler format should yield the same result. gen_variations(Base) -> gen_variations(Base, 12). gen_variations(Base, N) -> [gen_flat_list(Base, N), gen_nested_list(Base, N), gen_nasty_list(Base, N)]. gen_flat_list(Base, N) -> lists:flatten(gen_nested_list(Base, N)). gen_nested_list(Base, N) -> [Base || _ <- lists:seq(1, N)]. gen_nasty_list(Base, N) -> gen_nasty_list_1(gen_nested_list(Base, N), []). gen_nasty_list_1([], Result) -> Result; gen_nasty_list_1([Head | Base], Result) when is_list(Head) -> gen_nasty_list_1(Base, [[Result], [gen_nasty_list_1(Head, [])]]); gen_nasty_list_1([Head | Base], Result) -> gen_nasty_list_1(Base, [[Result], [Head]]).