1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2017-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(iovec_SUITE). 22 23-export([all/0, suite/0, init_per_suite/1, end_per_suite/1]). 24 25-export([integer_lists/1, binary_lists/1, empty_lists/1, empty_binary_lists/1, 26 mixed_lists/1, improper_lists/1, illegal_lists/1, cons_bomb/1, 27 sub_binary_lists/1, iolist_to_iovec_idempotence/1, 28 iolist_to_iovec_correctness/1, unaligned_sub_binaries/1, 29 direct_binary_arg/1]). 30 31-include_lib("common_test/include/ct.hrl"). 32 33suite() -> 34 [{ct_hooks,[ts_install_cth]}, 35 {timetrap, {minutes, 2}}]. 36 37all() -> 38 [integer_lists, binary_lists, empty_lists, empty_binary_lists, mixed_lists, 39 sub_binary_lists, illegal_lists, improper_lists, cons_bomb, 40 iolist_to_iovec_idempotence, iolist_to_iovec_correctness, 41 unaligned_sub_binaries, direct_binary_arg]. 42 43init_per_suite(Config) -> 44 Config. 45 46end_per_suite(Config) -> 47 application:stop(os_mon), 48 Config. 49 50integer_lists(Config) when is_list(Config) -> 51 Variations = gen_variations([I || I <- lists:seq(1, 255)]), 52 equivalence_test(fun erlang:iolist_to_iovec/1, Variations). 53 54sub_binary_lists(Config) when is_list(Config) -> 55 Parent = <<0:256/unit:8, "gazurka">>, 56 <<0:196/unit:8, Child/binary>> = Parent, 57 equivalence_test(fun erlang:iolist_to_iovec/1, gen_variations(Child)). 58 59binary_lists(Config) when is_list(Config) -> 60 Variations = gen_variations([<<I:8>> || I <- lists:seq(1, 255)]), 61 equivalence_test(fun erlang:iolist_to_iovec/1, Variations). 62 63empty_lists(Config) when is_list(Config) -> 64 Variations = gen_variations([[] || _ <- lists:seq(1, 256)]), 65 equivalence_test(fun erlang:iolist_to_iovec/1, Variations), 66 [] = erlang:iolist_to_iovec([]), 67 ok. 68 69empty_binary_lists(Config) when is_list(Config) -> 70 Variations = gen_variations([<<>> || _ <- lists:seq(1, 8192)]), 71 equivalence_test(fun erlang:iolist_to_iovec/1, Variations), 72 [] = erlang:iolist_to_iovec(Variations), 73 ok. 74 75mixed_lists(Config) when is_list(Config) -> 76 Variations = gen_variations([<<>>, lists:seq(1, 40), <<12, 45, 78>>]), 77 equivalence_test(fun erlang:iolist_to_iovec/1, Variations). 78 79illegal_lists(Config) when is_list(Config) -> 80 BitStrs = gen_variations(["gurka", <<1:1>>, "gaffel"]), 81 BadInts = gen_variations(["gurka", 890, "gaffel"]), 82 Atoms = gen_variations([gurka, "gaffel"]), 83 BadTails = [["test" | 0], ["gurka" | gaffel], ["gaffel" | <<1:1>>]], 84 85 Variations = 86 BitStrs ++ BadInts ++ Atoms ++ BadTails, 87 88 illegality_test(fun erlang:iolist_to_iovec/1, Variations). 89 90improper_lists(Config) when is_list(Config) -> 91 Variations = [ 92 [[[[1 | <<2>>] | <<3>>] | <<4>>] | <<5>>], 93 [[<<1>>, 2] | <<3, 4, 5>>], 94 [1, 2, 3 | <<4, 5>>] 95 ], 96 equivalence_test(fun erlang:iolist_to_iovec/1, Variations). 97 98cons_bomb(Config) when is_list(Config) -> 99 IntBase = gen_variations([I || I <- lists:seq(1, 255)]), 100 BinBase = gen_variations([<<I:8>> || I <- lists:seq(1, 255)]), 101 MixBase = gen_variations([<<12, 45, 78>>, lists:seq(1, 255)]), 102 103 Variations = gen_variations([IntBase, BinBase, MixBase], 16), 104 equivalence_test(fun erlang:iolist_to_iovec/1, Variations). 105 106iolist_to_iovec_idempotence(Config) when is_list(Config) -> 107 IntVariations = gen_variations([I || I <- lists:seq(1, 255)]), 108 BinVariations = gen_variations([<<I:8>> || I <- lists:seq(1, 255)]), 109 MixVariations = gen_variations([<<12, 45, 78>>, lists:seq(1, 255)]), 110 111 Variations = [IntVariations, BinVariations, MixVariations], 112 Optimized = erlang:iolist_to_iovec(Variations), 113 114 true = Optimized =:= erlang:iolist_to_iovec(Optimized), 115 ok. 116 117iolist_to_iovec_correctness(Config) when is_list(Config) -> 118 IntVariations = gen_variations([I || I <- lists:seq(1, 255)]), 119 BinVariations = gen_variations([<<I:8>> || I <- lists:seq(1, 255)]), 120 MixVariations = gen_variations([<<12, 45, 78>>, lists:seq(1, 255)]), 121 122 Variations = [IntVariations, BinVariations, MixVariations], 123 Optimized = erlang:iolist_to_iovec(Variations), 124 125 true = is_iolist_equal(Optimized, Variations), 126 ok. 127 128unaligned_sub_binaries(Config) when is_list(Config) -> 129 UnalignedBins = [gen_unaligned_binary(I) || I <- lists:seq(32, 4 bsl 10, 512)], 130 UnalignedVariations = gen_variations(UnalignedBins), 131 132 Optimized = erlang:iolist_to_iovec(UnalignedVariations), 133 134 true = is_iolist_equal(Optimized, UnalignedVariations), 135 ok. 136 137direct_binary_arg(Config) when is_list(Config) -> 138 {'EXIT',{badarg, _}} = (catch erlang:iolist_to_iovec(<<1:1>>)), 139 [<<1>>] = erlang:iolist_to_iovec(<<1>>), 140 [] = erlang:iolist_to_iovec(<<>>), 141 ok. 142 143illegality_test(Fun, Variations) -> 144 [{'EXIT',{badarg, _}} = (catch Fun(Variation)) || Variation <- Variations], 145 ok. 146 147equivalence_test(Fun, [Head | _] = Variations) -> 148 %% Check that each variation is equal to the others, and that the sum of 149 %% them is equal to the input. 150 Comparand = Fun(Head), 151 [true = is_iolist_equal(Comparand, Fun(V)) || V <- Variations], 152 true = is_iolist_equal(Variations, Fun(Variations)), 153 ok. 154 155is_iolist_equal(A, B) -> 156 iolist_to_binary(A) =:= iolist_to_binary(B). 157 158gen_unaligned_binary(Size) -> 159 Bin0 = << <<I>> || I <- lists:seq(1, Size) >>, 160 <<0:3,Bin:Size/binary,31:5>> = id(<<0:3,Bin0/binary,31:5>>), 161 Bin. 162 163id(I) -> I. 164 165%% Generates a bunch of lists whose contents will be equal to Base repeated a 166%% few times. The lists only differ by their structure, so their reduction to 167%% a simpler format should yield the same result. 168gen_variations(Base) -> 169 gen_variations(Base, 12). 170gen_variations(Base, N) -> 171 [gen_flat_list(Base, N), 172 gen_nested_list(Base, N), 173 gen_nasty_list(Base, N)]. 174 175gen_flat_list(Base, N) -> 176 lists:flatten(gen_nested_list(Base, N)). 177 178gen_nested_list(Base, N) -> 179 [Base || _ <- lists:seq(1, N)]. 180 181gen_nasty_list(Base, N) -> 182 gen_nasty_list_1(gen_nested_list(Base, N), []). 183gen_nasty_list_1([], Result) -> 184 Result; 185gen_nasty_list_1([Head | Base], Result) when is_list(Head) -> 186 gen_nasty_list_1(Base, [[Result], [gen_nasty_list_1(Head, [])]]); 187gen_nasty_list_1([Head | Base], Result) -> 188 gen_nasty_list_1(Base, [[Result], [Head]]). 189