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 %% Test full 64-bit pids 317 Vs = [1 bsl 30, 1 bsl 31, (1 bsl 31)-1, (1 bsl 32)-1], 318 [check_cmp(P, mk_pid({a@b, 4711}, A, B), mk_pid({a@b, 4711}, C, D)) 319 || A <- Vs, B <- Vs, C <- Vs, D <- Vs], 320 321 Cmd = case os:type() of 322 {win32, _} -> "cmd /q /c true"; 323 _ -> "true" 324 end, 325 326 Prt0 = open_port({spawn, Cmd},[]), 327 Prt1 = open_port({spawn, Cmd},[]), 328 329 check_cmp(P, Prt0, Prt0), 330 check_cmp(P, Prt1, Prt0), 331 check_cmp(P, Prt0, Prt1), 332 check_cmp(P, mk_port({a@b, 4711}, 17), mk_port({a@b, 4711}, 17)), 333 check_cmp(P, mk_port({a@b, 4711}, 17), mk_port({a@d, 4711}, 17)), 334 check_cmp(P, mk_port({a@b, 4711}, 17), mk_port({a@bc, 4711}, 17)), 335 check_cmp(P, mk_port({a@b, 4712}, 17), mk_port({a@b, 4711}, 17)), 336 check_cmp(P, mk_port({a@b, 4711}, 17), mk_port({a@b, 4711}, 18)), 337 338 send_raw(P, <<"done">>), 339 runner:recv_eot(P), 340 ok. 341 342mk_pid(Node, Num, Ser) -> 343 erts_test_utils:mk_ext_pid(Node, Num, Ser). 344 345mk_port(Node, Id) -> 346 erts_test_utils:mk_ext_port(Node, Id). 347 348mk_ref(Node, Numbers) -> 349 erts_test_utils:mk_ext_ref(Node, Numbers). 350 351check_cmp(P, A, B) when is_pid(A), is_pid(B) -> 352 check_cmp(P, {cmp_pids, A, B}); 353check_cmp(P, A, B) when is_port(A), is_port(B) -> 354 check_cmp(P, {cmp_ports, A, B}); 355check_cmp(P, A, B) when is_reference(A), is_reference(B) -> 356 check_cmp(P, {cmp_refs, A, B}). 357 358check_cmp(P, {_, A, B} = Data) -> 359 io:format("~n~nChecking: ~p~n", [Data]), 360 send_term_as_binary(P, Data), 361 {term, Res} = runner:get_term(P), 362 io:format("Res = ~p~n", [Res]), 363 case {{ei_cmp, Res}, {erlang, cmp_nc(A, B)}} of 364 {{ei_cmp, 0}, {erlang, equal}} -> 365 ok; 366 {{ei_cmp, Cmp}, {erlang, less_than}} when is_integer(Cmp), 367 Cmp < 0 -> 368 ok; 369 {{ei_cmp, Cmp}, {erlang, larger_than}} when is_integer(Cmp), 370 Cmp > 0 -> ok; 371 Fail -> 372 ct:fail(Fail) 373 end. 374 375cmp_nc(A, A) -> 376 equal; 377cmp_nc(A, B) when A < B -> 378 less_than; 379cmp_nc(_, _) -> 380 larger_than. 381 382 383%% ######################################################################## %% 384 385send_term_as_binary(Port, Term) when is_port(Port) -> 386 Port ! {self(), {command, term_to_binary(Term)}}. 387 388send_raw(Port, Bin) when is_port(Port) -> 389 Port ! {self(), {command, Bin}}. 390 391send_utf8_atom_as_binary(Port, String) -> 392 Port ! {self(), {command, term_to_binary(uc_atup(String))}}. 393 394send_latin1_atom_as_binary(Port, String) -> 395 Port ! {self(), {command, encode_latin1_atom(String)}}. 396 397send_integers(P) -> 398 send_term_as_binary(P,0), % SMALL_INTEGER_EXT smallest 399 send_term_as_binary(P,255), % SMALL_INTEGER_EXT largest 400 send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*) 401 send_term_as_binary(P,-1), % INTEGER_EXT largest neg 402 403 send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT old largest (28 bits) 404 send_term_as_binary(P,-16#08000000), % INTEGER_EXT old smallest 405 send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT old smallest pos(*) 406 send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT old largest neg (*) 407 408 send_term_as_binary(P, 16#7fffffff), % INTEGER_EXT new largest (32 bits) 409 send_term_as_binary(P,-16#80000000), % INTEGER_EXT new smallest (32 bis) 410 send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*) 411 send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*) 412 413 case erlang:system_info({wordsize,external}) of 414 4 -> 415 send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32 416 send_term_as_binary(P, 16#ffffffff),% SMALL_BIG_EXT largest u32 417 418 send_term_as_binary(P, 16#7fffffffffff), % largest i48 419 send_term_as_binary(P,-16#800000000000), % smallest i48 420 send_term_as_binary(P, 16#ffffffffffff), % largest u48 421 send_term_as_binary(P, 16#7fffffffffffffff), % largest i64 422 send_term_as_binary(P,-16#8000000000000000), % smallest i64 423 send_term_as_binary(P, 16#ffffffffffffffff); % largest u64 424 8 -> 425 send_term_as_binary(P, 16#8000000000000000),% SMALL_BIG_EXT u64 426 % SMALL_BIG_EXT largest u64 427 send_term_as_binary(P, 16#ffffffffffffffff), 428 % largest i96 429 send_term_as_binary(P, 16#7fffffffffffffffffffffff), 430 % smallest i96 431 send_term_as_binary(P,-16#800000000000000000000000), 432 % largest u96 433 send_term_as_binary(P, 16#ffffffffffffffffffffffff), 434 % largest i128 435 send_term_as_binary(P, 16#7fffffffffffffffffffffffffffffff), 436 % smallest i128 437 send_term_as_binary(P,-16#80000000000000000000000000000000), 438 % largest u128 439 send_term_as_binary(P, 16#ffffffffffffffffffffffffffffffff) 440 end, 441 send_term_as_binary(P, []), % illegal type 442 ok. 443 444send_integers2(P) -> 445 send_term_as_binary(P,0), % SMALL_INTEGER_EXT smallest 446 send_term_as_binary(P,255), % SMALL_INTEGER_EXT largest 447 send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*) 448 send_term_as_binary(P,-1), % INTEGER_EXT largest neg 449 450 send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT old largest (28 bits) 451 send_term_as_binary(P,-16#08000000), % INTEGER_EXT old smallest 452 send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT old smallest pos(*) 453 send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT old largest neg (*) 454 455 send_term_as_binary(P, 16#7fffffff), % INTEGER_EXT new largest (32 bits) 456 send_term_as_binary(P,-16#80000000), % INTEGER_EXT new smallest 457 send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*) 458 send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*) 459 460 send_term_as_binary(P, 16#ffffffff), % SMALL_BIG_EXT largest u32 461 462 send_term_as_binary(P, 16#7fffffffffff), % largest i48 463 send_term_as_binary(P,-16#800000000000), % smallest i48 464 send_term_as_binary(P, 16#ffffffffffff), % largest u48 465 send_term_as_binary(P, 16#7fffffffffffffff), % largest i64 466 send_term_as_binary(P,-16#8000000000000000), % smallest i64 467 send_term_as_binary(P, 16#ffffffffffffffff), % largest u64 468 send_term_as_binary(P, []), % illegal type 469 ok. 470 471encode_latin1_atom(String) -> 472 Len = length(String), 473 %% Use ATOM_EXT (not SMALL_*) to simulate old term_to_binary 474 TagLen = [$d, Len bsr 8, Len band 16#ff], 475 list_to_binary([131, TagLen, String]). 476 477uc_atup(ATxt) -> 478 string_to_atom(ATxt). 479 480string_to_atom(String) -> 481 Utf8List = string_to_utf8_list(String), 482 Len = length(Utf8List), 483 TagLen = case Len < 256 of 484 true -> [119, Len]; 485 false -> [118, Len bsr 8, Len band 16#ff] 486 end, 487 binary_to_term(list_to_binary([131, TagLen, Utf8List])). 488 489string_to_utf8_list([]) -> 490 []; 491string_to_utf8_list([CP|CPs]) when is_integer(CP), 492 0 =< CP, 493 CP =< 16#7F -> 494 [CP | string_to_utf8_list(CPs)]; 495string_to_utf8_list([CP|CPs]) when is_integer(CP), 496 16#80 =< CP, 497 CP =< 16#7FF -> 498 [16#C0 bor (CP bsr 6), 499 16#80 bor (16#3F band CP) | string_to_utf8_list(CPs)]; 500string_to_utf8_list([CP|CPs]) when is_integer(CP), 501 16#800 =< CP, 502 CP =< 16#FFFF -> 503 [16#E0 bor (CP bsr 12), 504 16#80 bor (16#3F band (CP bsr 6)), 505 16#80 bor (16#3F band CP) | string_to_utf8_list(CPs)]; 506string_to_utf8_list([CP|CPs]) when is_integer(CP), 507 16#10000 =< CP, 508 CP =< 16#10FFFF -> 509 [16#F0 bor (CP bsr 18), 510 16#80 bor (16#3F band (CP bsr 12)), 511 16#80 bor (16#3F band (CP bsr 6)), 512 16#80 bor (16#3F band CP) | string_to_utf8_list(CPs)]. 513