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_encode_SUITE). 23 24-include_lib("common_test/include/ct.hrl"). 25-include("ei_decode_encode_SUITE_data/ei_decode_encode_test_cases.hrl"). 26 27-export([all/0, suite/0, 28 init_per_testcase/2, 29 test_ei_decode_encode/1]). 30 31suite() -> 32 [{ct_hooks,[ts_install_cth]}]. 33 34all() -> 35 [test_ei_decode_encode]. 36 37init_per_testcase(Case, Config) -> 38 rand:uniform(), % Make sure rand is initialized and seeded. 39 io:format("** rand seed = ~p\n", [rand:export_seed()]), 40 runner:init_per_testcase(?MODULE, Case, Config). 41 42%% --------------------------------------------------------------------------- 43 44% NOTE: these types have no meaning on the C side so we pass them 45% to C and back just to see they are the same. 46 47 48%% ######################################################################## %% 49 50test_ei_decode_encode(Config) when is_list(Config) -> 51 P = runner:start(Config, ?test_ei_decode_encode), 52 53 Fun1 = fun (X) -> {X,true} end, 54 Fun2 = fun runner:init_per_testcase/3, 55 Pid = self(), 56 Port = case os:type() of 57 {win32,_} -> 58 open_port({spawn,"sort"},[]); 59 {unix, darwin} -> 60 open_port({spawn,"/usr/bin/true"},[]); 61 _ -> 62 open_port({spawn,"/bin/true"},[]) 63 end, 64 Ref = make_ref(), 65 Trace = {1,2,3,self(),4}, % FIXME how to construct?! 66 67 68 BigSmallA = 1696192905348584855517250509684275447603964214606878827319923580493120589769459602596313014087329389174229999430092223701630077631205171572331191216670754029016160388576759960413039261647653627052707047, 69 BigSmallB = 43581177444506616087519351724629421082877485633442736512567383077022781906420535744195118099822189576169114064491200598595995538299156626345938812352676950427869649947439032133573270227067833308153431095, 70 BigSmallC = 52751775381034251994634567029696659541685100826881826508158083211003576763074162948462801435204697796532659535818017760528684167216110865807581759669824808936751316879636014972704885388116861127856231, 71 72 BigLargeA = 1 bsl 11111 + BigSmallA, 73 BigLargeB = 1 bsl 11112 + BigSmallB, 74 BigLargeC = BigSmallA * BigSmallB * BigSmallC * BigSmallA, 75 76 send_rec(P, Fun1), 77 send_rec(P, Fun2), 78 send_rec(P, Pid), 79 send_rec(P, Port), 80 send_rec(P, Ref), 81 send_rec(P, Trace), 82 83 % bigs 84 85 send_rec(P, BigSmallA), 86 send_rec(P, BigSmallB), 87 send_rec(P, BigSmallC), 88 89 send_rec(P, BigLargeA), 90 send_rec(P, BigLargeB), 91 send_rec(P, BigLargeC), 92 93 %% Test large node containers... 94 95 ThisNode = {node(), erlang:system_info(creation)}, 96 TXPid = mk_pid(ThisNode, 32767, 8191), 97 TXPort = mk_port(ThisNode, 268435455), 98 TXRef = mk_ref(ThisNode, [262143, 4294967295, 4294967295]), 99 100 send_rec(P, TXPid), 101 send_rec(P, TXPort), 102 send_rec(P, TXRef), 103 104 [begin OtherNode = {gurka@sallad, Creation}, 105 send_rec(P, mk_pid(OtherNode, 32767, 8191)), 106 send_rec(P, mk_port(OtherNode, 268435455)), 107 send_rec(P, mk_ref(OtherNode, [262143, 4294967295, 4294967295])), 108 send_rec(P, mk_ref(OtherNode, [262143, 4294967295, 4294967295, 4294967294, 4294967293])), 109 void 110 end || Creation <- [1, 2, 3, 4, 16#adec0ded]], 111 112 %% Full 64-bit pids 113 [send_rec(P, mk_pid({gurka@sallad, 77}, 114 rand:uniform(1 bsl Bits)-1, 115 rand:uniform(1 bsl Bits)-1)) 116 || Bits <- lists:seq(16,32)], 117 118 %% Full 64-bit ports 119 [send_rec(P, mk_port({gurka@sallad, 4711}, 120 rand:uniform(1 bsl Bits)-1)) 121 || Bits <- lists:seq(24,40)], 122 123 %% Unicode atoms 124 [begin send_rec(P, Atom), 125 send_rec(P, mk_pid({Atom,1}, 23434, 3434)), 126 send_rec(P, mk_port({Atom,1}, 2343434)), 127 send_rec(P, mk_ref({Atom,1}, [262143, 8723648, 24097245])), 128 void 129 end || Atom <- unicode_atom_data()], 130 131 send_rec(P, {}), 132 send_rec(P, {atom, Pid, Port, Ref}), 133 send_rec(P, [atom, Pid, Port, Ref]), 134 send_rec(P, [atom | Fun1]), 135 send_rec(P, #{}), 136 send_rec(P, #{key => value}), 137 send_rec(P, maps:put(Port, Ref, #{key => value, key2 => Pid})), 138 139 [send_rec(P, <<16#dec0deb175:B/little>>) || B <- lists:seq(0,48)], 140 141 % And last an ugly duckling to test ei_encode_bitstring with bitoffs != 0 142 encode_bitstring(P), 143 144 runner:recv_eot(P), 145 ok. 146 147encode_bitstring(P) -> 148 %% Send one bitstring to c-node 149 Bits = <<16#18f6d4b2907e5c3a1:66>>, 150 P ! {self(), {command, term_to_binary(Bits, [{minor_version, 2}])}}, 151 152 %% and then receive and verify a number of different sub-bitstrings 153 receive_sub_bitstring(P, Bits, 0, bit_size(Bits)). 154 155receive_sub_bitstring(_, _, _, NBits) when NBits < 0 -> 156 ok; 157receive_sub_bitstring(P, Bits, BitOffs, NBits) -> 158 <<_:BitOffs, Sub:NBits/bits, _/bits>> = Bits, 159 %%io:format("expecting term_to_binary(~p) = ~p\n", [Sub, term_to_binary(Sub)]), 160 {_B,Sub} = get_buf_and_term(P), 161 receive_sub_bitstring(P, Bits, BitOffs+1, NBits - ((NBits div 20)+1)). 162 163 164 165%% ######################################################################## %% 166 167% We read two packets for each test, the ei_decode_encode and ei_x_decode_encode version.... 168 169send_rec(P, Term) when is_port(P) -> 170 P ! {self(), {command, term_to_binary(Term, [{minor_version, 2}])}}, 171 {_B,Term} = get_buf_and_term(P). 172 173 174get_buf_and_term(P) -> 175 B = get_binaries(P), 176 case B of 177 <<131>> -> 178 io:format("(got single magic, no content)\n",[]), 179 {B,'$$magic$$'}; 180 <<131,_>> -> 181 T = binary_to_term(B), 182 io:format("~w\n~w\n(got magic)\n",[B,T]), 183 {B,T}; 184 _ -> 185 B1 = list_to_binary([131,B]), % No magic, add 186 T = binary_to_term(B1), 187 %io:format("~w\n~w\n(got no magic)\n",[B,T]), 188 {B,T} 189 end. 190 191 192get_binaries(P) -> 193 B1 = get_binary(P), 194 B2 = get_binary(P), 195 B1 = B2. 196 197get_binary(P) -> 198 case runner:get_term(P) of 199 {bytes,L} -> 200 B = list_to_binary(L), 201 %%io:format("~w\n",[L]), 202 % For strange reasons <<131>> show up as <>.... 203 % io:format("~w\n",[B]), 204 B; 205 Other -> 206 Other 207 end. 208 209%% 210%% Node container constructor functions 211%% 212 213-define(VERSION_MAGIC, 131). 214 215-define(REFERENCE_EXT, 101). 216-define(PORT_EXT, 102). 217-define(PID_EXT, 103). 218-define(NEW_REFERENCE_EXT, 114). 219-define(NEW_PID_EXT, $X). 220-define(NEW_PORT_EXT, $Y). 221-define(NEWER_REFERENCE_EXT, $Z). 222-define(V4_PORT_EXT, $x). 223 224-define(OLD_MAX_PIDS_PORTS, ((1 bsl 28) - 1)). 225 226uint64_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 64 -> 227 [(Uint bsr 56) band 16#ff, 228 (Uint bsr 48) band 16#ff, 229 (Uint bsr 40) band 16#ff, 230 (Uint bsr 32) band 16#ff, 231 (Uint bsr 24) band 16#ff, 232 (Uint bsr 16) band 16#ff, 233 (Uint bsr 8) band 16#ff, 234 Uint band 16#ff]; 235uint64_be(Uint) -> 236 exit({badarg, uint64_be, [Uint]}). 237 238uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 -> 239 [(Uint bsr 24) band 16#ff, 240 (Uint bsr 16) band 16#ff, 241 (Uint bsr 8) band 16#ff, 242 Uint band 16#ff]; 243uint32_be(Uint) -> 244 exit({badarg, uint32_be, [Uint]}). 245 246 247uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 -> 248 [(Uint bsr 8) band 16#ff, 249 Uint band 16#ff]; 250uint16_be(Uint) -> 251 exit({badarg, uint16_be, [Uint]}). 252 253uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 -> 254 Uint band 16#ff; 255uint8(Uint) -> 256 exit({badarg, uint8, [Uint]}). 257 258pid_tag(Creation) when Creation =< 3 -> ?PID_EXT; 259pid_tag(_Creation) -> ?NEW_PID_EXT. 260 261enc_creation(Creation) when Creation =< 3 -> uint8(Creation); 262enc_creation(Creation) -> uint32_be(Creation). 263 264mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) -> 265 <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 266 mk_pid({NodeNameExt, Creation}, Number, Serial); 267mk_pid({NodeNameExt, Creation}, Number, Serial) -> 268 case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 269 pid_tag(Creation), 270 NodeNameExt, 271 uint32_be(Number), 272 uint32_be(Serial), 273 enc_creation(Creation)])) of 274 Pid when is_pid(Pid) -> 275 Pid; 276 {'EXIT', {badarg, _}} -> 277 exit({badarg, mk_pid, [{NodeNameExt, Creation}, Number, Serial]}); 278 Other -> 279 exit({unexpected_binary_to_term_result, Other}) 280 end. 281 282port_tag(Num, Creation) when 0 =< Num, Num =< ?OLD_MAX_PIDS_PORTS, Creation =< 3 -> 283 ?PORT_EXT; 284port_tag(Num, _Creation) when 0 =< Num, Num =< ?OLD_MAX_PIDS_PORTS -> 285 ?NEW_PORT_EXT; 286port_tag(_Num, _Creation) -> 287 ?V4_PORT_EXT. 288 289mk_port({NodeName, Creation}, Number) when is_atom(NodeName) -> 290 <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 291 mk_port({NodeNameExt, Creation}, Number); 292mk_port({NodeNameExt, Creation}, Number) -> 293 case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 294 port_tag(Number, Creation), 295 NodeNameExt, 296 case Number > ?OLD_MAX_PIDS_PORTS of 297 true -> uint64_be(Number); 298 false -> uint32_be(Number) 299 end, 300 enc_creation(Creation)])) of 301 Port when is_port(Port) -> 302 Port; 303 {'EXIT', {badarg, _}} -> 304 exit({badarg, mk_port, [{NodeNameExt, Creation}, Number]}); 305 Other -> 306 exit({unexpected_binary_to_term_result, Other}) 307 end. 308 309ref_tag(Creation) when Creation =< 3 -> ?NEW_REFERENCE_EXT; 310ref_tag(_Creation) -> ?NEWER_REFERENCE_EXT. 311 312mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName), 313 is_integer(Creation), 314 is_list(Numbers) -> 315 <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 316 mk_ref({NodeNameExt, Creation}, Numbers); 317mk_ref({NodeNameExt, Creation}, [Number]) when is_binary(NodeNameExt), 318 is_integer(Creation), 319 Creation =< 3, 320 is_integer(Number) -> 321 case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 322 ?REFERENCE_EXT, 323 NodeNameExt, 324 uint32_be(Number), 325 uint8(Creation)])) of 326 Ref when is_reference(Ref) -> 327 Ref; 328 {'EXIT', {badarg, _}} -> 329 exit({badarg, mk_ref, [{NodeNameExt, Creation}, [Number]]}); 330 Other -> 331 exit({unexpected_binary_to_term_result, Other}) 332 end; 333mk_ref({NodeNameExt, Creation}, Numbers) when is_binary(NodeNameExt), 334 is_integer(Creation), 335 is_list(Numbers) -> 336 case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 337 ref_tag(Creation), 338 uint16_be(length(Numbers)), 339 NodeNameExt, 340 enc_creation(Creation), 341 lists:map(fun (N) -> 342 uint32_be(N) 343 end, 344 Numbers)])) of 345 Ref when is_reference(Ref) -> 346 Ref; 347 {'EXIT', {badarg, _}} -> 348 exit({badarg, mk_ref, [{NodeNameExt, Creation}, Numbers]}); 349 Other -> 350 exit({unexpected_binary_to_term_result, Other}) 351 end. 352 353 354 355unicode_atom_data() -> 356 [uc_atup(lists:seq(16#1f600, 16#1f600+254)), 357 uc_atup(lists:seq(16#1f600, 16#1f600+63)), 358 uc_atup(lists:seq(1, 255)), 359 uc_atup(lists:seq(100, 163)), 360 uc_atup(lists:seq(200, 354)), 361 uc_atup(lists:seq(200, 263)), 362 uc_atup(lists:seq(2000, 2254)), 363 uc_atup(lists:seq(2000, 2063)), 364 uc_atup(lists:seq(65500, 65754)), 365 uc_atup(lists:seq(65500, 65563)) 366 | lists:map(fun (N) -> 367 Pow2 = (1 bsl N), 368 uc_atup(lists:seq(Pow2 - 127, Pow2 + 127)) 369 end, 370 lists:seq(7, 20)) 371 ]. 372 373uc_atup(ATxt) -> 374 string_to_atom(ATxt). 375 376string_to_atom(String) -> 377 Utf8List = string_to_utf8_list(String), 378 Len = length(Utf8List), 379 TagLen = case Len < 256 of 380 true -> [119, Len]; 381 false -> [118, Len bsr 8, Len band 16#ff] 382 end, 383 binary_to_term(list_to_binary([131, TagLen, Utf8List])). 384 385string_to_utf8_list([]) -> 386 []; 387string_to_utf8_list([CP|CPs]) when is_integer(CP), 388 0 =< CP, 389 CP =< 16#7F -> 390 [CP | string_to_utf8_list(CPs)]; 391string_to_utf8_list([CP|CPs]) when is_integer(CP), 392 16#80 =< CP, 393 CP =< 16#7FF -> 394 [16#C0 bor (CP bsr 6), 395 16#80 bor (16#3F band CP) 396 | string_to_utf8_list(CPs)]; 397string_to_utf8_list([CP|CPs]) when is_integer(CP), 398 16#800 =< CP, 399 CP =< 16#FFFF -> 400 [16#E0 bor (CP bsr 12), 401 16#80 bor (16#3F band (CP bsr 6)), 402 16#80 bor (16#3F band CP) 403 | string_to_utf8_list(CPs)]; 404string_to_utf8_list([CP|CPs]) when is_integer(CP), 405 16#10000 =< CP, 406 CP =< 16#10FFFF -> 407 [16#F0 bor (CP bsr 18), 408 16#80 bor (16#3F band (CP bsr 12)), 409 16#80 bor (16#3F band (CP bsr 6)), 410 16#80 bor (16#3F band CP) 411 | string_to_utf8_list(CPs)]. 412