1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2019. 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(bs_size_expr_SUITE).
22-compile(nowarn_shadow_vars).
23
24-export([all/0,suite/0,groups/0,init_per_suite/1, end_per_suite/1,
25         init_per_group/2,end_per_group/2,
26         init_per_testcase/2,end_per_testcase/2,
27         basic/1,size_shadow/1,complex/1,
28         recv/1,no_match/1]).
29
30suite() ->
31    [{ct_hooks,[ts_install_cth]},
32     {timetrap,{minutes,1}}].
33
34all() ->
35    [{group,p}].
36
37groups() ->
38    [{p,test_lib:parallel(),
39      [basic,
40       size_shadow,
41       complex,
42       recv,
43       no_match]}].
44
45init_per_suite(Config) ->
46    test_lib:recompile(?MODULE),
47    Config.
48
49end_per_suite(_Config) ->
50    ok.
51
52init_per_group(_GroupName, Config) ->
53    Config.
54
55end_per_group(_GroupName, Config) ->
56    Config.
57
58init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
59    Config.
60
61end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
62    ok.
63
64basic(_Config) ->
65    <<>> = do_basic(<<1:32>>),
66    <<"abcd">> = do_basic(<<2:32,"abcd">>),
67    no_match = do_basic(<<0:32>>),
68    no_match = do_basic(<<777:32>>),
69    ok.
70
71do_basic(Bin) ->
72    Res = do_basic_1(Bin),
73
74    Res = do_basic_2({tag,Bin}),
75    Res = do_basic_2([list,Bin]),
76    6 = do_basic_2({2,4}),
77
78    Res = do_basic_3(Bin),
79    Res = do_basic_4(Bin),
80
81    {result,Res} = do_basic_5(Bin),
82    case Res of
83        no_match ->
84            ok;
85        _ ->
86            {result,{Res,7777777}} = do_basic_5(<<Bin/binary,7777777:32>>)
87    end,
88
89    Res.
90
91do_basic_1(<<Sz:32,Tail:(4*Sz-4)/binary>>) ->
92    Tail;
93do_basic_1(<<_/binary>>) ->
94    no_match.
95
96do_basic_2({tag,<<Sz:32,Tail:(4*Sz-4)/binary>>}) ->
97    Tail;
98do_basic_2([list,<<Sz:32,Tail:((Sz-1)*4)/binary>>]) ->
99    Tail;
100do_basic_2({A,B}) when is_integer(A), is_integer(B) ->
101    A + B;
102do_basic_2(_) ->
103    no_match.
104
105do_basic_3(Bin) ->
106    WordSize = id(4),
107    case Bin of
108        <<Sz:32,Tail:(WordSize*Sz-WordSize)/binary>> ->
109            Tail;
110        _ ->
111            no_match
112    end.
113
114do_basic_4(Bin) ->
115    WordSize = id(4),
116    F = fun() ->
117                case Bin of
118                    <<Sz:32,Tail:(WordSize*Sz-WordSize)/binary>> ->
119                        Tail;
120                    _ ->
121                        no_match
122                end
123        end,
124    F().
125
126do_basic_5(Bin) ->
127    WordSize = id(4),
128    F = fun() ->
129                Res = case Bin of
130                          <<Sz:32,Tail:(WordSize*Sz-WordSize)/binary,More:(8*WordSize)>> ->
131                              {Tail,More};
132                          <<Sz:32,Tail:(WordSize*Sz-WordSize)/binary>> ->
133                              Tail;
134                          _ ->
135                              no_match
136                      end,
137                {result,Res}
138        end,
139    F().
140
141size_shadow(_Config) ->
142    12345678 = size_shadow_1(),
143    ok.
144
145size_shadow_1() ->
146    L = 8,
147    Offset = 16,
148    Fs = [fun(<<L:L,B:(L+16)>>) -> B end,
149          fun(<<L:L,B:(L+Offset)>>) -> B end,
150          fun(A) ->
151                  Res = (fun([<<L:L,B:(L+16)>>]) -> B end)([A]),
152                  Res = (fun([<<L:L,B:(L+Offset)>>]) -> B end)([A])
153          end,
154          fun(A) ->
155                  Res = (fun({<<L:L,B:(L+16)>>,<<L:L,B:(L+16)>>}) -> B end)({A,A}),
156                  Res = (fun({<<L:L,B:(L+Offset)>>,<<L:L,B:(L+16)>>}) -> B end)({A,A}),
157                  Res = (fun({<<L:L,B:(L+16)>>,<<L:L,B:(L+Offset)>>}) -> B end)({A,A}),
158                  Res = (fun({<<L:L,B:(L+Offset)>>,<<L:L,B:(L+Offset)>>}) -> B end)({A,A})
159          end,
160          fun(A) ->
161                  <<Size:L,_/bits>> = A,
162                  Inner = fun([L], {#{key1 := <<L:L,B:(L+Offset)>>,
163                                      key2 := <<L:L,B:(L+Offset)>>}, L}) -> B end,
164                  Inner([Size], {#{key1 => A,key2 => A},Size})
165          end],
166    size_shadow_apply(Fs, <<16:8, 12345678:32>>).
167
168size_shadow_apply([F|Fs], Arg) when is_function(F, 1) ->
169    size_shadow_apply(Fs, Arg, F(Arg)).
170
171size_shadow_apply([F|Fs], Arg, Res) when is_function(F, 1) ->
172    Res = F(Arg),
173    size_shadow_apply(Fs, Arg, Res);
174size_shadow_apply([], _, Res) ->
175    Res.
176
177-record(r, {a,b,c}).
178complex(Config) ->
179    (fun() ->
180             Len = length(id(Config)),
181             Bin = << <<I:13>> || I <- lists:seq(1, Len) >>,
182             <<Bin:(length(Config))/binary-unit:13>> = Bin
183     end)(),
184
185    (fun() ->
186             V = id([a,b,c]),
187             F = fun(<<V:(bit_size(<<0:(length(V))>>)*8)/signed-integer>>) ->
188                         V;
189                    ({A,B}) ->
190                         A + B
191                 end,
192             -1 = F(<<-1:(length(V)*8)>>),
193             7 = F({3,4})
194     end)(),
195
196    (fun() ->
197             A = a,
198             B = b,
199             F = fun(<<A:16,B:16,C:(A+B),D/bits>>) ->
200                         {A,B,C,D};
201                    (<<A:16,B:16>>) ->
202                         {A,B};
203                    (<<A:8,B:8>>) ->
204                         {A,B}
205                 end,
206             {13,21,16#cafebeef,<<"more">>} = F(<<13:16,21:16,16#cafebeef:34,"more">>),
207             {100,500} = F(<<100:16,500:16>>),
208             {157,77} = F(<<157:8,77:8>>),
209             {A,B}
210     end)(),
211
212    (fun() ->
213             Two = id(2),
214             F = fun(a, <<_:(#r.a - Two)/binary,Int:8,_/binary>>) -> Int;
215                    (b, <<_:(#r.b - Two)/binary,Int:8,_/binary>>) -> Int;
216                    (c, <<_:(#r.c - Two)/binary,Int:8,_/binary>>) -> Int
217                 end,
218             1 = F(a, <<1,2,3>>),
219             2 = F(b, <<1,2,3>>),
220             3 = F(c, <<1,2,3>>)
221     end)(),
222
223    (fun() ->
224             Bin = <<1,2,3,4>>,
225             F = fun(R) ->
226                         <<First:(R#r.a)/binary,Tail/binary>> = Bin,
227                         {First,Tail}
228                 end,
229             {<<>>,<<1,2,3,4>>} = F(#r{a=0}),
230             {<<1>>,<<2,3,4>>} = F(#r{a=1}),
231             {<<1,2>>,<<3,4>>} = F(#r{a=2}),
232             {<<1,2,3>>,<<4>>} = F(#r{a=3}),
233             {<<1,2,3,4>>,<<>>} = F(#r{a=4})
234     end)(),
235
236    [] = fun() ->
237                 case day of
238                     V0 -> ok
239                 end,
240                 %% A bug in v3_core prevented V0 as being seen as used,
241                 %% and because of that, V0 would not be exported from the
242                 %% case above.
243                 [0 || <<42:(V0#{key => value})>> <- []]
244         end(),
245
246    ok.
247
248recv(_Config) ->
249    R = fun(Msg) ->
250                self() ! Msg,
251                Res = receive
252                          <<L,I:(L-1)/unit:8,X:32>> -> {I,X};
253                          <<L,I:(L-1)/unit:8,X:64>> -> {I,X}
254                      end,
255                self() ! {tag,[Msg]},
256                Res = receive
257                          {tag,[<<L,I:(8*(L-1)),X:32>>]} -> {I,X};
258                          {tag,[<<L,I:(8*(L-1)),X:64>>]} -> {I,X}
259                      end
260        end,
261    {1234,16#deadbeef} = R(<<3,1234:16,16#deadbeef:32>>),
262    {99,16#cafebeeff00d} = R(<<2,99:8,16#cafebeeff00d:64>>),
263    ok.
264
265no_match(_Config) ->
266    B = id(<<1,2,3,4>>),
267    no_match = case B of
268                   <<Int:(bit_size(B)-1)>> -> Int;
269                   <<Int:(bit_size(B)*2)>> -> Int;
270                   <<Int:(length(B))>> -> Int;
271                   _ -> no_match
272               end,
273    no_match = case B of
274                   <<L:8,Int2:(is_integer(L))>> -> Int2;
275                   <<L:8,Int2:(L+3.0)>> -> Int2;
276                   _ -> no_match
277               end,
278
279    no_match = case B of
280                   <<Int3:(1/0)>> -> Int3;
281                   _ -> no_match
282               end,
283
284    no_match = case B of
285                   <<Int4:all>> -> Int4;
286                   <<Int4:bad_size>> -> Int4;
287                   _ -> no_match
288               end,
289
290    [] = [X || <<X:(is_list(B))/binary>> <= B],
291    <<>> = << <<X:32>> || <<X:(is_list(B))/binary>> <= B >>,
292
293    ok.
294
295id(I) ->
296    I.
297