From 2d785c07fbf9f533bf4627a65315a51c3efc2113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 23 Mar 2012 14:53:15 +0100 Subject: Allow the source to be set when compiling forms This commit adds a source option to compile:forms() that sets the source value returned by module_info(compile). --- lib/compiler/doc/src/compile.xml | 6 ++++++ lib/compiler/src/compile.erl | 10 ++++++---- lib/compiler/test/compile_SUITE.erl | 19 +++++++++++++++++-- 3 files changed, 29 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml index 84e9922847..60905710c9 100644 --- a/lib/compiler/doc/src/compile.xml +++ b/lib/compiler/doc/src/compile.xml @@ -294,6 +294,12 @@ module.beam: module.erl \ describing what it is doing.

+ {source,FileName} + +

Sets the value of the source, as returned by + module_info(compile).

+
+ {outdir,Dir}

Sets a new directory for the object code. The current diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index 9b505ad15c..7911f51a73 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -247,10 +247,12 @@ internal(Master, Input, Opts) -> catch error:Reason -> {error, Reason} end}. -internal({forms,Forms}, Opts) -> - {_,Ps} = passes(forms, Opts), - internal_comp(Ps, "", "", #compile{code=Forms,options=Opts, - mod_options=Opts}); +internal({forms,Forms}, Opts0) -> + {_,Ps} = passes(forms, Opts0), + Source = proplists:get_value(source, Opts0, ""), + Opts1 = proplists:delete(source, Opts0), + Compile = #compile{code=Forms,options=Opts1,mod_options=Opts1}, + internal_comp(Ps, Source, "", Compile); internal({file,File}, Opts) -> {Ext,Ps} = passes(file, Opts), Compile = #compile{options=Opts,mod_options=Opts}, diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index 512fa0e4ac..0dfa18490a 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -25,7 +25,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, app_test/1, - file_1/1, module_mismatch/1, big_file/1, outdir/1, + file_1/1, forms_2/1, module_mismatch/1, big_file/1, outdir/1, binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1, other_output/1, package_forms/1, encrypted_abstr/1, bad_record_use1/1, bad_record_use2/1, strict_record/1, @@ -42,7 +42,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> test_lib:recompile(?MODULE), - [app_test, file_1, module_mismatch, big_file, outdir, + [app_test, file_1, forms_2, module_mismatch, big_file, outdir, binary, makedep, cond_and_ifdef, listings, listings_big, other_output, package_forms, encrypted_abstr, {group, bad_record_use}, strict_record, @@ -105,6 +105,21 @@ file_1(Config) when is_list(Config) -> ?line test_server:timetrap_cancel(Dog), ok. +forms_2(Config) when is_list(Config) -> + {ok, simple, Binary} = compile:forms([{attribute,1,module,simple}], [binary, {source,"/foo/bar"}]), + code:load_binary(simple, "/foo/bar", Binary), + Info = simple:module_info(compile), + + %% Test proper source is returned. + "/foo/bar" = proplists:get_value(source, Info), + %% Ensure options is not polluted with the source. + [] = proplists:get_value(options, Info), + + %% Cleanup. + true = code:delete(simple), + false = code:purge(simple), + ok. + module_mismatch(Config) when is_list(Config) -> ?line DataDir = ?config(data_dir, Config), ?line File = filename:join(DataDir, "wrong_module_name.erl"), -- cgit v1.2.3 From b991b99f9a7cf875786c7e96970c7aff37c9a6e7 Mon Sep 17 00:00:00 2001 From: Tomer Chachamu Date: Wed, 2 May 2012 15:30:38 +0200 Subject: Fix rpc:call/5 for local calls with a finite Timeout -module(rpc_example). -export([f/0, should_return_ok/0]). should_return_ok() -> {badrpc, timeout} = rpc:call(node(), ?MODULE, f, [], 5000), ok. f() -> Ref = make_ref(), receive Ref -> ok end. --- lib/kernel/src/rpc.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl index e214ffa404..a3fc57a124 100644 --- a/lib/kernel/src/rpc.erl +++ b/lib/kernel/src/rpc.erl @@ -286,7 +286,7 @@ call(N,M,F,A) -> Reason :: term(), Timeout :: timeout(). -call(N,M,F,A,_Timeout) when node() =:= N -> %% Optimize local call +call(N,M,F,A,infinity) when node() =:= N -> %% Optimize local call local_call(M,F,A); call(N,M,F,A,infinity) -> do_call(N, {call,M,F,A,group_leader()}, infinity); -- cgit v1.2.3 From 7037b6524a3221a02bc8f28c71151c4c5cb335a2 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 8 May 2012 14:56:27 +0200 Subject: Fix close of suite when end_per_suite is skipped --- lib/common_test/doc/src/ct_hooks_chapter.xml | 2 +- lib/common_test/src/cth_surefire.erl | 42 +++++++++++++++++----------- 2 files changed, 26 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml index 1dbb841fb0..014507c886 100644 --- a/lib/common_test/doc/src/ct_hooks_chapter.xml +++ b/lib/common_test/doc/src/ct_hooks_chapter.xml @@ -453,7 +453,7 @@ terminate(State) -> Captures all test results and outputs them as surefire XML into a file. The file which is created is by default called junit_report.xml. The name can be by setting the path option for this hook. e.g. - -ct_hooks cth_surefix [{path,"/tmp/report.xml"}] + -ct_hooks cth_surefire [{path,"/tmp/report.xml"}] Surefire XML can forinstance be used by Jenkins to display test results. diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl index c42f956b3a..cb74bf0d81 100644 --- a/lib/common_test/src/cth_surefire.erl +++ b/lib/common_test/src/cth_surefire.erl @@ -49,9 +49,12 @@ init(Path, Opts) -> properties = proplists:get_value(properties,Opts,[]), timer = now() }. -pre_init_per_suite(Suite,Config,State) -> +pre_init_per_suite(Suite,Config,#state{ test_cases = [] } = State) -> {Config, init_tc(State#state{ curr_suite = Suite, curr_suite_ts = now() }, - Config) }. + Config) }; +pre_init_per_suite(Suite,Config,State) -> + %% Have to close the previous suite + pre_init_per_suite(Suite,Config,close_suite(State)). post_init_per_suite(_Suite,Config, Result, State) -> {Result, end_tc(init_per_suite,Config,Result,State)}. @@ -59,11 +62,7 @@ post_init_per_suite(_Suite,Config, Result, State) -> pre_end_per_suite(_Suite,Config,State) -> {Config, init_tc(State, Config)}. post_end_per_suite(_Suite,Config,Result,State) -> - NewState = end_tc(end_per_suite,Config,Result,State), - TCs = NewState#state.test_cases, - Suite = get_suite(NewState, TCs), - {Result, State#state{ test_cases = [], - test_suites = [Suite | State#state.test_suites]}}. + {Result, end_tc(end_per_suite,Config,Result,State)}. pre_init_per_group(Group,Config,State) -> {Config, init_tc(State#state{ curr_group = [Group|State#state.curr_group]}, @@ -118,26 +117,35 @@ end_tc(Name, _Config, _Res, State = #state{ curr_suite = Suite, name = Name, time = TimeTakes, failure = passed }| State#state.test_cases]}. - -get_suite(State, TCs) -> +close_suite(#state{ test_cases = [] } = State) -> + State; +close_suite(#state{ test_cases = TCs } = State) -> Total = length(TCs), Succ = length(lists:filter(fun(#testcase{ failure = F }) -> F == passed end,TCs)), Fail = Total - Succ, TimeTaken = timer:now_diff(now(),State#state.curr_suite_ts) / 1000000, - #testsuite{ name = atom_to_list(State#state.curr_suite), - package = State#state.package, - time = io_lib:format("~f",[TimeTaken]), - timestamp = now_to_string(State#state.curr_suite_ts), - errors = Fail, tests = Total, testcases = lists:reverse(TCs) }. - -terminate(State) -> + Suite = #testsuite{ name = atom_to_list(State#state.curr_suite), + package = State#state.package, + time = io_lib:format("~f",[TimeTaken]), + timestamp = now_to_string(State#state.curr_suite_ts), + errors = Fail, tests = Total, + testcases = lists:reverse(TCs) }, + State#state{ test_cases = [], + test_suites = [Suite | State#state.test_suites]}. + +terminate(State = #state{ test_cases = [] }) -> {ok,D} = file:open(State#state.filepath,[write]), io:format(D, "", []), io:format(D, to_xml(State), []), catch file:sync(D), - catch file:close(D). + catch file:close(D); +terminate(State) -> + %% Have to close the last suite + terminate(close_suite(State)). + + to_xml(#testcase{ group = Group, classname = CL, log = L, name = N, time = T, timestamp = TS, failure = F}) -> [" Date: Tue, 8 May 2012 12:55:05 -0400 Subject: Correct formating in exit error messages Ensure displayed sizes are not negative. --- lib/kernel/examples/uds_dist/c_src/uds_drv.c | 4 ++-- lib/runtime_tools/c_src/trace_ip_drv.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/kernel/examples/uds_dist/c_src/uds_drv.c b/lib/kernel/examples/uds_dist/c_src/uds_drv.c index 9327ab19dc..9ad6b85a0f 100644 --- a/lib/kernel/examples/uds_dist/c_src/uds_drv.c +++ b/lib/kernel/examples/uds_dist/c_src/uds_drv.c @@ -967,7 +967,7 @@ static void *my_malloc(size_t size) void *ptr; if ((ptr = driver_alloc(size)) == NULL) { - erl_exit(1,"Could not allocate %d bytes of memory",(int) size); + erl_exit(1,"Could not allocate %lu bytes of memory",(unsigned long) size); } return ptr; } @@ -977,7 +977,7 @@ static void *my_realloc(void *ptr, size_t size) void erl_exit(int, char *, ...); void *nptr; if ((nptr = driver_realloc(ptr, size)) == NULL) { - erl_exit(1,"Could not reallocate %d bytes of memory",(int) size); + erl_exit(1,"Could not reallocate %lu bytes of memory",(unsigned long) size); } return nptr; } diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c index 7f7ab8dd9d..6b77128761 100644 --- a/lib/runtime_tools/c_src/trace_ip_drv.c +++ b/lib/runtime_tools/c_src/trace_ip_drv.c @@ -590,8 +590,8 @@ static void *my_alloc(size_t size) void *ret; if ((ret = driver_alloc(size)) == NULL) { /* May or may not work... */ - fprintf(stderr, "Could not allocate %d bytes of memory in %s.", - (int) size, __FILE__); + fprintf(stderr, "Could not allocate %lu bytes of memory in %s.", + (unsigned long) size, __FILE__); exit(1); } return ret; @@ -605,8 +605,8 @@ static ErlDrvBinary *my_alloc_binary(int size) ErlDrvBinary *ret; if ((ret = driver_alloc_binary(size)) == NULL) { /* May or may not work... */ - fprintf(stderr, "Could not allocate a binary of %d bytes in %s.", - (int) size, __FILE__); + fprintf(stderr, "Could not allocate a binary of %lu bytes in %s.", + (unsigned long) size, __FILE__); exit(1); } return ret; -- cgit v1.2.3 From 8be5d558a7e9a0a949f2a38c0c531ea3e9c9f45a Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 15 May 2012 10:15:12 +0200 Subject: Allow non configlist returns from other cths --- lib/common_test/src/cth_surefire.erl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl index cb74bf0d81..7bb6d65a9a 100644 --- a/lib/common_test/src/cth_surefire.erl +++ b/lib/common_test/src/cth_surefire.erl @@ -97,6 +97,8 @@ on_tc_skip(_Tc, Res, State) -> {skipped,lists:flatten(io_lib:format("~p",[Res]))} }, State#state{ test_cases = [NewTC | tl(TCs)]}. +init_tc(State, Config) when is_list(Config) == false -> + State#state{ timer = now(), tc_log = "" }; init_tc(State, Config) -> State#state{ timer = now(), tc_log = proplists:get_value(tc_logfile, Config)}. -- cgit v1.2.3 From 24367b7d5169f9382550de38101a6bc247b70060 Mon Sep 17 00:00:00 2001 From: Artem Teslenko Date: Thu, 17 May 2012 15:19:56 +0300 Subject: Fix typo error in selected decode function --- lib/asn1/src/asn1ct_gen_ber_bin_v2.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl index 597fb0030b..3ccfca3784 100644 --- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl @@ -419,7 +419,7 @@ gen_decode_selected(Erules,Type,FuncName) -> " {Tlv,_} = ?RT_BER:decode(Bin2",asn1ct_gen:nif_parameter(),"),",nl]), emit("{ok,"), gen_decode_selected_type(Erules,Type), - emit(["};",nl," Err -> exit({error,{selctive_decode,Err}})",nl, + emit(["};",nl," Err -> exit({error,{selective_decode,Err}})",nl, " end.",nl]). gen_decode_selected_type(_Erules,TypeDef) -> -- cgit v1.2.3 From 46b41cd8d1c72b240ed34c52c71efa583fab9585 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 30 May 2012 17:59:18 +0200 Subject: Fix bug where auto skipped tcs would disappear --- lib/common_test/src/cth_surefire.erl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl index 7bb6d65a9a..d04a8b07db 100644 --- a/lib/common_test/src/cth_surefire.erl +++ b/lib/common_test/src/cth_surefire.erl @@ -89,7 +89,12 @@ on_tc_fail(_TC, Res, State) -> {fail,lists:flatten(io_lib:format("~p",[Res]))} }, State#state{ test_cases = [NewTC | tl(TCs)]}. +on_tc_skip(Tc,{Type,Reason} = Res, State) when Type == tc_auto_skip -> + do_tc_skip(Res, end_tc(Tc,[],Res,init_tc(State,[]))); on_tc_skip(_Tc, Res, State) -> + do_tc_skip(Res, State). + +do_tc_skip(Res, State) -> TCs = State#state.test_cases, TC = hd(State#state.test_cases), NewTC = TC#testcase{ @@ -101,7 +106,7 @@ init_tc(State, Config) when is_list(Config) == false -> State#state{ timer = now(), tc_log = "" }; init_tc(State, Config) -> State#state{ timer = now(), - tc_log = proplists:get_value(tc_logfile, Config)}. + tc_log = proplists:get_value(tc_logfile, Config, [])}. end_tc(Func, Config, Res, State) when is_atom(Func) -> end_tc(atom_to_list(Func), Config, Res, State); @@ -138,7 +143,7 @@ close_suite(#state{ test_cases = TCs } = State) -> test_suites = [Suite | State#state.test_suites]}. terminate(State = #state{ test_cases = [] }) -> - {ok,D} = file:open(State#state.filepath,[write]), + {ok,D} = file:open(State#state.filepath,[write,{encoding,utf8}]), io:format(D, "", []), io:format(D, to_xml(State), []), catch file:sync(D), -- cgit v1.2.3 From 06067a490863cf2e7ff3323b639176b6200c9c41 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Tue, 3 Jul 2012 14:31:22 +0200 Subject: Correct guard matching in gen_server:enter_loop/4 to match global scope in ServerName without timeout. OTP-10130 --- lib/stdlib/src/gen_server.erl | 2 +- lib/stdlib/test/gen_server_SUITE.erl | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index 59c6d240ba..04308a51b7 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -270,7 +270,7 @@ enter_loop(Mod, Options, State) -> enter_loop(Mod, Options, State, self(), infinity). enter_loop(Mod, Options, State, ServerName = {Scope, _}) - when Scope == local; Scope == local -> + when Scope == local; Scope == global -> enter_loop(Mod, Options, State, ServerName, infinity); enter_loop(Mod, Options, State, ServerName = {via, _, _}) -> diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index cdf15ba017..c38362d716 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -37,7 +37,8 @@ % spawn export -export([spec_init_local/2, spec_init_global/2, spec_init_via/2, - spec_init_default_timeout/2, spec_init_anonymous/1, + spec_init_default_timeout/2, spec_init_global_default_timeout/2, + spec_init_anonymous/1, spec_init_anonymous_default_timeout/1, spec_init_not_proc_lib/1, cast_fast_messup/0]). @@ -749,7 +750,7 @@ spec_init(suite) -> spec_init(Config) when is_list(Config) -> OldFlag = process_flag(trap_exit, true), - + ?line {ok, Pid0} = start_link(spec_init_local, [{ok, my_server}, []]), ?line ok = gen_server:call(Pid0, started_p), ?line ok = gen_server:call(Pid0, stop), @@ -819,6 +820,20 @@ spec_init(Config) when is_list(Config) -> test_server:fail(gen_server_did_not_die) end, + %% There is probably a better way to test this. + %% Before the OTP-10130 fix this failed because a timeout message + %% was generated as the spawned process crashed because a {global, Name} + %% was matched as a timeout value instead of matching on scope. + {ok, _PidHurra} = + start_link(spec_init_global_default_timeout, [{ok, hurra}, []]), + receive + _Anything -> + ct:log("OTP-10130, received: ~p~n", [_Anything]), + test_server:fail(init_of_global_default_timeout_failed) + after 5000 -> + ok + end, + ?line Pid5 = erlang:spawn_link(?MODULE, spec_init_not_proc_lib, [[]]), receive @@ -1125,6 +1140,15 @@ spec_init_default_timeout({ok, Name}, Options) -> %% Supervised init can occur here ... gen_server:enter_loop(?MODULE, Options, {}, {local, Name}). +%% OTP-10130, A bug was introduced where global scope was not matched when +%% enter_loop/4 was called (no timeout). +spec_init_global_default_timeout({ok, Name}, Options) -> + process_flag(trap_exit, true), + global:register_name(Name, self()), + proc_lib:init_ack({ok, self()}), + %% Supervised init can occur here ... + gen_server:enter_loop(?MODULE, Options, {}, {global, Name}). + spec_init_anonymous(Options) -> process_flag(trap_exit, true), proc_lib:init_ack({ok, self()}), -- cgit v1.2.3 From 30fe2fcfd7116959f97d62301b1e95b6c4635be7 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Wed, 4 Jul 2012 14:10:16 +0200 Subject: Change testcase of gen_server:enter_loop/4 with global scope to match on result of a gen_server:call/2 --- lib/stdlib/test/gen_server_SUITE.erl | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl index c38362d716..48ef7e55ed 100644 --- a/lib/stdlib/test/gen_server_SUITE.erl +++ b/lib/stdlib/test/gen_server_SUITE.erl @@ -820,20 +820,14 @@ spec_init(Config) when is_list(Config) -> test_server:fail(gen_server_did_not_die) end, - %% There is probably a better way to test this. %% Before the OTP-10130 fix this failed because a timeout message %% was generated as the spawned process crashed because a {global, Name} %% was matched as a timeout value instead of matching on scope. {ok, _PidHurra} = start_link(spec_init_global_default_timeout, [{ok, hurra}, []]), - receive - _Anything -> - ct:log("OTP-10130, received: ~p~n", [_Anything]), - test_server:fail(init_of_global_default_timeout_failed) - after 5000 -> - ok - end, - + timer:sleep(1000), + ok = gen_server:call(_PidHurra, started_p), + ?line Pid5 = erlang:spawn_link(?MODULE, spec_init_not_proc_lib, [[]]), receive -- cgit v1.2.3 From 449a093a22af91403c36ca45c620d648d9110ab5 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Thu, 1 Sep 2011 18:10:41 +0200 Subject: [erts,kernel,stdlib] fix escript/primary archive reloading If the mtime of an escript/primary archive file changes after being added to the code path, correctly reload the archive and update the cache. The existing code didn't consider that it might be a zip archive and failed: =ERROR REPORT==== 3-Aug-2011::09:21:21 === File operation error: bad_central_directory. Target: /escript_archive/module.beam. Function: get_file. Process: code_server. Thanks David Reid and Hakan Mattson. --- lib/kernel/src/code.erl | 13 ++++++++----- lib/kernel/src/code_server.erl | 4 ++-- lib/kernel/test/erl_prim_loader_SUITE.erl | 8 ++++++-- lib/stdlib/src/escript.erl | 18 ++++++++++++++++-- .../archive_script/archive_script_main2.erl | 17 ++++++++++++++++- 5 files changed, 48 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index b7fda69ce0..363072951e 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -63,7 +63,7 @@ which/1, where_is_file/1, where_is_file/2, - set_primary_archive/3, + set_primary_archive/4, clash/0]). -export_type([load_error_rsn/0, load_ret/0]). @@ -107,7 +107,7 @@ %% unstick_mod(Module) -> true %% is_sticky(Module) -> boolean() %% which(Module) -> Filename | loaded_ret_atoms() | non_existing -%% set_primary_archive((FileName, Bin, FileInfo) -> ok | {error, Reason} +%% set_primary_archive((FileName, ArchiveBin, FileInfo, ParserFun) -> ok | {error, Reason} %% clash() -> ok prints out number of clashes %%---------------------------------------------------------------------------- @@ -481,13 +481,16 @@ where_is_file(Path, File) when is_list(Path), is_list(File) -> -spec set_primary_archive(ArchiveFile :: file:filename(), ArchiveBin :: binary(), - FileInfo :: file:file_info()) + FileInfo :: file:file_info(), + ParserFun :: fun()) -> 'ok' | {'error', atom()}. -set_primary_archive(ArchiveFile0, ArchiveBin, #file_info{} = FileInfo) +set_primary_archive(ArchiveFile0, ArchiveBin, #file_info{} = FileInfo, + ParserFun) when is_list(ArchiveFile0), is_binary(ArchiveBin) -> ArchiveFile = filename:absname(ArchiveFile0), - case call({set_primary_archive, ArchiveFile, ArchiveBin, FileInfo}) of + case call({set_primary_archive, ArchiveFile, ArchiveBin, FileInfo, + ParserFun}) of {ok, []} -> ok; {ok, _Mode, Ebins} -> diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index a2db7c9790..00ad923466 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -394,8 +394,8 @@ handle_call(stop,{_From,_Tag}, S) -> handle_call({is_cached,_File}, {_From,_Tag}, S=#state{cache=no_cache}) -> {reply, no, S}; -handle_call({set_primary_archive, File, ArchiveBin, FileInfo}, {_From,_Tag}, S=#state{mode=Mode}) -> - case erl_prim_loader:set_primary_archive(File, ArchiveBin, FileInfo) of +handle_call({set_primary_archive, File, ArchiveBin, FileInfo, ParserFun}, {_From,_Tag}, S=#state{mode=Mode}) -> + case erl_prim_loader:set_primary_archive(File, ArchiveBin, FileInfo, ParserFun) of {ok, Files} -> {reply, {ok, Mode, Files}, S}; {error, _Reason} = Error -> diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl index 6f4f27d594..72239641e9 100644 --- a/lib/kernel/test/erl_prim_loader_SUITE.erl +++ b/lib/kernel/test/erl_prim_loader_SUITE.erl @@ -426,7 +426,9 @@ primary_archive(Config) when is_list(Config) -> ExpectedEbins = [Archive, DictDir ++ "/ebin", DummyDir ++ "/ebin"], io:format("ExpectedEbins: ~p\n", [ExpectedEbins]), ?line {ok, FileInfo} = prim_file:read_file_info(Archive), - ?line {ok, Ebins} = rpc:call(Node, erl_prim_loader, set_primary_archive, [Archive, ArchiveBin, FileInfo]), + ?line {ok, Ebins} = rpc:call(Node, erl_prim_loader, set_primary_archive, + [Archive, ArchiveBin, FileInfo, + fun escript:parse_file/1]), ?line ExpectedEbins = lists:sort(Ebins), % assert ?line {ok, TopFiles2} = rpc:call(Node, erl_prim_loader, list_dir, [Archive]), @@ -435,7 +437,9 @@ primary_archive(Config) when is_list(Config) -> ?line ok = test_archive(Node, Archive, DictDir, BeamName), %% Cleanup - ?line {ok, []} = rpc:call(Node, erl_prim_loader, set_primary_archive, [undefined, undefined, undefined]), + ?line {ok, []} = rpc:call(Node, erl_prim_loader, set_primary_archive, + [undefined, undefined, undefined, + fun escript:parse_file/1]), ?line stop_node(Node), ?line ok = file:delete(Archive), ok. diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl index 27e70ac4d4..498d850df3 100644 --- a/lib/stdlib/src/escript.erl +++ b/lib/stdlib/src/escript.erl @@ -22,7 +22,7 @@ -export([script_name/0, create/2, extract/2]). %% Internal API. --export([start/0, start/1]). +-export([start/0, start/1, parse_file/1]). %%----------------------------------------------------------------------- @@ -346,7 +346,8 @@ parse_and_run(File, Args, Options) -> case Source of archive -> {ok, FileInfo} = file:read_file_info(File), - case code:set_primary_archive(File, FormsOrBin, FileInfo) of + case code:set_primary_archive(File, FormsOrBin, FileInfo, + fun escript:parse_file/1) of ok when CheckOnly -> case code:load_file(Module) of {module, _} -> @@ -396,6 +397,19 @@ parse_and_run(File, Args, Options) -> %% Parse script %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Only used as callback by erl_prim_loader +parse_file(File) -> + try parse_file(File, false) of + {_Source, _Module, FormsOrBin, _HasRecs, _Mode} + when is_binary(FormsOrBin) -> + {ok, FormsOrBin}; + _ -> + {error, no_archive_bin} + catch + throw:Reason -> + {error, Reason} + end. + parse_file(File, CheckOnly) -> {HeaderSz, NextLineNo, Fd, Sections} = parse_header(File, false), diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl index de56579998..431a51b0e5 100644 --- a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl +++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl @@ -21,6 +21,8 @@ -export([main/1]). +-include_lib("kernel/include/file.hrl"). + -define(DUMMY, archive_script_dummy). -define(DICT, archive_script_dict). @@ -32,7 +34,7 @@ main(MainArgs) -> io:format("dummy:~p\n",[[E || E <- ErlArgs, element(1, E) =:= ?DUMMY]]), %% Start the applications - {error, {not_started, ?DICT}} = application:start(archive_script_dummy), + {error, {not_started, ?DICT}} = application:start(?DUMMY), ok = application:start(?DICT), ok = application:start(?DUMMY), @@ -57,4 +59,17 @@ main(MainArgs) -> ok = ?DICT:erase(Tab, Key), error = ?DICT:find(Tab, Key), ok = ?DICT:erase(Tab), + + %% Check mtime related caching bug with escript/primary archive files + Escript = escript:script_name(), + {ok, FileInfo} = file:read_file_info(Escript), + %% Modify mtime of archive file and try to reload module + FileInfo2 = FileInfo#file_info{mtime=calendar:now_to_local_time(now())}, + ok = file:write_file_info(Escript, FileInfo2), + Module = ?DICT, + {file, _} = code:is_loaded(Module), + true = code:delete(Module), + false = code:is_loaded(Module), + {module, Module} = code:ensure_loaded(Module), + ok. -- cgit v1.2.3 From 7875e98fcac4a45607a99ba08a421206a7cf1586 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Wed, 19 Oct 2011 13:27:18 +0200 Subject: escript_SUITE: remove gratuitous space --- lib/stdlib/test/escript_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl index 7ed1ee742a..3f2617fd13 100644 --- a/lib/stdlib/test/escript_SUITE.erl +++ b/lib/stdlib/test/escript_SUITE.erl @@ -356,7 +356,7 @@ beam_script(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Create an archive file containing two entire applications plus two %% alternate main modules. Generate a new escript containing the archive -%% (with .app and .beam files and ) and the escript header. +%% (with .app and .beam files and) and the escript header. archive_script(Config) when is_list(Config) -> %% Copy the orig files to priv_dir -- cgit v1.2.3 From fc241fdbfacdca72f219a601ed16fb9cb6159063 Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Mon, 9 Jul 2012 18:05:09 +0200 Subject: Add tests for problems with handling of primary archive Thanks to Tuncer Ayaz for co-authoring. --- lib/stdlib/test/escript_SUITE.erl | 126 ++++++++++++++++++++- .../archive_script_file_access.erl | 86 ++++++++++++++ 2 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl (limited to 'lib') diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl index 7ed1ee742a..253b18ecb0 100644 --- a/lib/stdlib/test/escript_SUITE.erl +++ b/lib/stdlib/test/escript_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. 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 @@ -29,6 +29,7 @@ module_script/1, beam_script/1, archive_script/1, + archive_script_file_access/1, epp/1, create_and_extract/1, foldl/1, @@ -44,7 +45,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, errors, strange_name, emulator_flags, module_script, beam_script, archive_script, epp, - create_and_extract, foldl, overflow]. + create_and_extract, foldl, overflow, + archive_script_file_access]. groups() -> []. @@ -464,6 +466,126 @@ archive_script(Config) when is_list(Config) -> ok. +%% Test the correction of OTP-10071 +%% The errors identified are +%% +%% * If primary archive was named "xxx", then a file in the same +%% directory named "xxxyyy" would be interpreted as a file named yyy +%% inside the archive. +%% +%% * erl_prim_loader did not correctly create and normalize absolute +%% paths for primary archive and files inside it, so unless given +%% with exact same path files inside the archive would not be +%% found. E.g. if escript was started as ./xxx then "xxx/file" would +%% not be found since erl_prim_loader would try to match +%% /full/path/to/xxx with /full/path/to/./xxx. Same problem with +%% ../ +%% +%% * Depending on how the primary archive was built, +%% erl_prim_loader:list_dir/1 would sometimes return an empty string +%% inside the file list. This was a virtual element representing the +%% top directory of the archive. This shall not occur. +%% +archive_script_file_access(Config) when is_list(Config) -> + %% Copy the orig files to priv_dir + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + + MainMod = "archive_script_file_access", + MainSrc = MainMod ++ ".erl", + MainBeam = MainMod ++ ".beam", + + Archive = filename:join([PrivDir, "archive_script_file_access.zip"]), + ?line {ok, _} = zip:create(Archive, ["archive_script_file_access"], + [{compress, []}, {cwd, DataDir}]), + ?line {ok, _} = zip:extract(Archive, [{cwd, PrivDir}]), + TopDir = filename:join([PrivDir, "archive_script_file_access"]), + + %% Compile the code + ?line ok = compile_files([MainSrc], TopDir, TopDir), + + %% First, create a file structure which will be included in the archive: + %% + %% dir1/ + %% dir1/subdir1/ + %% dir1/subdir1/file1 + %% + {ok, OldDir} = file:get_cwd(), + ok = file:set_cwd(TopDir), + DummyDir = "dir1", + DummySubDir = filename:join(DummyDir, "subdir1"), + RelDummyFile = filename:join(DummySubDir, "file1"), + DummyFile = filename:join(TopDir,RelDummyFile), + ok = filelib:ensure_dir(DummyFile), + ok = file:write_file(DummyFile, ["foo\nbar\nbaz"]), + + %% 1. Create zip archive by adding the dummy file and the beam + %% file as binaries to zip. + %% + %% This used to provoke the following issues when the script was run as + %% "./": + %% a. erl_prim_loader:read_file_info/1 returning 'error' + %% b. erl_prim_loader:list_dir/1 returning {ok, ["dir1", [], "file1"]} + %% leading to an infinite loop in reltool_target:spec_dir/1 + Files1 = + lists:map(fun(Filename) -> + {ok, Bin} = file:read_file(Filename), + {Filename,Bin} + end, + [RelDummyFile,MainBeam]), + {ok, {"mem", Bin1}} = zip:create("mem", Files1, [memory]), + + %% Create the escript + ScriptName1 = "archive_script_file_access1", + Script1 = filename:join([PrivDir, ScriptName1]), + Flags = "-escript main " ++ MainMod, + ok = escript:create(Script1,[shebang,{emu_args,Flags},{archive,Bin1}]), + ok = file:change_mode(Script1,8#00744), + + %% Also add a dummy file in the same directory with the same name + %% as the script except is also has an extension. This used to + %% cause erl_prim_loader to believe it was a file inside the + %% script. + ok = file:write_file(Script1 ++ ".extension", + <<"same name as script, but with extension">>), + + %% Change to script's directory and run it as "./" + ok = file:set_cwd(PrivDir), + do_run(PrivDir, "./" ++ ScriptName1, + [<<"file_access:[]\n", + "ExitCode:0">>]), + ok = file:set_cwd(TopDir), + + + %% 2. Create zip archive by letting zip read the files from the file system + %% + %% The difference compared to the archive_script_file_access1 is + %% that this will have a file element for each directory in the + %% archive - while archive_script_file_access1 will only have a + %% file element per regular file. + Files2 = [DummyDir,MainBeam], + {ok, {"mem", Bin2}} = zip:create("mem", Files2, [memory]), + + %% Create the escript + ScriptName2 = "archive_script_file_access2", + Script2 = filename:join([PrivDir, ScriptName2]), + ok = escript:create(Script2,[shebang,{emu_args,Flags},{archive,Bin2}]), + ok = file:change_mode(Script2,8#00744), + + %% Also add a dummy file in the same directory with the same name + %% as the script except is also has an extension. This used to + %% cause erl_prim_loader to believe it was a file inside the + %% script. + ok = file:write_file(Script2 ++ ".extension", + <<"same name as script, but with extension">>), + + %% Change to script's directory and run it as "./" + ok = file:set_cwd(PrivDir), + do_run(PrivDir, "./" ++ ScriptName2, + [<<"file_access:[]\n", + "ExitCode:0">>]), + ok = file:set_cwd(OldDir). + compile_app(TopDir, AppName) -> AppDir = filename:join([TopDir, AppName]), SrcDir = filename:join([AppDir, "src"]), diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl new file mode 100644 index 0000000000..226a8675db --- /dev/null +++ b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl @@ -0,0 +1,86 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. 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(archive_script_file_access). +-behaviour(escript). + +-export([main/1]). + +-include_lib("kernel/include/file.hrl"). + +main(MainArgs) -> + io:format("file_access:~p\n", [MainArgs]), + ArchiveFile = escript:script_name(), + + AbsArchiveFile = filename:absname(ArchiveFile), + RelArchiveFile = filename:basename(ArchiveFile), + DotSlashArchiveFile = "./" ++ RelArchiveFile, + + Beam = atom_to_list(?MODULE) ++ ".beam", + AbsBeam = filename:join(AbsArchiveFile,Beam), + RelBeam = filename:join(RelArchiveFile,Beam), + DotSlashBeam = filename:join(DotSlashArchiveFile,Beam), + Dir = "dir1", + AbsDir = filename:join(AbsArchiveFile,Dir), + RelDir = filename:join(RelArchiveFile,Dir), + DotSlashDir = filename:join(DotSlashArchiveFile,Dir), + + {ok,List1} = erl_prim_loader:list_dir(AbsArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(RelArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(DotSlashArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(AbsArchiveFile ++ "/"), + {ok,List1} = erl_prim_loader:list_dir(AbsArchiveFile ++ "/."), + {ok,List1} = erl_prim_loader:list_dir(filename:join([AbsDir,".."])), + {ok,List1} = erl_prim_loader:list_dir(filename:join([RelDir,".."])), + {ok,List1} = erl_prim_loader:list_dir(filename:join([DotSlashDir,".."])), + false = lists:member([],List1), + + {ok,List2} = erl_prim_loader:list_dir(AbsDir), + {ok,List2} = erl_prim_loader:list_dir(RelDir), + {ok,List2} = erl_prim_loader:list_dir(DotSlashDir), + false = lists:member([],List2), + + error = erl_prim_loader:list_dir(AbsBeam), + error = erl_prim_loader:list_dir(RelBeam), + error = erl_prim_loader:list_dir(DotSlashBeam), + + error = erl_prim_loader:get_file(AbsArchiveFile), + error = erl_prim_loader:get_file(RelArchiveFile), + error = erl_prim_loader:get_file(DotSlashArchiveFile), + error = erl_prim_loader:get_file(AbsArchiveFile ++ "/"), + error = erl_prim_loader:get_file(AbsArchiveFile ++ "/."), + {ok,Bin,AbsBeam} = erl_prim_loader:get_file(AbsBeam), + {ok,Bin,RelBeam} = erl_prim_loader:get_file(RelBeam), + {ok,Bin,DotSlashBeam} = erl_prim_loader:get_file(DotSlashBeam), + + {ok,#file_info{type=directory}=DFI} = + erl_prim_loader:read_file_info(AbsArchiveFile), + {ok,DFI} = erl_prim_loader:read_file_info(RelArchiveFile), + {ok,DFI} = erl_prim_loader:read_file_info(DotSlashArchiveFile), + {ok,DFI} = erl_prim_loader:read_file_info(AbsArchiveFile ++ "/"), + {ok,DFI} = erl_prim_loader:read_file_info(AbsArchiveFile ++ "/."), + {ok,#file_info{type=regular}=RFI} = erl_prim_loader:read_file_info(AbsBeam), + {ok,RFI} = erl_prim_loader:read_file_info(RelBeam), + {ok,RFI} = erl_prim_loader:read_file_info(DotSlashBeam), + + F = AbsArchiveFile ++ ".extension", + error = erl_prim_loader:list_dir(F), + {ok,_,_} = erl_prim_loader:get_file(F), + {ok,#file_info{type=regular}} = erl_prim_loader:read_file_info(F), + + ok. -- cgit v1.2.3 From fcf0e43a4fe06fc3f44fbff96ee42378a479d35f Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 5 Jul 2012 10:19:00 +0200 Subject: Fix a bug regarding spaces in C function prototypes Thanks to Richard O'Keefe for pointing the bug out. --- lib/erl_docgen/priv/xsl/db_html.xsl | 21 ++++++++++++++++++++- lib/erl_docgen/priv/xsl/db_man.xsl | 26 ++++++++++++++++++++++++-- lib/erl_docgen/priv/xsl/db_pdf.xsl | 20 ++++++++++++++++++-- 3 files changed, 62 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl index 7cf5465f90..4bc5abb364 100644 --- a/lib/erl_docgen/priv/xsl/db_html.xsl +++ b/lib/erl_docgen/priv/xsl/db_html.xsl @@ -1817,7 +1817,14 @@ -
+ + + + + + + +
@@ -1845,6 +1852,18 @@ + + + + + + + + + + + diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl index 5234ba6bd0..33808859c7 100644 --- a/lib/erl_docgen/priv/xsl/db_man.xsl +++ b/lib/erl_docgen/priv/xsl/db_man.xsl @@ -3,7 +3,7 @@ # # %CopyrightBegin% # - # Copyright Ericsson AB 2009-2011. All Rights Reserved. + # Copyright Ericsson AB 2009-2012. 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 @@ -758,10 +758,32 @@ .B - + + + + + + + + + + + + .br + + + + + + + + + + diff --git a/lib/erl_docgen/priv/xsl/db_pdf.xsl b/lib/erl_docgen/priv/xsl/db_pdf.xsl index bf17406d84..da96052462 100644 --- a/lib/erl_docgen/priv/xsl/db_pdf.xsl +++ b/lib/erl_docgen/priv/xsl/db_pdf.xsl @@ -3,7 +3,7 @@ # # %CopyrightBegin% # - # Copyright Ericsson AB 2009-2011. All Rights Reserved. + # Copyright Ericsson AB 2009-2012. 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 @@ -1424,7 +1424,13 @@ - + + + + + + + @@ -1432,6 +1438,16 @@ + + + + + + + + + -- cgit v1.2.3 From fe1ce64f4c0fdbc05e7dae1234eb1a878bb2cc99 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Mon, 9 Jul 2012 12:34:08 +0200 Subject: ic: add space before '*' in some function prototypes --- lib/ic/doc/src/ic_clib.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/ic/doc/src/ic_clib.xml b/lib/ic/doc/src/ic_clib.xml index b557c4b5f6..ebeaabae91 100644 --- a/lib/ic/doc/src/ic_clib.xml +++ b/lib/ic/doc/src/ic_clib.xml @@ -4,7 +4,7 @@

- 20032009 + 20032012 Ericsson AB. All Rights Reserved. @@ -41,7 +41,7 @@ - CORBA_Environment*CORBA_Environment_alloc(int inbufsz, int outbufsz) + CORBA_Environment *CORBA_Environment_alloc(int inbufsz, int outbufsz) Allocate environment data.

This function is used to allocate and initiate the @@ -79,14 +79,14 @@ - CORBA_char*CORBA_string_alloc(CORBA_unsigned_long len) + CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len) Allocate a string.

Allocates a (simple) CORBA character string of length len + 1.

- CORBA_wchar*CORBA_wstring_alloc(CORBA_unsigned_long len) + CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len) Allocate a wide string.

Allocates a CORBA wide string of length len + 1.

@@ -101,7 +101,7 @@ - CORBA_char*CORBA_exception_id(CORBA_Environment *env) + CORBA_char *CORBA_exception_id(CORBA_Environment *env) Get exception identity.

Returns the exception identity if an exception is set, otherwise @@ -109,7 +109,7 @@ - void*CORBA_exception_value(CORBA_Environment *env) + void *CORBA_exception_value(CORBA_Environment *env) Get exception value.

Returns the exception value, if an exception is set, otherwise @@ -160,7 +160,7 @@ - oe_map_t*oe_merge_maps(oe_map_t *maps, int size) + oe_map_t *oe_merge_maps(oe_map_t *maps, int size) Merge an array of server maps to one single map.

Merge an array of server maps to one single map.

-- cgit v1.2.3 From 1afa5d69e5d42e8837f7fb975671487c6301b42f Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 11 Jul 2012 12:55:46 +0200 Subject: Add ct:notify and ct:sync_notify --- lib/common_test/src/ct.erl | 27 ++++++++++++++++++++++++++- lib/common_test/src/ct_event.erl | 16 +++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index 571d99029f..6373634812 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -66,7 +66,8 @@ capture_start/0, capture_stop/0, capture_get/0, capture_get/1, fail/1, fail/2, comment/1, comment/2, make_priv_dir/0, testcases/2, userdata/2, userdata/3, - timetrap/1, get_timetrap_info/0, sleep/1]). + timetrap/1, get_timetrap_info/0, sleep/1, + notify/2, sync_notify/2]). %% New API for manipulating with config handlers -export([add_config/2, remove_config/2]). @@ -1047,3 +1048,27 @@ sleep({seconds,Ss}) -> sleep(trunc(Ss * 1000)); sleep(Time) -> test_server:adjusted_sleep(Time). + +%%%----------------------------------------------------------------- +%%% @spec notify(Name,Data) -> ok +%%% Name = atom() +%%% Data = term() +%%% +%%% @doc

Sends a asynchronous notification of type Name with +%%% Datato the common_test event manager. This can later be +%%% caught by any installed event manager.

+%%% @see //stdlib/gen_event +notify(Name,Data) -> + ct_event:notify(Name, Data). + +%%%----------------------------------------------------------------- +%%% @spec sync_notify(Name,Data) -> ok +%%% Name = atom() +%%% Data = term() +%%% +%%% @doc

Sends a synchronous notification of type Name with +%%% Datato the common_test event manager. This can later be +%%% caught by any installed event manager.

+%%% @see //stdlib/gen_event +sync_notify(Name,Data) -> + ct_event:sync_notify(Name, Data). diff --git a/lib/common_test/src/ct_event.erl b/lib/common_test/src/ct_event.erl index 3e79898ad1..998be35fda 100644 --- a/lib/common_test/src/ct_event.erl +++ b/lib/common_test/src/ct_event.erl @@ -31,7 +31,7 @@ %% API -export([start_link/0, add_handler/0, add_handler/1, stop/0]). --export([notify/1, sync_notify/1]). +-export([notify/1, notify/2, sync_notify/1,sync_notify/2]). -export([is_alive/0]). %% gen_event callbacks @@ -89,6 +89,13 @@ notify(Event) -> Result end. +%%-------------------------------------------------------------------- +%% Function: notify(Name,Data) -> ok +%% Description: Asynchronous notification to event manager. +%%-------------------------------------------------------------------- +notify(Name, Data) -> + notify(#event{ name = Name, data = Data}). + %%-------------------------------------------------------------------- %% Function: sync_notify(Event) -> ok %% Description: Synchronous notification to event manager. @@ -101,6 +108,13 @@ sync_notify(Event) -> Result end. +%%-------------------------------------------------------------------- +%% Function: sync_notify(Name,Data) -> ok +%% Description: Synchronous notification to event manager. +%%-------------------------------------------------------------------- +sync_notify(Name,Data) -> + sync_notify(#event{ name = Name, data = Data}). + %%-------------------------------------------------------------------- %% Function: is_alive() -> true | false %% Description: Check if Event Manager is alive. -- cgit v1.2.3 From 0da1a7be25ec7ae3a185dd69d3e3d6e1f5401dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 24 Jul 2012 17:03:01 +0200 Subject: os_mon: Elucidate port program error messages Try to avoid confusion of the message 'Erlang has closed' by clarifying that the message is sent from os_mon port programs. --- lib/os_mon/c_src/cpu_sup.c | 14 ++++++++++++-- lib/os_mon/c_src/memsup.c | 25 +++++++++++-------------- lib/os_mon/c_src/win32sysinfo.c | 30 ++++++++++++++---------------- 3 files changed, 37 insertions(+), 32 deletions(-) (limited to 'lib') diff --git a/lib/os_mon/c_src/cpu_sup.c b/lib/os_mon/c_src/cpu_sup.c index 9c5f9a6aa5..a0432b3093 100644 --- a/lib/os_mon/c_src/cpu_sup.c +++ b/lib/os_mon/c_src/cpu_sup.c @@ -458,8 +458,18 @@ static void error(char* err_msg) { * if we get error here we have trouble, * silence unnecessary warnings */ - if(write(FD_ERR, err_msg, strlen(err_msg))); - if(write(FD_ERR, "\n", 1)); + char buffer[256] = "[os_mon] cpu supervisor port (cpu_sup): "; + int i = strlen(buffer), j = 0; + int n = strlen(err_msg); + + while(i < 253 && j < n) { + buffer[i++] = err_msg[j++]; + } + buffer[i++] = '\r'; + buffer[i++] = '\n'; + + /* try to use one write only */ + if(write(FD_ERR, buffer, i)); exit(-1); } diff --git a/lib/os_mon/c_src/memsup.c b/lib/os_mon/c_src/memsup.c index 078f20ff98..593a066f98 100644 --- a/lib/os_mon/c_src/memsup.c +++ b/lib/os_mon/c_src/memsup.c @@ -493,7 +493,7 @@ get_basic_mem(unsigned long *tot, unsigned long *used, unsigned long *pagesize){ #elif defined(__linux__) && !defined(_SC_AVPHYS_PAGES) memory_ext me; if (get_mem_procfs(&me) < 0) { - print_error("ProcFS read error."); + print_error("ProcFS read error"); exit(1); } *tot = me.total; @@ -582,7 +582,7 @@ message_loop(int erlin_fd) * Wait for command from Erlang */ if ((res = read(erlin_fd, &cmdLen, 1)) < 0) { - print_error("Error reading from Erlang."); + print_error("Error reading from Erlang"); return; } @@ -603,19 +603,19 @@ message_loop(int erlin_fd) break; case 0: - print_error("Erlang has closed."); + print_error("Erlang has closed"); return; default: - print_error("Error reading from Erlang."); + print_error("Error reading from Erlang"); return; } /* switch() */ } else { /* cmdLen != 1 */ - print_error("Invalid command length (%d) received.", cmdLen); + print_error("Invalid command length (%d) received", cmdLen); return; } } else { /* Erlang end closed */ - print_error("Erlang has closed."); + print_error("Erlang has closed"); return; } } @@ -641,15 +641,12 @@ static void print_error(const char *format,...) { va_list args; + char buffer[256]; va_start(args, format); - fprintf(stderr, "%s: ", program_name); - vfprintf(stderr, format, args); + vsnprintf(buffer, 256, format, args); va_end(args); - fprintf(stderr, " \n"); + /* try to use one write only */ + fprintf(stderr, "[os_mon] memory supervisor port (memsup): %s\r\n", buffer); + fflush(stderr); } - - - - - diff --git a/lib/os_mon/c_src/win32sysinfo.c b/lib/os_mon/c_src/win32sysinfo.c index 2a155aae87..9d4587393f 100644 --- a/lib/os_mon/c_src/win32sysinfo.c +++ b/lib/os_mon/c_src/win32sysinfo.c @@ -89,6 +89,7 @@ typedef BOOL (WINAPI *tfpGetDiskFreeSpaceEx)(LPCTSTR, PULARGE_INTEGER,PULARGE_IN static tfpGetDiskFreeSpaceEx fpGetDiskFreeSpaceEx; +static void print_error(const char *msg); static void return_answer(char* value) { @@ -98,7 +99,7 @@ return_answer(char* value) res = write(1,(char*) &bytes,1); if (res != 1) { - fprintf(stderr,"win32sysinfo:Error writing to pipe"); + print_error("Error writing to pipe"); exit(1); } @@ -107,9 +108,8 @@ return_answer(char* value) while (left > 0) { res = write(1, value+bytes-left, left); - if (res <= 0) - { - fprintf(stderr,"win32sysinfo:Error writing to pipe"); + if (res <= 0) { + print_error("Error writing to pipe"); exit(1); } left -= res; @@ -248,7 +248,6 @@ message_loop() char cmd[512]; int res; - fprintf(stderr,"in message_loop\n"); /* Startup ACK. */ return_answer(OK); while (1) @@ -257,12 +256,12 @@ message_loop() * Wait for command from Erlang */ if ((res = read(0, &cmdLen, 1)) < 0) { - fprintf(stderr,"win32sysinfo:Error reading from Erlang."); + print_error("Error reading from Erlang"); return; } if (res != 1){ /* Exactly one byte read ? */ - fprintf(stderr,"win32sysinfo:Erlang has closed."); + print_error("Erlang has closed"); return; } if ((res = read(0, &cmd, cmdLen)) == cmdLen){ @@ -291,11 +290,11 @@ message_loop() return_answer("xEND"); } else if (res == 0) { - fprintf(stderr,"win32sysinfo:Erlang has closed."); + print_error("Erlang has closed"); return; } else { - fprintf(stderr,"win32sysinfo:Error reading from Erlang."); + print_error("Error reading from Erlang"); return; } } @@ -309,10 +308,9 @@ int main(int argc, char ** argv){ message_loop(); return 0; } - - - - - - - +static void +print_error(const char *msg) { + /* try to use one write only */ + fprintf(stderr, "[os_mon] win32 supervisor port (win32sysinfo): %s\r\n", msg); + fflush(stderr); +} -- cgit v1.2.3 From 1242f6da608ce0222bfb2115228e8f09b444ba23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 24 Jul 2012 19:04:27 +0200 Subject: doc: Fix faulty tag in inet bit8 documentation --- lib/kernel/doc/src/inet.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index 096ddfd847..b727960d96 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -452,8 +452,8 @@ fe80::204:acff:fe17:bf38 Scans every byte in received data-packets and checks if the 8 bit is set in any of them. Information is retrieved with inet:getopts/2. - Deprecated! Will be removed in Erlang/OTP R16.

+

Note that the bit8 option is deprecated and will be removed in Erlang/OTP R16.

{broadcast, Boolean}(UDP sockets) -- cgit v1.2.3 From 85a5f71087785c4eada6a4101ffeef6a15f5c409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 2 Aug 2012 10:07:58 +0200 Subject: compile_SUITE: Correct the forms_2 test case to work on Windows Correct the forms_2 test case introduced in 2d785c07fbf9f533bf so that it will work on Windows. As originally written, the test case assumed that filename:absname("/foo/bar") would return "/foo/bar", which is not true on Windows (typically, the result will be "c:/foo/bar"). While at it, clean up indentation, the overlong line, and comments. --- lib/compiler/test/compile_SUITE.erl | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index 0dfa18490a..9dbfb5883b 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -106,19 +106,23 @@ file_1(Config) when is_list(Config) -> ok. forms_2(Config) when is_list(Config) -> - {ok, simple, Binary} = compile:forms([{attribute,1,module,simple}], [binary, {source,"/foo/bar"}]), - code:load_binary(simple, "/foo/bar", Binary), - Info = simple:module_info(compile), - - %% Test proper source is returned. - "/foo/bar" = proplists:get_value(source, Info), - %% Ensure options is not polluted with the source. - [] = proplists:get_value(options, Info), - - %% Cleanup. - true = code:delete(simple), - false = code:purge(simple), - ok. + Src = "/foo/bar", + AbsSrc = filename:absname(Src), + {ok,simple,Binary} = compile:forms([{attribute,1,module,simple}], + [binary,{source,Src}]), + code:load_binary(simple, Src, Binary), + Info = simple:module_info(compile), + + %% Test that the proper source is returned. + AbsSrc = proplists:get_value(source, Info), + + %% Ensure that the options are not polluted with 'source'. + [] = proplists:get_value(options, Info), + + %% Cleanup. + true = code:delete(simple), + false = code:purge(simple), + ok. module_mismatch(Config) when is_list(Config) -> ?line DataDir = ?config(data_dir, Config), -- cgit v1.2.3 From c595aff5bd41a5d392145212606c87e40779e142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 6 Aug 2012 11:54:04 +0200 Subject: compiler: Eliminate EXIT messages from the temporary compiler process If a process trap exits, calling the compiler would leave an EXIT message in the message queue of the calling process because the compiler spawns a temporary work process. Eliminate the EXIT process by monitoring the temporary process instead of linking to it. Reported-by: Jeremy Heater --- lib/compiler/src/compile.erl | 18 ++++++++++-------- lib/compiler/test/compile_SUITE.erl | 12 ++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index 7911f51a73..7365706b94 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -146,10 +146,17 @@ env_default_opts() -> do_compile(Input, Opts0) -> Opts = expand_opts(Opts0), - Self = self(), - Serv = spawn_link(fun() -> internal(Self, Input, Opts) end), + {Pid,Ref} = + spawn_monitor(fun() -> + exit(try + internal(Input, Opts) + catch + error:Reason -> + {error,Reason} + end) + end), receive - {Serv,Rep} -> Rep + {'DOWN',Ref,process,Pid,Rep} -> Rep end. expand_opts(Opts0) -> @@ -242,11 +249,6 @@ format_error({module_name,Mod,Filename}) -> errors=[], warnings=[]}). -internal(Master, Input, Opts) -> - Master ! {self(), try internal(Input, Opts) - catch error:Reason -> {error, Reason} - end}. - internal({forms,Forms}, Opts0) -> {_,Ps} = passes(forms, Opts0), Source = proplists:get_value(source, Opts0, ""), diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index 9dbfb5883b..da53a6ba9c 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -76,6 +76,9 @@ app_test(Config) when is_list(Config) -> file_1(Config) when is_list(Config) -> ?line Dog = test_server:timetrap(test_server:minutes(5)), + + process_flag(trap_exit, true), + ?line {Simple, Target} = files(Config, "file_1"), ?line {ok, Cwd} = file:get_cwd(), ?line ok = file:set_cwd(filename:dirname(Target)), @@ -102,6 +105,15 @@ file_1(Config) when is_list(Config) -> %% Cleanup. ?line ok = file:delete(Target), ?line ok = file:del_dir(filename:dirname(Target)), + + %% There should not be any messages in the messages. + receive + Any -> + ?t:fail({unexpected,Any}) + after 10 -> + ok + end, + ?line test_server:timetrap_cancel(Dog), ok. -- cgit v1.2.3 From af23ae42edcd582ec72e6c97540f82ea03bb36fe Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Tue, 7 Aug 2012 17:23:26 +0200 Subject: Fix flattening of paths in erl_prim_loader When correcting OTP-10071, a new error was introduced in erl_prim_loader. In order to improve ability to detect if a file was inside the primary archive, all paths were flattened - i.e. "." and ".." were removed. This implementation had some faults, and it did not take symlinks into account. This has been corrected. --- lib/stdlib/test/escript_SUITE.erl | 69 ++++++++++++++-------- .../archive_script_file_access.erl | 29 +++++++-- 2 files changed, 69 insertions(+), 29 deletions(-) (limited to 'lib') diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl index 7b03fdafe3..e76d0972f3 100644 --- a/lib/stdlib/test/escript_SUITE.erl +++ b/lib/stdlib/test/escript_SUITE.erl @@ -469,22 +469,23 @@ archive_script(Config) when is_list(Config) -> %% Test the correction of OTP-10071 %% The errors identified are %% -%% * If primary archive was named "xxx", then a file in the same -%% directory named "xxxyyy" would be interpreted as a file named yyy -%% inside the archive. +%% a) If primary archive was named "xxx", then a file in the same +%% directory named "xxxyyy" would be interpreted as a file named yyy +%% inside the archive. %% -%% * erl_prim_loader did not correctly create and normalize absolute -%% paths for primary archive and files inside it, so unless given -%% with exact same path files inside the archive would not be -%% found. E.g. if escript was started as ./xxx then "xxx/file" would -%% not be found since erl_prim_loader would try to match -%% /full/path/to/xxx with /full/path/to/./xxx. Same problem with -%% ../ +%% b) erl_prim_loader did not correctly create and normalize absolute +%% paths for primary archive and files inside it, so unless given +%% with exact same path files inside the archive would not be +%% found. E.g. if escript was started as ./xxx then "xxx/file" +%% would not be found since erl_prim_loader would try to match +%% /full/path/to/xxx with /full/path/to/./xxx. Same problem with +%% ../. Also, the use of symlinks in the path to the archive would +%% cause problems. %% -%% * Depending on how the primary archive was built, -%% erl_prim_loader:list_dir/1 would sometimes return an empty string -%% inside the file list. This was a virtual element representing the -%% top directory of the archive. This shall not occur. +%% c) Depending on how the primary archive was built, +%% erl_prim_loader:list_dir/1 would sometimes return an empty string +%% inside the file list. This was a virtual element representing the +%% top directory of the archive. This shall not occur. %% archive_script_file_access(Config) when is_list(Config) -> %% Copy the orig files to priv_dir @@ -542,18 +543,22 @@ archive_script_file_access(Config) when is_list(Config) -> ok = escript:create(Script1,[shebang,{emu_args,Flags},{archive,Bin1}]), ok = file:change_mode(Script1,8#00744), + %% If supported, create a symlink to the script. This is used to + %% test error b) described above this test case. + SymlinkName1 = "symlink_to_"++ScriptName1, + Symlink1 = filename:join([PrivDir, SymlinkName1]), + file:make_symlink(ScriptName1,Symlink1), % will fail if not supported + %% Also add a dummy file in the same directory with the same name %% as the script except is also has an extension. This used to - %% cause erl_prim_loader to believe it was a file inside the - %% script. + %% test error a) described above this test case. ok = file:write_file(Script1 ++ ".extension", <<"same name as script, but with extension">>), %% Change to script's directory and run it as "./" ok = file:set_cwd(PrivDir), - do_run(PrivDir, "./" ++ ScriptName1, - [<<"file_access:[]\n", - "ExitCode:0">>]), + do_run(PrivDir, "./" ++ ScriptName1 ++ " " ++ ScriptName1, + [<<"ExitCode:0">>]), ok = file:set_cwd(TopDir), @@ -574,18 +579,34 @@ archive_script_file_access(Config) when is_list(Config) -> %% Also add a dummy file in the same directory with the same name %% as the script except is also has an extension. This used to - %% cause erl_prim_loader to believe it was a file inside the - %% script. + %% test error a) described above this test case. ok = file:write_file(Script2 ++ ".extension", <<"same name as script, but with extension">>), + %% If supported, create a symlink to the script. This is used to + %% test error b) described above this test case. + SymlinkName2 = "symlink_to_"++ScriptName2, + Symlink2 = filename:join([PrivDir, SymlinkName2]), + file:make_symlink(ScriptName2,Symlink2), % will fail if not supported + %% Change to script's directory and run it as "./" ok = file:set_cwd(PrivDir), - do_run(PrivDir, "./" ++ ScriptName2, - [<<"file_access:[]\n", - "ExitCode:0">>]), + do_run(PrivDir, "./" ++ ScriptName2 ++ " " ++ ScriptName2, + [<<"ExitCode:0">>]), + + %% 3. If symlinks are supported, run one of the scripts via a symlink. + %% + %% This is in order to test error b) described above this test case. + case file:read_link(Symlink2) of + {ok,_} -> + do_run(PrivDir, "./" ++ SymlinkName2 ++ " " ++ ScriptName2, + [<<"ExitCode:0">>]); + _ -> % not supported + ok + end, ok = file:set_cwd(OldDir). + compile_app(TopDir, AppName) -> AppDir = filename:join([TopDir, AppName]), SrcDir = filename:join([AppDir, "src"]), diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl index 226a8675db..b03c8ba70d 100644 --- a/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl +++ b/lib/stdlib/test/escript_SUITE_data/archive_script_file_access/archive_script_file_access.erl @@ -23,12 +23,9 @@ -include_lib("kernel/include/file.hrl"). -main(MainArgs) -> - io:format("file_access:~p\n", [MainArgs]), - ArchiveFile = escript:script_name(), +main([RelArchiveFile]) -> - AbsArchiveFile = filename:absname(ArchiveFile), - RelArchiveFile = filename:basename(ArchiveFile), + AbsArchiveFile = filename:absname(RelArchiveFile), DotSlashArchiveFile = "./" ++ RelArchiveFile, Beam = atom_to_list(?MODULE) ++ ".beam", @@ -39,6 +36,10 @@ main(MainArgs) -> AbsDir = filename:join(AbsArchiveFile,Dir), RelDir = filename:join(RelArchiveFile,Dir), DotSlashDir = filename:join(DotSlashArchiveFile,Dir), + SubDir = "subdir1", + AbsSubDir = filename:join(AbsDir,SubDir), + RelSubDir = filename:join(RelDir,SubDir), + DotSlashSubDir = filename:join(DotSlashDir,SubDir), {ok,List1} = erl_prim_loader:list_dir(AbsArchiveFile), {ok,List1} = erl_prim_loader:list_dir(RelArchiveFile), @@ -48,8 +49,26 @@ main(MainArgs) -> {ok,List1} = erl_prim_loader:list_dir(filename:join([AbsDir,".."])), {ok,List1} = erl_prim_loader:list_dir(filename:join([RelDir,".."])), {ok,List1} = erl_prim_loader:list_dir(filename:join([DotSlashDir,".."])), + {ok,List1} = erl_prim_loader:list_dir(filename:join([AbsSubDir,"..",".."])), + {ok,List1} = erl_prim_loader:list_dir(filename:join([RelSubDir,"..",".."])), + {ok,List1} = erl_prim_loader:list_dir(filename:join([DotSlashSubDir,"..",".."])), false = lists:member([],List1), + %% If symlinks are supported on this platform... + RelSymlinkArchiveFile = "symlink_to_" ++ RelArchiveFile, + case file:read_link(RelSymlinkArchiveFile) of + {ok,_} -> + DotSlashSymlinkArchiveFile = "./" ++ RelSymlinkArchiveFile, + AbsSymlinkArchiveFile=filename:join(filename:dirname(AbsArchiveFile), + RelSymlinkArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(AbsSymlinkArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(RelSymlinkArchiveFile), + {ok,List1} = erl_prim_loader:list_dir(DotSlashSymlinkArchiveFile); + _ -> % not supported + ok + end, + + {ok,List2} = erl_prim_loader:list_dir(AbsDir), {ok,List2} = erl_prim_loader:list_dir(RelDir), {ok,List2} = erl_prim_loader:list_dir(DotSlashDir), -- cgit v1.2.3 From 4968de7826816b4a9eac94fd8776fe4b7454ca14 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Mon, 4 Jun 2012 20:53:15 +0200 Subject: added special case for file names under Windows, thanks to Beads Land-Trujillo --- lib/edoc/src/edoc_lib.erl | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/edoc/src/edoc_lib.erl b/lib/edoc/src/edoc_lib.erl index 7fd8358add..90fb8a679c 100644 --- a/lib/edoc/src/edoc_lib.erl +++ b/lib/edoc/src/edoc_lib.erl @@ -469,6 +469,10 @@ uri_get("ftp:" ++ Path) -> uri_get("//" ++ Path) -> Msg = io_lib:format("cannot access network-path: '//~s'.", [Path]), {error, Msg}; +uri_get([C, $:, $/ | _]=Path) when C >= $A, C =< $Z; C >= $a, C =< $z -> + uri_get_file(Path); % special case for Windows +uri_get([C, $:, $\ | _]=Path) when C >= $A, C =< $Z; C >= $a, C =< $z -> + uri_get_file(Path); % special case for Windows uri_get(URI) -> case is_relative_uri(URI) of true -> -- cgit v1.2.3 From 715bb8044600ec16ad6ba97de9d033f6a5c06bfe Mon Sep 17 00:00:00 2001 From: Magnus Henoch Date: Wed, 25 Jul 2012 18:04:11 +0100 Subject: List behaviour callbacks in Edoc when using -callback attribute Defining a behaviour_info/1 function is no longer the only way to define a behaviour; you can use -callback attributes as well. This change makes edoc aware of the latter, such that the module documentation page for a behaviour module will list the name and arity of the required callback functions. Ideally, edoc should use the type information present in the callback attributes, but with this change, the documentation is at least no worse than when using an explicit behaviour_info function. --- lib/edoc/src/edoc_data.erl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/edoc/src/edoc_data.erl b/lib/edoc/src/edoc_data.erl index aad0b14371..624f9177a2 100644 --- a/lib/edoc/src/edoc_data.erl +++ b/lib/edoc/src/edoc_data.erl @@ -167,7 +167,10 @@ callbacks(Es, Module, Env, Opts) -> case lists:any(fun (#entry{name = {behaviour_info, 1}}) -> true; (_) -> false end, - Es) of + Es) + orelse + lists:keymember(callback, 1, Module#module.attributes) + of true -> try (Module#module.name):behaviour_info(callbacks) of Fs -> -- cgit v1.2.3 From 3d9dcf8a8a483742f57924348ae56e4a6bfa1c3c Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Wed, 8 Aug 2012 00:31:15 +0300 Subject: bumped revision --- lib/edoc/vsn.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk index b8f33894f1..2f403212c8 100644 --- a/lib/edoc/vsn.mk +++ b/lib/edoc/vsn.mk @@ -1 +1 @@ -EDOC_VSN = 0.7.9.1 +EDOC_VSN = 0.7.10 -- cgit v1.2.3 From 4e3cd7868d0d42c066b8222472b741195c76ecad Mon Sep 17 00:00:00 2001 From: Siri Hansen Date: Wed, 8 Aug 2012 16:17:30 +0200 Subject: Bugfix escript_SUITE:archive_script_file_access Used internal function do_run/3 instead of run/3 for executing escript. This will always fail on windows. --- lib/stdlib/test/escript_SUITE.erl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl index e76d0972f3..38c085616d 100644 --- a/lib/stdlib/test/escript_SUITE.erl +++ b/lib/stdlib/test/escript_SUITE.erl @@ -557,8 +557,8 @@ archive_script_file_access(Config) when is_list(Config) -> %% Change to script's directory and run it as "./" ok = file:set_cwd(PrivDir), - do_run(PrivDir, "./" ++ ScriptName1 ++ " " ++ ScriptName1, - [<<"ExitCode:0">>]), + run(PrivDir, "./" ++ ScriptName1 ++ " " ++ ScriptName1, + [<<"ExitCode:0">>]), ok = file:set_cwd(TopDir), @@ -591,16 +591,16 @@ archive_script_file_access(Config) when is_list(Config) -> %% Change to script's directory and run it as "./" ok = file:set_cwd(PrivDir), - do_run(PrivDir, "./" ++ ScriptName2 ++ " " ++ ScriptName2, - [<<"ExitCode:0">>]), + run(PrivDir, "./" ++ ScriptName2 ++ " " ++ ScriptName2, + [<<"ExitCode:0">>]), %% 3. If symlinks are supported, run one of the scripts via a symlink. %% %% This is in order to test error b) described above this test case. case file:read_link(Symlink2) of {ok,_} -> - do_run(PrivDir, "./" ++ SymlinkName2 ++ " " ++ ScriptName2, - [<<"ExitCode:0">>]); + run(PrivDir, "./" ++ SymlinkName2 ++ " " ++ ScriptName2, + [<<"ExitCode:0">>]); _ -> % not supported ok end, -- cgit v1.2.3 From 6f5900f9b136ae9aa6b89877727f6dac9e782ea6 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Sun, 11 Dec 2011 17:43:28 +0100 Subject: Add option 'no_tty' to silent the default tty report --- lib/eunit/src/eunit.erl | 7 ++++-- lib/eunit/src/eunit_tty.erl | 59 ++++++++++++++++++++++++++------------------- 2 files changed, 39 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl index 95857e83c8..51846d73b3 100644 --- a/lib/eunit/src/eunit.erl +++ b/lib/eunit/src/eunit.erl @@ -139,7 +139,7 @@ test(Tests, Options) -> %% @private %% @doc See {@link test/2}. test(Server, Tests, Options) -> - Listeners = [eunit_tty:start(Options) | listeners(Options)], + Listeners = listeners(Options), Serial = eunit_serial:start(Listeners), case eunit_server:start_test(Server, Serial, Tests, Options) of {ok, Reference} -> test_run(Reference, Listeners); @@ -194,7 +194,10 @@ submit(Server, T, Options) -> eunit_server:start_test(Server, Dummy, T, Options). listeners(Options) -> - Ps = start_listeners(proplists:get_all_values(report, Options)), + %% note that eunit_tty must always run, because it sends the final + %% {result,...} message that the test_run() function is waiting for + Ls = [{eunit_tty, Options} | proplists:get_all_values(report, Options)], + Ps = start_listeners(Ls), %% the event_log option is for debugging, to view the raw events case proplists:get_value(event_log, Options) of undefined -> diff --git a/lib/eunit/src/eunit_tty.erl b/lib/eunit/src/eunit_tty.erl index e3e7b710b2..a8cec86ade 100644 --- a/lib/eunit/src/eunit_tty.erl +++ b/lib/eunit/src/eunit_tty.erl @@ -44,6 +44,7 @@ start(Options) -> init(Options) -> St = #state{verbose = proplists:get_bool(verbose, Options)}, + put(no_tty, proplists:get_bool(no_tty, Options)), receive {start, _Reference} -> if St#state.verbose -> print_header(); @@ -59,30 +60,30 @@ terminate({ok, Data}, St) -> Cancel = proplists:get_value(cancel, Data, 0), if Fail =:= 0, Skip =:= 0, Cancel =:= 0 -> if Pass =:= 0 -> - io:fwrite(" There were no tests to run.\n"); + fwrite(" There were no tests to run.\n"); true -> if St#state.verbose -> print_bar(); true -> ok end, if Pass =:= 1 -> - io:fwrite(" Test passed.\n"); + fwrite(" Test passed.\n"); true -> - io:fwrite(" All ~w tests passed.\n", [Pass]) + fwrite(" All ~w tests passed.\n", [Pass]) end end, sync_end(ok); true -> print_bar(), - io:fwrite(" Failed: ~w. Skipped: ~w. Passed: ~w.\n", - [Fail, Skip, Pass]), + fwrite(" Failed: ~w. Skipped: ~w. Passed: ~w.\n", + [Fail, Skip, Pass]), if Cancel =/= 0 -> - io:fwrite("One or more tests were cancelled.\n"); + fwrite("One or more tests were cancelled.\n"); true -> ok end, sync_end(error) end; terminate({error, Reason}, _St) -> - io:fwrite("Internal error: ~P.\n", [Reason, 25]), + fwrite("Internal error: ~P.\n", [Reason, 25]), sync_end(error). sync_end(Result) -> @@ -93,10 +94,10 @@ sync_end(Result) -> end. print_header() -> - io:fwrite("======================== EUnit ========================\n"). + fwrite("======================== EUnit ========================\n"). print_bar() -> - io:fwrite("=======================================================\n"). + fwrite("=======================================================\n"). handle_begin(group, Data, St) -> @@ -170,18 +171,18 @@ handle_cancel(test, Data, St) -> indent(N) when is_integer(N), N >= 1 -> - io:put_chars(lists:duplicate(N * 2, $\s)); + fwrite(lists:duplicate(N * 2, $\s)); indent(_N) -> ok. print_group_start(I, Desc) -> indent(I), - io:fwrite("~s\n", [Desc]). + fwrite("~s\n", [Desc]). print_group_end(I, Time) -> if Time > 0 -> indent(I), - io:fwrite("[done in ~.3f s]\n", [Time/1000]); + fwrite("[done in ~.3f s]\n", [Time/1000]); true -> ok end. @@ -198,9 +199,9 @@ print_test_begin(I, Data) -> end, case proplists:get_value(source, Data) of {Module, Name, _Arity} -> - io:fwrite("~s:~s ~s~s...", [Module, L, Name, D]); + fwrite("~s:~s ~s~s...", [Module, L, Name, D]); _ -> - io:fwrite("~s~s...", [L, D]) + fwrite("~s~s...", [L, D]) end. print_test_end(Data) -> @@ -208,36 +209,35 @@ print_test_end(Data) -> T = if Time > 0 -> io_lib:fwrite("[~.3f s] ", [Time/1000]); true -> "" end, - io:fwrite("~sok\n", [T]). + fwrite("~sok\n", [T]). print_test_error({error, Exception}, Data) -> Output = proplists:get_value(output, Data), - io:fwrite("*failed*\n::~s", - [eunit_lib:format_exception(Exception)]), + fwrite("*failed*\n::~s", [eunit_lib:format_exception(Exception)]), case Output of <<>> -> - io:put_chars("\n\n"); + fwrite("\n\n"); <> -> - io:fwrite(" output:<<\"~s\">>...\n\n", [Text]); + fwrite(" output:<<\"~s\">>...\n\n", [Text]); _ -> - io:fwrite(" output:<<\"~s\">>\n\n", [Output]) + fwrite(" output:<<\"~s\">>\n\n", [Output]) end; print_test_error({skipped, Reason}, _) -> - io:fwrite("*did not run*\n::~s\n", [format_skipped(Reason)]). + fwrite("*did not run*\n::~s\n", [format_skipped(Reason)]). format_skipped({module_not_found, M}) -> - io_lib:format("missing module: ~w", [M]); + io_lib:fwrite("missing module: ~w", [M]); format_skipped({no_such_function, {M,F,A}}) -> - io_lib:format("no such function: ~w:~w/~w", [M,F,A]). + io_lib:fwrite("no such function: ~w:~w/~w", [M,F,A]). print_test_cancel(Reason) -> - io:fwrite(format_cancel(Reason)). + fwrite(format_cancel(Reason)). print_group_cancel(_I, {blame, _}) -> ok; print_group_cancel(I, Reason) -> indent(I), - io:fwrite(format_cancel(Reason)). + fwrite(format_cancel(Reason)). format_cancel(undefined) -> "*skipped*\n"; @@ -253,3 +253,12 @@ format_cancel({exit, Reason}) -> [Reason, 15]); format_cancel({abort, Reason}) -> eunit_lib:format_error(Reason). + +fwrite(String) -> + fwrite(String, []). + +fwrite(String, Args) -> + case get(no_tty) of + false -> io:fwrite(String, Args); + true -> ok + end. -- cgit v1.2.3 From fea574bac8464f07a72862e1a4f92e9b62e464e4 Mon Sep 17 00:00:00 2001 From: Klas Johansson Date: Sun, 12 Feb 2012 18:24:53 +0100 Subject: Make EUnit print stacktraces with location information The format of stacktraces was changed in Erlang/OTP R15, adding location information. This had the effect that EUnit did not recognize stack traces as such and only printed the exception term. This patch makes Eunit recognize and print the new stacktrace format as well as the old. --- lib/eunit/src/eunit_lib.erl | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl index 1c41e229c5..c700989bae 100644 --- a/lib/eunit/src/eunit_lib.erl +++ b/lib/eunit/src/eunit_lib.erl @@ -86,6 +86,12 @@ analyze_exit_term(Term) -> is_stacktrace([]) -> true; +is_stacktrace([{M,F,A,L}|Fs]) + when is_atom(M), is_atom(F), is_integer(A), is_list(L) -> + is_stacktrace(Fs); +is_stacktrace([{M,F,As,L}|Fs]) + when is_atom(M), is_atom(F), is_list(As), is_list(L) -> + is_stacktrace(Fs); is_stacktrace([{M,F,A}|Fs]) when is_atom(M), is_atom(F), is_integer(A) -> is_stacktrace(Fs); is_stacktrace([{M,F,As}|Fs]) when is_atom(M), is_atom(F), is_list(As) -> @@ -96,10 +102,11 @@ is_stacktrace(_) -> format_stacktrace(Trace) -> format_stacktrace(Trace, "in function", "in call from"). -format_stacktrace([{M,F,A}|Fs], Pre, Pre1) when is_integer(A) -> - [io_lib:fwrite(" ~s ~w:~w/~w\n", [Pre, M, F, A]) +format_stacktrace([{M,F,A,L}|Fs], Pre, Pre1) when is_integer(A) -> + [io_lib:fwrite(" ~s ~w:~w/~w~s\n", + [Pre, M, F, A, format_stacktrace_location(L)]) | format_stacktrace(Fs, Pre1, Pre1)]; -format_stacktrace([{M,F,As}|Fs], Pre, Pre1) when is_list(As) -> +format_stacktrace([{M,F,As,L}|Fs], Pre, Pre1) when is_list(As) -> A = length(As), C = case is_op(M,F,A) of true when A =:= 1 -> @@ -112,12 +119,23 @@ format_stacktrace([{M,F,As}|Fs], Pre, Pre1) when is_list(As) -> false -> io_lib:fwrite("~w(~s)", [F,format_arglist(As)]) end, - [io_lib:fwrite(" ~s ~w:~w/~w\n called as ~s\n", - [Pre,M,F,A,C]) + [io_lib:fwrite(" ~s ~w:~w/~w~s\n called as ~s\n", + [Pre,M,F,A,format_stacktrace_location(L),C]) | format_stacktrace(Fs,Pre1,Pre1)]; +format_stacktrace([{M,F,As}|Fs], Pre, Pre1) -> + format_stacktrace([{M,F,As,[]}|Fs], Pre, Pre1); format_stacktrace([],_Pre,_Pre1) -> "". +format_stacktrace_location(Location) -> + File = proplists:get_value(file, Location), + Line = proplists:get_value(line, Location), + if File =/= undefined, Line =/= undefined -> + io_lib:format(" (~s, line ~w)", [File, Line]); + true -> + "" + end. + format_arg(A) -> io_lib:format("~P",[A,15]). @@ -166,6 +184,21 @@ error_msg(Title, Fmt, Args) -> Msg = io_lib:format("::"++Fmt, Args), % gets indentation right io_lib:fwrite("*** ~s ***\n~s\n\n", [Title, Msg]). +-ifdef(TEST). +format_exception_test_() -> + [?_assertMatch( + "error:dummy"++_, + lists:flatten( + format_exception(try erlang:error(dummy) + catch C:R -> {C, R, erlang:get_stacktrace()} + end))), + ?_assertMatch( + "error:dummy"++_, + lists:flatten( + format_exception(try erlang:error(dummy, [a]) + catch C:R -> {C, R, erlang:get_stacktrace()} + end)))]. +-endif. %% --------------------------------------------------------------------- %% Deep list iterator; accepts improper lists/sublists, and also accepts -- cgit v1.2.3 From b91207f58f9c52ae09c42947029f28932e5991c5 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Mon, 13 Feb 2012 10:35:57 +0100 Subject: make stack trace pruning know about the new format --- lib/eunit/src/eunit_test.erl | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl index bca49ae626..3457b5ee21 100644 --- a/lib/eunit/src/eunit_test.erl +++ b/lib/eunit/src/eunit_test.erl @@ -43,8 +43,12 @@ get_stacktrace(Ts) -> prune_trace([{eunit_data, _, _} | Rest], Tail) -> prune_trace(Rest, Tail); +prune_trace([{eunit_data, _, _, _} | Rest], Tail) -> + prune_trace(Rest, Tail); prune_trace([{?MODULE, _, _} | _Rest], Tail) -> Tail; +prune_trace([{?MODULE, _, _, _} | _Rest], Tail) -> + Tail; prune_trace([T | Ts], Tail) -> [T | prune_trace(Ts, Tail)]; prune_trace([], Tail) -> -- cgit v1.2.3 From 975a3d513f3e112fa12b4de366ad54ac68b46b6e Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Mon, 13 Feb 2012 20:49:42 +0100 Subject: bumped revision --- lib/eunit/vsn.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk index 445c070e96..174d197117 100644 --- a/lib/eunit/vsn.mk +++ b/lib/eunit/vsn.mk @@ -1 +1 @@ -EUNIT_VSN = 2.2.2 +EUNIT_VSN = 2.2.3 -- cgit v1.2.3 From dab05b72fa5cfd383f1eac5525ac671a15c5cbf6 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Wed, 15 Feb 2012 16:43:31 +0100 Subject: improved layout of error messages - stack trace before error term --- lib/eunit/src/eunit_lib.erl | 23 ++++++++++++----------- lib/eunit/src/eunit_tty.erl | 4 ++-- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl index c700989bae..5d7025f038 100644 --- a/lib/eunit/src/eunit_lib.erl +++ b/lib/eunit/src/eunit_lib.erl @@ -59,8 +59,9 @@ format_exception({Class,Term,Trace}, Depth) when is_atom(Class), is_list(Trace) -> case is_stacktrace(Trace) of true -> - io_lib:format("~w:~P\n~s", - [Class, Term, Depth, format_stacktrace(Trace)]); + io_lib:format("~s**~w:~s", + [format_stacktrace(Trace), Class, + format_term(Term, Depth)]); false -> format_term(Term, Depth) end; @@ -103,7 +104,7 @@ format_stacktrace(Trace) -> format_stacktrace(Trace, "in function", "in call from"). format_stacktrace([{M,F,A,L}|Fs], Pre, Pre1) when is_integer(A) -> - [io_lib:fwrite(" ~s ~w:~w/~w~s\n", + [io_lib:fwrite("~s ~w:~w/~w~s\n", [Pre, M, F, A, format_stacktrace_location(L)]) | format_stacktrace(Fs, Pre1, Pre1)]; format_stacktrace([{M,F,As,L}|Fs], Pre, Pre1) when is_list(As) -> @@ -119,7 +120,7 @@ format_stacktrace([{M,F,As,L}|Fs], Pre, Pre1) when is_list(As) -> false -> io_lib:fwrite("~w(~s)", [F,format_arglist(As)]) end, - [io_lib:fwrite(" ~s ~w:~w/~w~s\n called as ~s\n", + [io_lib:fwrite("~s ~w:~w/~w~s\n called as ~s\n", [Pre,M,F,A,format_stacktrace_location(L),C]) | format_stacktrace(Fs,Pre1,Pre1)]; format_stacktrace([{M,F,As}|Fs], Pre, Pre1) -> @@ -181,23 +182,23 @@ format_error({instantiation_failed, Exception}) -> [format_exception(Exception)]). error_msg(Title, Fmt, Args) -> - Msg = io_lib:format("::"++Fmt, Args), % gets indentation right + Msg = io_lib:format("**"++Fmt, Args), % gets indentation right io_lib:fwrite("*** ~s ***\n~s\n\n", [Title, Msg]). -ifdef(TEST). format_exception_test_() -> [?_assertMatch( - "error:dummy"++_, - lists:flatten( + "\nymmud:rorre"++_, + lists:reverse(lists:flatten( format_exception(try erlang:error(dummy) catch C:R -> {C, R, erlang:get_stacktrace()} - end))), + end)))), ?_assertMatch( - "error:dummy"++_, - lists:flatten( + "\nymmud:rorre"++_, + lists:reverse(lists:flatten( format_exception(try erlang:error(dummy, [a]) catch C:R -> {C, R, erlang:get_stacktrace()} - end)))]. + end))))]. -endif. %% --------------------------------------------------------------------- diff --git a/lib/eunit/src/eunit_tty.erl b/lib/eunit/src/eunit_tty.erl index a8cec86ade..f21b2da3d3 100644 --- a/lib/eunit/src/eunit_tty.erl +++ b/lib/eunit/src/eunit_tty.erl @@ -213,7 +213,7 @@ print_test_end(Data) -> print_test_error({error, Exception}, Data) -> Output = proplists:get_value(output, Data), - fwrite("*failed*\n::~s", [eunit_lib:format_exception(Exception)]), + fwrite("*failed*\n~s", [eunit_lib:format_exception(Exception)]), case Output of <<>> -> fwrite("\n\n"); @@ -228,7 +228,7 @@ print_test_error({skipped, Reason}, _) -> format_skipped({module_not_found, M}) -> io_lib:fwrite("missing module: ~w", [M]); format_skipped({no_such_function, {M,F,A}}) -> - io_lib:fwrite("no such function: ~w:~w/~w", [M,F,A]). + io_lib:fwrite("no such function: ~w:~w/~w", [M,F,A]). print_test_cancel(Reason) -> fwrite(format_cancel(Reason)). -- cgit v1.2.3 From e2aaefc509b52eaeb0416ecc603806f1416c17ea Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Tue, 17 Apr 2012 14:00:24 +0200 Subject: eunit_tests should not be listed in eunit.app --- lib/eunit/src/eunit.app.src | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/eunit/src/eunit.app.src b/lib/eunit/src/eunit.app.src index 5e16dfa2ce..431abac98b 100644 --- a/lib/eunit/src/eunit.app.src +++ b/lib/eunit/src/eunit.app.src @@ -14,7 +14,6 @@ eunit_striptests, eunit_surefire, eunit_test, - eunit_tests, eunit_tty]}, {registered,[]}, {applications, [kernel,stdlib]}, -- cgit v1.2.3 From 1a90915b4305afb9ee097e03c8a40b3ff5f8e33d Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Tue, 17 Apr 2012 15:21:05 +0200 Subject: detect and report bad return values from generators and instantiators --- lib/eunit/src/eunit_data.erl | 21 ++++++++++++++++----- lib/eunit/src/eunit_lib.erl | 39 +++++++++++++++++++++++++++++++++++---- lib/eunit/src/eunit_test.erl | 22 ++++++++++++++++------ 3 files changed, 67 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl index 392d378a0e..da66864439 100644 --- a/lib/eunit/src/eunit_data.erl +++ b/lib/eunit/src/eunit_data.erl @@ -156,7 +156,8 @@ iter_prev(#iter{prev = [T | Ts]} = I) -> %% @spec (tests()) -> none | {testItem(), tests()} %% @type testItem() = #test{} | #group{} %% @throws {bad_test, term()} -%% | {generator_failed, exception()} +%% | {generator_failed, {{M::atom(),F::atom(),A::integer()}, +%% exception()}} %% | {no_such_function, eunit_lib:mfa()} %% | {module_not_found, moduleName()} %% | {application_not_found, appName()} @@ -221,17 +222,27 @@ parse({foreachx, P, S1, C1, Ps} = T) [] -> {data, []} end; -parse({generator, F} = T) when is_function(F) -> +parse({generator, F}) when is_function(F) -> + {module, M} = erlang:fun_info(F, module), + {name, N} = erlang:fun_info(F, name), + {arity, A} = erlang:fun_info(F, arity), + parse({generator, F, {M,N,A}}); +parse({generator, F, {M,N,A}} = T) + when is_function(F), is_atom(M), is_atom(N), is_integer(A) -> check_arity(F, 0, T), %% use run_testfun/1 to handle wrapper exceptions case eunit_test:run_testfun(F) of {ok, T1} -> + case eunit_lib:is_not_test(T1) of + true -> throw({bad_generator, {{M,N,A}, T1}}); + false -> ok + end, {data, T1}; {error, {Class, Reason, Trace}} -> - throw({generator_failed, {Class, Reason, Trace}}) + throw({generator_failed, {{M,N,A}, {Class, Reason, Trace}}}) end; parse({generator, M, F}) when is_atom(M), is_atom(F) -> - parse({generator, eunit_test:function_wrapper(M, F)}); + parse({generator, eunit_test:mf_wrapper(M, F), {M,F,0}}); parse({inorder, T}) -> group(#group{tests = T, order = inorder}); parse({inparallel, T}) -> @@ -422,7 +433,7 @@ parse_function(F) when is_function(F) -> check_arity(F, 0, F), #test{f = F, location = eunit_lib:fun_parent(F)}; parse_function({M,F}) when is_atom(M), is_atom(F) -> - #test{f = eunit_test:function_wrapper(M, F), location = {M, F, 0}}; + #test{f = eunit_test:mf_wrapper(M, F), location = {M, F, 0}}; parse_function(F) -> bad_test(F). diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl index 5d7025f038..f0fd26eb5d 100644 --- a/lib/eunit/src/eunit_lib.erl +++ b/lib/eunit/src/eunit_lib.erl @@ -30,7 +30,8 @@ -export([dlist_next/1, uniq/1, fun_parent/1, is_string/1, command/1, command/2, command/3, trie_new/0, trie_store/2, trie_match/2, split_node/1, consult_file/1, list_dir/1, format_exit_term/1, - format_exception/1, format_exception/2, format_error/1]). + format_exception/1, format_exception/2, format_error/1, + is_not_test/1]). %% Type definitions for describing exceptions @@ -158,9 +159,13 @@ is_op(_M, _F, _A) -> format_error({bad_test, Term}) -> error_msg("bad test descriptor", "~P", [Term, 15]); -format_error({generator_failed, Exception}) -> - error_msg("test generator failed", "~s", - [format_exception(Exception)]); +format_error({bad_generator, {{M,F,A}, Term}}) -> + error_msg(io_lib:format("result from generator ~w:~w/~w is not a test", + [M,F,A]), + "~P", [Term, 15]); +format_error({generator_failed, {{M,F,A}, Exception}}) -> + error_msg(io_lib:format("test generator ~w:~w/~w failed",[M,F,A]), + "~s", [format_exception(Exception)]); format_error({no_such_function, {M,F,A}}) when is_atom(M), is_atom(F), is_integer(A) -> error_msg(io_lib:format("no such function: ~w:~w/~w", [M,F,A]), @@ -177,6 +182,10 @@ format_error({setup_failed, Exception}) -> format_error({cleanup_failed, Exception}) -> error_msg("context cleanup failed", "~s", [format_exception(Exception)]); +format_error({{bad_instantiator, {{M,F,A}, Term}}, _DummyException}) -> + error_msg(io_lib:format("result from instantiator ~w:~w/~w is not a test", + [M,F,A]), + "~P", [Term, 15]); format_error({instantiation_failed, Exception}) -> error_msg("instantiation of subtests failed", "~s", [format_exception(Exception)]). @@ -201,6 +210,28 @@ format_exception_test_() -> end))))]. -endif. +%% --------------------------------------------------------------------- +%% detect common return values that are definitely not tests + +is_not_test(T) -> + case T of + ok -> true; + error -> true; + true -> true; + false -> true; + undefined -> true; + {ok, _} -> true; + {error, _} -> true; + {'EXIT', _} -> true; + N when is_number(N) -> true; + [N|_] when is_number(N) -> true; + X when is_binary(X) -> true; + X when is_pid(X) -> true; + X when is_port(X) -> true; + X when is_reference(X) -> true; + _ -> false + end. + %% --------------------------------------------------------------------- %% Deep list iterator; accepts improper lists/sublists, and also accepts %% non-lists on the top level. Nonempty strings (not deep strings) are diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl index 3457b5ee21..9cf40a738d 100644 --- a/lib/eunit/src/eunit_test.erl +++ b/lib/eunit/src/eunit_test.erl @@ -21,8 +21,7 @@ -module(eunit_test). --export([run_testfun/1, function_wrapper/2, enter_context/4, - multi_setup/1]). +-export([run_testfun/1, mf_wrapper/2, enter_context/4, multi_setup/1]). -include("eunit.hrl"). @@ -262,7 +261,7 @@ macro_test_() -> %% @type wrapperError() = {no_such_function, mfa()} %% | {module_not_found, moduleName()} -function_wrapper(M, F) -> +mf_wrapper(M, F) -> fun () -> try M:F() catch @@ -293,12 +292,12 @@ fail(Term) -> wrapper_test_() -> {"error handling in function wrapper", [?_assertException(throw, {module_not_found, eunit_nonexisting}, - run_testfun(function_wrapper(eunit_nonexisting,test))), + run_testfun(mf_wrapper(eunit_nonexisting,test))), ?_assertException(throw, {no_such_function, {?MODULE,nonexisting_test,0}}, - run_testfun(function_wrapper(?MODULE,nonexisting_test))), + run_testfun(mf_wrapper(?MODULE,nonexisting_test))), ?_test({error, {error, undef, _T}} - = run_testfun(function_wrapper(?MODULE,wrapper_test_exported_))) + = run_testfun(mf_wrapper(?MODULE,wrapper_test_exported_))) ]}. %% this must be exported (done automatically by the autoexport transform) @@ -323,6 +322,17 @@ enter_context(Setup, Cleanup, Instantiate, Callback) -> R -> try Instantiate(R) of T -> + case eunit_lib:is_not_test(T) of + true -> + catch throw(error), % generate a stack trace + {module,M} = erlang:fun_info(Instantiate, module), + {name,N} = erlang:fun_info(Instantiate, name), + {arity,A} = erlang:fun_info(Instantiate, arity), + context_error({bad_instantiator, {{M,N,A},T}}, + error, badarg); + false -> + ok + end, try Callback(T) %% call back to client code after %% Always run cleanup; client may be an idiot -- cgit v1.2.3 From c4065f1b503d97cd05e9c5c791ec387a93875021 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 30 May 2012 17:16:16 +0200 Subject: Write chars as UTF-8 to file --- lib/eunit/src/eunit_surefire.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl index 2a6cbca14d..69f471d130 100644 --- a/lib/eunit/src/eunit_surefire.erl +++ b/lib/eunit/src/eunit_surefire.erl @@ -232,7 +232,7 @@ write_reports(TestSuites, XmlDir) -> write_report(#testsuite{name = Name} = TestSuite, XmlDir) -> Filename = filename:join(XmlDir, lists:flatten(["TEST-", escape_suitename(Name)], ".xml")), - case file:open(Filename, [write, raw]) of + case file:open(Filename, [write,{encoding,utf8}]) of {ok, FileDescriptor} -> try write_report_to(TestSuite, FileDescriptor) -- cgit v1.2.3 From 99070064280a7141220fac2ccad8e73acde16091 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Thu, 5 Jul 2012 19:15:58 +0200 Subject: minor cleanup --- lib/eunit/include/eunit.hrl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl index db68d8ae60..fba840c3bd 100644 --- a/lib/eunit/include/eunit.hrl +++ b/lib/eunit/include/eunit.hrl @@ -25,11 +25,12 @@ %% will become undefined. NODEBUG also implies NOASSERT, unless testing %% is enabled. %% -%% If including this file causes TEST to be defined, then NOASSERT will -%% be undefined, even if it was previously defined and even if NODEBUG -%% is defined. If both ASSERT and NOASSERT are defined before the file -%% is included, then ASSERT takes precedence, and NOASSERT will become -%% undefined regardless of TEST. +%% Defining NOASSERT disables asserts. NODEBUG implies NOASSERT unless +%% testing is enabled. If including this file causes TEST to be defined, +%% then NOASSERT will be undefined, even if it was previously defined and +%% even if NODEBUG is defined. If both ASSERT and NOASSERT are defined +%% before the file is included, then ASSERT takes precedence, and NOASSERT +%% will become undefined regardless of TEST. %% %% After including this file, EUNIT will be defined if and only if TEST %% is defined. @@ -127,9 +128,9 @@ current_function)))). -endif. --ifdef(NOASSERT). %% The plain assert macro should be defined to do nothing if this file %% is included when debugging/testing is turned off. +-ifdef(NOASSERT). -ifndef(assert). -define(assert(BoolExpr),ok). -endif. -- cgit v1.2.3 From 7b1897b9cf0ef125a567004745b211698a976bd9 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Tue, 17 Jul 2012 18:27:29 +0200 Subject: add {test,M,F} as a better variant of {M,F} and make the latter obsolete --- lib/eunit/doc/overview.edoc | 7 +++++-- lib/eunit/src/eunit_data.erl | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc index ad449cb6fc..42d70a6963 100644 --- a/lib/eunit/doc/overview.edoc +++ b/lib/eunit/doc/overview.edoc @@ -723,8 +723,11 @@ A simple test object is one of the following: ```fun some_function/0''' ```fun some_module:some_function/0''' -
  • A pair of atoms `{ModuleName, FunctionName}', referring to the - function `ModuleName:FunctionName/0'
  • +
  • A tuple `{test, ModuleName, FunctionName}', where `ModuleName' and + `FunctionName' are atoms, referring to the function + `ModuleName:FunctionName/0'
  • +
  • Obsolete: a pair of atoms `{ModuleName, FunctionName}', equivalent to + `{test, ModuleName, FunctionName}' if nothing else matches first.
  • A pair `{LineNumber, SimpleTest}', where `LineNumber' is a nonnegative integer and `SimpleTest' is another simple test object. `LineNumber' should indicate the source line of the test. diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl index da66864439..0222becb18 100644 --- a/lib/eunit/src/eunit_data.erl +++ b/lib/eunit/src/eunit_data.erl @@ -83,6 +83,7 @@ %% SimpleTest = TestFunction | {Line::integer(), SimpleTest} %% %% TestFunction = () -> any() +%% | {test, M::moduleName(), F::functionName()} %% | {M::moduleName(), F::functionName()}. %% %% AbstractTestFunction = (X::any()) -> any() @@ -432,8 +433,11 @@ parse_simple(F) -> parse_function(F) when is_function(F) -> check_arity(F, 0, F), #test{f = F, location = eunit_lib:fun_parent(F)}; -parse_function({M,F}) when is_atom(M), is_atom(F) -> +parse_function({test, M, F}) when is_atom(M), is_atom(F) -> #test{f = eunit_test:mf_wrapper(M, F), location = {M, F, 0}}; +parse_function({M, F}) when is_atom(M), is_atom(F) -> + %% {M,F} is now considered obsolete; use {test,M,F} instead + parse_function({test, M, F}); parse_function(F) -> bad_test(F). @@ -591,7 +595,7 @@ testfuns(Es, M, TestSuffix, GeneratorSuffix) -> N = atom_to_list(F), case lists:suffix(TestSuffix, N) of true -> - [{M,F} | Fs]; + [{test, M, F} | Fs]; false -> case lists:suffix(GeneratorSuffix, N) of true -> @@ -734,6 +738,7 @@ data_test_() -> Tests = [T,T,T], [?_assertMatch(ok, eunit:test(T)), ?_assertMatch(error, eunit:test(Fail)), + ?_assertMatch(ok, eunit:test({test, ?MODULE, trivial_test})), ?_assertMatch(ok, eunit:test({generator, fun () -> Tests end})), ?_assertMatch(ok, eunit:test({generator, fun generator/0})), ?_assertMatch(ok, eunit:test({generator, ?MODULE, generator_exported_})), @@ -751,6 +756,12 @@ data_test_() -> %%?_test({foreach, Setup, [T, T, T]}) ]. +trivial_test() -> + ok. + +trivial_generator_test_() -> + [?_test(ok)]. + lazy_test_() -> {spawn, [?_test(undefined = put(count, 0)), lazy_gen(7), -- cgit v1.2.3 From 5f9ad541eb520162d86bdc5bcf58e235ced7e786 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Tue, 17 Jul 2012 18:32:31 +0200 Subject: documentation fixes --- lib/eunit/doc/overview.edoc | 5 +++-- lib/eunit/src/eunit_data.erl | 3 +-- lib/eunit/src/eunit_lib.erl | 5 +---- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc index 42d70a6963..b4af31ae6a 100644 --- a/lib/eunit/doc/overview.edoc +++ b/lib/eunit/doc/overview.edoc @@ -726,8 +726,9 @@ A simple test object is one of the following:
  • A tuple `{test, ModuleName, FunctionName}', where `ModuleName' and `FunctionName' are atoms, referring to the function `ModuleName:FunctionName/0'
  • -
  • Obsolete: a pair of atoms `{ModuleName, FunctionName}', equivalent to - `{test, ModuleName, FunctionName}' if nothing else matches first.
  • +
  • (Obsolete) A pair of atoms `{ModuleName, FunctionName}', equivalent to + `{test, ModuleName, FunctionName}' if nothing else matches first. This + might be removed in a future version.
  • A pair `{LineNumber, SimpleTest}', where `LineNumber' is a nonnegative integer and `SimpleTest' is another simple test object. `LineNumber' should indicate the source line of the test. diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl index 0222becb18..0350f9bf6e 100644 --- a/lib/eunit/src/eunit_data.erl +++ b/lib/eunit/src/eunit_data.erl @@ -96,7 +96,6 @@ %% %% @type moduleName() = atom() %% @type functionName() = atom() -%% @type arity() = integer() %% @type appName() = atom() %% @type fileName() = string() @@ -159,7 +158,7 @@ iter_prev(#iter{prev = [T | Ts]} = I) -> %% @throws {bad_test, term()} %% | {generator_failed, {{M::atom(),F::atom(),A::integer()}, %% exception()}} -%% | {no_such_function, eunit_lib:mfa()} +%% | {no_such_function, mfa()} %% | {module_not_found, moduleName()} %% | {application_not_found, appName()} %% | {file_read_error, {Reason::atom(), Message::string(), diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl index f0fd26eb5d..ea9e944d7e 100644 --- a/lib/eunit/src/eunit_lib.erl +++ b/lib/eunit/src/eunit_lib.erl @@ -40,13 +40,10 @@ %% %% @type exceptionClass() = error | exit | throw %% -%% @type stackTrace() = [{moduleName(), functionName(), -%% arity() | argList()}] +%% @type stackTrace() = [{moduleName(), functionName(), arity() | argList()}] %% %% @type moduleName() = atom() %% @type functionName() = atom() -%% @type arity() = integer() -%% @type mfa() = {moduleName(), functionName(), arity()} %% @type argList() = [term()] %% @type fileName() = string() -- cgit v1.2.3 From 95a78de4810ca25f7175d8eb7bb8f05e38034122 Mon Sep 17 00:00:00 2001 From: Magnus Henoch Date: Thu, 10 Mar 2011 10:18:37 +0000 Subject: Include fixture setup and cleanup errors in Eunit Surefire report An error during fixture setup means that some tests could not be run, and therefore needs to be highlighted in the test report. Likewise, a cleanup failure is often a problem that needs to be looked into. Since setup and cleanup are not part of any single test in Eunit's view, I include them as phantom test cases in the report whenever they fail. --- lib/eunit/src/eunit_surefire.erl | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl index 69f471d130..46b8c8b503 100644 --- a/lib/eunit/src/eunit_surefire.erl +++ b/lib/eunit/src/eunit_surefire.erl @@ -156,9 +156,33 @@ handle_end(test, Data, St) -> St#state{testsuites=store_suite(NewTestSuite, TestSuites)}. %% Cancel group does not give information on the individual cancelled test case -%% We ignore this event -handle_cancel(group, _Data, St) -> - St; +%% We ignore this event... +handle_cancel(group, Data, St) -> + %% ...except when it tells us that a fixture setup or cleanup failed. + case proplists:get_value(reason, Data) of + {abort, {SomethingFailed, Exception}} + when SomethingFailed =:= setup_failed; + SomethingFailed =:= cleanup_failed -> + [GroupId|_] = proplists:get_value(id, Data), + TestSuites = St#state.testsuites, + TestSuite = lookup_suite_by_group_id(GroupId, TestSuites), + + %% We don't have any proper name. Let's give all the + %% clues that we have. + Name = case SomethingFailed of + setup_failed -> "fixture setup "; + cleanup_failed -> "fixture cleanup " + end + ++ io_lib:format("~p", [proplists:get_value(id, Data)]), + Desc = format_desc(proplists:get_value(desc, Data)), + TestCase = #testcase{ + name = Name, description = Desc, + time = 0, output = <<>>}, + NewTestSuite = add_testcase_to_testsuite({error, Exception}, TestCase, TestSuite), + St#state{testsuites=store_suite(NewTestSuite, TestSuites)}; + _ -> + St + end; handle_cancel(test, Data, St) -> %% Retrieve existing test suite: [GroupId|_] = proplists:get_value(id, Data), -- cgit v1.2.3