diff options
73 files changed, 1518 insertions, 654 deletions
diff --git a/bootstrap/lib/compiler/ebin/beam_bool.beam b/bootstrap/lib/compiler/ebin/beam_bool.beam Binary files differindex 5d9de032ff..f339e76fce 100644 --- a/bootstrap/lib/compiler/ebin/beam_bool.beam +++ b/bootstrap/lib/compiler/ebin/beam_bool.beam diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam Binary files differindex a619db9d50..2b839bc997 100644 --- a/bootstrap/lib/compiler/ebin/beam_jump.beam +++ b/bootstrap/lib/compiler/ebin/beam_jump.beam diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam Binary files differindex 204a243a5b..8507db5454 100644 --- a/bootstrap/lib/compiler/ebin/beam_utils.beam +++ b/bootstrap/lib/compiler/ebin/beam_utils.beam diff --git a/bootstrap/lib/compiler/ebin/cerl_clauses.beam b/bootstrap/lib/compiler/ebin/cerl_clauses.beam Binary files differindex ec41e1098b..c55d8be59d 100644 --- a/bootstrap/lib/compiler/ebin/cerl_clauses.beam +++ b/bootstrap/lib/compiler/ebin/cerl_clauses.beam diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam Binary files differindex cfe023c601..5450bd23ab 100644 --- a/bootstrap/lib/compiler/ebin/cerl_inline.beam +++ b/bootstrap/lib/compiler/ebin/cerl_inline.beam diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam Binary files differindex dca9efc2f3..e172ec6af7 100644 --- a/bootstrap/lib/compiler/ebin/core_lint.beam +++ b/bootstrap/lib/compiler/ebin/core_lint.beam diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam Binary files differindex ffd15e985d..41b702efcf 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam Binary files differindex c270802455..6bf28f441e 100644 --- a/bootstrap/lib/compiler/ebin/v3_codegen.beam +++ b/bootstrap/lib/compiler/ebin/v3_codegen.beam diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam Binary files differindex 794bdc9f99..add7d2be2f 100644 --- a/bootstrap/lib/compiler/ebin/v3_core.beam +++ b/bootstrap/lib/compiler/ebin/v3_core.beam diff --git a/bootstrap/lib/compiler/ebin/v3_kernel.beam b/bootstrap/lib/compiler/ebin/v3_kernel.beam Binary files differindex ecec470cb0..1ac5932127 100644 --- a/bootstrap/lib/compiler/ebin/v3_kernel.beam +++ b/bootstrap/lib/compiler/ebin/v3_kernel.beam diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam Binary files differindex ac36354796..6f430b8c6c 100644 --- a/bootstrap/lib/stdlib/ebin/dets.beam +++ b/bootstrap/lib/stdlib/ebin/dets.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam Binary files differindex 4e3acd3422..6e9d06ea44 100644 --- a/bootstrap/lib/stdlib/ebin/erl_lint.beam +++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam diff --git a/erts/doc/src/escript.xml b/erts/doc/src/escript.xml index d2b09d4515..1abbdb2180 100644 --- a/erts/doc/src/escript.xml +++ b/erts/doc/src/escript.xml @@ -4,7 +4,7 @@ <comref> <header> <copyright> - <year>2007</year><year>2013</year> + <year>2007</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -92,6 +92,18 @@ $ <input>escript factorial 5</input> </pre> marker="stdlib:epp#encoding">encoding</seealso> it can be located on the second line.</p> + <note><p> + The encoding specified by the above mentioned comment + applies to the script itself. The encoding of the + I/O-server, however, has to be set explicitly like this: +<code>io:setopts([{encoding, unicode}])</code></p> + <p>The default encoding of the I/O-server for <c>standard_io</c> + is <c>latin1</c> + since the script runs in a non-interactive terminal + (see <seealso marker="stdlib:unicode_usage#unicode_options_summary"> + Using Unicode in Erlang</seealso>). + </p></note> + <p>On the third line (or second line depending on the presence of the Emacs directive), it is possible to give arguments to the emulator, such as </p> @@ -141,8 +153,9 @@ halt(1).</pre> -include_lib("kernel/include/file.hrl").</pre> <p>to include the record definitions for the records used by the <c>file:read_link_info/1</c> function. You can also select - encoding here, but if there is a valid encoding comment on - the second line it takes precedence.</p> + encoding by including a encoding comment here, but if there + is a valid encoding comment on the second line it takes + precedence.</p> <p>The script will be checked for syntactic and semantic correctness before being run. If there are warnings (such as @@ -163,7 +176,7 @@ halt(1).</pre> If much of the execution takes place in interpreted code it may be worthwhile to compile it, even though the compilation itself will take a little while. It is also possible to supply - <c>native</c> instead of compile, this will compile the script + <c>native</c> instead of <c>compile</c>, this will compile the script using the native flag, again depending on the characteristics of the escript this could or could not be worth while.</p> @@ -239,7 +252,7 @@ factorial 5 = 120 can either be returned as a binary or written to file.</p> <p>As an example of how the function can be used, we create an - interpreted escript which uses emu_args to set some emulator + interpreted escript which uses <c>emu_args</c> to set some emulator flag. In this case it happens to disable the smp_support. We do also extract the different sections from the newly created script:</p> diff --git a/erts/emulator/hipe/hipe_x86_signal.c b/erts/emulator/hipe/hipe_x86_signal.c index 8f997aafab..f5668013e2 100644 --- a/erts/emulator/hipe/hipe_x86_signal.c +++ b/erts/emulator/hipe/hipe_x86_signal.c @@ -2,7 +2,7 @@ * %CopyrightBegin% * - * Copyright Ericsson AB 2001-2013. All Rights Reserved. + * Copyright Ericsson AB 2001-2014. 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 @@ -304,7 +304,9 @@ static void hipe_sigaltstack(void *ss_sp) */ void hipe_thread_signal_init(void) { - hipe_sigaltstack(erts_alloc(ERTS_ALC_T_HIPE, SIGSTKSZ)); + /* Stack don't really need to be cache aligned. + We use it to suppress false leak report from valgrind */ + hipe_sigaltstack(erts_alloc_permanent_cache_aligned(ERTS_ALC_T_HIPE, SIGSTKSZ)); } #endif diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c index 55a0d2ac4f..11b5d0cc35 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_mod.c +++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c @@ -217,7 +217,8 @@ static int upgrade(ErlNifEnv* env, void** priv, void** old_priv_data, ERL_NIF_TE *priv = *old_priv_data; do_load_info(env, load_info, &retval); - + if (retval) + NifModPrivData_release(data); return retval; } diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index 580588fbd2..63bfea68c4 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -1277,28 +1277,35 @@ report(What,Data) -> ct_util:set_testdata({What,Data}), ok; tc_start -> - %% Data = {{Suite,Func},LogFileName} + %% Data = {Suite,{Func,GroupName}},LogFileName} + Data1 = case Data of + {{Suite,{Func,undefined}},LFN} -> {{Suite,Func},LFN}; + _ -> Data + end, ct_event:sync_notify(#event{name=tc_logfile, node=node(), - data=Data}), + data=Data1}), ok; tc_done -> - {_Suite,Case,Result} = Data, + {Suite,{Func,GrName},Result} = Data, + Data1 = if GrName == undefined -> {Suite,Func,Result}; + true -> Data + end, case Result of {failed, _} -> - ct_hooks:on_tc_fail(What, Data); + ct_hooks:on_tc_fail(What, Data1); {skipped,{failed,{_,init_per_testcase,_}}} -> - ct_hooks:on_tc_skip(tc_auto_skip, Data); + ct_hooks:on_tc_skip(tc_auto_skip, Data1); {skipped,{require_failed,_}} -> - ct_hooks:on_tc_skip(tc_auto_skip, Data); + ct_hooks:on_tc_skip(tc_auto_skip, Data1); {skipped,_} -> - ct_hooks:on_tc_skip(tc_user_skip, Data); + ct_hooks:on_tc_skip(tc_user_skip, Data1); {auto_skipped,_} -> - ct_hooks:on_tc_skip(tc_auto_skip, Data); + ct_hooks:on_tc_skip(tc_auto_skip, Data1); _Else -> ok end, - case {Case,Result} of + case {Func,Result} of {init_per_suite,_} -> ok; {end_per_suite,_} -> @@ -1327,20 +1334,17 @@ report(What,Data) -> tc_user_skip -> %% test case or config function specified as skipped in testspec, %% or init config func for suite/group has returned {skip,Reason} - %% Data = {Suite,Case,Comment} | - %% {Suite,{GroupConfigFunc,GroupName},Comment} + %% Data = {Suite,{Func,GroupName},Comment} {Func,Data1} = case Data of - {Suite,{ConfigFunc,undefined},Cmt} -> - {ConfigFunc,{Suite,ConfigFunc,Cmt}}; - {_,{ConfigFunc,_},_} -> {ConfigFunc,Data}; - {_,Case,_} -> {Case,Data} + {Suite,{F,undefined},Comment} -> + {F,{Suite,F,Comment}}; + D = {_,{F,_},_} -> + {F,D} end, - ct_event:sync_notify(#event{name=tc_user_skip, node=node(), data=Data1}), ct_hooks:on_tc_skip(What, Data1), - if Func /= init_per_suite, Func /= init_per_group, Func /= end_per_suite, Func /= end_per_group -> add_to_stats(user_skipped); @@ -1350,13 +1354,12 @@ report(What,Data) -> tc_auto_skip -> %% test case skipped because of error in config function, or %% config function skipped because of error in info function - %% Data = {Suite,Case,Comment} | - %% {Suite,{GroupConfigFunc,GroupName},Comment} + %% Data = {Suite,{Func,GroupName},Comment} {Func,Data1} = case Data of - {Suite,{ConfigFunc,undefined},Cmt} -> - {ConfigFunc,{Suite,ConfigFunc,Cmt}}; - {_,{ConfigFunc,_},_} -> {ConfigFunc,Data}; - {_,Case,_} -> {Case,Data} + {Suite,{F,undefined},Comment} -> + {F,{Suite,F,Comment}}; + D = {_,{F,_},_} -> + {F,D} end, %% this test case does not have a log, so printouts %% from event handlers should end up in the main log @@ -1364,7 +1367,6 @@ report(What,Data) -> node=node(), data=Data1}), ct_hooks:on_tc_skip(What, Data1), - if Func /= end_per_suite, Func /= end_per_group -> add_to_stats(auto_skipped); diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl index e845e9e908..2e667030a9 100644 --- a/lib/common_test/src/ct_hooks.erl +++ b/lib/common_test/src/ct_hooks.erl @@ -121,9 +121,11 @@ end_tc(_Mod, TC, Config, Result, _Return) -> call(fun call_generic/3, Result, [post_end_per_testcase, TC, Config], '$ct_no_change'). +%% Case = TestCase | {TestCase,GroupName} on_tc_skip(How, {Suite, Case, Reason}) -> call(fun call_cleanup/3, {How, Reason}, [on_tc_skip, Suite, Case]). +%% Case = TestCase | {TestCase,GroupName} on_tc_fail(_How, {Suite, Case, Reason}) -> call(fun call_cleanup/3, Reason, [on_tc_fail, Suite, Case]). diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 7c797be03e..03cf06abed 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -71,6 +71,7 @@ enable_builtin_hooks, include = [], auto_compile, + abort_if_missing_suites, silent_connections = [], stylesheet, multiply_timetraps = 1, @@ -246,9 +247,11 @@ script_start1(Parent, Args) -> Vts = get_start_opt(vts, true, Args), Shell = get_start_opt(shell, true, Args), Cover = get_start_opt(cover, fun([CoverFile]) -> ?abs(CoverFile) end, Args), - CoverStop = get_start_opt(cover_stop, fun([CS]) -> list_to_atom(CS) end, Args), + CoverStop = get_start_opt(cover_stop, + fun([CS]) -> list_to_atom(CS) end, Args), LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args), - LogOpts = get_start_opt(logopts, fun(Os) -> [list_to_atom(O) || O <- Os] end, + LogOpts = get_start_opt(logopts, + fun(Os) -> [list_to_atom(O) || O <- Os] end, [], Args), Verbosity = verbosity_args2opts(Args), MultTT = get_start_opt(multiply_timetraps, @@ -311,6 +314,12 @@ script_start1(Parent, Args) -> application:set_env(common_test, auto_compile, false), {false,[]} end, + + %% abort test run if some suites can't be compiled + AbortIfMissing = get_start_opt(abort_if_missing_suites, + fun([]) -> true; + ([Bool]) -> list_to_atom(Bool) + end, false, Args), %% silent connections SilentConns = get_start_opt(silent_connections, @@ -347,6 +356,7 @@ script_start1(Parent, Args) -> ct_hooks = CTHooks, enable_builtin_hooks = EnableBuiltinHooks, auto_compile = AutoCompile, + abort_if_missing_suites = AbortIfMissing, include = IncludeDirs, silent_connections = SilentConns, stylesheet = Stylesheet, @@ -551,6 +561,9 @@ combine_test_opts(TS, Specs, Opts) -> ACBool end, + AbortIfMissing = choose_val(Opts#opts.abort_if_missing_suites, + TSOpts#opts.abort_if_missing_suites), + BasicHtml = case choose_val(Opts#opts.basic_html, TSOpts#opts.basic_html) of @@ -578,6 +591,7 @@ combine_test_opts(TS, Specs, Opts) -> enable_builtin_hooks = EnableBuiltinHooks, stylesheet = Stylesheet, auto_compile = AutoCompile, + abort_if_missing_suites = AbortIfMissing, include = AllInclude, multiply_timetraps = MultTT, scale_timetraps = ScaleTT, @@ -753,6 +767,7 @@ script_usage() -> "\n\t[-verbosity GenVLvl | [CategoryVLvl1 .. CategoryVLvlN]]" "\n\t[-include InclDir1 InclDir2 .. InclDirN]" "\n\t[-no_auto_compile]" + "\n\t[-abort_if_missing_suites]" "\n\t[-multiply_timetraps N]" "\n\t[-scale_timetraps]" "\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" @@ -775,6 +790,7 @@ script_usage() -> "\n\t[-ct_hooks CTHook1 CTHook2 .. CTHookN]" "\n\t[-include InclDir1 InclDir2 .. InclDirN]" "\n\t[-no_auto_compile]" + "\n\t[-abort_if_missing_suites]" "\n\t[-multiply_timetraps N]" "\n\t[-scale_timetraps]" "\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" @@ -799,6 +815,7 @@ script_usage() -> "\n\t[-ct_hooks CTHook1 CTHook2 .. CTHookN]" "\n\t[-include InclDir1 InclDir2 .. InclDirN]" "\n\t[-no_auto_compile]" + "\n\t[-abort_if_missing_suites]" "\n\t[-multiply_timetraps N]" "\n\t[-scale_timetraps]" "\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]" @@ -1026,6 +1043,10 @@ run_test2(StartOpts) -> {ACBool,[]} end, + %% abort test run if some suites can't be compiled + AbortIfMissing = get_start_opt(abort_if_missing_suites, value, false, + StartOpts), + %% decrypt config file case proplists:get_value(decrypt, StartOpts) of undefined -> @@ -1067,6 +1088,7 @@ run_test2(StartOpts) -> ct_hooks = CTHooks, enable_builtin_hooks = EnableBuiltinHooks, auto_compile = AutoCompile, + abort_if_missing_suites = AbortIfMissing, include = Include, silent_connections = SilentConns, stylesheet = Stylesheet, @@ -1401,6 +1423,7 @@ get_data_for_node(#testspec{label = Labels, ct_hooks = CTHooks, enable_builtin_hooks = EnableBuiltinHooks, auto_compile = ACs, + abort_if_missing_suites = AiMSs, include = Incl, multiply_timetraps = MTs, scale_timetraps = STs, @@ -1435,6 +1458,7 @@ get_data_for_node(#testspec{label = Labels, EvHandlers = [{H,A} || {N,H,A} <- EvHs, N==Node], FiltCTHooks = [Hook || {N,Hook} <- CTHooks, N==Node], AutoCompile = proplists:get_value(Node, ACs), + AbortIfMissing = proplists:get_value(Node, AiMSs), Include = [I || {N,I} <- Incl, N==Node], #opts{label = Label, profile = Profile, @@ -1451,6 +1475,7 @@ get_data_for_node(#testspec{label = Labels, ct_hooks = FiltCTHooks, enable_builtin_hooks = EnableBuiltinHooks, auto_compile = AutoCompile, + abort_if_missing_suites = AbortIfMissing, include = Include, multiply_timetraps = MT, scale_timetraps = ST, @@ -1722,8 +1747,8 @@ compile_and_run(Tests, Skip, Opts, Args) -> {SuiteErrs,HelpErrs} = auto_compile(TestSuites), {TestSuites,SuiteErrs,SuiteErrs++HelpErrs} end, - - case continue(AllMakeErrors) of + + case continue(AllMakeErrors, Opts#opts.abort_if_missing_suites) of true -> SavedErrors = save_make_errors(SuiteMakeErrors), ct_repeat:log_loop_info(Args), @@ -2047,9 +2072,9 @@ final_skip([Skip|Skips], Final) -> final_skip([], Final) -> lists:reverse(Final). -continue([]) -> +continue([], _) -> true; -continue(_MakeErrors) -> +continue(_MakeErrors, AbortIfMissingSuites) -> io:nl(), OldGl = group_leader(), case set_group_leader_same_as_shell() of @@ -2077,26 +2102,26 @@ continue(_MakeErrors) -> true end; false -> % no shell process to use - true + not AbortIfMissingSuites end. set_group_leader_same_as_shell() -> %%! Locate the shell process... UGLY!!! GS2or3 = fun(P) -> - case process_info(P,initial_call) of - {initial_call,{group,server,X}} when X == 2 ; X == 3 -> - true; - _ -> - false - end - end, + case process_info(P,initial_call) of + {initial_call,{group,server,X}} when X == 2 ; X == 3 -> + true; + _ -> + false + end + end, case [P || P <- processes(), GS2or3(P), - true == lists:keymember(shell,1, - element(2,process_info(P,dictionary)))] of - [GL|_] -> - group_leader(GL, self()); - [] -> - false + true == lists:keymember(shell,1, + element(2,process_info(P,dictionary)))] of + [GL|_] -> + group_leader(GL, self()); + [] -> + false end. check_and_add([{TestDir0,M,_} | Tests], Added, PA) -> diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl index c07ea323e6..10a9bdac67 100644 --- a/lib/common_test/src/ct_testspec.erl +++ b/lib/common_test/src/ct_testspec.erl @@ -1120,8 +1120,9 @@ should_be_added(Tag,Node,_Data,Spec) -> %% list terms *without* possible duplicates here Tag == logdir; Tag == logopts; Tag == basic_html; Tag == label; - Tag == auto_compile; Tag == stylesheet; - Tag == verbosity; Tag == silent_connections -> + Tag == auto_compile; Tag == abort_if_missing_suites; + Tag == stylesheet; Tag == verbosity; + Tag == silent_connections -> lists:keymember(ref2node(Node,Spec#testspec.nodes),1, read_field(Spec,Tag)) == false; %% for terms *with* possible duplicates @@ -1496,6 +1497,8 @@ valid_terms() -> {include,3}, {auto_compile,2}, {auto_compile,3}, + {abort_if_missing_suites,2}, + {abort_if_missing_suites,3}, {stylesheet,2}, {stylesheet,3}, {suites,3}, diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl index a82d58cc42..845bb55486 100644 --- a/lib/common_test/src/ct_util.hrl +++ b/lib/common_test/src/ct_util.hrl @@ -48,6 +48,7 @@ release_shell=false, include=[], auto_compile=[], + abort_if_missing_suites=[], stylesheet=[], multiply_timetraps=[], scale_timetraps=[], diff --git a/lib/common_test/test/ct_config_info_SUITE.erl b/lib/common_test/test/ct_config_info_SUITE.erl index 8f2f0eb75f..9c242a41df 100644 --- a/lib/common_test/test/ct_config_info_SUITE.erl +++ b/lib/common_test/test/ct_config_info_SUITE.erl @@ -125,7 +125,7 @@ test_events(config_info) -> [{?eh,tc_start,{config_info_1_SUITE,{init_per_group,g1,[]}}}, {?eh,tc_done,{config_info_1_SUITE,{init_per_group,g1,[]}, {failed,{timetrap_timeout,350}}}}, - {?eh,tc_auto_skip,{config_info_1_SUITE,t11, + {?eh,tc_auto_skip,{config_info_1_SUITE,{t11,g1}, {failed,{config_info_1_SUITE,init_per_group,{timetrap_timeout,350}}}}}, {?eh,tc_auto_skip,{config_info_1_SUITE,{end_per_group,g1}, {failed,{config_info_1_SUITE,init_per_group, @@ -142,7 +142,7 @@ test_events(config_info) -> [{?eh,tc_start,{config_info_1_SUITE,{init_per_group,g4,[]}}}, {?eh,tc_done,{config_info_1_SUITE,{init_per_group,g4,[]}, {failed,{timetrap_timeout,400}}}}, - {?eh,tc_auto_skip,{config_info_1_SUITE,t41, + {?eh,tc_auto_skip,{config_info_1_SUITE,{t41,g4}, {failed,{config_info_1_SUITE,init_per_group, {timetrap_timeout,400}}}}}, {?eh,tc_auto_skip,{config_info_1_SUITE,{end_per_group,g4}, diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl index 194e7d42ae..ecf231529a 100644 --- a/lib/common_test/test/ct_error_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE.erl @@ -369,8 +369,8 @@ test_events(cfg_error) -> {'EXIT',init_per_suite_fails}}}}}, {?eh,test_stats,{0,0,{0,1}}}, {?eh,tc_auto_skip, - {cfg_error_1_SUITE,tc2,{failed,{cfg_error_1_SUITE,init_per_suite, - {'EXIT',init_per_suite_fails}}}}}, + {cfg_error_1_SUITE,{tc2,g1},{failed,{cfg_error_1_SUITE,init_per_suite, + {'EXIT',init_per_suite_fails}}}}}, {?eh,test_stats,{0,0,{0,2}}}, {?eh,tc_auto_skip, {cfg_error_1_SUITE,end_per_suite,{failed,{cfg_error_1_SUITE,init_per_suite, @@ -386,7 +386,7 @@ test_events(cfg_error) -> {'EXIT',{{badmatch,[1,2]},'_'}}}}}}, {?eh,test_stats,{0,0,{0,3}}}, {?eh,tc_auto_skip, - {cfg_error_2_SUITE,tc2, + {cfg_error_2_SUITE,{tc2,g1}, {failed,{cfg_error_2_SUITE,init_per_suite, {'EXIT',{{badmatch,[1,2]},'_'}}}}}}, {?eh,test_stats,{0,0,{0,4}}}, @@ -403,7 +403,7 @@ test_events(cfg_error) -> {failed,{cfg_error_3_SUITE,init_per_suite,{timetrap_timeout,2000}}}}}, {?eh,test_stats,{0,0,{0,5}}}, {?eh,tc_auto_skip, - {cfg_error_3_SUITE,tc2, + {cfg_error_3_SUITE,{tc2,g1}, {failed,{cfg_error_3_SUITE,init_per_suite,{timetrap_timeout,2000}}}}}, {?eh,test_stats,{0,0,{0,6}}}, {?eh,tc_auto_skip, @@ -417,7 +417,7 @@ test_events(cfg_error) -> {failed,{cfg_error_4_SUITE,init_per_suite,bad_return}}}}, {?eh,test_stats,{0,0,{0,7}}}, {?eh,tc_auto_skip, - {cfg_error_4_SUITE,tc2, + {cfg_error_4_SUITE,{tc2,g1}, {failed,{cfg_error_4_SUITE,init_per_suite,bad_return}}}}, {?eh,test_stats,{0,0,{0,8}}}, {?eh,tc_auto_skip, @@ -431,7 +431,7 @@ test_events(cfg_error) -> {failed,{cfg_error_5_SUITE,init_per_suite,bad_return}}}}, {?eh,test_stats,{0,0,{0,9}}}, {?eh,tc_auto_skip, - {cfg_error_5_SUITE,tc2, + {cfg_error_5_SUITE,{tc2,g1}, {failed,{cfg_error_5_SUITE,init_per_suite,bad_return}}}}, {?eh,test_stats,{0,0,{0,10}}}, {?eh,tc_auto_skip, @@ -477,7 +477,7 @@ test_events(cfg_error) -> {cfg_error_8_SUITE,{init_per_group,g1,[]}, {failed,{error,{init_per_group_fails,g1}}}}}, {?eh,tc_auto_skip, - {cfg_error_8_SUITE,tc1, + {cfg_error_8_SUITE,{tc1,g1}, {failed,{cfg_error_8_SUITE,init_per_group, {'EXIT',{init_per_group_fails,g1}}}}}}, {?eh,test_stats,{4,0,{0,11}}}, @@ -489,7 +489,7 @@ test_events(cfg_error) -> [{?eh,tc_start,{cfg_error_8_SUITE,{init_per_group,g2,[]}}}, {?eh,tc_done,{cfg_error_8_SUITE,{init_per_group,g2,[]}, {failed,{timetrap_timeout,2000}}}}, - {?eh,tc_auto_skip,{cfg_error_8_SUITE,tc1, + {?eh,tc_auto_skip,{cfg_error_8_SUITE,{tc1,g2}, {failed,{cfg_error_8_SUITE,init_per_group, {timetrap_timeout,2000}}}}}, {?eh,test_stats,{4,0,{0,12}}}, @@ -502,7 +502,7 @@ test_events(cfg_error) -> {cfg_error_8_SUITE,{init_per_group,g3,[]}, {failed,{error,{{badmatch,42},'_'}}}}}, {?eh,tc_auto_skip, - {cfg_error_8_SUITE,tc1, + {cfg_error_8_SUITE,{tc1,g3}, {failed,{cfg_error_8_SUITE,init_per_group, {'EXIT',{{badmatch,42},'_'}}}}}}, {?eh,test_stats,{4,0,{0,13}}}, @@ -528,7 +528,7 @@ test_events(cfg_error) -> {?eh,tc_done,{cfg_error_8_SUITE,{init_per_group,g6,[]}, {failed,{error,{sub_group_failed,g6}}}}}, {?eh,tc_auto_skip, - {cfg_error_8_SUITE,tc2, + {cfg_error_8_SUITE,{tc2,g6}, {failed,{cfg_error_8_SUITE,init_per_group, {'EXIT',{sub_group_failed,g6}}}}}}, {?eh,test_stats,{6,0,{0,14}}}, @@ -1111,11 +1111,11 @@ test_events(timetrap_fun_group) -> [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g4,[]}}}, {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g4,[]}, {user_timetrap_error,{kaboom,'_'}}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc0,g4}, {failed,{timetrap_8_SUITE,init_per_group, {user_timetrap_error,{kaboom,'_'}}}}}}, {?eh,test_stats,{0,11,{0,1}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc2,g4}, {failed,{timetrap_8_SUITE,init_per_group, {user_timetrap_error,{kaboom,'_'}}}}}}, {?eh,test_stats,{0,11,{0,2}}}, @@ -1126,11 +1126,11 @@ test_events(timetrap_fun_group) -> [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g5,[]}}}, {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g5,[]}, {user_timetrap_error,{kaboom,'_'}}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc0,g5}, {failed,{timetrap_8_SUITE,init_per_group, {user_timetrap_error,{kaboom,'_'}}}}}}, {?eh,test_stats,{0,11,{0,3}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc2,g5}, {failed,{timetrap_8_SUITE,init_per_group, {user_timetrap_error,{kaboom,'_'}}}}}}, {?eh,test_stats,{0,11,{0,4}}}, @@ -1141,11 +1141,11 @@ test_events(timetrap_fun_group) -> [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,g6,[]}}}, {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,g6,[]}, {failed,{timetrap_timeout,{'$approx',500}}}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc0,g6}, {failed,{timetrap_8_SUITE,init_per_group, {timetrap_timeout,'_'}}}}}, {?eh,test_stats,{0,11,{0,5}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc2,g6}, {failed,{timetrap_8_SUITE,init_per_group, {timetrap_timeout,'_'}}}}}, {?eh,test_stats,{0,11,{0,6}}}, @@ -1294,11 +1294,11 @@ test_events(timetrap_fun_group) -> [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg4,[parallel]}}}, {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg4,[parallel]}, {user_timetrap_error,{kaboom,'_'}}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc0,pg4}, {failed,{timetrap_8_SUITE,init_per_group, {user_timetrap_error,{kaboom,'_'}}}}}}, {?eh,test_stats,{4,26,{0,7}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc2,pg4}, {failed,{timetrap_8_SUITE,init_per_group, {user_timetrap_error,{kaboom,'_'}}}}}}, {?eh,test_stats,{4,26,{0,8}}}, @@ -1310,11 +1310,11 @@ test_events(timetrap_fun_group) -> [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg5,[parallel]}}}, {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg5,[parallel]}, {user_timetrap_error,{kaboom,'_'}}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc0,pg5}, {failed,{timetrap_8_SUITE,init_per_group, {user_timetrap_error,{kaboom,'_'}}}}}}, {?eh,test_stats,{4,26,{0,9}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc2,pg5}, {failed,{timetrap_8_SUITE,init_per_group, {user_timetrap_error,{kaboom,'_'}}}}}}, {?eh,test_stats,{4,26,{0,10}}}, @@ -1326,11 +1326,11 @@ test_events(timetrap_fun_group) -> [{?eh,tc_start,{timetrap_8_SUITE,{init_per_group,pg6,[parallel]}}}, {?eh,tc_done,{timetrap_8_SUITE,{init_per_group,pg6,[parallel]}, {failed,{timetrap_timeout,{'$approx',500}}}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc0, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc0,pg6}, {failed,{timetrap_8_SUITE,init_per_group, {timetrap_timeout,'_'}}}}}, {?eh,test_stats,{4,26,{0,11}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc2,pg6}, {failed,{timetrap_8_SUITE,init_per_group, {timetrap_timeout,'_'}}}}}, {?eh,test_stats,{4,26,{0,12}}}, @@ -1407,10 +1407,10 @@ test_events(timetrap_fun_group) -> {?eh,tc_done,{timetrap_8_SUITE,tc0, {user_timetrap_error,{kaboom,'_'}}}}, {?eh,test_stats,{9,31,{0,12}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc1, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc1,sg1}, {failed,{timetrap_8_SUITE,tc0}}}}, {?eh,test_stats,{9,31,{0,13}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc2,sg1}, {failed,{timetrap_8_SUITE,tc0}}}}, {?eh,test_stats,{9,31,{0,14}}}, {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,sg1,[sequence]}}}, @@ -1425,10 +1425,10 @@ test_events(timetrap_fun_group) -> {?eh,tc_done,{timetrap_8_SUITE,tc0, {failed,{timetrap_timeout,{'$approx',1000}}}}}, {?eh,test_stats,{10,32,{0,14}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc1, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc1,sg2}, {failed,{timetrap_8_SUITE,tc0}}}}, {?eh,test_stats,{10,32,{0,15}}}, - {?eh,tc_auto_skip,{timetrap_8_SUITE,tc2, + {?eh,tc_auto_skip,{timetrap_8_SUITE,{tc2,sg2}, {failed,{timetrap_8_SUITE,tc0}}}}, {?eh,test_stats,{10,32,{0,16}}}, {?eh,tc_start,{timetrap_8_SUITE,{end_per_group,sg2,[sequence]}}}, diff --git a/lib/common_test/test/ct_group_info_SUITE.erl b/lib/common_test/test/ct_group_info_SUITE.erl index e7bc5baaa1..83ac7dbbcf 100644 --- a/lib/common_test/test/ct_group_info_SUITE.erl +++ b/lib/common_test/test/ct_group_info_SUITE.erl @@ -273,7 +273,7 @@ test_events(timetrap_all) -> {init_per_group,g11,[]}, {auto_skipped,{group0_failed,bad_return_value}}}}, {?eh,tc_auto_skip, - {group_timetrap_1_SUITE,t111,{group0_failed,bad_return_value}}}, + {group_timetrap_1_SUITE,{t111,g11},{group0_failed,bad_return_value}}}, {?eh,test_stats,{0,13,{0,1}}}, {?eh,tc_auto_skip,{group_timetrap_1_SUITE, {end_per_group,g11}, @@ -431,7 +431,7 @@ test_events(timetrap_all_no_ips) -> {?eh,tc_done,{group_timetrap_2_SUITE, {init_per_group,g11,[]}, {auto_skipped,{group0_failed,bad_return_value}}}}, - {?eh,tc_auto_skip,{group_timetrap_2_SUITE,t111, + {?eh,tc_auto_skip,{group_timetrap_2_SUITE,{t111,g11}, {group0_failed,bad_return_value}}}, {?eh,test_stats,{0,13,{0,1}}}, {?eh,tc_auto_skip,{group_timetrap_2_SUITE, @@ -512,7 +512,7 @@ test_events(timetrap_all_no_ipg) -> {?eh,tc_done,{ct_framework, {init_per_group,g11,[{suite,group_timetrap_3_SUITE}]}, {auto_skipped,{group0_failed,bad_return_value}}}}, - {?eh,tc_auto_skip,{group_timetrap_3_SUITE,t111,{group0_failed,bad_return_value}}}, + {?eh,tc_auto_skip,{group_timetrap_3_SUITE,{t111,g11},{group0_failed,bad_return_value}}}, {?eh,test_stats,{0,13,{0,1}}}, {?eh,tc_auto_skip,{ct_framework,{end_per_group,g11}, {group0_failed,bad_return_value}}}], @@ -551,7 +551,7 @@ test_events(require) -> {?eh,tc_done,{group_require_1_SUITE,{init_per_group,g4,[]}, {auto_skipped,{require_failed, {name_in_use,common2_alias,common2}}}}}, - {?eh,tc_auto_skip,{group_require_1_SUITE,t41, + {?eh,tc_auto_skip,{group_require_1_SUITE,{t41,g4}, {require_failed, {name_in_use,common2_alias,common2}}}}, {?eh,test_stats,{4,0,{0,1}}}, @@ -580,7 +580,7 @@ test_events(require) -> {init_per_group,g8,[]}, {auto_skipped,{require_failed, {not_available,non_existing}}}}}, - {?eh,tc_auto_skip,{group_require_1_SUITE,t81, + {?eh,tc_auto_skip,{group_require_1_SUITE,{t81,g8}, {require_failed,{not_available,non_existing}}}}, {?eh,test_stats,{8,0,{0,2}}}, {?eh,tc_auto_skip,{group_require_1_SUITE,{end_per_group,g8}, @@ -604,7 +604,7 @@ test_events(require) -> {?eh,tc_done,{group_require_1_SUITE, {init_per_group,g11,[]}, {auto_skipped,{group0_failed,bad_return_value}}}}, - {?eh,tc_auto_skip,{group_require_1_SUITE,t111, + {?eh,tc_auto_skip,{group_require_1_SUITE,{t111,g11}, {group0_failed,bad_return_value}}}, {?eh,test_stats,{9,0,{0,4}}}, {?eh,tc_auto_skip,{group_require_1_SUITE, @@ -646,7 +646,7 @@ test_events(require_default) -> {?eh,tc_done,{group_require_1_SUITE, {init_per_group,g4,[]}, {auto_skipped,{require_failed,{not_available,common3}}}}}, - {?eh,tc_auto_skip,{group_require_1_SUITE,t41, + {?eh,tc_auto_skip,{group_require_1_SUITE,{t41,g4}, {require_failed,{not_available,common3}}}}, {?eh,test_stats,{4,0,{0,1}}}, {?eh,tc_auto_skip,{group_require_1_SUITE,{end_per_group,g4}, @@ -674,7 +674,7 @@ test_events(require_default) -> {init_per_group,g8,[]}, {auto_skipped,{require_failed, {not_available,non_existing}}}}}, - {?eh,tc_auto_skip,{group_require_1_SUITE,t81, + {?eh,tc_auto_skip,{group_require_1_SUITE,{t81,g8}, {require_failed,{not_available,non_existing}}}}, {?eh,test_stats,{8,0,{0,2}}}, {?eh,tc_auto_skip,{group_require_1_SUITE,{end_per_group,g8}, @@ -699,7 +699,7 @@ test_events(require_default) -> {?eh,tc_done,{group_require_1_SUITE, {init_per_group,g11,[]}, {auto_skipped,{group0_failed,bad_return_value}}}}, - {?eh,tc_auto_skip,{group_require_1_SUITE,t111, + {?eh,tc_auto_skip,{group_require_1_SUITE,{t111,g11}, {group0_failed,bad_return_value}}}, {?eh,test_stats,{9,0,{0,4}}}, {?eh,tc_auto_skip,{group_require_1_SUITE, @@ -740,7 +740,7 @@ test_events(require_no_ips) -> {?eh,tc_done,{group_require_2_SUITE,{init_per_group,g4,[]}, {auto_skipped,{require_failed, {name_in_use,common2_alias,common2}}}}}, - {?eh,tc_auto_skip,{group_require_2_SUITE,t41, + {?eh,tc_auto_skip,{group_require_2_SUITE,{t41,g4}, {require_failed,{name_in_use,common2_alias,common2}}}}, {?eh,test_stats,{4,0,{0,1}}}, {?eh,tc_auto_skip,{group_require_2_SUITE,{end_per_group,g4}, @@ -768,7 +768,7 @@ test_events(require_no_ips) -> {init_per_group,g8,[]}, {auto_skipped,{require_failed, {not_available,non_existing}}}}}, - {?eh,tc_auto_skip,{group_require_2_SUITE,t81, + {?eh,tc_auto_skip,{group_require_2_SUITE,{t81,g8}, {require_failed,{not_available,non_existing}}}}, {?eh,test_stats,{8,0,{0,2}}}, {?eh,tc_auto_skip,{group_require_2_SUITE,{end_per_group,g8}, @@ -792,7 +792,7 @@ test_events(require_no_ips) -> {?eh,tc_done,{group_require_2_SUITE, {init_per_group,g11,[]}, {auto_skipped,{group0_failed,bad_return_value}}}}, - {?eh,tc_auto_skip,{group_require_2_SUITE,t111, + {?eh,tc_auto_skip,{group_require_2_SUITE,{t111,g11}, {group0_failed,bad_return_value}}}, {?eh,test_stats,{9,0,{0,4}}}, {?eh,tc_auto_skip,{group_require_2_SUITE, @@ -831,7 +831,7 @@ test_events(require_no_ipg) -> [{?eh,tc_start,{ct_framework,{init_per_group,g4,[{suite,group_require_3_SUITE}]}}}, {?eh,tc_done,{ct_framework,{init_per_group,g4,[{suite,group_require_3_SUITE}]}, {auto_skipped,{require_failed,{name_in_use,common2_alias,common2}}}}}, - {?eh,tc_auto_skip,{group_require_3_SUITE,t41, + {?eh,tc_auto_skip,{group_require_3_SUITE,{t41,g4}, {require_failed,{name_in_use,common2_alias,common2}}}}, {?eh,test_stats,{4,0,{0,1}}}, {?eh,tc_auto_skip,{ct_framework,{end_per_group,g4}, @@ -857,7 +857,7 @@ test_events(require_no_ipg) -> [{?eh,tc_start,{ct_framework,{init_per_group,g8,[{suite,group_require_3_SUITE}]}}}, {?eh,tc_done,{ct_framework,{init_per_group,g8,[{suite,group_require_3_SUITE}]}, {auto_skipped,{require_failed,{not_available,non_existing}}}}}, - {?eh,tc_auto_skip,{group_require_3_SUITE,t81, + {?eh,tc_auto_skip,{group_require_3_SUITE,{t81,g8}, {require_failed,{not_available,non_existing}}}}, {?eh,test_stats,{8,0,{0,2}}}, {?eh,tc_auto_skip,{ct_framework,{end_per_group,g8}, @@ -879,7 +879,7 @@ test_events(require_no_ipg) -> [{?eh,tc_start,{ct_framework,{init_per_group,g11,[{suite,group_require_3_SUITE}]}}}, {?eh,tc_done,{ct_framework,{init_per_group,g11,[{suite,group_require_3_SUITE}]}, {auto_skipped,{group0_failed,bad_return_value}}}}, - {?eh,tc_auto_skip,{group_require_3_SUITE,t111,{group0_failed,bad_return_value}}}, + {?eh,tc_auto_skip,{group_require_3_SUITE,{t111,g11},{group0_failed,bad_return_value}}}, {?eh,test_stats,{9,0,{0,4}}}, {?eh,tc_auto_skip,{ct_framework,{end_per_group,g11}, {group0_failed,bad_return_value}}}], diff --git a/lib/common_test/test/ct_groups_spec_SUITE.erl b/lib/common_test/test/ct_groups_spec_SUITE.erl index 5a6d5ac0ac..de4ab77229 100644 --- a/lib/common_test/test/ct_groups_spec_SUITE.erl +++ b/lib/common_test/test/ct_groups_spec_SUITE.erl @@ -246,7 +246,8 @@ test_events(override_with_all) -> {?eh,tc_done,{groups_spec_1_SUITE,{init_per_group,g1,[sequence]},ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t11,ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t12,{failed,{error,crashes}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t13,{failed,{groups_spec_1_SUITE,t12}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t13,g1}, + {failed,{groups_spec_1_SUITE,t12}}}}, {?eh,test_stats,{3,2,{0,1}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g1,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{end_per_group,g1,[sequence]},ok}}], @@ -327,19 +328,27 @@ test_events(override_with_all) -> {?eh,tc_done,{groups_spec_1_SUITE,{init_per_group,g3,[sequence]},ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t31,ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t32,{failed,{error,crashes}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t33,{failed,{groups_spec_1_SUITE,t32}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t33,g3}, + {failed,{groups_spec_1_SUITE,t32}}}}, {?eh,test_stats,{14,9,{0,2}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g3,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{end_per_group,g3,[sequence]},ok}}], {?eh,tc_done,{groups_spec_1_SUITE,t22,{failed,{error,crashes}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t41,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t51,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t52,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t53,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t54,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t42,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t23,{failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t41,g4}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t51,g5}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t52,g5}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t53,g5}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t54,g5}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t42,g4}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t23,g2}, + {failed,{groups_spec_1_SUITE,t22}}}}, {?eh,test_stats,{14,10,{0,9}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g2,[sequence]}}}, @@ -355,7 +364,8 @@ test_events(override_with_all) -> {?eh,tc_done,{groups_spec_1_SUITE,{init_per_group,g3,[sequence]},ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t31,ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t32,{failed,{error,crashes}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t33,{failed,{groups_spec_1_SUITE,t32}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t33,g3}, + {failed,{groups_spec_1_SUITE,t32}}}}, {?eh,test_stats,{16,11,{0,10}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g3,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{end_per_group,g3,[sequence]},ok}}], @@ -372,8 +382,10 @@ test_events(override_with_all) -> {?eh,tc_done,{groups_spec_1_SUITE,{init_per_group,g5,[sequence]},ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t51,ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t52,{failed,{timetrap_timeout,2000}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t53,{failed,{groups_spec_1_SUITE,t52}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t54,{failed,{groups_spec_1_SUITE,t52}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t53,g5}, + {failed,{groups_spec_1_SUITE,t52}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t54,g5}, + {failed,{groups_spec_1_SUITE,t52}}}}, {?eh,test_stats,{18,13,{0,12}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g5,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{end_per_group,g5,[sequence]},ok}}], @@ -417,7 +429,8 @@ test_events(override_with_spec) -> {?eh,tc_done,{groups_spec_1_SUITE,{init_per_group,g1,[sequence]},ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t11,ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t12,{failed,{error,crashes}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t13,{failed,{groups_spec_1_SUITE,t12}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t13,g1}, + {failed,{groups_spec_1_SUITE,t12}}}}, {?eh,test_stats,{3,2,{0,1}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g1,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{end_per_group,g1,[sequence]},ok}}], @@ -493,18 +506,26 @@ test_events(override_with_spec) -> {?eh,tc_done,{groups_spec_1_SUITE,{init_per_group,g3,[sequence]},ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t31,ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t32,{failed,{error,crashes}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t33,{failed,{groups_spec_1_SUITE,t32}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t33,g3}, + {failed,{groups_spec_1_SUITE,t32}}}}, {?eh,test_stats,{14,9,{0,2}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g3,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{end_per_group,g3,[sequence]},ok}}], {?eh,tc_done,{groups_spec_1_SUITE,t22,{failed,{error,crashes}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t41,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t51,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t52,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t53,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t54,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t42,{failed,{groups_spec_1_SUITE,t22}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t23,{failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t41,g4}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t51,g5}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t52,g5}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t53,g5}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t54,g5}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t42,g4}, + {failed,{groups_spec_1_SUITE,t22}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t23,g2}, + {failed,{groups_spec_1_SUITE,t22}}}}, {?eh,test_stats,{14,10,{0,9}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g2,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{end_per_group,g2,[sequence]},ok}}], @@ -521,7 +542,8 @@ test_events(override_with_spec) -> {?eh,tc_done,{groups_spec_1_SUITE,{init_per_group,g3,[sequence]},ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t31,ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t32,{failed,{error,crashes}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t33,{failed,{groups_spec_1_SUITE,t32}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t33,g3}, + {failed,{groups_spec_1_SUITE,t32}}}}, {?eh,test_stats,{16,11,{0,10}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g3,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{end_per_group,g3,[sequence]},ok}}], @@ -535,8 +557,10 @@ test_events(override_with_spec) -> {?eh,tc_done,{groups_spec_1_SUITE,{init_per_group,g5,[sequence]},ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t51,ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t52,{failed,{timetrap_timeout,2000}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t53,{failed,{groups_spec_1_SUITE,t52}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t54,{failed,{groups_spec_1_SUITE,t52}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t53,g5}, + {failed,{groups_spec_1_SUITE,t52}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t54,g5}, + {failed,{groups_spec_1_SUITE,t52}}}}, {?eh,test_stats,{18,13,{0,12}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g5,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{end_per_group,g5,[sequence]},ok}}], @@ -555,7 +579,8 @@ test_events(override_with_spec) -> [{?eh,tc_start,{groups_spec_1_SUITE,{init_per_group,g1,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{init_per_group,g1,[sequence]},ok}}, {?eh,tc_done,{groups_spec_1_SUITE,t12,{failed,{error,crashes}}}}, - {?eh,tc_auto_skip,{groups_spec_1_SUITE,t13,{failed,{groups_spec_1_SUITE,t12}}}}, + {?eh,tc_auto_skip,{groups_spec_1_SUITE,{t13,g1}, + {failed,{groups_spec_1_SUITE,t12}}}}, {?eh,test_stats,{19,15,{0,13}}}, {?eh,tc_start,{groups_spec_1_SUITE,{end_per_group,g1,[sequence]}}}, {?eh,tc_done,{groups_spec_1_SUITE,{end_per_group,g1,[sequence]},ok}}], diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl index b5855da9df..c8fc4bd59b 100644 --- a/lib/common_test/test/ct_hooks_SUITE.erl +++ b/lib/common_test/test/ct_hooks_SUITE.erl @@ -786,7 +786,7 @@ test_events(skip_pre_end_cth) -> {?eh,cth,{'_',post_end_per_group,[group1,'$proplist','_',[]]}}, {?eh,tc_done,{ct_scope_per_group_cth_SUITE,{end_per_group,group1,[]}, {skipped,"Test skip"}}}], - {?eh,cth,{'_',on_tc_skip,[end_per_group, + {?eh,cth,{'_',on_tc_skip,[{end_per_group,group1}, {tc_user_skip,{skipped,"Test skip"}}, []]}}, {?eh,tc_start,{ct_scope_per_group_cth_SUITE,end_per_suite}}, diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl index 9ee2a90896..6caac7e447 100644 --- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl +++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl @@ -229,9 +229,9 @@ post_end_per_testcase(TC,Config,Return,State) -> %% This function should be used for extra cleanup which might be needed. %% It is not possible to modify the config or the status of the test run. -spec on_tc_fail(TC :: init_per_suite | end_per_suite | - init_per_group | end_per_group | atom(), - Reason :: term(), State :: #state{}) -> - NewState :: #state{}. + init_per_group | end_per_group | atom() | + {Function :: atom(), GroupName :: atom()}, + Reason :: term(), State :: #state{}) -> NewState :: #state{}. on_tc_fail(TC, Reason, State) -> gen_event:notify( ?CT_EVMGR_REF, #event{ name = cth, node = node(), @@ -243,11 +243,11 @@ on_tc_fail(TC, Reason, State) -> %% or due to an init function failing. Test case can be %% end_per_suite, init_per_group, end_per_group and the actual test cases. -spec on_tc_skip(TC :: end_per_suite | - init_per_group | end_per_group | atom(), + init_per_group | end_per_group | atom() | + {Function :: atom(), GroupName :: atom()}, {tc_auto_skip, {failed, {Mod :: atom(), Function :: atom(), Reason :: term()}}} | - {tc_user_skip, {skipped, Reason :: term()}}, - State :: #state{}) -> - NewState :: #state{}. + {tc_user_skip, {skipped, Reason :: term()}}, + State :: #state{}) -> NewState :: #state{}. on_tc_skip(TC, Reason, State) -> gen_event:notify( ?CT_EVMGR_REF, #event{ name = cth, node = node(), diff --git a/lib/common_test/test/ct_repeat_1_SUITE.erl b/lib/common_test/test/ct_repeat_1_SUITE.erl index 98eaa28763..e37aeb196c 100644 --- a/lib/common_test/test/ct_repeat_1_SUITE.erl +++ b/lib/common_test/test/ct_repeat_1_SUITE.erl @@ -225,7 +225,7 @@ test_events(repeat_cs_and_grs) -> {?eh,test_stats,{3,1,{0,0}}}, [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_fail_init,[]}, {failed,{error,fails_on_purpose}}}}, - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_1,gr_fail_init}, {failed,{repeat_1_SUITE,init_per_group, {'EXIT',fails_on_purpose}}}}}, {?eh,test_stats,{3,1,{0,1}}}, @@ -247,7 +247,7 @@ test_events(repeat_cs_and_grs) -> {?eh,test_stats,{7,2,{0,1}}}, [{?eh,tc_done,{repeat_1_SUITE,{init_per_group,gr_fail_init,[]}, {failed,{error,fails_on_purpose}}}}, - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_1,gr_fail_init}, {failed,{repeat_1_SUITE,init_per_group, {'EXIT',fails_on_purpose}}}}}, {?eh,test_stats,{7,2,{0,2}}}, @@ -269,7 +269,7 @@ test_events(repeat_seq) -> ok}}, {?eh,test_stats,{1,0,{0,0}}}, {?eh,test_stats,{1,1,{0,0}}}, - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_2, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_2,repeat_seq_1}, {failed,{repeat_1_SUITE,tc_fail_1}}}}, {?eh,test_stats,{1,1,{0,1}}}, {?eh,tc_done,{repeat_1_SUITE, @@ -291,7 +291,7 @@ test_events(repeat_seq) -> {?eh,tc_done,{repeat_1_SUITE, {end_per_group,gr_fail_result,[]}, {return_group_result,failed}}}], - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_2, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_2,repeat_seq_2}, {group_result,gr_fail_result,failed}}}, {?eh,test_stats,{4,2,{0,3}}}, {?eh,tc_done,{repeat_1_SUITE, @@ -315,7 +315,7 @@ test_events(repeat_seq) -> {failed, {repeat_1_SUITE,init_per_group, {'EXIT',fails_on_purpose}}}}}], - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_2, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_2,repeat_seq_3}, {group_result,gr_fail_init,failed}}}, {?eh,test_stats,{7,2,{0,6}}}, {?eh,tc_done,{repeat_1_SUITE, @@ -329,12 +329,13 @@ test_events(repeat_seq) -> [{?eh,tc_done,{repeat_1_SUITE, {init_per_group,repeat_seq_4,[sequence,{repeat,2}]}, ok}}, + {?eh,tc_done,{repeat_1_SUITE,tc_fail_1,'_'}}, {?eh,test_stats,{8,3,{0,8}}}, - {?eh,tc_auto_skip,{repeat_1_SUITE, - tc_ok_1,{failed,{repeat_1_SUITE,tc_fail_1}}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_1,gr_ok_1}, + {failed,{repeat_1_SUITE,tc_fail_1}}}}, {?eh,test_stats,{8,3,{0,9}}}, - {?eh,tc_auto_skip,{repeat_1_SUITE, - tc_ok_1,{failed,{repeat_1_SUITE,tc_fail_1}}}}, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_1,repeat_seq_4}, + {failed,{repeat_1_SUITE,tc_fail_1}}}}, {?eh,test_stats,{8,3,{0,10}}}, {?eh,tc_done,{repeat_1_SUITE, {end_per_group,repeat_seq_4,[sequence,{repeat,2}]}, @@ -764,7 +765,7 @@ test_events(repeat_gr_until_any_fail) -> {init_per_group,gr_ok_then_fail_init,[]}, {failed,{error,failing_this_time}}}}, {?eh,tc_auto_skip, - {repeat_1_SUITE,tc_ok_1, + {repeat_1_SUITE,{tc_ok_1,gr_ok_then_fail_init}, {failed, {repeat_1_SUITE,init_per_group, {'EXIT',failing_this_time}}}}}, @@ -963,7 +964,7 @@ test_events(repeat_gr_until_all_ok) -> [{?eh,tc_done,{repeat_1_SUITE, {init_per_group,gr_fail_init_then_ok,[]}, {failed,{error,failing_this_time}}}}, - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_1,gr_fail_init_then_ok}, {failed,{repeat_1_SUITE,init_per_group, {'EXIT',failing_this_time}}}}}, {?eh,test_stats,{7,1,{0,1}}}, @@ -1237,10 +1238,10 @@ test_events(repeat_seq_until_any_fail) -> {?eh,tc_done,{repeat_1_SUITE,tc_ok_then_fail_1, {failed,{error,failing_this_time}}}}, {?eh,test_stats,{15,1,{0,0}}}, - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_2, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_2,repeat_seq_until_any_fail_3}, {failed,{repeat_1_SUITE,tc_ok_then_fail_1}}}}, {?eh,test_stats,{15,1,{0,1}}}, - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_1,gr_ok_1}, {failed,{repeat_1_SUITE,tc_ok_then_fail_1}}}}, {?eh,test_stats,{15,1,{0,2}}}, {?eh,tc_done,{repeat_1_SUITE, @@ -1264,10 +1265,10 @@ test_events(repeat_seq_until_any_fail) -> [{?eh,tc_done,{repeat_1_SUITE, {end_per_group,gr_ok_then_fail_result,[]}, {return_group_result,failed}}}], - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_1,gr_ok_1}, {group_result,gr_ok_then_fail_result,failed}}}, {?eh,test_stats,{19,1,{0,3}}}, - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_1,repeat_seq_until_any_fail_4}, {group_result,gr_ok_then_fail_result,failed}}}, {?eh,test_stats,{19,1,{0,4}}}, {?eh,tc_done,{repeat_1_SUITE, @@ -1296,10 +1297,10 @@ test_events(repeat_seq_until_any_fail) -> {?eh,tc_auto_skip,{repeat_1_SUITE,{end_per_group,gr_ok_then_fail_init}, {failed,{repeat_1_SUITE,init_per_group, {'EXIT',failing_this_time}}}}}], - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_1,gr_ok_2}, {group_result,gr_ok_then_fail_init,failed}}}, {?eh,test_stats,{24,1,{0,6}}}, - {?eh,tc_auto_skip,{repeat_1_SUITE,tc_ok_1, + {?eh,tc_auto_skip,{repeat_1_SUITE,{tc_ok_1,repeat_seq_until_any_fail_5}, {group_result,gr_ok_then_fail_init,failed}}}, {?eh,test_stats,{24,1,{0,7}}}, {?eh,tc_done,{repeat_1_SUITE, diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE.erl index bb2aba2c5a..b6f285322d 100644 --- a/lib/common_test/test/ct_repeat_testrun_SUITE.erl +++ b/lib/common_test/test/ct_repeat_testrun_SUITE.erl @@ -343,9 +343,9 @@ skip_first_tc1(Suite) -> {?eh,tc_done,{Suite,tc2,?skipped}}, {?eh,test_stats,{'_',0,{0,1}}}, {?eh,tc_done,{Suite,{init_per_group,g,[]},?skipped}}, - {?eh,tc_auto_skip,{Suite,tc1,?skip_reason}}, + {?eh,tc_auto_skip,{Suite,{tc1,g},?skip_reason}}, {?eh,test_stats,{'_',0,{0,2}}}, - {?eh,tc_auto_skip,{Suite,tc2,?skip_reason}}, + {?eh,tc_auto_skip,{Suite,{tc2,g},?skip_reason}}, {?eh,test_stats,{'_',0,{0,3}}}, {?eh,tc_auto_skip,{Suite,{end_per_group,g},?skip_reason}}, {?eh,tc_done,{Suite,tc2,?skipped}}, diff --git a/lib/common_test/test/ct_sequence_1_SUITE.erl b/lib/common_test/test/ct_sequence_1_SUITE.erl index 8c87236838..5a775a1117 100644 --- a/lib/common_test/test/ct_sequence_1_SUITE.erl +++ b/lib/common_test/test/ct_sequence_1_SUITE.erl @@ -185,7 +185,8 @@ test_events(subgroup_return_fail) -> {?eh,tc_done,{subgroups_1_SUITE,{end_per_group,return_fail,[]}, {return_group_result,failed}}}], {?eh,tc_auto_skip, - {subgroups_1_SUITE,ok_tc,{group_result,return_fail,failed}}}, + {subgroups_1_SUITE,{ok_tc,ok_group}, + {group_result,return_fail,failed}}}, {?eh,test_stats,{0,1,{0,1}}}, {?eh,tc_start, {subgroups_1_SUITE,{end_per_group,subgroup_return_fail,[sequence]}}}, @@ -208,14 +209,15 @@ test_events(subgroup_init_fail) -> [{?eh,tc_start,{subgroups_1_SUITE,{init_per_group,fail_init,[]}}}, {?eh,tc_done,{subgroups_1_SUITE,{init_per_group,fail_init,[]}, {failed,{error,init_per_group_fails_on_purpose}}}}, - {?eh,tc_auto_skip,{subgroups_1_SUITE,ok_tc, + {?eh,tc_auto_skip,{subgroups_1_SUITE,{ok_tc,fail_init}, {failed,{subgroups_1_SUITE,init_per_group, {'EXIT',init_per_group_fails_on_purpose}}}}}, {?eh,test_stats,{0,0,{0,1}}}, {?eh,tc_auto_skip,{subgroups_1_SUITE,{end_per_group,fail_init}, {failed,{subgroups_1_SUITE,init_per_group, {'EXIT',init_per_group_fails_on_purpose}}}}}], - {?eh,tc_auto_skip,{subgroups_1_SUITE,ok_tc,{group_result,fail_init,failed}}}, + {?eh,tc_auto_skip,{subgroups_1_SUITE,{ok_tc,ok_group}, + {group_result,fail_init,failed}}}, {?eh,test_stats,{0,0,{0,2}}}, {?eh,tc_start,{subgroups_1_SUITE,{end_per_group,subgroup_init_fail,[sequence]}}}, {?eh,tc_done,{subgroups_1_SUITE, @@ -237,7 +239,8 @@ test_events(subgroup_after_failed_case) -> {?eh,tc_start,{subgroups_1_SUITE,failing_tc}}, {?eh,tc_done,{subgroups_1_SUITE,failing_tc,{failed,{error,{{badmatch,3},'_'}}}}}, {?eh,test_stats,{0,1,{0,0}}}, - {?eh,tc_auto_skip,{subgroups_1_SUITE,ok_tc,{failed,{subgroups_1_SUITE,failing_tc}}}}, + {?eh,tc_auto_skip,{subgroups_1_SUITE,{ok_tc,ok_group}, + {failed,{subgroups_1_SUITE,failing_tc}}}}, {?eh,test_stats,{0,1,{0,1}}}, {?eh,tc_start,{subgroups_1_SUITE, {end_per_group,subgroup_after_failed_case,[sequence]}}}, @@ -265,7 +268,8 @@ test_events(case_after_subgroup_return_fail) -> {?eh,tc_start,{subgroups_1_SUITE,{end_per_group,return_fail,[]}}}, {?eh,tc_done,{subgroups_1_SUITE,{end_per_group,return_fail,[]}, {return_group_result,failed}}}], - {?eh,tc_auto_skip,{subgroups_1_SUITE,ok_tc,{group_result,return_fail,failed}}}, + {?eh,tc_auto_skip,{subgroups_1_SUITE,{ok_tc,case_after_subgroup_return_fail}, + {group_result,return_fail,failed}}}, {?eh,test_stats,{0,1,{0,1}}}, {?eh,tc_start,{subgroups_1_SUITE, {end_per_group,case_after_subgroup_return_fail,[sequence]}}}, @@ -289,7 +293,7 @@ test_events(case_after_subgroup_fail_init) -> {?eh,tc_done,{subgroups_1_SUITE, {init_per_group,fail_init,[]}, {failed,{error,init_per_group_fails_on_purpose}}}}, - {?eh,tc_auto_skip,{subgroups_1_SUITE,ok_tc, + {?eh,tc_auto_skip,{subgroups_1_SUITE,{ok_tc,fail_init}, {failed, {subgroups_1_SUITE,init_per_group, {'EXIT',init_per_group_fails_on_purpose}}}}}, @@ -300,7 +304,8 @@ test_events(case_after_subgroup_fail_init) -> {'EXIT',init_per_group_fails_on_purpose}}}}}], {?eh,tc_auto_skip, - {subgroups_1_SUITE,ok_tc,{group_result,fail_init,failed}}}, + {subgroups_1_SUITE,{ok_tc,case_after_subgroup_fail_init}, + {group_result,fail_init,failed}}}, {?eh,test_stats,{0,0,{0,2}}}, {?eh,tc_start,{subgroups_1_SUITE, {end_per_group,case_after_subgroup_fail_init,[sequence]}}}, diff --git a/lib/common_test/test/ct_skip_SUITE.erl b/lib/common_test/test/ct_skip_SUITE.erl index b0a6c839a2..6fb803b928 100644 --- a/lib/common_test/test/ct_skip_SUITE.erl +++ b/lib/common_test/test/ct_skip_SUITE.erl @@ -153,10 +153,10 @@ testspec_skip(Config) when is_list(Config) -> {skip_groups, TestDir, user_skip_6_SUITE, psub1, "SKIPPED"}], {Opts,ERPid} = setup_testspec([{ts1,TestSpec1}, - {ts2,TestSpec2}, - {ts3,TestSpec3}, - {ts4,TestSpec4}, - {ts5,TestSpec5}], Config), + {ts2,TestSpec2}, + {ts3,TestSpec3}, + {ts4,TestSpec4}, + {ts5,TestSpec5}], Config), ok = ct_test_support:run(Opts, Config), @@ -234,8 +234,8 @@ test_events(auto_skip) -> {?eh,tc_done, {auto_skip_2_SUITE,init_per_suite,{failed,{error,init_per_suite_failed}}}}, {?eh,tc_auto_skip, - {auto_skip_2_SUITE,tc1,{failed,{auto_skip_2_SUITE,init_per_suite, - {'EXIT',init_per_suite_failed}}}}}, + {auto_skip_2_SUITE,{tc1,g1},{failed,{auto_skip_2_SUITE,init_per_suite, + {'EXIT',init_per_suite_failed}}}}}, {?eh,test_stats,{0,0,{0,3}}}, {?eh,tc_auto_skip, {auto_skip_2_SUITE,end_per_suite,{failed,{auto_skip_2_SUITE,init_per_suite, @@ -274,12 +274,12 @@ test_events(auto_skip) -> {?eh,tc_done, {auto_skip_5_SUITE,{init_per_group,g1,[]},{failed,{error,{group,g1,failed}}}}}, {?eh,tc_auto_skip, - {auto_skip_5_SUITE,tc1,{failed,{auto_skip_5_SUITE,init_per_group, - {'EXIT',{group,g1,failed}}}}}}, + {auto_skip_5_SUITE,{tc1,g1},{failed,{auto_skip_5_SUITE,init_per_group, + {'EXIT',{group,g1,failed}}}}}}, {?eh,test_stats,{2,0,{0,6}}}, {?eh,tc_auto_skip, - {auto_skip_5_SUITE,tc2,{failed,{auto_skip_5_SUITE,init_per_group, - {'EXIT',{group,g1,failed}}}}}}, + {auto_skip_5_SUITE,{tc2,g1},{failed,{auto_skip_5_SUITE,init_per_group, + {'EXIT',{group,g1,failed}}}}}}, {?eh,test_stats,{2,0,{0,7}}}, {?eh,tc_auto_skip, {auto_skip_5_SUITE,{end_per_group,g1}, @@ -295,20 +295,20 @@ test_events(auto_skip) -> {?eh,tc_done, {auto_skip_6_SUITE,{init_per_group,g1,[]},{failed,{error,{group,g1,failed}}}}}, {?eh,tc_auto_skip, - {auto_skip_6_SUITE,tc1,{failed,{auto_skip_6_SUITE,init_per_group, - {'EXIT',{group,g1,failed}}}}}}, + {auto_skip_6_SUITE,{tc1,g1},{failed,{auto_skip_6_SUITE,init_per_group, + {'EXIT',{group,g1,failed}}}}}}, {?eh,test_stats,{2,0,{0,8}}}, {?eh,tc_auto_skip, - {auto_skip_6_SUITE,tc3,{failed,{auto_skip_6_SUITE,init_per_group, - {'EXIT',{group,g1,failed}}}}}}, + {auto_skip_6_SUITE,{tc3,g2},{failed,{auto_skip_6_SUITE,init_per_group, + {'EXIT',{group,g1,failed}}}}}}, {?eh,test_stats,{2,0,{0,9}}}, {?eh,tc_auto_skip, - {auto_skip_6_SUITE,tc4,{failed,{auto_skip_6_SUITE,init_per_group, - {'EXIT',{group,g1,failed}}}}}}, + {auto_skip_6_SUITE,{tc4,g2},{failed,{auto_skip_6_SUITE,init_per_group, + {'EXIT',{group,g1,failed}}}}}}, {?eh,test_stats,{2,0,{0,10}}}, {?eh,tc_auto_skip, - {auto_skip_6_SUITE,tc2,{failed,{auto_skip_6_SUITE,init_per_group, - {'EXIT',{group,g1,failed}}}}}}, + {auto_skip_6_SUITE,{tc2,g1},{failed,{auto_skip_6_SUITE,init_per_group, + {'EXIT',{group,g1,failed}}}}}}, {?eh,test_stats,{2,0,{0,11}}}, {?eh,tc_auto_skip, {auto_skip_6_SUITE,{end_per_group,g1}, @@ -324,12 +324,12 @@ test_events(auto_skip) -> {?eh,tc_done,{auto_skip_6_SUITE,{init_per_group,g4,[]}, {failed,{error,{group,g4,failed}}}}}, {?eh,tc_auto_skip, - {auto_skip_6_SUITE,tc3,{failed,{auto_skip_6_SUITE,init_per_group, - {'EXIT',{group,g4,failed}}}}}}, + {auto_skip_6_SUITE,{tc3,g4},{failed,{auto_skip_6_SUITE,init_per_group, + {'EXIT',{group,g4,failed}}}}}}, {?eh,test_stats,{3,0,{0,12}}}, {?eh,tc_auto_skip, - {auto_skip_6_SUITE,tc4,{failed,{auto_skip_6_SUITE,init_per_group, - {'EXIT',{group,g4,failed}}}}}}, + {auto_skip_6_SUITE,{tc4,g4},{failed,{auto_skip_6_SUITE,init_per_group, + {'EXIT',{group,g4,failed}}}}}}, {?eh,test_stats,{3,0,{0,13}}}, {?eh,tc_auto_skip, {auto_skip_6_SUITE,{end_per_group,g4}, @@ -498,13 +498,13 @@ test_events(auto_skip) -> [{suite,auto_skip_12_SUITE}]}, {auto_skipped, {require_failed,{not_available,unknown_variable_g1}}}}}, - {?eh,tc_auto_skip,{auto_skip_12_SUITE,tc1, + {?eh,tc_auto_skip,{auto_skip_12_SUITE,{tc1,g1}, {require_failed,{not_available,unknown_variable_g1}}}}, {?eh,test_stats,{10,0,{0,25}}}, - {?eh,tc_auto_skip,{auto_skip_12_SUITE,tc2, + {?eh,tc_auto_skip,{auto_skip_12_SUITE,{tc2,g1}, {require_failed,{not_available,unknown_variable_g1}}}}, {?eh,test_stats,{10,0,{0,26}}}, - {?eh,tc_auto_skip,{auto_skip_12_SUITE,tc3, + {?eh,tc_auto_skip,{auto_skip_12_SUITE,{tc3,g2}, {require_failed,{not_available,unknown_variable_g1}}}}, {?eh,test_stats,{10,0,{0,27}}}, {?eh,tc_auto_skip,{ct_framework,{end_per_group,g1}, @@ -516,13 +516,13 @@ test_events(auto_skip) -> [{suite,auto_skip_12_SUITE}]}, {auto_skipped, {require_failed,{not_available,unknown_variable_g1}}}}}, - {?eh,tc_auto_skip,{auto_skip_12_SUITE,tc1, + {?eh,tc_auto_skip,{auto_skip_12_SUITE,{tc1,g1}, {require_failed,{not_available,unknown_variable_g1}}}}, {?eh,test_stats,{10,0,{0,28}}}, - {?eh,tc_auto_skip,{auto_skip_12_SUITE,tc2, + {?eh,tc_auto_skip,{auto_skip_12_SUITE,{tc2,g1}, {require_failed,{not_available,unknown_variable_g1}}}}, {?eh,test_stats,{10,0,{0,29}}}, - {?eh,tc_auto_skip,{auto_skip_12_SUITE,tc3, + {?eh,tc_auto_skip,{auto_skip_12_SUITE,{tc3,g2}, {require_failed,{not_available,unknown_variable_g1}}}}, {?eh,test_stats,{10,0,{0,30}}}, {?eh,tc_auto_skip,{ct_framework,{end_per_group,g1}, @@ -544,7 +544,7 @@ test_events(auto_skip) -> [{suite,auto_skip_12_SUITE}]}, {auto_skipped, {require_failed,{not_available,unknown_variable_g4}}}}}, - {?eh,tc_auto_skip,{auto_skip_12_SUITE,tc3, + {?eh,tc_auto_skip,{auto_skip_12_SUITE,{tc3,g4}, {require_failed,{not_available,unknown_variable_g4}}}}, {?eh,test_stats,{12,0,{0,31}}}, {?eh,tc_auto_skip,{ct_framework,{end_per_group,g4}, @@ -574,10 +574,10 @@ test_events(user_skip) -> {user_skip_1_SUITE,tc1,"Whole suite skipped"}}, {?eh,test_stats,{0,0,{1,0}}}, {?eh,tc_user_skip, - {user_skip_1_SUITE,tc2,"Whole suite skipped"}}, + {user_skip_1_SUITE,{tc2,g1},"Whole suite skipped"}}, {?eh,test_stats,{0,0,{2,0}}}, {?eh,tc_user_skip, - {user_skip_1_SUITE,tc3,"Whole suite skipped"}}, + {user_skip_1_SUITE,{tc3,g1},"Whole suite skipped"}}, {?eh,test_stats,{0,0,{3,0}}}, {?eh,tc_user_skip, {user_skip_1_SUITE,tc4,"Whole suite skipped"}}, @@ -638,9 +638,9 @@ test_events(user_skip) -> [{?eh,tc_start,{user_skip_4_SUITE,{init_per_group,g1,[]}}}, {?eh,tc_done,{user_skip_4_SUITE,{init_per_group,g1,[]},{skipped,"Group skipped"}}}, - {?eh,tc_user_skip,{user_skip_4_SUITE,tc1,"Group skipped"}}, + {?eh,tc_user_skip,{user_skip_4_SUITE,{tc1,g1},"Group skipped"}}, {?eh,test_stats,{3,0,{10,0}}}, - {?eh,tc_user_skip,{user_skip_4_SUITE,tc2,"Group skipped"}}, + {?eh,tc_user_skip,{user_skip_4_SUITE,{tc2,g1},"Group skipped"}}, {?eh,test_stats,{3,0,{11,0}}}, {?eh,tc_user_skip,{user_skip_4_SUITE,{end_per_group,g1},"Group skipped"}}], @@ -657,10 +657,10 @@ test_events(user_skip) -> [{?eh,tc_start,{user_skip_4_SUITE,{init_per_group,g3,[]}}}, {?eh,tc_done,{user_skip_4_SUITE,{init_per_group,g3,[]},{skipped,"Group skipped"}}}, - {?eh,tc_user_skip,{user_skip_4_SUITE,tc5,"Group skipped"}}, - {?eh,tc_user_skip,{user_skip_4_SUITE,tc6,"Group skipped"}}, - {?eh,tc_user_skip,{user_skip_4_SUITE,tc7,"Group skipped"}}, - {?eh,tc_user_skip,{user_skip_4_SUITE,tc8,"Group skipped"}}, + {?eh,tc_user_skip,{user_skip_4_SUITE,{tc5,g3},"Group skipped"}}, + {?eh,tc_user_skip,{user_skip_4_SUITE,{tc6,g4},"Group skipped"}}, + {?eh,tc_user_skip,{user_skip_4_SUITE,{tc7,g4},"Group skipped"}}, + {?eh,tc_user_skip,{user_skip_4_SUITE,{tc8,g3},"Group skipped"}}, {?eh,test_stats,{5,0,{15,0}}}, {?eh,tc_user_skip,{user_skip_4_SUITE,{end_per_group,g3},"Group skipped"}}], @@ -671,9 +671,9 @@ test_events(user_skip) -> {?eh,test_stats,{6,0,{15,0}}}, [{?eh,tc_start,{user_skip_4_SUITE,{init_per_group,g6,[]}}}, {?eh,tc_done,{user_skip_4_SUITE,{init_per_group,g6,[]},{skipped,"Group skipped"}}}, - {?eh,tc_user_skip,{user_skip_4_SUITE,tc10,"Group skipped"}}, + {?eh,tc_user_skip,{user_skip_4_SUITE,{tc10,g6},"Group skipped"}}, {?eh,test_stats,{6,0,{16,0}}}, - {?eh,tc_user_skip,{user_skip_4_SUITE,tc11,"Group skipped"}}, + {?eh,tc_user_skip,{user_skip_4_SUITE,{tc11,g6},"Group skipped"}}, {?eh,test_stats,{6,0,{17,0}}}, {?eh,tc_user_skip,{user_skip_4_SUITE,{end_per_group,g6},"Group skipped"}}], {?eh,tc_start,{user_skip_4_SUITE,{end_per_group,g5,[]}}}, @@ -687,9 +687,9 @@ test_events(user_skip) -> {skipped,{bad,'Whole suite skipped'}}}}, {?eh,tc_user_skip,{user_skip_5_SUITE,tc1,{bad,'Whole suite skipped'}}}, {?eh,test_stats,{6,0,{18,0}}}, - {?eh,tc_user_skip,{user_skip_5_SUITE,tc2,{bad,'Whole suite skipped'}}}, + {?eh,tc_user_skip,{user_skip_5_SUITE,{tc2,g1},{bad,'Whole suite skipped'}}}, {?eh,test_stats,{6,0,{19,0}}}, - {?eh,tc_user_skip,{user_skip_5_SUITE,tc3,{bad,'Whole suite skipped'}}}, + {?eh,tc_user_skip,{user_skip_5_SUITE,{tc3,g1},{bad,'Whole suite skipped'}}}, {?eh,test_stats,{6,0,{20,0}}}, {?eh,tc_user_skip,{user_skip_5_SUITE,tc4,{bad,'Whole suite skipped'}}}, {?eh,test_stats,{6,0,{21,0}}}, @@ -700,10 +700,10 @@ test_events(user_skip) -> {?eh,tc_done,{user_skip_6_SUITE, {init_per_group,ptop1,[parallel]}, {skipped,"Top group skipped"}}}, - {?eh,tc_user_skip,{user_skip_6_SUITE,tc1,"Top group skipped"}}, - {?eh,tc_user_skip,{user_skip_6_SUITE,tc3,"Top group skipped"}}, - {?eh,tc_user_skip,{user_skip_6_SUITE,tc4,"Top group skipped"}}, - {?eh,tc_user_skip,{user_skip_6_SUITE,tc2,"Top group skipped"}}, + {?eh,tc_user_skip,{user_skip_6_SUITE,{tc1,ptop1},"Top group skipped"}}, + {?eh,tc_user_skip,{user_skip_6_SUITE,{tc3,psub1},"Top group skipped"}}, + {?eh,tc_user_skip,{user_skip_6_SUITE,{tc4,psub1},"Top group skipped"}}, + {?eh,tc_user_skip,{user_skip_6_SUITE,{tc2,ptop1},"Top group skipped"}}, {?eh,tc_user_skip,{user_skip_6_SUITE,{end_per_group,ptop1}, "Top group skipped"}}]}, @@ -718,8 +718,8 @@ test_events(user_skip) -> {?eh,tc_done,{user_skip_6_SUITE, {init_per_group,psub2,[parallel]}, {skipped,"Sub group skipped"}}}, - {?eh,tc_user_skip,{user_skip_6_SUITE,tc3,"Sub group skipped"}}, - {?eh,tc_user_skip,{user_skip_6_SUITE,tc4,"Sub group skipped"}}, + {?eh,tc_user_skip,{user_skip_6_SUITE,{tc3,psub2},"Sub group skipped"}}, + {?eh,tc_user_skip,{user_skip_6_SUITE,{tc4,psub2},"Sub group skipped"}}, {?eh,tc_user_skip,{user_skip_6_SUITE,{end_per_group,psub2}, "Sub group skipped"}}]}, @@ -745,14 +745,14 @@ test_events(testspec_skip) -> {user_skip_7_SUITE,{init_per_group,ptop1,[parallel]}}}, {?eh,tc_done, {user_skip_7_SUITE,{init_per_group,ptop1,[parallel]},ok}}, - {?eh,tc_user_skip,{user_skip_7_SUITE,tc1,"SKIPPED"}}, + {?eh,tc_user_skip,{user_skip_7_SUITE,{tc1,ptop1},"SKIPPED"}}, {?eh,test_stats,{0,0,{1,0}}}, {parallel, [{?eh,tc_start, {user_skip_7_SUITE,{init_per_group,psub1,[parallel]}}}, {?eh,tc_done, {user_skip_7_SUITE,{init_per_group,psub1,[parallel]},ok}}, - {?eh,tc_user_skip,{user_skip_7_SUITE,tc3,"SKIPPED"}}, + {?eh,tc_user_skip,{user_skip_7_SUITE,{tc3,psub1},"SKIPPED"}}, {?eh,tc_start,{user_skip_7_SUITE,tc4}}, {?eh,tc_done,{user_skip_7_SUITE,tc4,ok}}, {?eh,test_stats,{1,0,{2,0}}}, @@ -778,13 +778,13 @@ test_events(testspec_skip) -> {?eh,tc_start,{ct_framework,init_per_suite}}, {?eh,tc_done,{ct_framework,init_per_suite,ok}}, {?eh,tc_user_skip,{user_skip_7_SUITE,{init_per_group,ptop1},"SKIPPED"}}, - {?eh,tc_user_skip,{user_skip_7_SUITE,tc1,"SKIPPED"}}, + {?eh,tc_user_skip,{user_skip_7_SUITE,{tc1,ptop1},"SKIPPED"}}, {?eh,test_stats,{0,0,{1,0}}}, - {?eh,tc_user_skip,{user_skip_7_SUITE,tc3,"SKIPPED"}}, + {?eh,tc_user_skip,{user_skip_7_SUITE,{tc3,psub1},"SKIPPED"}}, {?eh,test_stats,{0,0,{2,0}}}, - {?eh,tc_user_skip,{user_skip_7_SUITE,tc4,"SKIPPED"}}, + {?eh,tc_user_skip,{user_skip_7_SUITE,{tc4,psub1},"SKIPPED"}}, {?eh,test_stats,{0,0,{3,0}}}, - {?eh,tc_user_skip,{user_skip_7_SUITE,tc2,"SKIPPED"}}, + {?eh,tc_user_skip,{user_skip_7_SUITE,{tc2,ptop1},"SKIPPED"}}, {?eh,test_stats,{0,0,{4,0}}}, {?eh,tc_user_skip,{user_skip_7_SUITE,{end_per_group,ptop1},"SKIPPED"}}, {?eh,tc_start,{ct_framework,end_per_suite}}, @@ -804,8 +804,8 @@ test_events(testspec_skip) -> {user_skip_7_SUITE,{init_per_group,ptop1,[parallel]},ok}}, {?eh,tc_user_skip, {user_skip_7_SUITE,{init_per_group,psub1},"SKIPPED"}}, - {?eh,tc_user_skip,{user_skip_7_SUITE,tc3,"SKIPPED"}}, - {?eh,tc_user_skip,{user_skip_7_SUITE,tc4,"SKIPPED"}}, + {?eh,tc_user_skip,{user_skip_7_SUITE,{tc3,psub1},"SKIPPED"}}, + {?eh,tc_user_skip,{user_skip_7_SUITE,{tc4,psub1},"SKIPPED"}}, {?eh,test_stats,{0,0,{2,0}}}, {?eh,tc_user_skip,{user_skip_7_SUITE,{end_per_group,psub1},"SKIPPED"}}, {?eh,tc_start,{user_skip_7_SUITE,tc1}}, @@ -837,13 +837,13 @@ test_events(testspec_skip) -> {?eh,tc_done,{user_skip_6_SUITE, {init_per_group,ptop1,[parallel]}, {skipped,"Top group skipped"}}}, - {?eh,tc_user_skip,{user_skip_6_SUITE,tc1,"Top group skipped"}}, + {?eh,tc_user_skip,{user_skip_6_SUITE,{tc1,ptop1},"Top group skipped"}}, {?eh,test_stats,{0,0,{1,0}}}, - {?eh,tc_user_skip,{user_skip_6_SUITE,tc3,"SKIPPED"}}, + {?eh,tc_user_skip,{user_skip_6_SUITE,{tc3,psub1},"SKIPPED"}}, {?eh,test_stats,{0,0,{2,0}}}, - {?eh,tc_user_skip,{user_skip_6_SUITE,tc4,"SKIPPED"}}, + {?eh,tc_user_skip,{user_skip_6_SUITE,{tc4,psub1},"SKIPPED"}}, {?eh,test_stats,{0,0,{3,0}}}, - {?eh,tc_user_skip,{user_skip_6_SUITE,tc2,"Top group skipped"}}, + {?eh,tc_user_skip,{user_skip_6_SUITE,{tc2,ptop1},"Top group skipped"}}, {?eh,test_stats,{0,0,{4,0}}}, {?eh,tc_user_skip, {user_skip_6_SUITE,{end_per_group,ptop1},"Top group skipped"}}]}, diff --git a/lib/common_test/test/ct_surefire_SUITE.erl b/lib/common_test/test/ct_surefire_SUITE.erl index c5e44682b0..db7a0be915 100644 --- a/lib/common_test/test/ct_surefire_SUITE.erl +++ b/lib/common_test/test/ct_surefire_SUITE.erl @@ -205,7 +205,7 @@ test_events(_) -> [{?eh,tc_start,{surefire_SUITE,{init_per_group,g_fail,[]}}}, {?eh,tc_done,{surefire_SUITE,{init_per_group,g_fail,[]}, {failed,{error,all_cases_should_be_skipped}}}}, - {?eh,tc_auto_skip,{surefire_SUITE,tc_ok, + {?eh,tc_auto_skip,{surefire_SUITE,{tc_ok,g_fail}, {failed, {surefire_SUITE,init_per_group, {'EXIT',all_cases_should_be_skipped}}}}}, diff --git a/lib/common_test/test/ct_test_server_if_1_SUITE.erl b/lib/common_test/test/ct_test_server_if_1_SUITE.erl index 9882fa980c..b6ef3062d4 100644 --- a/lib/common_test/test/ct_test_server_if_1_SUITE.erl +++ b/lib/common_test/test/ct_test_server_if_1_SUITE.erl @@ -168,7 +168,7 @@ test_events(ts_if_1) -> {?eh,tc_start,{ts_if_1_SUITE,tc4}}, {?eh,tc_done,{ts_if_1_SUITE,tc4,{failed,{error,failed_on_purpose}}}}, {?eh,test_stats,{1,3,{0,2}}}, - {?eh,tc_auto_skip,{ts_if_1_SUITE,tc5,{failed,{ts_if_1_SUITE,tc4}}}}, + {?eh,tc_auto_skip,{ts_if_1_SUITE,{tc5,seq2},{failed,{ts_if_1_SUITE,tc4}}}}, {?eh,test_stats,{1,3,{0,3}}}, {?eh,tc_start,{ts_if_1_SUITE,{end_per_group,seq2,[sequence]}}}, {?eh,tc_done,{ts_if_1_SUITE,{end_per_group,seq2,[sequence]},ok}}], @@ -199,7 +199,7 @@ test_events(ts_if_1) -> [{?eh,tc_start,{ts_if_1_SUITE,{init_per_group,g1,[]}}}, {?eh,tc_done,{ts_if_1_SUITE,{init_per_group,g1,[]}, {skipped,g1_got_skipped}}}, - {?eh,tc_user_skip,{ts_if_1_SUITE,gtc1,g1_got_skipped}}, + {?eh,tc_user_skip,{ts_if_1_SUITE,{gtc1,g1},g1_got_skipped}}, {?eh,test_stats,{1,4,{3,6}}}, {?eh,tc_user_skip,{ts_if_1_SUITE,{end_per_group,g1},g1_got_skipped}}], @@ -208,7 +208,7 @@ test_events(ts_if_1) -> {?eh,tc_done,{ts_if_1_SUITE,{init_per_group,g2,[parallel]},ok}}, [{?eh,tc_start,{ts_if_1_SUITE,{init_per_group,g3,[]}}}, {?eh,tc_done,{ts_if_1_SUITE,{init_per_group,g3,[]},{skipped,g3_got_skipped}}}, - {?eh,tc_user_skip,{ts_if_1_SUITE,gtc2,g3_got_skipped}}, + {?eh,tc_user_skip,{ts_if_1_SUITE,{gtc2,g3},g3_got_skipped}}, {?eh,test_stats,{1,4,{4,6}}}, {?eh,tc_user_skip,{ts_if_1_SUITE,{end_per_group,g3},g3_got_skipped}}], {?eh,tc_start,{ts_if_1_SUITE,{end_per_group,g2,[parallel]}}}, @@ -279,7 +279,7 @@ test_events(ts_if_1) -> {init_per_group,g1,[]}, {auto_skipped,{group0_failed,bad_return_value}}}}, {?eh,tc_auto_skip, - {ts_if_7_SUITE,tc2,{group0_failed,bad_return_value}}}, + {ts_if_7_SUITE,{tc2,g1},{group0_failed,bad_return_value}}}, {?eh,test_stats,{2,7,{4,11}}}, {?eh,tc_auto_skip, {ts_if_7_SUITE,{end_per_group,g1},{group0_failed,bad_return_value}}}, diff --git a/lib/common_test/test/ct_testspec_1_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE.erl index 187b5e6d3a..c2670316b6 100644 --- a/lib/common_test/test/ct_testspec_1_SUITE.erl +++ b/lib/common_test/test/ct_testspec_1_SUITE.erl @@ -763,35 +763,35 @@ test_events(skip_all_groups) -> {?eh,start_info,{1,1,12}}, {?eh,tc_start,{groups_11_SUITE,init_per_suite}}, {?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_1a},"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1a,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1a,test_group_1a},"SKIPPED!"}}, {?eh,test_stats,{0,0,{1,0}}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1b,test_group_1a},"SKIPPED!"}}, {?eh,test_stats,{0,0,{2,0}}}, {?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_1a},"SKIPPED!"}}, {?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_1b},"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1a,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1a,test_group_1b},"SKIPPED!"}}, {?eh,test_stats,{0,0,{3,0}}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1b,test_group_1b},"SKIPPED!"}}, {?eh,test_stats,{0,0,{4,0}}}, {?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_1b},"SKIPPED!"}}, {?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_2},"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_2a,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_2a,test_group_2},"SKIPPED!"}}, {?eh,test_stats,{0,0,{5,0}}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_3a,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_3a,test_group_3},"SKIPPED!"}}, {?eh,test_stats,{0,0,{6,0}}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_3b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_3b,test_group_3},"SKIPPED!"}}, {?eh,test_stats,{0,0,{7,0}}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_2b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_2b,test_group_2},"SKIPPED!"}}, {?eh,test_stats,{0,0,{8,0}}}, {?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_2},"SKIPPED!"}}, {?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_4},"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_5a,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_5a,test_group_5},"SKIPPED!"}}, {?eh,test_stats,{0,0,{9,0}}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_7a,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_7a,test_group_7},"SKIPPED!"}}, {?eh,test_stats,{0,0,{10,0}}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_7b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_7b,test_group_7},"SKIPPED!"}}, {?eh,test_stats,{0,0,{11,0}}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_5b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_5b,test_group_5},"SKIPPED!"}}, {?eh,test_stats,{0,0,{12,0}}}, {?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_4},"SKIPPED!"}}, {?eh,tc_start,{groups_11_SUITE,end_per_suite}}, @@ -826,17 +826,17 @@ test_events(skip_group) -> {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_1a,[]},ok}}], {?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_1b}, "SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1a,test_group_1b},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1b,test_group_1b},"SKIPPED!"}}, {?eh,test_stats,{2,0,{2,0}}}, {?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_1b}, "SKIPPED!"}}, {?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_2}, "SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_2a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_3a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_3b,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_2b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_2a,test_group_2},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_3a,test_group_3},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_3b,test_group_3},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_2b,test_group_2},"SKIPPED!"}}, {?eh,test_stats,{2,0,{6,0}}}, {?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_2}, "SKIPPED!"}}, @@ -864,15 +864,15 @@ test_events(skip_group_all_testcases) -> {?eh,tc_start,{groups_11_SUITE,init_per_suite}}, {?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_1a}, "SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1a,test_group_1a},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1b,test_group_1a},"SKIPPED!"}}, {?eh,test_stats,{0,0,{2,0}}}, {?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_1a}, "SKIPPED!"}}, {?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_1b}, "SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1a,test_group_1b},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1b,test_group_1b},"SKIPPED!"}}, {?eh,test_stats,{0,0,{4,0}}}, {?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_1b}, "SKIPPED!"}}, @@ -901,13 +901,13 @@ test_events(skip_group_testcase) -> {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_1a,[]}}}, {?eh,tc_start,{groups_11_SUITE,testcase_1a}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1b,test_group_1a},"SKIPPED!"}}, {?eh,test_stats,{1,0,{1,0}}}, {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_1a,[]},'_'}}, {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_1b,[]}}}, {?eh,tc_start,{groups_11_SUITE,testcase_1b}}, - {?eh,tc_user_skip,{groups_11_SUITE,testcase_1a,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1a,test_group_1b},"SKIPPED!"}}, {?eh,test_stats,{2,0,{2,0}}}, {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_1b,[]},'_'}}, @@ -1045,8 +1045,8 @@ test_events(skip_subgroup) -> {?eh,tc_user_skip,{groups_12_SUITE, {init_per_group,test_group_8},"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_8a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_8b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_8a,test_group_8},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_8b,test_group_8},"SKIPPED!"}}, {?eh,tc_user_skip,{groups_12_SUITE, {end_per_group,test_group_8},"SKIPPED!"}}, @@ -1146,12 +1146,12 @@ test_events(skip_subgroup_all_testcases) -> {?eh,tc_done,{groups_12_SUITE,{init_per_group,test_group_4,[]},ok}}, {?eh,tc_user_skip,{groups_12_SUITE, {init_per_group,test_group_5},"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_5a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_7a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_7b,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_8a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_8b,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_5b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_5a,test_group_5},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_7a,test_group_7},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_7b,test_group_7},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_8a,test_group_8},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_8b,test_group_8},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_5b,test_group_5},"SKIPPED!"}}, {?eh,test_stats,{0,0,{6,0}}}, {?eh,tc_user_skip,{groups_12_SUITE, {end_per_group,test_group_5},"SKIPPED!"}}, @@ -1240,9 +1240,9 @@ test_events(skip_subgroup_testcase) -> {?eh,tc_done, {groups_12_SUITE,{init_per_group,test_group_6,[parallel]},ok}}, [{?eh,tc_start,{groups_12_SUITE,{init_per_group,test_group_7,'_'}}}, - {?eh,tc_user_skip, {groups_12_SUITE,testcase_7a,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_7a,test_group_7},"SKIPPED!"}}, {?eh,test_stats,{1,0,{1,0}}}, - {?eh,tc_user_skip, {groups_12_SUITE,testcase_7b,"SKIPPED!"}}, + {?eh,tc_user_skip, {groups_12_SUITE,{testcase_7b,test_group_7},"SKIPPED!"}}, {?eh,test_stats,{1,0,{2,0}}}, {?eh,tc_start,{groups_12_SUITE,{end_per_group,test_group_7,'_'}}}], {shuffle, @@ -1281,22 +1281,22 @@ test_events(sub_skipped_by_top) -> {?eh,tc_start,{groups_12_SUITE,init_per_suite}}, {?eh,tc_user_skip,{groups_12_SUITE,{init_per_group,test_group_4}, "SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_5a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_7a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_7b,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_8a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_8b,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_5b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_5a,test_group_5},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_7a,test_group_7},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_7b,test_group_7},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_8a,test_group_8},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_8b,test_group_8},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_5b,test_group_5},"SKIPPED!"}}, {?eh,tc_user_skip,{groups_12_SUITE, {end_per_group,test_group_4},"SKIPPED!"}}, {?eh,tc_user_skip,{groups_12_SUITE, {init_per_group,test_group_4},"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_5a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_7a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_7b,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_8a,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_8b,"SKIPPED!"}}, - {?eh,tc_user_skip,{groups_12_SUITE,testcase_5b,"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_5a,test_group_5},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_7a,test_group_7},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_7b,test_group_7},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_8a,test_group_8},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_8b,test_group_8},"SKIPPED!"}}, + {?eh,tc_user_skip,{groups_12_SUITE,{testcase_5b,test_group_5},"SKIPPED!"}}, {?eh,test_stats,{0,0,{12,0}}}, {?eh,tc_user_skip,{groups_12_SUITE, {end_per_group,test_group_4},"SKIPPED!"}}, diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml index c66c8ea4bf..5fccdcdcb5 100644 --- a/lib/compiler/doc/src/compile.xml +++ b/lib/compiler/doc/src/compile.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -551,6 +551,14 @@ module.beam: module.erl \ <c>{Module,Name,Arity}</c> or a list of such tuples.</p> </item> + <tag><c>nowarn_deprecated_type</c></tag> + <item> + <p>Turns off warnings for uses of deprecated types. By + default (<c>warn_deprecated_type</c>), warnings are + emitted for every use of a type known by the compiler + to be deprecated.</p> + </item> + <tag><c>warn_obsolete_guard</c></tag> <item> <p>Causes warnings to be emitted for calls to old type diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl index 590665514b..5a4621dc37 100644 --- a/lib/compiler/src/beam_bool.erl +++ b/lib/compiler/src/beam_bool.erl @@ -393,10 +393,14 @@ bopt_tree([{set,_,_,{bif,'xor',_}}|_], _, _) -> throw('xor'); bopt_tree([{protected,[Dst],Code,_}|Is], Forest0, Pre) -> ProtForest0 = gb_trees:from_orddict([P || {_,any}=P <- gb_trees:to_list(Forest0)]), - {ProtPre,[{_,ProtTree}]} = bopt_tree(Code, ProtForest0, []), - Prot = {prot,ProtPre,ProtTree}, - Forest = gb_trees:enter(Dst, Prot, Forest0), - bopt_tree(Is, Forest, Pre); + case bopt_tree(Code, ProtForest0, []) of + {ProtPre,[{_,ProtTree}]} -> + Prot = {prot,ProtPre,ProtTree}, + Forest = gb_trees:enter(Dst, Prot, Forest0), + bopt_tree(Is, Forest, Pre); + _Res -> + throw(not_boolean_expr) + end; bopt_tree([{set,[Dst],[Src],move}=Move|Is], Forest, Pre) -> case {Src,Dst} of {{tmp,_},_} -> throw(move); @@ -434,9 +438,10 @@ bopt_bool_args(As, Forest) -> mapfoldl(fun bopt_bool_arg/2, Forest, As). bopt_bool_arg({T,_}=R, Forest) when T =:= x; T =:= y; T =:= tmp -> - Val = case gb_trees:get(R, Forest) of - any -> {test,is_eq_exact,fail,[R,{atom,true}]}; - Val0 -> Val0 + Val = case gb_trees:lookup(R, Forest) of + {value,any} -> {test,is_eq_exact,fail,[R,{atom,true}]}; + {value,Val0} -> Val0; + none -> throw(mixed) end, {Val,gb_trees:delete(R, Forest)}; bopt_bool_arg(Term, Forest) -> @@ -527,7 +532,9 @@ bopt_cg({prot,Pre0,Tree}, Fail, Rs0, Acc, St0) -> bopt_cg({atom,true}, _Fail, _Rs, Acc, St) -> {Acc,St}; bopt_cg({atom,false}, Fail, _Rs, Acc, St) -> - {[{jump,{f,Fail}}|Acc],St}. + {[{jump,{f,Fail}}|Acc],St}; +bopt_cg(_, _, _, _, _) -> + throw(not_boolean_expr). bopt_cg_not({'and',As0}) -> As = [bopt_cg_not(A) || A <- As0], @@ -540,7 +547,9 @@ bopt_cg_not({'not',Arg}) -> bopt_cg_not({test,Test,Fail,As}) -> {inverted_test,Test,Fail,As}; bopt_cg_not({atom,Bool}) when is_boolean(Bool) -> - {atom,not Bool}. + {atom,not Bool}; +bopt_cg_not(_) -> + throw(not_boolean_expr). bopt_cg_not_not({'and',As}) -> {'and',[bopt_cg_not_not(A) || A <- As]}; diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl index 0fc8d45c80..b952139f2c 100644 --- a/lib/compiler/src/beam_jump.erl +++ b/lib/compiler/src/beam_jump.erl @@ -446,11 +446,13 @@ is_label_used_in_2({set,_,_,Info}, Lbl) -> case Info of {bif,_,{f,F}} -> F =:= Lbl; {alloc,_,{gc_bif,_,{f,F}}} -> F =:= Lbl; + {alloc,_,{put_map,_,{f,F}}} -> F =:= Lbl; {'catch',{f,F}} -> F =:= Lbl; {alloc,_,_} -> false; {put_tuple,_} -> false; {get_tuple_element,_} -> false; {set_tuple_element,_} -> false; + {get_map_elements,{f,F}} -> F =:= Lbl; {line,_} -> false; _ when is_atom(Info) -> false end. diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl index 27034aecce..8ca368c167 100644 --- a/lib/compiler/src/beam_utils.erl +++ b/lib/compiler/src/beam_utils.erl @@ -748,6 +748,8 @@ live_opt([{try_end,_}=I|Is], Regs, D, Acc) -> live_opt(Is, Regs, D, [I|Acc]); live_opt([{loop_rec_end,_}=I|Is], Regs, D, Acc) -> live_opt(Is, Regs, D, [I|Acc]); +live_opt([{wait_timeout,_,nil}=I|Is], Regs, D, Acc) -> + live_opt(Is, Regs, D, [I|Acc]); live_opt([{wait_timeout,_,{Tag,_}}=I|Is], Regs, D, Acc) when Tag =/= x -> live_opt(Is, Regs, D, [I|Acc]); live_opt([{line,_}=I|Is], Regs, D, Acc) -> diff --git a/lib/compiler/src/cerl_clauses.erl b/lib/compiler/src/cerl_clauses.erl index 99fa8dd9d5..76d70dcabf 100644 --- a/lib/compiler/src/cerl_clauses.erl +++ b/lib/compiler/src/cerl_clauses.erl @@ -354,6 +354,24 @@ match(P, E, Bs) -> {false, Bs} end end; + map -> + %% The most we can do is to say "definitely no match" if a + %% binary pattern is matched against non-binary data. + case E of + any -> + {false, Bs}; + _ -> + case type(E) of + literal -> + none; + cons -> + none; + tuple -> + none; + _ -> + {false, Bs} + end + end; _ -> match_1(P, E, Bs) end. diff --git a/lib/compiler/src/cerl_inline.erl b/lib/compiler/src/cerl_inline.erl index 44293bb8ce..fa1d34cc9b 100644 --- a/lib/compiler/src/cerl_inline.erl +++ b/lib/compiler/src/cerl_inline.erl @@ -42,7 +42,7 @@ bitstr_flags/1, binary_segments/1, update_c_alias/3, update_c_apply/3, update_c_binary/2, update_c_bitstr/6, update_c_call/4, update_c_case/3, update_c_catch/2, - update_c_clause/4, c_fun/2, c_int/1, c_let/3, + update_c_clause/4, c_fun/2, c_int/1, c_let/3, ann_c_let/4, update_c_let/4, update_c_letrec/3, update_c_module/5, update_c_primop/3, update_c_receive/4, update_c_seq/3, c_seq/2, update_c_try/6, c_tuple/1, update_c_values/2, @@ -51,7 +51,7 @@ catch_body/1, clause_body/1, clause_guard/1, clause_pats/1, clause_vars/1, concrete/1, cons_hd/1, cons_tl/1, data_arity/1, data_es/1, data_type/1, - fun_body/1, fun_vars/1, get_ann/1, int_val/1, + fname_arity/1, fun_body/1, fun_vars/1, get_ann/1, int_val/1, is_c_atom/1, is_c_cons/1, is_c_fname/1, is_c_int/1, is_c_list/1, is_c_seq/1, is_c_tuple/1, is_c_var/1, is_data/1, is_literal/1, is_literal_term/1, let_arg/1, @@ -1030,8 +1030,17 @@ i_apply(E, Ctxt, Ren, Env, S) -> visit_and_count_size(Opnd, S) end, S3, Opnds), - N = apply_size(length(Es)), - {update_c_apply(E, E1, Es), count_size(N, S4)} + Arity = length(Es), + E2 = case is_c_fname(E1) andalso length(Es) =/= fname_arity(E1) of + true -> + V = new_var(Env), + ann_c_let(get_ann(E), [V], E1, + update_c_apply(E, V, Es)); + false -> + update_c_apply(E, E1, Es) + end, + N = apply_size(Arity), + {E2, count_size(N, S4)} end. apply_size(A) -> diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl index 36165245a6..25df33a287 100644 --- a/lib/compiler/src/core_lint.erl +++ b/lib/compiler/src/core_lint.erl @@ -267,10 +267,21 @@ gexpr(#c_let{vars=Vs,arg=Arg,body=B}, Def, Rt, St0) -> St1 = gbody(Arg, Def, let_varcount(Vs), St0), %This is a guard body {Lvs,St2} = variable_list(Vs, St1), gbody(B, union(Lvs, Def), Rt, St2); -gexpr(#c_call{module=#c_literal{val=erlang}, - name=#c_literal{}, - args=As}, Def, 1, St) -> - gexpr_list(As, Def, St); +gexpr(#c_call{module=#c_literal{val=erlang},name=#c_literal{val=is_record}, + args=[Arg,#c_literal{val=Tag},#c_literal{val=Size}]}, + Def, 1, St) when is_atom(Tag), is_integer(Size) -> + gexpr(Arg, Def, 1, St); +gexpr(#c_call{module=#c_literal{val=erlang},name=#c_literal{val=is_record}}, + _Def, 1, St) -> + add_error({illegal_guard,St#lint.func}, St); +gexpr(#c_call{module=#c_literal{val=erlang},name=#c_literal{val=Name},args=As}, + Def, 1, St) when is_atom(Name) -> + case is_guard_bif(Name, length(As)) of + true -> + gexpr_list(As, Def, St); + false -> + add_error({illegal_guard,St#lint.func}, St) + end; gexpr(#c_primop{name=#c_literal{val=A},args=As}, Def, _Rt, St0) when is_atom(A) -> gexpr_list(As, Def, St0); gexpr(#c_try{arg=E,vars=[#c_var{name=X}],body=#c_var{name=X}, @@ -298,6 +309,14 @@ gbitstr_list(Es, Def, St0) -> gbitstr(#c_bitstr{val=V,size=S}, Def, St) -> gexpr_list([V,S], Def, St). +%% is_guard_bif(Name, Arity) -> Boolean. + +is_guard_bif(Name, Arity) -> + erl_internal:guard_bif(Name, Arity) + orelse erl_internal:arith_op(Name, Arity) + orelse erl_internal:bool_op(Name, Arity) + orelse erl_internal:comp_op(Name, Arity). + %% expr(Expr, Defined, RetCount, State) -> State. expr(#c_var{name={_,_}=FA}, Def, _Rt, St) -> diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 4ef345f563..058abd3357 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -1810,9 +1810,14 @@ opt_bool_clauses([#c_clause{pats=[#c_literal{val=Lit}], true -> %% This clause will match. C = C0#c_clause{body=opt_bool_case(B)}, - case Lit of - false -> [C|opt_bool_clauses(Cs, SeenT, true)]; - true -> [C|opt_bool_clauses(Cs, true, SeenF)] + case {Lit,SeenT,SeenF} of + {false,_,false} -> + [C|opt_bool_clauses(Cs, SeenT, true)]; + {true,false,_} -> + [C|opt_bool_clauses(Cs, true, SeenF)]; + _ -> + add_warning(C, nomatch_shadow), + opt_bool_clauses(Cs, SeenT, SeenF) end end; opt_bool_clauses([#c_clause{pats=Ps,guard=#c_literal{val=true}}=C|Cs], SeenT, SeenF) -> @@ -2362,6 +2367,15 @@ is_safe_bool_expr_1(#c_call{module=#c_literal{val=erlang}, %% been rewritten to is_record(Expr, LiteralTag, TupleSize). false; is_safe_bool_expr_1(#c_call{module=#c_literal{val=erlang}, + name=#c_literal{val=is_function}, + args=[A,#c_literal{val=Arity}]}, + Sub, _BoolVars) when is_integer(Arity), Arity >= 0 -> + is_safe_simple(A, Sub); +is_safe_bool_expr_1(#c_call{module=#c_literal{val=erlang}, + name=#c_literal{val=is_function}}, + _Sub, _BoolVars) -> + false; +is_safe_bool_expr_1(#c_call{module=#c_literal{val=erlang}, name=#c_literal{val=Name},args=Args}, Sub, BoolVars) -> NumArgs = length(Args), diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl index e00ee1f3ad..f1331d1fe7 100644 --- a/lib/compiler/src/v3_codegen.erl +++ b/lib/compiler/src/v3_codegen.erl @@ -1551,7 +1551,11 @@ map_pair_strip_and_termsort(Es) -> %% [{map_pair,K,V}] %% where K is for example {integer, 1} and we want to sort on 1. Ls = [{K,V}||{_,K,V}<-Es], - lists:sort(fun({{_,A},_},{{_,B},_}) -> erts_internal:cmp_term(A,B) < 0 end, Ls). + lists:sort(fun ({{_,A},_}, {{_,B},_}) -> erts_internal:cmp_term(A,B) =< 0; + ({nil,_}, {{_,B},_}) -> [] =< B; + ({{_,A},_}, {nil,_}) -> A =< []; + ({nil,_}, {nil,_}) -> true + end, Ls). %%% %%% Code generation for constructing binaries. diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index d3db395995..3d17557e01 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -274,51 +274,67 @@ gexpr({op,L,'orelse',E1,E2}, Bools, St0) -> True = {atom,L,true}, E = make_bool_switch_guard(L, E1, V, True, E2), gexpr(E, Bools, St); -gexpr({op,Line,Op,L,R}=Call, Bools0, St0) -> +gexpr({op,Line,Op,L,R}=E, Bools, St) -> case erl_internal:bool_op(Op, 2) of - true -> - {Le,Lps,Bools1,St1} = gexpr(L, Bools0, St0), - {Ll,Llps,St2} = force_safe(Le, St1), - {Re,Rps,Bools,St3} = gexpr(R, Bools1, St2), - {Rl,Rlps,St4} = force_safe(Re, St3), - Anno = lineno_anno(Line, St4), - {#icall{anno=#a{anno=Anno}, %Must have an #a{} - module=#c_literal{anno=Anno,val=erlang}, - name=#c_literal{anno=Anno,val=Op}, - args=[Ll,Rl]},Lps ++ Llps ++ Rps ++ Rlps,Bools,St4}; - false -> - gexpr_test(Call, Bools0, St0) + true -> + gexpr_bool(Op, L, R, Bools, St, Line); + false -> + gexpr_test(E, Bools, St) end; -gexpr({op,Line,Op,A}=Call, Bools0, St0) -> - case Op of - 'not' -> - {Ae0,Aps,Bools,St1} = gexpr(A, Bools0, St0), - case Ae0 of - #icall{module=#c_literal{val=erlang}, - name=#c_literal{val='=:='}, - args=[E,#c_literal{val=true}]}=EqCall -> - %% - %% Doing the following transformation - %% not(Expr =:= true) ==> Expr =:= false - %% will help eliminating redundant is_boolean/1 tests. - %% - Ae = EqCall#icall{args=[E,#c_literal{val=false}]}, - {Al,Alps,St2} = force_safe(Ae, St1), - {Al,Aps ++ Alps,Bools,St2}; - Ae -> - {Al,Alps,St2} = force_safe(Ae, St1), - Anno = lineno_anno(Line, St2), - {#icall{anno=#a{anno=Anno}, %Must have an #a{} - module=#c_literal{anno=Anno,val=erlang}, - name=#c_literal{anno=Anno,val=Op}, - args=[Al]},Aps ++ Alps,Bools,St2} - end; - _ -> - gexpr_test(Call, Bools0, St0) +gexpr({call,Line,{remote,_,{atom,_,erlang},{atom,_,Op}},[L,R]}=E, Bools, St) -> + case erl_internal:bool_op(Op, 2) of + true -> + gexpr_bool(Op, L, R, Bools, St, Line); + false -> + gexpr_test(E, Bools, St) end; +gexpr({op,Line,'not',A}, Bools, St) -> + gexpr_not(A, Bools, St, Line); +gexpr({call,Line,{remote,_,{atom,_,erlang},{atom,_,'not'}},[A]}, Bools, St) -> + gexpr_not(A, Bools, St, Line); gexpr(E0, Bools, St0) -> gexpr_test(E0, Bools, St0). +%% gexpr_not(L, R, Bools, State) -> {Cexpr,[PreExp],Bools,State}. +%% Generate a guard for boolean operators + +gexpr_bool(Op, L, R, Bools0, St0, Line) -> + {Le,Lps,Bools1,St1} = gexpr(L, Bools0, St0), + {Ll,Llps,St2} = force_safe(Le, St1), + {Re,Rps,Bools,St3} = gexpr(R, Bools1, St2), + {Rl,Rlps,St4} = force_safe(Re, St3), + Anno = lineno_anno(Line, St4), + {#icall{anno=#a{anno=Anno}, %Must have an #a{} + module=#c_literal{anno=Anno,val=erlang}, + name=#c_literal{anno=Anno,val=Op}, + args=[Ll,Rl]},Lps ++ Llps ++ Rps ++ Rlps,Bools,St4}. + +%% gexpr_not(Expr, Bools, State) -> {Cexpr,[PreExp],Bools,State}. +%% Generate an erlang:'not'/1 guard test. + +gexpr_not(A, Bools0, St0, Line) -> + {Ae0,Aps,Bools,St1} = gexpr(A, Bools0, St0), + case Ae0 of + #icall{module=#c_literal{val=erlang}, + name=#c_literal{val='=:='}, + args=[E,#c_literal{val=true}]}=EqCall -> + %% + %% Doing the following transformation + %% not(Expr =:= true) ==> Expr =:= false + %% will help eliminating redundant is_boolean/1 tests. + %% + Ae = EqCall#icall{args=[E,#c_literal{val=false}]}, + {Al,Alps,St2} = force_safe(Ae, St1), + {Al,Aps ++ Alps,Bools,St2}; + Ae -> + {Al,Alps,St2} = force_safe(Ae, St1), + Anno = lineno_anno(Line, St2), + {#icall{anno=#a{anno=Anno}, %Must have an #a{} + module=#c_literal{anno=Anno,val=erlang}, + name=#c_literal{anno=Anno,val='not'}, + args=[Al]},Aps ++ Alps,Bools,St2} + end. + %% gexpr_test(Expr, Bools, State) -> {Cexpr,[PreExp],Bools,State}. %% Generate a guard test. At this stage we must be sure that we have %% a proper boolean value here so wrap things with an true test if we @@ -335,7 +351,8 @@ gexpr_test(E0, Bools0, St0) -> #icall{anno=Anno,module=#c_literal{val=erlang},name=#c_literal{val=N},args=As} -> Ar = length(As), case erl_internal:type_test(N, Ar) orelse - erl_internal:comp_op(N, Ar) of + erl_internal:comp_op(N, Ar) orelse + erl_internal:bool_op(N, Ar) of true -> {E1,Eps0,Bools0,St1}; false -> Lanno = Anno#a.anno, @@ -1765,13 +1782,16 @@ uexpr(#iletrec{anno=A,defs=Fs0,body=B0}, Ks, St0) -> {B1,St2} = uexprs(B0, Ks, St1), Used = used_in_any(map(fun ({_,F}) -> F end, Fs1) ++ B1), {#iletrec{anno=A#a{us=Used,ns=[]},defs=Fs1,body=B1},St2}; -uexpr(#icase{anno=A,args=As0,clauses=Cs0,fc=Fc0}, Ks, St0) -> +uexpr(#icase{anno=#a{anno=Anno}=A,args=As0,clauses=Cs0,fc=Fc0}, Ks, St0) -> %% As0 will never generate new variables. {As1,St1} = uexpr_list(As0, Ks, St0), {Cs1,St2} = uclauses(Cs0, Ks, St1), {Fc1,St3} = uclause(Fc0, Ks, St2), Used = union(used_in_any(As1), used_in_any(Cs1)), - New = new_in_all(Cs1), + New = case member(list_comprehension, Anno) of + true -> []; + false -> new_in_all(Cs1) + end, {#icase{anno=A#a{us=Used,ns=New},args=As1,clauses=Cs1,fc=Fc1},St3}; uexpr(#ifun{anno=A0,id=Id,vars=As,clauses=Cs0,fc=Fc0,name=Name}, Ks0, St0) -> Avs = lit_list_vars(As), diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index 5675572092..d00dd56f30 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -519,7 +519,7 @@ map_split_pairs(A, Var, Ces, Sub, St0) -> Kes1 = [#k_map_pair{key=K,val=V}||{_,{assoc,K,V}} <- Assoc], {Mvar,Em,St2} = force_atomic(#k_map{anno=A,op=assoc,var=Var,es=Kes1},St1), Kes2 = [#k_map_pair{key=K,val=V}||{_,{exact,K,V}} <- Exact], - {#k_map{anno=A,op=exact,var=Mvar,es=Kes2},Em ++ Esp,St2} + {#k_map{anno=A,op=exact,var=Mvar,es=Kes2},Esp ++ Em,St2} end. diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl index 7bef0aa27c..b5408ecd8f 100644 --- a/lib/compiler/test/andor_SUITE.erl +++ b/lib/compiler/test/andor_SUITE.erl @@ -129,6 +129,10 @@ t_case_y(X, Y, Z) -> Y =:= 100 end. +-define(GUARD(E), if E -> true; + true -> false + end). + t_and_or(Config) when is_list(Config) -> ?line true = true and true, ?line false = true and false, @@ -160,11 +164,16 @@ t_and_or(Config) when is_list(Config) -> ?line true = false or id(true), ?line false = false or id(false), - ok. + True = id(true), --define(GUARD(E), if E -> true; - true -> false - end). + false = ?GUARD(erlang:'and'(bar, True)), + false = ?GUARD(erlang:'or'(bar, True)), + false = ?GUARD(erlang:'not'(erlang:'and'(bar, True))), + false = ?GUARD(erlang:'not'(erlang:'not'(erlang:'and'(bar, True)))), + + true = (fun (X = true) when X or true or X -> true end)(True), + + ok. t_andalso(Config) when is_list(Config) -> Bs = [true,false], diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl index aa222c48de..428ad65364 100644 --- a/lib/compiler/test/core_SUITE.erl +++ b/lib/compiler/test/core_SUITE.erl @@ -24,7 +24,7 @@ dehydrated_itracer/1,nested_tries/1, seq_in_guard/1,make_effect_seq/1,eval_is_boolean/1, unsafe_case/1,nomatch_shadow/1,reversed_annos/1, - map_core_test/1,eval_case/1]). + map_core_test/1,eval_case/1,bad_boolean_guard/1]). -include_lib("test_server/include/test_server.hrl"). @@ -50,7 +50,7 @@ groups() -> [{p,test_lib:parallel(), [dehydrated_itracer,nested_tries,seq_in_guard,make_effect_seq, eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos, - map_core_test,eval_case + map_core_test,eval_case,bad_boolean_guard ]}]. @@ -77,6 +77,7 @@ end_per_group(_GroupName, Config) -> ?comp(reversed_annos). ?comp(map_core_test). ?comp(eval_case). +?comp(bad_boolean_guard). try_it(Mod, Conf) -> Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)), diff --git a/lib/compiler/test/core_SUITE_data/bad_boolean_guard.core b/lib/compiler/test/core_SUITE_data/bad_boolean_guard.core new file mode 100644 index 0000000000..318f8e3dc7 --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/bad_boolean_guard.core @@ -0,0 +1,32 @@ +module 'bad_boolean_guard' ['bad_boolean_guard'/0, + 'module_info'/0, + 'module_info'/1] + attributes [] +'bad_boolean_guard'/0 = + fun () -> + apply 'f'/1 + ('true') +'f'/1 = + fun (_X_cor0) -> + case _X_cor0 of + <X> + when try + call 'erlang':'and' + ('bad', _X_cor0) + of <Try> -> + Try + catch <T,R> -> + 'false' -> + 'not_ok' + <_X_cor3> when 'true' -> + 'ok' + end +'module_info'/0 = + fun () -> + call 'erlang':'get_module_info' + ('bad_boolean_guard') +'module_info'/1 = + fun (_X_cor0) -> + call 'erlang':'get_module_info' + ('bad_boolean_guard', _X_cor0) +end
\ No newline at end of file diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index 8151dc1b16..9c986576d5 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -23,7 +23,7 @@ t_element/1,setelement/1,t_length/1,append/1,t_apply/1,bifs/1, eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1, unused_multiple_values_error/1,unused_multiple_values/1, - multiple_aliases/1]). + multiple_aliases/1,redundant_boolean_clauses/1]). -export([foo/0,foo/1,foo/2,foo/3]). @@ -40,7 +40,7 @@ groups() -> [t_element,setelement,t_length,append,t_apply,bifs, eq,nested_call_in_case,guard_try_catch,coverage, unused_multiple_values_error,unused_multiple_values, - multiple_aliases]}]. + multiple_aliases,redundant_boolean_clauses]}]. init_per_suite(Config) -> @@ -365,4 +365,13 @@ run_once() -> ok. +redundant_boolean_clauses(Config) when is_list(Config) -> + X = id(0), + yes = case X == 0 of + false -> no; + false -> no; + true -> yes + end. + + id(I) -> I. diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl index a0a9bb7ddd..eb205d09a7 100644 --- a/lib/compiler/test/guard_SUITE.erl +++ b/lib/compiler/test/guard_SUITE.erl @@ -33,7 +33,7 @@ tricky/1,rel_ops/1,literal_type_tests/1, basic_andalso_orelse/1,traverse_dcd/1, check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1, - bad_constants/1]). + bad_constants/1,bad_guards/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -50,7 +50,7 @@ groups() -> t_is_boolean,is_function_2,tricky,rel_ops, literal_type_tests,basic_andalso_orelse,traverse_dcd, check_qlc_hrl,andalso_semi,t_tuple_size,binary_part, - bad_constants]}]. + bad_constants,bad_guards]}]. init_per_suite(Config) -> Config. @@ -1023,6 +1023,10 @@ is_function_2(Config) when is_list(Config) -> true = is_function(id(fun() -> ok end), 0), false = is_function(id(fun ?MODULE:all/1), 0), false = is_function(id(fun() -> ok end), 1), + {'EXIT',{badarg,_}} = + (catch is_function(id(fun() -> ok end), -1) orelse error), + {'EXIT',{badarg,_}} = + (catch is_function(id(fun() -> ok end), '') orelse error), F = fun(_) -> ok end, if @@ -1550,6 +1554,10 @@ bad_constants(Config) when is_list(Config) -> ?line ?FAILING(3.14), ok. +bad_guards(Config) when is_list(Config) -> + if erlang:float(self()); true -> ok end, + ok. + %% Call this function to turn off constant propagation. id(I) -> I. diff --git a/lib/compiler/test/lc_SUITE.erl b/lib/compiler/test/lc_SUITE.erl index f5948504b3..398398a397 100644 --- a/lib/compiler/test/lc_SUITE.erl +++ b/lib/compiler/test/lc_SUITE.erl @@ -23,7 +23,7 @@ init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, basic/1,deeply_nested/1,no_generator/1, - empty_generator/1]). + empty_generator/1,no_export/1]). -include_lib("test_server/include/test_server.hrl"). @@ -31,7 +31,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> test_lib:recompile(?MODULE), - [basic, deeply_nested, no_generator, empty_generator]. + [basic, deeply_nested, no_generator, empty_generator, no_export]. groups() -> []. @@ -177,6 +177,10 @@ empty_generator(Config) when is_list(Config) -> ?line [] = [X || {X} <- [], (false or (X/0 > 3))], ok. +no_export(Config) when is_list(Config) -> + [] = [ _X = a || false ] ++ [ _X = a || false ], + ok. + id(I) -> I. fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Args,_}|_]}}) -> ok; diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl index 3639192a51..b7e27afef1 100644 --- a/lib/compiler/test/map_SUITE.erl +++ b/lib/compiler/test/map_SUITE.erl @@ -107,6 +107,9 @@ t_build_and_match_literals(Config) when is_list(Config) -> M = #{ map_1:=#{ map_2:=#{value_3 := third}, value_2:= second}, value_1:=first} = id(#{ map_1=>#{ map_2=>#{value_3 => third}, value_2=> second}, value_1=>first}), + %% nil key + #{[]:=ok,1:=2} = id(#{[]=>ok,1=>2}), + %% error case {'EXIT',{{badmatch,_},_}} = (catch (#{x:=3,x:=2} = id(#{x=>3}))), {'EXIT',{{badmatch,_},_}} = (catch (#{x:=2} = id(#{x=>3}))), @@ -189,7 +192,9 @@ loop_match_and_update_literals_x_q(#{q:=Q0,x:=X0} = Map, [{X,Q}|Vs]) -> t_update_map_expressions(Config) when is_list(Config) -> M = maps:new(), - #{ a := 1 } = M#{a => 1}, + X = id(fondue), + M1 = #{ a := 1 } = M#{a => 1}, + #{ b := {X} } = M1#{ a := 1, b => {X} }, #{ b := 2 } = (maps:new())#{ b => 2 }, @@ -287,16 +292,21 @@ get_val(#{ val := V }) -> {some_val, V}. t_guard_bifs(Config) when is_list(Config) -> true = map_guard_empty(), + true = map_guard_empty_2(), true = map_guard_head(#{a=>1}), false = map_guard_head([]), true = map_guard_body(#{a=>1}), false = map_guard_body({}), true = map_guard_pattern(#{a=>1, <<"hi">> => "hi" }), false = map_guard_pattern("list"), + true = map_guard_tautology(), + true = map_guard_ill_map_size(), ok. map_guard_empty() when is_map(#{}); false -> true. +map_guard_empty_2() when true; #{} andalso false -> true. + map_guard_head(M) when is_map(M) -> true; map_guard_head(_) -> false. @@ -305,6 +315,10 @@ map_guard_body(M) -> is_map(M). map_guard_pattern(#{}) -> true; map_guard_pattern(_) -> false. +map_guard_tautology() when #{} =:= #{}; true -> true. + +map_guard_ill_map_size() when true; map_size(0) -> true. + t_guard_sequence(Config) when is_list(Config) -> {1, "a"} = map_guard_sequence_1(#{seq=>1,val=>id("a")}), {2, "b"} = map_guard_sequence_1(#{seq=>2,val=>id("b")}), diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl index ec49267ded..00a6e900d4 100644 --- a/lib/compiler/test/receive_SUITE.erl +++ b/lib/compiler/test/receive_SUITE.erl @@ -257,6 +257,7 @@ wait(Config) when is_list(Config) -> self() ! <<42>>, <<42>> = wait_1(r, 1, 2), {1,2,3} = wait_1(1, 2, 3), + {'EXIT',{timeout_value,_}} = (catch receive after [] -> timeout end), ok. wait_1(r, _, _) -> diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl index 16d15a59e5..de56a59e12 100644 --- a/lib/compiler/test/warnings_SUITE.erl +++ b/lib/compiler/test/warnings_SUITE.erl @@ -37,7 +37,8 @@ -export([pattern/1,pattern2/1,pattern3/1,pattern4/1, guard/1,bad_arith/1,bool_cases/1,bad_apply/1, - files/1,effect/1,bin_opt_info/1,bin_construction/1, comprehensions/1]). + files/1,effect/1,bin_opt_info/1,bin_construction/1, comprehensions/1, + maps/1,redundant_boolean_clauses/1]). % Default timetrap timeout (set in init_per_testcase). -define(default_timeout, ?t:minutes(2)). @@ -61,7 +62,8 @@ groups() -> [{p,test_lib:parallel(), [pattern,pattern2,pattern3,pattern4,guard, bad_arith,bool_cases,bad_apply,files,effect, - bin_opt_info,bin_construction,comprehensions]}]. + bin_opt_info,bin_construction,comprehensions,maps, + redundant_boolean_clauses]}]. init_per_suite(Config) -> Config. @@ -200,6 +202,8 @@ pattern4(Config) when is_list(Config) -> [nowarn_unused_vars], {warnings, [{9,sys_core_fold,no_clause_match}, + {11,sys_core_fold,nomatch_shadow}, + {15,sys_core_fold,nomatch_shadow}, {18,sys_core_fold,no_clause_match}, {23,sys_core_fold,no_clause_match}, {33,sys_core_fold,no_clause_match} @@ -552,6 +556,41 @@ comprehensions(Config) when is_list(Config) -> run(Config, Ts), ok. +maps(Config) when is_list(Config) -> + Ts = [{bad_map, + <<" + t() -> + case maybe_map of + #{} -> ok; + not_map -> error + end. + x() -> + case true of + #{} -> error; + true -> ok + end. + ">>, + [], + {warnings,[{3,sys_core_fold,no_clause_match}, + {9,sys_core_fold,nomatch_clause_type}]}}], + run(Config, Ts), + ok. + +redundant_boolean_clauses(Config) when is_list(Config) -> + Ts = [{redundant_boolean_clauses, + <<" + t(X) -> + case X == 0 of + false -> no; + false -> no; + true -> yes + end. + ">>, + [], + {warnings,[{5,sys_core_fold,nomatch_shadow}]}}], + run(Config, Ts), + ok. + %%% %%% End of test cases. %%% diff --git a/lib/dialyzer/test/small_SUITE_data/src/predef.erl b/lib/dialyzer/test/small_SUITE_data/src/predef.erl index c2364fd1c2..ee9073aa67 100644 --- a/lib/dialyzer/test/small_SUITE_data/src/predef.erl +++ b/lib/dialyzer/test/small_SUITE_data/src/predef.erl @@ -5,8 +5,8 @@ -export_type([array/0, digraph/0, gb_set/0]). -%% Before R17B local re-definitions of pre-defined opaque types were -%% ignored but did not generate any warning. +%% Before Erlang/OTP 17.0 local re-definitions of pre-defined opaque +%% types were ignored but did not generate any warning. -opaque array() :: atom(). -opaque digraph() :: atom(). -opaque gb_set() :: atom(). diff --git a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl index e3cc354206..e6bf9ce20e 100644 --- a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl +++ b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl @@ -1014,6 +1014,8 @@ t_type([#xmlElement{name = nil}]) -> t_nil(); t_type([#xmlElement{name = list, content = Es}]) -> t_list(Es); +t_type([#xmlElement{name = nonempty_list, content = Es}]) -> + t_nonempty_list(Es); t_type([#xmlElement{name = tuple, content = Es}]) -> t_tuple(Es); t_type([#xmlElement{name = 'fun', content = Es}]) -> @@ -1023,7 +1025,11 @@ t_type([#xmlElement{name = abstype, content = Es}]) -> t_type([#xmlElement{name = union, content = Es}]) -> t_union(Es); t_type([#xmlElement{name = record, content = Es}]) -> - t_record(Es). + t_record(Es); +t_type([#xmlElement{name = map, content = Es}]) -> + t_map(Es); +t_type([#xmlElement{name = map_field, content = Es}]) -> + t_map_field(Es). t_var(E) -> [get_attrval(name, E)]. @@ -1046,6 +1052,9 @@ t_nil() -> t_list(Es) -> ["["] ++ t_utype(get_elem(type, Es)) ++ ["]"]. +t_nonempty_list(Es) -> + ["["] ++ t_utype(get_elem(type, Es)) ++ [", ...]"]. + t_tuple(Es) -> ["{"] ++ seq(fun t_utype_elem/1, Es, ["}"]). @@ -1058,6 +1067,12 @@ t_record([E|Es]) -> t_field(#xmlElement{name=field, content=[Atom,Type]}) -> [get_attrval(value, Atom), "="] ++ t_utype_elem(Type). +t_map(Es) -> + ["#{"] ++ seq(fun t_utype_elem/1, Es, ["}"]). + +t_map_field([K,V]) -> + [t_utype_elem(K) ++ " => " ++ t_utype_elem(V)]. + t_abstype(Es) -> case split_at_colon(t_name(get_elem(erlangName, Es)),[]) of {Mod,Type} -> diff --git a/lib/erl_docgen/src/docgen_otp_specs.erl b/lib/erl_docgen/src/docgen_otp_specs.erl index 3240edd68e..886194598f 100644 --- a/lib/erl_docgen/src/docgen_otp_specs.erl +++ b/lib/erl_docgen/src/docgen_otp_specs.erl @@ -433,7 +433,7 @@ t_tuple(Es) -> ["{"] ++ seq(fun t_utype_elem/1, Es, ["}"]). t_map() -> - ["#{}"]. + ["map()"]. t_fun(Es) -> ["("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es), diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 0512d4bc3c..a460f16272 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -1073,14 +1073,14 @@ type(hipe_bifs, fun_to_address, 1, Xs, Opaques) -> %% type(hipe_bifs, get_emu_address, 1, Xs, Opaques) -> %% strict(hipe_bifs, get_emu_address, 1, Xs, %% fun (_) -> t_integer() end, Opaques); % address +type(hipe_bifs, get_fe, 2, Xs, Opaques) -> + strict(hipe_bifs, get_fe, 2, Xs, fun (_) -> t_integer() end, Opaques); type(hipe_bifs, get_rts_param, 1, Xs, Opaques) -> strict(hipe_bifs, get_rts_param, 1, Xs, fun (_) -> t_sup(t_integer(), t_nil()) end, Opaques); type(hipe_bifs, invalidate_funinfo_native_addresses, 1, Xs, Opaques) -> strict(hipe_bifs, invalidate_funinfo_native_addresses, 1, Xs, fun (_) -> t_nil() end, Opaques); -type(hipe_bifs, make_fe, 3, Xs, Opaques) -> - strict(hipe_bifs, make_fe, 3, Xs, fun (_) -> t_integer() end, Opaques); %% type(hipe_bifs, make_native_stub, 2, Xs, Opaques) -> %% strict(hipe_bifs, make_native_stub, 2, Xs, %% fun (_) -> t_integer() end, Opaques); % address @@ -1116,6 +1116,9 @@ type(hipe_bifs, set_funinfo_native_address, 3, Xs, Opaques) -> type(hipe_bifs, set_native_address, 3, Xs, Opaques) -> strict(hipe_bifs, set_native_address, 3, Xs, fun (_) -> t_nil() end, Opaques); +type(hipe_bifs, set_native_address_in_fe, 2, Xs, Opaques) -> + strict(hipe_bifs, set_native_address_in_fe, 2, Xs, + fun (_) -> t_atom('true') end, Opaques); type(hipe_bifs, system_crc, 1, Xs, Opaques) -> strict(hipe_bifs, system_crc, 1, Xs, fun (_) -> t_crc32() end, Opaques); type(hipe_bifs, term_to_word, 1, Xs, Opaques) -> @@ -2451,12 +2454,12 @@ arg_types(hipe_bifs, fun_to_address, 1) -> [t_mfa()]; %% arg_types(hipe_bifs, get_emu_address, 1) -> %% [t_mfa()]; +arg_types(hipe_bifs, get_fe, 2) -> + [t_atom(), t_tuple([t_integer(), t_integer(), t_integer()])]; arg_types(hipe_bifs, get_rts_param, 1) -> [t_fixnum()]; arg_types(hipe_bifs, invalidate_funinfo_native_addresses, 1) -> [t_list(t_mfa())]; -arg_types(hipe_bifs, make_fe, 3) -> - [t_integer(), t_atom(), t_tuple([t_integer(), t_integer(), t_integer()])]; %% arg_types(hipe_bifs, make_native_stub, 2) -> %% [t_integer(), t_arity()]; arg_types(hipe_bifs, mark_referred_from, 1) -> @@ -2485,6 +2488,8 @@ arg_types(hipe_bifs, set_funinfo_native_address, 3) -> arg_types(hipe_bifs, set_native_address, 3); arg_types(hipe_bifs, set_native_address, 3) -> [t_mfa(), t_integer(), t_boolean()]; +arg_types(hipe_bifs, set_native_address_in_fe, 2) -> + [t_integer(), t_integer()]; arg_types(hipe_bifs, system_crc, 1) -> [t_crc32()]; arg_types(hipe_bifs, term_to_word, 1) -> diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile index 6f1e61e70c..ff77c3eea0 100644 --- a/lib/stdlib/doc/src/Makefile +++ b/lib/stdlib/doc/src/Makefile @@ -71,6 +71,7 @@ XML_REF3_FILES = \ lib.xml \ lists.xml \ log_mf_h.xml \ + maps.xml \ math.xml \ ms_transform.xml \ orddict.xml \ diff --git a/lib/stdlib/doc/src/maps.xml b/lib/stdlib/doc/src/maps.xml new file mode 100644 index 0000000000..76137e3dee --- /dev/null +++ b/lib/stdlib/doc/src/maps.xml @@ -0,0 +1,318 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2013</year><year>2014</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + <title>maps</title> + <prepared>Björn-Egil Dahlberg</prepared> + <docno>1</docno> + <date>2014-02-28</date> + <rev>A</rev> + </header> + <module>maps</module> + <modulesummary>Maps Processing Functions</modulesummary> + <description> + <p>This module contains functions for maps processing.</p> + </description> + <funcs> + + <func> + <name name="find" arity="2"/> + <fsummary></fsummary> + <desc> + <p> + Returns a tuple <c>{ok, Value}</c> where <c><anno>Value</anno></c> is the value associated with <c><anno>Key</anno></c>, + or <c>error</c> if no value is associated with <c><anno>Key</anno></c> in <c><anno>Map</anno></c>. + </p> + <p>Example:</p> + <code type="none"> +> Map = #{"hi" => 42}, + Key = "hi", + maps:find(Key,Map). +{ok,42} </code> + </desc> + </func> + + <func> + <name name="fold" arity="3"/> + <fsummary></fsummary> + <desc> + <p> + Calls <c>F(K, V, AccIn)</c> for every <c><anno>K</anno></c> to value <c><anno>V</anno></c> + association in <c><anno>Map</anno></c> in + arbitrary order. The function <c>fun F/3</c> must return a new accumulator + which is passed to the next successive call. <c>maps:fold/3</c> returns the final + value of the accumulator. The initial accumulator value <c><anno>Init</anno></c> is returned if + the map is empty. + </p> + <p>Example:</p> + <code type="none"> +> Fun = fun(K,V,AccIn) when is_list(K) -> AccIn + V end, + Map = #{"k1" => 1, "k2" => 2, "k3" => 3}, + maps:fold(Fun,0,Map). +6</code> + </desc> + </func> + + <func> + <name name="from_list" arity="1"/> + <fsummary></fsummary> + <desc> + <p> + The function takes a list of key-value tuples elements and builds a + map. The associations may be in any order and both keys and values in the + association may be of any term. If the same key appears more than once, + the latter (rightmost) value is used and the previous values are ignored. + </p> + <p>Example:</p> + <code type="none"> +> List = [{"a",ignored},{1337,"value two"},{42,value_three},{"a",1}], + maps:from_list(List). +#{42 => value_three,1337 => "value two","a" => 1}</code> + </desc> + </func> + + <func> + <name name="get" arity="2"/> + <fsummary></fsummary> + <desc> + <p> + Returns the value <c><anno>Value</anno></c> associated with <c><anno>Key</anno></c> if + <c><anno>Map</anno></c> contains <c><anno>Key</anno></c>. + If no value is associated with <c><anno>Key</anno></c> then the call will + fail with an exception. + </p> + <p>Example:</p> + <code type="none"> +> Key = 1337, + Map = #{42 => value_two,1337 => "value one","a" => 1}, + maps:get(Key,Map). +"value one"</code> + </desc> + </func> + + <func> + <name name="is_key" arity="2"/> + <fsummary></fsummary> + <desc> + <p> + Returns <c>true</c> if map <c><anno>Map</anno></c> contains <c><anno>Key</anno></c> and returns + <c>false</c> if it does not contain the <c><anno>Key</anno></c>. + The function will fail with an exception if <c><anno>Map</anno></c> is not a Map. + </p> + <p>Example:</p> + <code type="none"> +> Map = #{"42" => value}. +#{"42"> => value} +> maps:is_key("42",Map). +true +> maps:is_key(value,Map). +false</code> + </desc> + </func> + + <func> + <name name="keys" arity="1"/> + <fsummary></fsummary> + <desc> + <p> + Returns a complete list of keys, in arbitrary order, which resides within <c><anno>Map</anno></c>. + </p> + <p>Example:</p> + <code type="none"> +> Map = #{42 => value_three,1337 => "value two","a" => 1}, + maps:keys(Map). +[42,1337,"a"]</code> + </desc> + </func> + + <func> + <name name="map" arity="2"/> + <fsummary></fsummary> + <desc> + <p> + The function produces a new map <c><anno>Map2</anno></c> by calling the function <c>fun F(K, V1)</c> for + every <c><anno>K</anno></c> to value <c><anno>V1</anno></c> association in <c><anno>Map1</anno></c> in arbitrary order. + The function <c>fun F/2</c> must return the value <c><anno>V2</anno></c> to be associated with key <c><anno>K</anno></c> for + the new map <c><anno>Map2</anno></c>. + </p> + <p>Example:</p> + <code type="none"> +> Fun = fun(K,V1) when is_list(K) -> V1*2 end, + Map = #{"k1" => 1, "k2" => 2, "k3" => 3}, + maps:map(Fun,Map). +#{"k1" => 2,"k2" => 4,"k3" => 6}</code> + </desc> + </func> + + <func> + <name name="merge" arity="2"/> + <fsummary></fsummary> + <desc> + <p> + Merges two maps into a single map <c><anno>Map3</anno></c>. If two keys exists in both maps the + value in <c><anno>Map1</anno></c> will be superseded by the value in <c><anno>Map2</anno></c>. + </p> + <p>Example:</p> + <code type="none"> +> Map1 = #{a => "value_one", b => "value_two"}, + Map2 = #{a => 1, c => 2}, + maps:merge(Map1,Map2). +#{a => 1,b => "value_two",c => 2}</code> + </desc> + </func> + + <func> + <name name="new" arity="0"/> + <fsummary></fsummary> + <desc> + <p> + Returns a new empty map. + </p> + <p>Example:</p> + <code type="none"> +> maps:new(). +#{}</code> + </desc> + </func> + + <func> + <name name="put" arity="3"/> + <fsummary></fsummary> + <desc> + <p> + Associates <c><anno>Key</anno></c> with value <c><anno>Value</anno></c> and inserts the association into map <c>Map2</c>. + If key <c><anno>Key</anno></c> already exists in map <c><anno>Map1</anno></c>, the old associated value is + replaced by value <c><anno>Value</anno></c>. The function returns a new map <c><anno>Map2</anno></c> containing the new association and + the old associations in <c><anno>Map1</anno></c>. + </p> + <p>Example:</p> + <code type="none"> +> Map = #{"a" => 1}. +#{"a" => 1} +> maps:put("a", 42, Map). +#{"a" => 42} +> maps:put("b", 1337, Map). +#{"a" => 1,"b" => 1337}</code> + </desc> + </func> + + <func> + <name name="remove" arity="2"/> + <fsummary></fsummary> + <desc> + <p> + The function removes the <c><anno>Key</anno></c>, if it exists, and its associated value from + <c><anno>Map1</anno></c> and returns a new map <c><anno>Map2</anno></c> without key <c><anno>Key</anno></c>. + </p> + <p>Example:</p> + <code type="none"> +> Map = #{"a" => 1}. +#{"a" => 1} +> maps:remove("a",Map). +#{} +> maps:remove("b",Map). +#{"a" => 1}</code> + </desc> + </func> + + <func> + <name name="size" arity="1"/> + <fsummary></fsummary> + <desc> + <p> + The function returns the number of key-value associations in the <c><anno>Map</anno></c>. + This operation happens in constant time. + </p> + <p>Example:</p> + <code type="none"> +> Map = #{42 => value_two,1337 => "value one","a" => 1}, + maps:size(Map). +3</code> + </desc> + </func> + + <func> + <name name="to_list" arity="1"/> + <fsummary></fsummary> + <desc> + <p> + The fuction returns a list of pairs representing the key-value associations of <c><anno>Map</anno></c>, + where the pairs, <c>[{K1,V1}, ..., {Kn,Vn}]</c>, are returned in arbitrary order. + </p> + <p>Example:</p> + <code type="none"> +> Map = #{42 => value_three,1337 => "value two","a" => 1}, + maps:to_list(Map). +[{42,value_three},{1337,"value two"},{"a",1}]</code> + </desc> + </func> + + <func> + <name name="update" arity="3"/> + <fsummary></fsummary> + <desc> + <p> + If <c><anno>Key</anno></c> exists in <c><anno>Map1</anno></c> the old associated value is + replaced by value <c><anno>Value</anno></c>. The function returns a new map <c><anno>Map2</anno></c> containing + the new associated value. If <c><anno>Key</anno></c> does not exist in <c><anno>Map1</anno></c> an exception is + generated. + </p> + <p>Example:</p> + <code type="none"> +> Map = #{"a" => 1}. +#{"a" => 1} +> maps:update("a", 42, Map). +#{"a" => 42}</code> + </desc> + </func> + + <func> + <name name="values" arity="1"/> + <fsummary></fsummary> + <desc> + <p> + Returns a complete list of values, in arbitrary order, contained in map <c>M</c>. + </p> + <p>Example:</p> + <code type="none"> +> Map = #{42 => value_three,1337 => "value two","a" => 1}, + maps:values(Map). +[value_three,"value two",1]</code> + </desc> + </func> + + <func> + <name name="without" arity="2"/> + <fsummary></fsummary> + <desc> + <p> + Returns a new map <c><anno>Map2</anno></c> without the keys <c>K1</c> through <c>Kn</c> and their associated values from map <c><anno>Map1</anno></c>. + Any key in <c><anno>Ks</anno></c> that does not exist in <c><anno>Map1</anno></c> are ignored. + </p> + <p>Example:</p> + <code type="none"> +> Map = #{42 => value_three,1337 => "value two","a" => 1}, + Ks = ["a",42,"other key"], + maps:without(Ks,Map). +#{1337 => "value two"}</code> + </desc> + </func> + </funcs> +</erlref> diff --git a/lib/stdlib/doc/src/ref_man.xml b/lib/stdlib/doc/src/ref_man.xml index 4ecd02a4bf..6c35578bdf 100644 --- a/lib/stdlib/doc/src/ref_man.xml +++ b/lib/stdlib/doc/src/ref_man.xml @@ -68,6 +68,7 @@ <xi:include href="lib.xml"/> <xi:include href="lists.xml"/> <xi:include href="log_mf_h.xml"/> + <xi:include href="maps.xml"/> <xi:include href="math.xml"/> <xi:include href="ms_transform.xml"/> <xi:include href="orddict.xml"/> diff --git a/lib/stdlib/doc/src/specs.xml b/lib/stdlib/doc/src/specs.xml index 213ce7563f..60a04ed5e7 100644 --- a/lib/stdlib/doc/src/specs.xml +++ b/lib/stdlib/doc/src/specs.xml @@ -34,6 +34,7 @@ <xi:include href="../specs/specs_lib.xml"/> <xi:include href="../specs/specs_lists.xml"/> <xi:include href="../specs/specs_log_mf_h.xml"/> + <xi:include href="../specs/specs_maps.xml"/> <xi:include href="../specs/specs_math.xml"/> <xi:include href="../specs/specs_ms_transform.xml"/> <xi:include href="../specs/specs_orddict.xml"/> diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index 8197684d2d..3a5027d595 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -262,12 +262,12 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} locally as <c>Name</c> using <c>register/2</c>. If <c><anno>SupName</anno>={global,Name}</c> the supervisor is registered globally as <c>Name</c> using <c>global:register_name/2</c>. If - <c><anno>SupName</anno>={via,Module,Name}</c> the supervisor + <c><anno>SupName</anno>={via,<anno>Module</anno>,<anno>Name</anno>}</c> the supervisor is registered as <c>Name</c> using the registry represented by <c>Module</c>. The <c>Module</c> callback should export the functions <c>register_name/2</c>, <c>unregister_name/1</c> and <c>send/2</c>, which should behave like the corresponding functions in <c>global</c>. - Thus, <c>{via,global,Name}</c> is a valid reference.</p> + Thus, <c>{via,global,<anno>Name</anno>}</c> is a valid reference.</p> <p>If no name is provided, the supervisor is not registered.</p> <p><c><anno>Module</anno></c> is the name of the callback module.</p> <p><c><anno>Args</anno></c> is an arbitrary term which is passed as diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml index 75505d7d84..c843ef7736 100644 --- a/lib/stdlib/doc/src/unicode_usage.xml +++ b/lib/stdlib/doc/src/unicode_usage.xml @@ -996,7 +996,8 @@ ok </pre> </section> <section> - <title><marker id="unicode_options_summary"/>Summary of Options</title> + <title>Summary of Options</title> + <marker id="unicode_options_summary"/> <p>The Unicode support is controlled by both command line switches, some standard environment variables and the version of OTP you are using. Most options affect mainly the way Unicode data is displayed, diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl index 44dad04f43..c32da1624f 100644 --- a/lib/stdlib/src/dets.erl +++ b/lib/stdlib/src/dets.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -1785,6 +1785,7 @@ read_file_header(FileName, Access, RamFile) -> Version =:= 9 -> dets_v9:read_file_header(Fd, FileName); true -> + _ = file:close(Fd), throw({error, {not_a_dets_file, FileName}}) end. @@ -2113,6 +2114,8 @@ test_bchunk_format(Head, Term) -> do_open_file([Fname, Verbose], Parent, Server, Ref) -> case catch fopen2(Fname, Ref) of + {error, {tooshort, _}} -> + err({error, {not_a_dets_file, Fname}}); {error, _Reason} = Error -> err(Error); {ok, Head} -> @@ -2126,11 +2129,10 @@ do_open_file([Fname, Verbose], Parent, Server, Ref) -> [Bad]), {error, {dets_bug, Fname, Bad}} end; -do_open_file([Tab, OpenArgs, Verb], Parent, Server, Ref) -> +do_open_file([Tab, OpenArgs, Verb], Parent, Server, _Ref) -> case catch fopen3(Tab, OpenArgs) of {error, {tooshort, _}} -> - _ = file:delete(OpenArgs#open_args.file), - do_open_file([Tab, OpenArgs, Verb], Parent, Server, Ref); + err({error, {not_a_dets_file, OpenArgs#open_args.file}}); {error, _Reason} = Error -> err(Error); {ok, Head} -> @@ -2486,7 +2488,6 @@ fopen2(Fname, Tab) -> {ok, _} -> Acc = read_write, Ram = false, - %% Fd is not always closed upon error, but exit is soon called. {ok, Fd, FH} = read_file_header(Fname, Acc, Ram), Mod = FH#fileheader.mod, Do = case Mod:check_file_header(FH, Fd) of @@ -2542,7 +2543,6 @@ fopen_existing_file(Tab, OpenArgs) -> ram_file = Ram, delayed_write = CacheSz, auto_save = Auto, access = Acc, version = Version, debug = Debug} = OpenArgs, - %% Fd is not always closed upon error, but exit is soon called. {ok, Fd, FH} = read_file_header(Fname, Acc, Ram), V9 = (Version =:= 9) or (Version =:= default), MinF = (MinSlots =:= default) or (MinSlots =:= FH#fileheader.min_no_slots), diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index 9f5be2da37..269e4b34cf 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -344,10 +344,19 @@ format_error(spec_wrong_arity) -> "spec has the wrong arity"; format_error(callback_wrong_arity) -> "callback has the wrong arity"; -format_error({deprecated_type, {Name, Arity}, {Mod, NewName}, Rel}) -> +format_error({deprecated_builtin_type, {Name, Arity}, + Replacement, Rel}) -> + UseS = case Replacement of + {Mod, NewName} -> + io_lib:format("use ~w:~w/~w", [Mod, NewName, Arity]); + {Mod, NewName, NewArity} -> + io_lib:format("use ~w:~w/~w or preferably ~w:~w/~w", + [Mod, NewName, Arity, + Mod, NewName, NewArity]) + end, io_lib:format("type ~w/~w is deprecated and will be " - "removed in ~s; use ~w:~w/~w", - [Name, Arity, Rel, Mod, NewName, Arity]); + "removed in ~s; use ~s", + [Name, Arity, Rel, UseS]); format_error({not_exported_opaque, {TypeName, Arity}}) -> io_lib:format("opaque type ~w~s is not exported", [TypeName, gen_type_paren(Arity)]); @@ -499,6 +508,9 @@ start(File, Opts) -> {deprecated_function, bool_option(warn_deprecated_function, nowarn_deprecated_function, true, Opts)}, + {deprecated_type, + bool_option(warn_deprecated_type, nowarn_deprecated_type, + true, Opts)}, {obsolete_guard, bool_option(warn_obsolete_guard, nowarn_obsolete_guard, true, Opts)}, @@ -1373,18 +1385,19 @@ pattern({cons,_Line,H,T}, Vt, Old, Bvt, St0) -> pattern({tuple,_Line,Ps}, Vt, Old, Bvt, St) -> pattern_list(Ps, Vt, Old, Bvt, St); pattern({map,_Line,Ps}, Vt, Old, Bvt, St) -> - pattern_list(Ps, Vt, Old, Bvt, St); -pattern({map_field_assoc,Line,_,_}, _, _, _, St) -> - {[],[],add_error(Line, illegal_pattern, St)}; -pattern({map_field_exact,Line,KP,VP}, Vt, Old, Bvt0, St0) -> - %% if the key pattern has variables we should fail - case expr(KP,[],St0) of - {[],_} -> - pattern(VP, Vt, Old, Bvt0, St0); - {[Var|_],_} -> - %% found variables in key expression - {Vt,Old,add_error(Line,{illegal_map_key_variable,element(1,Var)},St0)} - end; + foldl(fun ({map_field_assoc,L,_,_}, {Psvt,Bvt0,St0}) -> + {Psvt,Bvt0,add_error(L, illegal_pattern, St0)}; + ({map_field_exact,L,KP,VP}, {Psvt,Bvt0,St0}) -> + case expr(KP, [], St0) of + {[],_} -> + {Pvt,Bvt1,St1} = pattern(VP, Vt, Old, Bvt, St0), + {vtmerge_pat(Pvt, Psvt),vtmerge_pat(Bvt0, Bvt1), + St1}; + {[Var|_],_} -> + Error = {illegal_map_key_variable,element(1, Var)}, + {Psvt,Bvt0,add_error(L, Error, St0)} + end + end, {[],[],St}, Ps); %%pattern({struct,_Line,_Tag,Ps}, Vt, Old, Bvt, St) -> %% pattern_list(Ps, Vt, Old, Bvt, St); pattern({record_index,Line,Name,Field}, _Vt, _Old, _Bvt, St) -> @@ -1773,13 +1786,11 @@ gexpr({cons,_Line,H,T}, Vt, St) -> gexpr({tuple,_Line,Es}, Vt, St) -> gexpr_list(Es, Vt, St); gexpr({map,_Line,Es}, Vt, St) -> - gexpr_list(Es, Vt, St); + map_fields(Es, Vt, check_assoc_fields(Es, St), fun gexpr_list/3); gexpr({map,_Line,Src,Es}, Vt, St) -> - gexpr_list([Src|Es], Vt, St); -gexpr({map_field_assoc,_Line,K,V}, Vt, St) -> - gexpr_list([K,V], Vt, St); -gexpr({map_field_exact,_Line,K,V}, Vt, St) -> - gexpr_list([K,V], Vt, St); + {Svt,St1} = gexpr(Src, Vt, St), + {Fvt,St2} = map_fields(Es, Vt, St1, fun gexpr_list/3), + {vtmerge(Svt, Fvt),St2}; gexpr({record_index,Line,Name,Field}, _Vt, St) -> check_record(Line, Name, St, fun (Dfs, St1) -> record_field(Field, Name, Dfs, St1) end ); @@ -1852,6 +1863,10 @@ gexpr({op,Line,Op,A}, Vt, St0) -> true -> {Avt,St1}; false -> {Avt,add_error(Line, illegal_guard_expr, St1)} end; +gexpr({op,_,'andalso',L,R}, Vt, St) -> + gexpr_list([L,R], Vt, St); +gexpr({op,_,'orelse',L,R}, Vt, St) -> + gexpr_list([L,R], Vt, St); gexpr({op,Line,Op,L,R}, Vt, St0) -> {Avt,St1} = gexpr_list([L,R], Vt, St0), case is_gexpr_op(Op, 2) of @@ -1938,12 +1953,14 @@ is_gexpr({call,L,{tuple,Lt,[{atom,Lm,erlang},{atom,Lf,F}]},As}, RDs) -> is_gexpr({call,L,{remote,Lt,{atom,Lm,erlang},{atom,Lf,F}},As}, RDs); is_gexpr({op,_L,Op,A}, RDs) -> is_gexpr_op(Op, 1) andalso is_gexpr(A, RDs); +is_gexpr({op,_L,'andalso',A1,A2}, RDs) -> + is_gexpr_list([A1,A2], RDs); +is_gexpr({op,_L,'orelse',A1,A2}, RDs) -> + is_gexpr_list([A1,A2], RDs); is_gexpr({op,_L,Op,A1,A2}, RDs) -> is_gexpr_op(Op, 2) andalso is_gexpr_list([A1,A2], RDs); is_gexpr(_Other, _RDs) -> false. -is_gexpr_op('andalso', 2) -> true; -is_gexpr_op('orelse', 2) -> true; is_gexpr_op(Op, A) -> try erl_internal:op_type(Op, A) of arith -> true; @@ -1997,24 +2014,12 @@ expr({bc,_Line,E,Qs}, Vt, St) -> handle_comprehension(E, Qs, Vt, St); expr({tuple,_Line,Es}, Vt, St) -> expr_list(Es, Vt, St); -expr({map,Line,Es}, Vt, St) -> - {Rvt,St1} = expr_list(Es,Vt,St), - case is_valid_map_construction(Es) of - true -> {Rvt,St1}; - false -> {[],add_error(Line,illegal_map_construction,St1)} - end; +expr({map,_Line,Es}, Vt, St) -> + map_fields(Es, Vt, check_assoc_fields(Es, St), fun expr_list/3); expr({map,_Line,Src,Es}, Vt, St) -> - expr_list([Src|Es], Vt, St); -expr({map_field_assoc,Line,K,V}, Vt, St) -> - case is_valid_map_key(K,St) of - true -> expr_list([K,V], Vt, St); - {false,Var} -> {[],add_error(Line,{illegal_map_key_variable,Var},St)} - end; -expr({map_field_exact,Line,K,V}, Vt, St) -> - case is_valid_map_key(K,St) of - true -> expr_list([K,V], Vt, St); - {false,Var} -> {[],add_error(Line,{illegal_map_key_variable,Var},St)} - end; + {Svt,St1} = expr(Src, Vt, St), + {Fvt,St2} = map_fields(Es, Vt, St1, fun expr_list/3), + {vtupdate(Svt, Fvt),St2}; expr({record_index,Line,Name,Field}, _Vt, St) -> check_record(Line, Name, St, fun (Dfs, St1) -> record_field(Field, Name, Dfs, St1) end); @@ -2222,6 +2227,25 @@ record_expr(Line, Rec, Vt, St0) -> St1 = warn_invalid_record(Line, Rec, St0), expr(Rec, Vt, St1). +check_assoc_fields([{map_field_exact,Line,_,_}|Fs], St) -> + check_assoc_fields(Fs, add_error(Line, illegal_map_construction, St)); +check_assoc_fields([{map_field_assoc,_,_,_}|Fs], St) -> + check_assoc_fields(Fs, St); +check_assoc_fields([], St) -> + St. + +map_fields([{Tag,Line,K,V}|Fs], Vt, St, F) when Tag =:= map_field_assoc; + Tag =:= map_field_exact -> + St1 = case is_valid_map_key(K, St) of + true -> St; + {false,Var} -> add_error(Line, {illegal_map_key_variable,Var}, St) + end, + {Pvt,St2} = F([K,V], Vt, St1), + {Vts,St3} = map_fields(Fs, Vt, St2, F), + {vtupdate(Pvt, Vts),St3}; +map_fields([], Vt, St, _) -> + {Vt,St}. + %% warn_invalid_record(Line, Record, State0) -> State %% Adds warning if the record is invalid. @@ -2274,13 +2298,6 @@ is_valid_call(Call) -> _ -> true end. -%% check_map_construction -%% Only #{ K => V }, i.e. assoc is a valid construction -is_valid_map_construction([{map_field_assoc,_,_,_}|Es]) -> - is_valid_map_construction(Es); -is_valid_map_construction([]) -> true; -is_valid_map_construction(_) -> false. - is_valid_map_key(K,St) -> case expr(K,[],St) of {[],_} -> true; @@ -2518,32 +2535,39 @@ type_def(Attr, Line, TypeName, ProtoType, Args, St0) -> CheckType = {type, -1, product, [ProtoType|Args]}, check_type(CheckType, St#lint{types=NewDefs}) end, - case (dict:is_key(TypePair, TypeDefs) orelse is_var_arity_type(TypeName)) of - true -> - case is_default_type(TypePair) of - true -> - case is_newly_introduced_builtin_type(TypePair) of - %% allow some types just for bootstrapping - true -> - Warn = {new_builtin_type, TypePair}, - St1 = add_warning(Line, Warn, St0), + case is_default_type(TypePair) of + true -> + case is_obsolete_builtin_type(TypePair) of + true -> StoreType(St0); + false -> + case is_newly_introduced_builtin_type(TypePair) of + %% allow some types just for bootstrapping + true -> + Warn = {new_builtin_type, TypePair}, + St1 = add_warning(Line, Warn, St0), StoreType(St1); - false -> - add_error(Line, {builtin_type, TypePair}, St0) - end; - false -> add_error(Line, {redefine_type, TypePair}, St0) - end; - false -> - St1 = case - Attr =:= opaque andalso - is_underspecified(ProtoType, Arity) - of - true -> - Warn = {underspecified_opaque, TypePair}, - add_warning(Line, Warn, St0); - false -> St0 - end, - StoreType(St1) + false -> + add_error(Line, {builtin_type, TypePair}, St0) + end + end; + false -> + case + dict:is_key(TypePair, TypeDefs) + orelse is_var_arity_type(TypeName) + of + true -> add_error(Line, {redefine_type, TypePair}, St0); + false -> + St1 = case + Attr =:= opaque andalso + is_underspecified(ProtoType, Arity) + of + true -> + Warn = {underspecified_opaque, TypePair}, + add_warning(Line, Warn, St0); + false -> St0 + end, + StoreType(St1) + end end. is_underspecified({type,_,term,[]}, 0) -> true; @@ -2637,10 +2661,11 @@ check_type({type, La, TypeName, Args}, SeenVars, St) -> St1 = case is_var_arity_type(TypeName) of true -> St; false -> - Obsolete = obsolete_type(TypePair), + Obsolete = (is_warn_enabled(deprecated_type, St) + andalso obsolete_builtin_type(TypePair)), IsObsolete = case Obsolete of - {deprecated, {M, _}, _} when M =/= Module -> + {deprecated, Repl, _} when element(1, Repl) =/= Module -> case dict:find(TypePair, Types) of {ok, _} -> false; error -> true @@ -2650,7 +2675,8 @@ check_type({type, La, TypeName, Args}, SeenVars, St) -> case IsObsolete of true -> {deprecated, Replacement, Rel} = Obsolete, - W = {deprecated_type, TypePair, Replacement, Rel}, + Tag = deprecated_builtin_type, + W = {Tag, TypePair, Replacement, Rel}, add_warning(La, W, St); false -> OldUsed = Usage#usage.used_types, @@ -2764,31 +2790,29 @@ is_default_type({timeout, 0}) -> true; is_default_type({var, 1}) -> true; is_default_type(_) -> false. -%% R13 -is_newly_introduced_builtin_type({arity, 0}) -> true; -is_newly_introduced_builtin_type({array, 0}) -> true; % opaque -is_newly_introduced_builtin_type({bitstring, 0}) -> true; -is_newly_introduced_builtin_type({dict, 0}) -> true; % opaque -is_newly_introduced_builtin_type({digraph, 0}) -> true; % opaque -is_newly_introduced_builtin_type({gb_set, 0}) -> true; % opaque -is_newly_introduced_builtin_type({gb_tree, 0}) -> true; % opaque -is_newly_introduced_builtin_type({iodata, 0}) -> true; -is_newly_introduced_builtin_type({queue, 0}) -> true; % opaque -is_newly_introduced_builtin_type({set, 0}) -> true; % opaque -%% R13B01 -is_newly_introduced_builtin_type({boolean, 0}) -> true; is_newly_introduced_builtin_type({Name, _}) when is_atom(Name) -> false. +is_obsolete_builtin_type(TypePair) -> + obsolete_builtin_type(TypePair) =/= no. + %% Obsolete in OTP 17.0. -obsolete_type({array, 0}) -> {deprecated, {array, array}, "OTP 18.0"}; -obsolete_type({dict, 0}) -> {deprecated, {dict, dict}, "OTP 18.0"}; -obsolete_type({digraph, 0}) -> {deprecated, {digraph, graph}, "OTP 18.0"}; -obsolete_type({gb_set, 0}) -> {deprecated, {gb_sets, set}, "OTP 18.0"}; -obsolete_type({gb_tree, 0}) -> {deprecated, {gb_trees, tree}, "OTP 18.0"}; -obsolete_type({queue, 0}) -> {deprecated, {queue, queue}, "OTP 18.0"}; -obsolete_type({set, 0}) -> {deprecated, {sets, set}, "OTP 18.0"}; -obsolete_type({tid, 0}) -> {deprecated, {ets, tid}, "OTP 18.0"}; -obsolete_type({Name, _}) when is_atom(Name) -> no. +obsolete_builtin_type({array, 0}) -> + {deprecated, {array, array, 1}, "OTP 18.0"}; +obsolete_builtin_type({dict, 0}) -> + {deprecated, {dict, dict, 2}, "OTP 18.0"}; +obsolete_builtin_type({digraph, 0}) -> + {deprecated, {digraph, graph}, "OTP 18.0"}; +obsolete_builtin_type({gb_set, 0}) -> + {deprecated, {gb_sets, set, 1}, "OTP 18.0"}; +obsolete_builtin_type({gb_tree, 0}) -> + {deprecated, {gb_trees, tree, 2}, "OTP 18.0"}; +obsolete_builtin_type({queue, 0}) -> + {deprecated, {queue, queue, 1}, "OTP 18.0"}; +obsolete_builtin_type({set, 0}) -> + {deprecated, {sets, set, 1}, "OTP 18.0"}; +obsolete_builtin_type({tid, 0}) -> + {deprecated, {ets, tid}, "OTP 18.0"}; +obsolete_builtin_type({Name, A}) when is_atom(Name), is_integer(A) -> no. %% spec_decl(Line, Fun, Types, State) -> State. diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl index 7281549ea7..63116fa16e 100644 --- a/lib/stdlib/src/gen.erl +++ b/lib/stdlib/src/gen.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -37,7 +37,9 @@ %%----------------------------------------------------------------- -type linkage() :: 'link' | 'nolink'. --type emgr_name() :: {'local', atom()} | {'global', term()} | {via, atom(), term()}. +-type emgr_name() :: {'local', atom()} + | {'global', term()} + | {'via', Module :: module(), Name :: term()}. -type start_ret() :: {'ok', pid()} | 'ignore' | {'error', term()}. diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl index 57b5072639..1f94d9e69d 100644 --- a/lib/stdlib/src/maps.erl +++ b/lib/stdlib/src/maps.erl @@ -45,7 +45,6 @@ -compile(no_native). -%% Shadowed by erl_bif_types: maps:get/3 -spec get(Key,Map) -> Value when Key :: term(), Map :: map(), @@ -54,7 +53,6 @@ get(_,_) -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:find/3 -spec find(Key,Map) -> {ok, Value} | error when Key :: term(), Map :: map(), @@ -63,8 +61,8 @@ get(_,_) -> erlang:nif_error(undef). find(_,_) -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:from_list/1 --spec from_list([{Key,Value}]) -> Map when +-spec from_list(List) -> Map when + List :: [{Key,Value}], Key :: term(), Value :: term(), Map :: map(). @@ -72,7 +70,6 @@ find(_,_) -> erlang:nif_error(undef). from_list(_) -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:is_key/2 -spec is_key(Key,Map) -> boolean() when Key :: term(), Map :: map(). @@ -80,7 +77,6 @@ from_list(_) -> erlang:nif_error(undef). is_key(_,_) -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:keys/1 -spec keys(Map) -> Keys when Map :: map(), Keys :: [Key], @@ -89,7 +85,6 @@ is_key(_,_) -> erlang:nif_error(undef). keys(_) -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:merge/2 -spec merge(Map1,Map2) -> Map3 when Map1 :: map(), Map2 :: map(), @@ -99,14 +94,12 @@ merge(_,_) -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:new/0 -spec new() -> Map when Map :: map(). new() -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:put/3 -spec put(Key,Value,Map1) -> Map2 when Key :: term(), Value :: term(), @@ -116,7 +109,6 @@ new() -> erlang:nif_error(undef). put(_,_,_) -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:put/3 -spec remove(Key,Map1) -> Map2 when Key :: term(), Map1 :: map(), @@ -125,7 +117,6 @@ put(_,_,_) -> erlang:nif_error(undef). remove(_,_) -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:to_list/1 -spec to_list(Map) -> [{Key,Value}] when Map :: map(), Key :: term(), @@ -134,7 +125,6 @@ remove(_,_) -> erlang:nif_error(undef). to_list(_) -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:update/3 -spec update(Key,Value,Map1) -> Map2 when Key :: term(), Value :: term(), @@ -144,7 +134,6 @@ to_list(_) -> erlang:nif_error(undef). update(_,_,_) -> erlang:nif_error(undef). -%% Shadowed by erl_bif_types: maps:values/1 -spec values(Map) -> Keys when Map :: map(), Keys :: [Key], diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl index 059d553b00..00a5da42ad 100644 --- a/lib/stdlib/test/dets_SUITE.erl +++ b/lib/stdlib/test/dets_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -52,7 +52,7 @@ simultaneous_open/1, insert_new/1, repair_continuation/1, otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1, otp_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1, - otp_8923/1, otp_9282/1, otp_11245/1]). + otp_8923/1, otp_9282/1, otp_11245/1, otp_11709/1]). -export([dets_dirty_loop/0]). @@ -109,7 +109,7 @@ all() -> many_clients, otp_4906, otp_5402, simultaneous_open, insert_new, repair_continuation, otp_5487, otp_6206, otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898, - otp_8899, otp_8903, otp_8923, otp_9282, otp_11245 + otp_8899, otp_8903, otp_8923, otp_9282, otp_11245, otp_11709 ]. groups() -> @@ -772,9 +772,9 @@ open_1(Config, V) -> crash(Fname, TypePos), {error, {invalid_type_code,Fname}} = dets:open_file(Fname), truncate(Fname, HeadSize - 10), - {error, {tooshort,Fname}} = dets:open_file(Fname), - {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]), - ok = dets:close(TabRef), + {error,{not_a_dets_file,Fname}} = dets:open_file(Fname), + {error,{not_a_dets_file,Fname}} = + dets:open_file(TabRef, [{file,Fname},{version,V}]), file:delete(Fname), {error,{file_error,{foo,bar},_}} = dets:is_dets_file({foo,bar}), @@ -967,10 +967,12 @@ fast_init_table(Config) -> {'EXIT', _} = (catch dets:init_table(TabRef, fun(foo) -> bar end, {format,bchunk})), dets:close(TabRef), + file:delete(Fname), {ok, _} = dets:open_file(TabRef, Args), {'EXIT', _} = (catch dets:init_table(TabRef, fun() -> foo end, {format,bchunk})), dets:close(TabRef), + file:delete(Fname), {ok, _} = dets:open_file(TabRef, Args), {'EXIT', {badarg, _}} = (catch dets:init_table(TabRef, nofun, {format,bchunk})), @@ -979,10 +981,12 @@ fast_init_table(Config) -> away = (catch dets:init_table(TabRef, fun(_) -> throw(away) end, {format,bchunk})), dets:close(TabRef), + file:delete(Fname), {ok, _} = dets:open_file(TabRef, Args), {error, {init_fun, fopp}} = dets:init_table(TabRef, fun(read) -> fopp end, {format,bchunk}), dets:close(TabRef), + file:delete(Fname), {ok, _} = dets:open_file(TabRef, Args), dets:safe_fixtable(TabRef, true), {error, {fixed_table, TabRef}} = @@ -1389,23 +1393,6 @@ repair(Config, V) -> {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]), ok = ins(TabRef, 100), ok = dets:close(TabRef), - truncate(Fname, HeadSize - 10), - %% a new file is created ('tooshort') - {ok, TabRef} = dets:open_file(TabRef, - [{file,Fname},{version,V}, - {min_no_slots,1000}, - {max_no_slots,1000000}]), - case dets:info(TabRef, no_slots) of - undefined -> ok; - {Min1,Slot1,Max1} -> - true = Min1 =< Slot1, true = Slot1 =< Max1, - true = 1000 < Min1, true = 1000+256 > Min1, - true = 1000000 < Max1, true = (1 bsl 20)+256 > Max1 - end, - 0 = dets:info(TabRef, size), - no_keys_test(TabRef), - _ = histogram(TabRef, silent), - ok = dets:close(TabRef), file:delete(Fname), %% version bump (v8) @@ -3920,6 +3907,48 @@ otp_11245(Config) when is_list(Config) -> file:delete(File), ok. +otp_11709(doc) -> + ["OTP-11709. Bugfixes."]; +otp_11709(suite) -> + []; +otp_11709(Config) when is_list(Config) -> + Short = <<"foo">>, + Long = <<"a sufficiently long text">>, + + %% Bug: leaking file descriptor + P0 = pps(), + File = filename(otp_11709, Config), + ok = file:write_file(File, Long), + false = dets:is_dets_file(File), + check_pps(P0), + + %% Bug: deleting file + Args = [[{access, A}, {repair, R}] || + A <- [read, read_write], + R <- [true, false, force]], + Fun1 = fun(S, As) -> + P1 = pps(), + ok = file:write_file(File, S), + {error,{not_a_dets_file,File}} = dets:open_file(File, As), + {ok, S} = file:read_file(File), + check_pps(P1) + end, + Fun2 = fun(S) -> + _ = [Fun1(S, As) || As <- Args], + ok + end, + ok = Fun2(Long), % no change here + ok = Fun2(Short), % mimic the behaviour for longer files + + %% open_file/1 + ok = file:write_file(File, Long), + {error,{not_a_dets_file,File}} = dets:open_file(File), % no change + ok = file:write_file(File, Short), + {error,{not_a_dets_file,File}} = dets:open_file(File), % mimic + + _ = file:delete(File), + ok. + %% %% Parts common to several test cases %% diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 1614a2722f..5d189006a1 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -52,6 +52,7 @@ guard/1, otp_4886/1, otp_4988/1, otp_5091/1, otp_5276/1, otp_5338/1, otp_5362/1, otp_5371/1, otp_7227/1, otp_5494/1, otp_5644/1, otp_5878/1, otp_5917/1, otp_6585/1, otp_6885/1, otp_10436/1, otp_11254/1, + otp_11772/1, otp_11771/1, export_all/1, bif_clash/1, behaviour_basic/1, behaviour_multiple/1, @@ -61,7 +62,8 @@ on_load_successful/1, on_load_failing/1, too_many_arguments/1, basic_errors/1,bin_syntax_errors/1, - predef/1 + predef/1, + maps/1 ]). % Default timetrap timeout (set in init_per_testcase). @@ -85,10 +87,11 @@ all() -> unsized_binary_in_bin_gen_pattern, otp_4886, otp_4988, otp_5091, otp_5276, otp_5338, otp_5362, otp_5371, otp_7227, otp_5494, otp_5644, - otp_5878, otp_5917, otp_6585, otp_6885, otp_10436, otp_11254,export_all, + otp_5878, otp_5917, otp_6585, otp_6885, otp_10436, otp_11254, + otp_11772, otp_11771, export_all, bif_clash, behaviour_basic, behaviour_multiple, otp_7550, otp_8051, format_warn, {group, on_load}, - too_many_arguments, basic_errors, bin_syntax_errors, predef]. + too_many_arguments, basic_errors, bin_syntax_errors, predef, maps]. groups() -> [{unused_vars_warn, [], @@ -1494,7 +1497,15 @@ guard(Config) when is_list(Config) -> [], {errors,[{1,erl_lint,illegal_guard_expr}, {2,erl_lint,illegal_guard_expr}, - {3,erl_lint,illegal_guard_expr}],[]}} + {3,erl_lint,illegal_guard_expr}],[]}}, + {guard9, + <<"t(X, Y) when erlang:'andalso'(X, Y) -> ok; + t(X, Y) when erlang:'orelse'(X, Y) -> ok. + ">>, + [], + {errors,[{1,erl_lint,illegal_guard_expr}, + {2,erl_lint,illegal_guard_expr}], + []}} ], ?line [] = run(Config, Ts1), ok. @@ -2553,7 +2564,7 @@ otp_10436(Config) when is_list(Config) -> ok. otp_11254(doc) -> - "OTP-11254. Warnings for opaque types."; + "OTP-11254. M:F/A could crash the linter."; otp_11254(suite) -> []; otp_11254(Config) when is_list(Config) -> Ts = <<"-module(p2). @@ -2566,6 +2577,62 @@ otp_11254(Config) when is_list(Config) -> run_test2(Config, Ts, []), ok. +otp_11772(doc) -> + "OTP-11772. Reintroduce errors for redefined builtin types."; +otp_11772(suite) -> []; +otp_11772(Config) when is_list(Config) -> + Ts = <<" + -module(newly). + + -compile(export_all). + + %% Built-in: + -type node() :: node(). + -type mfa() :: tuple(). + -type gb_tree() :: mfa(). % Allowed since Erlang/OTP 17.0 + -type digraph() :: [_]. % Allowed since Erlang/OTP 17.0 + + -type t() :: mfa() | digraph() | gb_tree() | node(). + + -spec t() -> t(). + + t() -> + 1. + ">>, + {errors,[{7,erl_lint,{builtin_type,{node,0}}}, + {8,erl_lint,{builtin_type,{mfa,0}}}], + []} = run_test2(Config, Ts, []), + ok. + +otp_11771(doc) -> + "OTP-11771. Do not allow redefinition of the types arity(_) &c.."; +otp_11771(suite) -> []; +otp_11771(Config) when is_list(Config) -> + Ts = <<" + -module(newly). + + -compile(export_all). + + %% No longer allowed in 17.0: + -type arity() :: atom(). + -type bitstring() :: list(). + -type iodata() :: integer(). + -type boolean() :: iodata(). + + -type t() :: arity() | bitstring() | iodata() | boolean(). + + -spec t() -> t(). + + t() -> + 1. + ">>, + {errors,[{7,erl_lint,{builtin_type,{arity,0}}}, + {8,erl_lint,{builtin_type,{bitstring,0}}}, + {9,erl_lint,{builtin_type,{iodata,0}}}, + {10,erl_lint,{builtin_type,{boolean,0}}}], + []} = run_test2(Config, Ts, []), + ok. + export_all(doc) -> "OTP-7392. Warning for export_all."; export_all(Config) when is_list(Config) -> @@ -3243,20 +3310,88 @@ bin_syntax_errors(Config) -> ok. predef(doc) -> - "Predefined types: array(), digraph(), and so on"; + "OTP-10342: Predefined types: array(), digraph(), and so on"; predef(suite) -> []; predef(Config) when is_list(Config) -> W = get_compilation_warnings(Config, "predef", []), [] = W, W2 = get_compilation_warnings(Config, "predef2", []), - [{7,erl_lint,{deprecated_type,{array,0},{array,array},"OTP 18.0"}}, - {12,erl_lint,{deprecated_type,{dict,0},{dict,dict},"OTP 18.0"}}, - {17,erl_lint,{deprecated_type,{digraph,0},{digraph,graph},"OTP 18.0"}}, - {27,erl_lint,{deprecated_type,{gb_set,0},{gb_sets,set},"OTP 18.0"}}, - {32,erl_lint,{deprecated_type,{gb_tree,0},{gb_trees,tree},"OTP 18.0"}}, - {37,erl_lint,{deprecated_type,{queue,0},{queue,queue},"OTP 18.0"}}, - {42,erl_lint,{deprecated_type,{set,0},{sets,set},"OTP 18.0"}}, - {47,erl_lint,{deprecated_type,{tid,0},{ets,tid},"OTP 18.0"}}] = W2, + Tag = deprecated_builtin_type, + [{7,erl_lint,{Tag,{array,0},{array,array,1},"OTP 18.0"}}, + {12,erl_lint,{Tag,{dict,0},{dict,dict,2},"OTP 18.0"}}, + {17,erl_lint,{Tag,{digraph,0},{digraph,graph},"OTP 18.0"}}, + {27,erl_lint,{Tag,{gb_set,0},{gb_sets,set,1},"OTP 18.0"}}, + {32,erl_lint,{Tag,{gb_tree,0},{gb_trees,tree,2},"OTP 18.0"}}, + {37,erl_lint,{Tag,{queue,0},{queue,queue,1},"OTP 18.0"}}, + {42,erl_lint,{Tag,{set,0},{sets,set,1},"OTP 18.0"}}, + {47,erl_lint,{Tag,{tid,0},{ets,tid},"OTP 18.0"}}] = W2, + Ts = [{otp_10342_1, + <<"-compile(nowarn_deprecated_type). + + -spec t(dict()) -> non_neg_integer(). + + t(D) -> + erlang:phash2(D, 3000). + ">>, + {[nowarn_unused_function]}, + []}, + {otp_10342_2, + <<"-spec t(dict()) -> non_neg_integer(). + + t(D) -> + erlang:phash2(D, 3000). + ">>, + {[nowarn_unused_function]}, + {warnings,[{1,erl_lint, + {deprecated_builtin_type,{dict,0},{dict,dict,2}, + "OTP 18.0"}}]}}], + [] = run(Config, Ts), + ok. + +maps(Config) -> + %% TODO: test key patterns, not done because map patterns are going to be + %% changed a lot. + Ts = [{illegal_map_construction, + <<"t() -> + #{ a := b, + c => d, + e := f + }#{ a := b, + c => d, + e := f }; + t() when is_map(#{ a := b, + c => d + }#{ a := b, + c => d, + e := f }) -> + ok. + ">>, + [], + {errors,[{2,erl_lint,illegal_map_construction}, + {4,erl_lint,illegal_map_construction}, + {8,erl_lint,illegal_map_construction}], + []}}, + {illegal_pattern, + <<"t(#{ a := A, + c => d, + e := F, + g := 1 + 1, + h := _, + i := (_X = _Y), + j := (x ! y) }) -> + {A,F}. + ">>, + [], + {errors,[{2,erl_lint,illegal_pattern}, + {7,erl_lint,illegal_pattern}], + []}}, + {error_in_illegal_map_construction, + <<"t() -> #{ a := X }.">>, + [], + {errors,[{1,erl_lint,illegal_map_construction}, + {1,erl_lint,{unbound_var,'X'}}], + []}}], + [] = run(Config, Ts), ok. run(Config, Tests) -> diff --git a/lib/stdlib/test/erl_lint_SUITE_data/predef.erl b/lib/stdlib/test/erl_lint_SUITE_data/predef.erl index c2364fd1c2..ee9073aa67 100644 --- a/lib/stdlib/test/erl_lint_SUITE_data/predef.erl +++ b/lib/stdlib/test/erl_lint_SUITE_data/predef.erl @@ -5,8 +5,8 @@ -export_type([array/0, digraph/0, gb_set/0]). -%% Before R17B local re-definitions of pre-defined opaque types were -%% ignored but did not generate any warning. +%% Before Erlang/OTP 17.0 local re-definitions of pre-defined opaque +%% types were ignored but did not generate any warning. -opaque array() :: atom(). -opaque digraph() :: atom(). -opaque gb_set() :: atom(). diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl index dcf905db24..5fbc47a813 100644 --- a/lib/test_server/src/test_server_ctrl.erl +++ b/lib/test_server/src/test_server_ctrl.erl @@ -1407,7 +1407,7 @@ remove_conf([{conf, _Ref, Props, _MF}|Cases], NoConf, Repeats) -> end; remove_conf([{make,_Ref,_MF}|Cases], NoConf, Repeats) -> remove_conf(Cases, NoConf, Repeats); -remove_conf([{skip_case,{{_M,all},_Cmt}}|Cases], NoConf, Repeats) -> +remove_conf([{skip_case,{{_M,all},_Cmt},_Mode}|Cases], NoConf, Repeats) -> remove_conf(Cases, NoConf, Repeats); remove_conf([{skip_case,{Type,_Ref,_MF,_Cmt}}|Cases], NoConf, Repeats) when Type==conf; @@ -1431,7 +1431,7 @@ remove_conf([], NoConf, true) -> remove_conf([], NoConf, false) -> lists:reverse(NoConf). -get_suites([{skip_case,{{Mod,_Func},_Cmt}}|Tests], Mods) when is_atom(Mod) -> +get_suites([{skip_case,{{Mod,_F},_Cmt},_Mode}|Tests], Mods) when is_atom(Mod) -> case add_mod(Mod, Mods) of true -> get_suites(Tests, [Mod|Mods]); false -> get_suites(Tests, Mods) @@ -1833,7 +1833,7 @@ html_isolate_modules(List, FwMod) -> html_isolate_modules(List, sets:new(), FwMod). html_isolate_modules([], Set, _) -> sets:to_list(Set); -html_isolate_modules([{skip_case,_}|Cases], Set, FwMod) -> +html_isolate_modules([{skip_case,{_Case,_Cmt},_Mode}|Cases], Set, FwMod) -> html_isolate_modules(Cases, Set, FwMod); html_isolate_modules([{conf,_Ref,Props,{FwMod,_Func}}|Cases], Set, FwMod) -> Set1 = case proplists:get_value(suite, Props) of @@ -1937,26 +1937,30 @@ copy_html_file(Src, DestDir) -> add_init_and_end_per_suite([{make,_,_}=Case|Cases], LastMod, LastRef, FwMod) -> [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)]; -add_init_and_end_per_suite([{skip_case,{{Mod,all},_}}=Case|Cases], LastMod, +add_init_and_end_per_suite([{skip_case,{{Mod,all},_},_}=Case|Cases], LastMod, LastRef, FwMod) when Mod =/= LastMod -> {PreCases, NextMod, NextRef} = do_add_end_per_suite_and_skip(LastMod, LastRef, Mod, FwMod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; -add_init_and_end_per_suite([{skip_case,{{Mod,_},_}}=Case|Cases], LastMod, - LastRef, FwMod) when Mod =/= LastMod -> + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, + NextRef, FwMod)]; +add_init_and_end_per_suite([{skip_case,{{Mod,_},_Cmt},_Mode}=Case|Cases], + LastMod, LastRef, FwMod) when Mod =/= LastMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; -add_init_and_end_per_suite([{skip_case,{conf,_,{Mod,_},_},_}=Case|Cases], LastMod, - LastRef, FwMod) when Mod =/= LastMod -> + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, + NextRef, FwMod)]; +add_init_and_end_per_suite([{skip_case,{conf,_,{Mod,_},_},_}=Case|Cases], + LastMod, LastRef, FwMod) when Mod =/= LastMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, + NextRef, FwMod)]; add_init_and_end_per_suite([{skip_case,{conf,_,{Mod,_},_}}=Case|Cases], LastMod, LastRef, FwMod) when Mod =/= LastMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, + NextRef, FwMod)]; add_init_and_end_per_suite([{conf,Ref,Props,{FwMod,Func}}=Case|Cases], LastMod, LastRef, FwMod) -> %% if Mod == FwMod, this conf test is (probably) a test case group where @@ -1977,7 +1981,8 @@ add_init_and_end_per_suite([{conf,_,_,{Mod,_}}=Case|Cases], LastMod, LastRef, FwMod) when Mod =/= LastMod, Mod =/= FwMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, + NextRef, FwMod)]; add_init_and_end_per_suite([SkipCase|Cases], LastMod, LastRef, FwMod) when element(1,SkipCase) == skip_case -> [SkipCase|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)]; @@ -1987,12 +1992,14 @@ add_init_and_end_per_suite([{Mod,_}=Case|Cases], LastMod, LastRef, FwMod) when Mod =/= LastMod, Mod =/= FwMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, + NextRef, FwMod)]; add_init_and_end_per_suite([{Mod,_,_}=Case|Cases], LastMod, LastRef, FwMod) when Mod =/= LastMod, Mod =/= FwMod -> {PreCases, NextMod, NextRef} = do_add_init_and_end_per_suite(LastMod, LastRef, Mod, FwMod), - PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, NextRef, FwMod)]; + PreCases ++ [Case|add_init_and_end_per_suite(Cases, NextMod, + NextRef, FwMod)]; add_init_and_end_per_suite([Case|Cases], LastMod, LastRef, FwMod)-> [Case|add_init_and_end_per_suite(Cases, LastMod, LastRef, FwMod)]; add_init_and_end_per_suite([], _LastMod, undefined, _FwMod) -> @@ -2169,7 +2176,7 @@ run_test_cases(TestSpec, Config, TimetrapData) -> %% comment (which gets printed in the log files) describes why the case %% was skipped. %% -%% {skip_case,{Case,Comment}} A normal test case skipped by the user. +%% {skip_case,{Case,Comment},Mode} A normal test case skipped by the user. %% The comment (which gets printed in the log files) describes why the %% case was skipped. %% @@ -2342,7 +2349,7 @@ run_test_cases_loop([{SkipTag,{Type,Ref,Case,Comment},SkipMode}|Cases], ParentRef -> Reason = {group_result,GrName,failed}, skip_cases_upto(ParentRef, Cases, - Reason, tc, Mode, + Reason, tc, ParentMode, SkipTag) end; false -> @@ -2401,22 +2408,27 @@ run_test_cases_loop([{auto_skip_case,{Case,Comment},SkipMode}|Cases], Config, TimetrapData, Mode, Status) -> {Mod,Func} = skip_case(auto, undefined, get(test_server_case_num)+1, Case, Comment, is_io_buffered(), SkipMode), - test_server_sup:framework_call(report, [tc_auto_skip,{Mod,Func,Comment}]), + test_server_sup:framework_call(report, [tc_auto_skip, + {Mod,{Func,get_name(SkipMode)}, + Comment}]), run_test_cases_loop(Cases, Config, TimetrapData, Mode, update_status(skipped, Mod, Func, Status)); -run_test_cases_loop([{skip_case,{{Mod,all}=Case,Comment}}|Cases], +run_test_cases_loop([{skip_case,{{Mod,all}=Case,Comment},SkipMode}|Cases], Config, TimetrapData, Mode, Status) -> - skip_case(user, undefined, 0, Case, Comment, false, Mode), + skip_case(user, undefined, 0, Case, Comment, false, SkipMode), test_server_sup:framework_call(report, [tc_user_skip, - {Mod,all,Comment}]), + {Mod,{all,get_name(SkipMode)}, + Comment}]), run_test_cases_loop(Cases, Config, TimetrapData, Mode, Status); -run_test_cases_loop([{skip_case,{Case,Comment}}|Cases], +run_test_cases_loop([{skip_case,{Case,Comment},SkipMode}|Cases], Config, TimetrapData, Mode, Status) -> {Mod,Func} = skip_case(user, undefined, get(test_server_case_num)+1, - Case, Comment, is_io_buffered()), - test_server_sup:framework_call(report, [tc_user_skip,{Mod,Func,Comment}]), + Case, Comment, is_io_buffered(), SkipMode), + test_server_sup:framework_call(report, [tc_user_skip, + {Mod,{Func,get_name(SkipMode)}, + Comment}]), run_test_cases_loop(Cases, Config, TimetrapData, Mode, update_status(skipped, Mod, Func, Status)); @@ -2430,8 +2442,9 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0, {Ref,Ref} -> case check_props(parallel, tl(Mode0)) of false -> - %% this is an end conf for a top level parallel group, collect - %% results from the test case processes and calc total time + %% this is an end conf for a top level parallel group, + %% collect results from the test case processes + %% and calc total time OkSkipFail = handle_test_case_io_and_status(), file:set_cwd(filename:dirname(get(test_server_dir))), After = ?now, @@ -2955,7 +2968,6 @@ get_tc_results([{_,{OkSkipFail,_}} | _Status]) -> get_tc_results([]) -> % in case init_per_suite crashed {[],[],[]}. - conf(Ref, Props) -> {Ref,Props,?now}. @@ -3160,10 +3172,6 @@ random_order(N, {Pos,NewSeed}, IxCases, Shuffled) -> %% SendSync determines if start and finished messages must be sent so %% that the printouts can be buffered and handled in order with io from %% parallel processes. - -skip_case(Type, Ref, CaseNum, Case, Comment, SendSync) -> - skip_case(Type, Ref, CaseNum, Case, Comment, SendSync, []). - skip_case(Type, Ref, CaseNum, Case, Comment, SendSync, Mode) -> MF = {Mod,Func} = case Case of {M,F,_A} -> {M,F}; @@ -3241,7 +3249,7 @@ skip_case1(Type, CaseNum, Mod, Func, Comment, Mode) -> %% SkipType = skip_case | auto_skip_case %% Mark all cases tagged with Ref as skipped. -skip_cases_upto(Ref, Cases, Reason, Origin, Mode, SkipType) -> +skip_cases_upto(Ref, Cases, Reason, Origin, Mode, SkipType) -> {_,Modified,Rest} = modify_cases_upto(Ref, {skip,Reason,Origin,Mode,SkipType}, Cases), Modified++Rest. @@ -3326,21 +3334,34 @@ modify_cases_upto1(Ref, {copy,NewRef}, {[C|Orig],[{skip_case,{Type,NewRef,MF,Cmt}}|Alt],T}; %% next is a skip_case, could be one test case or 'all' in suite, we must proceed -modify_cases_upto1(Ref, ModOp, [{skip_case,{_F,_Cmt}}=MF|T], Orig, Alt) -> +modify_cases_upto1(Ref, ModOp, [{skip_case,{_F,_Cmt},_Mode}=MF|T], Orig, Alt) -> modify_cases_upto1(Ref, ModOp, T, [MF|Orig], [MF|Alt]); %% next is a normal case (possibly in a sequence), mark as skipped, or copy, and proceed -modify_cases_upto1(Ref, {skip,Reason,_,_,skip_case}=Op, +modify_cases_upto1(Ref, {skip,Reason,_,Mode,skip_case}=Op, [{_M,_F}=MF|T], Orig, Alt) -> - modify_cases_upto1(Ref, Op, T, Orig, [{skip_case,{MF,Reason}}|Alt]); + modify_cases_upto1(Ref, Op, T, Orig, [{skip_case,{MF,Reason},Mode}|Alt]); modify_cases_upto1(Ref, {skip,Reason,_,Mode,auto_skip_case}=Op, [{_M,_F}=MF|T], Orig, Alt) -> modify_cases_upto1(Ref, Op, T, Orig, [{auto_skip_case,{MF,Reason},Mode}|Alt]); modify_cases_upto1(Ref, CopyOp, [{_M,_F}=MF|T], Orig, Alt) -> modify_cases_upto1(Ref, CopyOp, T, [MF|Orig], [MF|Alt]); +%% next is a conf case, modify the Mode arg to keep track of sub groups +modify_cases_upto1(Ref, {skip,Reason,FType,Mode,SkipType}, + [{conf,OtherRef,Props,_MF}|T], Orig, Alt) -> + case hd(Mode) of + {OtherRef,_,_} -> % end conf + modify_cases_upto1(Ref, {skip,Reason,FType,tl(Mode),SkipType}, + T, Orig, Alt); + _ -> % start conf + Mode1 = [conf(OtherRef,Props)|Mode], + modify_cases_upto1(Ref, {skip,Reason,FType,Mode1,SkipType}, + T, Orig, Alt) + end; + %% next is some other case, ignore or copy -modify_cases_upto1(Ref, {skip,_,_,_,_}=Op, [_|T], Orig, Alt) -> +modify_cases_upto1(Ref, {skip,_,_,_,_}=Op, [_Other|T], Orig, Alt) -> modify_cases_upto1(Ref, Op, T, Orig, Alt); modify_cases_upto1(Ref, CopyOp, [C|T], Orig, Alt) -> modify_cases_upto1(Ref, CopyOp, T, [C|Orig], [C|Alt]). @@ -3665,12 +3686,13 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, update_config(hd(Args), [{priv_dir,PrivDir++"/"}, {tc_logfile,MinorName}]) end, - + GrName = get_name(Mode), test_server_sup:framework_call(report, - [tc_start,{{Mod,Func},MinorName}]), + [tc_start,{{Mod,{Func,GrName}}, + MinorName}]), print_props((RunInit==skip_init), get_props(Mode)), - GroupName = case get_name(Mode) of + GrNameStr = case GrName of undefined -> ""; Name -> cast_to_list(Name) end, @@ -3683,14 +3705,14 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, "<td>" ++ Col0 ++ "~ts" ++ Col1 ++ "</td>" "<td><a href=\"~ts\">~w</a></td>" "<td><a href=\"~ts#top\"><</a> <a href=\"~ts#end\">></a></td>", - [num2str(Num),fw_name(Mod),GroupName,EncMinorBase,Func, + [num2str(Num),fw_name(Mod),GrNameStr,EncMinorBase,Func, EncMinorBase,EncMinorBase]), do_unless_parallel(Main, fun erlang:yield/0), %% run the test case {Result,DetectedFail,ProcsBefore,ProcsAfter} = - run_test_case_apply(Num, Mod, Func, [UpdatedArgs], get_name(Mode), + run_test_case_apply(Num, Mod, Func, [UpdatedArgs], GrName, RunInit, TimetrapData), {Time,RetVal,Loc,Opts,Comment} = case Result of @@ -3709,41 +3731,41 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Status = case {Time,RetVal} of {died,{timetrap_timeout,TimetrapTimeout}} -> - progress(failed, Num, Mod, Func, Loc, + progress(failed, Num, Mod, Func, GrName, Loc, timetrap_timeout, TimetrapTimeout, Comment, Style); {died,Reason} -> - progress(failed, Num, Mod, Func, Loc, Reason, + progress(failed, Num, Mod, Func, GrName, Loc, Reason, Time, Comment, Style); {_,{'EXIT',{Skip,Reason}}} when Skip==skip; Skip==skipped; Skip==auto_skip -> - progress(skip, Num, Mod, Func, Loc, Reason, + progress(skip, Num, Mod, Func, GrName, Loc, Reason, Time, Comment, Style); {_,{'EXIT',_Pid,{Skip,Reason}}} when Skip==skip; Skip==skipped -> - progress(skip, Num, Mod, Func, Loc, Reason, + progress(skip, Num, Mod, Func, GrName, Loc, Reason, Time, Comment, Style); {_,{'EXIT',_Pid,Reason}} -> - progress(failed, Num, Mod, Func, Loc, Reason, + progress(failed, Num, Mod, Func, GrName, Loc, Reason, Time, Comment, Style); {_,{'EXIT',Reason}} -> - progress(failed, Num, Mod, Func, Loc, Reason, + progress(failed, Num, Mod, Func, GrName, Loc, Reason, Time, Comment, Style); {_,{Fail,Reason}} when Fail =:= fail; Fail =:= failed -> - progress(failed, Num, Mod, Func, Loc, Reason, + progress(failed, Num, Mod, Func, GrName, Loc, Reason, Time, Comment, Style); {_,Reason={auto_skip,_Why}} -> - progress(skip, Num, Mod, Func, Loc, Reason, + progress(skip, Num, Mod, Func, GrName, Loc, Reason, Time, Comment, Style); {_,{Skip,Reason}} when Skip==skip; Skip==skipped -> - progress(skip, Num, Mod, Func, Loc, Reason, + progress(skip, Num, Mod, Func, GrName, Loc, Reason, Time, Comment, Style); {Time,RetVal} -> case DetectedFail of [] -> - progress(ok, Num, Mod, Func, Loc, RetVal, + progress(ok, Num, Mod, Func, GrName, Loc, RetVal, Time, Comment, Style); Reason -> - progress(failed, Num, Mod, Func, Loc, Reason, + progress(failed, Num, Mod, Func, GrName, Loc, Reason, Time, Comment, Style) end end, @@ -3848,7 +3870,7 @@ num2str(N) -> integer_to_list(N). %% Note: Strings that are to be written to the minor log must %% be prefixed with "=== " here, or the indentation will be wrong. -progress(skip, CaseNum, Mod, Func, Loc, Reason, Time, +progress(skip, CaseNum, Mod, Func, GrName, Loc, Reason, Time, Comment, {St0,St1}) -> {Reason1,{Color,Ret,ReportTag}} = if_auto_skip(Reason, @@ -3857,7 +3879,7 @@ progress(skip, CaseNum, Mod, Func, Loc, Reason, Time, print(major, "=result ~w: ~p", [ReportTag,Reason1]), print(1, "*** SKIPPED ~ts ***", [get_info_str(Mod,Func, CaseNum, get(test_server_cases))]), - test_server_sup:framework_call(report, [tc_done,{Mod,Func, + test_server_sup:framework_call(report, [tc_done,{Mod,{Func,GrName}, {ReportTag,Reason1}}]), ReasonStr = reason_to_string(Reason1), ReasonStr1 = lists:flatten([string:strip(S,left) || @@ -3882,13 +3904,13 @@ progress(skip, CaseNum, Mod, Func, Loc, Reason, Time, print(minor, "=== reason = ~ts", [ReasonStr1]), Ret; -progress(failed, CaseNum, Mod, Func, Loc, timetrap_timeout, T, +progress(failed, CaseNum, Mod, Func, GrName, Loc, timetrap_timeout, T, Comment0, {St0,St1}) -> print(major, "=result failed: timeout, ~p", [Loc]), print(1, "*** FAILED ~ts ***", [get_info_str(Mod,Func, CaseNum, get(test_server_cases))]), test_server_sup:framework_call(report, - [tc_done,{Mod,Func, + [tc_done,{Mod,{Func,GrName}, {failed,timetrap_timeout}}]), FormatLastLoc = test_server_sup:format_loc(get_last_loc(Loc)), ErrorReason = io_lib:format("{timetrap_timeout,~ts}", [FormatLastLoc]), @@ -3908,13 +3930,13 @@ progress(failed, CaseNum, Mod, Func, Loc, timetrap_timeout, T, print(minor, "=== reason = timetrap timeout", []), failed; -progress(failed, CaseNum, Mod, Func, Loc, {testcase_aborted,Reason}, _T, +progress(failed, CaseNum, Mod, Func, GrName, Loc, {testcase_aborted,Reason}, _T, Comment0, {St0,St1}) -> print(major, "=result failed: testcase_aborted, ~p", [Loc]), print(1, "*** FAILED ~ts ***", [get_info_str(Mod,Func, CaseNum, get(test_server_cases))]), test_server_sup:framework_call(report, - [tc_done,{Mod,Func, + [tc_done,{Mod,{Func,GrName}, {failed,testcase_aborted}}]), FormatLastLoc = test_server_sup:format_loc(get_last_loc(Loc)), ErrorReason = io_lib:format("{testcase_aborted,~ts}", [FormatLastLoc]), @@ -3934,12 +3956,12 @@ progress(failed, CaseNum, Mod, Func, Loc, {testcase_aborted,Reason}, _T, print(minor, "=== reason = {testcase_aborted,~p}", [Reason]), failed; -progress(failed, CaseNum, Mod, Func, unknown, Reason, Time, +progress(failed, CaseNum, Mod, Func, GrName, unknown, Reason, Time, Comment0, {St0,St1}) -> print(major, "=result failed: ~p, ~w", [Reason,unknown]), print(1, "*** FAILED ~ts ***", [get_info_str(Mod,Func, CaseNum, get(test_server_cases))]), - test_server_sup:framework_call(report, [tc_done,{Mod,Func, + test_server_sup:framework_call(report, [tc_done,{Mod,{Func,GrName}, {failed,Reason}}]), TimeStr = io_lib:format(if is_float(Time) -> "~.3fs"; true -> "~w" @@ -3970,12 +3992,12 @@ progress(failed, CaseNum, Mod, Func, unknown, Reason, Time, print(minor, "=== reason = " ++ FStr, [FormattedReason]), failed; -progress(failed, CaseNum, Mod, Func, Loc, Reason, Time, +progress(failed, CaseNum, Mod, Func, GrName, Loc, Reason, Time, Comment0, {St0,St1}) -> print(major, "=result failed: ~p, ~p", [Reason,Loc]), print(1, "*** FAILED ~ts ***", [get_info_str(Mod,Func, CaseNum, get(test_server_cases))]), - test_server_sup:framework_call(report, [tc_done,{Mod,Func, + test_server_sup:framework_call(report, [tc_done,{Mod,{Func,GrName}, {failed,Reason}}]), TimeStr = io_lib:format(if is_float(Time) -> "~.3fs"; true -> "~w" @@ -3997,10 +4019,10 @@ progress(failed, CaseNum, Mod, Func, Loc, Reason, Time, print(minor, "=== reason = " ++ FStr, [FormattedReason]), failed; -progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time, +progress(ok, _CaseNum, Mod, Func, GrName, _Loc, RetVal, Time, Comment0, {St0,St1}) -> print(minor, "successfully completed test case", []), - test_server_sup:framework_call(report, [tc_done,{Mod,Func,ok}]), + test_server_sup:framework_call(report, [tc_done,{Mod,{Func,GrName},ok}]), Comment = case RetVal of {comment,RetComment} -> @@ -4489,18 +4511,18 @@ update_config(Config, []) -> collect_all_cases(Top, Skip) when is_list(Skip) -> Result = - case collect_cases(Top, #cc{mod=[],skip=Skip}) of + case collect_cases(Top, #cc{mod=[],skip=Skip}, []) of {ok,Cases,_St} -> Cases; Other -> Other end, Result. -collect_cases([], St) -> {ok,[],St}; -collect_cases([Case|Cs0], St0) -> - case collect_cases(Case, St0) of +collect_cases([], St, _) -> {ok,[],St}; +collect_cases([Case|Cs0], St0, Mode) -> + case collect_cases(Case, St0, Mode) of {ok,FlatCases1,St1} -> - case collect_cases(Cs0, St1) of + case collect_cases(Cs0, St1, Mode) of {ok,FlatCases2,St} -> {ok,FlatCases1 ++ FlatCases2,St}; {error,_Reason} = Error -> Error @@ -4509,39 +4531,41 @@ collect_cases([Case|Cs0], St0) -> end; -collect_cases({module,Case}, St) when is_atom(Case), is_atom(St#cc.mod) -> - collect_case({St#cc.mod,Case}, St); -collect_cases({module,Mod,Case}, St) -> - collect_case({Mod,Case}, St); -collect_cases({module,Mod,Case,Args}, St) -> - collect_case({Mod,Case,Args}, St); - -collect_cases({dir,SubDir}, St) -> - collect_files(SubDir, "*_SUITE", St); -collect_cases({dir,SubDir,Pattern}, St) -> - collect_files(SubDir, Pattern++"*", St); - -collect_cases({conf,InitF,CaseList,FinMF}, St) when is_atom(InitF) -> - collect_cases({conf,[],{St#cc.mod,InitF},CaseList,FinMF}, St); -collect_cases({conf,InitMF,CaseList,FinF}, St) when is_atom(FinF) -> - collect_cases({conf,[],InitMF,CaseList,{St#cc.mod,FinF}}, St); -collect_cases({conf,InitMF,CaseList,FinMF}, St0) -> - collect_cases({conf,[],InitMF,CaseList,FinMF}, St0); -collect_cases({conf,Props,InitF,CaseList,FinMF}, St) when is_atom(InitF) -> +collect_cases({module,Case}, St, Mode) when is_atom(Case), is_atom(St#cc.mod) -> + collect_case({St#cc.mod,Case}, St, Mode); +collect_cases({module,Mod,Case}, St, Mode) -> + collect_case({Mod,Case}, St, Mode); +collect_cases({module,Mod,Case,Args}, St, Mode) -> + collect_case({Mod,Case,Args}, St, Mode); + +collect_cases({dir,SubDir}, St, Mode) -> + collect_files(SubDir, "*_SUITE", St, Mode); +collect_cases({dir,SubDir,Pattern}, St, Mode) -> + collect_files(SubDir, Pattern++"*", St, Mode); + +collect_cases({conf,InitF,CaseList,FinMF}, St, Mode) when is_atom(InitF) -> + collect_cases({conf,[],{St#cc.mod,InitF},CaseList,FinMF}, St, Mode); +collect_cases({conf,InitMF,CaseList,FinF}, St, Mode) when is_atom(FinF) -> + collect_cases({conf,[],InitMF,CaseList,{St#cc.mod,FinF}}, St, Mode); +collect_cases({conf,InitMF,CaseList,FinMF}, St0, Mode) -> + collect_cases({conf,[],InitMF,CaseList,FinMF}, St0, Mode); +collect_cases({conf,Props,InitF,CaseList,FinMF}, St, Mode) when is_atom(InitF) -> case init_props(Props) of {error,_} -> {ok,[],St}; Props1 -> - collect_cases({conf,Props1,{St#cc.mod,InitF},CaseList,FinMF}, St) + collect_cases({conf,Props1,{St#cc.mod,InitF},CaseList,FinMF}, + St, Mode) end; -collect_cases({conf,Props,InitMF,CaseList,FinF}, St) when is_atom(FinF) -> +collect_cases({conf,Props,InitMF,CaseList,FinF}, St, Mode) when is_atom(FinF) -> case init_props(Props) of {error,_} -> {ok,[],St}; Props1 -> - collect_cases({conf,Props1,InitMF,CaseList,{St#cc.mod,FinF}}, St) + collect_cases({conf,Props1,InitMF,CaseList,{St#cc.mod,FinF}}, + St, Mode) end; -collect_cases({conf,Props,InitMF,CaseList,FinMF} = Conf, St) -> +collect_cases({conf,Props,InitMF,CaseList,FinMF} = Conf, St, Mode) -> case init_props(Props) of {error,_} -> {ok,[],St}; @@ -4549,13 +4573,13 @@ collect_cases({conf,Props,InitMF,CaseList,FinMF} = Conf, St) -> Ref = make_ref(), Skips = St#cc.skip, Props2 = [{suite,St#cc.mod} | lists:delete(suite,Props1)], - Mode = [{Ref,Props2,undefined}], + Mode1 = [{Ref,Props2,undefined} | Mode], case in_skip_list({St#cc.mod,Conf}, Skips) of {true,Comment} -> % conf init skipped - {ok,[{skip_case,{conf,Ref,InitMF,Comment},Mode} | + {ok,[{skip_case,{conf,Ref,InitMF,Comment},Mode1} | [] ++ [{conf,Ref,[],FinMF}]],St}; {true,Name,Comment} when is_atom(Name) -> % all cases skipped - case collect_cases(CaseList, St) of + case collect_cases(CaseList, St, Mode1) of {ok,[],_St} = Empty -> Empty; {ok,FlatCases,St1} -> @@ -4563,15 +4587,15 @@ collect_cases({conf,Props,InitMF,CaseList,FinMF} = Conf, St) -> keep_name(Props1), FinMF}], Skipped = skip_cases_upto(Ref, Cases2Skip, Comment, - conf, Mode, skip_case), - {ok,[{skip_case,{conf,Ref,InitMF,Comment},Mode} | + conf, Mode1, skip_case), + {ok,[{skip_case,{conf,Ref,InitMF,Comment},Mode1} | Skipped],St1}; {error,_Reason} = Error -> Error end; {true,ToSkip,_} when is_list(ToSkip) -> % some cases skipped case collect_cases(CaseList, - St#cc{skip=ToSkip++Skips}) of + St#cc{skip=ToSkip++Skips}, Mode1) of {ok,[],_St} = Empty -> Empty; {ok,FlatCases,St1} -> @@ -4583,7 +4607,7 @@ collect_cases({conf,Props,InitMF,CaseList,FinMF} = Conf, St) -> Error end; false -> - case collect_cases(CaseList, St) of + case collect_cases(CaseList, St, Mode1) of {ok,[],_St} = Empty -> Empty; {ok,FlatCases,St1} -> @@ -4597,8 +4621,8 @@ collect_cases({conf,Props,InitMF,CaseList,FinMF} = Conf, St) -> end end; -collect_cases({make,InitMFA,CaseList,FinMFA}, St0) -> - case collect_cases(CaseList, St0) of +collect_cases({make,InitMFA,CaseList,FinMFA}, St0, Mode) -> + case collect_cases(CaseList, St0, Mode) of {ok,[],_St} = Empty -> Empty; {ok,FlatCases,St} -> Ref = make_ref(), @@ -4607,62 +4631,62 @@ collect_cases({make,InitMFA,CaseList,FinMFA}, St0) -> {error,_Reason} = Error -> Error end; -collect_cases({Module, Cases}, St) when is_list(Cases) -> - case (catch collect_case(Cases, St#cc{mod=Module}, [])) of +collect_cases({Module, Cases}, St, Mode) when is_list(Cases) -> + case (catch collect_case(Cases, St#cc{mod=Module}, [], Mode)) of {ok, NewCases, NewSt} -> {ok, NewCases, NewSt}; Other -> {error, Other} end; -collect_cases({_Mod,_Case}=Spec, St) -> - collect_case(Spec, St); +collect_cases({_Mod,_Case}=Spec, St, Mode) -> + collect_case(Spec, St, Mode); -collect_cases({_Mod,_Case,_Args}=Spec, St) -> - collect_case(Spec, St); -collect_cases(Case, St) when is_atom(Case), is_atom(St#cc.mod) -> - collect_case({St#cc.mod,Case}, St); -collect_cases(Other, St) -> +collect_cases({_Mod,_Case,_Args}=Spec, St, Mode) -> + collect_case(Spec, St, Mode); +collect_cases(Case, St, Mode) when is_atom(Case), is_atom(St#cc.mod) -> + collect_case({St#cc.mod,Case}, St, Mode); +collect_cases(Other, St, _Mode) -> {error,{bad_subtest_spec,St#cc.mod,Other}}. -collect_case({Mod,{conf,_,_,_,_}=Conf}, St) -> - collect_case_invoke(Mod, Conf, [], St); +collect_case({Mod,{conf,_,_,_,_}=Conf}, St, Mode) -> + collect_case_invoke(Mod, Conf, [], St, Mode); -collect_case(MFA, St) -> +collect_case(MFA, St, Mode) -> case in_skip_list(MFA, St#cc.skip) of {true,Comment} -> - {ok,[{skip_case,{MFA,Comment}}],St}; + {ok,[{skip_case,{MFA,Comment},Mode}],St}; false -> case MFA of - {Mod,Case} -> collect_case_invoke(Mod, Case, MFA, St); + {Mod,Case} -> collect_case_invoke(Mod, Case, MFA, St, Mode); {_Mod,_Case,_Args} -> {ok,[MFA],St} end end. -collect_case([], St, Acc) -> +collect_case([], St, Acc, _Mode) -> {ok, Acc, St}; -collect_case([Case | Cases], St, Acc) -> - {ok, FlatCases, NewSt} = collect_case({St#cc.mod, Case}, St), - collect_case(Cases, NewSt, Acc ++ FlatCases). +collect_case([Case | Cases], St, Acc, Mode) -> + {ok, FlatCases, NewSt} = collect_case({St#cc.mod, Case}, St, Mode), + collect_case(Cases, NewSt, Acc ++ FlatCases, Mode). -collect_case_invoke(Mod, Case, MFA, St) -> +collect_case_invoke(Mod, Case, MFA, St, Mode) -> case get_fw_mod(undefined) of undefined -> case catch apply(Mod, Case, [suite]) of {'EXIT',_} -> {ok,[MFA],St}; Suite -> - collect_subcases(Mod, Case, MFA, St, Suite) + collect_subcases(Mod, Case, MFA, St, Suite, Mode) end; _ -> Suite = test_server_sup:framework_call(get_suite, [Mod,Case], []), - collect_subcases(Mod, Case, MFA, St, Suite) + collect_subcases(Mod, Case, MFA, St, Suite, Mode) end. -collect_subcases(Mod, Case, MFA, St, Suite) -> +collect_subcases(Mod, Case, MFA, St, Suite, Mode) -> case Suite of [] when Case == all -> {ok,[],St}; [] when element(1, Case) == conf -> {ok,[],St}; @@ -4670,28 +4694,28 @@ collect_subcases(Mod, Case, MFA, St, Suite) -> %%%! --- START Kept for backwards compatibility --- %%%! Requirements are not used {req,ReqList} -> - collect_case_deny(Mod, Case, MFA, ReqList, [], St); + collect_case_deny(Mod, Case, MFA, ReqList, [], St, Mode); {req,ReqList,SubCases} -> - collect_case_deny(Mod, Case, MFA, ReqList, SubCases, St); + collect_case_deny(Mod, Case, MFA, ReqList, SubCases, St, Mode); %%%! --- END Kept for backwards compatibility --- {Skip,Reason} when Skip==skip; Skip==skipped -> - {ok,[{skip_case,{MFA,Reason}}],St}; + {ok,[{skip_case,{MFA,Reason},Mode}],St}; {error,Reason} -> throw(Reason); SubCases -> - collect_case_subcases(Mod, Case, SubCases, St) + collect_case_subcases(Mod, Case, SubCases, St, Mode) end. -collect_case_subcases(Mod, Case, SubCases, St0) -> +collect_case_subcases(Mod, Case, SubCases, St0, Mode) -> OldMod = St0#cc.mod, - case collect_cases(SubCases, St0#cc{mod=Mod}) of + case collect_cases(SubCases, St0#cc{mod=Mod}, Mode) of {ok,FlatCases,St} -> {ok,FlatCases,St#cc{mod=OldMod}}; {error,Reason} -> {error,{{Mod,Case},Reason}} end. -collect_files(Dir, Pattern, St) -> +collect_files(Dir, Pattern, St, Mode) -> {ok,Cwd} = file:get_cwd(), Dir1 = filename:join(Cwd, Dir), Wc = filename:join([Dir1,Pattern++code:objfile_extension()]), @@ -4701,7 +4725,7 @@ collect_files(Dir, Pattern, St) -> {error,{collect_fail,Dir,Pattern}}; Mods0 -> Mods = [{path_to_module(Mod),all} || Mod <- lists:sort(Mods0)], - collect_cases(Mods, St) + collect_cases(Mods, St, Mode) end. path_to_module(Path) when is_list(Path) -> @@ -4711,14 +4735,14 @@ path_to_module(Path) when is_list(Path) -> %% anyway. It should be removed or renamed! list_to_atom(filename:rootname(filename:basename(Path))). -collect_case_deny(Mod, Case, MFA, ReqList, SubCases, St) -> +collect_case_deny(Mod, Case, MFA, ReqList, SubCases, St, Mode) -> case {check_deny(ReqList, St#cc.skip),SubCases} of {{denied,Comment},_SubCases} -> - {ok,[{skip_case,{MFA,Comment}}],St}; + {ok,[{skip_case,{MFA,Comment},Mode}],St}; {granted,[]} -> {ok,[MFA],St}; {granted,SubCases} -> - collect_case_subcases(Mod, Case, SubCases, St) + collect_case_subcases(Mod, Case, SubCases, St, Mode) end. check_deny([Req|Reqs], DenyList) -> @@ -5476,10 +5500,16 @@ write_html_file(File,Content) -> %% The 'major' log file, which is a pure text file is also written %% with utf8 encoding open_utf8_file(File) -> - file:open(File,[write,{encoding,utf8}]). + case file:open(File,AllOpts=[write,{encoding,utf8}]) of + {error,Reason} -> {error,{Reason,{File,AllOpts}}}; + Result -> Result + end. open_utf8_file(File,Opts) -> - file:open(File,[{encoding,utf8}|Opts]). + case file:open(File,AllOpts=[{encoding,utf8}|Opts]) of + {error,Reason} -> {error,{Reason,{File,AllOpts}}}; + Result -> Result + end. %% Write a file with specified encoding write_file(File,Content,latin1) -> diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl index 11d6f7af4d..bc7d244c7c 100644 --- a/lib/test_server/src/ts.erl +++ b/lib/test_server/src/ts.erl @@ -24,7 +24,7 @@ -module(ts). --export([run/0, run/1, run/2, run/3, run/4, +-export([run/0, run/1, run/2, run/3, run/4, run/5, tests/0, tests/1, install/0, install/1, bench/0, bench/1, bench/2, benchmarks/0, @@ -389,6 +389,16 @@ run(Testspec, Mod, Grs={group,_Groups}, Config) when is_atom(Testspec), Args = [{suite,Mod},Grs], run_test(atom_to_list(Testspec), Args, Options). +%% run/5 +%% Run one or more test cases in a group with Options. +run(Testspec, Mod, Group, Cases, Config) when is_atom(Testspec), + is_atom(Mod), + is_list(Config) -> + Group1 = if is_tuple(Group) -> Group; true -> {group,Group} end, + Cases1 = if is_tuple(Cases) -> Cases; true -> {testcase,Cases} end, + Options=check_test_get_opts(Testspec, Config), + Args = [{suite,Mod},Group1,Cases1], + run_test(atom_to_list(Testspec), Args, Options). is_list_of_suites(List) -> lists:all(fun(Suite) -> diff --git a/lib/test_server/src/ts_run.erl b/lib/test_server/src/ts_run.erl index d96abfc55a..18d021f780 100644 --- a/lib/test_server/src/ts_run.erl +++ b/lib/test_server/src/ts_run.erl @@ -398,8 +398,9 @@ make_common_test_args(Args0, Options0, _Vars) -> end, ConfigFiles = [{config,[filename:join(ConfigPath,File) || File <- get_config_files()]}], - io_lib:format("~100000p",[Args0++Trace++Cover++Logdir++ - ConfigFiles++Options++TimeTrap]). + io_lib:format("~100000p",[[{abort_if_missing_suites,true} | + Args0++Trace++Cover++Logdir++ + ConfigFiles++Options++TimeTrap]]). to_list(X) when is_atom(X) -> atom_to_list(X); |