aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bootstrap/lib/compiler/ebin/beam_bool.beambin16240 -> 16292 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_jump.beambin8680 -> 8700 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_utils.beambin13460 -> 13476 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_clauses.beambin2876 -> 2928 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_inline.beambin38880 -> 39064 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin38852 -> 38852 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_lint.beambin12196 -> 12820 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin49840 -> 50008 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_pre_expand.beambin14216 -> 14252 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_codegen.beambin54480 -> 54556 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_core.beambin51748 -> 52376 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel.beambin46996 -> 46996 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/hipe_unified_loader.beambin13256 -> 13516 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets.beambin53624 -> 53656 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin86612 -> 87856 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc_pt.beambin73660 -> 73720 bytes
-rw-r--r--erts/doc/src/escript.xml23
-rw-r--r--erts/emulator/beam/utils.c6
-rw-r--r--erts/emulator/hipe/hipe_bif0.c39
-rw-r--r--erts/emulator/hipe/hipe_bif0.tab3
-rw-r--r--erts/emulator/test/map_SUITE.erl19
-rw-r--r--lib/common_test/src/ct_framework.erl50
-rw-r--r--lib/common_test/src/ct_hooks.erl2
-rw-r--r--lib/common_test/src/ct_run.erl65
-rw-r--r--lib/common_test/src/ct_testspec.erl7
-rw-r--r--lib/common_test/src/ct_util.hrl1
-rw-r--r--lib/common_test/test/ct_config_info_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_error_SUITE.erl52
-rw-r--r--lib/common_test/test/ct_group_info_SUITE.erl30
-rw-r--r--lib/common_test/test/ct_groups_spec_SUITE.erl75
-rw-r--r--lib/common_test/test/ct_hooks_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl14
-rw-r--r--lib/common_test/test/ct_repeat_1_SUITE.erl35
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_sequence_1_SUITE.erl19
-rw-r--r--lib/common_test/test/ct_skip_SUITE.erl118
-rw-r--r--lib/common_test/test/ct_surefire_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_test_server_if_1_SUITE.erl8
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE.erl92
-rw-r--r--lib/compiler/doc/src/compile.xml10
-rw-r--r--lib/compiler/src/beam_bool.erl22
-rw-r--r--lib/compiler/src/beam_jump.erl2
-rw-r--r--lib/compiler/src/beam_utils.erl2
-rw-r--r--lib/compiler/src/cerl_clauses.erl18
-rw-r--r--lib/compiler/src/cerl_inline.erl14
-rw-r--r--lib/compiler/src/compile.erl2
-rw-r--r--lib/compiler/src/core_lint.erl27
-rw-r--r--lib/compiler/src/sys_core_fold.erl21
-rw-r--r--lib/compiler/src/sys_pre_expand.erl7
-rw-r--r--lib/compiler/src/v3_codegen.erl6
-rw-r--r--lib/compiler/src/v3_core.erl115
-rw-r--r--lib/compiler/src/v3_kernel.erl2
-rw-r--r--lib/compiler/test/andor_SUITE.erl15
-rw-r--r--lib/compiler/test/core_SUITE.erl5
-rw-r--r--lib/compiler/test/core_SUITE_data/bad_boolean_guard.core32
-rw-r--r--lib/compiler/test/fun_SUITE.erl8
-rw-r--r--lib/compiler/test/guard_SUITE.erl12
-rw-r--r--lib/compiler/test/lc_SUITE.erl8
-rw-r--r--lib/compiler/test/map_SUITE.erl30
-rw-r--r--lib/compiler/test/receive_SUITE.erl1
-rw-r--r--lib/compiler/test/record_SUITE.erl8
-rw-r--r--lib/compiler/test/warnings_SUITE.erl25
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/predef.erl4
-rw-r--r--lib/erl_docgen/src/docgen_edoc_xml_cb.erl17
-rw-r--r--lib/erl_docgen/src/docgen_otp_specs.erl2
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl13
-rw-r--r--lib/kernel/src/hipe_unified_loader.erl24
-rw-r--r--lib/ssl/doc/src/ssl.xml28
-rw-r--r--lib/ssl/src/ssl.erl13
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl14
-rw-r--r--lib/stdlib/doc/src/Makefile1
-rw-r--r--lib/stdlib/doc/src/maps.xml318
-rw-r--r--lib/stdlib/doc/src/ref_man.xml1
-rw-r--r--lib/stdlib/doc/src/specs.xml1
-rw-r--r--lib/stdlib/doc/src/supervisor.xml6
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml3
-rw-r--r--lib/stdlib/src/dets.erl12
-rw-r--r--lib/stdlib/src/erl_lint.erl218
-rw-r--r--lib/stdlib/src/gen.erl6
-rw-r--r--lib/stdlib/src/maps.erl15
-rw-r--r--lib/stdlib/src/qlc_pt.erl11
-rw-r--r--lib/stdlib/test/dets_SUITE.erl75
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl163
-rw-r--r--lib/stdlib/test/erl_lint_SUITE_data/predef.erl4
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl19
-rw-r--r--lib/test_server/src/test_server_ctrl.erl302
-rw-r--r--lib/test_server/src/ts.erl12
-rw-r--r--lib/test_server/src/ts_run.erl5
-rw-r--r--lib/tools/src/cover.erl19
89 files changed, 1678 insertions, 690 deletions
diff --git a/bootstrap/lib/compiler/ebin/beam_bool.beam b/bootstrap/lib/compiler/ebin/beam_bool.beam
index fb414eb9b1..f5f45d14a5 100644
--- a/bootstrap/lib/compiler/ebin/beam_bool.beam
+++ b/bootstrap/lib/compiler/ebin/beam_bool.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam
index a619db9d50..2b839bc997 100644
--- a/bootstrap/lib/compiler/ebin/beam_jump.beam
+++ b/bootstrap/lib/compiler/ebin/beam_jump.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam
index 204a243a5b..8507db5454 100644
--- a/bootstrap/lib/compiler/ebin/beam_utils.beam
+++ b/bootstrap/lib/compiler/ebin/beam_utils.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_clauses.beam b/bootstrap/lib/compiler/ebin/cerl_clauses.beam
index ec41e1098b..c55d8be59d 100644
--- a/bootstrap/lib/compiler/ebin/cerl_clauses.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_clauses.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam
index cfe023c601..d42de9d40d 100644
--- a/bootstrap/lib/compiler/ebin/cerl_inline.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index c13c3a40a6..81261e8c5c 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam
index dca9efc2f3..e172ec6af7 100644
--- a/bootstrap/lib/compiler/ebin/core_lint.beam
+++ b/bootstrap/lib/compiler/ebin/core_lint.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
index 667d56d6d1..a664909bdc 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam
index 6a6216e80f..5c14528eff 100644
--- a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam
+++ b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam
index c270802455..6bf28f441e 100644
--- a/bootstrap/lib/compiler/ebin/v3_codegen.beam
+++ b/bootstrap/lib/compiler/ebin/v3_codegen.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam
index 0b4228f8a8..add7d2be2f 100644
--- a/bootstrap/lib/compiler/ebin/v3_core.beam
+++ b/bootstrap/lib/compiler/ebin/v3_core.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_kernel.beam b/bootstrap/lib/compiler/ebin/v3_kernel.beam
index ecec470cb0..1ac5932127 100644
--- a/bootstrap/lib/compiler/ebin/v3_kernel.beam
+++ b/bootstrap/lib/compiler/ebin/v3_kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
index 31a54ecef4..d24c06f112 100644
--- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
+++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam
index ac36354796..6f430b8c6c 100644
--- a/bootstrap/lib/stdlib/ebin/dets.beam
+++ b/bootstrap/lib/stdlib/ebin/dets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index 4e3acd3422..6e9d06ea44 100644
--- a/bootstrap/lib/stdlib/ebin/erl_lint.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
index f53c840702..6184f0c295 100644
--- a/bootstrap/lib/stdlib/ebin/qlc_pt.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
Binary files differ
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/beam/utils.c b/erts/emulator/beam/utils.c
index 5b43d25e3c..738f793020 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -2125,7 +2125,11 @@ tailrecur_ne:
if (!is_boxed(b) || *boxed_val_rel(b,b_base) != *aa)
goto not_equal;
bb = map_val_rel(b,b_base);
- if ((sz = map_get_size((map_t*)aa)) == 0) goto pop_next;
+ sz = map_get_size((map_t*)aa);
+
+ if (sz != map_get_size((map_t*)bb)) goto not_equal;
+ if (sz == 0) goto pop_next;
+
aa += 2;
bb += 2;
sz += 1; /* increment for tuple-keys */
diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c
index fa99c817f0..2497d51df1 100644
--- a/erts/emulator/hipe/hipe_bif0.c
+++ b/erts/emulator/hipe/hipe_bif0.c
@@ -1101,9 +1101,9 @@ BIF_RETTYPE hipe_bifs_make_fun_3(BIF_ALIST_3)
#endif
/*
- * args: Nativecodeaddress, Module, {Uniq, Index, BeamAddress}
+ * args: Module, {Uniq, Index, BeamAddress}
*/
-BIF_RETTYPE hipe_bifs_make_fe_3(BIF_ALIST_3)
+BIF_RETTYPE hipe_bifs_get_fe_2(BIF_ALIST_2)
{
Eterm mod;
Uint index;
@@ -1111,20 +1111,15 @@ BIF_RETTYPE hipe_bifs_make_fe_3(BIF_ALIST_3)
void *beam_address;
ErlFunEntry *fe;
Eterm *tp;
- void *native_address;
-
- native_address = term_to_address(BIF_ARG_1);
- if (!native_address)
- BIF_ERROR(BIF_P, BADARG);
- if (is_not_atom(BIF_ARG_2))
+ if (is_not_atom(BIF_ARG_1))
BIF_ERROR(BIF_P, BADARG);
- mod = BIF_ARG_2;
+ mod = BIF_ARG_1;
- if (is_not_tuple(BIF_ARG_3) ||
- (arityval(*tuple_val(BIF_ARG_3)) != 3))
+ if (is_not_tuple(BIF_ARG_2) ||
+ (arityval(*tuple_val(BIF_ARG_2)) != 3))
BIF_ERROR(BIF_P, BADARG);
- tp = tuple_val(BIF_ARG_3);
+ tp = tuple_val(BIF_ARG_2);
if (term_to_Uint(tp[1], &uniq) == 0)
BIF_ERROR(BIF_P, BADARG);
if (term_to_Uint(tp[2], &index) == 0)
@@ -1144,10 +1139,28 @@ BIF_RETTYPE hipe_bifs_make_fe_3(BIF_ALIST_3)
printf("no fun entry for %s %ld:%ld\n", atom_buf, uniq, index);
BIF_ERROR(BIF_P, BADARG);
}
+ BIF_RET(address_to_term((void *)fe, BIF_P));
+}
+
+/*
+ * args: FE, Nativecodeaddress
+ */
+BIF_RETTYPE hipe_bifs_set_native_address_in_fe_2(BIF_ALIST_2)
+{
+ ErlFunEntry *fe;
+ void *native_address;
+
+ fe = (ErlFunEntry *)term_to_address(BIF_ARG_1);
+ if (!fe)
+ BIF_ERROR(BIF_P, BADARG);
+ native_address = term_to_address(BIF_ARG_2);
+ if (!native_address)
+ BIF_ERROR(BIF_P, BADARG);
+
fe->native_address = native_address;
if (erts_refc_dectest(&fe->refc, 0) == 0)
erts_erase_fun_entry(fe);
- BIF_RET(address_to_term((void *)fe, BIF_P));
+ BIF_RET(am_true);
}
#if 0 /* XXX: unused */
diff --git a/erts/emulator/hipe/hipe_bif0.tab b/erts/emulator/hipe/hipe_bif0.tab
index ce641365e9..2514b1c3a5 100644
--- a/erts/emulator/hipe/hipe_bif0.tab
+++ b/erts/emulator/hipe/hipe_bif0.tab
@@ -69,7 +69,8 @@ bif hipe_bifs:atom_to_word/1
bif hipe_bifs:term_to_word/1
#bif hipe_bifs:make_fun/3
-bif hipe_bifs:make_fe/3
+bif hipe_bifs:get_fe/2
+bif hipe_bifs:set_native_address_in_fe/2
#bif hipe_bifs:make_native_stub/2
bif hipe_bifs:find_na_or_make_stub/2
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index 8cc5621181..753d6f7727 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -29,6 +29,7 @@
t_guard_receive/1, t_guard_fun/1,
t_list_comprehension/1,
t_map_sort_literals/1,
+ t_map_equal/1,
%t_size/1,
t_map_size/1,
@@ -74,6 +75,7 @@ all() -> [
t_update_assoc,t_update_exact,
t_guard_bifs, t_guard_sequence, t_guard_update,
t_guard_receive,t_guard_fun, t_list_comprehension,
+ t_map_equal,
t_map_sort_literals,
%% Specific Map BIFs
@@ -450,6 +452,23 @@ t_map_sort_literals(Config) when is_list(Config) ->
ok.
+t_map_equal(Config) when is_list(Config) ->
+ true = id(#{}) =:= id(#{}),
+ false = id(#{}) =:= id(#{a=>1}),
+ false = id(#{a=>1}) =:= id(#{}),
+ true = id(#{ "a" => "hi", b => 134 }) =:= id(#{ b => 134,"a" => "hi"}),
+
+ false = id(#{ a => 1 }) =:= id(#{ a => 2}),
+ false = id(#{ a => 2 }) =:= id(#{ a => 1}),
+ false = id(#{ a => 2, b => 1 }) =:= id(#{ a => 1, b => 3}),
+ false = id(#{ a => 1, b => 1 }) =:= id(#{ a => 1, b => 3}),
+
+ true = id(#{ a => 1 }) =:= id(#{ a => 1}),
+ true = id(#{ "a" => 2 }) =:= id(#{ "a" => 2}),
+ true = id(#{ "a" => 2, b => 3 }) =:= id(#{ "a" => 2, b => 3}),
+ true = id(#{ a => 1, b => 3, c => <<"wat">> }) =:= id(#{ a => 1, b => 3, c=><<"wat">>}),
+ ok.
+
%% BIFs
t_bif_map_get(Config) when is_list(Config) ->
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 124abd13c1..d01f9ee13d 100644
--- a/lib/compiler/src/beam_bool.erl
+++ b/lib/compiler/src/beam_bool.erl
@@ -318,6 +318,8 @@ split_block_label_used([{set,[_],_,{bif,_,{f,Fail}}}|_], Fail) ->
true;
split_block_label_used([{set,[_],_,{alloc,_,{gc_bif,_,{f,Fail}}}}|_], Fail) ->
true;
+split_block_label_used([{set,[_],_,{alloc,_,{put_map,_,{f,Fail}}}}|_], Fail) ->
+ true;
split_block_label_used([_|Is], Fail) ->
split_block_label_used(Is, Fail);
split_block_label_used([], _) -> false.
@@ -391,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);
@@ -525,7 +531,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],
@@ -538,7 +546,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..bc9bdc67a4 100644
--- a/lib/compiler/src/cerl_inline.erl
+++ b/lib/compiler/src/cerl_inline.erl
@@ -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,16 @@ 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),
+ update_c_let(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/compile.erl b/lib/compiler/src/compile.erl
index b88f9792a5..9030dd998b 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -246,7 +246,7 @@ format_error_reason({Reason, Stack}) when is_list(Stack) ->
end,
FormatFun = fun (Term, _) -> io_lib:format("~tp", [Term]) end,
[io_lib:format("~tp", [Reason]),"\n\n",
- lib:format_stacktrace(1, erlang:get_stacktrace(), StackFun, FormatFun)];
+ lib:format_stacktrace(1, Stack, StackFun, FormatFun)];
format_error_reason(Reason) ->
io_lib:format("~tp", [Reason]).
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 eb9c302334..6fdeea51d1 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -2346,16 +2346,31 @@ is_safe_bool_expr(Core, Sub) ->
is_safe_bool_expr_1(Core, Sub, gb_sets:empty()).
is_safe_bool_expr_1(#c_call{module=#c_literal{val=erlang},
- name=#c_literal{val=is_record},
- args=[_,_]},
- _Sub, _BoolVars) ->
+ name=#c_literal{val=is_record},
+ args=[A,#c_literal{val=Tag},#c_literal{val=Size}]},
+ Sub, _BoolVars) when is_atom(Tag), is_integer(Size) ->
+ is_safe_simple(A, Sub);
+is_safe_bool_expr_1(#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=is_record}},
+ _Sub, _BoolVars) ->
%% The is_record/2 BIF is NOT allowed in guards.
+ %% The is_record/3 BIF where its second argument is not an atom or its third
+ %% is not an integer is NOT allowed in guards.
%%
%% NOTE: Calls like is_record(Expr, LiteralTag), where LiteralTag
%% is a literal atom referring to a defined record, have already
%% 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/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index 9998043013..91a46a20fe 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -331,9 +331,10 @@ expr({tuple,Line,Es0}, St0) ->
expr({map,Line,Es0}, St0) ->
{Es1,St1} = expr_list(Es0, St0),
{{map,Line,Es1},St1};
-expr({map,Line,Var,Es0}, St0) ->
- {Es1,St1} = expr_list(Es0, St0),
- {{map,Line,Var,Es1},St1};
+expr({map,Line,E0,Es0}, St0) ->
+ {E1,St1} = expr(E0, St0),
+ {Es1,St2} = expr_list(Es0, St1),
+ {{map,Line,E1,Es1},St2};
expr({map_field_assoc,Line,K0,V0}, St0) ->
{K,St1} = expr(K0, St0),
{V,St2} = expr(V0, St1),
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 a50b46bd7b..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,
@@ -623,7 +640,7 @@ expr({call,Lc,{atom,Lf,F},As0}, St0) ->
Op = #c_var{anno=lineno_anno(Lf, St1),name={F,length(As1)}},
{#iapply{anno=#a{anno=lineno_anno(Lc, St1)},op=Op,args=As1},Aps,St1};
expr({call,L,FunExp,As0}, St0) ->
- {Fun,Fps,St1} = safe(FunExp, St0),
+ {Fun,Fps,St1} = safe_fun(length(As0), FunExp, St0),
{As1,Aps,St2} = safe_list(As0, St1),
Lanno = lineno_anno(L, St2),
{#iapply{anno=#a{anno=Lanno},op=Fun,args=As1},Fps ++ Aps,St2};
@@ -1408,6 +1425,15 @@ safe(E0, St0) ->
{Se,Sps,St2} = force_safe(E1, St1),
{Se,Eps ++ Sps,St2}.
+safe_fun(A0, E0, St0) ->
+ case safe(E0, St0) of
+ {#c_var{name={_,A1}}=E1,Eps,St1} when A1 =/= A0 ->
+ {V,St2} = new_var(St1),
+ {V,Eps ++ [#iset{var=V,arg=E1}],St2};
+ Result ->
+ Result
+ end.
+
safe_list(Es, St) ->
foldr(fun (E, {Ces,Esp,St0}) ->
{Ce,Ep,St1} = safe(E, St0),
@@ -1756,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..d79696df38 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,14 @@ 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)))),
+
+ 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/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl
index e35692efd1..25b7f677b5 100644
--- a/lib/compiler/test/fun_SUITE.erl
+++ b/lib/compiler/test/fun_SUITE.erl
@@ -21,7 +21,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
test1/1,overwritten_fun/1,otp_7202/1,bif_fun/1,
- external/1,eep37/1]).
+ external/1,eep37/1,badarity/1]).
%% Internal export.
-export([call_me/1]).
@@ -32,7 +32,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [test1,overwritten_fun,otp_7202,bif_fun,external,eep37].
+ [test1,overwritten_fun,otp_7202,bif_fun,external,eep37,badarity].
groups() ->
[].
@@ -206,5 +206,9 @@ eep37(Config) when is_list(Config) ->
50 = UnusedName(8),
ok.
+badarity(Config) when is_list(Config) ->
+ {'EXIT',{{badarity,{_,[]}},_}} = (catch (fun badarity/1)()),
+ ok.
+
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 b4baef461b..b7e27afef1 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -42,7 +42,8 @@
t_build_and_match_val/1,
%% errors in 17.0-rc1
- t_update_values/1
+ t_update_values/1,
+ t_expand_map_update/1
]).
suite() -> [].
@@ -68,7 +69,8 @@ all() -> [
t_build_and_match_val,
%% errors in 17.0-rc1
- t_update_values
+ t_update_values,
+ t_expand_map_update
].
groups() -> [].
@@ -105,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}))),
@@ -187,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 },
@@ -273,20 +280,33 @@ t_update_values(Config) when is_list(Config) ->
end, {none, none, #{val1=>none,val2=>none}},List),
ok.
+t_expand_map_update(Config) when is_list(Config) ->
+ M = #{<<"hello">> => <<"world">>}#{<<"hello">> := <<"les gens">>},
+ #{<<"hello">> := <<"les gens">>} = M,
+ ok.
+
check_val(#{val1:=V1, val2:=V2},V1,V2) -> ok.
get_val(#{ "wazzup" := _, val := V}) -> V;
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.
@@ -295,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/record_SUITE.erl b/lib/compiler/test/record_SUITE.erl
index c9f5a2053e..f736e14bf6 100644
--- a/lib/compiler/test/record_SUITE.erl
+++ b/lib/compiler/test/record_SUITE.erl
@@ -369,6 +369,14 @@ record_test_3(Config) when is_list(Config) ->
?line false = is_record(id(#barf{}), id(barf), id(42)),
?line false = is_record(id(#barf{}), id(foo), id(6)),
+ Rec = id(#barf{}),
+ Good = id(barf),
+ Bad = id(foo),
+ Size = id(6),
+
+ true = is_record(Rec, Good, Size) orelse error,
+ error = is_record(Rec, Bad, Size) orelse error,
+
ok.
record_access_in_guards(Config) when is_list(Config) ->
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index 16d15a59e5..f63299ea35 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]).
% Default timetrap timeout (set in init_per_testcase).
-define(default_timeout, ?t:minutes(2)).
@@ -61,7 +62,7 @@ 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]}].
init_per_suite(Config) ->
Config.
@@ -552,6 +553,26 @@ 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.
+
%%%
%%% 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/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl
index e111cb800e..976d5e35cb 100644
--- a/lib/kernel/src/hipe_unified_loader.erl
+++ b/lib/kernel/src/hipe_unified_loader.erl
@@ -203,6 +203,7 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
"please regenerate native code for this runtime system\n", [Mod]),
bad_crc;
true ->
+ put(closures_to_patch, []),
%% Create data segment
{ConstAddr,ConstMap2} =
create_data_segment(ConstAlign, ConstSize, ConstMap),
@@ -224,14 +225,23 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
%% Patch all dynamic references in the code.
%% Function calls, Atoms, Constants, System calls
ok = patch(Refs, CodeAddress, ConstMap2, Addresses, TrampolineMap),
+
%% Tell the system where the loaded funs are.
%% (patches the BEAM code to redirect to native.)
case Beam of
[] ->
+ %% This module was previously loaded as BEAM code during system
+ %% start-up before the code server has started (-enable-native-libs
+ %% is active), so we must now patch the pre-existing entries in the
+ %% fun table with the native code addresses for all closures.
+ lists:foreach(fun({FE, DestAddress}) ->
+ hipe_bifs:set_native_address_in_fe(FE, DestAddress)
+ end, erase(closures_to_patch)),
export_funs(Addresses),
ok;
BeamBinary when is_binary(BeamBinary) ->
%% Find all closures in the code.
+ [] = erase(closures_to_patch), %Clean up, assertion.
ClosurePatches = find_closure_patches(Refs),
AddressesOfClosuresToPatch =
calculate_addresses(ClosurePatches, CodeAddress, Addresses),
@@ -245,6 +255,9 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
%% The call to export_funs/1 above updated the native addresses
%% for the targets, so passing 'Addresses' is not needed.
redirect(ReferencesToPatch),
+ %% Final clean up.
+ _ = erase(hipe_patch_closures),
+ _ = erase(hipe_assert_code_area),
?debug_msg("****************Loader Finished****************\n", []),
{module,Mod} % for compatibility with code:load_file/1
end.
@@ -562,12 +575,17 @@ patch_closure(DestMFA, Uniq, Index, Address, Addresses) ->
case get(hipe_patch_closures) of
false ->
[]; % This is taken care of when registering the module.
- true -> % We are not loading a module patch these closures
+ true ->
+ %% We are replacing a previosly loaded BEAM module with native code,
+ %% so we must reference the pre-existing entries in the fun table
+ %% from the native code. We must delay actually patching the native
+ %% address into the fun entry to ensure that the native code cannot
+ %% be called until it has been completely fixed up.
RemoteOrLocal = local, % closure code refs are local
DestAddress = get_native_address(DestMFA, Addresses, RemoteOrLocal),
BEAMAddress = hipe_bifs:fun_to_address(DestMFA),
- FE = hipe_bifs:make_fe(DestAddress, mod(DestMFA),
- {Uniq, Index, BEAMAddress}),
+ FE = hipe_bifs:get_fe(mod(DestMFA), {Uniq, Index, BEAMAddress}),
+ put(closures_to_patch, [{FE,DestAddress}|get(closures_to_patch)]),
?debug_msg("Patch FE(~w) to 0x~.16b->0x~.16b (emu:0x~.16b)\n",
[DestMFA, FE, DestAddress, BEAMAddress]),
?ASSERT(assert_local_patch(Address)),
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 910dca3889..4bc1a9a644 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1999</year><year>2013</year>
+ <year>1999</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -184,12 +184,6 @@
<item> The DER encoded trusted certificates. If this option
is supplied it will override the cacertfile option.</item>
- <tag>{cacertfile, path()}</tag>
- <item>Path to file containing PEM encoded
- CA certificates (trusted certificates used for verifying a peer
- certificate). May be omitted if you do not want to verify
- the peer.</item>
-
<tag>{ciphers, ciphers()}</tag>
<item>The cipher suites that should be supported. The function
<c>cipher_suites/0</c> can be used to find all ciphers that are
@@ -354,7 +348,13 @@ fun(srp, Username :: string(), UserState :: term()) ->
<item>Specifies if client should try to reuse sessions
when possible.
</item>
-
+
+ <tag>{cacertfile, path()}</tag>
+ <item>The path to a file containing PEM encoded CA certificates. The CA
+ certificates are used during server authentication and when building the
+ client certificate chain.
+ </item>
+
<tag>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()]}}</tag>
<tag>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()], Default :: binary()}}</tag>
<item>
@@ -403,7 +403,17 @@ fun(srp, Username :: string(), UserState :: term()) ->
meaning in the server than in the client.</p>
<taglist>
-
+
+ <tag>{cacertfile, path()}</tag>
+ <item>The path to a file containing PEM encoded CA
+ certificates. The CA certificates are used to build the server
+ certificate chain, and for client authentication. Also the CAs
+ are used in the list of acceptable client CAs passed to the
+ client when a certificate is requested. May be omitted if there
+ is no need to verify the client and if there are not any
+ intermediate CAs for the server certificate.
+ </item>
+
<tag>{dh, der_encoded()}</tag>
<item>The DER encoded Diffie Hellman parameters. If this option
is supplied it will override the dhfile option.
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index c3bdeb1a54..9e098e12c4 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -557,6 +557,7 @@ do_connect(Address, Port,
handle_options(Opts0, _Role) ->
Opts = proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Opts0),
+ assert_proplist(Opts),
ReuseSessionFun = fun(_, _, _, _) -> true end,
DefaultVerifyNoneFun =
@@ -1042,3 +1043,15 @@ connection_sup(dtls_connection) ->
binary_filename(FileName) ->
Enc = file:native_name_encoding(),
unicode:characters_to_binary(FileName, unicode, Enc).
+
+assert_proplist([]) ->
+ true;
+assert_proplist([{Key,_} | Rest]) when is_atom(Key) ->
+ assert_proplist(Rest);
+%% Handle exceptions
+assert_proplist([inet | Rest]) ->
+ assert_proplist(Rest);
+assert_proplist([inet6 | Rest]) ->
+ assert_proplist(Rest);
+assert_proplist([Value | _]) ->
+ throw({option_not_a_key_value_tuple, Value}).
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 523760aba6..64a93440c7 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -96,6 +96,7 @@ basic_tests() ->
options_tests() ->
[der_input,
misc_ssl_options,
+ ssl_options_not_proplist,
socket_options,
invalid_inet_get_option,
invalid_inet_get_option_not_list,
@@ -990,7 +991,7 @@ misc_ssl_options(Config) when is_list(Config) ->
ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- %% Chek that ssl options not tested elsewhere are filtered away e.i. not passed to inet.
+ %% Check that ssl options not tested elsewhere are filtered away e.i. not passed to inet.
TestOpts = [{depth, 1},
{key, undefined},
{password, []},
@@ -1018,6 +1019,17 @@ misc_ssl_options(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+ssl_options_not_proplist() ->
+ [{doc,"Test what happens if an option is not a key value tuple"}].
+
+ssl_options_not_proplist(Config) when is_list(Config) ->
+ BadOption = {client_preferred_next_protocols,
+ client, [<<"spdy/3">>,<<"http/1.1">>], <<"http/1.1">>},
+ {option_not_a_key_value_tuple, BadOption} =
+ ssl:connect("twitter.com", 443, [binary, {active, false},
+ BadOption]).
+
+%%--------------------------------------------------------------------
versions() ->
[{doc,"Test API function versions/0"}].
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/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl
index c26764eb18..b6bb758dfb 100644
--- a/lib/stdlib/src/qlc_pt.erl
+++ b/lib/stdlib/src/qlc_pt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -1218,13 +1218,14 @@ lu_skip(ColConstants, FilterData, PatternFrame, PatternVars,
%% column, the filter will not be skipped.
%% (an example: {X=1} <- ..., X =:= 1).
length(D = Cols -- PatternColumns) =:= 1,
- Frame <- SFs,
- begin
+ {{_,Col} = Column, Constants} <- D,
+ %% Check that the following holds for all frames.
+ lists:all(
+ fun(Frame) ->
%% The column is compared/matched against a constant.
%% If there are no more comparisons/matches then
%% the filter can be replaced by the lookup of
%% the constant.
- [{{_,Col} = Column, Constants}] = D,
{VarI, FrameI} = unify_column(Frame, PV, Col, BindFun,
Imported),
VarValues = deref_skip(VarI, FrameI, LookupOp, Imported),
@@ -1253,7 +1254,7 @@ lu_skip(ColConstants, FilterData, PatternFrame, PatternVars,
length(VarValues) =< 1 andalso
(Constants -- LookedUpConstants =:= []) andalso
bindings_is_subset(Frame, F2, Imported)
- end],
+ end, SFs)],
ColFils = family_list(ColFil),
%% The skip tag 'all' means that all filters are covered by the lookup.
%% It does not imply that there is only one generator as is the case
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/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index 2846657c09..37fbb5267b 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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
@@ -72,7 +72,7 @@
otp_5644/1, otp_5195/1, otp_6038_bug/1, otp_6359/1, otp_6562/1,
otp_6590/1, otp_6673/1, otp_6964/1, otp_7114/1, otp_7238/1,
- otp_7232/1, otp_7552/1, otp_6674/1, otp_7714/1,
+ otp_7232/1, otp_7552/1, otp_6674/1, otp_7714/1, otp_11758/1,
manpage/1,
@@ -142,7 +142,7 @@ groups() ->
{tickets, [],
[otp_5644, otp_5195, otp_6038_bug, otp_6359, otp_6562,
otp_6590, otp_6673, otp_6964, otp_7114, otp_7232,
- otp_7238, otp_7552, otp_6674, otp_7714]},
+ otp_7238, otp_7552, otp_6674, otp_7714, otp_11758]},
{compat, [], [backward, forward]}].
init_per_suite(Config) ->
@@ -6670,6 +6670,19 @@ otp_7714(Config) when is_list(Config) ->
ets:delete(E2)">>],
?line run(Config, Ts).
+otp_11758(doc) ->
+ "OTP-11758. Bug.";
+otp_11758(suite) -> [];
+otp_11758(Config) when is_list(Config) ->
+ Ts = [<<"T = ets:new(r, [{keypos, 2}]),
+ L = [{rrr, xxx, aaa}, {rrr, yyy, bbb}],
+ true = ets:insert(T, L),
+ QH = qlc:q([{rrr, B, C} || {rrr, B, C} <- ets:table(T),
+ (B =:= xxx) or (B =:= yyy) and (C =:= aaa)]),
+ [{rrr,xxx,aaa}] = qlc:e(QH),
+ ets:delete(T)">>],
+ run(Config, Ts).
+
otp_6674(doc) ->
"OTP-6674. match/comparison.";
otp_6674(suite) -> [];
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);
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index a24d70ed92..113fa24bd5 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -1764,6 +1764,25 @@ munge_expr({record,Line,Arg,Name,Exprs}, Vars) ->
munge_expr({record_field,Line,ExprL,ExprR}, Vars) ->
{MungedExprR, Vars2} = munge_expr(ExprR, Vars),
{{record_field,Line,ExprL,MungedExprR}, Vars2};
+munge_expr({map,Line,Fields}, Vars) ->
+ %% EEP 43
+ {MungedFields, Vars2} = munge_exprs(Fields, Vars, []),
+ {{map,Line,MungedFields}, Vars2};
+munge_expr({map,Line,Arg,Fields}, Vars) ->
+ %% EEP 43
+ {MungedArg, Vars2} = munge_expr(Arg, Vars),
+ {MungedFields, Vars3} = munge_exprs(Fields, Vars2, []),
+ {{map,Line,MungedArg,MungedFields}, Vars3};
+munge_expr({map_field_assoc,Line,Name,Value}, Vars) ->
+ %% EEP 43
+ {MungedName, Vars2} = munge_expr(Name, Vars),
+ {MungedValue, Vars3} = munge_expr(Value, Vars2),
+ {{map_field_assoc,Line,MungedName,MungedValue}, Vars3};
+munge_expr({map_field_exact,Line,Name,Value}, Vars) ->
+ %% EEP 43
+ {MungedName, Vars2} = munge_expr(Name, Vars),
+ {MungedValue, Vars3} = munge_expr(Value, Vars2),
+ {{map_field_exact,Line,MungedName,MungedValue}, Vars3};
munge_expr({cons,Line,ExprH,ExprT}, Vars) ->
{MungedExprH, Vars2} = munge_expr(ExprH, Vars),
{MungedExprT, Vars3} = munge_expr(ExprT, Vars2),