1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2005-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%%% File : erl_print_SUITE.erl 23%%% Author : Rickard Green <rickard.s.green@ericsson.com> 24%%% Description : 25%%% 26%%% Created : 10 Mar 2005 by Rickard Green <rickard.s.green@ericsson.com> 27%%%------------------------------------------------------------------- 28-module(erl_print_SUITE). 29-author('rickard.s.green@ericsson.com'). 30 31-export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2]). 32 33-export([erlang_display/1, integer/1, float/1, 34 string/1, character/1, snprintf/1, quote/1]). 35 36-include_lib("common_test/include/ct.hrl"). 37 38suite() -> 39 [{ct_hooks,[ts_install_cth]}, 40 {timetrap, {minutes, 10}}]. 41 42all() -> 43 [erlang_display, integer, float, string, character, 44 snprintf, quote]. 45 46init_per_testcase(Case, Config) -> 47 [{testcase, Case}|Config]. 48 49end_per_testcase(_Case, _Config) -> 50 ok. 51 52%% 53%% 54%% Test cases 55%% 56%% 57 58erlang_display(Config) when is_list(Config) -> 59 put(erlang_display_test, ok), 60 OAIS = erts_debug:set_internal_state(available_internal_state, true), 61 62 %% atoms 63 chk_display(atom, "atom"), 64 chk_display(true, "true"), 65 chk_display(false, "false"), 66 chk_display('DOWN', "'DOWN'"), 67 chk_display('EXIT', "'EXIT'"), 68 chk_display('asdDofw $@{}][', "'asdDofw $@{}]['"), 69 70 %% integers 71 chk_display(0, "0"), 72 chk_display(1, "1"), 73 chk_display(4711, "4711"), 74 chk_display(((1 bsl 27) - 1), "134217727"), 75 chk_display((1 bsl 27), "134217728"), 76 chk_display((1 bsl 32), "4294967296"), 77 chk_display(11111111111, "11111111111"), 78 chk_display((1 bsl 59) - 1, "576460752303423487"), 79 chk_display(1 bsl 59, "576460752303423488"), 80 chk_display(111111111111111111111, "111111111111111111111"), 81 chk_display(123456789012345678901234567890, 82 "123456789012345678901234567890"), 83 chk_display(1 bsl 10000, str_1_bsl_10000()), 84 chk_display(-1, "-1"), 85 chk_display(-4711, "-4711"), 86 chk_display(-(1 bsl 27), "-134217728"), 87 chk_display(-((1 bsl 27) + 1), "-134217729"), 88 chk_display(-(1 bsl 32), "-4294967296"), 89 chk_display(-11111111111, "-11111111111"), 90 chk_display(-(1 bsl 59), "-576460752303423488"), 91 chk_display(-((1 bsl 59) + 1), "-576460752303423489"), 92 chk_display(-111111111111111111111, "-111111111111111111111"), 93 chk_display(-123456789012345678901234567890, 94 "-123456789012345678901234567890"), 95 chk_display(-(1 bsl 10000), [$- | str_1_bsl_10000()]), 96 97 MyCre = my_cre(), 98 99 %% pids 100 chk_display(mk_pid_xstr({node(), MyCre}, 4711, 42)), 101 chk_display(mk_pid_xstr({node(), oth_cre(MyCre)}, 4711, 42)), 102 chk_display(mk_pid_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711, 42)), 103 104 chk_display(mk_pid_xstr({a@b, MyCre}, 4711, 42)), 105 chk_display(mk_pid_xstr({a@b, oth_cre(MyCre)}, 4711, 42)), 106 chk_display(mk_pid_xstr({a@b, oth_cre(oth_cre(MyCre))}, 4711, 42)), 107 108 %% ports 109 chk_display(mk_port_xstr({node(), MyCre}, 4711)), 110 chk_display(mk_port_xstr({node(), oth_cre(MyCre)}, 4711)), 111 chk_display(mk_port_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711)), 112 113 chk_display(mk_port_xstr({c@d, MyCre}, 4711)), 114 chk_display(mk_port_xstr({c@d, oth_cre(MyCre)}, 4711)), 115 chk_display(mk_port_xstr({c@d, oth_cre(oth_cre(MyCre))}, 4711)), 116 117 %% refs 118 chk_display(mk_ref_xstr({node(), MyCre}, [1,2,3])), 119 chk_display(mk_ref_xstr({node(), oth_cre(MyCre)}, [1,2,3])), 120 chk_display(mk_ref_xstr({node(), oth_cre(oth_cre(MyCre))}, [1,2,3])), 121 122 chk_display(mk_ref_xstr({e@f, MyCre},[1,2,3] )), 123 chk_display(mk_ref_xstr({e@f, oth_cre(MyCre)}, [1,2,3])), 124 chk_display(mk_ref_xstr({e@f, oth_cre(oth_cre(MyCre))}, [1,2,3])), 125 126 %% Compund terms 127 {Pid, PidStr} = mk_pid_xstr({x@y, oth_cre(MyCre)}, 4712, 41), 128 {Port, PortStr} = mk_port_xstr({x@y, oth_cre(MyCre)}, 4712), 129 {Ref, RefStr} = mk_ref_xstr({e@f, oth_cre(MyCre)}, [11,12,13]), 130 131 chk_display({atom,-4711,Ref,{"hej",[Pid,222222222222222222222222,Port,4711]}}, 132 "{atom,-4711,"++RefStr++",{\"hej\",["++PidStr++",222222222222222222222222,"++PortStr++",4711]}}"), 133 chk_display({{{{{{{{{{{{{{{{{{{{{{{hi}}}}}}}}}}}}}}}}}}}}}}}, 134 "{{{{{{{{{{{{{{{{{{{{{{{hi}}}}}}}}}}}}}}}}}}}}}}}"), 135 chk_display([[[[[[[[[[[[[[[[[[[[[[[yo]]]]]]]]]]]]]]]]]]]]]]], 136 "[[[[[[[[[[[[[[[[[[[[[[[yo]]]]]]]]]]]]]]]]]]]]]]]"), 137 chk_display({[{[{[{[{[{[{[{[{[{[{[{[ii]}]}]}]}]}]}]}]}]}]}]}]}, 138 "{[{[{[{[{[{[{[{[{[{[{[{[ii]}]}]}]}]}]}]}]}]}]}]}]}"), 139 chk_display([], "[]"), % Not really a compound term :) 140 chk_display([a|b], "[a|b]"), 141 chk_display([a,b,c|z], "[a,b,c|z]"), 142 chk_display([a,b,c], "[a,b,c]"), 143 chk_display([Pid,Port,Ref], 144 "["++PidStr++","++PortStr++","++RefStr++"]"), 145 chk_display("abcdefghijklmnopqrstuvwxyz", 146 "\"abcdefghijklmnopqrstuvwxyz\""), 147 chk_display("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 148 "\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\""), 149 chk_display("H E J", "\"H E J\""), 150 chk_display("asdDofw $@{}][", "\"asdDofw $@{}][\""), 151 152 %% 153 %% TODO: Check binaries, fun and floats... 154 %% 155 156 erts_debug:set_internal_state(available_internal_state, OAIS), 157 ok = get(erlang_display_test). 158 159get_chnl_no(NodeName) when is_atom(NodeName) -> 160 erts_debug:get_internal_state({channel_number, NodeName}). 161 162chk_display(Term, Expect) when is_list(Expect) -> 163 Dstr = erts_debug:display(Term), 164 case Expect ++ io_lib:nl() of 165 Dstr -> 166 io:format("Test of \"~p\" succeeded.~n" 167 " Expected and got: ~s~n", 168 [Term, io_lib:write_string(Dstr)]); 169 DoExpect -> 170 io:format("***~n" 171 "*** Test of \"~p\" failed!~n" 172 "*** Expected: ~s~n" 173 "*** Got: ~s~n" 174 "***~n", 175 [Term, 176 io_lib:write_string(DoExpect), 177 io_lib:write_string(Dstr)]), 178 put(erlang_display_test, failed) 179 end. 180 181chk_display({Term, Expect}) -> 182 chk_display(Term, Expect). 183 184mk_pid_xstr({NodeName, Creation}, Number, Serial) -> 185 Pid = mk_pid({NodeName, Creation}, Number, Serial), 186 XStr = "<" ++ integer_to_list(get_chnl_no(NodeName)) 187 ++ "." ++ integer_to_list(Number) 188 ++ "." ++ integer_to_list(Serial) ++ ">", 189 {Pid, XStr}. 190 191mk_port_xstr({NodeName, Creation}, Number) -> 192 Port = mk_port({NodeName, Creation}, Number), 193 XStr = "#Port<" ++ integer_to_list(get_chnl_no(NodeName)) 194 ++ "." ++ integer_to_list(Number) ++ ">", 195 {Port, XStr}. 196 197mk_ref_xstr({NodeName, Creation}, Numbers) -> 198 Ref = mk_ref({NodeName, Creation}, Numbers), 199 XStr = "#Ref<" ++ integer_to_list(get_chnl_no(NodeName)) 200 ++ ref_numbers_xstr(Numbers) ++ ">", 201 {Ref, XStr}. 202 203ref_numbers_xstr([]) -> 204 []; 205ref_numbers_xstr([N | Ns]) -> 206 ref_numbers_xstr(Ns) ++ "." ++ integer_to_list(N). 207 208-define(TESTCASE_IMPL(T), T(A) -> default_testcase_impl(A)). 209 210?TESTCASE_IMPL(integer). 211?TESTCASE_IMPL(float). 212?TESTCASE_IMPL(string). 213?TESTCASE_IMPL(character). 214?TESTCASE_IMPL(snprintf). 215?TESTCASE_IMPL(quote). 216 217%% 218%% 219%% Auxiliary functions 220%% 221%% 222 223default_testcase_impl(Config) when is_list(Config) -> run_case(Config). 224 225-define(TESTPROG, "erl_print_tests"). 226-define(FAILED_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$F,$A,$I,$L,$U,$R,$E). 227-define(SKIPPED_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$S,$K,$I,$P). 228-define(SUCCESS_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$S,$U,$C,$C,$E,$S,$S). 229-define(PID_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$P,$I,$D). 230 231port_prog_killer(EProc, OSProc) when is_pid(EProc), is_list(OSProc) -> 232 process_flag(trap_exit, true), 233 Ref = erlang:monitor(process, EProc), 234 receive 235 {'DOWN', Ref, _, _, Reason} when is_tuple(Reason), 236 element(1, Reason) 237 == timetrap_timeout -> 238 Cmd = "kill -9 " ++ OSProc, 239 io:format("Test case timed out. " 240 "Trying to kill port program.~n" 241 " Executing: ~p~n", [Cmd]), 242 case os:cmd(Cmd) of 243 [] -> 244 ok; 245 OsCmdRes -> 246 io:format(" ~s", [OsCmdRes]) 247 end; 248 {'DOWN', Ref, _, _, _} -> 249 %% OSProc is assumed to have terminated by itself 250 ok 251 end. 252 253get_line(_Port, eol, Data) -> 254 Data; 255get_line(Port, noeol, Data) -> 256 receive 257 {Port, {data, {Flag, NextData}}} -> 258 get_line(Port, Flag, Data ++ NextData); 259 {Port, eof} -> 260 ct:fail(port_prog_unexpectedly_closed) 261 end. 262 263read_case_data(Port, TestCase) -> 264 receive 265 {Port, {data, {eol, [?SUCCESS_MARKER]}}} -> 266 ok; 267 {Port, {data, {Flag, [?SUCCESS_MARKER | CommentStart]}}} -> 268 {comment, get_line(Port, Flag, CommentStart)}; 269 {Port, {data, {Flag, [?SKIPPED_MARKER | CommentStart]}}} -> 270 {skipped, get_line(Port, Flag, CommentStart)}; 271 {Port, {data, {Flag, [?FAILED_MARKER | ReasonStart]}}} -> 272 ct:fail(get_line(Port, Flag, ReasonStart)); 273 {Port, {data, {eol, [?PID_MARKER | PidStr]}}} -> 274 io:format("Port program pid: ~s~n", [PidStr]), 275 CaseProc = self(), 276 _ = list_to_integer(PidStr), % Sanity check 277 spawn_opt(fun () -> 278 port_prog_killer(CaseProc, PidStr) 279 end, 280 [{priority, max}, link]), 281 read_case_data(Port, TestCase); 282 {Port, {data, {Flag, LineStart}}} -> 283 io:format("~s~n", [get_line(Port, Flag, LineStart)]), 284 read_case_data(Port, TestCase); 285 {Port, eof} -> 286 ct:fail(port_prog_unexpectedly_closed) 287 end. 288 289run_case(Config) -> 290 run_case(Config, ""). 291 292run_case(Config, TestArgs) -> 293 run_case(Config, TestArgs, fun (_Port) -> ok end). 294 295run_case(Config, TestArgs, Fun) -> 296 Test = atom_to_list(proplists:get_value(testcase, Config)), 297 TestProg = filename:join([proplists:get_value(data_dir, Config), 298 ?TESTPROG 299 ++ "." 300 ++ atom_to_list(erlang:system_info(threads))]), 301 Cmd = TestProg ++ " " ++ Test ++ " " ++ TestArgs, 302 case catch open_port({spawn, Cmd}, [stream, 303 use_stdio, 304 stderr_to_stdout, 305 eof, 306 {line, 1024}]) of 307 Port when is_port(Port) -> 308 Fun(Port), 309 CaseResult = read_case_data(Port, Test), 310 receive 311 {Port, eof} -> 312 ok 313 end, 314 CaseResult; 315 Error -> 316 ct:fail({open_port_failed, Error}) 317 end. 318 319 320-define(VERSION_MAGIC, 131). 321 322-define(ATOM_EXT, 100). 323-define(REFERENCE_EXT, 101). 324-define(PORT_EXT, 102). 325-define(PID_EXT, 103). 326-define(NEW_REFERENCE_EXT, 114). 327-define(NEW_PID_EXT, $X). 328-define(NEW_PORT_EXT, $Y). 329-define(NEWER_REFERENCE_EXT, $Z). 330 331uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 -> 332 [(Uint bsr 24) band 16#ff, 333 (Uint bsr 16) band 16#ff, 334 (Uint bsr 8) band 16#ff, 335 Uint band 16#ff]; 336uint32_be(Uint) -> 337 exit({badarg, uint32_be, [Uint]}). 338 339 340uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 -> 341 [(Uint bsr 8) band 16#ff, 342 Uint band 16#ff]; 343uint16_be(Uint) -> 344 exit({badarg, uint16_be, [Uint]}). 345 346uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 -> 347 Uint band 16#ff; 348uint8(Uint) -> 349 exit({badarg, uint8, [Uint]}). 350 351 352 353mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) -> 354 mk_pid({atom_to_list(NodeName), Creation}, Number, Serial); 355mk_pid({NodeName, Creation}, Number, Serial) -> 356 case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 357 ?NEW_PID_EXT, 358 ?ATOM_EXT, 359 uint16_be(length(NodeName)), 360 NodeName, 361 uint32_be(Number), 362 uint32_be(Serial), 363 uint32_be(Creation)])) of 364 Pid when is_pid(Pid) -> 365 Pid; 366 {'EXIT', {badarg, _}} -> 367 exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]}); 368 Other -> 369 exit({unexpected_binary_to_term_result, Other}) 370 end. 371 372mk_port({NodeName, Creation}, Number) when is_atom(NodeName) -> 373 mk_port({atom_to_list(NodeName), Creation}, Number); 374mk_port({NodeName, Creation}, Number) -> 375 case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 376 ?NEW_PORT_EXT, 377 ?ATOM_EXT, 378 uint16_be(length(NodeName)), 379 NodeName, 380 uint32_be(Number), 381 uint32_be(Creation)])) of 382 Port when is_port(Port) -> 383 Port; 384 {'EXIT', {badarg, _}} -> 385 exit({badarg, mk_port, [{NodeName, Creation}, Number]}); 386 Other -> 387 exit({unexpected_binary_to_term_result, Other}) 388 end. 389 390mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName), 391 is_integer(Creation), 392 is_list(Numbers) -> 393 mk_ref({atom_to_list(NodeName), Creation}, Numbers); 394mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName), 395 is_integer(Creation), 396 is_list(Numbers) -> 397 case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 398 ?NEWER_REFERENCE_EXT, 399 uint16_be(length(Numbers)), 400 ?ATOM_EXT, 401 uint16_be(length(NodeName)), 402 NodeName, 403 uint32_be(Creation), 404 lists:map(fun (N) -> 405 uint32_be(N) 406 end, 407 Numbers)])) of 408 Ref when is_reference(Ref) -> 409 Ref; 410 {'EXIT', {badarg, _}} -> 411 exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]}); 412 Other -> 413 exit({unexpected_binary_to_term_result, Other}) 414 end. 415 416my_cre() -> erlang:system_info(creation). 417 418oth_cre(N) when N >= 0, N < (1 bsl 32) -> 419 (N rem ((1 bsl 32) - 1)) + 1; 420oth_cre(N) -> 421 exit({invalid_creation, N}). 422 423str_1_bsl_10000() -> 424 "19950631168807583848837421626835850838234968318861924548520089498529438830221946631919961684036194597899331129423209124271556491349413781117593785932096323957855730046793794526765246551266059895520550086918193311542508608460618104685509074866089624888090489894838009253941633257850621568309473902556912388065225096643874441046759871626985453222868538161694315775629640762836880760732228535091641476183956381458969463899410840960536267821064621427333394036525565649530603142680234969400335934316651459297773279665775606172582031407994198179607378245683762280037302885487251900834464581454650557929601414833921615734588139257095379769119277800826957735674444123062018757836325502728323789270710373802866393031428133241401624195671690574061419654342324638801248856147305207431992259611796250130992860241708340807605932320161268492288496255841312844061536738951487114256315111089745514203313820202931640957596464756010405845841566072044962867016515061920631004186422275908670900574606417856951911456055068251250406007519842261898059237118054444788072906395242548339221982707404473162376760846613033778706039803413197133493654622700563169937455508241780972810983291314403571877524768509857276937926433221599399876886660808368837838027643282775172273657572744784112294389733810861607423253291974813120197604178281965697475898164531258434135959862784130128185406283476649088690521047580882615823961985770122407044330583075869039319604603404973156583208672105913300903752823415539745394397715257455290510212310947321610753474825740775273986348298498340756937955646638621874569499279016572103701364433135817214311791398222983845847334440270964182851005072927748364550578634501100852987812389473928699540834346158807043959118985815145779177143619698728131459483783202081474982171858011389071228250905826817436220577475921417653715687725614904582904992461028630081535583308130101987675856234343538955409175623400844887526162643568648833519463720377293240094456246923254350400678027273837755376406726898636241037491410966718557050759098100246789880178271925953381282421954028302759408448955014676668389697996886241636313376393903373455801407636741877711055384225739499110186468219696581651485130494222369947714763069155468217682876200362777257723781365331611196811280792669481887201298643660768551639860534602297871557517947385246369446923087894265948217008051120322365496288169035739121368338393591756418733850510970271613915439590991598154654417336311656936031122249937969999226781732358023111862644575299135758175008199839236284615249881088960232244362173771618086357015468484058622329792853875623486556440536962622018963571028812361567512543338303270029097668650568557157505516727518899194129711337690149916181315171544007728650573189557450920330185304847113818315407324053319038462084036421763703911550639789000742853672196280903477974533320468368795868580237952218629120080742819551317948157624448298518461509704888027274721574688131594750409732115080498190455803416826949787141316063210686391511681774304792596709376". 425