1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2004-2020. 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 test_ei_decode_iodata/1, 38 test_ei_cmp_nc/1]). 39 40suite() -> [{ct_hooks,[ts_install_cth]}]. 41 42all() -> 43 [test_ei_decode_long, test_ei_decode_ulong, 44 test_ei_decode_longlong, test_ei_decode_ulonglong, 45 test_ei_decode_char, test_ei_decode_nonoptimal, 46 test_ei_decode_misc, test_ei_decode_utf8_atom, 47 test_ei_decode_iodata, test_ei_cmp_nc]. 48 49init_per_testcase(Case, Config) -> 50 runner:init_per_testcase(?MODULE, Case, Config). 51 52%% --------------------------------------------------------------------------- 53 54% NOTE: for historical reasons we don't pach as tight as we can, 55% we only fill 27 bits in 32 bit INTEGER_EXT 56 57 58%% ######################################################################## %% 59 60test_ei_decode_long(Config) when is_list(Config) -> 61 P = runner:start(Config, ?test_ei_decode_long), 62 send_integers(P), 63 runner:recv_eot(P), 64 ok. 65 66 67%% ######################################################################## %% 68 69test_ei_decode_ulong(Config) when is_list(Config) -> 70 P = runner:start(Config, ?test_ei_decode_ulong), 71 send_integers(P), 72 runner:recv_eot(P), 73 ok. 74 75 76% (*) In practical terms, other values may fit into the ext format 77% i32 is signed 32 bit on C side 78% u32 is unsigned 32 bit on C side 79 80%% ######################################################################## %% 81 82test_ei_decode_longlong(Config) when is_list(Config) -> 83 P = runner:start(Config, ?test_ei_decode_longlong), 84 send_integers2(P), 85 runner:recv_eot(P), 86 ok. 87 88 89%% ######################################################################## %% 90 91test_ei_decode_ulonglong(Config) when is_list(Config) -> 92 P = runner:start(Config, ?test_ei_decode_ulonglong), 93 send_integers2(P), 94 runner:recv_eot(P), 95 ok. 96 97 98%% ######################################################################## %% 99%% A "character" for us is an 8 bit integer, always positive, i.e. 100%% it is unsigned. 101%% FIXME maybe the API should change to use "unsigned char" to be clear?! 102 103test_ei_decode_char(Config) when is_list(Config) -> 104 P = runner:start(Config, ?test_ei_decode_char), 105 106 send_term_as_binary(P,0), 107 send_term_as_binary(P,16#7f), 108 send_term_as_binary(P,16#ff), 109 110 send_term_as_binary(P, []), % illegal type 111 112 runner:recv_eot(P), 113 ok. 114 115 116%% ######################################################################## %% 117 118test_ei_decode_nonoptimal(Config) when is_list(Config) -> 119 P = runner:start(Config, ?test_ei_decode_nonoptimal), 120 121 send_non_optimal_pos(P), % decode_char 122 send_non_optimal(P), % decode_long 123 send_non_optimal_pos(P), % decode_ulong 124 send_non_optimal(P), % decode_longlong 125 send_non_optimal_pos(P), % decode_ulonglong 126 127 runner:recv_eot(P), 128 ok. 129 130 131send_non_optimal(P) -> 132 send_non_optimal_pos(P), 133 send_non_optimal_neg(P). 134 135send_non_optimal_pos(P) -> 136 send_raw(P, <<131,97,42>>), 137 send_raw(P, <<131,98,42:32>>), 138 send_raw(P, <<131,110,1,0,42>>), 139 send_raw(P, <<131,110,2,0,42,0>>), 140 send_raw(P, <<131,110,4,0,42,0,0,0>>), 141 send_raw(P, <<131,111,0,0,0,1,0,42>>), 142 send_raw(P, <<131,111,0,0,0,2,0,42,0>>), 143 send_raw(P, <<131,111,0,0,0,3,0,42,0,0>>), 144 send_raw(P, <<131,111,0,0,0,6,0,42,0,0,0,0,0>>), 145 ok. 146 147send_non_optimal_neg(P) -> 148 % send_raw(P, <<131,97,-42>>), 149 send_raw(P, <<131,98,-42:32>>), 150 send_raw(P, <<131,110,1,1,42>>), 151 send_raw(P, <<131,110,2,1,42,0>>), 152 send_raw(P, <<131,110,4,1,42,0,0,0>>), 153 send_raw(P, <<131,111,0,0,0,1,1,42>>), 154 send_raw(P, <<131,111,0,0,0,2,1,42,0>>), 155 send_raw(P, <<131,111,0,0,0,3,1,42,0,0>>), 156 send_raw(P, <<131,111,0,0,0,6,1,42,0,0,0,0,0>>), 157 ok. 158 159 160%% ######################################################################## %% 161 162test_ei_decode_misc(Config) when is_list(Config) -> 163 P = runner:start(Config, ?test_ei_decode_misc), 164 165 send_term_as_binary(P,0.0), 166 send_term_as_binary(P,-1.0), 167 send_term_as_binary(P,1.0), 168 169 send_term_as_binary(P,false), 170 send_term_as_binary(P,true), 171 172 send_term_as_binary(P,foo), 173 send_term_as_binary(P,''), 174 %%send_term_as_binary(P,'ÅÄÖåäö'), 175 send_latin1_atom_as_binary(P, "ÅÄÖåäö"), 176 177 send_term_as_binary(P,"foo"), 178 send_term_as_binary(P,""), 179 send_term_as_binary(P,"ÅÄÖåäö"), 180 181 send_term_as_binary(P,<<"foo">>), 182 send_term_as_binary(P,<<>>), 183 send_term_as_binary(P,<<"ÅÄÖåäö">>), 184 185 send_term_as_binary(P,<<1, 2, 3:5>>), 186 send_term_as_binary(P,<<1:1>>), 187 188 % send_term_as_binary(P,{}), 189 % send_term_as_binary(P,[]), 190 191 runner:recv_eot(P), 192 ok. 193 194%% ######################################################################## %% 195 196test_ei_decode_utf8_atom(Config) -> 197 P = runner:start(Config, ?test_ei_decode_utf8_atom), 198 199 send_latin1_atom_as_binary(P,"å"), 200 send_latin1_atom_as_binary(P,"ä"), 201 send_latin1_atom_as_binary(P,"ö"), 202 send_latin1_atom_as_binary(P,"õ"), 203 204 send_utf8_atom_as_binary(P,[1758]), 205 send_utf8_atom_as_binary(P,[1758,1758]), 206 send_utf8_atom_as_binary(P,[1758,1758,1758]), 207 send_utf8_atom_as_binary(P,[1758,1758,1758,1758]), 208 209 send_latin1_atom_as_binary(P,"a"), 210 send_latin1_atom_as_binary(P,"b"), 211 212 send_term_as_binary(P,'c'), 213 send_term_as_binary(P,'d'), 214 215 runner:recv_eot(P), 216 ok. 217 218 219%% ######################################################################## %% 220 221test_ei_decode_iodata(Config) when is_list(Config) -> 222 P = runner:start(Config, ?test_ei_decode_iodata), 223 224 check_decode_iodata(P, [], true), 225 check_decode_iodata(P, $a, false), 226 check_decode_iodata(P, an_atom, false), 227 check_decode_iodata(P, self(), false), 228 check_decode_iodata(P, [$a,$a], true), 229 check_decode_iodata(P, [$a|$a], false), 230 check_decode_iodata(P, [[$a|$a],$a], false), 231 check_decode_iodata(P, "hej", true), 232 check_decode_iodata(P, ["hej", " ", "hopp"], true), 233 check_decode_iodata(P, <<"hopp san sa">>, true), 234 check_decode_iodata(P, [$a | <<"a">>], true), 235 check_decode_iodata(P, [[[["hej"]]], [$ , <<"hopp">>, $ , "san" | <<" sa">>]], true), 236 check_decode_iodata(P, [[[["hej"]]], [$ , <<"hopp">>, 0, "san" | <<" sa">>]], true), 237 check_decode_iodata(P, [[[["hej"]]], [$ , <<"hopp">>, 256, "san" | <<" sa">>]], false), 238 check_decode_iodata(P, [[[["hej"]]], [$ , <<"hopp">>, -2, "san" | <<" sa">>]], false), 239 check_decode_iodata(P, [[[["hej"]]], [$ , <<"hopp">>, $ , san | <<" sa">>]], false), 240 check_decode_iodata(P, [[[["hej"]]], [$ , <<"hopp">>, $ , "san s" | $a], " "], false), 241 check_decode_iodata(P, [[[[[[[]|<<"a">>]]]]]], true), 242 check_decode_iodata(P, [[[[[[[[]]]]]]],[[[],[],[]]]], true), 243 244 send_raw(P, <<"done">>), 245 runner:recv_eot(P), 246 ok. 247 248check_decode_iodata(P, Data, Valid) -> 249 io:format("~n~nChecking: ~p~n", [Data]), 250 Expect = case Valid of 251 true -> 252 io:format("Expecting decode SUCCESS... ", []), 253 iolist_to_binary(Data); 254 false -> 255 io:format("Expecting decode FAILURE... ", []), 256 badarg = try 257 iolist_to_binary(Data) 258 catch 259 error:badarg -> 260 badarg 261 end, 262 decode_size_failed 263 end, 264 send_term_as_binary(P, Data), 265 Actual = case runner:get_term(P) of 266 {bytes, B} when is_binary(B) -> 267 B; 268 {bytes, L} when is_list(L) -> 269 list_to_binary(L); 270 {term, T} -> 271 T 272 end, 273 case Expect =:= Actual of 274 true -> 275 io:format("Expected result!~n",[]), 276 ok; 277 false -> 278 io:format("Expect: ~w~nActual: ~w~n", [Expect, Actual]), 279 ct:fail(unexpected_result) 280 end. 281 282%% ######################################################################## %% 283 284%% Should be moved to its own suite... 285 286test_ei_cmp_nc(Config) when is_list(Config) -> 287 P = runner:start(Config, ?test_ei_cmp_nc), 288 R0 = make_ref(), 289 R1 = make_ref(), 290 check_cmp(P, R0, R0), 291 check_cmp(P, R0, R1), 292 check_cmp(P, R1, R0), 293 check_cmp(P, mk_ref({a@b, 4711}, [17, 17, 17]), mk_ref({a@c, 4711}, [17, 17, 17])), 294 check_cmp(P, mk_ref({a@b, 4711}, [17, 17, 17]), mk_ref({a@d, 4711}, [17, 17, 17])), 295 check_cmp(P, mk_ref({a@b, 4711}, [17, 17, 17]), mk_ref({a@bc, 4711}, [17, 17, 17])), 296 check_cmp(P, mk_ref({a@b, 4712}, [17, 17, 17]), mk_ref({a@b, 4711}, [17, 17, 17])), 297 check_cmp(P, mk_ref({a@b, 4711}, [17, 17, 17]), mk_ref({a@b, 4711}, [18, 17, 17])), 298 check_cmp(P, mk_ref({a@b, 4711}, [17, 17, 17]), mk_ref({a@b, 4711}, [17, 18, 17])), 299 check_cmp(P, mk_ref({a@b, 4711}, [17, 17, 17]), mk_ref({a@b, 4711}, [17, 17, 18])), 300 check_cmp(P, mk_ref({a@b, 4711}, [0, 17]), mk_ref({a@b, 4711}, [18])), 301 check_cmp(P, mk_ref({a@b, 4711}, [17, 17]), mk_ref({a@b, 4711}, [17, 18])), 302 check_cmp(P, mk_ref({a@b, 4711}, [0, 0, 0]), mk_ref({a@b, 4711}, [17])), 303 check_cmp(P, mk_ref({a@b, 4711}, [0, 0, 17]), mk_ref({a@b, 4711}, [18, 17])), 304 check_cmp(P, mk_ref({a@b, 4711}, [0, 17, 17]), mk_ref({a@b, 4711}, [18])), 305 306 check_cmp(P, self(), self()), 307 check_cmp(P, self(), whereis(file_server_2)), 308 check_cmp(P, whereis(file_server_2), self()), 309 check_cmp(P, mk_pid({a@b, 4711}, 17, 17), mk_pid({a@c, 4711}, 17, 17)), 310 check_cmp(P, mk_pid({a@b, 4711}, 17, 17), mk_pid({a@d, 4711}, 17, 17)), 311 check_cmp(P, mk_pid({a@b, 4711}, 17, 17), mk_pid({a@bc, 4711}, 17, 17)), 312 check_cmp(P, mk_pid({a@b, 4712}, 17, 17), mk_pid({a@b, 4711}, 17, 17)), 313 check_cmp(P, mk_pid({a@b, 4711}, 17, 17), mk_pid({a@b, 4711}, 18, 17)), 314 check_cmp(P, mk_pid({a@b, 4711}, 17, 17), mk_pid({a@b, 4711}, 17, 18)), 315 316 Cmd = case os:type() of 317 {win32, _} -> "cmd /q /c true"; 318 _ -> "true" 319 end, 320 321 Prt0 = open_port({spawn, Cmd},[]), 322 Prt1 = open_port({spawn, Cmd},[]), 323 324 check_cmp(P, Prt0, Prt0), 325 check_cmp(P, Prt1, Prt0), 326 check_cmp(P, Prt0, Prt1), 327 check_cmp(P, mk_port({a@b, 4711}, 17), mk_port({a@b, 4711}, 17)), 328 check_cmp(P, mk_port({a@b, 4711}, 17), mk_port({a@d, 4711}, 17)), 329 check_cmp(P, mk_port({a@b, 4711}, 17), mk_port({a@bc, 4711}, 17)), 330 check_cmp(P, mk_port({a@b, 4712}, 17), mk_port({a@b, 4711}, 17)), 331 check_cmp(P, mk_port({a@b, 4711}, 17), mk_port({a@b, 4711}, 18)), 332 333 send_raw(P, <<"done">>), 334 runner:recv_eot(P), 335 ok. 336 337mk_pid(Node, Num, Ser) -> 338 erts_test_utils:mk_ext_pid(Node, Num, Ser). 339 340mk_port(Node, Id) -> 341 erts_test_utils:mk_ext_port(Node, Id). 342 343mk_ref(Node, Numbers) -> 344 erts_test_utils:mk_ext_ref(Node, Numbers). 345 346check_cmp(P, A, B) when is_pid(A), is_pid(B) -> 347 check_cmp(P, {cmp_pids, A, B}); 348check_cmp(P, A, B) when is_port(A), is_port(B) -> 349 check_cmp(P, {cmp_ports, A, B}); 350check_cmp(P, A, B) when is_reference(A), is_reference(B) -> 351 check_cmp(P, {cmp_refs, A, B}). 352 353check_cmp(P, {_, A, B} = Data) -> 354 io:format("~n~nChecking: ~p~n", [Data]), 355 send_term_as_binary(P, Data), 356 {term, Res} = runner:get_term(P), 357 io:format("Res = ~p~n", [Res]), 358 case {{ei_cmp, Res}, {erlang, cmp_nc(A, B)}} of 359 {{ei_cmp, 0}, {erlang, equal}} -> 360 ok; 361 {{ei_cmp, Cmp}, {erlang, less_than}} when is_integer(Cmp), 362 Cmp < 0 -> 363 ok; 364 {{ei_cmp, Cmp}, {erlang, larger_than}} when is_integer(Cmp), 365 Cmp > 0 -> ok; 366 Fail -> 367 ct:fail(Fail) 368 end. 369 370cmp_nc(A, A) -> 371 equal; 372cmp_nc(A, B) when A < B -> 373 less_than; 374cmp_nc(_, _) -> 375 larger_than. 376 377 378%% ######################################################################## %% 379 380send_term_as_binary(Port, Term) when is_port(Port) -> 381 Port ! {self(), {command, term_to_binary(Term)}}. 382 383send_raw(Port, Bin) when is_port(Port) -> 384 Port ! {self(), {command, Bin}}. 385 386send_utf8_atom_as_binary(Port, String) -> 387 Port ! {self(), {command, term_to_binary(uc_atup(String))}}. 388 389send_latin1_atom_as_binary(Port, String) -> 390 Port ! {self(), {command, encode_latin1_atom(String)}}. 391 392send_integers(P) -> 393 send_term_as_binary(P,0), % SMALL_INTEGER_EXT smallest 394 send_term_as_binary(P,255), % SMALL_INTEGER_EXT largest 395 send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*) 396 send_term_as_binary(P,-1), % INTEGER_EXT largest neg 397 398 send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT old largest (28 bits) 399 send_term_as_binary(P,-16#08000000), % INTEGER_EXT old smallest 400 send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT old smallest pos(*) 401 send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT old largest neg (*) 402 403 send_term_as_binary(P, 16#7fffffff), % INTEGER_EXT new largest (32 bits) 404 send_term_as_binary(P,-16#80000000), % INTEGER_EXT new smallest (32 bis) 405 send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*) 406 send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*) 407 408 case erlang:system_info({wordsize,external}) of 409 4 -> 410 send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32 411 send_term_as_binary(P, 16#ffffffff),% SMALL_BIG_EXT largest u32 412 413 send_term_as_binary(P, 16#7fffffffffff), % largest i48 414 send_term_as_binary(P,-16#800000000000), % smallest i48 415 send_term_as_binary(P, 16#ffffffffffff), % largest u48 416 send_term_as_binary(P, 16#7fffffffffffffff), % largest i64 417 send_term_as_binary(P,-16#8000000000000000), % smallest i64 418 send_term_as_binary(P, 16#ffffffffffffffff); % largest u64 419 8 -> 420 send_term_as_binary(P, 16#8000000000000000),% SMALL_BIG_EXT u64 421 % SMALL_BIG_EXT largest u64 422 send_term_as_binary(P, 16#ffffffffffffffff), 423 % largest i96 424 send_term_as_binary(P, 16#7fffffffffffffffffffffff), 425 % smallest i96 426 send_term_as_binary(P,-16#800000000000000000000000), 427 % largest u96 428 send_term_as_binary(P, 16#ffffffffffffffffffffffff), 429 % largest i128 430 send_term_as_binary(P, 16#7fffffffffffffffffffffffffffffff), 431 % smallest i128 432 send_term_as_binary(P,-16#80000000000000000000000000000000), 433 % largest u128 434 send_term_as_binary(P, 16#ffffffffffffffffffffffffffffffff) 435 end, 436 send_term_as_binary(P, []), % illegal type 437 ok. 438 439send_integers2(P) -> 440 send_term_as_binary(P,0), % SMALL_INTEGER_EXT smallest 441 send_term_as_binary(P,255), % SMALL_INTEGER_EXT largest 442 send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*) 443 send_term_as_binary(P,-1), % INTEGER_EXT largest neg 444 445 send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT old largest (28 bits) 446 send_term_as_binary(P,-16#08000000), % INTEGER_EXT old smallest 447 send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT old smallest pos(*) 448 send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT old largest neg (*) 449 450 send_term_as_binary(P, 16#7fffffff), % INTEGER_EXT new largest (32 bits) 451 send_term_as_binary(P,-16#80000000), % INTEGER_EXT new smallest 452 send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*) 453 send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*) 454 455 send_term_as_binary(P, 16#ffffffff), % SMALL_BIG_EXT largest u32 456 457 send_term_as_binary(P, 16#7fffffffffff), % largest i48 458 send_term_as_binary(P,-16#800000000000), % smallest i48 459 send_term_as_binary(P, 16#ffffffffffff), % largest u48 460 send_term_as_binary(P, 16#7fffffffffffffff), % largest i64 461 send_term_as_binary(P,-16#8000000000000000), % smallest i64 462 send_term_as_binary(P, 16#ffffffffffffffff), % largest u64 463 send_term_as_binary(P, []), % illegal type 464 ok. 465 466encode_latin1_atom(String) -> 467 Len = length(String), 468 %% Use ATOM_EXT (not SMALL_*) to simulate old term_to_binary 469 TagLen = [$d, Len bsr 8, Len band 16#ff], 470 list_to_binary([131, TagLen, String]). 471 472uc_atup(ATxt) -> 473 string_to_atom(ATxt). 474 475string_to_atom(String) -> 476 Utf8List = string_to_utf8_list(String), 477 Len = length(Utf8List), 478 TagLen = case Len < 256 of 479 true -> [119, Len]; 480 false -> [118, Len bsr 8, Len band 16#ff] 481 end, 482 binary_to_term(list_to_binary([131, TagLen, Utf8List])). 483 484string_to_utf8_list([]) -> 485 []; 486string_to_utf8_list([CP|CPs]) when is_integer(CP), 487 0 =< CP, 488 CP =< 16#7F -> 489 [CP | string_to_utf8_list(CPs)]; 490string_to_utf8_list([CP|CPs]) when is_integer(CP), 491 16#80 =< CP, 492 CP =< 16#7FF -> 493 [16#C0 bor (CP bsr 6), 494 16#80 bor (16#3F band CP) | string_to_utf8_list(CPs)]; 495string_to_utf8_list([CP|CPs]) when is_integer(CP), 496 16#800 =< CP, 497 CP =< 16#FFFF -> 498 [16#E0 bor (CP bsr 12), 499 16#80 bor (16#3F band (CP bsr 6)), 500 16#80 bor (16#3F band CP) | string_to_utf8_list(CPs)]; 501string_to_utf8_list([CP|CPs]) when is_integer(CP), 502 16#10000 =< CP, 503 CP =< 16#10FFFF -> 504 [16#F0 bor (CP bsr 18), 505 16#80 bor (16#3F band (CP bsr 12)), 506 16#80 bor (16#3F band (CP bsr 6)), 507 16#80 bor (16#3F band CP) | string_to_utf8_list(CPs)]. 508