diff options
Diffstat (limited to 'erts/test')
38 files changed, 10280 insertions, 0 deletions
diff --git a/erts/test/Makefile b/erts/test/Makefile new file mode 100644 index 0000000000..47e41a3625 --- /dev/null +++ b/erts/test/Makefile @@ -0,0 +1,81 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include $(ERL_TOP)/make/target.mk + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +EBIN = . + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES= \ + erlc_SUITE \ + nt_SUITE \ + otp_SUITE \ + ethread_SUITE \ + erl_print_SUITE \ + run_erl_SUITE \ + erlexec_SUITE \ + z_SUITE + + +ERL_FILES= $(MODULES:%=%.erl) + +TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/system_test + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +tests debug opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f core *~ + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: + +release_tests_spec: opt + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) system.spec system.dynspec system.spec.vxworks \ + $(ERL_FILES) $(TARGET_FILES) $(RELSYSDIR) + chmod -f -R u+w $(RELSYSDIR) + tar cf - *_SUITE_data utils | (cd $(RELSYSDIR); tar xf -) + +release_docs_spec: diff --git a/erts/test/erl_print_SUITE.erl b/erts/test/erl_print_SUITE.erl new file mode 100644 index 0000000000..b1458d84d0 --- /dev/null +++ b/erts/test/erl_print_SUITE.erl @@ -0,0 +1,453 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%%------------------------------------------------------------------- +%%% File : erl_print_SUITE.erl +%%% Author : Rickard Green <[email protected]> +%%% Description : +%%% +%%% Created : 10 Mar 2005 by Rickard Green <[email protected]> +%%%------------------------------------------------------------------- +-module(erl_print_SUITE). +-author('[email protected]'). + + +%-define(line_trace, 1). + +-define(DEFAULT_TIMEOUT, ?t:minutes(10)). + +-export([all/1, init_per_testcase/2, fin_per_testcase/2]). + +-export([erlang_display/1, integer/1, float/1, string/1, character/1, snprintf/1, quote/1]). + +-include("test_server.hrl"). + +all(doc) -> []; +all(suite) -> test_cases(). + +%% +%% +%% Test cases +%% +%% + +test_cases() -> + [erlang_display, + integer, + float, + string, + character, + snprintf, + quote]. + +erlang_display(doc) -> []; +erlang_display(suite) -> []; +erlang_display(Config) when is_list(Config) -> + ?line put(erlang_display_test, ok), + OAIS = erts_debug:set_internal_state(available_internal_state, true), + + %% atoms + ?line chk_display(atom, "atom"), + ?line chk_display(true, "true"), + ?line chk_display(false, "false"), + ?line chk_display('DOWN', "'DOWN'"), + ?line chk_display('EXIT', "'EXIT'"), + ?line chk_display('asdDofw $@{}][', "'asdDofw $@{}]['"), + + %% integers + ?line chk_display(0, "0"), + ?line chk_display(1, "1"), + ?line chk_display(4711, "4711"), + ?line chk_display(((1 bsl 27) - 1), "134217727"), + ?line chk_display((1 bsl 27), "134217728"), + ?line chk_display((1 bsl 32), "4294967296"), + ?line chk_display(11111111111, "11111111111"), + ?line chk_display((1 bsl 59) - 1, "576460752303423487"), + ?line chk_display(1 bsl 59, "576460752303423488"), + ?line chk_display(111111111111111111111, "111111111111111111111"), + ?line chk_display(123456789012345678901234567890, + "123456789012345678901234567890"), + ?line chk_display(1 bsl 10000, str_1_bsl_10000()), + ?line chk_display(-1, "-1"), + ?line chk_display(-4711, "-4711"), + ?line chk_display(-(1 bsl 27), "-134217728"), + ?line chk_display(-((1 bsl 27) + 1), "-134217729"), + ?line chk_display(-(1 bsl 32), "-4294967296"), + ?line chk_display(-11111111111, "-11111111111"), + ?line chk_display(-(1 bsl 59), "-576460752303423488"), + ?line chk_display(-((1 bsl 59) + 1), "-576460752303423489"), + ?line chk_display(-111111111111111111111, "-111111111111111111111"), + ?line chk_display(-123456789012345678901234567890, + "-123456789012345678901234567890"), + ?line chk_display(-(1 bsl 10000), [$- | str_1_bsl_10000()]), + + ?line MyCre = my_cre(), + + %% pids + ?line chk_display(mk_pid_xstr({node(), MyCre}, 4711, 42)), + ?line chk_display(mk_pid_xstr({node(), oth_cre(MyCre)}, 4711, 42)), + ?line chk_display(mk_pid_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711, 42)), + + ?line chk_display(mk_pid_xstr({a@b, MyCre}, 4711, 42)), + ?line chk_display(mk_pid_xstr({a@b, oth_cre(MyCre)}, 4711, 42)), + ?line chk_display(mk_pid_xstr({a@b, oth_cre(oth_cre(MyCre))}, 4711, 42)), + + %% ports + ?line chk_display(mk_port_xstr({node(), MyCre}, 4711)), + ?line chk_display(mk_port_xstr({node(), oth_cre(MyCre)}, 4711)), + ?line chk_display(mk_port_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711)), + + ?line chk_display(mk_port_xstr({c@d, MyCre}, 4711)), + ?line chk_display(mk_port_xstr({c@d, oth_cre(MyCre)}, 4711)), + ?line chk_display(mk_port_xstr({c@d, oth_cre(oth_cre(MyCre))}, 4711)), + + %% refs + ?line chk_display(mk_ref_xstr({node(), MyCre}, [1,2,3])), + ?line chk_display(mk_ref_xstr({node(), oth_cre(MyCre)}, [1,2,3])), + ?line chk_display(mk_ref_xstr({node(), oth_cre(oth_cre(MyCre))}, [1,2,3])), + + ?line chk_display(mk_ref_xstr({e@f, MyCre},[1,2,3] )), + ?line chk_display(mk_ref_xstr({e@f, oth_cre(MyCre)}, [1,2,3])), + ?line chk_display(mk_ref_xstr({e@f, oth_cre(oth_cre(MyCre))}, [1,2,3])), + + %% Compund terms + ?line {Pid, PidStr} = mk_pid_xstr({x@y, oth_cre(MyCre)}, 4712, 41), + ?line {Port, PortStr} = mk_port_xstr({x@y, oth_cre(MyCre)}, 4712), + ?line {Ref, RefStr} = mk_ref_xstr({e@f, oth_cre(MyCre)}, [11,12,13]), + + ?line chk_display({atom,-4711,Ref,{"hej",[Pid,222222222222222222222222,Port,4711]}}, + "{atom,-4711,"++RefStr++",{\"hej\",["++PidStr++",222222222222222222222222,"++PortStr++",4711]}}"), + ?line chk_display({{{{{{{{{{{{{{{{{{{{{{{hi}}}}}}}}}}}}}}}}}}}}}}}, + "{{{{{{{{{{{{{{{{{{{{{{{hi}}}}}}}}}}}}}}}}}}}}}}}"), + ?line chk_display([[[[[[[[[[[[[[[[[[[[[[[yo]]]]]]]]]]]]]]]]]]]]]]], + "[[[[[[[[[[[[[[[[[[[[[[[yo]]]]]]]]]]]]]]]]]]]]]]]"), + ?line chk_display({[{[{[{[{[{[{[{[{[{[{[{[ii]}]}]}]}]}]}]}]}]}]}]}]}, + "{[{[{[{[{[{[{[{[{[{[{[{[ii]}]}]}]}]}]}]}]}]}]}]}]}"), + ?line chk_display([], "[]"), % Not really a compound term :) + ?line chk_display([a|b], "[a|b]"), + ?line chk_display([a,b,c|z], "[a,b,c|z]"), + ?line chk_display([a,b,c], "[a,b,c]"), + ?line chk_display([Pid,Port,Ref], + "["++PidStr++","++PortStr++","++RefStr++"]"), + ?line chk_display("abcdefghijklmnopqrstuvwxyz", + "\"abcdefghijklmnopqrstuvwxyz\""), + ?line chk_display("ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\""), + ?line chk_display("H E J", "\"H E J\""), + ?line chk_display("asdDofw $@{}][", "\"asdDofw $@{}][\""), + + %% + %% TODO: Check binaries, fun and floats... + %% + + erts_debug:set_internal_state(available_internal_state, OAIS), + ?line ok = get(erlang_display_test). + +get_chnl_no(NodeName) when is_atom(NodeName) -> + erts_debug:get_internal_state({channel_number, NodeName}). + +chk_display(Term, Expect) when is_list(Expect) -> + Dstr = erts_debug:display(Term), + case Expect ++ io_lib:nl() of + Dstr -> + ?t:format("Test of \"~p\" succeeded.~n" + " Expected and got: ~s~n", + [Term, io_lib:write_string(Dstr)]); + DoExpect -> + ?t:format("***~n" + "*** Test of \"~p\" failed!~n" + "*** Expected: ~s~n" + "*** Got: ~s~n" + "***~n", + [Term, + io_lib:write_string(DoExpect), + io_lib:write_string(Dstr)]), + put(erlang_display_test, failed) + end. + +chk_display({Term, Expect}) -> + chk_display(Term, Expect). + +mk_pid_xstr({NodeName, Creation}, Number, Serial) -> + Pid = mk_pid({NodeName, Creation}, Number, Serial), + XStr = "<" ++ integer_to_list(get_chnl_no(NodeName)) + ++ "." ++ integer_to_list(Number) + ++ "." ++ integer_to_list(Serial) ++ ">", + {Pid, XStr}. + +mk_port_xstr({NodeName, Creation}, Number) -> + Port = mk_port({NodeName, Creation}, Number), + XStr = "#Port<" ++ integer_to_list(get_chnl_no(NodeName)) + ++ "." ++ integer_to_list(Number) ++ ">", + {Port, XStr}. + +mk_ref_xstr({NodeName, Creation}, Numbers) -> + Ref = mk_ref({NodeName, Creation}, Numbers), + XStr = "#Ref<" ++ integer_to_list(get_chnl_no(NodeName)) + ++ ref_numbers_xstr(Numbers) ++ ">", + {Ref, XStr}. + +ref_numbers_xstr([]) -> + []; +ref_numbers_xstr([N | Ns]) -> + ref_numbers_xstr(Ns) ++ "." ++ integer_to_list(N). + +-define(TESTCASE_IMPL(T), T(A) -> default_testcase_impl(A)). + +?TESTCASE_IMPL(integer). +?TESTCASE_IMPL(float). +?TESTCASE_IMPL(string). +?TESTCASE_IMPL(character). +?TESTCASE_IMPL(snprintf). +?TESTCASE_IMPL(quote). + +%% +%% +%% Auxiliary functions +%% +%% + +default_testcase_impl(doc) -> []; +default_testcase_impl(suite) -> []; +default_testcase_impl(Config) when is_list(Config) -> ?line run_case(Config). + +init_per_testcase(Case, Config) -> + Dog = ?t:timetrap(?DEFAULT_TIMEOUT), + [{testcase, Case}, {watchdog, Dog} |Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +-define(TESTPROG, "erl_print_tests"). +-define(FAILED_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$F,$A,$I,$L,$U,$R,$E). +-define(SKIPPED_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$S,$K,$I,$P). +-define(SUCCESS_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$S,$U,$C,$C,$E,$S,$S). +-define(PID_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$P,$I,$D). + +port_prog_killer(EProc, OSProc) when is_pid(EProc), is_list(OSProc) -> + ?line process_flag(trap_exit, true), + ?line Ref = erlang:monitor(process, EProc), + ?line receive + {'DOWN', Ref, _, _, Reason} when is_tuple(Reason), + element(1, Reason) + == timetrap_timeout -> + ?line Cmd = "kill -9 " ++ OSProc, + ?line ?t:format("Test case timed out. " + "Trying to kill port program.~n" + " Executing: ~p~n", [Cmd]), + ?line case os:cmd(Cmd) of + [] -> + ok; + OsCmdRes -> + ?line ?t:format(" ~s", [OsCmdRes]) + end; + {'DOWN', Ref, _, _, _} -> + %% OSProc is assumed to have terminated by itself + ?line ok + end. + +get_line(_Port, eol, Data) -> + ?line Data; +get_line(Port, noeol, Data) -> + ?line receive + {Port, {data, {Flag, NextData}}} -> + ?line get_line(Port, Flag, Data ++ NextData); + {Port, eof} -> + ?line ?t:fail(port_prog_unexpectedly_closed) + end. + +read_case_data(Port, TestCase) -> + ?line receive + {Port, {data, {eol, [?SUCCESS_MARKER]}}} -> + ?line ok; + {Port, {data, {Flag, [?SUCCESS_MARKER | CommentStart]}}} -> + ?line {comment, get_line(Port, Flag, CommentStart)}; + {Port, {data, {Flag, [?SKIPPED_MARKER | CommentStart]}}} -> + ?line {skipped, get_line(Port, Flag, CommentStart)}; + {Port, {data, {Flag, [?FAILED_MARKER | ReasonStart]}}} -> + ?line ?t:fail(get_line(Port, Flag, ReasonStart)); + {Port, {data, {eol, [?PID_MARKER | PidStr]}}} -> + ?line ?t:format("Port program pid: ~s~n", [PidStr]), + ?line CaseProc = self(), + ?line list_to_integer(PidStr), % Sanity check + spawn_opt(fun () -> + port_prog_killer(CaseProc, PidStr) + end, + [{priority, max}, link]), + read_case_data(Port, TestCase); + {Port, {data, {Flag, LineStart}}} -> + ?line ?t:format("~s~n", [get_line(Port, Flag, LineStart)]), + read_case_data(Port, TestCase); + {Port, eof} -> + ?line ?t:fail(port_prog_unexpectedly_closed) + end. + +run_case(Config) -> + run_case(Config, ""). + +run_case(Config, TestArgs) -> + run_case(Config, TestArgs, fun (_Port) -> ok end). + +run_case(Config, TestArgs, Fun) -> + Test = atom_to_list(?config(testcase, Config)), + TestProg = filename:join([?config(data_dir, Config), + ?TESTPROG + ++ "." + ++ atom_to_list(erlang:system_info(threads))]), + Cmd = TestProg ++ " " ++ Test ++ " " ++ TestArgs, + case catch open_port({spawn, Cmd}, [stream, + use_stdio, + stderr_to_stdout, + eof, + {line, 1024}]) of + Port when is_port(Port) -> + ?line Fun(Port), + ?line CaseResult = read_case_data(Port, Test), + ?line receive + {Port, eof} -> + ?line ok + end, + ?line CaseResult; + Error -> + ?line ?t:fail({open_port_failed, Error}) + end. + + +-define(VERSION_MAGIC, 131). + +-define(ATOM_EXT, 100). +-define(REFERENCE_EXT, 101). +-define(PORT_EXT, 102). +-define(PID_EXT, 103). +-define(NEW_REFERENCE_EXT, 114). + +uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 -> + [(Uint bsr 24) band 16#ff, + (Uint bsr 16) band 16#ff, + (Uint bsr 8) band 16#ff, + Uint band 16#ff]; +uint32_be(Uint) -> + exit({badarg, uint32_be, [Uint]}). + + +uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 -> + [(Uint bsr 8) band 16#ff, + Uint band 16#ff]; +uint16_be(Uint) -> + exit({badarg, uint16_be, [Uint]}). + +uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 -> + Uint band 16#ff; +uint8(Uint) -> + exit({badarg, uint8, [Uint]}). + + + +mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) -> + mk_pid({atom_to_list(NodeName), Creation}, Number, Serial); +mk_pid({NodeName, Creation}, Number, Serial) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?PID_EXT, + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint32_be(Number), + uint32_be(Serial), + uint8(Creation)])) of + Pid when is_pid(Pid) -> + Pid; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end. + +mk_port({NodeName, Creation}, Number) when is_atom(NodeName) -> + mk_port({atom_to_list(NodeName), Creation}, Number); +mk_port({NodeName, Creation}, Number) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?PORT_EXT, + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint32_be(Number), + uint8(Creation)])) of + Port when is_port(Port) -> + Port; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_port, [{NodeName, Creation}, Number]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end. + +mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName), + is_integer(Creation), + is_list(Numbers) -> + mk_ref({atom_to_list(NodeName), Creation}, Numbers); +mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName), + is_integer(Creation), + is_integer(Number) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?REFERENCE_EXT, + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint32_be(Number), + uint8(Creation)])) of + Ref when is_reference(Ref) -> + Ref; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_ref, [{NodeName, Creation}, [Number]]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end; +mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName), + is_integer(Creation), + is_list(Numbers) -> + case catch binary_to_term(list_to_binary([?VERSION_MAGIC, + ?NEW_REFERENCE_EXT, + uint16_be(length(Numbers)), + ?ATOM_EXT, + uint16_be(length(NodeName)), + NodeName, + uint8(Creation), + lists:map(fun (N) -> + uint32_be(N) + end, + Numbers)])) of + Ref when is_reference(Ref) -> + Ref; + {'EXIT', {badarg, _}} -> + exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]}); + Other -> + exit({unexpected_binary_to_term_result, Other}) + end. + +my_cre() -> erlang:system_info(creation). + +oth_cre(0) -> 1; +oth_cre(1) -> 2; +oth_cre(2) -> 3; +oth_cre(3) -> 1; +oth_cre(N) -> exit({invalid_creation, N}). + +str_1_bsl_10000() -> + "19950631168807583848837421626835850838234968318861924548520089498529438830221946631919961684036194597899331129423209124271556491349413781117593785932096323957855730046793794526765246551266059895520550086918193311542508608460618104685509074866089624888090489894838009253941633257850621568309473902556912388065225096643874441046759871626985453222868538161694315775629640762836880760732228535091641476183956381458969463899410840960536267821064621427333394036525565649530603142680234969400335934316651459297773279665775606172582031407994198179607378245683762280037302885487251900834464581454650557929601414833921615734588139257095379769119277800826957735674444123062018757836325502728323789270710373802866393031428133241401624195671690574061419654342324638801248856147305207431992259611796250130992860241708340807605932320161268492288496255841312844061536738951487114256315111089745514203313820202931640957596464756010405845841566072044962867016515061920631004186422275908670900574606417856951911456055068251250406007519842261898059237118054444788072906395242548339221982707404473162376760846613033778706039803413197133493654622700563169937455508241780972810983291314403571877524768509857276937926433221599399876886660808368837838027643282775172273657572744784112294389733810861607423253291974813120197604178281965697475898164531258434135959862784130128185406283476649088690521047580882615823961985770122407044330583075869039319604603404973156583208672105913300903752823415539745394397715257455290510212310947321610753474825740775273986348298498340756937955646638621874569499279016572103701364433135817214311791398222983845847334440270964182851005072927748364550578634501100852987812389473928699540834346158807043959118985815145779177143619698728131459483783202081474982171858011389071228250905826817436220577475921417653715687725614904582904992461028630081535583308130101987675856234343538955409175623400844887526162643568648833519463720377293240094456246923254350400678027273837755376406726898636241037491410966718557050759098100246789880178271925953381282421954028302759408448955014676668389697996886241636313376393903373455801407636741877711055384225739499110186468219696581651485130494222369947714763069155468217682876200362777257723781365331611196811280792669481887201298643660768551639860534602297871557517947385246369446923087894265948217008051120322365496288169035739121368338393591756418733850510970271613915439590991598154654417336311656936031122249937969999226781732358023111862644575299135758175008199839236284615249881088960232244362173771618086357015468484058622329792853875623486556440536962622018963571028812361567512543338303270029097668650568557157505516727518899194129711337690149916181315171544007728650573189557450920330185304847113818315407324053319038462084036421763703911550639789000742853672196280903477974533320468368795868580237952218629120080742819551317948157624448298518461509704888027274721574688131594750409732115080498190455803416826949787141316063210686391511681774304792596709376". diff --git a/erts/test/erl_print_SUITE_data/Makefile.src b/erts/test/erl_print_SUITE_data/Makefile.src new file mode 100644 index 0000000000..109d55e572 --- /dev/null +++ b/erts/test/erl_print_SUITE_data/Makefile.src @@ -0,0 +1,45 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2005-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erts_lib_include_internal_generated@@[email protected] + +CC = @CC@ +CFLAGS = @ERTS_CFLAGS@ +LIBS = @ERTS_LIBS@ + +EPTF_CFLAGS = -Wall $(CFLAGS) @DEFS@ -I@erts_lib_include_internal@ -I@erts_lib_include_internal_generated@ +EPTF_LIBS = $(LIBS) -L@erts_lib_internal_path@ -lerts_internal@type_marker@ + +EPTT_CFLAGS = -DTHREAD_SAFE $(ETHR_DEFS) $(EPTF_CFLAGS) +EPTT_LIBS = $(LIBS) -L@erts_lib_internal_path@ -lerts_internal_r@type_marker@ $(ETHR_LIBS) + +GCC = .@DS@gccifier -CC"$(CC)" + +PROGS = erl_print_tests.@emu_threads@@exe@ + +all: $(PROGS) + +gccifier@exe@: ..@DS@utils@[email protected] + $(CC) $(CFLAGS) -o gccifier@exe@ ..@DS@utils@[email protected] $(LIBS) + +erl_print_tests.false@exe@: gccifier@exe@ erl_print_tests.c + $(GCC) $(EPTF_CFLAGS) -o erl_print_tests.false@exe@ erl_print_tests.c $(EPTF_LIBS) + +erl_print_tests.true@exe@: gccifier@exe@ erl_print_tests.c + $(GCC) $(EPTT_CFLAGS) -o erl_print_tests.true@exe@ erl_print_tests.c $(EPTT_LIBS) diff --git a/erts/test/erl_print_SUITE_data/character_test.h b/erts/test/erl_print_SUITE_data/character_test.h new file mode 100644 index 0000000000..9c66618a71 --- /dev/null +++ b/erts/test/erl_print_SUITE_data/character_test.h @@ -0,0 +1,586 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2005-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * This file has been automatically generated. Do NOT edit it; instead, + * run 'erl_print_tests.false character save_expected_result' + */ + +char *character_expected_result[] = { + "a", + "a ", + " a", + "a ", + " a", + "b", + "b ", + " b", + "b ", + " b", + "c", + "c ", + " c", + "c ", + " c", + "d", + "d ", + " d", + "d ", + " d", + "e", + "e ", + " e", + "e ", + " e", + "f", + "f ", + " f", + "f ", + " f", + "g", + "g ", + " g", + "g ", + " g", + "h", + "h ", + " h", + "h ", + " h", + "i", + "i ", + " i", + "i ", + " i", + "j", + "j ", + " j", + "j ", + " j", + "k", + "k ", + " k", + "k ", + " k", + "l", + "l ", + " l", + "l ", + " l", + "m", + "m ", + " m", + "m ", + " m", + "n", + "n ", + " n", + "n ", + " n", + "o", + "o ", + " o", + "o ", + " o", + "p", + "p ", + " p", + "p ", + " p", + "q", + "q ", + " q", + "q ", + " q", + "r", + "r ", + " r", + "r ", + " r", + "s", + "s ", + " s", + "s ", + " s", + "t", + "t ", + " t", + "t ", + " t", + "u", + "u ", + " u", + "u ", + " u", + "v", + "v ", + " v", + "v ", + " v", + "w", + "w ", + " w", + "w ", + " w", + "x", + "x ", + " x", + "x ", + " x", + "y", + "y ", + " y", + "y ", + " y", + "z", + "z ", + " z", + "z ", + " z", + "�", + "� ", + " �", + "� ", + " �", + "�", + "� ", + " �", + "� ", + " �", + "�", + "� ", + " �", + "� ", + " �", + "A", + "A ", + " A", + "A ", + " A", + "B", + "B ", + " B", + "B ", + " B", + "C", + "C ", + " C", + "C ", + " C", + "D", + "D ", + " D", + "D ", + " D", + "E", + "E ", + " E", + "E ", + " E", + "F", + "F ", + " F", + "F ", + " F", + "G", + "G ", + " G", + "G ", + " G", + "H", + "H ", + " H", + "H ", + " H", + "I", + "I ", + " I", + "I ", + " I", + "J", + "J ", + " J", + "J ", + " J", + "K", + "K ", + " K", + "K ", + " K", + "L", + "L ", + " L", + "L ", + " L", + "M", + "M ", + " M", + "M ", + " M", + "N", + "N ", + " N", + "N ", + " N", + "O", + "O ", + " O", + "O ", + " O", + "P", + "P ", + " P", + "P ", + " P", + "Q", + "Q ", + " Q", + "Q ", + " Q", + "R", + "R ", + " R", + "R ", + " R", + "S", + "S ", + " S", + "S ", + " S", + "T", + "T ", + " T", + "T ", + " T", + "U", + "U ", + " U", + "U ", + " U", + "V", + "V ", + " V", + "V ", + " V", + "X", + "X ", + " X", + "X ", + " X", + "Y", + "Y ", + " Y", + "Y ", + " Y", + "Z", + "Z ", + " Z", + "Z ", + " Z", + "�", + "� ", + " �", + "� ", + " �", + "�", + "� ", + " �", + "� ", + " �", + "�", + "� ", + " �", + "� ", + " �", + "1", + "1 ", + " 1", + "1 ", + " 1", + "2", + "2 ", + " 2", + "2 ", + " 2", + "3", + "3 ", + " 3", + "3 ", + " 3", + "4", + "4 ", + " 4", + "4 ", + " 4", + "5", + "5 ", + " 5", + "5 ", + " 5", + "6", + "6 ", + " 6", + "6 ", + " 6", + "7", + "7 ", + " 7", + "7 ", + " 7", + "8", + "8 ", + " 8", + "8 ", + " 8", + "9", + "9 ", + " 9", + "9 ", + " 9", + "0", + "0 ", + " 0", + "0 ", + " 0", + "(", + "( ", + " (", + "( ", + " (", + ")", + ") ", + " )", + ") ", + " )", + "[", + "[ ", + " [", + "[ ", + " [", + "]", + "] ", + " ]", + "] ", + " ]", + "{", + "{ ", + " {", + "{ ", + " {", + "}", + "} ", + " }", + "} ", + " }", + "+", + "+ ", + " +", + "+ ", + " +", + "-", + "- ", + " -", + "- ", + " -", + ";", + "; ", + " ;", + "; ", + " ;", + ",", + ", ", + " ,", + ", ", + " ,", + ":", + ": ", + " :", + ": ", + " :", + ".", + ". ", + " .", + ". ", + " .", + "@", + "@ ", + " @", + "@ ", + " @", + "�", + "� ", + " �", + "� ", + " �", + "$", + "$ ", + " $", + "$ ", + " $", + "!", + "! ", + " !", + "! ", + " !", + "\"", + "\" ", + " \"", + "\" ", + " \"", + "#", + "# ", + " #", + "# ", + " #", + "�", + "� ", + " �", + "� ", + " �", + "%", + "% ", + " %", + "% ", + " %", + "&", + "& ", + " &", + "& ", + " &", + "/", + "/ ", + " /", + "/ ", + " /", + "\\", + "\\ ", + " \\", + "\\ ", + " \\", + "=", + "= ", + " =", + "= ", + " =", + "?", + "? ", + " ?", + "? ", + " ?", + "'", + "' ", + " '", + "' ", + " '", + "`", + "` ", + " `", + "` ", + " `", + "�", + "� ", + " �", + "� ", + " �", + "^", + "^ ", + " ^", + "^ ", + " ^", + "~", + "~ ", + " ~", + "~ ", + " ~", + "�", + "� ", + " �", + "� ", + " �", + "�", + "� ", + " �", + "� ", + " �", + "|", + "| ", + " |", + "| ", + " |", + "<", + "< ", + " <", + "< ", + " <", + ">", + "> ", + " >", + "> ", + " >", + "�", + "� ", + " �", + "� ", + " �", + "*", + "* ", + " *", + "* ", + " *", + "_", + "_ ", + " _", + "_ ", + " _", + "\a", + "\a ", + " \a", + "\a ", + " \a", + "\b", + "\b ", + " \b", + "\b ", + " \b", + "\f", + "\f ", + " \f", + "\f ", + " \f", + "\n", + "\n ", + " \n", + "\n ", + " \n", + "\r", + "\r ", + " \r", + "\r ", + " \r", + "\t", + "\t ", + " \t", + "\t ", + " \t", + "\v", + "\v ", + " \v", + "\v ", + " \v", + NULL}; diff --git a/erts/test/erl_print_SUITE_data/erl_print_tests.c b/erts/test/erl_print_SUITE_data/erl_print_tests.c new file mode 100644 index 0000000000..28ce78f4e1 --- /dev/null +++ b/erts/test/erl_print_SUITE_data/erl_print_tests.c @@ -0,0 +1,560 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2005-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Description: Test suite for the ethread thread library. + * Author: Rickard Green + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <limits.h> +#include <float.h> +#ifndef __WIN32__ +#include <unistd.h> +#endif + +#include "erl_printf.h" +#ifdef THREAD_SAFE +#include "ethread.h" +#endif + +#ifdef __WIN32__ +#undef HAVE_VSNPRINTF +#define HAVE_VSNPRINTF 1 +#define vsnprintf _vsnprintf +#endif + +#ifdef __WIN32__ +#define signed_long_long LONGLONG +#define unsigned_long_long ULONGLONG +#else +#define signed_long_long signed long long +#define unsigned_long_long unsigned long long +#endif + +/* + * Auxiliary functions + */ + +#define PRINT_VA_LIST(FRMT) \ +do { \ + if (FRMT && FRMT != '\0') { \ + va_list args; \ + va_start(args, FRMT); \ + vfprintf(stderr, FRMT, args); \ + va_end(args); \ + } \ +} while (0) + +#define ASSERT(B) \ +do { \ + if (!(B)) \ + fail("%s:%d: Assertion \"%s\" failed!",__FILE__,__LINE__,#B); \ +} while (0) + +static void +print_eol(void) +{ + fprintf(stderr, "\n"); +} + +static void print_line(char *frmt,...) +{ + PRINT_VA_LIST(frmt); + print_eol(); +} + +static void print(char *frmt,...) +{ + PRINT_VA_LIST(frmt); +} + +static void fail(char *frmt,...) +{ + char *abrt_env; + print_eol(); + fprintf(stderr, "EP-TEST-FAILURE"); + PRINT_VA_LIST(frmt); + print_eol(); + abrt_env = getenv("ERL_ABORT_ON_FAILURE"); + if (abrt_env && strcmp("true", abrt_env) == 0) + abort(); + else + exit(1); +} + +static void skip(char *frmt,...) +{ + print_eol(); + fprintf(stderr, "EP-TEST-SKIP"); + PRINT_VA_LIST(frmt); + print_eol(); + exit(0); +} + +static void succeed(char *frmt,...) +{ + print_eol(); + fprintf(stderr, "EP-TEST-SUCCESS"); + PRINT_VA_LIST(frmt); + print_eol(); + exit(0); +} + +#if 0 /* Not used */ + +static void +do_sleep(unsigned secs) +{ +#ifdef __WIN32__ + Sleep((DWORD) secs*1000); +#else + sleep(secs); +#endif +} + +#endif + +static void +send_my_pid(void) +{ +#ifndef __WIN32__ + int pid = (int) getpid(); + fprintf(stderr, "\nEP-TEST-PID%d\n", pid); +#endif +} + +#define BUF_SIZE (1024*1024) + +FILE *outfile = NULL; +char **expected_result; + +#define FENCE_SIZE 512 +static void +print_cmp_test(int n, char *frmt, ...) +{ + int res = -1; + static char clib_buf[BUF_SIZE]; + static unsigned char the_erts_buf[BUF_SIZE]; + char *erts_buf = (char *) &the_erts_buf[FENCE_SIZE]; + va_list args; + + if (outfile) { + char *fp, *tp; + va_start(args, frmt); + if (n < 0) + res = vsprintf(erts_buf, frmt, args); + else { +#ifdef HAVE_VSNPRINTF + res = vsnprintf(erts_buf, (size_t) n, frmt, args); +#else + fail("No vsnprintf()"); +#endif + } + va_end(args); + ASSERT(res >= 0); + fp = erts_buf; + tp = clib_buf; + while (*fp) { + switch (*fp) { + case '\a': *(tp++) = '\\'; *(tp++) = 'a'; break; + case '\b': *(tp++) = '\\'; *(tp++) = 'b'; break; + case '\f': *(tp++) = '\\'; *(tp++) = 'f'; break; + case '\n': *(tp++) = '\\'; *(tp++) = 'n'; break; + case '\r': *(tp++) = '\\'; *(tp++) = 'r'; break; + case '\t': *(tp++) = '\\'; *(tp++) = 't'; break; + case '\v': *(tp++) = '\\'; *(tp++) = 'v'; break; + case '\"': *(tp++) = '\\'; *(tp++) = '\"'; break; + case '\\': *(tp++) = '\\'; *(tp++) = '\\'; break; + default: *(tp++) = *fp; break; + } + fp++; + } + *tp = '\0'; + res = fprintf(outfile, "\t\"%s\",\n", clib_buf); + ASSERT(res >= 0); + } + else { + char *xres; + va_start(args, frmt); + if (n < 0) + res = erts_vsprintf(erts_buf, frmt, args); + else { + int i; + int chk_sz = 2*FENCE_SIZE + n; + for (i = 0; i < chk_sz; i++) + the_erts_buf[i] = 0xeb; + res = erts_vsnprintf(erts_buf, (size_t) n, frmt, args); + for (i = 0; i < chk_sz; i++) + if ((((char *) &the_erts_buf[i]) < erts_buf + || erts_buf + n <= ((char *) &the_erts_buf[i])) + && the_erts_buf[i] != 0xeb) { + int j; + for (j = 0; j < chk_sz; j++) + print(j ? ",%x(%d)" : "%x(%d)", + (unsigned) the_erts_buf[j], j - FENCE_SIZE); + print_eol(); + fail("Garbage written out of bounds (%d,%d)", + i - FENCE_SIZE, n); + } + } + va_end(args); + ASSERT(res >= 0); + + if (expected_result) { + ASSERT(*expected_result); + xres = *expected_result; + expected_result++; + } + else { + va_start(args, frmt); + if (n < 0) + res = vsprintf(clib_buf, frmt, args); + else { +#ifdef HAVE_VSNPRINTF + res = vsnprintf(clib_buf, (size_t) n, frmt, args); +#else + fail("No vsnprintf()"); +#endif + } + va_end(args); + ASSERT(res >= 0); + xres = clib_buf; + } + + if (strcmp(xres, erts_buf) != 0) { + print_line("expected result : \"%s\"", xres); + print_line("erts_buf : \"%s\"", erts_buf); + fail("\"%s\" != \"%s\" (format=\"%s\")", xres, erts_buf, frmt); + } + + print_line("Checked format \"%s\" with result: \"%s\"", frmt, erts_buf); + } +} + +/* + * The test-cases + */ + +#include "integer_64_test.h" +#include "integer_test.h" + +#define INT_SUB_BATCH_TEST(FRMT, TYPE) \ + print_cmp_test(-1, FRMT, ((TYPE) 4711)); \ + print_cmp_test(-1, FRMT, ~((TYPE) 4711)); \ + print_cmp_test(-1, FRMT, (~((TYPE) 0))/2 + (~((TYPE) 0))/4);\ + print_cmp_test(-1, FRMT, ((TYPE) - 1)); \ + print_cmp_test(-1, FRMT, ((TYPE) 1)); \ + print_cmp_test(-1, FRMT, ((TYPE) ((long) 0xabcdef01))); \ + +#define INT_BATCH_TEST(P, X, S) \ + print_line("%s:%d",__FILE__,__LINE__); \ + INT_SUB_BATCH_TEST("%" P "h" X, S char); \ + INT_SUB_BATCH_TEST("%" P "h" X, S short); \ + INT_SUB_BATCH_TEST("%" P X, S int); \ + INT_SUB_BATCH_TEST("%" P "l" X, S long); \ + INT_SUB_BATCH_TEST("%" P "ll" X, S ## _long_long); \ + +static void +integer_test(void) +{ + /* This testcase should be rewritten. It assumes the following + sizes of types... */ + if (sizeof(char) != 1 + || sizeof(short) != 2 + || sizeof(int) != 4 + || sizeof(long) != (sizeof(void *) == 8 ? 8 : 4) + || sizeof(signed_long_long) != 8) + skip("Unexpected size of primitive datatype:" + " sizeof(char) == %d (expected 1);" + " sizeof(short) == %d (expected 2);" + " sizeof(int) == %d (expected 4);" + " sizeof(long) == %d (expected %d);" + " sizeof(signed_long_long) == %d (expected 8)", + sizeof(char), + sizeof(short), + sizeof(int), + sizeof(long), sizeof(void *) == 8 ? 8 : 4, + sizeof(signed_long_long)); + + expected_result = (sizeof(void *) == 8 + ? integer_64_expected_result + : integer_expected_result); + + INT_BATCH_TEST("", "i", signed); + INT_BATCH_TEST("", "d", signed); + INT_BATCH_TEST("", "u", unsigned); + INT_BATCH_TEST("", "o", unsigned); + INT_BATCH_TEST("", "x", unsigned); + INT_BATCH_TEST("", "X", unsigned); + INT_BATCH_TEST("010.5", "i", signed); + INT_BATCH_TEST("010.5", "d", signed); + INT_BATCH_TEST("010.5", "u", unsigned); + INT_BATCH_TEST("010.5", "o", unsigned); + INT_BATCH_TEST("010.5", "x", unsigned); + INT_BATCH_TEST("010.5", "X", unsigned); + INT_BATCH_TEST("-+29", "i", signed); + INT_BATCH_TEST("-+29", "d", signed); + INT_BATCH_TEST("-29", "u", unsigned); + INT_BATCH_TEST("-29", "o", unsigned); + INT_BATCH_TEST("-29", "x", unsigned); + INT_BATCH_TEST("-29", "X", unsigned); + INT_BATCH_TEST("22.8", "i", signed); + INT_BATCH_TEST("22.8", "d", signed); + INT_BATCH_TEST("22.8", "u", unsigned); + INT_BATCH_TEST("22.8", "o", unsigned); + INT_BATCH_TEST("22.8", "x", unsigned); + INT_BATCH_TEST("22.8", "X", unsigned); + INT_BATCH_TEST("-22.8", "i", signed); + INT_BATCH_TEST("-22.8", "d", signed); + INT_BATCH_TEST("-22.8", "u", unsigned); + INT_BATCH_TEST("-22.8", "o", unsigned); + INT_BATCH_TEST("-22.8", "x", unsigned); + INT_BATCH_TEST("-22.8", "X", unsigned); + INT_BATCH_TEST("-823.193", "i", signed); + INT_BATCH_TEST("-823.193", "d", signed); + INT_BATCH_TEST("-823.193", "u", unsigned); + INT_BATCH_TEST("-823.193", "o", unsigned); + INT_BATCH_TEST("-823.193", "x", unsigned); + INT_BATCH_TEST("-823.193", "X", unsigned); + +} + +static void +float_test(void) +{ + expected_result = NULL; + print_cmp_test(-1, "%70.10f", DBL_MAX); + print_cmp_test(-1, "%500.10f", DBL_MAX); + print_cmp_test(-1, "%-500.10f", DBL_MAX); + print_cmp_test(-1, "%500.10e", DBL_MAX); + print_cmp_test(-1, "%-500.10e", DBL_MAX); + print_cmp_test(-1, "%500.10E", DBL_MAX); + print_cmp_test(-1, "%-500.10E", DBL_MAX); + print_cmp_test(-1, "%500.10g", DBL_MAX); + print_cmp_test(-1, "%-500.10g", DBL_MAX); + print_cmp_test(-1, "%500.10G", DBL_MAX); + print_cmp_test(-1, "%-500.10G", DBL_MAX); +} + +char some_characters[] = +"abcdefghijklmnopqrstuvwxyz���" +"ABCDEFGHIJKLMNOPQRSTUVXYZ���" +"1234567890" +"()[]{}+-;,:.@�$!\"#�%&/\\=?'`�^~��|<>�*_" +"\a\b\f\n\r\t\v"; + +#include "string_test.h" + +static void +string_test(void) +{ + expected_result = string_expected_result; + print_cmp_test(-1, "%s", "hej"); + print_cmp_test(-1, "%-10.5s", "hopp"); + print_cmp_test(-1, "%10.5s", "hopp"); + print_cmp_test(-1, "%-500.500s", "hopp"); + print_cmp_test(-1, "%500.500s", "hopp"); + print_cmp_test(-1, "\t%10.4s", some_characters); + print_cmp_test(-1, "\t%500.500s", some_characters); +} + +#include "character_test.h" + +static void +character_test(void) +{ + char *cp; + expected_result = character_expected_result; + for (cp = some_characters; *cp; cp++) { + print_cmp_test(-1, "%c", *cp); + print_cmp_test(-1, "%-10.5c", *cp); + print_cmp_test(-1, "%10.5c", *cp); + print_cmp_test(-1, "%-500.500c", *cp); + print_cmp_test(-1, "%500.500c", *cp); + } +} + +#include "snprintf_test.h" + +static void +snprintf_test(void) +{ + expected_result = snprintf_expected_result; + print_cmp_test(6, "hej hopp"); + print_cmp_test(7, "hej hopp"); + print_cmp_test(8, "hej hopp"); + print_cmp_test(9, "hej hopp"); + print_cmp_test(10, "hej hopp"); + print_cmp_test(6, "hej %d", 4711); + print_cmp_test(7, "hej %d", 4711); + print_cmp_test(8, "hej %d", 4711); + print_cmp_test(9, "hej %d", 4711); + print_cmp_test(10, "hej %d", 4711); + print_cmp_test(sizeof(some_characters)-2, "%s", some_characters); + print_cmp_test(sizeof(some_characters)-1, "%s", some_characters); + print_cmp_test(sizeof(some_characters), "%s", some_characters); + print_cmp_test(sizeof(some_characters)+1, "%s", some_characters); + print_cmp_test(sizeof(some_characters)+2, "%s", some_characters); + print_cmp_test(sizeof(some_characters)/2, "%s%s", + some_characters, some_characters); + print_cmp_test(sizeof(some_characters)*3, "%s%s", + some_characters, some_characters); +} + +static void +quote_test(void) +{ + expected_result = NULL; + print_cmp_test(-1, "\n"); + print_cmp_test(-1, "\\n"); + print_cmp_test(-1, "\r"); + print_cmp_test(-1, "\\r"); + print_cmp_test(-1, "\t"); + print_cmp_test(-1, "\\t"); + print_cmp_test(-1, "\v"); + print_cmp_test(-1, "\\v"); + print_cmp_test(-1, "\b"); + print_cmp_test(-1, "\\b"); + print_cmp_test(-1, "\f"); + print_cmp_test(-1, "\\f"); + print_cmp_test(-1, "\x80"); + print_cmp_test(-1, "\\x80"); + print_cmp_test(-1, "\x14"); + print_cmp_test(-1, "\\x14"); + print_cmp_test(-1, "\xff"); + print_cmp_test(-1, "\\xff"); + print_cmp_test(-1, "\043"); + print_cmp_test(-1, "\\043"); + print_cmp_test(-1, "\053"); + print_cmp_test(-1, "\\053"); + print_cmp_test(-1, "\0143"); + print_cmp_test(-1, "\\0143"); + print_cmp_test(-1, "\\lf"); + print_cmp_test(-1, "\\msss"); + print_cmp_test(-1, "\\ss"); + +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * The dispatcher * +\* */ + +int +main(int argc, char *argv[]) +{ + if (argc < 2) + fail("To few arguments for test case"); + + { + char *testcase; + int save_xres = 0; + int i; + + send_my_pid(); + + testcase = argv[1]; +#ifdef THREAD_SAFE + { + int res = ethr_init(NULL); + if (res != 0) + fail("Failed to initialize the ethread library"); + } +#endif + + for (i = 2; i < argc; i++) { + if (strcmp(argv[i], "save_expected_result") == 0) { + save_xres = 1; + break; + } + } + + if (save_xres) { + char filename[100]; + sprintf(filename, + "%s%s_test.h", + testcase, + sizeof(void *) == 8 ? "_64" : ""); + printf("Saving expected result to %s\n", filename); + outfile = fopen(filename, "w"); + ASSERT(outfile); + fprintf(outfile, + "/*\n" + " * %%CopyrightBegin%%\n" + " * Copyright Ericsson AB 1996-2009. All Rights Reserved.\n" + " * \n" + " * The contents of this file are subject to the Erlang Public License,\n" + " * Version 1.1, (the \"License\"); you may not use this file except in\n" + " * compliance with the License. You should have received a copy of the\n" + " * Erlang Public License along with this software. If not, it can be\n" + " * retrieved online at http://www.erlang.org/.\n" + " * \n" + " * Software distributed under the License is distributed on an \"AS IS\"\n" + " * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See\n" + " * the License for the specific language governing rights and limitations\n" + " * under the License.\n" + " * %%CopyrightEnd%%\n" + " */\n" + "\n"); + fprintf(outfile, + "/* \n" + " * This file has been automatically generated. Do NOT edit it; instead,\n" + " * run '%s %s save_expected_result'%s.\n" + " */\n" + "\n", + argv[0], + testcase, + sizeof(void *) == 8 ? " on a 64-bit machine" : ""); + fprintf(outfile, + "char *%s%s_expected_result[] = {\n", + testcase, + sizeof(void *) == 8 ? "_64" : ""); + } + + if (strcmp("integer", testcase) == 0) + integer_test(); + else if (strcmp("float", testcase) == 0) + float_test(); + else if (strcmp("string", testcase) == 0) + string_test(); + else if (strcmp("character", testcase) == 0) + character_test(); + else if (strcmp("snprintf", testcase) == 0) + snprintf_test(); + else if (strcmp("quote", testcase) == 0) + quote_test(); + else if (!save_xres) + skip("Test case \"%s\" not implemented yet", testcase); + + if (save_xres) { + fprintf(outfile, "\tNULL};\n"); + fclose(outfile); + } + + succeed(NULL); + } + + return 0; +} + + + diff --git a/erts/test/erl_print_SUITE_data/integer_64_test.h b/erts/test/erl_print_SUITE_data/integer_64_test.h new file mode 100644 index 0000000000..0df09ded44 --- /dev/null +++ b/erts/test/erl_print_SUITE_data/integer_64_test.h @@ -0,0 +1,1106 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2005-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * This file has been automatically generated. Do NOT edit it; instead, + * run 'erl_print_tests.true integer save_expected_result' on a 64-bit machine. + */ + +char *integer_64_expected_result[] = { + "103", + "-104", + "0", + "-1", + "1", + "1", + "4711", + "-4712", + "0", + "-1", + "1", + "-4351", + "4711", + "-4712", + "0", + "-1", + "1", + "-1412567295", + "4711", + "-4712", + "0", + "-1", + "1", + "2882400001", + "4711", + "-4712", + "0", + "-1", + "1", + "2882400001", + "103", + "-104", + "0", + "-1", + "1", + "1", + "4711", + "-4712", + "0", + "-1", + "1", + "-4351", + "4711", + "-4712", + "0", + "-1", + "1", + "-1412567295", + "4711", + "-4712", + "0", + "-1", + "1", + "2882400001", + "4711", + "-4712", + "0", + "-1", + "1", + "2882400001", + "103", + "65432", + "0", + "255", + "1", + "1", + "4711", + "60824", + "0", + "65535", + "1", + "61185", + "4711", + "4294962584", + "3221225470", + "4294967295", + "1", + "2882400001", + "4711", + "18446744073709546904", + "13835058055282163710", + "18446744073709551615", + "1", + "2882400001", + "4711", + "18446744073709546904", + "13835058055282163710", + "18446744073709551615", + "1", + "2882400001", + "147", + "177630", + "0", + "377", + "1", + "1", + "11147", + "166630", + "0", + "177777", + "1", + "167401", + "11147", + "37777766630", + "27777777776", + "37777777777", + "1", + "25363367401", + "11147", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + "1", + "25363367401", + "11147", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + "1", + "25363367401", + "67", + "ff98", + "0", + "ff", + "1", + "1", + "1267", + "ed98", + "0", + "ffff", + "1", + "ef01", + "1267", + "ffffed98", + "bffffffe", + "ffffffff", + "1", + "abcdef01", + "1267", + "ffffffffffffed98", + "bffffffffffffffe", + "ffffffffffffffff", + "1", + "abcdef01", + "1267", + "ffffffffffffed98", + "bffffffffffffffe", + "ffffffffffffffff", + "1", + "abcdef01", + "67", + "FF98", + "0", + "FF", + "1", + "1", + "1267", + "ED98", + "0", + "FFFF", + "1", + "EF01", + "1267", + "FFFFED98", + "BFFFFFFE", + "FFFFFFFF", + "1", + "ABCDEF01", + "1267", + "FFFFFFFFFFFFED98", + "BFFFFFFFFFFFFFFE", + "FFFFFFFFFFFFFFFF", + "1", + "ABCDEF01", + "1267", + "FFFFFFFFFFFFED98", + "BFFFFFFFFFFFFFFE", + "FFFFFFFFFFFFFFFF", + "1", + "ABCDEF01", + " 00103", + " -00104", + " 00000", + " -00001", + " 00001", + " 00001", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + " -04351", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "-1412567295", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "2882400001", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "2882400001", + " 00103", + " -00104", + " 00000", + " -00001", + " 00001", + " 00001", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + " -04351", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "-1412567295", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "2882400001", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "2882400001", + " 00103", + " 65432", + " 00000", + " 00255", + " 00001", + " 00001", + " 04711", + " 60824", + " 00000", + " 65535", + " 00001", + " 61185", + " 04711", + "4294962584", + "3221225470", + "4294967295", + " 00001", + "2882400001", + " 04711", + "18446744073709546904", + "13835058055282163710", + "18446744073709551615", + " 00001", + "2882400001", + " 04711", + "18446744073709546904", + "13835058055282163710", + "18446744073709551615", + " 00001", + "2882400001", + " 00147", + " 177630", + " 00000", + " 00377", + " 00001", + " 00001", + " 11147", + " 166630", + " 00000", + " 177777", + " 00001", + " 167401", + " 11147", + "37777766630", + "27777777776", + "37777777777", + " 00001", + "25363367401", + " 11147", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + " 00001", + "25363367401", + " 11147", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + " 00001", + "25363367401", + " 00067", + " 0ff98", + " 00000", + " 000ff", + " 00001", + " 00001", + " 01267", + " 0ed98", + " 00000", + " 0ffff", + " 00001", + " 0ef01", + " 01267", + " ffffed98", + " bffffffe", + " ffffffff", + " 00001", + " abcdef01", + " 01267", + "ffffffffffffed98", + "bffffffffffffffe", + "ffffffffffffffff", + " 00001", + " abcdef01", + " 01267", + "ffffffffffffed98", + "bffffffffffffffe", + "ffffffffffffffff", + " 00001", + " abcdef01", + " 00067", + " 0FF98", + " 00000", + " 000FF", + " 00001", + " 00001", + " 01267", + " 0ED98", + " 00000", + " 0FFFF", + " 00001", + " 0EF01", + " 01267", + " FFFFED98", + " BFFFFFFE", + " FFFFFFFF", + " 00001", + " ABCDEF01", + " 01267", + "FFFFFFFFFFFFED98", + "BFFFFFFFFFFFFFFE", + "FFFFFFFFFFFFFFFF", + " 00001", + " ABCDEF01", + " 01267", + "FFFFFFFFFFFFED98", + "BFFFFFFFFFFFFFFE", + "FFFFFFFFFFFFFFFF", + " 00001", + " ABCDEF01", + "+103 ", + "-104 ", + "+0 ", + "-1 ", + "+1 ", + "+1 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-4351 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-1412567295 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "+2882400001 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "+2882400001 ", + "+103 ", + "-104 ", + "+0 ", + "-1 ", + "+1 ", + "+1 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-4351 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-1412567295 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "+2882400001 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "+2882400001 ", + "103 ", + "65432 ", + "0 ", + "255 ", + "1 ", + "1 ", + "4711 ", + "60824 ", + "0 ", + "65535 ", + "1 ", + "61185 ", + "4711 ", + "4294962584 ", + "3221225470 ", + "4294967295 ", + "1 ", + "2882400001 ", + "4711 ", + "18446744073709546904 ", + "13835058055282163710 ", + "18446744073709551615 ", + "1 ", + "2882400001 ", + "4711 ", + "18446744073709546904 ", + "13835058055282163710 ", + "18446744073709551615 ", + "1 ", + "2882400001 ", + "147 ", + "177630 ", + "0 ", + "377 ", + "1 ", + "1 ", + "11147 ", + "166630 ", + "0 ", + "177777 ", + "1 ", + "167401 ", + "11147 ", + "37777766630 ", + "27777777776 ", + "37777777777 ", + "1 ", + "25363367401 ", + "11147 ", + "1777777777777777766630 ", + "1377777777777777777776 ", + "1777777777777777777777 ", + "1 ", + "25363367401 ", + "11147 ", + "1777777777777777766630 ", + "1377777777777777777776 ", + "1777777777777777777777 ", + "1 ", + "25363367401 ", + "67 ", + "ff98 ", + "0 ", + "ff ", + "1 ", + "1 ", + "1267 ", + "ed98 ", + "0 ", + "ffff ", + "1 ", + "ef01 ", + "1267 ", + "ffffed98 ", + "bffffffe ", + "ffffffff ", + "1 ", + "abcdef01 ", + "1267 ", + "ffffffffffffed98 ", + "bffffffffffffffe ", + "ffffffffffffffff ", + "1 ", + "abcdef01 ", + "1267 ", + "ffffffffffffed98 ", + "bffffffffffffffe ", + "ffffffffffffffff ", + "1 ", + "abcdef01 ", + "67 ", + "FF98 ", + "0 ", + "FF ", + "1 ", + "1 ", + "1267 ", + "ED98 ", + "0 ", + "FFFF ", + "1 ", + "EF01 ", + "1267 ", + "FFFFED98 ", + "BFFFFFFE ", + "FFFFFFFF ", + "1 ", + "ABCDEF01 ", + "1267 ", + "FFFFFFFFFFFFED98 ", + "BFFFFFFFFFFFFFFE ", + "FFFFFFFFFFFFFFFF ", + "1 ", + "ABCDEF01 ", + "1267 ", + "FFFFFFFFFFFFED98 ", + "BFFFFFFFFFFFFFFE ", + "FFFFFFFFFFFFFFFF ", + "1 ", + "ABCDEF01 ", + " 00000103", + " -00000104", + " 00000000", + " -00000001", + " 00000001", + " 00000001", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -00004351", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -1412567295", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " 2882400001", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " 2882400001", + " 00000103", + " -00000104", + " 00000000", + " -00000001", + " 00000001", + " 00000001", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -00004351", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -1412567295", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " 2882400001", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " 2882400001", + " 00000103", + " 00065432", + " 00000000", + " 00000255", + " 00000001", + " 00000001", + " 00004711", + " 00060824", + " 00000000", + " 00065535", + " 00000001", + " 00061185", + " 00004711", + " 4294962584", + " 3221225470", + " 4294967295", + " 00000001", + " 2882400001", + " 00004711", + " 18446744073709546904", + " 13835058055282163710", + " 18446744073709551615", + " 00000001", + " 2882400001", + " 00004711", + " 18446744073709546904", + " 13835058055282163710", + " 18446744073709551615", + " 00000001", + " 2882400001", + " 00000147", + " 00177630", + " 00000000", + " 00000377", + " 00000001", + " 00000001", + " 00011147", + " 00166630", + " 00000000", + " 00177777", + " 00000001", + " 00167401", + " 00011147", + " 37777766630", + " 27777777776", + " 37777777777", + " 00000001", + " 25363367401", + " 00011147", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + " 00000001", + " 25363367401", + " 00011147", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + " 00000001", + " 25363367401", + " 00000067", + " 0000ff98", + " 00000000", + " 000000ff", + " 00000001", + " 00000001", + " 00001267", + " 0000ed98", + " 00000000", + " 0000ffff", + " 00000001", + " 0000ef01", + " 00001267", + " ffffed98", + " bffffffe", + " ffffffff", + " 00000001", + " abcdef01", + " 00001267", + " ffffffffffffed98", + " bffffffffffffffe", + " ffffffffffffffff", + " 00000001", + " abcdef01", + " 00001267", + " ffffffffffffed98", + " bffffffffffffffe", + " ffffffffffffffff", + " 00000001", + " abcdef01", + " 00000067", + " 0000FF98", + " 00000000", + " 000000FF", + " 00000001", + " 00000001", + " 00001267", + " 0000ED98", + " 00000000", + " 0000FFFF", + " 00000001", + " 0000EF01", + " 00001267", + " FFFFED98", + " BFFFFFFE", + " FFFFFFFF", + " 00000001", + " ABCDEF01", + " 00001267", + " FFFFFFFFFFFFED98", + " BFFFFFFFFFFFFFFE", + " FFFFFFFFFFFFFFFF", + " 00000001", + " ABCDEF01", + " 00001267", + " FFFFFFFFFFFFED98", + " BFFFFFFFFFFFFFFE", + " FFFFFFFFFFFFFFFF", + " 00000001", + " ABCDEF01", + "00000103 ", + "-00000104 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "00000001 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-00004351 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-1412567295 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "2882400001 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "2882400001 ", + "00000103 ", + "-00000104 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "00000001 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-00004351 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-1412567295 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "2882400001 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "2882400001 ", + "00000103 ", + "00065432 ", + "00000000 ", + "00000255 ", + "00000001 ", + "00000001 ", + "00004711 ", + "00060824 ", + "00000000 ", + "00065535 ", + "00000001 ", + "00061185 ", + "00004711 ", + "4294962584 ", + "3221225470 ", + "4294967295 ", + "00000001 ", + "2882400001 ", + "00004711 ", + "18446744073709546904 ", + "13835058055282163710 ", + "18446744073709551615 ", + "00000001 ", + "2882400001 ", + "00004711 ", + "18446744073709546904 ", + "13835058055282163710 ", + "18446744073709551615 ", + "00000001 ", + "2882400001 ", + "00000147 ", + "00177630 ", + "00000000 ", + "00000377 ", + "00000001 ", + "00000001 ", + "00011147 ", + "00166630 ", + "00000000 ", + "00177777 ", + "00000001 ", + "00167401 ", + "00011147 ", + "37777766630 ", + "27777777776 ", + "37777777777 ", + "00000001 ", + "25363367401 ", + "00011147 ", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + "00000001 ", + "25363367401 ", + "00011147 ", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + "00000001 ", + "25363367401 ", + "00000067 ", + "0000ff98 ", + "00000000 ", + "000000ff ", + "00000001 ", + "00000001 ", + "00001267 ", + "0000ed98 ", + "00000000 ", + "0000ffff ", + "00000001 ", + "0000ef01 ", + "00001267 ", + "ffffed98 ", + "bffffffe ", + "ffffffff ", + "00000001 ", + "abcdef01 ", + "00001267 ", + "ffffffffffffed98 ", + "bffffffffffffffe ", + "ffffffffffffffff ", + "00000001 ", + "abcdef01 ", + "00001267 ", + "ffffffffffffed98 ", + "bffffffffffffffe ", + "ffffffffffffffff ", + "00000001 ", + "abcdef01 ", + "00000067 ", + "0000FF98 ", + "00000000 ", + "000000FF ", + "00000001 ", + "00000001 ", + "00001267 ", + "0000ED98 ", + "00000000 ", + "0000FFFF ", + "00000001 ", + "0000EF01 ", + "00001267 ", + "FFFFED98 ", + "BFFFFFFE ", + "FFFFFFFF ", + "00000001 ", + "ABCDEF01 ", + "00001267 ", + "FFFFFFFFFFFFED98 ", + "BFFFFFFFFFFFFFFE ", + "FFFFFFFFFFFFFFFF ", + "00000001 ", + "ABCDEF01 ", + "00001267 ", + "FFFFFFFFFFFFED98 ", + "BFFFFFFFFFFFFFFE ", + "FFFFFFFFFFFFFFFF ", + "00000001 ", + "ABCDEF01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004351 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001412567295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002882400001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002882400001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004351 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001412567295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002882400001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002882400001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065432 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000255 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060824 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065535 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061185 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004294962584 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003221225470 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004294967295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002882400001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018446744073709546904 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013835058055282163710 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018446744073709551615 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002882400001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018446744073709546904 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013835058055282163710 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018446744073709551615 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002882400001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000147 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000177630 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000377 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011147 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166630 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000177777 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000167401 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011147 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037777766630 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027777777776 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037777777777 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025363367401 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011147 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001777777777777777766630 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001377777777777777777776 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001777777777777777777777 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025363367401 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011147 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001777777777777777766630 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001377777777777777777776 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001777777777777777777777 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025363367401 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff98 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ed98 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffff ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ef01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffed98 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bffffffe ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000abcdef01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffed98 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bffffffffffffffe ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000abcdef01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffed98 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bffffffffffffffe ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000abcdef01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF98 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ED98 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000EF01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFED98 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BFFFFFFE ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFF ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ABCDEF01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFED98 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BFFFFFFFFFFFFFFE ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ABCDEF01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFED98 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BFFFFFFFFFFFFFFE ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ABCDEF01 ", + NULL}; diff --git a/erts/test/erl_print_SUITE_data/integer_test.h b/erts/test/erl_print_SUITE_data/integer_test.h new file mode 100644 index 0000000000..94c8d59897 --- /dev/null +++ b/erts/test/erl_print_SUITE_data/integer_test.h @@ -0,0 +1,1106 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2005-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * This file has been automatically generated. Do NOT edit it; instead, + * run 'erl_print_tests.true integer save_expected_result' + */ + +char *integer_expected_result[] = { + "103", + "-104", + "0", + "-1", + "1", + "1", + "4711", + "-4712", + "0", + "-1", + "1", + "-4351", + "4711", + "-4712", + "0", + "-1", + "1", + "-1412567295", + "4711", + "-4712", + "0", + "-1", + "1", + "-1412567295", + "4711", + "-4712", + "0", + "-1", + "1", + "-1412567295", + "103", + "-104", + "0", + "-1", + "1", + "1", + "4711", + "-4712", + "0", + "-1", + "1", + "-4351", + "4711", + "-4712", + "0", + "-1", + "1", + "-1412567295", + "4711", + "-4712", + "0", + "-1", + "1", + "-1412567295", + "4711", + "-4712", + "0", + "-1", + "1", + "-1412567295", + "103", + "65432", + "0", + "255", + "1", + "1", + "4711", + "60824", + "0", + "65535", + "1", + "61185", + "4711", + "4294962584", + "3221225470", + "4294967295", + "1", + "2882400001", + "4711", + "4294962584", + "3221225470", + "4294967295", + "1", + "2882400001", + "4711", + "18446744073709546904", + "13835058055282163710", + "18446744073709551615", + "1", + "18446744072296984321", + "147", + "177630", + "0", + "377", + "1", + "1", + "11147", + "166630", + "0", + "177777", + "1", + "167401", + "11147", + "37777766630", + "27777777776", + "37777777777", + "1", + "25363367401", + "11147", + "37777766630", + "27777777776", + "37777777777", + "1", + "25363367401", + "11147", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + "1", + "1777777777765363367401", + "67", + "ff98", + "0", + "ff", + "1", + "1", + "1267", + "ed98", + "0", + "ffff", + "1", + "ef01", + "1267", + "ffffed98", + "bffffffe", + "ffffffff", + "1", + "abcdef01", + "1267", + "ffffed98", + "bffffffe", + "ffffffff", + "1", + "abcdef01", + "1267", + "ffffffffffffed98", + "bffffffffffffffe", + "ffffffffffffffff", + "1", + "ffffffffabcdef01", + "67", + "FF98", + "0", + "FF", + "1", + "1", + "1267", + "ED98", + "0", + "FFFF", + "1", + "EF01", + "1267", + "FFFFED98", + "BFFFFFFE", + "FFFFFFFF", + "1", + "ABCDEF01", + "1267", + "FFFFED98", + "BFFFFFFE", + "FFFFFFFF", + "1", + "ABCDEF01", + "1267", + "FFFFFFFFFFFFED98", + "BFFFFFFFFFFFFFFE", + "FFFFFFFFFFFFFFFF", + "1", + "FFFFFFFFABCDEF01", + " 00103", + " -00104", + " 00000", + " -00001", + " 00001", + " 00001", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + " -04351", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "-1412567295", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "-1412567295", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "-1412567295", + " 00103", + " -00104", + " 00000", + " -00001", + " 00001", + " 00001", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + " -04351", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "-1412567295", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "-1412567295", + " 04711", + " -04712", + " 00000", + " -00001", + " 00001", + "-1412567295", + " 00103", + " 65432", + " 00000", + " 00255", + " 00001", + " 00001", + " 04711", + " 60824", + " 00000", + " 65535", + " 00001", + " 61185", + " 04711", + "4294962584", + "3221225470", + "4294967295", + " 00001", + "2882400001", + " 04711", + "4294962584", + "3221225470", + "4294967295", + " 00001", + "2882400001", + " 04711", + "18446744073709546904", + "13835058055282163710", + "18446744073709551615", + " 00001", + "18446744072296984321", + " 00147", + " 177630", + " 00000", + " 00377", + " 00001", + " 00001", + " 11147", + " 166630", + " 00000", + " 177777", + " 00001", + " 167401", + " 11147", + "37777766630", + "27777777776", + "37777777777", + " 00001", + "25363367401", + " 11147", + "37777766630", + "27777777776", + "37777777777", + " 00001", + "25363367401", + " 11147", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + " 00001", + "1777777777765363367401", + " 00067", + " 0ff98", + " 00000", + " 000ff", + " 00001", + " 00001", + " 01267", + " 0ed98", + " 00000", + " 0ffff", + " 00001", + " 0ef01", + " 01267", + " ffffed98", + " bffffffe", + " ffffffff", + " 00001", + " abcdef01", + " 01267", + " ffffed98", + " bffffffe", + " ffffffff", + " 00001", + " abcdef01", + " 01267", + "ffffffffffffed98", + "bffffffffffffffe", + "ffffffffffffffff", + " 00001", + "ffffffffabcdef01", + " 00067", + " 0FF98", + " 00000", + " 000FF", + " 00001", + " 00001", + " 01267", + " 0ED98", + " 00000", + " 0FFFF", + " 00001", + " 0EF01", + " 01267", + " FFFFED98", + " BFFFFFFE", + " FFFFFFFF", + " 00001", + " ABCDEF01", + " 01267", + " FFFFED98", + " BFFFFFFE", + " FFFFFFFF", + " 00001", + " ABCDEF01", + " 01267", + "FFFFFFFFFFFFED98", + "BFFFFFFFFFFFFFFE", + "FFFFFFFFFFFFFFFF", + " 00001", + "FFFFFFFFABCDEF01", + "+103 ", + "-104 ", + "+0 ", + "-1 ", + "+1 ", + "+1 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-4351 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-1412567295 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-1412567295 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-1412567295 ", + "+103 ", + "-104 ", + "+0 ", + "-1 ", + "+1 ", + "+1 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-4351 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-1412567295 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-1412567295 ", + "+4711 ", + "-4712 ", + "+0 ", + "-1 ", + "+1 ", + "-1412567295 ", + "103 ", + "65432 ", + "0 ", + "255 ", + "1 ", + "1 ", + "4711 ", + "60824 ", + "0 ", + "65535 ", + "1 ", + "61185 ", + "4711 ", + "4294962584 ", + "3221225470 ", + "4294967295 ", + "1 ", + "2882400001 ", + "4711 ", + "4294962584 ", + "3221225470 ", + "4294967295 ", + "1 ", + "2882400001 ", + "4711 ", + "18446744073709546904 ", + "13835058055282163710 ", + "18446744073709551615 ", + "1 ", + "18446744072296984321 ", + "147 ", + "177630 ", + "0 ", + "377 ", + "1 ", + "1 ", + "11147 ", + "166630 ", + "0 ", + "177777 ", + "1 ", + "167401 ", + "11147 ", + "37777766630 ", + "27777777776 ", + "37777777777 ", + "1 ", + "25363367401 ", + "11147 ", + "37777766630 ", + "27777777776 ", + "37777777777 ", + "1 ", + "25363367401 ", + "11147 ", + "1777777777777777766630 ", + "1377777777777777777776 ", + "1777777777777777777777 ", + "1 ", + "1777777777765363367401 ", + "67 ", + "ff98 ", + "0 ", + "ff ", + "1 ", + "1 ", + "1267 ", + "ed98 ", + "0 ", + "ffff ", + "1 ", + "ef01 ", + "1267 ", + "ffffed98 ", + "bffffffe ", + "ffffffff ", + "1 ", + "abcdef01 ", + "1267 ", + "ffffed98 ", + "bffffffe ", + "ffffffff ", + "1 ", + "abcdef01 ", + "1267 ", + "ffffffffffffed98 ", + "bffffffffffffffe ", + "ffffffffffffffff ", + "1 ", + "ffffffffabcdef01 ", + "67 ", + "FF98 ", + "0 ", + "FF ", + "1 ", + "1 ", + "1267 ", + "ED98 ", + "0 ", + "FFFF ", + "1 ", + "EF01 ", + "1267 ", + "FFFFED98 ", + "BFFFFFFE ", + "FFFFFFFF ", + "1 ", + "ABCDEF01 ", + "1267 ", + "FFFFED98 ", + "BFFFFFFE ", + "FFFFFFFF ", + "1 ", + "ABCDEF01 ", + "1267 ", + "FFFFFFFFFFFFED98 ", + "BFFFFFFFFFFFFFFE ", + "FFFFFFFFFFFFFFFF ", + "1 ", + "FFFFFFFFABCDEF01 ", + " 00000103", + " -00000104", + " 00000000", + " -00000001", + " 00000001", + " 00000001", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -00004351", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -1412567295", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -1412567295", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -1412567295", + " 00000103", + " -00000104", + " 00000000", + " -00000001", + " 00000001", + " 00000001", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -00004351", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -1412567295", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -1412567295", + " 00004711", + " -00004712", + " 00000000", + " -00000001", + " 00000001", + " -1412567295", + " 00000103", + " 00065432", + " 00000000", + " 00000255", + " 00000001", + " 00000001", + " 00004711", + " 00060824", + " 00000000", + " 00065535", + " 00000001", + " 00061185", + " 00004711", + " 4294962584", + " 3221225470", + " 4294967295", + " 00000001", + " 2882400001", + " 00004711", + " 4294962584", + " 3221225470", + " 4294967295", + " 00000001", + " 2882400001", + " 00004711", + " 18446744073709546904", + " 13835058055282163710", + " 18446744073709551615", + " 00000001", + " 18446744072296984321", + " 00000147", + " 00177630", + " 00000000", + " 00000377", + " 00000001", + " 00000001", + " 00011147", + " 00166630", + " 00000000", + " 00177777", + " 00000001", + " 00167401", + " 00011147", + " 37777766630", + " 27777777776", + " 37777777777", + " 00000001", + " 25363367401", + " 00011147", + " 37777766630", + " 27777777776", + " 37777777777", + " 00000001", + " 25363367401", + " 00011147", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + " 00000001", + "1777777777765363367401", + " 00000067", + " 0000ff98", + " 00000000", + " 000000ff", + " 00000001", + " 00000001", + " 00001267", + " 0000ed98", + " 00000000", + " 0000ffff", + " 00000001", + " 0000ef01", + " 00001267", + " ffffed98", + " bffffffe", + " ffffffff", + " 00000001", + " abcdef01", + " 00001267", + " ffffed98", + " bffffffe", + " ffffffff", + " 00000001", + " abcdef01", + " 00001267", + " ffffffffffffed98", + " bffffffffffffffe", + " ffffffffffffffff", + " 00000001", + " ffffffffabcdef01", + " 00000067", + " 0000FF98", + " 00000000", + " 000000FF", + " 00000001", + " 00000001", + " 00001267", + " 0000ED98", + " 00000000", + " 0000FFFF", + " 00000001", + " 0000EF01", + " 00001267", + " FFFFED98", + " BFFFFFFE", + " FFFFFFFF", + " 00000001", + " ABCDEF01", + " 00001267", + " FFFFED98", + " BFFFFFFE", + " FFFFFFFF", + " 00000001", + " ABCDEF01", + " 00001267", + " FFFFFFFFFFFFED98", + " BFFFFFFFFFFFFFFE", + " FFFFFFFFFFFFFFFF", + " 00000001", + " FFFFFFFFABCDEF01", + "00000103 ", + "-00000104 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "00000001 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-00004351 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-1412567295 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-1412567295 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-1412567295 ", + "00000103 ", + "-00000104 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "00000001 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-00004351 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-1412567295 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-1412567295 ", + "00004711 ", + "-00004712 ", + "00000000 ", + "-00000001 ", + "00000001 ", + "-1412567295 ", + "00000103 ", + "00065432 ", + "00000000 ", + "00000255 ", + "00000001 ", + "00000001 ", + "00004711 ", + "00060824 ", + "00000000 ", + "00065535 ", + "00000001 ", + "00061185 ", + "00004711 ", + "4294962584 ", + "3221225470 ", + "4294967295 ", + "00000001 ", + "2882400001 ", + "00004711 ", + "4294962584 ", + "3221225470 ", + "4294967295 ", + "00000001 ", + "2882400001 ", + "00004711 ", + "18446744073709546904 ", + "13835058055282163710 ", + "18446744073709551615 ", + "00000001 ", + "18446744072296984321 ", + "00000147 ", + "00177630 ", + "00000000 ", + "00000377 ", + "00000001 ", + "00000001 ", + "00011147 ", + "00166630 ", + "00000000 ", + "00177777 ", + "00000001 ", + "00167401 ", + "00011147 ", + "37777766630 ", + "27777777776 ", + "37777777777 ", + "00000001 ", + "25363367401 ", + "00011147 ", + "37777766630 ", + "27777777776 ", + "37777777777 ", + "00000001 ", + "25363367401 ", + "00011147 ", + "1777777777777777766630", + "1377777777777777777776", + "1777777777777777777777", + "00000001 ", + "1777777777765363367401", + "00000067 ", + "0000ff98 ", + "00000000 ", + "000000ff ", + "00000001 ", + "00000001 ", + "00001267 ", + "0000ed98 ", + "00000000 ", + "0000ffff ", + "00000001 ", + "0000ef01 ", + "00001267 ", + "ffffed98 ", + "bffffffe ", + "ffffffff ", + "00000001 ", + "abcdef01 ", + "00001267 ", + "ffffed98 ", + "bffffffe ", + "ffffffff ", + "00000001 ", + "abcdef01 ", + "00001267 ", + "ffffffffffffed98 ", + "bffffffffffffffe ", + "ffffffffffffffff ", + "00000001 ", + "ffffffffabcdef01 ", + "00000067 ", + "0000FF98 ", + "00000000 ", + "000000FF ", + "00000001 ", + "00000001 ", + "00001267 ", + "0000ED98 ", + "00000000 ", + "0000FFFF ", + "00000001 ", + "0000EF01 ", + "00001267 ", + "FFFFED98 ", + "BFFFFFFE ", + "FFFFFFFF ", + "00000001 ", + "ABCDEF01 ", + "00001267 ", + "FFFFED98 ", + "BFFFFFFE ", + "FFFFFFFF ", + "00000001 ", + "ABCDEF01 ", + "00001267 ", + "FFFFFFFFFFFFED98 ", + "BFFFFFFFFFFFFFFE ", + "FFFFFFFFFFFFFFFF ", + "00000001 ", + "FFFFFFFFABCDEF01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004351 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001412567295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001412567295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001412567295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004351 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001412567295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001412567295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004712 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001412567295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065432 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000255 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060824 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000065535 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061185 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004294962584 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003221225470 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004294967295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002882400001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004294962584 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003221225470 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004294967295 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002882400001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004711 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018446744073709546904 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013835058055282163710 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018446744073709551615 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018446744072296984321 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000147 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000177630 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000377 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011147 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000166630 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000177777 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000167401 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011147 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037777766630 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027777777776 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037777777777 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025363367401 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011147 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037777766630 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027777777776 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037777777777 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025363367401 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011147 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001777777777777777766630 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001377777777777777777776 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001777777777777777777777 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001777777777765363367401 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff98 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ed98 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffff ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ef01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffed98 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bffffffe ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000abcdef01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffed98 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bffffffe ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000abcdef01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffed98 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bffffffffffffffe ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffabcdef01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF98 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ED98 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000EF01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFED98 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BFFFFFFE ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFF ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ABCDEF01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFED98 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BFFFFFFE ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFF ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ABCDEF01 ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001267 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFED98 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BFFFFFFFFFFFFFFE ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF ", + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ", + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFABCDEF01 ", + NULL}; diff --git a/erts/test/erl_print_SUITE_data/snprintf_test.h b/erts/test/erl_print_SUITE_data/snprintf_test.h new file mode 100644 index 0000000000..0849b60562 --- /dev/null +++ b/erts/test/erl_print_SUITE_data/snprintf_test.h @@ -0,0 +1,43 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2005-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * This file has been automatically generated. Do NOT edit it; instead, + * run 'erl_print_tests.false snprintf save_expected_result' + */ + +char *snprintf_expected_result[] = { + "hej h", + "hej ho", + "hej hop", + "hej hopp", + "hej hopp", + "hej 4", + "hej 47", + "hej 471", + "hej 4711", + "hej 4711", + "abcdefghijklmnopqrstuvwxyz���ABCDEFGHIJKLMNOPQRSTUVXYZ���1234567890()[]{}+-;,:.@�$!\"#�%&/\\=?'`�^~��|<>�*_\a\b\f\n\r", + "abcdefghijklmnopqrstuvwxyz���ABCDEFGHIJKLMNOPQRSTUVXYZ���1234567890()[]{}+-;,:.@�$!\"#�%&/\\=?'`�^~��|<>�*_\a\b\f\n\r\t", + "abcdefghijklmnopqrstuvwxyz���ABCDEFGHIJKLMNOPQRSTUVXYZ���1234567890()[]{}+-;,:.@�$!\"#�%&/\\=?'`�^~��|<>�*_\a\b\f\n\r\t\v", + "abcdefghijklmnopqrstuvwxyz���ABCDEFGHIJKLMNOPQRSTUVXYZ���1234567890()[]{}+-;,:.@�$!\"#�%&/\\=?'`�^~��|<>�*_\a\b\f\n\r\t\v", + "abcdefghijklmnopqrstuvwxyz���ABCDEFGHIJKLMNOPQRSTUVXYZ���1234567890()[]{}+-;,:.@�$!\"#�%&/\\=?'`�^~��|<>�*_\a\b\f\n\r\t\v", + "abcdefghijklmnopqrstuvwxyz���ABCDEFGHIJKLMNOPQRSTUVXYZ�", + "abcdefghijklmnopqrstuvwxyz���ABCDEFGHIJKLMNOPQRSTUVXYZ���1234567890()[]{}+-;,:.@�$!\"#�%&/\\=?'`�^~��|<>�*_\a\b\f\n\r\t\vabcdefghijklmnopqrstuvwxyz���ABCDEFGHIJKLMNOPQRSTUVXYZ���1234567890()[]{}+-;,:.@�$!\"#�%&/\\=?'`�^~��|<>�*_\a\b\f\n\r\t\v", + NULL}; diff --git a/erts/test/erl_print_SUITE_data/string_test.h b/erts/test/erl_print_SUITE_data/string_test.h new file mode 100644 index 0000000000..32249ab6e9 --- /dev/null +++ b/erts/test/erl_print_SUITE_data/string_test.h @@ -0,0 +1,33 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2005-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * This file has been automatically generated. Do NOT edit it; instead, + * run 'erl_print_tests.false string save_expected_result' + */ + +char *string_expected_result[] = { + "hej", + "hopp ", + " hopp", + "hopp ", + " hopp", + "\t abcd", + "\t abcdefghijklmnopqrstuvwxyz���ABCDEFGHIJKLMNOPQRSTUVXYZ���1234567890()[]{}+-;,:.@�$!\"#�%&/\\=?'`�^~��|<>�*_\a\b\f\n\r\t\v", + NULL}; diff --git a/erts/test/erlc_SUITE.erl b/erts/test/erlc_SUITE.erl new file mode 100644 index 0000000000..ce64ef1a75 --- /dev/null +++ b/erts/test/erlc_SUITE.erl @@ -0,0 +1,286 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(erlc_SUITE). + +%% Tests the erlc command by compiling various types of files. + +-export([all/1, compile_erl/1, compile_yecc/1, compile_script/1, + compile_mib/1, good_citizen/1, deep_cwd/1]). + +-include("test_server.hrl"). + +all(suite) -> + [compile_erl, compile_yecc, compile_script, compile_mib, + good_citizen, deep_cwd]. + +%% Copy from erlc_SUITE_data/include/erl_test.hrl. + +-record(person, {name, shoe_size}). + +%% Tests that compiling Erlang source code works. + +compile_erl(Config) when is_list(Config) -> + ?line {SrcDir, OutDir, Cmd} = get_cmd(Config), + ?line FileName = filename:join(SrcDir, "erl_test_ok.erl"), + + %% By default, warnings are now turned on. + ?line run(Config, Cmd, FileName, "", + ["Warning: function foo/0 is unused\$", + "_OK_"]), + + %% Test that the compiled file is where it should be, + %% and that it is runnable. + + ?line {module, erl_test_ok} = code:load_abs(filename:join(OutDir, + "erl_test_ok")), + ?line 42 = erl_test_ok:shoe_size(#person{shoe_size=42}), + ?line code:purge(erl_test_ok), + + %% Try disabling warnings. + + ?line run(Config, Cmd, FileName, "-W0", ["_OK_"]), + + %% Check a bad file. + + ?line BadFile = filename:join(SrcDir, "erl_test_bad.erl"), + ?line run(Config, Cmd, BadFile, "", ["function non_existing/1 undefined\$", + "_ERROR_"]), + + ok. + +%% Test that compiling yecc source code works. + +compile_yecc(Config) when is_list(Config) -> + ?line {SrcDir, _, OutDir} = get_dirs(Config), + ?line Cmd = erlc() ++ " -o" ++ OutDir ++ " ", + ?line FileName = filename:join(SrcDir, "yecc_test_ok.yrl"), + ?line run(Config, Cmd, FileName, "-W0", ["_OK_"]), + ?line true = exists(filename:join(OutDir, "yecc_test_ok.erl")), + + ?line BadFile = filename:join(SrcDir, "yecc_test_bad.yrl"), + ?line run(Config, Cmd, BadFile, "-W0", + ["rootsymbol form is not a nonterminal\$", + "undefined nonterminal: form\$", + "Nonterminals is missing\$", + "_ERROR_"]), + ?line exists(filename:join(OutDir, "yecc_test_ok.erl")), + + ok. + +%% Test that compiling start scripts works. + +compile_script(Config) when is_list(Config) -> + ?line {SrcDir, OutDir, Cmd} = get_cmd(Config), + ?line FileName = filename:join(SrcDir, "start_ok.script"), + ?line run(Config, Cmd, FileName, "", ["_OK_"]), + ?line true = exists(filename:join(OutDir, "start_ok.boot")), + + ?line BadFile = filename:join(SrcDir, "start_bad.script"), + ?line run(Config, Cmd, BadFile, "", ["syntax error before:", "_ERROR_"]), + ok. + +%% Test that compiling SNMP mibs works. + +compile_mib(Config) when is_list(Config) -> + ?line {SrcDir, OutDir, Cmd} = get_cmd(Config), + ?line FileName = filename:join(SrcDir, "GOOD-MIB.mib"), + ?line run(Config, Cmd, FileName, "", ["_OK_"]), + ?line Output = filename:join(OutDir, "GOOD-MIB.bin"), + ?line true = exists(Output), + + %% Try -W option. + + ?line ok = file:delete(Output), + ?line run(Config, Cmd, FileName, "-W", + ["_OK_"]), + ?line true = exists(Output), + + %% Try -W option and more verbose. + + ?line ok = file:delete(Output), + ?line case test_server:os_type() of + {unix,_} -> + ?line run(Config, Cmd, FileName, "-W +'{verbosity,info}'", + ["GOOD-MIB.mib: Info. No accessfunction for 'sysDescr'", + "_OK_"]), + ?line true = exists(Output), + ?line ok = file:delete(Output); + _ -> ok %Don't bother -- too much work. + end, + + %% Try a bad file. + + ?line BadFile = filename:join(SrcDir, "BAD-MIB.mib"), + ?line run(Config, Cmd, BadFile, "", + ["Error: syntax error before: mibs\$", "compilation_failed_ERROR_"]), + + %% Make sure that no -I option works. + + ?line NewCmd = erlc() ++ " -o" ++ OutDir ++ " ", + ?line run(Config, NewCmd, FileName, "", ["_OK_"]), + ?line true = exists(Output), + + ok. + +%% Checks that 'erlc' doesn't eat any input (important when called from a +%% shell script with redirected input). +good_citizen(Config) when is_list(Config) -> + case os:type() of + {unix, _} -> + ?line PrivDir = ?config(priv_dir, Config), + ?line Answer = filename:join(PrivDir, "answer"), + ?line Script = filename:join(PrivDir, "test_script"), + ?line Test = filename:join(PrivDir, "test.erl"), + ?line S = ["#! /bin/sh\n", "erlc ", Test, "\n", + "read reply\n", "echo $reply\n"], + ?line ok = file:write_file(Script, S), + ?line ok = file:write_file(Test, "-module(test).\n"), + ?line Cmd = "echo y | sh " ++ Script ++ " > " ++ Answer, + ?line os:cmd(Cmd), + ?line {ok, Answer0} = file:read_file(Answer), + ?line [$y|_] = binary_to_list(Answer0), + ok; + _ -> + {skip, "Unix specific"} + end. + +%% Make sure that compiling an Erlang module deep down in +%% in a directory with more than 255 characters works. +deep_cwd(Config) when is_list(Config) -> + case os:type() of + {unix, _} -> + PrivDir = ?config(priv_dir, Config), + deep_cwd_1(PrivDir); + _ -> + {skip, "Only a problem on Unix"} + end. + +deep_cwd_1(PrivDir) -> + ?line DeepDir0 = filename:join(PrivDir, lists:duplicate(128, $a)), + ?line DeepDir = filename:join(DeepDir0, lists:duplicate(128, $b)), + ?line ok = file:make_dir(DeepDir0), + ?line ok = file:make_dir(DeepDir), + ?line ok = file:set_cwd(DeepDir), + ?line ok = file:write_file("test.erl", "-module(test).\n\n"), + ?line io:format("~s\n", [os:cmd("erlc test.erl")]), + ?line true = filelib:is_file("test.beam"), + ok. + +erlc() -> + case os:find_executable("erlc") of + false -> + test_server:fail("Can't find erlc"); + Erlc -> + Erlc + end. + +%% Runs a command. + +run(Config, Cmd0, Name, Options, Expect) -> + Cmd = Cmd0 ++ " " ++ Options ++ " " ++ Name, + io:format("~s", [Cmd]), + Result = run_command(Config, Cmd), + Messages = split(Result, [], []), + io:format("Result: ~p", [Messages]), + io:format("Expected: ~p", [Expect]), + match_messages(Messages, Expect). + +split([$\n|Rest], Current, Lines) -> + split(Rest, [], [lists:reverse(Current)|Lines]); +split([$\r|Rest], Current, Lines) -> + split(Rest, Current, Lines); +split([Char|Rest], Current, Lines) -> + split(Rest, [Char|Current], Lines); +split([], [], Lines) -> + lists:reverse(Lines); +split([], Current, Lines) -> + split([], [], [lists:reverse(Current)|Lines]). + +match_messages([Msg|Rest1], [Regexp|Rest2]) -> + case re:run(Msg, Regexp, [{capture,none}]) of + match -> + ok; + nomatch -> + io:format("Not matching: ~s\n", [Msg]), + io:format("Regexp : ~s\n", [Regexp]), + test_server:fail(message_mismatch) + end, + match_messages(Rest1, Rest2); +match_messages([], [Expect|Rest]) -> + test_server:fail({too_few_messages, [Expect|Rest]}); +match_messages([Msg|Rest], []) -> + test_server:fail({too_many_messages, [Msg|Rest]}); +match_messages([], []) -> + ok. + +get_cmd(Cfg) -> + ?line {SrcDir, IncDir, OutDir} = get_dirs(Cfg), + ?line Cmd = erlc() ++ " -I" ++ IncDir ++ " -o" ++ OutDir ++ " ", + {SrcDir, OutDir, Cmd}. + +get_dirs(Cfg) -> + ?line DataDir = ?config(data_dir, Cfg), + ?line PrivDir = ?config(priv_dir, Cfg), + ?line SrcDir = filename:join(DataDir, "src"), + ?line IncDir = filename:join(DataDir, "include"), + {SrcDir, IncDir, PrivDir}. + +exists(Name) -> + filelib:is_file(Name). + +%% Runs the command using os:cmd/1. +%% +%% Returns the output from the command (as a list of characters with +%% embedded newlines). The very last line will indicate the +%% exit status of the command, where _OK_ means zero, and _ERROR_ +%% a non-zero exit status. + +run_command(Config, Cmd) -> + TmpDir = filename:join(?config(priv_dir, Config), "tmp"), + file:make_dir(TmpDir), + {RunFile, Run, Script} = run_command(TmpDir, os:type(), Cmd), + ok = file:write_file(filename:join(TmpDir, RunFile), Script), + os:cmd(Run). + +run_command(Dir, {win32, _}, Cmd) -> + BatchFile = filename:join(Dir, "run.bat"), + Run = re:replace(filename:rootname(BatchFile), "/", "\\", + [global,{return,list}]), + {BatchFile, + Run, + ["@echo off\r\n", + "set ERLC_EMULATOR=", atom_to_list(lib:progname()), "\r\n", + Cmd, "\r\n", + "if errorlevel 1 echo _ERROR_\r\n", + "if not errorlevel 1 echo _OK_\r\n"]}; +run_command(Dir, {unix, _}, Cmd) -> + Name = filename:join(Dir, "run"), + {Name, + "/bin/sh " ++ Name, + ["#!/bin/sh\n", + "ERLC_EMULATOR='", atom_to_list(lib:progname()), "'\n", + "export ERLC_EMULATOR\n", + Cmd, "\n", + "case $? in\n", + " 0) echo '_OK_';;\n", + " *) echo '_ERROR_';;\n", + "esac\n"]}; +run_command(_Dir, Other, _Cmd) -> + M = io_lib:format("Don't know how to test exit code for ~p", [Other]), + test_server:fail(lists:flatten(M)). diff --git a/erts/test/erlc_SUITE_data/include/erl_test.hrl b/erts/test/erlc_SUITE_data/include/erl_test.hrl new file mode 100644 index 0000000000..fd89cb2f60 --- /dev/null +++ b/erts/test/erlc_SUITE_data/include/erl_test.hrl @@ -0,0 +1,19 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-record(person, {name, shoe_size}). diff --git a/erts/test/erlc_SUITE_data/src/BAD-MIB.mib b/erts/test/erlc_SUITE_data/src/BAD-MIB.mib new file mode 100644 index 0000000000..93bde356f4 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/BAD-MIB.mib @@ -0,0 +1 @@ +All mibs are bad! diff --git a/erts/test/erlc_SUITE_data/src/GOOD-MIB.mib b/erts/test/erlc_SUITE_data/src/GOOD-MIB.mib new file mode 100644 index 0000000000..af350ba891 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/GOOD-MIB.mib @@ -0,0 +1,39 @@ + GOOD-MIB DEFINITIONS ::= BEGIN + + IMPORTS + mgmt + FROM RFC1155-SMI + OBJECT-TYPE + FROM RFC-1212; + + + -- textual conventions + + DisplayString ::= + OCTET STRING + + -- This data type is used to model textual information taken + -- from the NVT ASCII character set. By convention, objects + -- with this syntax are declared as having + -- the System group + + -- Implementation of the System group is mandatory for all + -- systems. If an agent is not configured to have a value + -- for any of these variables, a string of length 0 is + -- returned. + + sysDescr OBJECT-TYPE + SYNTAX DisplayString (SIZE (0..255)) + ACCESS read-only + STATUS mandatory + + DESCRIPTION + "A textual description of the entity. This value + should include the full name and version + identification of the system's hardware type, + software operating-system, and networking + software. It is mandatory that this only contain + printable ASCII characters." + ::= { mgmt 1 } + + END diff --git a/erts/test/erlc_SUITE_data/src/erl_test_bad.erl b/erts/test/erlc_SUITE_data/src/erl_test_bad.erl new file mode 100644 index 0000000000..fb62f835ca --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/erl_test_bad.erl @@ -0,0 +1,22 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(erl_test_bad). + +-export([non_existing/1]). diff --git a/erts/test/erlc_SUITE_data/src/erl_test_ok.erl b/erts/test/erlc_SUITE_data/src/erl_test_ok.erl new file mode 100644 index 0000000000..50fa063a94 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/erl_test_ok.erl @@ -0,0 +1,29 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(erl_test_ok). +-export([shoe_size/1]). + +-include("erl_test.hrl"). + +shoe_size(#person{shoe_size=Size}) -> + Size. + +foo() -> + ok. diff --git a/erts/test/erlc_SUITE_data/src/start_bad.script b/erts/test/erlc_SUITE_data/src/start_bad.script new file mode 100644 index 0000000000..0cb903fabd --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/start_bad.script @@ -0,0 +1 @@ +script,{"OTP APN 181 01","NT"} diff --git a/erts/test/erlc_SUITE_data/src/start_ok.script b/erts/test/erlc_SUITE_data/src/start_ok.script new file mode 100644 index 0000000000..4cd89f0439 --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/start_ok.script @@ -0,0 +1,207 @@ +{script,{"OTP APN 181 01","NT"}, + [{preLoaded,[init,erl_prim_loader]}, + {progress,preloaded}, + {path,["$ROOT/lib/kernel/ebin", + "$ROOT/lib/stdlib/ebin"]}, + {primLoad,[error_handler, + ets, + lib, + lists, + heart, + application_controller, + application_master, + application, + auth, + c, + calendar, + code, + erlang, + erl_distribution, + erl_parse, + erl_scan, + io_lib, + io_lib_format, + io_lib_fread, + io_lib_pretty, + error_logger, + file, + filename, + os, + gen, + gen_event, + gen_server, + global, + kernel, + net_kernel, + proc_lib, + rpc, + supervisor, + sys]}, + {kernel_load_completed}, + {progress,kernel_load_completed}, + {primLoad,[group, + user, + user_drv, + kernel_config, + net, + erl_boot_server, + net_adm]}, + {primLoad,[math, + random, + ordsets, + shell_default, + timer, + gen_fsm, + pg, + unix, + dict, + pool, + string, + digraph, + io, + epp, + queue, + erl_eval, + erl_id_trans, + shell, + erl_internal, + erl_lint, + edlin, + erl_pp, + error_logger_file_h, + error_logger_tty_h, + log_mf_h, + dets, + disk_log, + regexp, + slave, + supervisor_bridge]}, + {progress,modules_loaded}, + {kernelProcess,heart,{heart,start,[]}}, + {kernelProcess,error_logger,{error_logger,start_link,[]}}, + {kernelProcess,application_controller, + {application_controller, + start, + [{application, + kernel, + [{description,"ERTS CXC 138 10"}, + {vsn,"NT"}, + {modules, + [{application,1}, + {erlang,1}, + {group,1}, + {rpc,1}, + {application_controller,1}, + {error_handler,1}, + {heart,1}, + {application_master,1}, + {error_logger,1}, + {init,1}, + {user,1}, + {auth,1}, + {kernel,1}, + {user_drv,1}, + {code,1}, + {kernel_config,1}, + {net,1}, + {erl_boot_server,1}, + {erl_prim_loader,1}, + {file,1}, + {net_adm,1}, + {erl_distribution,1}, + {global,1}, + {net_kernel,1}]}, + {registered, + [init, + erl_prim_loader, + heart, + error_logger, + application_controller, + kernel_sup, + kernel_config, + net_sup, + net_kernel, + auth, + code_server, + file_server, + boot_server, + global_name_server, + rex, + user]}, + {applications,[]}, + {env, + [{error_logger,tty}, + {os, nt}]}, + {maxT,infinity}, + {maxP,infinity}, + {mod,{kernel,[]}}]}]}}, + {progress,init_kernel_started}, + {apply,{application,load, + [{application, + stdlib, + [{description,"ERTS CXC 138 10"}, + {vsn,"NT"}, + {modules, + [{c,1}, + {gen,1}, + {io_lib_format,1}, + {math,1}, + {random,1}, + {sys,1}, + {calendar,1}, + {gen_event,1}, + {io_lib_fread,1}, + {ordsets,1}, + {shell_default,1}, + {timer,1}, + {gen_fsm,1}, + {io_lib_pretty,1}, + {pg,1}, + {slave,1}, + {unix,1}, + {dict,1}, + {gen_server,1}, + {lib,1}, + {pool,1}, + {string,1}, + {digraph,1}, + {io,1}, + {lists,1}, + {proc_lib,1}, + {supervisor,1}, + {epp,1}, + {io_lib,1}, + {log_mf_h,1}, + {queue,1}, + {erl_eval,1}, + {erl_id_trans,1}, + {shell,1}, + {erl_internal,1}, + {erl_lint,1}, + {error_logger_file_h,1}, + {erl_parse,1}, + {error_logger_tty_h,1}, + {edlin,1}, + {erl_pp,1}, + {ets,1}, + {dets,1}, + {disk_log,1}, + {regexp,1}, + {erl_scan,1}, + {supervisor_bridge,1}]}, + {registered, + [timer_server, + rsh_starter, + take_over_monitor, + pool_master, + dets, + disk_log]}, + {applications,[kernel]}, + {env,[]}, + {maxT,infinity}, + {maxP,infinity}]}]}}, + {progress,applications_loaded}, + {apply,{application,start,[kernel,permanent]}}, + {apply,{application,start,[stdlib,permanent]}}, + {apply,{c,erlangrc,[]}}, + {progress,started}]}. diff --git a/erts/test/erlc_SUITE_data/src/yecc_test_bad.yrl b/erts/test/erlc_SUITE_data/src/yecc_test_bad.yrl new file mode 100644 index 0000000000..409718e24c --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/yecc_test_bad.yrl @@ -0,0 +1,32 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +foo + +Nonterminals +form. + +Terminals +atom dot. + +Rootsymbol form. + +form -> atom dot : '$1'. + +Erlang code. diff --git a/erts/test/erlc_SUITE_data/src/yecc_test_ok.yrl b/erts/test/erlc_SUITE_data/src/yecc_test_ok.yrl new file mode 100644 index 0000000000..a96085ac2d --- /dev/null +++ b/erts/test/erlc_SUITE_data/src/yecc_test_ok.yrl @@ -0,0 +1,29 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +Nonterminals +form. + +Terminals +atom dot. + +Rootsymbol form. + +form -> atom dot : '$1'. + +Erlang code. diff --git a/erts/test/erlexec_SUITE.erl b/erts/test/erlexec_SUITE.erl new file mode 100644 index 0000000000..fcf1e67e9e --- /dev/null +++ b/erts/test/erlexec_SUITE.erl @@ -0,0 +1,437 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%%------------------------------------------------------------------- +%%% File : erlexec_SUITE.erl +%%% Author : Rickard Green <[email protected]> +%%% Description : Test erlexec's command line parsing +%%% +%%% Created : 22 May 2007 by Rickard Green <[email protected]> +%%%------------------------------------------------------------------- +-module(erlexec_SUITE). + + +%-define(line_trace, 1). + +-define(DEFAULT_TIMEOUT, ?t:minutes(1)). + +-export([all/1, init_per_testcase/2, fin_per_testcase/2]). + +-export([args_file/1, evil_args_file/1, env/1, args_file_env/1, otp_7461/1, otp_7461_remote/1, otp_8209/1]). + +-include("test_server.hrl"). + + +init_per_testcase(Case, Config) -> + Dog = ?t:timetrap(?DEFAULT_TIMEOUT), + SavedEnv = save_env(), + [{testcase, Case}, {watchdog, Dog}, {erl_flags_env, SavedEnv} |Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + SavedEnv = ?config(erl_flags_env, Config), + restore_env(SavedEnv), + cleanup_nodes(), + ?t:timetrap_cancel(Dog), + ok. + +all(doc) -> []; +all(suite) -> + [args_file, evil_args_file, env, args_file_env, otp_7461, otp_8209]. + + +otp_8209(doc) -> + ["Test that plain first argument does not " + "destroy -home switch [OTP-8209]"]; +otp_8209(suite) -> + []; +otp_8209(Config) when is_list(Config) -> + ?line {ok,[[PName]]} = init:get_argument(progname), + ?line SNameS = "erlexec_test_01", + ?line SName = list_to_atom(SNameS++"@"++ + hd(tl(string:tokens(atom_to_list(node()),"@")))), + ?line Cmd = PName ++ " dummy_param -sname "++SNameS++" -setcookie "++ + atom_to_list(erlang:get_cookie()), + ?line open_port({spawn,Cmd},[]), + ?line pong = loop_ping(SName,40), + ?line {ok,[[_]]} = rpc:call(SName,init,get_argument,[home]), + ?line ["dummy_param"] = rpc:call(SName,init,get_plain_arguments,[]), + ?line ok = cleanup_nodes(), + ok. + +cleanup_nodes() -> + cleanup_node("erlexec_test_01",20). +cleanup_node(SNameS,0) -> + {error, {would_not_die,list_to_atom(SNameS)}}; +cleanup_node(SNameS,N) -> + SName = list_to_atom(SNameS++"@"++ + hd(tl(string:tokens(atom_to_list(node()),"@")))), + case rpc:call(SName,init,stop,[]) of + {badrpc,_} -> + ok; + ok -> + receive after 500 -> ok end, + cleanup_node(SNameS,N-1) + end. + +loop_ping(_,0) -> + pang; +loop_ping(Node,N) -> + case net_adm:ping(Node) of + pang -> + receive + after 500 -> + ok + end, + loop_ping(Node, N-1); + pong -> + pong + end. + +args_file(doc) -> []; +args_file(suite) -> []; +args_file(Config) when is_list(Config) -> + ?line AFN1 = privfile("1", Config), + ?line AFN2 = privfile("2", Config), + ?line AFN3 = privfile("3", Config), + ?line AFN4 = privfile("4", Config), + ?line AFN5 = privfile("5", Config), + ?line AFN6 = privfile("6", Config), + ?line write_file(AFN1, + "-MiscArg2~n" + "# a comment +\\#1000~n" + "+\\#200 # another comment~n" + "~n" + "# another config file to read~n" + " -args_file ~s#acomment~n" + "~n" + "-MiscArg7~n" + "#~n" + "+\\#700~n" + "-extra +XtraArg6~n", + [AFN2]), + ?line write_file(AFN2, + "-MiscArg3~n" + "+\\#300~n" + "-args_file ~s~n" + "-MiscArg5~n" + "+\\#500#anothercomment -MiscArg10~n" + "-args_file ~s~n" + "-args_file ~s~n" + "-args_file ~s~n" + "-extra +XtraArg5~n", + [AFN3, AFN4, AFN5, AFN6]), + ?line write_file(AFN3, + "# comment again~n" + " -MiscArg4 +\\#400 -extra +XtraArg1"), + ?line write_file(AFN4, + " -MiscArg6 +\\#600 -extra +XtraArg2~n" + "+XtraArg3~n" + "+XtraArg4~n" + "# comment again~n"), + ?line write_file(AFN5, ""), + ?line write_file(AFN6, "-extra # +XtraArg10~n"), + ?line CmdLine = "+#100 -MiscArg1 " + ++ "-args_file " ++ AFN1 + ++ " +#800 -MiscArg8 -extra +XtraArg7 +XtraArg8", + ?line {Emu, Misc, Extra} = emu_args(CmdLine), + ?line verify_args(["-#100", "-#200", "-#300", "-#400", + "-#500", "-#600", "-#700", "-#800"], Emu), + ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", + "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8"], + Misc), + ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", + "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], + Extra), + ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", + "-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", + "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8", + "+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", + "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], + Emu), + ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", + "-#100", "-#200", "-#300", "-#400", + "-#500", "-#600", "-#700", "-#800", + "+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", + "+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"], + Misc), + ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10", + "-#100", "-#200", "-#300", "-#400", + "-#500", "-#600", "-#700", "-#800", + "-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", + "-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8"], + Extra), + ?line ok. + +evil_args_file(doc) -> []; +evil_args_file(suite) -> []; +evil_args_file(Config) when is_list(Config) -> + ?line Lim = 300, + ?line FNums = lists:seq(1, Lim), + lists:foreach(fun (End) when End == Lim -> + ?line AFN = privfile(integer_to_list(End), Config), + ?line write_file(AFN, + "-MiscArg~p ", + [End]); + (I) -> + ?line AFNX = privfile(integer_to_list(I), Config), + ?line AFNY = privfile(integer_to_list(I+1), Config), + {Frmt, Args} = + case I rem 2 of + 0 -> + {"-MiscArg~p -args_file ~s -MiscArg~p", + [I, AFNY, I]}; + _ -> + {"-MiscArg~p -args_file ~s", + [I, AFNY]} + end, + ?line write_file(AFNX, Frmt, Args) + end, + FNums), + ?line {_Emu, Misc, _Extra} = emu_args("-args_file " + ++ privfile("1", Config)), + ?line ANums = FNums + ++ lists:reverse(lists:filter(fun (I) when I == Lim -> false; + (I) when I rem 2 == 0 -> true; + (_) -> false + end, FNums)), + ?line verify_args(lists:map(fun (I) -> "-MiscArg"++integer_to_list(I) end, + ANums), + Misc), + ?line ok. + + + +env(doc) -> []; +env(suite) -> []; +env(Config) when is_list(Config) -> + ?line os:putenv("ERL_AFLAGS", "-MiscArg1 +#100 -extra +XtraArg1 +XtraArg2"), + ?line CmdLine = "+#200 -MiscArg2 -extra +XtraArg3 +XtraArg4", + ?line os:putenv("ERL_FLAGS", "-MiscArg3 +#300 -extra +XtraArg5"), + ?line os:putenv("ERL_ZFLAGS", "-MiscArg4 +#400 -extra +XtraArg6"), + ?line {Emu, Misc, Extra} = emu_args(CmdLine), + ?line verify_args(["-#100", "-#200", "-#300", "-#400"], Emu), + ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4"], + Misc), + ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", + "+XtraArg5", "+XtraArg6"], + Extra), + ?line ok. + +args_file_env(doc) -> []; +args_file_env(suite) -> []; +args_file_env(Config) when is_list(Config) -> + ?line AFN1 = privfile("1", Config), + ?line AFN2 = privfile("2", Config), + ?line write_file(AFN1, "-MiscArg2 +\\#200 -extra +XtraArg1"), + ?line write_file(AFN2, "-MiscArg3 +\\#400 -extra +XtraArg3"), + ?line os:putenv("ERL_AFLAGS", + "-MiscArg1 +#100 -args_file "++AFN1++ " -extra +XtraArg2"), + ?line CmdLine = "+#300 -args_file "++AFN2++" -MiscArg4 -extra +XtraArg4", + ?line os:putenv("ERL_FLAGS", "-MiscArg5 +#500 -extra +XtraArg5"), + ?line os:putenv("ERL_ZFLAGS", "-MiscArg6 +#600 -extra +XtraArg6"), + ?line {Emu, Misc, Extra} = emu_args(CmdLine), + ?line verify_args(["-#100", "-#200", "-#300", "-#400", + "-#500", "-#600"], Emu), + ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4", + "-MiscArg5", "-MiscArg6"], + Misc), + ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4", + "+XtraArg5", "+XtraArg6"], + Extra), + ?line ok. + +%% Make sure "erl -detached" survives when parent process group gets killed +otp_7461(doc) -> []; +otp_7461(suite) -> []; +otp_7461(Config) when is_list(Config) -> + case os:type() of + {unix,_} -> + {NetStarted, _} = net_kernel:start([test_server, shortnames]), + try + net_kernel:monitor_nodes(true), + register(otp_7461, self()), + + otp_7461_do(Config) + after + catch unregister(otp_7461), + catch net_kernel:monitor_nodes(false), + case NetStarted of + ok -> net_kernel:stop(); + _ -> ok + end + end; + _ -> + {skip,"Only on Unix."} + end. + +otp_7461_do(Config) -> + io:format("alive=~p node=~p\n",[is_alive(), node()]), + TestProg = filename:join([?config(data_dir, Config), "erlexec_tests"]), + {ok, [[ErlProg]]} = init:get_argument(progname), + ?line Cmd = TestProg ++ " " ++ ErlProg ++ + " -detached -sname " ++ get_nodename(otp_7461) ++ + " -setcookie " ++ atom_to_list(erlang:get_cookie()) ++ + " -pa " ++ filename:dirname(code:which(?MODULE)) ++ + " -s erlexec_SUITE otp_7461_remote init " ++ atom_to_list(node()), + + %% otp_7461 --------> erlexec_tests.c --------> cerl -detached + %% open_port fork+exec + + io:format("spawn port prog ~p\n",[Cmd]), + ?line Port = open_port({spawn, Cmd}, [eof]), + + io:format("Wait for node to connect...\n",[]), + ?line {nodeup, Slave} = receive Msg -> Msg + after 20*1000 -> timeout end, + io:format("Node alive: ~p\n", [Slave]), + + ?line pong = net_adm:ping(Slave), + io:format("Ping ok towards ~p\n", [Slave]), + + ?line Port ! { self(), {command, "K"}}, % Kill child process group + ?line {Port, {data, "K"}} = receive Msg2 -> Msg2 end, + ?line port_close(Port), + + %% Now the actual test. Detached node should still be alive. + ?line pong = net_adm:ping(Slave), + io:format("Ping still ok towards ~p\n", [Slave]), + + %% Halt node + ?line rpc:cast(Slave, ?MODULE, otp_7461_remote, [[halt, self()]]), + + ?line {nodedown, Slave} = receive Msg3 -> Msg3 + after 20*1000 -> timeout end, + io:format("Node dead: ~p\n", [Slave]), + ok. + + +%% Executed on slave node +otp_7461_remote([init, Master]) -> + io:format("otp_7461_remote(init,~p) at ~p\n",[Master, node()]), + net_kernel:connect_node(Master); +otp_7461_remote([halt, Pid]) -> + io:format("halt order from ~p to node ~p\n",[Pid,node()]), + halt(). + + + +%% +%% Utils +%% + +save_env() -> + {erl_flags, + os:getenv("ERL_AFLAGS"), + os:getenv("ERL_FLAGS"), + os:getenv("ERL_"++erlang:system_info(otp_release)++"_FLAGS"), + os:getenv("ERL_ZFLAGS")}. + +restore_env(EVar, false) when is_list(EVar) -> + restore_env(EVar, ""); +restore_env(EVar, "") when is_list(EVar) -> + case os:getenv(EVar) of + false -> ok; + "" -> ok; + " " -> ok; + _ -> os:putenv(EVar, " ") + end; +restore_env(EVar, Value) when is_list(EVar), is_list(Value) -> + case os:getenv(EVar) of + Value -> ok; + _ -> os:putenv(EVar, Value) + end. + +restore_env({erl_flags, AFlgs, Flgs, RFlgs, ZFlgs}) -> + restore_env("ERL_AFLAGS", AFlgs), + restore_env("ERL_FLAGS", Flgs), + restore_env("ERL_"++erlang:system_info(otp_release)++"_FLAGS", RFlgs), + restore_env("ERL_ZFLAGS", ZFlgs), + ok. + +privfile(Name, Config) -> + filename:join([?config(priv_dir, Config), + atom_to_list(?config(testcase, Config)) ++ "." ++ Name]). + +write_file(FileName, Frmt) -> + write_file(FileName, Frmt, []). + +write_file(FileName, Frmt, Args) -> + {ok, File} = file:open(FileName, [write]), + io:format(File, Frmt, Args), + ok = file:close(File). + +verify_args([], _Ys) -> + ok; +verify_args(Xs, []) -> + exit({args_not_found_in_order, Xs}); +verify_args([X|Xs], [X|Ys]) -> + verify_args(Xs, Ys); +verify_args(Xs, [_Y|Ys]) -> + verify_args(Xs, Ys). + +verify_not_args(Xs, Ys) -> + lists:foreach(fun (X) -> + case lists:member(X, Ys) of + true -> exit({arg_present, X}); + false -> ok + end + end, + Xs). + +emu_args(CmdLineArgs) -> + io:format("CmdLineArgs = ~s~n", [CmdLineArgs]), + {ok,[[Erl]]} = init:get_argument(progname), + EmuCL = os:cmd(Erl ++ " -emu_args_exit " ++ CmdLineArgs), + io:format("EmuCL = ~s", [EmuCL]), + split_emu_clt(string:tokens(EmuCL, [$ ,$\t,$\n,$\r])). + +split_emu_clt(EmuCLT) -> + split_emu_clt(EmuCLT, [], [], [], emu). + +split_emu_clt([], _Emu, _Misc, _Extra, emu) -> + exit(bad_cmd_line); +split_emu_clt([], Emu, Misc, Extra, _Type) -> + {lists:reverse(Emu), lists:reverse(Misc), lists:reverse(Extra)}; + +split_emu_clt(["--"|As], Emu, Misc, Extra, emu) -> + split_emu_clt(As, Emu, Misc, Extra, misc); +split_emu_clt([A|As], Emu, Misc, Extra, emu = Type) -> + split_emu_clt(As, [A|Emu], Misc, Extra, Type); + +split_emu_clt(["-extra"|As], Emu, Misc, Extra, misc) -> + split_emu_clt(As, Emu, Misc, Extra, extra); +split_emu_clt([A|As], Emu, Misc, Extra, misc = Type) -> + split_emu_clt(As, Emu, [A|Misc], Extra, Type); + +split_emu_clt([A|As], Emu, Misc, Extra, extra = Type) -> + split_emu_clt(As, Emu, Misc, [A|Extra], Type). + + +get_nodename(T) -> + {A, B, C} = now(), + atom_to_list(T) + ++ "-" + ++ atom_to_list(?MODULE) + ++ "-" + ++ integer_to_list(A) + ++ "-" + ++ integer_to_list(B) + ++ "-" + ++ integer_to_list(C). diff --git a/erts/test/erlexec_SUITE_data/Makefile.src b/erts/test/erlexec_SUITE_data/Makefile.src new file mode 100644 index 0000000000..b751547b8f --- /dev/null +++ b/erts/test/erlexec_SUITE_data/Makefile.src @@ -0,0 +1,37 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2008-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +CC = @CC@ +CFLAGS = @ERTS_CFLAGS@ +LIBS = @ERTS_LIBS@ + +ERLX_T_CFLAGS = -Wall $(ERLX_DEFS) $(CFLAGS) @DEFS@ + +GCC = .@DS@gccifier -CC"$(CC)" + +PROGS = erlexec_tests@exe@ + +all: $(PROGS) + +gccifier@exe@: ..@DS@utils@[email protected] + $(CC) $(CFLAGS) -o gccifier@exe@ ..@DS@utils@[email protected] $(LIBS) + +erlexec_tests@exe@: gccifier@exe@ erlexec_tests.c + $(GCC) $(ERLX_T_CFLAGS) -o erlexec_tests@exe@ erlexec_tests.c + diff --git a/erts/test/erlexec_SUITE_data/erlexec_tests.c b/erts/test/erlexec_SUITE_data/erlexec_tests.c new file mode 100644 index 0000000000..a49a0b21a8 --- /dev/null +++ b/erts/test/erlexec_SUITE_data/erlexec_tests.c @@ -0,0 +1,110 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2008-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* Used by test case otp_7461 to spawn a child process with a given + * command line. Child process group is killed by order received on stdin. + * + * Author: Sverker Eriksson + */ + +#if defined (__WIN32__) || defined(VXWORKS) || defined(_OSE_) +int main() {return 0;} + +#else /* UNIX only */ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +#define TRY(cmd) if ((cmd) < 0) bail_out(#cmd " failed") + +static void bail_out(const char* msg) +{ + perror(msg); + exit(-1); +} + +static void alarm_handler(int signo) +{ + fprintf(stderr, __FILE__" self terminating after timeout\n"); + exit(1); +} + +int main(int argc, char* argv[]) +{ + pid_t child; + int ret; + char cmd; + int child_exit; + + if (argc < 2) { + fprintf(stderr, "Must specify command to run in background\n"); + exit(-1); + } + TRY(child=fork()); + + if (child == 0) { /* child */ + pid_t gchild; + TRY(setpgid(getpid(), getpid())); /* create process group */ + + TRY(gchild=fork()); + if (gchild == 0) { /* grandchild */ + TRY(execvp(argv[1],&argv[1])); + } + exit(0); + } + /* parent */ + + signal(SIGALRM, alarm_handler); + alarm(10*60); /* suicide in case nothing happens */ + + TRY(wait(&child_exit)); + if (!WIFEXITED(child_exit) || WEXITSTATUS(child_exit)!=0) { + fprintf(stderr, "child did not exit normally (status=%d)\n", child_exit); + exit(-1); + } + + for (;;) + { + TRY(ret=read(STDIN_FILENO, &cmd, 1)); + if (ret == 0) break; /* eof -> exit */ + switch (cmd) + { + case 'K': + ret = kill(-child, SIGINT); /* child process _group_ */ + if (ret < 0 && errno != ESRCH) { + bail_out("kill failed"); + } + write(STDOUT_FILENO, &cmd, 1); /* echo ack */ + break; + case '\n': + break;/* ignore (for interactive testing) */ + default: + fprintf(stderr, "Unknown command '%c'\n", cmd); + exit(-1); + } + } + + return 0; +} + +#endif /* UNIX */ diff --git a/erts/test/ethread_SUITE.erl b/erts/test/ethread_SUITE.erl new file mode 100644 index 0000000000..a8f4f5e90c --- /dev/null +++ b/erts/test/ethread_SUITE.erl @@ -0,0 +1,365 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%%------------------------------------------------------------------- +%%% File : ethread_SUITE.erl +%%% Author : Rickard Green <[email protected]> +%%% Description : +%%% +%%% Created : 17 Jun 2004 by Rickard Green <[email protected]> +%%%------------------------------------------------------------------- +-module(ethread_SUITE). +-author('[email protected]'). + +%-define(line_trace, 1). + +-define(DEFAULT_TIMEOUT, ?t:minutes(10)). + +-export([all/1, init_per_testcase/2, fin_per_testcase/2]). + +-export([create_join_thread/1, + equal_tids/1, + mutex/1, + try_lock_mutex/1, + recursive_mutex/1, + time_now/1, + cond_wait/1, + cond_timedwait/1, + broadcast/1, + detached_thread/1, + max_threads/1, + forksafety/1, + vfork/1, + tsd/1, + spinlock/1, + rwspinlock/1, + rwmutex/1, + atomic/1, + gate/1]). + +-include("test_server.hrl"). + +tests() -> + [create_join_thread, + equal_tids, + mutex, + try_lock_mutex, + recursive_mutex, + time_now, + cond_wait, + cond_timedwait, + broadcast, + detached_thread, + max_threads, + forksafety, + vfork, + tsd, + spinlock, + rwspinlock, + rwmutex, + atomic, + gate]. + +all(doc) -> []; +all(suite) -> tests(). + + +%% +%% +%% The test-cases +%% +%% + +create_join_thread(doc) -> + ["Tests ethr_thr_create and ethr_thr_join."]; +create_join_thread(suite) -> + []; +create_join_thread(Config) -> + run_case(Config, "create_join_thread", ""). + +equal_tids(doc) -> + ["Tests ethr_equal_tids."]; +equal_tids(suite) -> + []; +equal_tids(Config) -> + run_case(Config, "equal_tids", ""). + +mutex(doc) -> + ["Tests mutexes."]; +mutex(suite) -> + []; +mutex(Config) -> + run_case(Config, "mutex", ""). + +try_lock_mutex(doc) -> + ["Tests try lock on mutex."]; +try_lock_mutex(suite) -> + []; +try_lock_mutex(Config) -> + run_case(Config, "try_lock_mutex", ""). + +recursive_mutex(doc) -> + ["Tests recursive mutexes."]; +recursive_mutex(suite) -> + []; +recursive_mutex(Config) -> + run_case(Config, "recursive_mutex", ""). + +time_now(doc) -> + ["Tests ethr_time_now by comparing time values with Erlang."]; +time_now(suite) -> + []; +time_now(Config) -> + run_case(Config, "time_now", "", fun (P) -> + spawn_link(fun () -> + watchdog(P) + end) + end). + +wd_dispatch(P) -> + receive + bye -> + ?line true = port_command(P, "-1 "), + ?line bye; + L when is_list(L) -> + ?line true = port_command(P, L), + ?line wd_dispatch(P) + end. + +watchdog(Port) -> + ?line process_flag(priority, max), + ?line receive after 500 -> ok end, + + ?line random:seed(), + ?line true = port_command(Port, "0 "), + ?line lists:foreach(fun (T) -> + erlang:send_after(T, + self(), + integer_to_list(T) + ++ " ") + end, + lists:usort(lists:map(fun (_) -> + random:uniform(4500)+500 + end, + lists:duplicate(50,0)))), + ?line erlang:send_after(5100, self(), bye), + + wd_dispatch(Port). + +cond_wait(doc) -> + ["Tests ethr_cond_wait with ethr_cond_signal and ethr_cond_broadcast."]; +cond_wait(suite) -> + []; +cond_wait(Config) -> + run_case(Config, "cond_wait", ""). + +cond_timedwait(doc) -> + ["Tests ethr_cond_timedwait with ethr_cond_signal and ethr_cond_broadcast."]; +cond_timedwait(suite) -> + []; +cond_timedwait(Config) -> + run_case(Config, "cond_timedwait", ""). + +broadcast(doc) -> + ["Tests that a ethr_cond_broadcast really wakes up all waiting threads"]; +broadcast(suite) -> + []; +broadcast(Config) -> + run_case(Config, "broadcast", ""). + +detached_thread(doc) -> + ["Tests detached threads."]; +detached_thread(suite) -> + []; +detached_thread(Config) -> + run_case(Config, "detached_thread", ""). + +max_threads(doc) -> + ["Tests maximum number of threads."]; +max_threads(suite) -> + []; +max_threads(Config) -> + run_case(Config, "max_threads", ""). + +forksafety(doc) -> + ["Tests forksafety."]; +forksafety(suite) -> + []; +forksafety(Config) -> + run_case(Config, "forksafety", ""). + +vfork(doc) -> + ["Tests vfork with threads."]; +vfork(suite) -> + case ?t:os_type() of + {unix, osf1} -> + {skip, "vfork() known to hang multi-threaded applications on osf1"}; + _ -> + [] + end; +vfork(Config) -> + run_case(Config, "vfork", ""). + +tsd(doc) -> + ["Tests thread specific data."]; +tsd(suite) -> + []; +tsd(Config) -> + run_case(Config, "tsd", ""). + +spinlock(doc) -> + ["Tests spinlocks."]; +spinlock(suite) -> + []; +spinlock(Config) -> + run_case(Config, "spinlock", ""). + +rwspinlock(doc) -> + ["Tests rwspinlocks."]; +rwspinlock(suite) -> + []; +rwspinlock(Config) -> + run_case(Config, "rwspinlock", ""). + +rwmutex(doc) -> + ["Tests rwmutexes."]; +rwmutex(suite) -> + []; +rwmutex(Config) -> + run_case(Config, "rwmutex", ""). + +atomic(doc) -> + ["Tests atomics."]; +atomic(suite) -> + []; +atomic(Config) -> + run_case(Config, "atomic", ""). + +gate(doc) -> + ["Tests gates."]; +gate(suite) -> + []; +gate(Config) -> + run_case(Config, "gate", ""). + +%% +%% +%% Auxiliary functions +%% +%% + +init_per_testcase(_Case, Config) -> + Dog = ?t:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +-define(TESTPROG, "ethread_tests"). +-define(FAILED_MARKER, $E,$T,$H,$R,$-,$T,$E,$S,$T,$-,$F,$A,$I,$L,$U,$R,$E). +-define(SKIPPED_MARKER, $E,$T,$H,$R,$-,$T,$E,$S,$T,$-,$S,$K,$I,$P). +-define(SUCCESS_MARKER, $E,$T,$H,$R,$-,$T,$E,$S,$T,$-,$S,$U,$C,$C,$E,$S,$S). +-define(PID_MARKER, $E,$T,$H,$R,$-,$T,$E,$S,$T,$-,$P,$I,$D). + +port_prog_killer(EProc, OSProc) when is_pid(EProc), is_list(OSProc) -> + ?line process_flag(trap_exit, true), + ?line Ref = erlang:monitor(process, EProc), + ?line receive + {'DOWN', Ref, _, _, Reason} when is_tuple(Reason), + element(1, Reason) + == timetrap_timeout -> + ?line Cmd = "kill -9 " ++ OSProc, + ?line ?t:format("Test case timed out. " + "Trying to kill port program.~n" + " Executing: ~p~n", [Cmd]), + ?line case os:cmd(Cmd) of + [] -> + ok; + OsCmdRes -> + ?line ?t:format(" ~s", [OsCmdRes]) + end; + {'DOWN', Ref, _, _, _} -> + %% OSProc is assumed to have terminated by itself + ?line ok + end. + +get_line(_Port, eol, Data) -> + ?line Data; +get_line(Port, noeol, Data) -> + ?line receive + {Port, {data, {Flag, NextData}}} -> + ?line get_line(Port, Flag, Data ++ NextData); + {Port, eof} -> + ?line ?t:fail(port_prog_unexpectedly_closed) + end. + +read_case_data(Port, TestCase) -> + ?line receive + {Port, {data, {eol, [?SUCCESS_MARKER]}}} -> + ?line ok; + {Port, {data, {Flag, [?SUCCESS_MARKER | CommentStart]}}} -> + ?line {comment, get_line(Port, Flag, CommentStart)}; + {Port, {data, {Flag, [?SKIPPED_MARKER | CommentStart]}}} -> + ?line {skipped, get_line(Port, Flag, CommentStart)}; + {Port, {data, {Flag, [?FAILED_MARKER | ReasonStart]}}} -> + ?line ?t:fail(get_line(Port, Flag, ReasonStart)); + {Port, {data, {eol, [?PID_MARKER | PidStr]}}} -> + ?line ?t:format("Port program pid: ~s~n", [PidStr]), + ?line CaseProc = self(), + ?line list_to_integer(PidStr), % Sanity check + spawn_opt(fun () -> + port_prog_killer(CaseProc, PidStr) + end, + [{priority, max}, link]), + read_case_data(Port, TestCase); + {Port, {data, {Flag, LineStart}}} -> + ?line ?t:format("~s~n", [get_line(Port, Flag, LineStart)]), + read_case_data(Port, TestCase); + {Port, eof} -> + ?line ?t:fail(port_prog_unexpectedly_closed) + end. + +run_case(Config, Test, TestArgs) -> + run_case(Config, Test, TestArgs, fun (_Port) -> ok end). + +run_case(Config, Test, TestArgs, Fun) -> + TestProg = filename:join([?config(data_dir, Config), ?TESTPROG]), + Cmd = TestProg ++ " " ++ Test ++ " " ++ TestArgs, + case catch open_port({spawn, Cmd}, [stream, + use_stdio, + stderr_to_stdout, + eof, + {line, 1024}]) of + Port when is_port(Port) -> + ?line Fun(Port), + ?line CaseResult = read_case_data(Port, Test), + ?line receive + {Port, eof} -> + ?line ok + end, + ?line CaseResult; + Error -> + ?line ?t:fail({open_port_failed, Error}) + end. + + + + diff --git a/erts/test/ethread_SUITE_data/Makefile.src b/erts/test/ethread_SUITE_data/Makefile.src new file mode 100644 index 0000000000..132b23344c --- /dev/null +++ b/erts/test/ethread_SUITE_data/Makefile.src @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include @erts_lib_include_internal_generated@@[email protected] +include @erts_lib_include_internal_generated@@DS@erts_internal.mk + +CC = @CC@ +CFLAGS = @ERTS_CFLAGS@ +LIBS = @ERTS_LIBS@ + +ETHR_T_CFLAGS = -Wall $(ETHR_DEFS) $(CFLAGS) @DEFS@ -I@erts_lib_include_internal@ -I@erts_lib_include_internal_generated@ +ETHR_T_LIBS = $(LIBS) -L@erts_lib_internal_path@ $(ETHR_LIBS) $(ERTS_INTERNAL_X_LIBS) + +GCC = .@DS@gccifier -CC"$(CC)" + +PROGS = ethread_tests@exe@ + +all: $(PROGS) + +gccifier@exe@: ..@DS@utils@[email protected] + $(CC) $(CFLAGS) -o gccifier@exe@ ..@DS@utils@[email protected] $(LIBS) + +ethread_tests@exe@: gccifier@exe@ ethread_tests.c + $(GCC) $(ETHR_T_CFLAGS) -o ethread_tests@exe@ ethread_tests.c -lerts_internal_r $(ETHR_T_LIBS) + diff --git a/erts/test/ethread_SUITE_data/ethread_tests.c b/erts/test/ethread_SUITE_data/ethread_tests.c new file mode 100644 index 0000000000..f779f13c51 --- /dev/null +++ b/erts/test/ethread_SUITE_data/ethread_tests.c @@ -0,0 +1,2403 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Description: Test suite for the ethread thread library. + * Author: Rickard Green + */ + +#define ETHR_NO_SUPP_THR_LIB_NOT_FATAL +#include "ethread.h" +#include "erl_misc_utils.h" + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#ifndef __WIN32__ +#include <unistd.h> +#endif +#include <limits.h> + +/* + * Auxiliary functions + */ + +#define PRINT_VA_LIST(FRMT) \ +do { \ + if (FRMT && FRMT != '\0') { \ + va_list args; \ + va_start(args, FRMT); \ + vfprintf(stderr, FRMT, args); \ + va_end(args); \ + } \ +} while (0) + +#define ASSERT(B) \ +do { \ + if (!(B)) \ + fail("%s:%d: Assertion \"%s\" failed!",__FILE__,__LINE__,#B); \ +} while (0) + + +#define ASSERT_PRINT(B, PRNT) \ +do { \ + if (!(B)) { \ + print PRNT; \ + fail("%s:%d: Assertion \"%s\" failed!",__FILE__,__LINE__,#B); \ + } \ +} while (0) + +#define ASSERT_EQ(VAR, VAL, FSTR) \ +do { \ + if ((VAR) != (VAL)) { \ + print("%s=" FSTR "\n", #VAR, (VAR)); \ + fail("%s:%d: Assertion \"%s == " FSTR "\" failed!", \ + __FILE__, __LINE__, #VAR, (VAL)); \ + } \ +} while (0) + +#ifdef __WIN32_ +#define EOL "\r\n" +#else +#define EOL "\n" +#endif + +static void +print_eol(void) +{ + fprintf(stderr, EOL); +} + +static void print_line(char *frmt,...) +{ + PRINT_VA_LIST(frmt); + print_eol(); +} + +static void print(char *frmt,...) +{ + PRINT_VA_LIST(frmt); +} + +static void fail(char *frmt,...) +{ + char *abrt_env; + print_eol(); + fprintf(stderr, "ETHR-TEST-FAILURE"); + PRINT_VA_LIST(frmt); + print_eol(); + abrt_env = getenv("ERL_ABORT_ON_FAILURE"); + if (abrt_env && strcmp("true", abrt_env) == 0) + abort(); + else + exit(1); +} + +static void skip(char *frmt,...) +{ + print_eol(); + fprintf(stderr, "ETHR-TEST-SKIP"); + PRINT_VA_LIST(frmt); + print_eol(); + exit(0); +} + +static void succeed(char *frmt,...) +{ + print_eol(); + fprintf(stderr, "ETHR-TEST-SUCCESS"); + PRINT_VA_LIST(frmt); + print_eol(); + exit(0); +} + +static void +do_sleep(unsigned secs) +{ + while (erts_milli_sleep(secs*1000) != 0); +} + +#define WAIT_UNTIL_INTERVAL 10 + +#define WAIT_UNTIL_LIM(TEST, LIM) \ +do { \ + int ms__ = (LIM)*1000; \ + while (!(TEST)) { \ + while (erts_milli_sleep(WAIT_UNTIL_INTERVAL) != 0); \ + ms__ -= WAIT_UNTIL_INTERVAL; \ + if (ms__ <= 0) \ + break; \ + } \ +} while (0) + +static void +send_my_pid(void) +{ +#ifndef __WIN32__ + int pid = (int) getpid(); + fprintf(stderr, EOL "ETHR-TEST-PID%d" EOL, pid); +#endif +} + +/* + * The test-cases + */ + +#ifndef ETHR_NO_THREAD_LIB + +/* + * The create join thread test case. + * + * Tests ethr_thr_create and ethr_thr_join. + */ + +#define CJTT_NO_THREADS 64 +ethr_tid cjtt_tids[CJTT_NO_THREADS + 1]; +int cjtt_ix[CJTT_NO_THREADS + 1]; +int cjtt_res[CJTT_NO_THREADS + 1]; +void *cjtt_thread(void *vpix) +{ + int ix = *((int *) vpix); + cjtt_res[ix] = ix; + return (void *) &cjtt_res[ix]; +} + +static void +create_join_thread_test(void) +{ + int i, res; + + for (i = 1; i <= CJTT_NO_THREADS; i++) { + cjtt_ix[i] = i; + cjtt_res[i] = 0; + } + + for (i = 1; i <= CJTT_NO_THREADS; i++) { + res = ethr_thr_create(&cjtt_tids[i], + cjtt_thread, + (void *) &cjtt_ix[i], + NULL); + ASSERT(res == 0); + } + + for (i = 1; i <= CJTT_NO_THREADS; i++) { + int *tres; + res = ethr_thr_join(cjtt_tids[i], (void **) &tres); + ASSERT(res == 0); + ASSERT(tres == &cjtt_res[i]); + ASSERT(cjtt_res[i] == i); + } + +} + + +/* + * The eq tid test case. + * + * Tests ethr_equal_tids. + */ + +#define ETT_THREADS 100000 + +static ethr_tid ett_tids[3]; +static ethr_mutex ett_mutex = ETHR_MUTEX_INITER; +static ethr_cond ett_cond = ETHR_COND_INITER; +static int ett_terminate; + +static void * +ett_thread(void *my_tid) +{ + + ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[0])); + ASSERT(ethr_equal_tids(ethr_self(), *((ethr_tid *) my_tid))); + + return NULL; +} + +static void * +ett_thread2(void *unused) +{ + int res; + res = ethr_mutex_lock(&ett_mutex); + ASSERT(res == 0); + while (!ett_terminate) { + res = ethr_cond_wait(&ett_cond, &ett_mutex); + ASSERT(res == 0); + } + res = ethr_mutex_unlock(&ett_mutex); + ASSERT(res == 0); + return NULL; +} + +static void +equal_tids_test(void) +{ + int res, i; + + ett_tids[0] = ethr_self(); + + res = ethr_thr_create(&ett_tids[1], ett_thread, (void *) &ett_tids[1], NULL); + ASSERT(res == 0); + + ASSERT(ethr_equal_tids(ethr_self(), ett_tids[0])); + ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[1])); + + res = ethr_thr_join(ett_tids[1], NULL); + + res = ethr_thr_create(&ett_tids[2], ett_thread, (void *) &ett_tids[2], NULL); + ASSERT(res == 0); + + ASSERT(ethr_equal_tids(ethr_self(), ett_tids[0])); + ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[1])); + ASSERT(!ethr_equal_tids(ethr_self(), ett_tids[2])); + +#if 0 + /* This fails on some linux platforms. Until we decides if a tid + * is allowed to be reused right away or not, we disable the test. + */ + + ASSERT(!ethr_equal_tids(ett_tids[1], ett_tids[2])); +#endif + + res = ethr_thr_join(ett_tids[2], NULL); + ASSERT(res == 0); + + /* Second part of test */ + + ett_terminate = 0; + + res = ethr_thr_create(&ett_tids[1], ett_thread2, NULL, NULL); + ASSERT(res == 0); + + ASSERT(!ethr_equal_tids(ett_tids[0], ett_tids[1])); + + for (i = 0; i < ETT_THREADS; i++) { + res = ethr_thr_create(&ett_tids[2], ett_thread, (void*)&ett_tids[2], NULL); + ASSERT(res == 0); + + ASSERT(!ethr_equal_tids(ett_tids[0], ett_tids[2])); + ASSERT(!ethr_equal_tids(ett_tids[1], ett_tids[2])); + + res = ethr_thr_join(ett_tids[2], NULL); + ASSERT(res == 0); + } + + res = ethr_mutex_lock(&ett_mutex); + ASSERT(res == 0); + ett_terminate = 1; + res = ethr_cond_signal(&ett_cond); + ASSERT(res == 0); + res = ethr_mutex_unlock(&ett_mutex); + ASSERT(res == 0); + res = ethr_thr_join(ett_tids[1], NULL); + ASSERT(res == 0); + + res = ethr_cond_destroy(&ett_cond); + ASSERT(res == 0); + res = ethr_mutex_destroy(&ett_mutex); + ASSERT(res == 0); + +} + +/* + * The mutex test case. + * + * Tests mutexes. + */ + +static ethr_mutex mt_mutex = ETHR_MUTEX_INITER; +static int mt_data; + +void * +mt_thread(void *unused) +{ + int res; + + print_line("Aux thread tries to lock mutex"); + res = ethr_mutex_lock(&mt_mutex); + ASSERT(res == 0); + print_line("Aux thread locked mutex"); + + ASSERT(mt_data == 0); + + mt_data = 1; + print_line("Aux thread wrote"); + + print_line("Aux thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Aux thread woke up"); + + ASSERT(mt_data == 1); + + res = ethr_mutex_unlock(&mt_mutex); + ASSERT(res == 0); + print_line("Aux thread unlocked mutex"); + + return NULL; +} + + +static void +mutex_test(void) +{ + int do_restart = 1; + int res; + ethr_tid tid; + + print_line("Running test with statically initialized mutex"); + + restart: + mt_data = 0; + + print_line("Main thread tries to lock mutex"); + res = ethr_mutex_lock(&mt_mutex); + ASSERT(res == 0); + print_line("Main thread locked mutex"); + + ASSERT(mt_data == 0); + + print_line("Main thread about to create aux thread"); + res = ethr_thr_create(&tid, mt_thread, NULL, NULL); + ASSERT(res == 0); + print_line("Main thread created aux thread"); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(mt_data == 0); + + res = ethr_mutex_unlock(&mt_mutex); + ASSERT(res == 0); + print_line("Main thread unlocked mutex"); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + print_line("Main thread tries to lock mutex"); + res = ethr_mutex_lock(&mt_mutex); + ASSERT(res == 0); + print_line("Main thread locked mutex"); + + ASSERT(mt_data == 1); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(mt_data == 1); + + res = ethr_mutex_unlock(&mt_mutex); + ASSERT(res == 0); + print_line("Main thread unlocked mutex"); + + res = ethr_thr_join(tid, NULL); + ASSERT(res == 0); + print_line("Main thread joined aux thread"); + + res = ethr_mutex_destroy(&mt_mutex); + ASSERT(res == 0); + print_line("Main thread destroyed mutex"); + + if (do_restart) { + do_restart = 0; + + print_line("Running test with dynamically initialized mutex"); + + print_line("Trying to initialize mutex"); + res = ethr_mutex_init(&mt_mutex); + ASSERT(res == 0); + print_line("Initialized mutex"); + + goto restart; + + } + +} + +/* + * The try lock mutex test case. + * + * Tests try lock mutex operation. + */ + +static ethr_mutex tlmt_mtx1 = ETHR_MUTEX_INITER; +static ethr_mutex tlmt_mtx2 = ETHR_MUTEX_INITER; +static ethr_cond tlmt_cnd2 = ETHR_COND_INITER; + +static int tlmt_mtx1_locked; +static int tlmt_mtx1_do_unlock; + +static void * +tlmt_thread(void *unused) +{ + int res; + + res = ethr_mutex_lock(&tlmt_mtx1); + ASSERT(res == 0); + res = ethr_mutex_lock(&tlmt_mtx2); + ASSERT(res == 0); + + tlmt_mtx1_locked = 1; + res = ethr_cond_signal(&tlmt_cnd2); + ASSERT(res == 0); + + while (!tlmt_mtx1_do_unlock) { + res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2); + ASSERT(res == 0 || res == EINTR); + } + + res = ethr_mutex_unlock(&tlmt_mtx2); + ASSERT(res == 0); + res = ethr_mutex_unlock(&tlmt_mtx1); + ASSERT(res == 0); + + res = ethr_mutex_lock(&tlmt_mtx2); + ASSERT(res == 0); + tlmt_mtx1_locked = 0; + res = ethr_cond_signal(&tlmt_cnd2); + ASSERT(res == 0); + res = ethr_mutex_unlock(&tlmt_mtx2); + ASSERT(res == 0); + + return NULL; +} + +static void +try_lock_mutex_test(void) +{ + int i, res; + ethr_tid tid; + + tlmt_mtx1_locked = 0; + tlmt_mtx1_do_unlock = 0; + + res = ethr_thr_create(&tid, tlmt_thread, NULL, NULL); + ASSERT(res == 0); + + res = ethr_mutex_lock(&tlmt_mtx2); + ASSERT(res == 0); + + while (!tlmt_mtx1_locked) { + res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2); + ASSERT(res == 0 || res == EINTR); + } + + res = ethr_mutex_unlock(&tlmt_mtx2); + ASSERT(res == 0); + + for (i = 0; i < 10; i++) { + res = ethr_mutex_trylock(&tlmt_mtx1); + ASSERT(res == EBUSY); + } + + res = ethr_mutex_lock(&tlmt_mtx2); + ASSERT(res == 0); + + tlmt_mtx1_do_unlock = 1; + res = ethr_cond_signal(&tlmt_cnd2); + ASSERT(res == 0); + + while (tlmt_mtx1_locked) { + res = ethr_cond_wait(&tlmt_cnd2, &tlmt_mtx2); + ASSERT(res == 0 || res == EINTR); + } + + res = ethr_mutex_unlock(&tlmt_mtx2); + ASSERT(res == 0); + + res = ethr_mutex_trylock(&tlmt_mtx1); + ASSERT(res == 0); + + res = ethr_mutex_unlock(&tlmt_mtx1); + ASSERT(res == 0); + + res = ethr_thr_join(tid, NULL); + ASSERT(res == 0); + + res = ethr_mutex_destroy(&tlmt_mtx1); + ASSERT(res == 0); + res = ethr_mutex_destroy(&tlmt_mtx2); + ASSERT(res == 0); + res = ethr_cond_destroy(&tlmt_cnd2); + ASSERT(res == 0); +} + +/* + * The recursive mutex test case. + * + * Tests recursive mutexes. + */ + +#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT + +static ethr_mutex rmt_mutex +#ifdef ETHR_REC_MUTEX_INITER + = ETHR_REC_MUTEX_INITER +#endif + ; +static int rmt_data; + +void * +rmt_thread(void *unused) +{ + int res; + + print_line("Aux thread tries to lock mutex"); + res = ethr_mutex_lock(&rmt_mutex); + ASSERT(res == 0); + print_line("Aux thread locked mutex"); + + ASSERT(rmt_data == 0); + + rmt_data = 1; + print_line("Aux thread wrote"); + + print_line("Aux thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Aux thread woke up"); + + ASSERT(rmt_data == 1); + + res = ethr_mutex_unlock(&rmt_mutex); + ASSERT(res == 0); + print_line("Aux thread unlocked mutex"); + + return NULL; +} + +#endif + +static void +recursive_mutex_test(void) +{ +#ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT + int do_restart = 1; + int res; + ethr_tid tid; + +#ifdef ETHR_REC_MUTEX_INITER + print_line("Running test with statically initialized mutex"); +#else + goto dynamic_init; +#endif + + restart: + rmt_data = 0; + + print_line("Main thread tries to lock mutex"); + res = ethr_mutex_lock(&rmt_mutex); + ASSERT(res == 0); + print_line("Main thread locked mutex"); + + print_line("Main thread tries to lock mutex again"); + res = ethr_mutex_lock(&rmt_mutex); + ASSERT(res == 0); + print_line("Main thread locked mutex again"); + + ASSERT(rmt_data == 0); + + print_line("Main thread about to create aux thread"); + res = ethr_thr_create(&tid, rmt_thread, NULL, NULL); + ASSERT(res == 0); + print_line("Main thread created aux thread"); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(rmt_data == 0); + + res = ethr_mutex_unlock(&rmt_mutex); + ASSERT(res == 0); + print_line("Main thread unlocked mutex"); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(rmt_data == 0); + + res = ethr_mutex_unlock(&rmt_mutex); + ASSERT(res == 0); + print_line("Main thread unlocked mutex again"); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + print_line("Main thread tries to lock mutex"); + res = ethr_mutex_lock(&rmt_mutex); + ASSERT(res == 0); + print_line("Main thread locked mutex"); + + ASSERT(rmt_data == 1); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(rmt_data == 1); + + res = ethr_mutex_unlock(&rmt_mutex); + ASSERT(res == 0); + print_line("Main thread unlocked mutex"); + + res = ethr_thr_join(tid, NULL); + ASSERT(res == 0); + print_line("Main thread joined aux thread"); + + res = ethr_mutex_destroy(&rmt_mutex); + ASSERT(res == 0); + print_line("Main thread destroyed mutex"); + + if (do_restart) { +#ifndef ETHR_REC_MUTEX_INITER + dynamic_init: +#endif + do_restart = 0; + + print_line("Running test with dynamically initialized mutex"); + + print_line("Trying to initialize mutex"); + res = ethr_rec_mutex_init(&rmt_mutex); + ASSERT(res == 0); + print_line("Initialized mutex"); + + goto restart; + } + +#ifndef ETHR_REC_MUTEX_INITER + succeed("Static initializer for recursive mutexes not supported"); +#endif + +#else /* #ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT */ + skip("Recursive mutexes not supported"); +#endif /* #ifdef ETHR_HAVE_ETHR_REC_MUTEX_INIT */ +} + +/* + * The time now test. + * + * Tests ethr_time_now by comparing time values with Erlang. + */ +#define TNT_MAX_TIME_DIFF 200000 +#define TNT_MAX_TIME_VALUES 52 + +static void +time_now_test(void) +{ + int scanf_res, time_now_res, i, no_values, max_abs_diff; + static ethr_timeval tv[TNT_MAX_TIME_VALUES]; + static int ms[TNT_MAX_TIME_VALUES]; + + i = 0; + do { + ASSERT(i < TNT_MAX_TIME_VALUES); + scanf_res = scanf("%d", &ms[i]); + time_now_res = ethr_time_now(&tv[i]); + ASSERT(scanf_res == 1); + ASSERT(time_now_res == 0); +#if 0 + print_line("Got %d; %ld:%ld", ms[i], tv[i].tv_sec, tv[i].tv_nsec); +#endif + i++; + } while (ms[i-1] >= 0); + + no_values = i-1; + + ASSERT(ms[0] == 0); + + print_line("TNT_MAX_TIME_DIFF = %d (us)", TNT_MAX_TIME_DIFF); + + max_abs_diff = 0; + + for (i = 1; i < no_values; i++) { + long diff; + long tn_us; + long e_us; + + tn_us = (tv[i].tv_sec - tv[0].tv_sec) * 1000000; + tn_us += (tv[i].tv_nsec - tv[0].tv_nsec)/1000; + + e_us = ms[i]*1000; + + diff = e_us - tn_us; + + print_line("Erlang time = %ld us; ethr_time_now = %ld us; diff %ld us", + e_us, tn_us, diff); + + if (max_abs_diff < abs((int) diff)) { + max_abs_diff = abs((int) diff); + } + + ASSERT(e_us - TNT_MAX_TIME_DIFF <= tn_us); + ASSERT(tn_us <= e_us + TNT_MAX_TIME_DIFF); + } + + print_line("Max absolute diff = %d us", max_abs_diff); + succeed("Max absolute diff = %d us", max_abs_diff); +} + +/* + * The cond wait test case. + * + * Tests ethr_cond_wait with ethr_cond_signal and ethr_cond_broadcast. + */ + + +static ethr_mutex cwt_mutex = ETHR_MUTEX_INITER; +static ethr_cond cwt_cond = ETHR_COND_INITER; +static int cwt_counter; + +void * +cwt_thread(void *is_timedwait_test_ptr) +{ + int use_timedwait = *((int *) is_timedwait_test_ptr); + int res; + + res = ethr_mutex_lock(&cwt_mutex); + ASSERT(res == 0); + + if (use_timedwait) { + ethr_timeval tv; + res = ethr_time_now(&tv); + ASSERT(res == 0); + tv.tv_sec += 3600; /* Make sure we won't time out */ + + do { + res = ethr_cond_timedwait(&cwt_cond, &cwt_mutex, &tv); + } while (res == EINTR); + ASSERT(res == 0); + } + else { + do { + res = ethr_cond_wait(&cwt_cond, &cwt_mutex); + } while (res == EINTR); + ASSERT(res == 0); + } + + cwt_counter++; + + res = ethr_mutex_unlock(&cwt_mutex); + ASSERT(res == 0); + + return NULL; +} + +static void +cond_wait_test(int is_timedwait_test) +{ + int do_restart = !is_timedwait_test; + ethr_tid tid1, tid2; + int res; + + if (!is_timedwait_test) + print_line("Running test with statically initialized mutex and cond"); + + restart: + /* Wake with signal */ + + cwt_counter = 0; + + res = ethr_thr_create(&tid1, cwt_thread, (void *) &is_timedwait_test, NULL); + ASSERT(res == 0); + res = ethr_thr_create(&tid2, cwt_thread, (void *) &is_timedwait_test, NULL); + ASSERT(res == 0); + + do_sleep(1); /* Make sure threads waits on cond var */ + + res = ethr_mutex_lock(&cwt_mutex); + ASSERT(res == 0); + + res = ethr_cond_signal(&cwt_cond); /* Wake one thread */ + ASSERT(res == 0); + + do_sleep(1); /* Make sure awakened thread waits on mutex */ + + ASSERT(cwt_counter == 0); + + res = ethr_mutex_unlock(&cwt_mutex); + ASSERT(res == 0); + + do_sleep(1); /* Let awakened thread proceed */ + + res = ethr_mutex_lock(&cwt_mutex); + ASSERT(res == 0); + + ASSERT(cwt_counter == 1); + + res = ethr_cond_signal(&cwt_cond); /* Wake the other thread */ + ASSERT(res == 0); + + do_sleep(1); /* Make sure awakened thread waits on mutex */ + + ASSERT(cwt_counter == 1); + + res = ethr_mutex_unlock(&cwt_mutex); + ASSERT(res == 0); + + do_sleep(1); /* Let awakened thread proceed */ + + res = ethr_mutex_lock(&cwt_mutex); + ASSERT(res == 0); + + ASSERT(cwt_counter == 2); + + res = ethr_mutex_unlock(&cwt_mutex); + ASSERT(res == 0); + + res = ethr_thr_join(tid1, NULL); + ASSERT(res == 0); + + res = ethr_thr_join(tid2, NULL); + ASSERT(res == 0); + + + /* Wake with broadcast */ + + cwt_counter = 0; + + res = ethr_thr_create(&tid1, cwt_thread, (void *) &is_timedwait_test, NULL); + ASSERT(res == 0); + res = ethr_thr_create(&tid2, cwt_thread, (void *) &is_timedwait_test, NULL); + ASSERT(res == 0); + + do_sleep(1); /* Make sure threads waits on cond var */ + + res = ethr_mutex_lock(&cwt_mutex); + ASSERT(res == 0); + + res = ethr_cond_broadcast(&cwt_cond); /* Wake the threads */ + ASSERT(res == 0); + + do_sleep(1); /* Make sure awakened threads wait on mutex */ + + ASSERT(cwt_counter == 0); + + res = ethr_mutex_unlock(&cwt_mutex); + ASSERT(res == 0); + + do_sleep(1); /* Let awakened threads proceed */ + + res = ethr_mutex_lock(&cwt_mutex); + ASSERT(res == 0); + + ASSERT(cwt_counter == 2); + + res = ethr_mutex_unlock(&cwt_mutex); + ASSERT(res == 0); + + res = ethr_thr_join(tid1, NULL); + ASSERT(res == 0); + + res = ethr_thr_join(tid2, NULL); + ASSERT(res == 0); + + res = ethr_mutex_destroy(&cwt_mutex); + ASSERT(res == 0); + res = ethr_cond_destroy(&cwt_cond); + ASSERT(res == 0); + + if (do_restart) { + do_restart = 0; + res = ethr_mutex_init(&cwt_mutex); + ASSERT(res == 0); + res = ethr_cond_init(&cwt_cond); + ASSERT(res == 0); + print_line("Running test with dynamically initialized mutex and cond"); + goto restart; + } +} + +/* + * The cond timedwait test case. + * + * Tests ethr_cond_timedwait with ethr_cond_signal and ethr_cond_broadcast. + */ + +#define CTWT_MAX_TIME_DIFF 100000 + +static long +ctwt_check_timeout(long to) +{ + int res; + ethr_timeval tva, tvb; + long diff, abs_diff; + + res = ethr_time_now(&tva); + ASSERT(res == 0); + + tva.tv_sec += to / 1000; + tva.tv_nsec += (to % 1000) * 1000000; + if (tva.tv_nsec >= 1000000000) { + tva.tv_sec++; + tva.tv_nsec -= 1000000000; + ASSERT(tva.tv_nsec < 1000000000); + } + + do { + res = ethr_cond_timedwait(&cwt_cond, &cwt_mutex, &tva); + } while (res == EINTR); + ASSERT(res == ETIMEDOUT); + + res = ethr_time_now(&tvb); + ASSERT(res == 0); + + diff = (tvb.tv_sec - tva.tv_sec) * 1000000; + diff += (tvb.tv_nsec - tva.tv_nsec)/1000; + + print("Timeout=%ld; ", to); + print("tva.tv_sec=%ld tva.tv_nsec=%ld; ", tva.tv_sec, tva.tv_nsec); + print("tvb.tv_sec=%ld tvb.tv_nsec=%ld; ", tvb.tv_sec, tvb.tv_nsec); + print_line("diff (tvb - tva) = %ld us", diff); + + abs_diff = (long) abs((int) diff); + + ASSERT(CTWT_MAX_TIME_DIFF >= abs_diff); + return abs_diff; +} + +static void +cond_timedwait_test(void) +{ + int do_restart = 1; + long abs_diff, max_abs_diff = 0; + int res; + +#define CTWT_UPD_MAX_DIFF if (abs_diff > max_abs_diff) max_abs_diff = abs_diff; + + print_line("Running test with statically initialized mutex and cond"); + + print_line("CTWT_MAX_TIME_DIFF=%d", CTWT_MAX_TIME_DIFF); + + restart: + + res = ethr_mutex_lock(&cwt_mutex); + ASSERT(res == 0); + + abs_diff = ctwt_check_timeout(300); + CTWT_UPD_MAX_DIFF; + abs_diff = ctwt_check_timeout(700); + CTWT_UPD_MAX_DIFF; + abs_diff = ctwt_check_timeout(1000); + CTWT_UPD_MAX_DIFF; + abs_diff = ctwt_check_timeout(2300); + CTWT_UPD_MAX_DIFF; + abs_diff = ctwt_check_timeout(5100); + CTWT_UPD_MAX_DIFF; + + res = ethr_mutex_unlock(&cwt_mutex); + ASSERT(res == 0); + + cond_wait_test(1); + + if (do_restart) { + do_restart = 0; + res = ethr_mutex_init(&cwt_mutex); + ASSERT(res == 0); + res = ethr_cond_init(&cwt_cond); + ASSERT(res == 0); + print_line("Running test with dynamically initialized mutex and cond"); + goto restart; + } + + print_line("Max absolute diff = %d us", max_abs_diff); + succeed("Max absolute diff = %d us", max_abs_diff); + +#undef CTWT_UPD_MAX_DIFF +} + +/* + * The broadcast test case. + * + * Tests that a ethr_cond_broadcast really wakes up all waiting threads. + */ + +#define BCT_THREADS 64 +#define BCT_NO_OF_WAITS 100 + +static int bct_woken = 0; +static int bct_waiting = 0; +static int bct_done = 0; +static ethr_mutex bct_mutex = ETHR_MUTEX_INITER; +static ethr_cond bct_cond = ETHR_COND_INITER; +static ethr_cond bct_cntrl_cond = ETHR_COND_INITER; + + +static void * +bct_thread(void *unused) +{ + int res; + + res = ethr_mutex_lock(&bct_mutex); + ASSERT(res == 0); + + while (!bct_done) { + + bct_waiting++; + if (bct_waiting == BCT_THREADS) { + res = ethr_cond_signal(&bct_cntrl_cond); + ASSERT(res == 0); + } + do { + res = ethr_cond_wait(&bct_cond, &bct_mutex); + } while (res == EINTR); + ASSERT(res == 0); + bct_woken++; + if (bct_woken == BCT_THREADS) { + res = ethr_cond_signal(&bct_cntrl_cond); + ASSERT(res == 0); + } + + } + + res = ethr_mutex_unlock(&bct_mutex); + ASSERT(res == 0); + + return NULL; +} + +static void +broadcast_test(void) +{ + int res, i; + ethr_tid tid[BCT_THREADS]; + + for (i = 0; i < BCT_THREADS; i++) { + res = ethr_thr_create(&tid[i], bct_thread, NULL, NULL); + ASSERT(res == 0); + + } + + res = ethr_mutex_lock(&bct_mutex); + ASSERT(res == 0); + + for (i = 0; i < BCT_NO_OF_WAITS; i++) { + + while (bct_waiting != BCT_THREADS) { + res = ethr_cond_wait(&bct_cntrl_cond, &bct_mutex); + ASSERT(res == 0 || res == EINTR); + } + + bct_waiting = 0; + bct_woken = 0; + + /* Wake all threads */ + res = ethr_cond_broadcast(&bct_cond); + ASSERT(res == 0); + + while (bct_woken != BCT_THREADS) { + res = ethr_cond_wait(&bct_cntrl_cond, &bct_mutex); + ASSERT(res == 0 || res == EINTR); + } + + } + + bct_done = 1; + + /* Wake all threads */ + res = ethr_cond_broadcast(&bct_cond); + ASSERT(res == 0); + + res = ethr_mutex_unlock(&bct_mutex); + ASSERT(res == 0); + + for (i = 0; i < BCT_THREADS - 1; i++) { + res = ethr_thr_join(tid[i], NULL); + ASSERT(res == 0); + } + + res = ethr_mutex_destroy(&bct_mutex); + ASSERT(res == 0); + res = ethr_cond_destroy(&bct_cntrl_cond); + ASSERT(res == 0); + res = ethr_cond_destroy(&bct_cond); + ASSERT(res == 0); + +} + +/* + * The detached thread test case. + * + * Tests detached threads. + */ + +#define DT_THREADS (50*1024) +#define DT_BATCH_SIZE 64 + +static ethr_mutex dt_mutex = ETHR_MUTEX_INITER; +static ethr_cond dt_cond = ETHR_COND_INITER; +static int dt_count; +static int dt_limit; + +static void * +dt_thread(void *unused) +{ + int res; + + res = ethr_mutex_lock(&dt_mutex); + ASSERT(res == 0); + + dt_count++; + + if (dt_count >= dt_limit) + ethr_cond_signal(&dt_cond); + + res = ethr_mutex_unlock(&dt_mutex); + ASSERT(res == 0); + + return NULL; +} + +static void +detached_thread_test(void) +{ + ethr_thr_opts thr_opts = ETHR_THR_OPTS_DEFAULT_INITER; + ethr_tid tid[DT_BATCH_SIZE]; + int i, j, res; + + thr_opts.detached = 1; + dt_count = 0; + dt_limit = 0; + + for (i = 0; i < DT_THREADS/DT_BATCH_SIZE; i++) { + + dt_limit += DT_BATCH_SIZE; + + for (j = 0; j < DT_BATCH_SIZE; j++) { + res = ethr_thr_create(&tid[j], dt_thread, NULL, &thr_opts); + ASSERT(res == 0); + } + + res = ethr_mutex_lock(&dt_mutex); + ASSERT(res == 0); + while (dt_count < dt_limit) { + res = ethr_cond_wait(&dt_cond, &dt_mutex); + ASSERT(res == 0 || res == EINTR); + } + res = ethr_mutex_unlock(&dt_mutex); + ASSERT(res == 0); + + print_line("dt_count = %d", dt_count); + } + do_sleep(1); +} + + + +/* + * The max threads test case. + * + * Tests + */ +#define MTT_TIMES 10 + +static int mtt_terminate; +static ethr_mutex mtt_mutex = ETHR_MUTEX_INITER; +static ethr_cond mtt_cond = ETHR_COND_INITER; +static char mtt_string[22*MTT_TIMES]; /* 22 is enough for ", %d" */ + + +void *mtt_thread(void *unused) +{ + int res; + + res = ethr_mutex_lock(&mtt_mutex); + ASSERT(res == 0); + + while (!mtt_terminate) { + res = ethr_cond_wait(&mtt_cond, &mtt_mutex); + ASSERT(res == 0 || res == EINTR); + } + + res = ethr_mutex_unlock(&mtt_mutex); + ASSERT(res == 0); + + return NULL; +} + + +static int +mtt_create_join_threads(void) +{ + int no_tids = 100, ix = 0, res = 0, no_threads; + ethr_tid *tids; + + mtt_terminate = 0; + + tids = (ethr_tid *) malloc(sizeof(ethr_tid)*no_tids); + ASSERT(tids); + + print_line("Beginning to create threads"); + + while (1) { + if (ix >= no_tids) { + no_tids += 100; + tids = (ethr_tid *) realloc((void *)tids, sizeof(ethr_tid)*no_tids); + ASSERT(tids); + } + res = ethr_thr_create(&tids[ix], mtt_thread, NULL, NULL); + if (res != 0) + break; + ix++; + } while (res == 0); + + no_threads = ix; + + print_line("%d = ethr_thr_create()", res); + print_line("Number of created threads: %d", no_threads); + + res = ethr_mutex_lock(&mtt_mutex); + ASSERT(res == 0); + + mtt_terminate = 1; + + res = ethr_cond_broadcast(&mtt_cond); + ASSERT(res == 0); + + res = ethr_mutex_unlock(&mtt_mutex); + ASSERT(res == 0); + + while (ix) { + res = ethr_thr_join(tids[--ix], NULL); + ASSERT(res == 0); + } + + print_line("All created threads terminated"); + + free((void *) tids); + + return no_threads; + +} + +static void +max_threads_test(void) +{ + int no_threads[MTT_TIMES], i, up, down, eq; + char *str; + + for (i = 0; i < MTT_TIMES; i++) { + no_threads[i] = mtt_create_join_threads(); + } + + str = &mtt_string[0]; + eq = up = down = 0; + for (i = 0; i < MTT_TIMES; i++) { + if (i == 0) { + str += sprintf(str, "%d", no_threads[i]); + continue; + } + + str += sprintf(str, ", %d", no_threads[i]); + + if (no_threads[i] < no_threads[i-1]) + down++; + else if (no_threads[i] > no_threads[i-1]) + up++; + else + eq++; + } + + print_line("Max created threads: %s", mtt_string); + + /* We fail if the no of threads we are able to create constantly decrease */ + ASSERT(!down || up || eq); + + succeed("Max created threads: %s", mtt_string); + +} + + +/* + * The forksafety test case. + * + * Tests forksafety. + */ +#ifdef __WIN32__ +#define NO_FORK_PRESENT +#endif + +#ifndef NO_FORK_PRESENT + +static ethr_mutex ft_test_inner_mutex = ETHR_MUTEX_INITER; +static ethr_mutex ft_test_outer_mutex = ETHR_MUTEX_INITER; +static ethr_mutex ft_go_mutex = ETHR_MUTEX_INITER; +static ethr_cond ft_go_cond = ETHR_COND_INITER; +static int ft_go; +static int ft_have_forked; + +static void * +ft_thread(void *unused) +{ + int res; + + res = ethr_mutex_lock(&ft_test_outer_mutex); + ASSERT(res == 0); + + res = ethr_mutex_lock(&ft_go_mutex); + ASSERT(res == 0); + + ft_go = 1; + res = ethr_cond_signal(&ft_go_cond); + ASSERT(res == 0); + res = ethr_mutex_unlock(&ft_go_mutex); + ASSERT(res == 0); + + do_sleep(1); + ASSERT(!ft_have_forked); + + res = ethr_mutex_lock(&ft_test_inner_mutex); + ASSERT(res == 0); + + res = ethr_mutex_unlock(&ft_test_inner_mutex); + ASSERT(res == 0); + + do_sleep(1); + ASSERT(!ft_have_forked); + + res = ethr_mutex_unlock(&ft_test_outer_mutex); + ASSERT(res == 0); + + do_sleep(1); + ASSERT(ft_have_forked); + + + return NULL; +} + +#endif /* #ifndef NO_FORK_PRESENT */ + +static void +forksafety_test(void) +{ +#ifdef NO_FORK_PRESENT + skip("No fork() present; nothing to test"); +#elif defined(DEBUG) + skip("Doesn't work in debug build"); +#else + char snd_msg[] = "ok, bye!"; + char rec_msg[sizeof(snd_msg)*2]; + ethr_tid tid; + int res; + int fds[2]; + + + res = ethr_mutex_set_forksafe(&ft_test_inner_mutex); + if (res == ENOTSUP) { + skip("Forksafety not supported on this platform!"); + } + ASSERT(res == 0); + res = ethr_mutex_set_forksafe(&ft_test_outer_mutex); + ASSERT(res == 0); + + + res = pipe(fds); + ASSERT(res == 0); + + ft_go = 0; + ft_have_forked = 0; + + res = ethr_mutex_lock(&ft_go_mutex); + ASSERT(res == 0); + + res = ethr_thr_create(&tid, ft_thread, NULL, NULL); + ASSERT(res == 0); + + do { + res = ethr_cond_wait(&ft_go_cond, &ft_go_mutex); + } while (res == EINTR || !ft_go); + ASSERT(res == 0); + + res = ethr_mutex_unlock(&ft_go_mutex); + ASSERT(res == 0); + + res = fork(); + ft_have_forked = 1; + if (res == 0) { + close(fds[0]); + res = ethr_mutex_lock(&ft_test_outer_mutex); + if (res != 0) + _exit(1); + res = ethr_mutex_lock(&ft_test_inner_mutex); + if (res != 0) + _exit(1); + res = ethr_mutex_unlock(&ft_test_inner_mutex); + if (res != 0) + _exit(1); + res = ethr_mutex_unlock(&ft_test_outer_mutex); + if (res != 0) + _exit(1); + + res = ethr_mutex_destroy(&ft_test_inner_mutex); + if (res != 0) + _exit(1); + res = ethr_mutex_destroy(&ft_test_outer_mutex); + if (res != 0) + _exit(1); + + res = (int) write(fds[1], (void *) snd_msg, sizeof(snd_msg)); + if (res != sizeof(snd_msg)) + _exit(1); + close(fds[1]); + _exit(0); + } + ASSERT(res > 0); + close(fds[1]); + + res = (int) read(fds[0], (void *) rec_msg, sizeof(rec_msg)); + ASSERT(res == (int) sizeof(snd_msg)); + ASSERT(strcmp(snd_msg, rec_msg) == 0); + + close(fds[0]); +#endif +} + + +/* + * The vfork test case. + * + * Tests vfork with threads. + */ + +#ifdef __WIN32__ +#define NO_VFORK_PRESENT +#endif + +#ifndef NO_VFORK_PRESENT + +#undef vfork + +static ethr_mutex vt_mutex = ETHR_MUTEX_INITER; + +static void * +vt_thread(void *vprog) +{ + char *prog = (char *) vprog; + int res; + char snd_msg[] = "ok, bye!"; + char rec_msg[sizeof(snd_msg)*2]; + int fds[2]; + char closefd[20]; + char writefd[20]; + + res = pipe(fds); + ASSERT(res == 0); + + res = sprintf(closefd, "%d", fds[0]); + ASSERT(res <= 20); + res = sprintf(writefd, "%d", fds[1]); + ASSERT(res <= 20); + + print("parent: About to vfork and execute "); + print("execlp(\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", NULL)", + prog, prog, "vfork", "exec", snd_msg, closefd, writefd); + print_line(" in child"); + res = vfork(); + if (res == 0) { + execlp(prog, prog, "vfork", "exec", snd_msg, closefd, writefd, NULL); + _exit(1); + } + ASSERT(res > 0); + + print_line("parent: I'm back"); + + close(fds[1]); + + res = (int) read(fds[0], (void *) rec_msg, sizeof(rec_msg)); + print_line("parent: %d = read()", res); + print_line("parent: rec_msg=\"%s\"", rec_msg); + ASSERT(res == (int) sizeof(snd_msg)); + ASSERT(strcmp(snd_msg, rec_msg) == 0); + + close(fds[0]); + + return NULL; +} + +#endif /* #ifndef NO_VFORK_PRESENT */ + +static void +vfork_test(int argc, char *argv[]) +{ +#ifdef NO_VFORK_PRESENT + skip("No vfork() present; nothing to test"); +#else + int res; + ethr_tid tid; + + if (argc == 6 && strcmp("exec", argv[2]) == 0) { + /* We are child after vfork() and execlp() ... */ + + char *snd_msg; + int closefd; + int writefd; + + snd_msg = argv[3]; + closefd = atoi(argv[4]); + writefd = atoi(argv[5]); + + print_line("child: snd_msg=\"%s\"; closefd=%d writefd=%d", + snd_msg, closefd, writefd); + + close(closefd); + + res = (int) write(writefd, (void *) snd_msg, strlen(snd_msg)+1); + print_line("child: %d = write()", res); + if (res != strlen(snd_msg)+1) + exit(1); + close(writefd); + print_line("child: bye"); + exit(0); + } + ASSERT(argc == 2); + + res = ethr_mutex_set_forksafe(&vt_mutex); + ASSERT(res == 0 || res == ENOTSUP); + res = ethr_mutex_lock(&vt_mutex); + ASSERT(res == 0); + + res = ethr_thr_create(&tid, vt_thread, (void *) argv[0], NULL); + ASSERT(res == 0); + + do_sleep(1); + + res = ethr_mutex_unlock(&vt_mutex); + ASSERT(res == 0); + + res = ethr_thr_join(tid, NULL); + ASSERT(res == 0); + + res = ethr_mutex_destroy(&vt_mutex); + ASSERT(res == 0); +#endif +} + + +/* + * The tsd test case. + * + * Tests thread specific data. + */ + +#define TT_THREADS 10 +static ethr_tsd_key tt_key; + +static void * +tt_thread(void *arg) +{ + int res = ethr_tsd_set(tt_key, arg); + ASSERT(res == 0); + return ethr_tsd_get(tt_key); +} + +static void +tsd_test(void) +{ + void *tres; + int i, res; + ethr_tid tid[TT_THREADS]; + int values[TT_THREADS]; + + res = ethr_tsd_key_create(&tt_key); + ASSERT(res == 0); + + for (i = 1; i < TT_THREADS; i++) { + res = ethr_thr_create(&tid[i], tt_thread, (void *) &values[i], NULL); + ASSERT(res == 0); + } + + tres = tt_thread((void *) &values[0]); + ASSERT(tres == (void *) &values[0]); + + for (i = 1; i < TT_THREADS; i++) { + res = ethr_thr_join(tid[i], &tres); + ASSERT(res == 0); + ASSERT(tres == (void *) &values[i]); + } + + res = ethr_tsd_key_delete(tt_key); + ASSERT(res == 0); +} + + +/* + * The spinlock test case. + * + * Tests spinlocks. + */ + +static ethr_spinlock_t st_spinlock; +static int st_data; + +void * +st_thread(void *unused) +{ + int res; + + print_line("Aux thread tries to lock spinlock"); + res = ethr_spin_lock(&st_spinlock); + ASSERT(res == 0); + print_line("Aux thread locked spinlock"); + + ASSERT(st_data == 0); + + st_data = 1; + print_line("Aux thread wrote"); + + print_line("Aux thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Aux thread woke up"); + + ASSERT(st_data == 1); + + res = ethr_spin_unlock(&st_spinlock); + ASSERT(res == 0); + print_line("Aux thread unlocked spinlock"); + + return NULL; +} + + +static void +spinlock_test(void) +{ + int res; + ethr_tid tid; + + print_line("Trying to initialize spinlock"); + res = ethr_spinlock_init(&st_spinlock); + ASSERT(res == 0); + print_line("Initialized spinlock"); + + st_data = 0; + + print_line("Main thread tries to lock spinlock"); + res = ethr_spin_lock(&st_spinlock); + ASSERT(res == 0); + print_line("Main thread locked spinlock"); + + ASSERT(st_data == 0); + + print_line("Main thread about to create aux thread"); + res = ethr_thr_create(&tid, st_thread, NULL, NULL); + ASSERT(res == 0); + print_line("Main thread created aux thread"); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(st_data == 0); + + res = ethr_spin_unlock(&st_spinlock); + ASSERT(res == 0); + print_line("Main thread unlocked spinlock"); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + print_line("Main thread tries to lock spinlock"); + res = ethr_spin_lock(&st_spinlock); + ASSERT(res == 0); + print_line("Main thread locked spinlock"); + + ASSERT(st_data == 1); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(st_data == 1); + + res = ethr_spin_unlock(&st_spinlock); + ASSERT(res == 0); + print_line("Main thread unlocked spinlock"); + + res = ethr_thr_join(tid, NULL); + ASSERT(res == 0); + print_line("Main thread joined aux thread"); + + res = ethr_spinlock_destroy(&st_spinlock); + ASSERT(res == 0); + print_line("Main thread destroyed spinlock"); + +} + + +/* + * The rwspinlock test case. + * + * Tests rwspinlocks. + */ + +static ethr_rwlock_t rwst_rwspinlock; +static int rwst_data; + +void * +rwst_thread(void *unused) +{ + int data; + int res; + + print_line("Aux thread tries to read lock rwspinlock"); + res = ethr_read_lock(&rwst_rwspinlock); + ASSERT(res == 0); + print_line("Aux thread read locked rwspinlock"); + + ASSERT(rwst_data == 4711); + + print_line("Aux thread tries to read unlock rwspinlock"); + res = ethr_read_unlock(&rwst_rwspinlock); + ASSERT(res == 0); + print_line("Aux thread read unlocked rwspinlock"); + + print_line("Aux thread tries to write lock rwspinlock"); + res = ethr_write_lock(&rwst_rwspinlock); + ASSERT(res == 0); + print_line("Aux thread write locked rwspinlock"); + + data = ++rwst_data; + print_line("Aux thread wrote"); + + print_line("Aux thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Aux thread woke up"); + + ASSERT(rwst_data == data); + ++rwst_data; + + print_line("Aux thread tries to write unlock rwspinlock"); + res = ethr_write_unlock(&rwst_rwspinlock); + ASSERT(res == 0); + print_line("Aux thread write unlocked rwspinlock"); + + return NULL; +} + + +static void +rwspinlock_test(void) +{ + int data; + int res; + ethr_tid tid; + + print_line("Trying to initialize rwspinlock"); + res = ethr_rwlock_init(&rwst_rwspinlock); + ASSERT(res == 0); + print_line("Initialized rwspinlock"); + + rwst_data = 4711; + + print_line("Main thread tries to read lock rwspinlock"); + res = ethr_read_lock(&rwst_rwspinlock); + ASSERT(res == 0); + print_line("Main thread read locked rwspinlock"); + + ASSERT(rwst_data == 4711); + + print_line("Main thread about to create aux thread"); + res = ethr_thr_create(&tid, rwst_thread, NULL, NULL); + ASSERT(res == 0); + print_line("Main thread created aux thread"); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(rwst_data == 4711); + + print_line("Main thread tries to read unlock rwspinlock"); + res = ethr_read_unlock(&rwst_rwspinlock); + ASSERT(res == 0); + print_line("Main thread read unlocked rwspinlock"); + + print_line("Main thread tries to write lock rwspinlock"); + res = ethr_write_lock(&rwst_rwspinlock); + ASSERT(res == 0); + print_line("Main thread write locked rwspinlock"); + + data = ++rwst_data; + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(rwst_data == data); + ++rwst_data; + + print_line("Main thread tries to write unlock rwspinlock"); + res = ethr_write_unlock(&rwst_rwspinlock); + ASSERT(res == 0); + print_line("Main thread write unlocked rwspinlock"); + + res = ethr_thr_join(tid, NULL); + ASSERT(res == 0); + print_line("Main thread joined aux thread"); + + res = ethr_rwlock_destroy(&rwst_rwspinlock); + ASSERT(res == 0); + print_line("Main thread destroyed rwspinlock"); + +} + + +/* + * The rwmutex test case. + * + * Tests rwmutexes. + */ + +static ethr_rwmutex rwmt_rwmutex; +static int rwmt_data; + +void * +rwmt_thread(void *unused) +{ + int data; + int res; + + print_line("Aux thread tries to read lock rwmutex"); + res = ethr_rwmutex_rlock(&rwmt_rwmutex); + ASSERT(res == 0); + print_line("Aux thread read locked rwmutex"); + + ASSERT(rwmt_data == 4711); + + print_line("Aux thread tries to read unlock rwmutex"); + res = ethr_rwmutex_runlock(&rwmt_rwmutex); + ASSERT(res == 0); + print_line("Aux thread read unlocked rwmutex"); + + print_line("Aux thread tries to write lock rwmutex"); + res = ethr_rwmutex_rwlock(&rwmt_rwmutex); + ASSERT(res == 0); + print_line("Aux thread write locked rwmutex"); + + data = ++rwmt_data; + print_line("Aux thread wrote"); + + print_line("Aux thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Aux thread woke up"); + + ASSERT(rwmt_data == data); + ++rwmt_data; + + print_line("Aux thread tries to write unlock rwmutex"); + res = ethr_rwmutex_rwunlock(&rwmt_rwmutex); + ASSERT(res == 0); + print_line("Aux thread write unlocked rwmutex"); + + return NULL; +} + + +static void +rwmutex_test(void) +{ + int data; + int res; + ethr_tid tid; + + print_line("Trying to initialize rwmutex"); + res = ethr_rwmutex_init(&rwmt_rwmutex); + ASSERT(res == 0); + print_line("Initialized rwmutex"); + + rwmt_data = 4711; + + print_line("Main thread tries to read lock rwmutex"); + res = ethr_rwmutex_rlock(&rwmt_rwmutex); + ASSERT(res == 0); + print_line("Main thread read locked rwmutex"); + + ASSERT(rwmt_data == 4711); + + print_line("Main thread about to create aux thread"); + res = ethr_thr_create(&tid, rwmt_thread, NULL, NULL); + ASSERT(res == 0); + print_line("Main thread created aux thread"); + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(rwmt_data == 4711); + + print_line("Main thread tries to read unlock rwmutex"); + res = ethr_rwmutex_runlock(&rwmt_rwmutex); + ASSERT(res == 0); + print_line("Main thread read unlocked rwmutex"); + + print_line("Main thread tries to write lock rwmutex"); + res = ethr_rwmutex_rwlock(&rwmt_rwmutex); + ASSERT(res == 0); + print_line("Main thread write locked rwmutex"); + + data = ++rwmt_data; + + print_line("Main thread goes to sleep for 1 second"); + do_sleep(1); + print_line("Main thread woke up"); + + ASSERT(rwmt_data == data); + ++rwmt_data; + + print_line("Main thread tries to write unlock rwmutex"); + res = ethr_rwmutex_rwunlock(&rwmt_rwmutex); + ASSERT(res == 0); + print_line("Main thread write unlocked rwmutex"); + + res = ethr_thr_join(tid, NULL); + ASSERT(res == 0); + print_line("Main thread joined aux thread"); + + res = ethr_rwmutex_destroy(&rwmt_rwmutex); + ASSERT(res == 0); + print_line("Main thread destroyed rwmutex"); + +} + +/* + * The atomic test case. + * + * Tests atomics. + */ + +#define AT_THREADS 4 +#define AT_ITER 10000 + +long at_set_val, at_rm_val, at_max_val; + +static ethr_atomic_t at_ready; +static ethr_atomic_t at_go; +static ethr_atomic_t at_done; +static ethr_atomic_t at_data; + +void * +at_thread(void *unused) +{ + int res, i; + long val, go; + + + res = ethr_atomic_inctest(&at_ready, &val); + ASSERT(res == 0); + ASSERT(val > 0); + ASSERT(val <= AT_THREADS); + + do { + res = ethr_atomic_read(&at_go, &go); + ASSERT(res == 0); + } while (!go); + + for (i = 0; i < AT_ITER; i++) { + res = ethr_atomic_or_old(&at_data, at_set_val, &val); + ASSERT(res == 0); + ASSERT(val >= (i == 0 ? 0 : at_set_val) + (long) 4711); + ASSERT(val <= at_max_val); + + res = ethr_atomic_and_old(&at_data, ~at_rm_val, &val); + ASSERT(res == 0); + ASSERT(val >= at_set_val + (long) 4711); + ASSERT(val <= at_max_val); + + res = ethr_atomic_read(&at_data, &val); + ASSERT(res == 0); + ASSERT(val >= at_set_val + (long) 4711); + ASSERT(val <= at_max_val); + + res = ethr_atomic_inctest(&at_data, &val); + ASSERT(res == 0); + ASSERT(val > at_set_val + (long) 4711); + ASSERT(val <= at_max_val); + + res = ethr_atomic_dectest(&at_data, &val); + ASSERT(res == 0); + ASSERT(val >= at_set_val + (long) 4711); + ASSERT(val <= at_max_val); + + res = ethr_atomic_inc(&at_data); + ASSERT(res == 0); + + res = ethr_atomic_dec(&at_data); + ASSERT(res == 0); + + res = ethr_atomic_addtest(&at_data, (long) 4711, &val); + ASSERT(res == 0); + ASSERT(val >= at_set_val + (long) 2*4711); + ASSERT(val <= at_max_val); + + res = ethr_atomic_add(&at_data, (long) -4711); + ASSERT(res == 0); + ASSERT(val >= at_set_val + (long) 4711); + ASSERT(val <= at_max_val); + } + + res = ethr_atomic_inc(&at_done); + ASSERT(res == 0); + return NULL; +} + + +static void +atomic_test(void) +{ + long data_init, data_final, val; + int res, i; + ethr_tid tid[AT_THREADS]; + ethr_thr_opts thr_opts = ETHR_THR_OPTS_DEFAULT_INITER; + + if (sizeof(long) > 4) { + at_rm_val = ((long) 1) << 57; + at_set_val = ((long) 1) << 60; + } + else { + at_rm_val = ((long) 1) << 27; + at_set_val = ((long) 1) << 30; + } + + at_max_val = at_set_val + at_rm_val + ((long) AT_THREADS + 1) * 4711; + data_init = at_rm_val + (long) 4711; + data_final = at_set_val + (long) 4711; + + thr_opts.detached = 1; + + print_line("Initializing"); + res = ethr_atomic_init(&at_ready, 0); + ASSERT(res == 0); + res = ethr_atomic_init(&at_go, 0); + ASSERT(res == 0); + res = ethr_atomic_init(&at_done, data_init); + ASSERT(res == 0); + res = ethr_atomic_init(&at_data, data_init); + ASSERT(res == 0); + + res = ethr_atomic_read(&at_data, &val); + ASSERT(res == 0); + ASSERT(val == data_init); + res = ethr_atomic_set(&at_done, 0); + ASSERT(res == 0); + res = ethr_atomic_read(&at_done, &val); + ASSERT(res == 0); + ASSERT(val == 0); + + print_line("Creating threads"); + for (i = 0; i < AT_THREADS; i++) { + res = ethr_thr_create(&tid[i], at_thread, NULL, &thr_opts); + ASSERT(res == 0); + } + + print_line("Waiting for threads to ready up"); + do { + res = ethr_atomic_read(&at_ready, &val); + ASSERT(res == 0); + ASSERT(val >= 0); + ASSERT(val <= AT_THREADS); + } while (val != AT_THREADS); + + print_line("Letting threads loose"); + res = ethr_atomic_xchg(&at_go, 17, &val); + ASSERT(res == 0); + ASSERT(val == 0); + res = ethr_atomic_read(&at_go, &val); + ASSERT(res == 0); + ASSERT(val == 17); + + + print_line("Waiting for threads to finish"); + do { + res = ethr_atomic_read(&at_done, &val); + ASSERT(res == 0); + ASSERT(val >= 0); + ASSERT(val <= AT_THREADS); + } while (val != AT_THREADS); + + print_line("Checking result"); + res = ethr_atomic_read(&at_data, &val); + ASSERT(res == 0); + ASSERT(val == data_final); + print_line("Result ok"); + +} + + +/* + * The gate test case. + * + * Tests gates. + */ + +#define GT_THREADS 10 + +static ethr_atomic_t gt_wait1; +static ethr_atomic_t gt_wait2; +static ethr_atomic_t gt_done; + +static ethr_gate gt_gate1; +static ethr_gate gt_gate2; + +void * +gt_thread(void *thr_no) +{ + int no = (int)(long) thr_no; + int swait = no % 2 == 0; + int res; + long done; + + + do { + + res = ethr_atomic_inc(>_wait1); + ASSERT(res == 0); + + if (swait) + res = ethr_gate_swait(>_gate1, INT_MAX); + else + res = ethr_gate_wait(>_gate1); + ASSERT(res == 0); + + res = ethr_atomic_dec(>_wait1); + ASSERT(res == 0); + + res = ethr_atomic_inc(>_wait2); + ASSERT(res == 0); + + if (swait) + res = ethr_gate_swait(>_gate2, INT_MAX); + else + res = ethr_gate_wait(>_gate2); + ASSERT(res == 0); + + res = ethr_atomic_dec(>_wait2); + ASSERT(res == 0); + + res = ethr_atomic_read(>_done, &done); + ASSERT(res == 0); + } while (!done); + return NULL; +} + + +static void +gate_test(void) +{ + long val; + int res, i; + ethr_tid tid[GT_THREADS]; + + print_line("Initializing"); + res = ethr_atomic_init(>_wait1, 0); + ASSERT_EQ(res, 0, "%d"); + res = ethr_atomic_init(>_wait2, 0); + ASSERT_EQ(res, 0, "%d"); + res = ethr_atomic_init(>_done, 0); + ASSERT_EQ(res, 0, "%d"); + res = ethr_gate_init(>_gate1); + ASSERT_EQ(res, 0, "%d"); + res = ethr_gate_init(>_gate2); + ASSERT_EQ(res, 0, "%d"); + + print_line("Creating threads"); + for (i = 0; i < GT_THREADS; i++) { + res = ethr_thr_create(&tid[i], gt_thread, (void *) i, NULL); + ASSERT_EQ(res, 0, "%d"); + } + + print_line("Waiting for threads to ready up"); + do { + res = ethr_atomic_read(>_wait1, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT(0 <= val && val <= GT_THREADS); + } while (val != GT_THREADS); + + print_line("Testing"); + + res = ethr_gate_let_through(>_gate1, 8); + ASSERT_EQ(res, 0, "%d"); + + WAIT_UNTIL_LIM((res = ethr_atomic_read(>_wait2, &val), + (res != 0 || val == 8)), + 60); + + res = ethr_atomic_read(>_wait1, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT_EQ(val, GT_THREADS - 8, "%ld"); + + res = ethr_atomic_read(>_wait2, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT_EQ(val, 8, "%ld"); + + res = ethr_gate_let_through(>_gate2, 4); + ASSERT_EQ(res, 0, "%d"); + + WAIT_UNTIL_LIM((res = ethr_atomic_read(>_wait2, &val), + (res != 0 || val == 4)), + 60); + + res = ethr_atomic_read(>_wait1, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT_EQ(val, GT_THREADS - 4, "%ld"); + + res = ethr_atomic_read(>_wait2, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT_EQ(val, 4, "%ld"); + + res = ethr_gate_let_through(>_gate1, GT_THREADS); + ASSERT_EQ(res, 0, "%d"); + + WAIT_UNTIL_LIM((res = ethr_atomic_read(>_wait2, &val), + (res != 0 || val == GT_THREADS)), + 60); + res = ethr_atomic_read(>_wait1, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT_EQ(val, 0, "%ld"); + + res = ethr_atomic_read(>_wait2, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT_EQ(val, GT_THREADS, "%ld"); + + res = ethr_gate_let_through(>_gate2, GT_THREADS); + ASSERT_EQ(res, 0, "%d"); + + WAIT_UNTIL_LIM((res = ethr_atomic_read(>_wait2, &val), + (res != 0 || val == 4)), + 60); + res = ethr_atomic_read(>_wait1, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT_EQ(val, GT_THREADS - 4, "%ld"); + + res = ethr_atomic_read(>_wait2, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT_EQ(val, 4, "%ld"); + + res = ethr_atomic_set(>_done, 1); + ASSERT_EQ(res, 0, "%d"); + + res = ethr_gate_let_through(>_gate2, GT_THREADS); + ASSERT_EQ(res, 0, "%d"); + res = ethr_gate_let_through(>_gate1, GT_THREADS - 4); + ASSERT_EQ(res, 0, "%d"); + + WAIT_UNTIL_LIM(((res = ethr_atomic_read(>_wait1, &val)) != 0 + || (val == 0 + && ((res = ethr_atomic_read(>_wait2, &val)) != 0 + || val == 0))), + 60); + + res = ethr_atomic_read(>_wait1, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT_EQ(val, 0, "%ld"); + + res = ethr_atomic_read(>_wait2, &val); + ASSERT_EQ(res, 0, "%d"); + ASSERT_EQ(val, 0, "%ld"); + + print_line("Joining threads"); + for (i = 0; i < GT_THREADS; i++) { + res = ethr_thr_join(tid[i], NULL); + ASSERT_EQ(res, 0, "%d"); + } + + res = ethr_gate_destroy(>_gate1); + ASSERT_EQ(res, 0, "%d"); + res = ethr_gate_destroy(>_gate2); + ASSERT_EQ(res, 0, "%d"); + +} + +#endif /* #ifndef ETHR_NO_THREAD_LIB */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * The dispatcher * +\* */ + +int +main(int argc, char *argv[]) +{ + if (argc < 2) + fail("To few arguments for test case"); + +#ifndef ETHR_NO_THREAD_LIB + { + char *testcase; + int res; + + send_my_pid(); + + testcase = argv[1]; + res = ethr_init(NULL); + + if (res != 0) + fail("Failed to initialize the ethread library"); + + if (strcmp(testcase, "create_join_thread") == 0) + create_join_thread_test(); + else if (strcmp(testcase, "equal_tids") == 0) + equal_tids_test(); + else if (strcmp(testcase, "mutex") == 0) + mutex_test(); + else if (strcmp(testcase, "try_lock_mutex") == 0) + try_lock_mutex_test(); + else if (strcmp(testcase, "recursive_mutex") == 0) + recursive_mutex_test(); + else if (strcmp(testcase, "time_now") == 0) + time_now_test(); + else if (strcmp(testcase, "cond_wait") == 0) + cond_wait_test(0); + else if (strcmp(testcase, "cond_timedwait") == 0) + cond_timedwait_test(); + else if (strcmp(testcase, "broadcast") == 0) + broadcast_test(); + else if (strcmp(testcase, "detached_thread") == 0) + detached_thread_test(); + else if (strcmp(testcase, "max_threads") == 0) + max_threads_test(); + else if (strcmp(testcase, "forksafety") == 0) + forksafety_test(); + else if (strcmp(testcase, "vfork") == 0) + vfork_test(argc, argv); + else if (strcmp(testcase, "tsd") == 0) + tsd_test(); + else if (strcmp(testcase, "spinlock") == 0) + spinlock_test(); + else if (strcmp(testcase, "rwspinlock") == 0) + rwspinlock_test(); + else if (strcmp(testcase, "rwmutex") == 0) + rwmutex_test(); + else if (strcmp(testcase, "atomic") == 0) + atomic_test(); + else if (strcmp(testcase, "gate") == 0) + gate_test(); + else + skip("Test case \"%s\" not implemented yet", testcase); + + succeed(NULL); + } +#else /* #ifndef ETHR_NO_THREAD_LIB */ + skip("No ethread library to test"); +#endif /* #ifndef ETHR_NO_THREAD_LIB */ + + return 0; +} diff --git a/erts/test/ignore_cores.erl b/erts/test/ignore_cores.erl new file mode 100644 index 0000000000..7ec2cac706 --- /dev/null +++ b/erts/test/ignore_cores.erl @@ -0,0 +1,158 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%%------------------------------------------------------------------- +%%% File : ignore_cores.erl +%%% Author : Rickard Green <[email protected]> +%%% Description : +%%% +%%% Created : 11 Feb 2008 by Rickard Green <[email protected]> +%%%------------------------------------------------------------------- + +-module(ignore_cores). + +-include("test_server.hrl"). + +-export([init/1, fini/1, setup/3, setup/4, restore/1, dir/1]). + +-record(ignore_cores, {org_cwd, + org_path, + org_pwd_env, + ign_dir = false, + cores_dir = false}). + +%% +%% Takes a testcase config +%% + +init(Config) -> + {ok, OrgCWD} = file:get_cwd(), + [{ignore_cores, + #ignore_cores{org_cwd = OrgCWD, + org_path = code:get_path(), + org_pwd_env = os:getenv("PWD")}} + | lists:keydelete(ignore_cores, 1, Config)]. + +fini(Config) -> + #ignore_cores{org_cwd = OrgCWD, + org_path = OrgPath, + org_pwd_env = OrgPWD} = ?config(ignore_cores, Config), + ok = file:set_cwd(OrgCWD), + true = code:set_path(OrgPath), + case OrgPWD of + false -> ok; + _ -> true = os:putenv("PWD", OrgPWD) + end, + lists:keydelete(ignore_cores, 1, Config). + +setup(Suite, Testcase, Config) -> + setup(Suite, Testcase, Config, false). + +setup(Suite, Testcase, Config, SetCwd) when is_atom(Suite), + is_atom(Testcase), + is_list(Config) -> + #ignore_cores{org_cwd = OrgCWD, + org_path = OrgPath, + org_pwd_env = OrgPWD} = ?config(ignore_cores, Config), + Path = lists:map(fun (".") -> OrgCWD; (Dir) -> Dir end, OrgPath), + true = code:set_path(Path), + PrivDir = ?config(priv_dir, Config), + IgnDir = filename:join([PrivDir, + atom_to_list(Suite) + ++ "_" + ++ atom_to_list(Testcase) + ++ "_wd"]), + ok = file:make_dir(IgnDir), + case SetCwd of + false -> + ok; + _ -> + ok = file:set_cwd(IgnDir), + OrgPWD = case os:getenv("PWD") of + false -> false; + PWD -> + os:putenv("PWD", IgnDir), + PWD + end + end, + ok = file:write_file(filename:join([IgnDir, "ignore_core_files"]), <<>>), + %% cores are dumped in /cores on MacOS X + CoresDir = case {?t:os_type(), filelib:is_dir("/cores")} of + {{unix,darwin}, true} -> + filelib:fold_files("/cores", + "^core.*$", + false, + fun (C,Cs) -> [C|Cs] end, + []); + _ -> + false + end, + lists:keyreplace(ignore_cores, + 1, + Config, + {ignore_cores, + #ignore_cores{org_cwd = OrgCWD, + org_path = OrgPath, + org_pwd_env = OrgPWD, + ign_dir = IgnDir, + cores_dir = CoresDir}}). + +restore(Config) -> + #ignore_cores{org_cwd = OrgCWD, + org_path = OrgPath, + org_pwd_env = OrgPWD, + ign_dir = IgnDir, + cores_dir = CoresDir} = ?config(ignore_cores, Config), + try + case CoresDir of + false -> + ok; + _ -> + %% Move cores dumped by these testcases in /cores + %% to cwd. + lists:foreach(fun (C) -> + case lists:member(C, CoresDir) of + true -> ok; + _ -> + Dst = filename:join( + [IgnDir, + filename:basename(C)]), + {ok, _} = file:copy(C, Dst), + file:delete(C) + end + end, + filelib:fold_files("/cores", + "^core.*$", + false, + fun (C,Cs) -> [C|Cs] end, + [])) + end + after + catch file:set_cwd(OrgCWD), + catch code:set_path(OrgPath), + case OrgPWD of + false -> ok; + _ -> catch os:putenv("PWD", OrgPWD) + end + end. + + +dir(Config) -> + #ignore_cores{ign_dir = Dir} = ?config(ignore_cores, Config), + Dir. diff --git a/erts/test/nt_SUITE.erl b/erts/test/nt_SUITE.erl new file mode 100644 index 0000000000..7ff5c908e6 --- /dev/null +++ b/erts/test/nt_SUITE.erl @@ -0,0 +1,551 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%% Purpose: Test NT specific utilities +-module(nt_SUITE). +-include("test_server.hrl"). +-include_lib("kernel/include/file.hrl"). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2,nt/1,handle_eventlog/2, + middleman/1,service_basic/1, service_env/1, user_env/1, synced/1, + service_prio/1, + logout/1, debug/1, restart/1, restart_always/1,stopaction/1, + shutdown_io/0,do_shutdown_io/0]). +-define(TEST_TIMEOUT, ?t:seconds(180)). + +-define(TEST_SERVICES, [1,2,3,4,5,6,7,8,9,10,11]). + +all(suite) -> + case os:type() of + {win32,nt} -> + [nt, service_basic, service_env, user_env, synced, service_prio, + logout, debug, + restart, restart_always, stopaction]; + _ -> [nt] %%% Just to give a little hint why they are skipped... + end. + +init_per_testcase(_Func, Config) -> + Dog = test_server:timetrap(?TEST_TIMEOUT), + [{watchdog, Dog} | Config]. + +fin_per_testcase(_Func, Config) -> + lists:foreach(fun(X) -> + catch remove_service("test_service_" ++ + integer_to_list(X)) end, + ?TEST_SERVICES), + Dog = ?config(watchdog, Config), + catch test_server:timetrap_cancel(Dog), + ok. + +erlsrv() -> + os:find_executable(erlsrv). + + +recv_prog_output(Port) -> + receive + {Port, {data, {eol,Data}}} -> + %%io:format("Got data: ~s~n", [Data]), + [ Data | recv_prog_output(Port)]; + _X -> + %%io:format("Got data: ~p~n", [_X]), + Port ! {self(), close}, + receive + _ -> + [] + end + end. + + +%%% X == parameters to erlsrv +%%% returns command output without stderr +do_command(X) -> + %%io:format("Command: ~s~n", [erlsrv() ++ " " ++ X]), + Port = open_port({spawn, erlsrv() ++ " " ++ X}, [stream, {line, 100}, eof, in]), + Res = recv_prog_output(Port), + case Res of + [] -> + failed; + _Y -> + %%io:format("~p~n",[_Y]), + ok + end. + + +create_service(Name) -> + ok = do_command("add " ++ Name). + +start_service(Name) -> + ok = do_command("start " ++ Name). + +stop_service(Name) -> + ok = do_command("stop " ++ Name). + +remove_service(Name) -> + ok = do_command("remove " ++ Name). +do_wait_for_it(_,0) -> + false; +do_wait_for_it(FullName,N) -> + case net_adm:ping(FullName) of + pong -> + true; + _ -> + receive + after 1000 -> + do_wait_for_it(FullName,N-1) + end + end. + +wait_for_node(Name) -> + FullName = make_full_name(Name), + do_wait_for_it(FullName,30). + +make_full_name(Name) -> + [_,Suffix] = string:tokens(atom_to_list(node()),"@"), + list_to_atom(Name ++ "@" ++ Suffix). + + +%%% The following tests are only run on NT: + +service_basic(doc) -> + ["Check some basic (cosmetic) service parameters"]; +service_basic(suite) -> []; +service_basic(Config) when is_list(Config) -> + ?line Name = "test_service_20", + ?line IntName = Name++"_internal", + ?line Service = [{servicename,Name}, + {args, ["-setcookie", + atom_to_list(erlang:get_cookie())]}, + {internalservicename,IntName}, + {comment,"Epic comment"}], + ?line ok = erlsrv:store_service(Service), + ?line start_service(Name), + ?line true = wait_for_node(Name), + ?line S2 = erlsrv:get_service(Name), + ?line {value,{comment,"Epic comment"}} = lists:keysearch(comment,1,S2), + ?line {value,{internalservicename,IntName}} = + lists:keysearch(internalservicename,1,S2), + ?line S3 = lists:keyreplace(comment,1,S2,{comment,"Basic comment"}), + ?line S4 = lists:keyreplace(internalservicename,1,S3, + {internalservicename,"WillNotHappen"}), + ?line ok = erlsrv:store_service(S4), + ?line S5 = erlsrv:get_service(Name), + ?line {value,{comment,"Basic comment"}} = lists:keysearch(comment,1,S5), + ?line {value,{internalservicename,IntName}} = + lists:keysearch(internalservicename,1,S5), + ?line NewName = "test_service_21", + ?line S6 = erlsrv:new_service(NewName,S5,[]), % should remove + % internalservicename + ?line ok = erlsrv:store_service(S6), + ?line S7 = erlsrv:get_service(NewName), + ?line {value,{comment,"Basic comment"}} = lists:keysearch(comment,1,S7), + ?line {value,{internalservicename,[$t,$e,$s,$t | _]}} = + lists:keysearch(internalservicename,1,S7), + ?line remove_service(Name), + ?line remove_service(NewName), + ok. + +service_env(doc) -> + ["Check that service name and executable is in the environment of the " ++ + "erlang process created by erlsrv."]; +service_env(suite) -> []; +service_env(Config) when is_list(Config) -> + ?line Name = "test_service_2", + ?line Service = [{servicename,Name}, + {args, ["-setcookie", + atom_to_list(erlang:get_cookie())]}], + ?line ok = erlsrv:store_service(Service), + ?line start_service(Name), + ?line true = wait_for_node(Name), + ?line Name = rpc:call(make_full_name(Name),os,getenv, + ["ERLSRV_SERVICE_NAME"]), + ?line "erlsrv.exe" = filename:basename( + hd( + string:tokens( + rpc:call(make_full_name(Name), + os, + getenv, + ["ERLSRV_EXECUTABLE"]), + "\""))), + ?line remove_service(Name), + ok. +user_env(doc) -> + ["Check that the user defined environment is ADDED to the service's"++ + " normal dito."]; +user_env(suite) -> []; +user_env(Config) when is_list(Config) -> + ?line Name = "test_service_3", + ?line Service = [{servicename,Name},{env,[{"HUBBA","BUBBA"}]}, + {args, ["-setcookie", + atom_to_list(erlang:get_cookie())]}], + ?line ok = erlsrv:store_service(Service), + ?line start_service(Name), + ?line true = wait_for_node(Name), + ?line true = rpc:call(make_full_name(Name),os,getenv, + ["SystemDrive"]) =/= false, + ?line "BUBBA" = rpc:call(make_full_name(Name),os,getenv,["HUBBA"]), + ?line remove_service(Name), + ok. +synced(doc) -> + ["Check that services are stopped and started syncronous and that"++ + " failed stopactions kill the erlang machine anyway."]; +synced(suite) -> []; +synced(Config) when is_list(Config) -> + ?line Name0 = "test_service_4", + ?line Service0 = [{servicename,Name0}, + {machine, "N:\\nickeNyfikenPaSjukhus"}], + ?line ok = erlsrv:store_service(Service0), + ?line true = (catch start_service(Name0)) =/= ok, + ?line remove_service(Name0), + ?line Name = "test_service_5", + ?line Service = [{servicename,Name}, + {stopaction,"erlang:info(garbage_collection)."}, + {args, ["-setcookie", + atom_to_list(erlang:get_cookie())]}], + ?line ok = erlsrv:store_service(Service), + ?line start_service(Name), + ?line true = wait_for_node(Name), + ?line T1 = calendar:datetime_to_gregorian_seconds( + calendar:universal_time()), + ?line stop_service(Name), + ?line Diff1 = calendar:datetime_to_gregorian_seconds( + calendar:universal_time()) - T1, + ?line true = Diff1 > 30, + ?line start_service(Name), + ?line true = wait_for_node(Name), + ?line T2 = calendar:datetime_to_gregorian_seconds( + calendar:universal_time()), + ?line remove_service(Name), + ?line Diff2 = calendar:datetime_to_gregorian_seconds( + calendar:universal_time()) - T2, + ?line true = Diff2 > 30, + ok. +service_prio(doc) -> + ["Check that a service with higher prio create port programs with " + "higher prio."]; +service_prio(suite) -> []; +service_prio(Config) when is_list(Config) -> + ?line Name = "test_service_6", + ?line Service = [{servicename,Name},{prio,"high"}, + {env, [{"HEART_COMMAND","echo off"}]}, + {args, ["-setcookie", + atom_to_list(erlang:get_cookie()), + "-heart"]}], + ?line ok = erlsrv:store_service(Service), + ?line {ok, OldProcs} = get_current_procs(Config), + ?line start_service(Name), + ?line {ok, NewProcs} = get_current_procs(Config), + ?line remove_service(Name), + ?line Diff = arrived_procs(OldProcs,NewProcs), + %% Not really correct, could fail if another heart is + %% started at the same time... + ?line {value, {"heart.exe",_,"high"}} = + lists:keysearch("heart.exe",1,Diff), + ok. +logout(doc) -> + ["Check that logout does not kill services"]; +logout(suite) -> []; +logout(Config) when is_list(Config) -> + ?line {comment, "Have to be run manually by registering a service with " ++ + "heart, logout and log in again and then examine that the heart " ++ + "process id is not changed."}. +debug(doc) -> + ["Check the debug options to erlsrv."]; +debug(suite) -> []; +debug(Config) when is_list(Config) -> + ?line Name0 = "test_service_7", + + %% We used to set the privdir as temporary directory, but for some + %% reason we don't seem to have write access to that directory, + %% so we'll use the directory specified in the next line. + ?line TempDir = "C:/TEMP", + ?line Service0 = [{servicename,Name0}, + {workdir,filename:nativename(TempDir)}, + {debugtype,"reuse"}, + {args, ["-setcookie", + atom_to_list(erlang:get_cookie())]}], + ?line ok = erlsrv:store_service(Service0), + ?line T1 = calendar:datetime_to_gregorian_seconds( + calendar:local_time()), + %% sleep a little + ?line receive after 2000 -> ok end, + ?line start_service(Name0), + ?line true = wait_for_node(Name0), + ?line LF = filename:join(TempDir, Name0++".debug"), + ?line {ok,Info0} = file:read_file_info(LF), + ?line T2 = calendar:datetime_to_gregorian_seconds( + Info0#file_info.mtime), + ?line true = T2 > T1, + ?line remove_service(Name0), + ?line file:delete(LF), + ?line Name1 = "test_service_8", + ?line Service1 = [{servicename,Name1}, + {workdir, filename:nativename(TempDir)}, + {debugtype,"new"}, + {args, ["-setcookie", + atom_to_list(erlang:get_cookie())]}], + ?line ok = erlsrv:store_service(Service1), + ?line T3 = calendar:datetime_to_gregorian_seconds( + calendar:local_time()), + %% sleep a little + ?line receive after 2000 -> ok end, + ?line NF = next_logfile(TempDir, Name1), + ?line start_service(Name1), + ?line true = wait_for_node(Name1), + ?line {ok,Info1} = file:read_file_info(NF), + ?line T4 = calendar:datetime_to_gregorian_seconds( + Info1#file_info.mtime), + ?line true = T4 > T3, + ?line remove_service(Name1), + ?line file:delete(NF), + ok. + +restart(doc) -> + ["Check the restart options to erlsrv"]; +restart(suite) -> []; +restart(Config) when is_list(Config) -> + ?line Name = "test_service_9", + ?line Service = [{servicename,Name}, + {workdir, filename:nativename(logdir(Config))}, + {onfail,"restart"}, + {args, ["-setcookie", + atom_to_list(erlang:get_cookie())]}], + ?line ok = erlsrv:store_service(Service), + ?line start_service(Name), + ?line true = wait_for_node(Name), + ?line receive after 20000 -> ok end, + ?line rpc:call(make_full_name(Name),erlang,halt,[]), + ?line receive after 1000 -> ok end, + ?line true = wait_for_node(Name), + ?line rpc:call(make_full_name(Name),erlang,halt,[]), + ?line receive after 1000 -> ok end, + ?line false = wait_for_node(Name), + ?line remove_service(Name), + ok. + +restart_always(doc) -> + ["Check the restart options to erlsrv"]; +restart_always(suite) -> []; +restart_always(Config) when is_list(Config) -> + ?line Name = "test_service_10", + ?line Service = [{servicename,Name}, + {workdir, filename:nativename(logdir(Config))}, + {onfail,"restart_always"}, + {args, ["-setcookie", + atom_to_list(erlang:get_cookie())]}], + ?line ok = erlsrv:store_service(Service), + ?line start_service(Name), + ?line true = wait_for_node(Name), + ?line rpc:call(make_full_name(Name),erlang,halt,[]), + ?line receive after 1000 -> ok end, + ?line true = wait_for_node(Name), + ?line rpc:call(make_full_name(Name),erlang,halt,[]), + ?line receive after 1000 -> ok end, + ?line true = wait_for_node(Name), + ?line remove_service(Name), + ok. +stopaction(doc) -> + ["Check that stopaction does not hang output while shutting down"]; +stopaction(suite) -> []; +stopaction(Config) when is_list(Config) -> + ?line Name = "test_service_11", + %% Icky, I prepend the first element in the codepath, cause + %% I "suppose" it's the one to where I am. + ?line Service = [{servicename,Name}, + {stopaction,atom_to_list(?MODULE) ++ ":shutdown_io()."}, + {args, ["-setcookie", + atom_to_list(erlang:get_cookie()), + "-pa", hd(code:get_path())]}], + ?line ok = erlsrv:store_service(Service), + ?line start_service(Name), + ?line true = wait_for_node(Name), + ?line T1 = calendar:datetime_to_gregorian_seconds( + calendar:universal_time()), + ?line stop_service(Name), + ?line Diff1 = calendar:datetime_to_gregorian_seconds( + calendar:universal_time()) - T1, + ?line true = Diff1 < 30, + ?line remove_service(Name), + ok. + + +%%% This test is run on all platforms, but just gives a comment on +%%% other platforms than NT. + +nt(doc) -> + ["Run NT specific tests."]; +nt(suite) -> + []; +nt(Config) when is_list(Config) -> + case os:type() of + {win32,nt} -> + nt_run(); + _ -> + {skipped, "This test case is intended for Win NT only."} + end. + + +nt_run() -> + ?line start_all(), + ?line create_service("test_service_1"), + ?line R = start_look_for_single("System","ErlSrv","Informational", + ".*test_service_1.*started.*"), + ?line start_service("test_service_1"), + ?line Res = look_for_single(R), + ?line io:format("Result from eventlog: ~p~n", + [Res]), + ?line remove_service("test_service_1"), + ?line stop_all(), + ok. + +start_all() -> + Pid1 = spawn_link(?MODULE,middleman,[[]]), + register(?MODULE,Pid1), + _Pid2 = nteventlog:start("log_testing", + {?MODULE,handle_eventlog,[Pid1]}). + +stop_all() -> + ?MODULE ! stop, + nteventlog:stop(). + +start_look_for_single(Cat,Fac,Sev,MessRE) -> + Ref = make_ref(), + ?MODULE ! {lookfor, {self(), Ref, {Cat,Fac,Sev,MessRE}}}, + Ref. + +look_for_single(Ref) -> + receive + {Ref,Time,Mes} -> + {Time,Mes} + after 60000 -> + timeout + end. + + +%%% Mes = {Time,Category,Facility,Severity,Message} +handle_eventlog(Mes,Pid) -> + Pid ! Mes. + +%%% Waitfor = [{Pid, Ref, {Category,Facility,Severity,MessageRE}} ...] +middleman(Waitfor) -> + receive + {Time,Category,Facility,Severity,Message} -> + io:format("Middleman got ~s...", [Message]), + case match_event({Time,Category,Facility,Severity,Message}, + Waitfor) of + {ok, {Pid,Ref,Time,Mes}, Rest} -> + io:format("matched~n"), + Pid ! {Ref,Time,Mes}, + middleman(Rest); + _ -> + io:format("no match~n"), + middleman(Waitfor) + end; + {lookfor, X} -> + io:format("Middleman told to look for ~p~n", [X]), + middleman([X|Waitfor]); + stop -> + stopped; + _ -> + middleman(Waitfor) + end. + + +%%% Matches events, not tail recursive. +match_event(_X, []) -> + nomatch; +match_event({Time,Cat,Fac,Sev,Mes},[{Pid,Ref,{Cat,Fac,Sev,MesRE}} | Tail]) -> + case regexp:match(Mes,MesRE) of + {match,_,_} -> + %%io:format("Match!~n"), + {ok,{Pid,Ref,Time,Mes},Tail}; + _Z -> + %%io:format("No match (~p)~n",[_Z]), + case match_event({Time,Cat,Fac,Sev,Mes},Tail) of + {ok,X,Rest} -> + {ok,X,[{Pid,Ref,{Cat,Fac,Sev,MesRE}} | Rest]}; + X -> + X + end + end; +match_event(X,[Y | T]) -> + %%io:format("X == ~p, Y == ~p~n",[X,Y]), + case match_event(X,T) of + {ok,Z,R} -> + {ok,Z,[Y|R]}; + XX -> + XX + end. + +arrived_procs(_,[]) -> + []; +arrived_procs(OldProcs,[{Executable, Pid, Priority} | TNewProcs]) -> + case lists:keysearch(Pid,2,OldProcs) of + {value, _} -> + arrived_procs(OldProcs, TNewProcs); + false -> + [{Executable, Pid, Priority} | arrived_procs(OldProcs, TNewProcs)] + end. + + +get_current_procs(Config) -> + ?line P = open_port({spawn,nt_info(Config) ++ " -E"}, + [{line,10000}]), + ?line L = receive + {P,{data,{eol,D}}} -> + D; + _ -> "error. " + end, + ?line P ! {self(), close}, + ?line receive + {P, closed} -> ok + end, + ?line {done,{ok,Tok,_},_} = erl_scan:tokens([],L,0), + ?line erl_parse:parse_term(Tok). + +nt_info(Config) when is_list(Config) -> + ?line filename:join(?config(data_dir, Config), "nt_info"). + + +logdir(Config) -> + ?line ?config(priv_dir, Config). + +look_for_next(Template,L,N) -> + ?line FN = Template ++ integer_to_list(N), + ?line case lists:member(FN,L) of + true -> + ?line look_for_next(Template,L,N+1); + false -> + ?line FN + end. + +next_logfile(LD, Servicename) -> + ?line {ok, Files} = file:list_dir(LD), + ?line Ftmpl = Servicename ++ ".debug.", + ?line filename:join(LD,look_for_next(Ftmpl,Files,1)). + +%%% Functions run by the service + +do_shutdown_io() -> + receive + after 2000 -> + io:format("IO in shutting down...~n"), + erlang:halt() + end. + +shutdown_io() -> + spawn(?MODULE,do_shutdown_io,[]). diff --git a/erts/test/nt_SUITE_data/Makefile.src b/erts/test/nt_SUITE_data/Makefile.src new file mode 100644 index 0000000000..b26666252e --- /dev/null +++ b/erts/test/nt_SUITE_data/Makefile.src @@ -0,0 +1,33 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +CC = @CC@ +LD = @LD@ +CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@ +CROSSLDFLAGS = @CROSSLDFLAGS@ + +PROGS = nt_info@exe@ + +all: $(PROGS) + +nt_info@exe@: nt_info@obj@ + $(LD) $(CROSSLDFLAGS) -o nt_info nt_info@obj@ @LIBS@ + +nt_info@obj@: nt_info.c + $(CC) -c -o nt_info@obj@ $(CFLAGS) nt_info.c diff --git a/erts/test/nt_SUITE_data/nt_info.c b/erts/test/nt_SUITE_data/nt_info.c new file mode 100644 index 0000000000..33cf046bb6 --- /dev/null +++ b/erts/test/nt_SUITE_data/nt_info.c @@ -0,0 +1,176 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * This is a simple command that gives some interesting + * system information on NT. + * It is run as a port program by the nt test suite to find out priorities + * of programs etc. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(VXWORKS) +int nt_info(int argc, char **argv){ + printf("Hello �lvsj�!\n"); + return 0; +} +#elif !defined(__WIN32__) +int main(int argc, char **argv){ + printf("Hello �lvsj�!\n"); + return 0; +} +#else /* Windows NT, here we go... */ + +#include <windows.h> + + +int erlang_format = 0; + +#if 0 +int last_error = 0; + +void print_last_error(void){ + char *mes; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + (last_error) ? last_error : GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &mes, + 0, + NULL ); + fprintf(stderr,"Error: %s",mes); + LocalFree(mes); +} +#endif + +typedef BOOL (WINAPI *tEnumProcesses)(DWORD *, DWORD, DWORD *); +typedef BOOL (WINAPI *tEnumProcessModules)(HANDLE, HMODULE *, DWORD, DWORD *); +typedef DWORD (WINAPI *tGetModuleBaseName)(HANDLE, HMODULE, char *, DWORD); + +static tGetModuleBaseName pGetModuleBaseName = NULL; +static tEnumProcessModules pEnumProcessModules = NULL; +static tEnumProcesses pEnumProcesses = NULL; + +static BOOL init_fpointers(void){ + HINSTANCE instance = LoadLibrary("PSAPI.DLL"); + if(instance == NULL){ + fprintf(stderr,"Failed to load PSAPI.DLL.\n"); + return FALSE; + } + if((pEnumProcesses = + (tEnumProcesses) GetProcAddress(instance,"EnumProcesses")) == + NULL){ + fprintf(stderr,"Failed to find EnumProcesses in DLL.\n"); + return FALSE; + } + if((pEnumProcessModules = + (tEnumProcessModules) GetProcAddress(instance,"EnumProcessModules")) == + NULL){ + fprintf(stderr,"Failed to find EnumProcessModules in DLL.\n"); + return FALSE; + } + if((pGetModuleBaseName = + (tGetModuleBaseName) GetProcAddress(instance,"GetModuleBaseNameA")) == + NULL){ + fprintf(stderr,"Failed to find GetModuleBaseName in DLL.\n"); + return FALSE; + } + return TRUE; +} + + +void one_line(DWORD pid){ + char pname[MAX_PATH] = "???"; + HMODULE hmod = NULL; + DWORD dummy; + DWORD priority = -1; + struct { + DWORD sym; + char *txt; + } tab[] = { + {HIGH_PRIORITY_CLASS,"high"}, + {IDLE_PRIORITY_CLASS, "idle"}, + {NORMAL_PRIORITY_CLASS,"normal"}, + {REALTIME_PRIORITY_CLASS, "realtime"} + }; + int tabsiz = sizeof(tab)/sizeof(*tab); + char *class = "???"; + int i; + + HANDLE hproc = OpenProcess(PROCESS_QUERY_INFORMATION | + PROCESS_VM_READ, + FALSE, pid ); + if(!hproc) + goto print; + if(!(*pEnumProcessModules)(hproc,&hmod,sizeof(hmod),&dummy)) + goto print; + if(!(*pGetModuleBaseName)(hproc,hmod,pname,sizeof(pname))) + goto print; + if(!(priority = GetPriorityClass(hproc))) + goto print; + for(i=0;i<tabsiz;++i) + if(tab[i].sym == priority) + class = tab[i].txt; +print: + if(erlang_format) + printf("{\"%s\", %lu, \"%s\"}%s", pname, pid, class, + (erlang_format > 1) ? "" : "\n"); + else + printf("%-32s %8lu %-9s\n", pname, pid, class); + if(hproc) + CloseHandle(hproc); + if(hmod) + CloseHandle(hmod); +} + +int do_simple_ps(void){ + DWORD procs[1024]; + DWORD num_procs; + DWORD needed; + int i; + + if(!(*pEnumProcesses)(procs,sizeof(procs),&needed)){ + fprintf(stderr,"Failed to EnumProcesses\n"); + return 1; + } + num_procs = needed / sizeof(DWORD); + if(erlang_format > 1) + printf("["); + for(i=0;i<num_procs;++i){ + one_line(procs[i]); + if(erlang_format > 1 && i < num_procs -1) + printf(", "); + } + if(erlang_format > 1) + printf("]. \n"); + return 0; +} + +int main(int argc, char **argv){ + if(argc>1 && !strcmp(argv[1],"-e")) + erlang_format = 1; + else if(argc>1 && !strcmp(argv[1],"-E")) + erlang_format = 2; + if(!init_fpointers()) + return 1; + return do_simple_ps(); +} +#endif diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl new file mode 100644 index 0000000000..c6769743dd --- /dev/null +++ b/erts/test/otp_SUITE.erl @@ -0,0 +1,297 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(otp_SUITE). + +-export([all/1,init_per_suite/1,end_per_suite/1]). +-export([undefined_functions/1,deprecated_not_in_obsolete/1, + obsolete_but_not_deprecated/1,call_to_deprecated/1, + call_to_size_1/1,strong_components/1]). + +-include("test_server.hrl"). +-import(lists, [filter/2,foldl/3,foreach/2]). + +all(suite) -> + [undefined_functions,deprecated_not_in_obsolete, + obsolete_but_not_deprecated,call_to_deprecated, + call_to_size_1,strong_components]. + +init_per_suite(Config) -> + Dog = test_server:timetrap(?t:minutes(10)), + Root = code:root_dir(), + Server = daily_xref, + ?line xref:start(Server), + ?line xref:set_default(Server, [{verbose,false}, + {warnings,false}, + {builtins,true}]), + ?line {ok,_Relname} = xref:add_release(Server, Root, {name,otp}), + + %% If we are running the tests in the source tree, the ERTS application + %% is not in the code path. We must add it explicitly. + case code:lib_dir(erts) of + {error,bad_name} -> + Erts = filename:join([code:root_dir(),"erts","preloaded","ebin"]), + ?line {ok,_} = xref:add_directory(Server, Erts, []); + _ -> + ok + end, + + ?line ?t:timetrap_cancel(Dog), + [{xref_server,Server}|Config]. + +end_per_suite(Config) -> + Server = ?config(xref_server, Config), + catch xref:stop(Server), + Config. + +undefined_functions(Config) when is_list(Config) -> + Server = ?config(xref_server, Config), + + %% Exclude calls from generated modules in the SSL application. + ExcludeFrom = "SSL-PKIX|PKIX.*|ssl_pkix_oid", + ?line UndefS = xref_base:analysis(undefined_function_calls), + ?line Q = io_lib:format("Undef = ~s," + "ExcludedFrom = ~p:_/_," + "Undef - Undef | ExcludedFrom", + [UndefS,ExcludeFrom]), + ?line {ok,Undef0} = xref:q(Server, lists:flatten(Q)), + ?line Undef1 = hipe_filter(Undef0), + ?line Undef2 = ssl_crypto_filter(Undef1), + ?line Undef3 = edoc_filter(Undef2), + ?line Undef = eunit_filter(Undef3), + ?line Undef = megaco_filter(Undef), + + case Undef of + [] -> ok; + _ -> + foreach(fun ({MFA1,MFA2}) -> + io:format("~s calls undefined ~s", + [format_mfa(MFA1),format_mfa(MFA2)]) + end, Undef), + ?line ?t:fail({length(Undef),undefined_functions_in_otp}) + + end, + + ok. + +hipe_filter(Undef) -> + case erlang:system_info(hipe_architecture) of + undefined -> + filter(fun ({_,{hipe_bifs,_,_}}) -> false; + ({_,{hipe,_,_}}) -> false; + ({_,{hipe_consttab,_,_}}) -> false; + ({_,{hipe_converters,_,_}}) -> false; + ({{code,_,_},{Mod,_,_}}) -> + not is_hipe_module(Mod); + ({{code_server,_,_},{Mod,_,_}}) -> + not is_hipe_module(Mod); + ({{compile,_,_},{Mod,_,_}}) -> + not is_hipe_module(Mod); + ({{hipe,_,_},{Mod,_,_}}) -> + %% See comment for the next clause. + not is_hipe_module(Mod); + ({{cerl_to_icode,translate_flags1,2}, + {hipe_rtl_arch,endianess,0}}) -> + false; + ({{Caller,_,_},{Callee,_,_}}) -> + %% Part of the hipe application is here + %% for the sake of Dialyzer. There are many + %% undefined calls within the hipe application. + not is_hipe_module(Caller) orelse + not is_hipe_module(Callee); + (_) -> true + end, Undef); + _Arch -> + filter(fun ({{Mod,_,_},{hipe_bifs,write_u64,2}}) -> + %% Unavailable except in 64 bit AMD. Ignore it. + not is_hipe_module(Mod); + (_) -> true + end, Undef) + end. + +is_hipe_module(Mod) -> + case atom_to_list(Mod) of + "hipe_"++_ -> true; + _ -> false + end. + +ssl_crypto_filter(Undef) -> + case {code:lib_dir(crypto),code:lib_dir(ssl)} of + {{error,bad_name},{error,bad_name}} -> + filter(fun({_,{ssl,_,_}}) -> false; + ({_,{crypto,_,_}}) -> false; + (_) -> true + end, Undef); + {_,_} -> Undef + end. + +edoc_filter(Undef) -> + %% Filter away function call that is catched. + filter(fun({{edoc_lib,uri_get_http,1},{http,request_sync,2}}) -> false; + (_) -> true + end, Undef). + +eunit_filter(Undef) -> + filter(fun({{eunit_test,wrapper_test_exported_,0}, + {eunit_test,nonexisting_function,0}}) -> false; + (_) -> true + end, Undef). + +megaco_filter(Undef) -> + %% Intentional calls to undefined functions. + filter(fun({{megaco_compact_text_encoder,encode_action_reply,3}, + {megaco_compact_text_encoder_v3,encode_action_reply,2}}) -> false; + ({{megaco_compact_text_encoder,encode_action_request,3}, + {megaco_compact_text_encoder_v3,encode_action_request,2}}) -> false; + ({{megaco_compact_text_encoder,encode_action_requests,3}, + {megaco_compact_text_encoder_v3,encode_action_requests,2}}) -> false; + ({{megaco_compact_text_encoder,encode_command_request,3}, + {megaco_compact_text_encoder_v3,encode_command_request,2}}) -> false; + ({{megaco_compact_text_encoder,encode_message,3}, + {megaco_compact_text_encoder_v3,encode_message,2}}) -> false; + ({{megaco_compact_text_encoder,encode_transaction,3}, + {megaco_compact_text_encoder_v3,encode_transaction,2}}) -> false; + ({{megaco_pretty_text_encoder,encode_action_reply,3}, + {megaco_pretty_text_encoder_v3,encode_action_reply,2}}) -> false; + ({{megaco_pretty_text_encoder,encode_action_request,3}, + {megaco_pretty_text_encoder_v3,encode_action_request,2}}) -> false; + ({{megaco_pretty_text_encoder,encode_action_requests,3}, + {megaco_pretty_text_encoder_v3,encode_action_requests,2}}) -> false; + ({{megaco_pretty_text_encoder,encode_command_request,3}, + {megaco_pretty_text_encoder_v3,encode_command_request,2}}) -> false; + ({{megaco_pretty_text_encoder,encode_message,3}, + {megaco_pretty_text_encoder_v3,encode_message,2}}) -> false; + ({{megaco_pretty_text_encoder,encode_transaction,3}, + {megaco_pretty_text_encoder_v3,encode_transaction,2}}) -> false; + (_) -> true + end, Undef). + +deprecated_not_in_obsolete(Config) when is_list(Config) -> + ?line Server = ?config(xref_server, Config), + ?line {ok,DeprecatedFunctions} = xref:q(Server, "DF"), + + ?line L = foldl(fun({M,F,A}=MFA, Acc) -> + case otp_internal:obsolete(M, F, A) of + no -> [MFA|Acc]; + _ -> Acc + end + end, [], DeprecatedFunctions), + case L of + [] -> ok; + _ -> + io:put_chars("The following functions have -deprecated() attributes,\n" + "but are not listed in otp_internal:obsolete/3.\n"), + ?line print_mfas(L), + ?line ?t:fail({length(L),deprecated_but_not_obsolete}) + end. + +obsolete_but_not_deprecated(Config) when is_list(Config) -> + ?line Server = ?config(xref_server, Config), + ?line {ok,NotDeprecated} = xref:q(Server, "X - DF"), + + ?line L = foldl(fun({M,F,A}=MFA, Acc) -> + case otp_internal:obsolete(M, F, A) of + no -> Acc; + _ -> [MFA|Acc] + end + end, [], NotDeprecated), + + case L of + [] -> ok; + _ -> + io:put_chars("The following functions are listed " + "in otp_internal:obsolete/3,\n" + "but don't have -deprecated() attributes.\n"), + ?line print_mfas(L), + ?line ?t:fail({length(L),obsolete_but_not_deprecated}) + end. + + +call_to_deprecated(Config) when is_list(Config) -> + Server = ?config(xref_server, Config), + ?line {ok,DeprecatedCalls} = xref:q(Server, "strict(E || DF)"), + foreach(fun ({MFA1,MFA2}) -> + io:format("~s calls deprecated ~s", + [format_mfa(MFA1),format_mfa(MFA2)]) + end, DeprecatedCalls), + {comment,integer_to_list(length(DeprecatedCalls))++" calls to deprecated functions"}. + +call_to_size_1(Config) when is_list(Config) -> + Server = ?config(xref_server, Config), + + %% Applications that do not call erlang:size/1: + Apps = [compiler,debugger,kernel,observer,parsetools, + runtime_tools,stdlib,tools,webtool], + + Fs = [{erlang,size,1}], + + Q1 = io_lib:format("E || ~p : Fun", [Fs]), + ?line {ok,AllCallsToSize1} = xref:q(Server, lists:flatten(Q1)), + + Q2 = io_lib:format("E | ~p : App || ~p : Fun", [Apps,Fs]), + ?line {ok,CallsToSize1} = xref:q(Server, lists:flatten(Q2)), + + case CallsToSize1 of + [] -> + ok; + _ -> + io:format("These calls cause an error:~n"), + foreach(fun ({MFA1,MFA2}) -> + io:format("~s calls soon to be deprecated ~s", + [format_mfa(MFA1),format_mfa(MFA2)]) + end, CallsToSize1) + end, + + %% Enumerate calls to erlang:size/1 from other applications than + %% the ones known not to call erlang:size/1: + case AllCallsToSize1--CallsToSize1 of + [] -> + ok; + Calls -> + io:format("~n~nThese calls do not cause an error (yet):~n"), + foreach(fun ({MFA1,MFA2}) -> + io:format("~s calls soon to be deprecated ~s", + [format_mfa(MFA1),format_mfa(MFA2)]) + end, Calls) + end, + case CallsToSize1 of + [] -> + ok; + _ -> + ?line ?t:fail({length(CallsToSize1),calls_to_size_1}) + end. + +strong_components(Config) when is_list(Config) -> + Server = ?config(xref_server, Config), + ?line {ok,Cs} = xref:q(Server, "components AE"), + io:format("\n\nStrong components:\n\n~p\n", [Cs]), + ok. + +%%% +%%% Common help functions. +%%% + + +print_mfas([MFA|T]) -> + io:format("~s\n", [format_mfa(MFA)]), + print_mfas(T); +print_mfas([]) -> ok. + +format_mfa({M,F,A}) -> + lists:flatten(io_lib:format("~s:~s/~p", [M,F,A])). diff --git a/erts/test/run_erl_SUITE.erl b/erts/test/run_erl_SUITE.erl new file mode 100644 index 0000000000..afff4120d4 --- /dev/null +++ b/erts/test/run_erl_SUITE.erl @@ -0,0 +1,270 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(run_erl_SUITE). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2, + basic/1,heavy/1,heavier/1,defunct/1]). +-export([ping_me_back/1]). + +-include("test_server.hrl"). + +init_per_testcase(_Case, Config) -> + Dog = ?t:timetrap(?t:minutes(2)), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +all(suite) -> + [basic,heavy,heavier,defunct]. + +basic(Config) when is_list(Config) -> + case os:type() of + {unix,_} -> basic_1(Config); + _ -> {skip,"Not Unix"} + end. + +basic_1(Config) -> + ?line {Node,Pipe} = do_run_erl(Config, "basic"), + + ?line ToErl = open_port({spawn,"to_erl "++Pipe}, []), + ?line erlang:port_command(ToErl, "halt().\r\n"), + + receive + {nodedown,Node} -> + ?line io:format("Down: ~p\n", [Node]) + after 10000 -> + ?line ?t:fail() + end, + + ok. + +heavy(Config) when is_list(Config) -> + case os:type() of + {unix,_} -> heavy_1(Config); + _ -> {skip,"Not Unix"} + end. + +heavy_1(Config) -> + ?line {Node,Pipe} = do_run_erl(Config, "heavy"), + + ?line ToErl = open_port({spawn,"to_erl "++Pipe}, []), + IoFormat = "io:format(\"~s\n\", [lists:duplicate(10000, 10)]).\r\n", + ?line erlang:port_command(ToErl, IoFormat), + ?line erlang:port_command(ToErl, IoFormat), + ?line erlang:port_command(ToErl, IoFormat), + ?line erlang:port_command(ToErl, "init:stop().\r\n"), + + receive + {nodedown,Node} -> + ?line io:format("Down: ~p\n", [Node]) + after 10000 -> + ?line ?t:fail() + end, + + ?line case count_new_lines(ToErl, 0) of + Nls when Nls > 30000 -> + ok; + Nls -> + ?line io:format("new_lines: ~p\n", [Nls]), + ?line ?t:fail() + end. + + +ping_me_back([Node]) when is_atom(Node) -> + net_adm:ping(Node); +ping_me_back([Node]) -> + net_adm:ping(list_to_atom(Node)). + +count_new_lines(P, N) -> + receive + {P,{data,S}} -> + count_new_lines(P, count_new_lines_1(S, N)) + after 0 -> + N + end. + +count_new_lines_1([$\n|T], N) -> + count_new_lines_1(T, N+1); +count_new_lines_1([_|T], N) -> + count_new_lines_1(T, N); +count_new_lines_1([], N) -> N. + +heavier(Config) when is_list(Config) -> + case os:type() of + {unix,_} -> heavier_1(Config); + _ -> {skip,"Not Unix"} + end. + +heavier_1(Config) -> + ?line {Node,Pipe} = do_run_erl(Config, "heavier"), + + ?line ToErl = open_port({spawn,"to_erl "++Pipe}, []), + io:format("ToErl = ~p\n", [ToErl]), + X = 1, + Y = 555, + Z = 42, + ?line random:seed(X, Y, Z), + SeedCmd = lists:flatten(io_lib:format("random:seed(~p, ~p, ~p). \r\n", + [X,Y,Z])), + ?line io:format("~p\n", [SeedCmd]), + ?line erlang:port_command(ToErl, SeedCmd), + + Iter = 1000, + MaxLen = 2048, + + Random = "f(F), "++ + "F = fun(F,0) -> ok; "++ + "(F,N) -> " ++ + "io:format(\"\\\"~s\\\"~n\","++ + "[[35|[random:uniform(25)+65 || " ++ + "_ <- lists:seq(1, "++ + "random:uniform("++ + integer_to_list(MaxLen)++ + "))]]]), "++ + "F(F,N-1) "++ + "end,"++ + "F(F,"++integer_to_list(Iter)++")."++" \r\n", + + + ?line io:format("~p\n", [Random]), + ?line erlang:port_command(ToErl, Random), + + %% Finish. + + ?line erlang:port_command(ToErl, "init:stop().\r\n"), + ?line receive_all(Iter, ToErl, MaxLen), + receive + {nodedown,Node} -> + ?line io:format("Down: ~p\n", [Node]) + after 10000 -> + ?line c:flush(), + ?line ?t:fail() + end, + + ok. + +receive_all(Iter, ToErl, MaxLen) -> + receive_all_1(Iter, [], ToErl, MaxLen). + +receive_all_1(0, _, _, _) -> ok; +receive_all_1(Iter, Line, ToErl, MaxLen) -> + NumChars = random:uniform(MaxLen), + Pattern = [random:uniform(25)+65 || _ <- lists:seq(1, NumChars)], + receive_all_2(Iter, {NumChars,Pattern}, Line, ToErl, MaxLen). + + +receive_all_2(Iter, {NumChars,Pattern}, Line0, ToErl, MaxLen) -> + case receive_match(Line0, {NumChars,Pattern}) of + {match,Line} -> + %%io:format("Match: ~p\n", [Line]), + receive_all_1(Iter-1, Line, ToErl, MaxLen); + {nomatch,Line} -> + %%io:format("NoMatch: ~p\n", [Line]), + receive + {ToErl,{data,S}} -> + %%io:format("Recv: ~p\n", [S]), + receive_all_2(Iter, {NumChars,Pattern}, Line++S, ToErl, MaxLen) + after 10000 -> + io:format("Timeout waiting for\n~p\ngot\n~p\n", + [Pattern, Line]), + ?line ?t:fail() + end + end. + + +receive_match("\"#"++T, {NumChars,Pattern}) when length(T) >= NumChars -> + Match = lists:sublist(T, NumChars), + io:format("match candidate: ~p\n", [Match]), + Match = Pattern, + {match,lists:nthtail(NumChars, T)}; +receive_match("\"#"++T, _) -> + {nomatch,"\"#"++T}; +receive_match("\""=Line, _) -> + {nomatch,Line}; +receive_match([_|T], Tpl) -> + receive_match(T, Tpl); +receive_match(Line, _) -> + {nomatch,Line}. + + +defunct(Config) when is_list(Config) -> + case os:type() of + {unix,_} -> defunct_1(Config); + _ -> {skip,"Not Unix"} + end. + +defunct_1(Config) -> + case os:find_executable(perl) of + false -> + {skip,"No perl found"}; + Perl -> + defunct_2(Config, Perl) + end. + +defunct_2(Config, Perl) -> + ?line Data = ?config(data_dir, Config), + ?line RunErlTest = filename:join(Data, "run_erl_test.pl"), + ?line Defuncter = filename:join(Data, "defuncter.pl"), + ?line Priv = ?config(priv_dir, Config), + ?line LogDir = filename:join(Priv, "defunct"), + ?line ok = file:make_dir(LogDir), + ?line Pipe = LogDir ++ "/", + ?line RunErl = os:find_executable(run_erl), + ?line Cmd = Perl ++ " " ++ RunErlTest ++ " " ++ RunErl ++ " " ++ + Defuncter ++ " " ++ Pipe ++ " " ++ LogDir, + ?line io:format("~p", [Cmd]), + ?line Res = os:cmd(Cmd), + ?line io:format("~p\n", [Res]), + "OK"++_ = Res, + ok. + +%%% Utilities. + +do_run_erl(Config, Case) -> + ?line Priv = ?config(priv_dir, Config), + ?line LogDir = filename:join(Priv, Case), + ?line ok = file:make_dir(LogDir), + ?line Pipe = LogDir ++ "/", + ?line NodeName = "run_erl_node_" ++ Case, + ?line Cmd = "run_erl "++Pipe++" "++LogDir++" \"erl -sname " ++ NodeName ++ + " -pa " ++ filename:dirname(code:which(?MODULE)) ++ + " -s " ++ ?MODULE_STRING ++ " ping_me_back " ++ + atom_to_list(node()) ++ "\"", + ?line io:format("~p\n", [Cmd]), + + ?line net_kernel:monitor_nodes(true), + ?line open_port({spawn,Cmd}, []), + ?line [_,Host] = string:tokens(atom_to_list(node()), "@"), + ?line Node = list_to_atom(NodeName++"@"++Host), + + receive + {nodeup,Node} -> + ?line io:format("Up: ~p\n", [Node]); + Other -> + ?line io:format("Unexpected: ~p\n", [Other]), + ?line ?t:fail() + after 10000 -> + ?line ?t:fail() + end, + + {Node,Pipe}. diff --git a/erts/test/run_erl_SUITE_data/defuncter.pl b/erts/test/run_erl_SUITE_data/defuncter.pl new file mode 100644 index 0000000000..261f1b8061 --- /dev/null +++ b/erts/test/run_erl_SUITE_data/defuncter.pl @@ -0,0 +1,31 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2006-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +$SIG{HUP} = 'IGNORE'; +if (fork() == 0) { + print "child\n"; + my $i = 0; + for (;;) { + sleep(5); + print $i++, "\n"; + } +} else { + print "hejsan\n"; + exit(1); +} diff --git a/erts/test/run_erl_SUITE_data/run_erl_test.pl b/erts/test/run_erl_SUITE_data/run_erl_test.pl new file mode 100644 index 0000000000..2155225e7f --- /dev/null +++ b/erts/test/run_erl_SUITE_data/run_erl_test.pl @@ -0,0 +1,41 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2006-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +my $run_erl = shift; +my $defuncter = shift; +my $pipe = shift; +my $log_dir = shift; +my $cmd = "run_erl $pipe $log_dir \"$^X $defuncter\""; +my $pid; + +if (($pid = fork()) == 0) { + #print join(" ", $run_erl, $pipe, $log_dir, "$^X $defuncter"); + exec($run_erl, $pipe, $log_dir, "$^X $defuncter"); + die "ERROR: exec failed: $!\n"; +} elsif ($pid > 0) { + sleep(1); + my $res = waitpid($pid, 0); + if ($res == $pid) { + print "OK\n"; + exit(0); + } + die "ERROR: waitpid($pid, 0) returned $res\n"; +} else { + die "ERROR: fork() failed: $!\n"; +} diff --git a/erts/test/system.dynspec b/erts/test/system.dynspec new file mode 100644 index 0000000000..799fd7611d --- /dev/null +++ b/erts/test/system.dynspec @@ -0,0 +1,18 @@ +%% -*- erlang -*- +%% You can test this file using this command. +%% file:script("system.dynspec", [{'TestCCompiler',{msc | gnuc, undefined}}]). + +case {TestCCompiler, erlang:system_info(c_compiler_used)} of + {{CC, _}, {CC, _}} -> + []; + {{CC1, _}, {CC2, _}} when CC1 == msc; CC2 == msc -> + Comment = + "OTP's static C libraries (compiled with " + ++ atom_to_list(CC2) ++ ") aren't compatible " + "with the C compiler (" ++ atom_to_list(CC1) + ++ ") used for testing.", + StaticLibSuites = [ethread_SUITE, erl_print_SUITE], + lists:map(fun (Suite) -> {skip,{Suite, Comment}} end, StaticLibSuites); + {{CC1, _}, {CC2, _}} -> + [] +end. diff --git a/erts/test/system.spec b/erts/test/system.spec new file mode 100644 index 0000000000..9bfe2dbcf8 --- /dev/null +++ b/erts/test/system.spec @@ -0,0 +1 @@ +{topcase, {dir, "../system_test"}}. diff --git a/erts/test/system.spec.vxworks b/erts/test/system.spec.vxworks new file mode 100644 index 0000000000..378adf56ac --- /dev/null +++ b/erts/test/system.spec.vxworks @@ -0,0 +1,2 @@ +{topcase, {dir, "../system_test"}}. +{skip,{erlc_SUITE, "Not on VxWorks, erlc is a HOST tool."}} diff --git a/erts/test/utils/gccifier.c b/erts/test/utils/gccifier.c new file mode 100644 index 0000000000..64de764260 --- /dev/null +++ b/erts/test/utils/gccifier.c @@ -0,0 +1,316 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ + +/* + * A compiler wrapper that translate (some) gcc command line arguments + * to the Visual C++ compiler and (of course) the gcc compiler. It also + * makes some changes in the command line arguments when debug compiling. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + + +#if !defined(__WIN32__) +#define USE_EXEC +#include <unistd.h> +#endif + + +#ifdef __WIN32__ +#define EOL "\r\n" +#else +#define EOL "\n" +#endif + +#define ARGS_INCR 20 + +static char *prog; + +typedef struct { + char **vec; + int no; + int ix; + int chars; +} args_t; + +static void +enomem(void) +{ + fprintf(stderr, "%s: Out of memory%s", prog, EOL); + exit(1); +} + +static void +save_arg(args_t *args, char *arg1, ...) +{ + char *carg; + va_list argp; + + va_start(argp, arg1); + carg = arg1; + while (carg) { + if (args->no <= args->ix) { + args->vec = (char **) (args->no + ? realloc((void *) args->vec, + (sizeof(char *) + *(args->no + ARGS_INCR + 1))) + : malloc((sizeof(char *) + *(args->no + ARGS_INCR + 1)))); + if (!args->vec) + enomem(); + args->no += ARGS_INCR; + } + args->vec[args->ix++] = carg; + args->chars += strlen(carg); + carg = va_arg(argp, char *); + } + args->vec[args->ix++] = " "; + args->chars++; + va_end(argp); +} + +static int +is_prefix(char *prfx, char **str) +{ + int i; + for (i = 0; prfx[i] && (*str)[i]; i++) { + if (prfx[i] != (*str)[i]) + return 0; + } + if (!prfx[i]) { + *str = &(*str)[i]; + return 1; + } + return 0; +} + +static void +cpy(char **dst, char *src) +{ + int i; + for (i = 0; src[i]; i++) + (*dst)[i] = src[i]; + *dst = &(*dst)[i]; +} + +typedef enum { + STDLIB_NONE, + STDLIB_MD, + STDLIB_ML, + STDLIB_MT +} stdlib_t; + +int +main(int argc, char *argv[]) +{ + int res; + int i; + size_t cmd_len; + char *cmd; + char *cmd_end; + char *cc = NULL; + args_t args = {0}; + int is_debug = 0; + int is_purify = 0; + int is_quantify = 0; + int is_purecov = 0; +#ifdef __WIN32__ + int is_shared = 0; + stdlib_t stdlib = STDLIB_NONE; + char *shared_flag = ""; + char *stdlib_flag = ""; + int have_link_args = 0; + args_t link_args = {0}; + +#define CHECK_FIRST_LINK_ARG \ + if (!have_link_args) { \ + save_arg(&link_args, "-link", NULL); \ + have_link_args = 1; \ + } +#else /* #ifdef __WIN32__ */ +#define CHECK_FIRST_LINK_ARG +#endif /* #ifdef __WIN32__ */ + + prog = argv[0]; + + + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + if (is_prefix("-CC", &arg)) { + cc = arg; + } + else if (is_prefix("-O", &arg)) { + if (!is_debug) + save_arg(&args, argv[i], NULL); + } + else if (strcmp("-DDEBUG", arg) == 0) { + save_arg(&args, arg, NULL); +#ifdef __WIN32__ + set_debug: +#endif + if (!is_debug) { + int j; + is_debug = 1; +#ifdef __WIN32__ + save_arg(&args, "-Z7", NULL); + CHECK_FIRST_LINK_ARG; + save_arg(&link_args, "-debug", NULL); + save_arg(&link_args, "-pdb:none", NULL); +#endif + for (j = 0; j < args.ix; j++) { + char *tmp_arg = args.vec[j]; + if (is_prefix("-O", &tmp_arg)) + args.vec[j] = ""; + } + } + } + else if (strcmp("-DPURIFY", arg) == 0) { + save_arg(&args, arg, NULL); + is_purify = 1; + } + else if (strcmp("-DQUANTIFY", arg) == 0) { + save_arg(&args, arg, NULL); + is_quantify = 1; + } + else if (strcmp("-DPURECOV", arg) == 0) { + save_arg(&args, arg, NULL); + is_purecov = 1; + } +#ifdef __WIN32__ + else if (strcmp("-g", arg) == 0) { + goto set_debug; + } + else if (strcmp("-MD", arg) == 0) + stdlib = STDLIB_MD; + else if (strcmp("-MDd", arg) == 0) { + stdlib = STDLIB_MD; + goto set_debug; + } + else if (strcmp("-ML", arg) == 0) + stdlib = STDLIB_ML; + else if (strcmp("-MLd", arg) == 0) { + stdlib = STDLIB_ML; + goto set_debug; + } + else if (strcmp("-MT", arg) == 0) + stdlib = STDLIB_MT; + else if (strcmp("-MTd", arg) == 0) { + stdlib = STDLIB_MT; + goto set_debug; + } + else if (strcmp("-shared", arg) == 0 || strcmp("-LD", arg) == 0) + is_shared = 1; + else if (strcmp("-LDd", arg) == 0) { + is_shared = 1; + goto set_debug; + } + else if (strcmp("-Wall", arg) == 0) { + save_arg(&args, "-W3", NULL); + } + else if (is_prefix("-L", &arg)) { + CHECK_FIRST_LINK_ARG; + save_arg(&link_args, "-libpath:", arg, NULL); + } +#endif /* #ifdef __WIN32__ */ + else if (is_prefix("-l", &arg)) { + CHECK_FIRST_LINK_ARG; + if (is_debug && strcmp("ethread", arg) == 0) + arg = "ethread.debug"; + else if (is_purify && strcmp("ethread", arg) == 0) + arg = "ethread.purify"; + else if (is_quantify && strcmp("ethread", arg) == 0) + arg = "ethread.quantify"; + else if (is_purecov && strcmp("ethread", arg) == 0) + arg = "ethread.purecov"; +#ifdef __WIN32__ + else if (strcmp("socket", arg) == 0) + arg = "ws2_32"; + save_arg(&link_args, arg, ".lib", NULL); +#else + save_arg(&args, "-l", arg, NULL); +#endif + } + else + save_arg(&args, argv[i], NULL); + } + + if (!cc || !cc[0]) { + fprintf(stderr, "%s: Missing compulsory -CC flag%s", prog, EOL); + exit(1); + } + + cmd_len = strlen(cc) + 1 + args.chars + 1; + +#ifdef __WIN32__ + if (is_shared) + shared_flag = is_debug ? "-LDd " : "-LD "; + switch (stdlib) { + case STDLIB_MD: stdlib_flag = is_debug ? "-MDd " : "-MD "; break; + case STDLIB_ML: stdlib_flag = is_debug ? "-MLd " : "-ML "; break; + case STDLIB_MT: stdlib_flag = is_debug ? "-MTd " : "-MT "; break; + case STDLIB_NONE: break; + } + + cmd_len += strlen(shared_flag) + strlen(stdlib_flag) + link_args.chars; +#endif + + cmd = (char *) malloc(sizeof(char) * cmd_len); + + if (!cmd) + enomem(); + cmd_end = cmd; + cpy(&cmd_end, cc); + cpy(&cmd_end, " "); +#ifdef __WIN32__ + cpy(&cmd_end, stdlib_flag); + cpy(&cmd_end, shared_flag); +#endif + for (i = 0; i < args.ix; i++) + cpy(&cmd_end, args.vec[i]); +#ifdef __WIN32__ + for (i = 0; i < link_args.ix; i++) + cpy(&cmd_end, link_args.vec[i]); +#endif + *cmd_end = '\0'; + + printf("==> %s%s", cmd, EOL); + fflush(stdout); + +#ifdef USE_EXEC + (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL); + perror(NULL); + res = 1; +#else + res = system(cmd); +#endif + + free((void *) args.vec); +#ifdef __WIN32__ + free((void *) link_args.vec); +#endif + free((void *) cmd); + + if (res < 0) + res = 1; + return res; +} diff --git a/erts/test/z_SUITE.erl b/erts/test/z_SUITE.erl new file mode 100644 index 0000000000..0e37af1ca2 --- /dev/null +++ b/erts/test/z_SUITE.erl @@ -0,0 +1,315 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(z_SUITE). + +%% +%% This suite expects to be run as the last suite of all suites. +%% + +%-define(line_trace, 1). + +-include_lib("kernel/include/file.hrl"). + +-record(core_search_conf, {search_dir, + extra_search_dir, + cerl, + file, + run_by_ts}). + +-define(DEFAULT_TIMEOUT, ?t:minutes(5)). + +-export([all/1, init_per_testcase/2, fin_per_testcase/2]). + +-export([search_for_core_files/1, core_files/1]). + +-include("test_server.hrl"). + + +init_per_testcase(Case, Config) -> + Dog = ?t:timetrap(?DEFAULT_TIMEOUT), + [{testcase, Case}, {watchdog, Dog} |Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +all(doc) -> []; +all(suite) -> + [core_files]. + + +core_files(doc) -> + []; +core_files(suite) -> + []; +core_files(Config) when is_list(Config) -> + case os:type() of + {win32, _} -> + {skipped, "No idea searching for core-files on windows"}; + {unix, darwin} -> + core_file_search( + core_search_conf(true, + os:getenv("OTP_DAILY_BUILD_TOP_DIR"), + "/cores")); + _ -> + core_file_search( + core_search_conf(true, + os:getenv("OTP_DAILY_BUILD_TOP_DIR"))) + end. + +search_for_core_files(Dir) -> + case os:type() of + {win32, _} -> + io:format("No idea searching for core-files on windows"); + {unix, darwin} -> + core_file_search(core_search_conf(false, Dir, "/cores")); + _ -> + core_file_search(core_search_conf(false, Dir)) + end. + +find_cerl(false) -> + case os:getenv("ERL_TOP") of + false -> false; + ETop -> + Cerl = filename:join([ETop, "bin", "cerl"]), + case filelib:is_regular(Cerl) of + true -> Cerl; + _ -> false + end + end; +find_cerl(DBTop) -> + case catch filelib:wildcard(filename:join([DBTop, + "otp_src_R*", + "bin", + "cerl"])) of + [Cerl | _ ] -> + case filelib:is_regular(Cerl) of + true -> Cerl; + _ -> false + end; + _ -> + false + end. + +is_dir(false) -> + false; +is_dir(Dir) -> + filelib:is_dir(Dir). + +core_search_conf(RunByTS, DBTop) -> + core_search_conf(RunByTS, DBTop, false). + +core_search_conf(RunByTS, DBTop, XDir) -> + SearchDir = case is_dir(DBTop) of + false -> + case code:which(test_server) of + non_existing -> + {ok, CWD} = file:get_cwd(), + CWD; + TS -> + filename:dirname(filename:dirname(TS)) + end; + true -> + DBTop + end, + XSearchDir = case is_dir(XDir) of + false -> + false; + true -> + case SearchDir == XDir of + true -> false; + _ -> XDir + end + end, + #core_search_conf{search_dir = SearchDir, + extra_search_dir = XSearchDir, + cerl = find_cerl(DBTop), + file = os:find_executable("file"), + run_by_ts = RunByTS}. + +file_inspect(#core_search_conf{file = File}, Core) -> + FRes0 = os:cmd(File ++ " " ++ Core), + FRes = case regexp:match(FRes0, Core) of + {match, S, E} -> + L = length(FRes0), + case S of + 1 -> + lists:sublist(FRes0, E+1, L+1); + _ -> + lists:sublist(FRes0, 1, S-1) + ++ + " " + ++ + lists:sublist(FRes0, E+1, L+1) + end; + _ -> FRes0 + end, + case regexp:match(FRes, "[Tt][Ee][Xx][Tt]") of + nomatch -> + case regexp:match(FRes, "[Aa][Ss][Cc][Ii][Ii]") of + nomatch -> + probably_a_core; + _ -> + not_a_core + end; + _ -> + not_a_core + end. + +mk_readable(F) -> + catch file:write_file_info(F, #file_info{mode = 8#00444}). + +ignore_core(C) -> + filelib:is_regular(filename:join([filename:dirname(C), + "ignore_core_files"])). + +core_cand(#core_search_conf{file = false}, C, Cs) -> + %% Guess that it is a core file; make it readable by anyone and save it + mk_readable(C), + [C|Cs]; +core_cand(Conf, C, Cs) -> + case file_inspect(Conf, C) of + not_a_core -> Cs; + _ -> + %% Probably a core file; make it readable by anyone and save it + mk_readable(C), + case ignore_core(C) of + true -> [{ignore, C}|Cs]; + _ -> [C|Cs] + end + end. + +time_fstr() -> + "(~w-~.2.0w-~.2.0w ~w.~.2.0w:~.2.0w)". +mod_time_list(F) -> + case catch filelib:last_modified(F) of + {{Y,Mo,D},{H,Mi,S}} -> + [Y,Mo,D,H,Mi,S]; + _ -> + [0,0,0,0,0,0] + end. + +str_strip(S) -> + string:strip(string:strip(string:strip(S), both, $\n), both, $\r). + +format_core(Conf, {ignore, Core}) -> + format_core(Conf, Core, "[ignored] "); +format_core(Conf, Core) -> + format_core(Conf, Core, ""). + +format_core(#core_search_conf{file = false}, Core, Ignore) -> + io:format(" ~s~s " ++ time_fstr() ++ "~s~n", + [Ignore, Core] ++ mod_time_list(Core)); +format_core(#core_search_conf{file = File}, Core, Ignore) -> + FRes = str_strip(os:cmd(File ++ " " ++ Core)), + case catch regexp:match(FRes, Core) of + {match, _, _} -> + io:format(" ~s~s " ++ time_fstr() ++ "~n", + [Ignore, FRes] ++ mod_time_list(Core)); + _ -> + io:format(" ~s~s: ~s " ++ time_fstr() ++ "~n", + [Ignore, Core, FRes] ++ mod_time_list(Core)) + end. + +core_file_search(#core_search_conf{search_dir = Base, + extra_search_dir = XBase, + cerl = Cerl, + run_by_ts = RunByTS} = Conf) -> + case Cerl of + false -> ok; + _ -> catch io:format("A cerl script that probably can be used for " + "inspection of emulator cores:~n ~s~n", + [Cerl]) + end, + io:format("Searching for core-files in: ~s~s~n", + [case XBase of + false -> ""; + _ -> XBase ++ " and " + end, + Base]), + Filter = fun (Core, Cores) -> + case filelib:is_regular(Core) of + true -> + case filename:basename(Core) of + "core" -> + core_cand(Conf, Core, Cores); + "core." ++ _ -> + core_cand(Conf, Core, Cores); + BName -> + case lists:suffix(".core", BName) of + true -> core_cand(Conf, Core, Cores); + _ -> Cores + end + end; + _ -> + Cores + end + end, + case case XBase of + false -> []; + _ -> filelib:fold_files(XBase, "core", true, Filter, []) + end ++ filelib:fold_files(Base, "core", true, Filter, []) of + [] -> + io:format("No core-files found.~n", []), + ok; + Cores -> + io:format("Found core files:~n",[]), + lists:foreach(fun (C) -> format_core(Conf, C) end, Cores), + {ICores, FCores} = lists:foldl(fun ({ignore, IC}, {ICs, FCs}) -> + {[" "++IC|ICs], FCs}; + (FC, {ICs, FCs}) -> + {ICs, [" "++FC|FCs]} + end, + {[],[]}, + Cores), + ICoresComment = + "Core-files marked with [ignored] were found in directories~n" + "containing an ignore_core_files file, i.e., the testcase~n" + "writer has decided that core-files dumped there should be~n" + "ignored. This testcase won't fail on ignored core-files~n" + "found.~n", + Res = lists:flatten([case FCores of + [] -> + []; + _ -> + ["Core-files found:", + lists:reverse(FCores)] + end, + case {FCores, ICores} of + {[], []} -> []; + {_, []} -> []; + {[], _} -> []; + _ -> " " + end, + case ICores of + [] -> []; + _ -> + io:format(ICoresComment, []), + ["Ignored core-files found:", + lists:reverse(ICores)] + end]), + case {RunByTS, ICores, FCores} of + {true, [], []} -> ok; + {true, _, []} -> {comment, Res}; + {true, _, _} -> ?t:fail(Res); + _ -> Res + end + end. |