1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2004-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%%
22-module(ei_decode_SUITE).
23
24-include_lib("common_test/include/ct.hrl").
25-include("ei_decode_SUITE_data/ei_decode_test_cases.hrl").
26
27-export([all/0, suite/0,
28         init_per_testcase/2,
29         test_ei_decode_long/1,
30         test_ei_decode_ulong/1,
31         test_ei_decode_longlong/1,
32         test_ei_decode_ulonglong/1,
33         test_ei_decode_char/1,
34         test_ei_decode_nonoptimal/1,
35         test_ei_decode_misc/1,
36         test_ei_decode_utf8_atom/1]).
37
38suite() -> [{ct_hooks,[ts_install_cth]}].
39
40all() ->
41    [test_ei_decode_long, test_ei_decode_ulong,
42     test_ei_decode_longlong, test_ei_decode_ulonglong,
43     test_ei_decode_char, test_ei_decode_nonoptimal,
44     test_ei_decode_misc, test_ei_decode_utf8_atom].
45
46init_per_testcase(Case, Config) ->
47    runner:init_per_testcase(?MODULE, Case, Config).
48
49%% ---------------------------------------------------------------------------
50
51% NOTE: for historical reasons we don't pach as tight as we can,
52%       we only fill 27 bits in 32 bit INTEGER_EXT
53
54
55%% ######################################################################## %%
56
57test_ei_decode_long(Config) when is_list(Config) ->
58    P = runner:start(Config, ?test_ei_decode_long),
59    send_integers(P),
60    runner:recv_eot(P),
61    ok.
62
63
64%% ######################################################################## %%
65
66test_ei_decode_ulong(Config) when is_list(Config) ->
67    P = runner:start(Config, ?test_ei_decode_ulong),
68    send_integers(P),
69    runner:recv_eot(P),
70    ok.
71
72
73% (*) In practical terms, other values may fit into the ext format
74% i32 is signed 32 bit on C side
75% u32 is unsigned 32 bit on C side
76
77%% ######################################################################## %%
78
79test_ei_decode_longlong(Config) when is_list(Config) ->
80    case os:type() of
81        vxworks ->
82            {skip,"Skipped on VxWorks"};
83        _ ->
84            P = runner:start(Config, ?test_ei_decode_longlong),
85            send_integers2(P),
86            runner:recv_eot(P),
87            ok
88    end.
89
90
91%% ######################################################################## %%
92
93test_ei_decode_ulonglong(Config) when is_list(Config) ->
94    case os:type() of
95        vxworks ->
96            {skip,"Skipped on VxWorks"};
97        _ ->
98            P = runner:start(Config, ?test_ei_decode_ulonglong),
99            send_integers2(P),
100            runner:recv_eot(P),
101            ok
102    end.
103
104
105%% ######################################################################## %%
106%% A "character" for us is an 8 bit integer, always positive, i.e.
107%% it is unsigned.
108%% FIXME maybe the API should change to use "unsigned char" to be clear?!
109
110test_ei_decode_char(Config) when is_list(Config) ->
111    P = runner:start(Config, ?test_ei_decode_char),
112
113    send_term_as_binary(P,0),
114    send_term_as_binary(P,16#7f),
115    send_term_as_binary(P,16#ff),
116
117    send_term_as_binary(P, []), % illegal type
118
119    runner:recv_eot(P),
120    ok.
121
122
123%% ######################################################################## %%
124
125test_ei_decode_nonoptimal(Config) when is_list(Config) ->
126    P = runner:start(Config, ?test_ei_decode_nonoptimal),
127
128    send_non_optimal_pos(P),			% decode_char
129    send_non_optimal(P),			% decode_long
130    send_non_optimal_pos(P),			% decode_ulong
131    case os:type() of
132        vxworks ->
133            ok;
134        _ ->
135            send_non_optimal(P),			% decode_longlong
136            send_non_optimal_pos(P)			% decode_ulonglong
137    end,
138
139    runner:recv_eot(P),
140    ok.
141
142
143send_non_optimal(P) ->
144    send_non_optimal_pos(P),
145    send_non_optimal_neg(P).
146
147send_non_optimal_pos(P) ->
148    send_raw(P, <<131,97,42>>),
149    send_raw(P, <<131,98,42:32>>),
150    send_raw(P, <<131,110,1,0,42>>),
151    send_raw(P, <<131,110,2,0,42,0>>),
152    send_raw(P, <<131,110,4,0,42,0,0,0>>),
153    send_raw(P, <<131,111,0,0,0,1,0,42>>),
154    send_raw(P, <<131,111,0,0,0,2,0,42,0>>),
155    send_raw(P, <<131,111,0,0,0,3,0,42,0,0>>),
156    send_raw(P, <<131,111,0,0,0,6,0,42,0,0,0,0,0>>),
157    ok.
158
159send_non_optimal_neg(P) ->
160    %   send_raw(P, <<131,97,-42>>),
161    send_raw(P, <<131,98,-42:32>>),
162    send_raw(P, <<131,110,1,1,42>>),
163    send_raw(P, <<131,110,2,1,42,0>>),
164    send_raw(P, <<131,110,4,1,42,0,0,0>>),
165    send_raw(P, <<131,111,0,0,0,1,1,42>>),
166    send_raw(P, <<131,111,0,0,0,2,1,42,0>>),
167    send_raw(P, <<131,111,0,0,0,3,1,42,0,0>>),
168    send_raw(P, <<131,111,0,0,0,6,1,42,0,0,0,0,0>>),
169    ok.
170
171
172%% ######################################################################## %%
173
174test_ei_decode_misc(Config) when is_list(Config) ->
175    P = runner:start(Config, ?test_ei_decode_misc),
176
177    send_term_as_binary(P,0.0),
178    send_term_as_binary(P,-1.0),
179    send_term_as_binary(P,1.0),
180
181    send_term_as_binary(P,false),
182    send_term_as_binary(P,true),
183
184    send_term_as_binary(P,foo),
185    send_term_as_binary(P,''),
186    %%send_term_as_binary(P,'ÅÄÖåäö'),
187    send_latin1_atom_as_binary(P, "ÅÄÖåäö"),
188
189    send_term_as_binary(P,"foo"),
190    send_term_as_binary(P,""),
191    send_term_as_binary(P,"ÅÄÖåäö"),
192
193    send_term_as_binary(P,<<"foo">>),
194    send_term_as_binary(P,<<>>),
195    send_term_as_binary(P,<<"ÅÄÖåäö">>),
196
197    %    send_term_as_binary(P,{}),
198    %    send_term_as_binary(P,[]),
199
200    runner:recv_eot(P),
201    ok.
202
203%% ######################################################################## %%
204
205test_ei_decode_utf8_atom(Config) ->
206    P = runner:start(Config, ?test_ei_decode_utf8_atom),
207
208    send_latin1_atom_as_binary(P,"å"),
209    send_latin1_atom_as_binary(P,"ä"),
210    send_latin1_atom_as_binary(P,"ö"),
211    send_latin1_atom_as_binary(P,"õ"),
212
213    send_utf8_atom_as_binary(P,[1758]),
214    send_utf8_atom_as_binary(P,[1758,1758]),
215    send_utf8_atom_as_binary(P,[1758,1758,1758]),
216    send_utf8_atom_as_binary(P,[1758,1758,1758,1758]),
217
218    send_latin1_atom_as_binary(P,"a"),
219    send_latin1_atom_as_binary(P,"b"),
220
221    send_term_as_binary(P,'c'),
222    send_term_as_binary(P,'d'),
223
224    runner:recv_eot(P),
225    ok.
226
227
228%% ######################################################################## %%
229
230send_term_as_binary(Port, Term) when is_port(Port) ->
231    Port ! {self(), {command, term_to_binary(Term)}}.
232
233send_raw(Port, Bin) when is_port(Port) ->
234    Port ! {self(), {command, Bin}}.
235
236send_utf8_atom_as_binary(Port, String) ->
237    Port ! {self(), {command, term_to_binary(uc_atup(String))}}.
238
239send_latin1_atom_as_binary(Port, String) ->
240    Port ! {self(), {command, encode_latin1_atom(String)}}.
241
242send_integers(P) ->
243    send_term_as_binary(P,0),		% SMALL_INTEGER_EXT smallest
244    send_term_as_binary(P,255),		% SMALL_INTEGER_EXT largest
245    send_term_as_binary(P,256),		% INTEGER_EXT smallest pos (*)
246    send_term_as_binary(P,-1),		% INTEGER_EXT largest  neg
247
248    send_term_as_binary(P, 16#07ffffff),	% INTEGER_EXT old largest (28 bits)
249    send_term_as_binary(P,-16#08000000),	% INTEGER_EXT old smallest
250    send_term_as_binary(P, 16#08000000),  % SMALL_BIG_EXT old smallest pos(*)
251    send_term_as_binary(P,-16#08000001),	% SMALL_BIG_EXT old largest neg (*)
252
253    send_term_as_binary(P, 16#7fffffff),	% INTEGER_EXT new largest (32 bits)
254    send_term_as_binary(P,-16#80000000),	% INTEGER_EXT new smallest (32 bis)
255    send_term_as_binary(P, 16#80000000),  % SMALL_BIG_EXT new smallest pos(*)
256    send_term_as_binary(P,-16#80000001),	% SMALL_BIG_EXT new largest neg (*)
257
258    case erlang:system_info({wordsize,external}) of
259        4 ->
260            send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32
261            send_term_as_binary(P, 16#ffffffff),% SMALL_BIG_EXT largest u32
262
263            send_term_as_binary(P, 16#7fffffffffff), % largest  i48
264            send_term_as_binary(P,-16#800000000000), % smallest i48
265            send_term_as_binary(P, 16#ffffffffffff), % largest  u48
266            send_term_as_binary(P, 16#7fffffffffffffff), % largest  i64
267            send_term_as_binary(P,-16#8000000000000000), % smallest i64
268            send_term_as_binary(P, 16#ffffffffffffffff); % largest  u64
269        8 ->
270            send_term_as_binary(P, 16#8000000000000000),% SMALL_BIG_EXT u64
271            % SMALL_BIG_EXT largest u64
272            send_term_as_binary(P, 16#ffffffffffffffff),
273            % largest  i96
274            send_term_as_binary(P, 16#7fffffffffffffffffffffff),
275            % smallest i96
276            send_term_as_binary(P,-16#800000000000000000000000),
277            % largest  u96
278            send_term_as_binary(P, 16#ffffffffffffffffffffffff),
279            % largest  i128
280            send_term_as_binary(P, 16#7fffffffffffffffffffffffffffffff),
281            % smallest i128
282            send_term_as_binary(P,-16#80000000000000000000000000000000),
283            % largest  u128
284            send_term_as_binary(P, 16#ffffffffffffffffffffffffffffffff)
285    end,
286    send_term_as_binary(P, []), % illegal type
287    ok.
288
289send_integers2(P) ->
290    send_term_as_binary(P,0),           % SMALL_INTEGER_EXT smallest
291    send_term_as_binary(P,255),	        % SMALL_INTEGER_EXT largest
292    send_term_as_binary(P,256),	        % INTEGER_EXT smallest pos (*)
293    send_term_as_binary(P,-1),          % INTEGER_EXT largest  neg
294
295    send_term_as_binary(P, 16#07ffffff),     % INTEGER_EXT old largest (28 bits)
296    send_term_as_binary(P,-16#08000000),     % INTEGER_EXT old smallest
297    send_term_as_binary(P, 16#08000000),     % SMALL_BIG_EXT old smallest pos(*)
298    send_term_as_binary(P,-16#08000001),     % SMALL_BIG_EXT old largest neg (*)
299
300    send_term_as_binary(P, 16#7fffffff),     % INTEGER_EXT new largest (32 bits)
301    send_term_as_binary(P,-16#80000000),     % INTEGER_EXT new smallest
302    send_term_as_binary(P, 16#80000000),     % SMALL_BIG_EXT new smallest pos(*)
303    send_term_as_binary(P,-16#80000001),     % SMALL_BIG_EXT new largest neg (*)
304
305    send_term_as_binary(P, 16#ffffffff),     % SMALL_BIG_EXT largest u32
306
307    send_term_as_binary(P, 16#7fffffffffff),     % largest  i48
308    send_term_as_binary(P,-16#800000000000),     % smallest i48
309    send_term_as_binary(P, 16#ffffffffffff),     % largest  u48
310    send_term_as_binary(P, 16#7fffffffffffffff), % largest  i64
311    send_term_as_binary(P,-16#8000000000000000), % smallest i64
312    send_term_as_binary(P, 16#ffffffffffffffff), % largest  u64
313    send_term_as_binary(P, []), % illegal type
314    ok.
315
316encode_latin1_atom(String) ->
317    Len = length(String),
318    %% Use ATOM_EXT (not SMALL_*) to simulate old term_to_binary
319    TagLen = [$d, Len bsr 8, Len band 16#ff],
320    list_to_binary([131, TagLen, String]).
321
322uc_atup(ATxt) ->
323    string_to_atom(ATxt).
324
325string_to_atom(String) ->
326    Utf8List = string_to_utf8_list(String),
327    Len = length(Utf8List),
328    TagLen = case Len < 256 of
329                 true -> [119, Len];
330                 false -> [118, Len bsr 8, Len band 16#ff]
331             end,
332    binary_to_term(list_to_binary([131, TagLen, Utf8List])).
333
334string_to_utf8_list([]) ->
335    [];
336string_to_utf8_list([CP|CPs]) when is_integer(CP),
337                                   0 =< CP,
338                                   CP =< 16#7F ->
339    [CP | string_to_utf8_list(CPs)];
340string_to_utf8_list([CP|CPs]) when is_integer(CP),
341                                   16#80 =< CP,
342                                   CP =< 16#7FF ->
343    [16#C0 bor (CP bsr 6),
344     16#80 bor (16#3F band CP) | string_to_utf8_list(CPs)];
345string_to_utf8_list([CP|CPs]) when is_integer(CP),
346                                   16#800 =< CP,
347                                   CP =< 16#FFFF ->
348    [16#E0 bor (CP bsr 12),
349     16#80 bor (16#3F band (CP bsr 6)),
350     16#80 bor (16#3F band CP) | string_to_utf8_list(CPs)];
351string_to_utf8_list([CP|CPs]) when is_integer(CP),
352                                   16#10000 =< CP,
353                                   CP =< 16#10FFFF ->
354    [16#F0 bor (CP bsr 18),
355     16#80 bor (16#3F band (CP bsr 12)),
356     16#80 bor (16#3F band (CP bsr 6)),
357     16#80 bor (16#3F band CP) | string_to_utf8_list(CPs)].
358