aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--erts/emulator/beam/big.c8
-rw-r--r--erts/emulator/beam/external.c53
-rw-r--r--erts/emulator/beam/packet_parser.c2
-rw-r--r--erts/emulator/beam/utils.c4
-rw-r--r--erts/emulator/drivers/common/inet_drv.c8
-rw-r--r--erts/emulator/test/decode_packet_SUITE.erl4
-rw-r--r--erts/emulator/test/hash_SUITE.erl8
-rw-r--r--erts/emulator/test/nif_SUITE.erl168
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c114
-rw-r--r--erts/emulator/test/send_term_SUITE.erl67
-rw-r--r--erts/emulator/test/send_term_SUITE_data/send_term_drv.c218
-rw-r--r--erts/epmd/src/epmd.c8
-rw-r--r--erts/epmd/src/epmd_cli.c36
-rw-r--r--erts/epmd/src/epmd_srv.c6
-rw-r--r--lib/common_test/Makefile6
-rw-r--r--lib/common_test/doc/src/run_test.xml13
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml118
-rw-r--r--lib/common_test/priv/Makefile.in20
-rw-r--r--lib/common_test/priv/tile1.jpgbin0 -> 34734 bytes
-rw-r--r--lib/common_test/src/ct.erl20
-rw-r--r--lib/common_test/src/ct_framework.erl299
-rw-r--r--lib/common_test/src/ct_logs.erl179
-rw-r--r--lib/common_test/src/ct_run.erl303
-rw-r--r--lib/common_test/src/ct_testspec.erl66
-rw-r--r--lib/common_test/src/ct_util.erl1
-rw-r--r--lib/common_test/src/ct_util.hrl1
-rw-r--r--lib/common_test/test/Makefile1
-rw-r--r--lib/common_test/test/ct_groups_test_1_SUITE_data/groups_1/test/groups_11_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_groups_test_2_SUITE.erl24
-rw-r--r--lib/common_test/test/ct_groups_test_2_SUITE_data/specs/groups_2.1.spec26
-rw-r--r--lib/common_test/test/ct_test_support.erl7
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE.erl433
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl281
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_12_SUITE.erl344
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_21_SUITE.erl281
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_22_SUITE.erl314
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_1_SUITE.erl146
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_2_SUITE.erl146
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/src/beam_dict.erl4
-rw-r--r--lib/compiler/src/compile.erl32
-rw-r--r--lib/crypto/src/crypto.erl8
-rw-r--r--lib/debugger/src/dbg_icmd.erl29
-rw-r--r--lib/debugger/src/dbg_ieval.erl53
-rw-r--r--lib/debugger/src/dbg_iload.erl31
-rw-r--r--lib/debugger/src/dbg_iserver.erl50
-rw-r--r--lib/debugger/src/dbg_ui_break_win.erl7
-rw-r--r--lib/debugger/src/dbg_ui_filedialog_win.erl13
-rw-r--r--lib/debugger/src/dbg_ui_mon.erl21
-rw-r--r--lib/debugger/src/dbg_ui_mon_win.erl28
-rw-r--r--lib/debugger/src/dbg_ui_trace_win.erl205
-rw-r--r--lib/debugger/src/dbg_ui_view.erl6
-rw-r--r--lib/debugger/src/dbg_ui_win.erl8
-rw-r--r--lib/debugger/src/dbg_ui_winman.erl12
-rw-r--r--lib/debugger/src/dbg_wx_break_win.erl6
-rw-r--r--lib/debugger/src/dbg_wx_interpret.erl10
-rw-r--r--lib/debugger/src/dbg_wx_mon.erl19
-rw-r--r--lib/debugger/src/dbg_wx_mon_win.erl11
-rw-r--r--lib/debugger/src/dbg_wx_trace.erl50
-rwxr-xr-xlib/debugger/src/dbg_wx_trace_win.erl24
-rw-r--r--lib/debugger/src/dbg_wx_view.erl39
-rwxr-xr-xlib/debugger/src/dbg_wx_winman.erl12
-rw-r--r--lib/debugger/src/i.erl8
-rw-r--r--lib/debugger/src/int.erl10
-rw-r--r--lib/docbuilder/src/docb_edoc_xml_cb.erl64
-rw-r--r--lib/docbuilder/src/docb_html.erl27
-rw-r--r--lib/docbuilder/src/docb_html_util.erl17
-rw-r--r--lib/docbuilder/src/docb_main.erl27
-rw-r--r--lib/docbuilder/src/docb_pretty_format.erl4
-rw-r--r--lib/docbuilder/src/docb_tr_application2html.erl12
-rw-r--r--lib/docbuilder/src/docb_tr_cite2html.erl22
-rw-r--r--lib/docbuilder/src/docb_tr_index2html.erl4
-rw-r--r--lib/docbuilder/src/docb_tr_part2html.erl15
-rw-r--r--lib/docbuilder/src/docb_tr_term2html.erl22
-rw-r--r--lib/docbuilder/src/docb_transform.erl4
-rw-r--r--lib/docbuilder/src/docb_util.erl8
-rw-r--r--lib/docbuilder/src/docb_xmerl_tree_cb.erl4
-rw-r--r--lib/erl_interface/src/legacy/erl_marshal.c93
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE.erl34
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c50
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c102
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl21
-rw-r--r--lib/jinterface/java_src/Makefile16
-rw-r--r--lib/jinterface/java_src/pom.xml.src106
-rw-r--r--lib/kernel/doc/src/file.xml2
-rw-r--r--lib/kernel/src/auth.erl6
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl21
-rw-r--r--lib/ssl/src/ssl_handshake.erl12
-rw-r--r--lib/ssl/test/ssl_test_lib.erl4
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl4
-rw-r--r--lib/ssl/vsn.mk10
-rw-r--r--lib/stdlib/doc/src/beam_lib.xml1
-rw-r--r--lib/stdlib/doc/src/timer.xml26
-rw-r--r--lib/stdlib/src/beam_lib.erl1
-rw-r--r--lib/stdlib/src/escript.erl88
-rw-r--r--lib/stdlib/src/timer.erl13
-rw-r--r--lib/stdlib/test/timer_simple_SUITE.erl18
-rw-r--r--lib/test_server/src/test_server_ctrl.erl175
-rw-r--r--lib/test_server/vsn.mk2
100 files changed, 4205 insertions, 1265 deletions
diff --git a/.gitignore b/.gitignore
index cba7caa074..aa32bd9582 100644
--- a/.gitignore
+++ b/.gitignore
@@ -182,6 +182,8 @@ a.out.dSYM/
/lib/jinterface/priv/OtpErlang.jar
/lib/jinterface/priv/com/
/lib/jinterface/doc/html/java
+/lib/jinterface/pom.xml
+/lib/jinterface/target
# kernel
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index 90d3a0304a..2d250f32cf 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -1509,14 +1509,14 @@ Eterm erts_uint64_to_big(Uint64 x, Eterm **hpp)
*hp = make_pos_bignum_header(2);
BIG_DIGIT(hp, 0) = (Uint) (x & ((Uint) 0xffffffff));
BIG_DIGIT(hp, 1) = (Uint) ((x >> 32) & ((Uint) 0xffffffff));
- *hpp += 2;
+ *hpp += 3;
}
else
#endif
{
*hp = make_pos_bignum_header(1);
BIG_DIGIT(hp, 0) = (Uint) x;
- *hpp += 1;
+ *hpp += 2;
}
return make_big(hp);
}
@@ -1539,7 +1539,7 @@ Eterm erts_sint64_to_big(Sint64 x, Eterm **hpp)
*hp = make_pos_bignum_header(2);
BIG_DIGIT(hp, 0) = (Uint) (x & ((Uint) 0xffffffff));
BIG_DIGIT(hp, 1) = (Uint) ((x >> 32) & ((Uint) 0xffffffff));
- *hpp += 2;
+ *hpp += 3;
}
else
#endif
@@ -1549,7 +1549,7 @@ Eterm erts_sint64_to_big(Sint64 x, Eterm **hpp)
else
*hp = make_pos_bignum_header(1);
BIG_DIGIT(hp, 0) = (Uint) x;
- *hpp += 1;
+ *hpp += 2;
}
return make_big(hp);
}
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index f41b61d73d..466165f26f 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -65,11 +65,9 @@
# endif
#endif
-/*
- * For backward compatibility reasons, only encode integers that
- * fit in 28 bits (signed) using INTEGER_EXT.
+/* Does Sint fit in Sint32?
*/
-#define IS_SSMALL28(x) (((Uint) (((x) >> (28-1)) + 1)) < 2)
+#define IS_SSMALL32(x) (((Uint) (((x) >> (32-1)) + 1)) < 2)
/*
* Valid creations for nodes are 1, 2, or 3. 0 can also be sent
@@ -1571,13 +1569,15 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags)
case SMALL_DEF:
{
+ /* From R14B we no longer restrict INTEGER_EXT to 28 bits,
+ * as done earlier for backward compatibility reasons. */
Sint val = signed_val(obj);
if ((Uint)val < 256) {
*ep++ = SMALL_INTEGER_EXT;
put_int8(val, ep);
ep++;
- } else if (sizeof(Sint) == 4 || IS_SSMALL28(val)) {
+ } else if (sizeof(Sint) == 4 || IS_SSMALL32(val)) {
*ep++ = INTEGER_EXT;
put_int32(val, ep);
ep += 4;
@@ -1599,18 +1599,32 @@ enc_term(ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags)
break;
case BIG_DEF:
- if ((n = big_bytes(obj)) < 256) {
- *ep++ = SMALL_BIG_EXT;
- put_int8(n, ep);
- ep += 1;
- }
- else {
- *ep++ = LARGE_BIG_EXT;
- put_int32(n, ep);
- ep += 4;
+ {
+ int sign = big_sign(obj);
+ n = big_bytes(obj);
+ if (sizeof(Sint)==4 && n<=4) {
+ Uint dig = big_digit(obj,0);
+ Sint val = sign ? -dig : dig;
+ if ((val<0) == sign) {
+ *ep++ = INTEGER_EXT;
+ put_int32(val, ep);
+ ep += 4;
+ break;
+ }
+ }
+ if (n < 256) {
+ *ep++ = SMALL_BIG_EXT;
+ put_int8(n, ep);
+ ep += 1;
+ }
+ else {
+ *ep++ = LARGE_BIG_EXT;
+ put_int32(n, ep);
+ ep += 4;
+ }
+ *ep++ = sign;
+ ep = big_to_bytes(obj, ep);
}
- *ep++ = big_sign(obj);
- ep = big_to_bytes(obj, ep);
break;
case PID_DEF:
@@ -2687,7 +2701,7 @@ encode_size_struct2(ErtsAtomCacheMap *acmp, Eterm obj, unsigned dflags)
if ((Uint)val < 256)
result += 1 + 1; /* SMALL_INTEGER_EXT */
- else if (sizeof(Sint) == 4 || IS_SSMALL28(val))
+ else if (sizeof(Sint) == 4 || IS_SSMALL32(val))
result += 1 + 4; /* INTEGER_EXT */
else {
DeclareTmpHeapNoproc(tmp_big,2);
@@ -2699,7 +2713,10 @@ encode_size_struct2(ErtsAtomCacheMap *acmp, Eterm obj, unsigned dflags)
}
break;
case BIG_DEF:
- if ((i = big_bytes(obj)) < 256)
+ i = big_bytes(obj);
+ if (sizeof(Sint)==4 && i <= 4 && (big_digit(obj,0)-big_sign(obj)) < (1<<31))
+ result += 1 + 4; /* INTEGER_EXT */
+ else if (i < 256)
result += 1 + 1 + 1 + i; /* tag,size,sign,digits */
else
result += 1 + 4 + 1 + i; /* tag,size,sign,digits */
diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c
index 8c8029d450..5bcd567b5f 100644
--- a/erts/emulator/beam/packet_parser.c
+++ b/erts/emulator/beam/packet_parser.c
@@ -679,7 +679,7 @@ int packet_parse_http(const char* buf, int len, int* statep,
while (n && SP(ptr)) {
ptr++; n--;
}
- if (ptr==p0) return -1;
+ if (ptr==p0 && n>0) return -1;
/* NOTE: the syntax allows empty reason phrases */
(*statep) = !0;
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index da6f9ed12f..b8d407f5e5 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -409,7 +409,7 @@ erts_bld_uint64(Uint **hpp, Uint *szp, Uint64 ui64)
}
else {
if (szp)
- *szp = ERTS_UINT64_HEAP_SIZE(ui64);
+ *szp += ERTS_UINT64_HEAP_SIZE(ui64);
if (hpp)
res = erts_uint64_to_big(ui64, hpp);
}
@@ -426,7 +426,7 @@ erts_bld_sint64(Uint **hpp, Uint *szp, Sint64 si64)
}
else {
if (szp)
- *szp = ERTS_SINT64_HEAP_SIZE(si64);
+ *szp += ERTS_SINT64_HEAP_SIZE(si64);
if (hpp)
res = erts_sint64_to_big(si64, hpp);
}
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 87691fc1bc..0ea54930ba 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -9333,11 +9333,13 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
if (err != ERRNO_BLOCK) {
if (!desc->active) {
#ifdef HAVE_SCTP
- if (short_recv)
+ if (short_recv) {
async_error_am(desc, am_short_recv);
- else
-#else
+ } else {
async_error(desc, err);
+ }
+#else
+ async_error(desc, err);
#endif
driver_cancel_timer(desc->port);
sock_select(desc,FD_READ,0);
diff --git a/erts/emulator/test/decode_packet_SUITE.erl b/erts/emulator/test/decode_packet_SUITE.erl
index 6cde286871..d9e961be2f 100644
--- a/erts/emulator/test/decode_packet_SUITE.erl
+++ b/erts/emulator/test/decode_packet_SUITE.erl
@@ -304,6 +304,10 @@ http(Config) when is_list(Config) ->
{ok, {http_request, 'GET', ResB, {1,1}}, Rest} = decode_pkt(http_bin,Bin)
end,
lists:foreach(UriF, http_uri_variants()),
+
+ %% Response with empty phrase
+ ?line {ok,{http_response,{1,1},200,[]},<<>>} = decode_pkt(http, <<"HTTP/1.1 200\r\n">>, []),
+ ?line {ok,{http_response,{1,1},200,<<>>},<<>>} = decode_pkt(http_bin, <<"HTTP/1.1 200\r\n">>, []),
ok.
http_with_bin(http) ->
diff --git a/erts/emulator/test/hash_SUITE.erl b/erts/emulator/test/hash_SUITE.erl
index 85bdb8bff8..f5d1871bfb 100644
--- a/erts/emulator/test/hash_SUITE.erl
+++ b/erts/emulator/test/hash_SUITE.erl
@@ -480,14 +480,14 @@ otp_5292_test() ->
S2 = md5([md5(hash_int(S, E, PH)) || {Start, N, Sz} <- d(),
{S, E} <- int(Start, N, Sz)]),
?line Comment = case S1 of
- <<43,186,76,102,87,4,110,245,203,177,206,6,130,69,43,99>> ->
+ <<4,248,208,156,200,131,7,1,173,13,239,173,112,81,16,174>> ->
?line big = erlang:system_info(endian),
"Big endian machine";
- <<21,206,139,15,149,28,167,81,98,225,132,254,49,125,174,195>> ->
+ <<180,28,33,231,239,184,71,125,76,47,227,241,78,184,176,233>> ->
?line little = erlang:system_info(endian),
"Little endian machine"
end,
- ?line <<140,37,79,80,26,242,130,22,20,229,123,240,223,244,43,99>> = S2,
+ ?line <<124,81,198,121,174,233,19,137,10,83,33,80,226,111,238,99>> = S2,
?line 2 = erlang:hash(1, (1 bsl 27) -1),
?line {'EXIT', _} = (catch erlang:hash(1, (1 bsl 27))),
{comment, Comment}.
@@ -507,7 +507,7 @@ hash_int(Start, End, F) ->
{Start, End, md5(HL)}.
md5(T) ->
- erlang:md5(term_to_binary(T)).
+ erlang:md5(term_to_binary(T)).
bit_level_binaries() ->
?line [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 888bf582d8..f45cfa3e4a 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -30,7 +30,7 @@
fin_per_testcase/2, basic/1, reload/1, upgrade/1, heap_frag/1,
types/1, many_args/1, binaries/1, get_string/1, get_atom/1, api_macros/1,
from_array/1, iolist_as_binary/1, resource/1, resource_binary/1, resource_takeover/1,
- threading/1, send/1, send2/1, send_threaded/1, neg/1, is_checks/1,
+ threading/1, send/1, send2/1, send3/1, send_threaded/1, neg/1, is_checks/1,
get_length/1, make_atom/1, make_string/1]).
-export([many_args_100/100]).
@@ -51,7 +51,7 @@
all(suite) ->
[basic, reload, upgrade, heap_frag, types, many_args, binaries, get_string,
get_atom, api_macros, from_array, iolist_as_binary, resource, resource_binary,
- resource_takeover, threading, send, send2, send_threaded, neg, is_checks,
+ resource_takeover, threading, send, send2, send3, send_threaded, neg, is_checks,
get_length, make_atom, make_string].
%%init_per_testcase(_Case, Config) ->
@@ -916,7 +916,164 @@ forwarder(To, N) ->
other_term() ->
{fun(X,Y) -> X*Y end, make_ref()}.
-
+
+send3(doc) -> ["Message sending stress test"];
+send3(Config) when is_list(Config) ->
+ %% Let a number of processes send random message blobs between each other
+ %% using enif_send. Kill and spawn new ones randomly to keep a ~constant
+ %% number of workers running.
+ Seed = now(),
+ io:format("seed: ~p\n",[Seed]),
+ random:seed(Seed),
+ ets:new(nif_SUITE,[named_table,public]),
+ ?line true = ets:insert(nif_SUITE,{send3,0,0,0,0}),
+ timer:send_after(10000, timeout), % Run for 10 seconds
+ SpawnCnt = send3_controller(0, [], [], 20),
+ ?line [{_,Rcv,SndOk,SndFail,Balance}] = ets:lookup(nif_SUITE,send3),
+ io:format("spawns=~p received=~p, sent=~p send-failure=~p balance=~p\n",
+ [SpawnCnt,Rcv,SndOk,SndFail,Balance]),
+ ets:delete(nif_SUITE).
+
+send3_controller(SpawnCnt, [], _, infinity) ->
+ SpawnCnt;
+send3_controller(SpawnCnt0, Mons0, Pids0, Tick) ->
+ receive
+ timeout ->
+ io:format("Timeout. Sending 'halt' to ~p\n",[Pids0]),
+ lists:foreach(fun(P) -> P ! {halt,self()} end, Pids0),
+ lists:foreach(fun(P) -> receive {halted,P} -> ok end end, Pids0),
+ QTot = lists:foldl(fun(P,QSum) ->
+ {message_queue_len,QLen} =
+ erlang:process_info(P,message_queue_len),
+ QSum + QLen
+ end, 0, Pids0),
+ io:format("Total queue length ~p\n",[QTot]),
+ lists:foreach(fun(P) -> P ! die end, Pids0),
+ send3_controller(SpawnCnt0, Mons0, [], infinity);
+ {'DOWN', MonRef, process, _Pid, _} ->
+ Mons1 = lists:delete(MonRef, Mons0),
+ %%io:format("Got DOWN from ~p. Monitors left: ~p\n",[Pid,Mons1]),
+ send3_controller(SpawnCnt0, Mons1, Pids0, Tick)
+ after Tick ->
+ Max = 20,
+ N = length(Pids0),
+ PidN = random:uniform(Max),
+ %%io:format("N=~p PidN=~p Pids0=~p\n", [N,PidN,Pids0]),
+ case PidN > N of
+ true ->
+ {NewPid,Mon} = spawn_opt(fun send3_proc/0, [link,monitor]),
+ lists:foreach(fun(P) -> P ! {is_born,NewPid} end, Pids0),
+ ?line Balance = ets:lookup_element(nif_SUITE,send3,5),
+ Inject = (Balance =< 0),
+ case Inject of
+ true -> ok;
+ false -> ets:update_element(nif_SUITE,send3,{5,-1})
+ end,
+ NewPid ! {pids,Pids0,Inject},
+ send3_controller(SpawnCnt0+1, [Mon|Mons0], [NewPid|Pids0], Tick);
+ false ->
+ KillPid = lists:nth(PidN,Pids0),
+ KillPid ! die,
+ Pids1 = lists:delete(KillPid, Pids0),
+ lists:foreach(fun(P) -> P ! {is_dead,KillPid} end, Pids1),
+ send3_controller(SpawnCnt0, Mons0, Pids1, Tick)
+ end
+ end.
+
+send3_proc() ->
+ %%io:format("Process ~p spawned\n",[self()]),
+ send3_proc([self()], {0,0,0}, {1,2,3,4,5}).
+send3_proc(Pids0, Counters={Rcv,SndOk,SndFail}, State0) ->
+ %%io:format("~p: Pids0=~p", [self(), Pids0]),
+ %%timer:sleep(10),
+ receive
+ {pids, Pids1, Inject} ->
+ %%io:format("~p: got ~p Inject=~p\n", [self(), Pids1, Inject]),
+ ?line Pids0 = [self()],
+ Pids2 = [self() | Pids1],
+ case Inject of
+ true -> send3_proc_send(Pids2, Counters, State0);
+ false -> send3_proc(Pids2, Counters, State0)
+ end;
+ {is_born, Pid} ->
+ %%io:format("~p: is_born ~p, got ~p\n", [self(), Pid, Pids0]),
+ send3_proc([Pid | Pids0], Counters, State0);
+ {is_dead, Pid} ->
+ Pids1 = lists:delete(Pid,Pids0),
+ %%io:format("~p: is_dead ~p, got ~p\n", [self(), Pid, Pids1]),
+ send3_proc(Pids1, Counters, State0);
+ {blob, Blob0} ->
+ %%io:format("~p: blob ~p\n", [self(), Blob0]),
+ State1 = send3_new_state(State0, Blob0),
+ send3_proc_send(Pids0, {Rcv+1,SndOk,SndFail}, State1);
+ die ->
+ %%io:format("Process ~p terminating, stats = ~p\n",[self(),Counters]),
+ {message_queue_len,Dropped} = erlang:process_info(self(),message_queue_len),
+ _R = ets:update_counter(nif_SUITE,send3,
+ [{2,Rcv},{3,SndOk},{4,SndFail},{5,1-Dropped}]),
+ %%io:format("~p: dies R=~p\n", [self(), R]),
+ ok;
+ {halt,Papa} ->
+ Papa ! {halted,self()},
+ io:format("~p halted\n",[self()]),
+ receive die -> ok end,
+ io:format("~p dying\n",[self()])
+ end.
+
+send3_proc_send(Pids, {Rcv,SndOk,SndFail}, State0) ->
+ To = lists:nth(random:uniform(length(Pids)),Pids),
+ Blob = send3_make_blob(),
+ State1 = send3_new_state(State0,Blob),
+ case send3_send(To, Blob) of
+ true ->
+ send3_proc(Pids, {Rcv,SndOk+1,SndFail}, State1);
+ false ->
+ send3_proc(Pids, {Rcv,SndOk,SndFail+1}, State1)
+ end.
+
+
+send3_make_blob() ->
+ case random:uniform(20)-1 of
+ 0 -> {term,[]};
+ N ->
+ MsgEnv = alloc_msgenv(),
+ repeat(N bsr 1,
+ fun(_) -> grow_blob(MsgEnv,other_term(),random:uniform(1 bsl 20))
+ end, void),
+ case (N band 1) of
+ 0 -> {term,copy_blob(MsgEnv)};
+ 1 -> {msgenv,MsgEnv}
+ end
+ end.
+
+send3_send(Pid, Msg) ->
+ %% 90% enif_send and 10% normal bang
+ case random:uniform(10) of
+ 1 -> send3_send_bang(Pid,Msg);
+ _ -> send3_send_nif(Pid,Msg)
+ end.
+send3_send_nif(Pid, {term,Blob}) ->
+ %%io:format("~p send term nif\n",[self()]),
+ send_term(Pid, {blob, Blob}) =:= 1;
+send3_send_nif(Pid, {msgenv,MsgEnv}) ->
+ %%io:format("~p send blob nif\n",[self()]),
+ send3_blob(MsgEnv, Pid, blob) =:= 1.
+
+send3_send_bang(Pid, {term,Blob}) ->
+ %%io:format("~p send term bang\n",[self()]),
+ Pid ! {blob, Blob},
+ true;
+send3_send_bang(Pid, {msgenv,MsgEnv}) ->
+ %%io:format("~p send blob bang\n",[self()]),
+ Pid ! {blob, copy_blob(MsgEnv)},
+ true.
+
+send3_new_state(State, Blob) ->
+ case random:uniform(5+2) of
+ N when N =< 5-> setelement(N, State, Blob);
+ _ -> State % Don't store blob
+ end.
+
neg(doc) -> ["Negative testing of load_nif"];
neg(Config) when is_list(Config) ->
TmpMem = tmpmem(),
@@ -1070,10 +1227,13 @@ send_new_blob(_,_) -> ?nif_stub.
alloc_msgenv() -> ?nif_stub.
clear_msgenv(_) -> ?nif_stub.
grow_blob(_,_) -> ?nif_stub.
+grow_blob(_,_,_) -> ?nif_stub.
send_blob(_,_) -> ?nif_stub.
+send3_blob(_,_,_) -> ?nif_stub.
send_blob_thread(_,_,_) -> ?nif_stub.
join_send_thread(_) -> ?nif_stub.
-
+copy_blob(_) -> ?nif_stub.
+send_term(_,_) -> ?nif_stub.
nif_stub_error(Line) ->
exit({nif_not_loaded,module,?MODULE,line,Line}).
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index c8cd323b7e..17f644829f 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -1038,36 +1038,41 @@ static ERL_NIF_TERM make_term_copy(struct make_term_info* mti, int n)
{
return enif_make_copy(mti->dst_env, mti->other_term);
}
+
+typedef ERL_NIF_TERM Make_term_Func(struct make_term_info*, int);
+static Make_term_Func* make_funcs[] = {
+ make_term_binary,
+ make_term_int,
+ make_term_ulong,
+ make_term_double,
+ make_term_atom,
+ make_term_existing_atom,
+ make_term_string,
+ //make_term_ref,
+ make_term_sub_binary,
+ make_term_uint,
+ make_term_long,
+ make_term_tuple0,
+ make_term_list0,
+ make_term_resource,
+ make_term_new_binary,
+ make_term_caller_pid,
+ make_term_tuple,
+ make_term_list,
+ make_term_list_cell,
+ make_term_tuple_from_array,
+ make_term_list_from_array,
+ make_term_garbage,
+ make_term_copy
+};
+static unsigned num_of_make_funcs()
+{
+ return sizeof(make_funcs)/sizeof(*make_funcs);
+}
static int make_term_n(struct make_term_info* mti, int n, ERL_NIF_TERM* res)
{
- typedef ERL_NIF_TERM Make_term_Func(struct make_term_info*, int);
- static Make_term_Func* funcs[] = {
- make_term_binary,
- make_term_int,
- make_term_ulong,
- make_term_double,
- make_term_atom,
- make_term_existing_atom,
- make_term_string,
- //make_term_ref,
- make_term_sub_binary,
- make_term_uint,
- make_term_long,
- make_term_tuple0,
- make_term_list0,
- make_term_resource,
- make_term_new_binary,
- make_term_caller_pid,
- make_term_tuple,
- make_term_list,
- make_term_list_cell,
- make_term_tuple_from_array,
- make_term_list_from_array,
- make_term_garbage,
- make_term_copy
- };
- if (n < sizeof(funcs)/sizeof(*funcs)) {
- *res = funcs[n](mti, n);
+ if (n < num_of_make_funcs()) {
+ *res = make_funcs[n](mti, n);
push_term(mti, *res);
return 1;
}
@@ -1167,14 +1172,14 @@ static ERL_NIF_TERM grow_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
{
union { void* vp; struct make_term_info* p; }mti;
ERL_NIF_TERM term;
- if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)) {
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)
+ || (argc>2 && !enif_get_uint(env,argv[2], &mti.p->n))) {
return enif_make_badarg(env);
}
mti.p->caller_env = env;
mti.p->other_term = argv[1];
- while (!make_term_n(mti.p, mti.p->n++, &term)) {
- mti.p->n = 0;
- }
+ mti.p->n %= num_of_make_funcs();
+ make_term_n(mti.p, mti.p->n++, &term);
mti.p->blob = enif_make_list_cell(mti.p->dst_env, term, mti.p->blob);
return atom_ok;
}
@@ -1194,6 +1199,23 @@ static ERL_NIF_TERM send_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
return enif_make_tuple3(env, atom_ok, enif_make_int(env,res), copy);
}
+static ERL_NIF_TERM send3_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union { void* vp; struct make_term_info* p; }mti;
+ ErlNifPid to;
+ ERL_NIF_TERM copy;
+ int res;
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)
+ || !enif_get_local_pid(env, argv[1], &to)) {
+ return enif_make_badarg(env);
+ }
+ mti.p->blob = enif_make_tuple2(mti.p->dst_env,
+ enif_make_copy(mti.p->dst_env, argv[2]),
+ mti.p->blob);
+ res = enif_send(env, &to, mti.p->dst_env, mti.p->blob);
+ return enif_make_int(env,res);
+}
+
void* threaded_sender(void *arg)
{
@@ -1253,6 +1275,28 @@ static ERL_NIF_TERM join_send_thread(ErlNifEnv* env, int argc, const ERL_NIF_TER
return enif_make_tuple2(env, atom_ok, enif_make_int(env, mti.p->send_res));
}
+static ERL_NIF_TERM copy_blob(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ union { void* vp; struct make_term_info* p; }mti;
+ if (!enif_get_resource(env, argv[0], msgenv_resource_type, &mti.vp)) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_copy(env, mti.p->blob);
+}
+
+static ERL_NIF_TERM send_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifEnv* menv;
+ ErlNifPid pid;
+ int ret;
+ if (!enif_get_local_pid(env, argv[0], &pid)) {
+ return enif_make_badarg(env);
+ }
+ menv = enif_alloc_env();
+ ret = enif_send(env, &pid, menv, enif_make_copy(menv, argv[1]));
+ enif_free_env(menv);
+ return enif_make_int(env, ret);
+}
static ErlNifFunc nif_funcs[] =
{
@@ -1291,9 +1335,13 @@ static ErlNifFunc nif_funcs[] =
{"alloc_msgenv", 0, alloc_msgenv},
{"clear_msgenv", 1, clear_msgenv},
{"grow_blob", 2, grow_blob},
+ {"grow_blob", 3, grow_blob},
{"send_blob", 2, send_blob},
+ {"send3_blob", 3, send3_blob},
{"send_blob_thread", 3, send_blob_thread},
- {"join_send_thread", 1, join_send_thread}
+ {"join_send_thread", 1, join_send_thread},
+ {"copy_blob", 1, copy_blob},
+ {"send_term", 2, send_term}
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
diff --git a/erts/emulator/test/send_term_SUITE.erl b/erts/emulator/test/send_term_SUITE.erl
index 489adbd660..5fd01a9ac5 100644
--- a/erts/emulator/test/send_term_SUITE.erl
+++ b/erts/emulator/test/send_term_SUITE.erl
@@ -76,40 +76,43 @@ basic(Config) when is_list(Config) ->
?line ExpectedBinTup = term(P, 7),
%% single terms
- ?line [] = term(P, 8), % ERL_DRV_NIL
- ?line '' = term(P, 9), % ERL_DRV_ATOM
- ?line an_atom = term(P, 10), % ERL_DRV_ATOM
- ?line -4711 = term(P, 11), % ERL_DRV_INT
- ?line 4711 = term(P, 12), % ERL_DRV_UINT
- ?line P = term(P, 13), % ERL_DRV_PORT
- ?line <<>> = term(P, 14), % ERL_DRV_BINARY
- ?line <<"hejsan">> = term(P, 15), % ERL_DRV_BINARY
- ?line <<>> = term(P, 16), % ERL_DRV_BUF2BINARY
- ?line <<>> = term(P, 17), % ERL_DRV_BUF2BINARY
- ?line <<"hoppsan">> = term(P, 18), % ERL_DRV_BUF2BINARY
- ?line "" = term(P, 19), % ERL_DRV_STRING
- ?line "" = term(P, 20), % ERL_DRV_STRING
- ?line "hippsan" = term(P, 21), % ERL_DRV_STRING
- ?line {} = term(P, 22), % ERL_DRV_TUPLE
- ?line [] = term(P, 23), % ERL_DRV_LIST
- ?line Self = term(P, 24), % ERL_DRV_PID
- ?line [] = term(P, 25), % ERL_DRV_STRING_CONS
- ?line AFloat = term(P, 26), % ERL_DRV_FLOAT
+ Singles = [{[], 8}, % ERL_DRV_NIL
+ {'', 9}, % ERL_DRV_ATOM
+ {an_atom, 10}, % ERL_DRV_ATOM
+ {-4711, 11}, % ERL_DRV_INT
+ {4711, 12}, % ERL_DRV_UINT
+ {P, 13}, % ERL_DRV_PORT
+ {<<>>, 14}, % ERL_DRV_BINARY
+ {<<"hejsan">>, 15}, % ERL_DRV_BINARY
+ {<<>>, 16}, % ERL_DRV_BUF2BINARY
+ {<<>>, 17}, % ERL_DRV_BUF2BINARY
+ {<<"hoppsan">>, 18}, % ERL_DRV_BUF2BINARY
+ {"", 19}, % ERL_DRV_STRING
+ {"", 20}, % ERL_DRV_STRING
+ {"hippsan", 21}, % ERL_DRV_STRING
+ {{}, 22}, % ERL_DRV_TUPLE
+ {[], 23}, % ERL_DRV_LIST
+ {Self, 24}, % ERL_DRV_PID
+ {[], 25}, % ERL_DRV_STRING_CONS
+ {[], 27}, % ERL_DRV_EXT2TERM
+ {18446744073709551615, 28}, % ERL_DRV_UINT64
+ {20233590931456, 29}, % ERL_DRV_UINT64
+ {4711, 30}, % ERL_DRV_UINT64
+ {0, 31}, % ERL_DRV_UINT64
+ {9223372036854775807, 32}, % ERL_DRV_INT64
+ {20233590931456, 33}, % ERL_DRV_INT64
+ {4711, 34}, % ERL_DRV_INT64
+ {0, 35}, % ERL_DRV_INT64
+ {-1, 36}, % ERL_DRV_INT64
+ {-4711, 37}, % ERL_DRV_INT64
+ {-20233590931456, 38}, % ERL_DRV_INT64
+ {-9223372036854775808, 39}], % ERL_DRV_INT64
+ ?line {Terms, Ops} = lists:unzip(Singles),
+ ?line Terms = term(P,Ops),
+
+ AFloat = term(P, 26), % ERL_DRV_FLOAT
?line true = AFloat < 0.001,
?line true = AFloat > -0.001,
- ?line [] = term(P, 27), % ERL_DRV_EXT2TERM
- ?line 18446744073709551615 = term(P, 28), % ERL_DRV_UINT64
- ?line 20233590931456 = term(P, 29), % ERL_DRV_UINT64
- ?line 4711 = term(P, 30), % ERL_DRV_UINT64
- ?line 0 = term(P, 31), % ERL_DRV_UINT64
- ?line 9223372036854775807 = term(P, 32), % ERL_DRV_INT64
- ?line 20233590931456 = term(P, 33), % ERL_DRV_INT64
- ?line 4711 = term(P, 34), % ERL_DRV_INT64
- ?line 0 = term(P, 35), % ERL_DRV_INT64
- ?line -1 = term(P, 36), % ERL_DRV_INT64
- ?line -4711 = term(P, 37), % ERL_DRV_INT64
- ?line -20233590931456 = term(P, 38), % ERL_DRV_INT64
- ?line -9223372036854775808 = term(P, 39), % ERL_DRV_INT64
%% Failure cases.
?line [] = term(P, 127),
diff --git a/erts/emulator/test/send_term_SUITE_data/send_term_drv.c b/erts/emulator/test/send_term_SUITE_data/send_term_drv.c
index 6638de0560..165cce2e9d 100644
--- a/erts/emulator/test/send_term_SUITE_data/send_term_drv.c
+++ b/erts/emulator/test/send_term_SUITE_data/send_term_drv.c
@@ -17,6 +17,7 @@
*/
#include "erl_driver.h"
+#include <stdio.h>
#include <errno.h>
#include <string.h>
@@ -65,12 +66,21 @@ static void fail_term(ErlDrvTermData* msg, int len, int line);
static void send_term_drv_run(ErlDrvData port, char *buf, int count)
{
- ErlDrvTermData msg[1024];
-
- switch (*buf) {
+ char buf7[1024];
+ ErlDrvTermData spec[1024];
+ ErlDrvTermData* msg = spec;
+ ErlDrvBinary* bins[15];
+ int bin_ix = 0;
+ ErlDrvSInt64 s64[15];
+ int s64_ix = 0;
+ ErlDrvUInt64 u64[15];
+ int u64_ix = 0;
+ int i = 0;
+
+ for (i=0; i<count; i++) switch (buf[i]) {
case 0:
msg[0] = ERL_DRV_NIL;
- output_term(msg, 1);
+ msg += 1;
break;
case 1: /* Most term types inside a tuple. */
@@ -102,7 +112,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[22] = driver_connected(erlang_port);
msg[23] = ERL_DRV_TUPLE;
msg[24] = (ErlDrvTermData) 7;
- output_term(msg, 25);
+ msg += 25;
}
break;
@@ -117,7 +127,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[i] = ERL_DRV_NIL;
msg[i+1] = ERL_DRV_LIST;
msg[i+2] = (ErlDrvTermData) 201;
- output_term(msg, i+3);
+ msg += i+3;
}
break;
@@ -126,7 +136,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
ErlDrvBinary* bin;
int i;
- bin = driver_alloc_binary(256);
+ bin = bins[bin_ix++] = driver_alloc_binary(256);
for (i = 0; i < 256; i++) {
bin->orig_bytes[i] = i;
}
@@ -140,8 +150,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[7] = (ErlDrvTermData) 23;
msg[8] = ERL_DRV_TUPLE;
msg[9] = (ErlDrvTermData) 2;
- output_term(msg, 10);
- driver_free_binary(bin);
+ msg += 10;
}
break;
@@ -152,11 +161,11 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[3] = driver_caller(erlang_port);
msg[4] = ERL_DRV_TUPLE;
msg[5] = (ErlDrvTermData) 2;
- output_term(msg, 6);
+ msg += 6;
break;
case 5:
- output_term(msg, make_ext_term_list(msg, 0));
+ msg += make_ext_term_list(msg, 0);
break;
case 6:
@@ -166,94 +175,91 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[3] = ~((ErlDrvTermData) 0);
msg[4] = ERL_DRV_TUPLE;
msg[5] = (ErlDrvTermData) 2;
- output_term(msg, 6);
+ msg += 6;
break;
case 7: {
int len = 0;
- char buf[1024];
- memset(buf, 17, sizeof(buf));
+ memset(buf7, 17, sizeof(buf7));
/* empty heap binary */
msg[len++] = ERL_DRV_BUF2BINARY;
msg[len++] = (ErlDrvTermData) NULL; /* NULL is ok if size == 0 */
msg[len++] = (ErlDrvTermData) 0;
/* empty heap binary again */
msg[len++] = ERL_DRV_BUF2BINARY;
- msg[len++] = (ErlDrvTermData) &buf[0]; /* ptr is ok if size == 0 */
+ msg[len++] = (ErlDrvTermData) buf7; /* ptr is ok if size == 0 */
msg[len++] = (ErlDrvTermData) 0;
/* heap binary */
msg[len++] = ERL_DRV_BUF2BINARY;
- msg[len++] = (ErlDrvTermData) &buf[0];
+ msg[len++] = (ErlDrvTermData) buf7;
msg[len++] = (ErlDrvTermData) 17;
/* off heap binary */
msg[len++] = ERL_DRV_BUF2BINARY;
- msg[len++] = (ErlDrvTermData) &buf[0];
- msg[len++] = (ErlDrvTermData) sizeof(buf);
+ msg[len++] = (ErlDrvTermData) buf7;
+ msg[len++] = (ErlDrvTermData) sizeof(buf7);
msg[len++] = ERL_DRV_TUPLE;
msg[len++] = (ErlDrvTermData) 4;
- output_term(msg, len);
+ msg += len;
break;
}
case 8:
msg[0] = ERL_DRV_NIL;
- output_term(msg, 1);
+ msg += 1;
break;
case 9:
msg[0] = ERL_DRV_ATOM;
msg[1] = (ErlDrvTermData) driver_mk_atom("");
- output_term(msg, 2);
+ msg += 2;
break;
case 10:
msg[0] = ERL_DRV_ATOM;
msg[1] = (ErlDrvTermData) driver_mk_atom("an_atom");
- output_term(msg, 2);
+ msg += 2;
break;
case 11:
msg[0] = ERL_DRV_INT;
msg[1] = (ErlDrvTermData) -4711;
- output_term(msg, 2);
+ msg += 2;
break;
case 12:
msg[0] = ERL_DRV_UINT;
msg[1] = (ErlDrvTermData) 4711;
- output_term(msg, 2);
+ msg += 2;
break;
case 13:
msg[0] = ERL_DRV_PORT;
msg[1] = driver_mk_port(erlang_port);
- output_term(msg, 2);
+ msg += 2;
break;
case 14: {
- ErlDrvBinary *dbin = driver_alloc_binary(0);
+ ErlDrvBinary *dbin = bins[bin_ix++] = driver_alloc_binary(0);
msg[0] = ERL_DRV_BINARY;
msg[1] = (ErlDrvTermData) dbin;
msg[2] = (ErlDrvTermData) 0;
msg[3] = (ErlDrvTermData) 0;
- output_term(msg, 4);
- driver_free_binary(dbin);
+ msg += 4;
break;
}
case 15: {
- char buf[] = "hejsan";
- ErlDrvBinary *dbin = driver_alloc_binary(sizeof(buf)-1);
+ static const char buf[] = "hejsan";
+ ErlDrvBinary *dbin = bins[bin_ix++] = driver_alloc_binary(sizeof(buf)-1);
if (dbin)
memcpy((void *) dbin->orig_bytes, (void *) buf, sizeof(buf)-1);
msg[0] = ERL_DRV_BINARY;
msg[1] = (ErlDrvTermData) dbin;
msg[2] = (ErlDrvTermData) (dbin ? sizeof(buf)-1 : 0);
msg[3] = (ErlDrvTermData) 0;
- output_term(msg, 4);
- driver_free_binary(dbin);
+ msg += 4;
break;
}
@@ -261,24 +267,24 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[0] = ERL_DRV_BUF2BINARY;
msg[1] = (ErlDrvTermData) NULL;
msg[2] = (ErlDrvTermData) 0;
- output_term(msg, 3);
+ msg += 3;
break;
case 17: {
- char buf[] = "";
+ static const char buf[] = "";
msg[0] = ERL_DRV_BUF2BINARY;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) sizeof(buf)-1;
- output_term(msg, 3);
+ msg += 3;
break;
}
case 18: {
- char buf[] = "hoppsan";
+ static const char buf[] = "hoppsan";
msg[0] = ERL_DRV_BUF2BINARY;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) sizeof(buf)-1;
- output_term(msg, 3);
+ msg += 3;
break;
}
@@ -286,44 +292,44 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[0] = ERL_DRV_STRING;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) 0;
- output_term(msg, 3);
+ msg += 3;
break;
case 20: {
- char buf[] = "";
+ static const char buf[] = "";
msg[0] = ERL_DRV_STRING;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) sizeof(buf)-1;
- output_term(msg, 3);
+ msg += 3;
break;
}
case 21: {
- char buf[] = "hippsan";
+ static const char buf[] = "hippsan";
msg[0] = ERL_DRV_STRING;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) sizeof(buf)-1;
- output_term(msg, 3);
+ msg += 3;
break;
}
case 22:
msg[0] = ERL_DRV_TUPLE;
msg[1] = (ErlDrvTermData) 0;
- output_term(msg, 2);
+ msg += 2;
break;
case 23:
msg[0] = ERL_DRV_NIL;
msg[1] = ERL_DRV_LIST;
msg[2] = (ErlDrvTermData) 1;
- output_term(msg, 3);
+ msg += 3;
break;
case 24:
msg[0] = ERL_DRV_PID;
msg[1] = driver_connected(erlang_port);
- output_term(msg, 2);
+ msg += 2;
break;
case 25:
@@ -331,132 +337,131 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
msg[1] = ERL_DRV_STRING_CONS;
msg[2] = (ErlDrvTermData) "";
msg[3] = (ErlDrvTermData) 0;
- output_term(msg, 4);
+ msg += 4;
break;
case 26: {
- double my_float = 0.0;
+ static double my_float = 0.0;
msg[0] = ERL_DRV_FLOAT;
msg[1] = (ErlDrvTermData) &my_float;
- output_term(msg, 2);
+ msg += 2;
break;
}
case 27: {
- char buf[] = {131, 106}; /* [] */
+ static char buf[] = {131, 106}; /* [] */
msg[0] = ERL_DRV_EXT2TERM;
msg[1] = (ErlDrvTermData) buf;
msg[2] = (ErlDrvTermData) sizeof(buf);
- output_term(msg, 3);
+ msg += 3;
break;
}
case 28: {
- ErlDrvUInt64 x = ~((ErlDrvUInt64) 0);
+ ErlDrvUInt64* x = &u64[u64_ix++];
+ *x = ~((ErlDrvUInt64) 0);
msg[0] = ERL_DRV_UINT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 29: {
- ErlDrvUInt64 x = ((ErlDrvUInt64) 4711) << 32;
+ ErlDrvUInt64* x = &u64[u64_ix++];
+ *x = ((ErlDrvUInt64) 4711) << 32;
msg[0] = ERL_DRV_UINT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 30: {
- ErlDrvUInt64 x = 4711;
+ ErlDrvUInt64* x = &u64[u64_ix++];
+ *x = 4711;
msg[0] = ERL_DRV_UINT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 31: {
- ErlDrvUInt64 x = 0;
+ ErlDrvUInt64* x = &u64[u64_ix++];
+ *x = 0;
msg[0] = ERL_DRV_UINT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 32: {
- ErlDrvSInt64 x = ((((ErlDrvUInt64) 0x7fffffff) << 32)
- | ((ErlDrvUInt64) 0xffffffff));
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = ((((ErlDrvUInt64) 0x7fffffff) << 32) | ((ErlDrvUInt64) 0xffffffff));
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 33: {
- ErlDrvSInt64 x = (ErlDrvSInt64) (((ErlDrvUInt64) 4711) << 32);
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = (ErlDrvSInt64) (((ErlDrvUInt64) 4711) << 32);
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 34: {
- ErlDrvSInt64 x = 4711;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = 4711;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 35: {
- ErlDrvSInt64 x = 0;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = 0;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 36: {
- ErlDrvSInt64 x = -1;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = -1;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 37: {
- ErlDrvSInt64 x = -4711;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = -4711;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 38: {
- ErlDrvSInt64 x = ((ErlDrvSInt64) ((ErlDrvUInt64) 4711) << 32)*-1;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = ((ErlDrvSInt64) ((ErlDrvUInt64) 4711) << 32)*-1;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
case 39: {
- ErlDrvSInt64 x = ((ErlDrvSInt64) 1) << 63;
+ ErlDrvSInt64* x = &s64[s64_ix++];
+ *x = ((ErlDrvSInt64) 1) << 63;
msg[0] = ERL_DRV_INT64;
- msg[1] = (ErlDrvTermData) &x;
- output_term(msg, 2);
-
+ msg[1] = (ErlDrvTermData) x;
+ msg += 2;
break;
}
@@ -464,7 +469,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
case 127: /* Error cases */
{
long refc;
- ErlDrvBinary* bin = driver_alloc_binary(256);
+ ErlDrvBinary* bin = bins[bin_ix++] = driver_alloc_binary(256);
FAIL_TERM(msg, 0);
@@ -537,7 +542,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
refc = driver_binary_get_refc(bin);
if (refc > 3) {
char sbuf[128];
- sprintf(sbuf, "bad_refc:%d", refc);
+ sprintf(sbuf, "bad_refc:%ld", refc);
driver_failure_atom(erlang_port, sbuf);
}
driver_free_binary(bin);
@@ -644,6 +649,7 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
/* Signal end of test case */
msg[0] = ERL_DRV_NIL;
driver_output_term(erlang_port, msg, 1);
+ return;
}
break;
@@ -651,6 +657,16 @@ static void send_term_drv_run(ErlDrvData port, char *buf, int count)
driver_failure_atom(erlang_port, "bad_request");
break;
}
+ if (count > 1) {
+ *msg++ = ERL_DRV_NIL;
+ *msg++ = ERL_DRV_LIST;
+ *msg++ = count + 1;
+ }
+ output_term(spec, msg-spec);
+ if ((bin_ix|s64_ix|u64_ix) > 15) abort();
+ while (bin_ix) {
+ driver_free_binary(bins[--bin_ix]);
+ }
}
static void output_term(ErlDrvTermData* msg, int len)
diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c
index c509c49b39..6ddf30efe3 100644
--- a/erts/epmd/src/epmd.c
+++ b/erts/epmd/src/epmd.c
@@ -226,6 +226,12 @@ int main(int argc, char** argv)
else
usage(g);
epmd_cleanup_exit(g,0);
+ } else if (strcmp(argv[0], "-stop") == 0) {
+ if (argc == 2)
+ stop_cli(g, argv[1]);
+ else
+ usage(g);
+ epmd_cleanup_exit(g,0);
}
else
usage(g);
@@ -382,7 +388,7 @@ static void run_daemon(EpmdVars *g)
static void usage(EpmdVars *g)
{
fprintf(stderr, "usage: epmd [-d|-debug] [DbgExtra...] [-port No] [-daemon]\n");
- fprintf(stderr, " [-d|-debug] [-port No] [-names|-kill]\n\n");
+ fprintf(stderr, " [-d|-debug] [-port No] [-names|-kill|-stop name]\n\n");
fprintf(stderr, "See the Erlang epmd manual page for info about the usage.\n");
fprintf(stderr, "The -port and DbgExtra options are\n\n");
fprintf(stderr, " -port No\n");
diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c
index c12f711bc5..2aed861390 100644
--- a/erts/epmd/src/epmd_cli.c
+++ b/erts/epmd/src/epmd_cli.c
@@ -54,6 +54,42 @@ void kill_epmd(EpmdVars *g)
}
}
+void stop_cli(EpmdVars *g, char *name)
+{
+ char buf[1024];
+ int fd, rval, bsize;
+
+ bsize = strlen(name);
+ if (bsize > 1000) {
+ printf("epmd: Name too long!");
+ epmd_cleanup_exit(g, 1);
+ }
+
+ fd = conn_to_epmd(g);
+ bsize++;
+ put_int16(bsize, buf);
+ buf[2] = EPMD_STOP_REQ;
+ bsize += 2;
+ strcpy(buf+3, name);
+
+ if (write(fd, buf, bsize) != bsize) {
+ printf("epmd: Can't write to epmd\n");
+ epmd_cleanup_exit(g,1);
+ }
+ if ((rval = read_fill(fd,buf,7)) == 7) {
+ buf[7] = '\000';
+ printf("%s\n", buf);
+ epmd_cleanup_exit(g,0);
+ } else if (rval < 0) {
+ printf("epmd: failed to read answer from local epmd\n");
+ epmd_cleanup_exit(g,1);
+ } else { /* rval is now 0 or 1 */
+ buf[rval] = '\0';
+ printf("epmd: local epmd responded with <%s>\n", buf);
+ epmd_cleanup_exit(g,1);
+ }
+}
+
/* what == EPMD_NAMES_REQ || EPMD_DUMP_REQ */
void epmd_call(EpmdVars *g,int what)
diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
index 34f657fb16..c836bf0bb7 100644
--- a/erts/epmd/src/epmd_srv.c
+++ b/erts/epmd/src/epmd_srv.c
@@ -591,7 +591,7 @@ static void do_request(g, fd, s, buf, bsize)
if (bsize <= 1)
{
- dbg_printf(g,0,"packet to small for request PORT2_REQ (%d)", bsize);
+ dbg_printf(g,0,"packet too small for request PORT2_REQ (%d)", bsize);
return;
}
@@ -740,7 +740,7 @@ static void do_request(g, fd, s, buf, bsize)
dbg_printf(g,1,"** got STOP_REQ");
if (bsize <= 1 )
{
- dbg_printf(g,0,"packet to small for request STOP_REQ (%d)",bsize);
+ dbg_printf(g,0,"packet too small for request STOP_REQ (%d)",bsize);
return;
}
@@ -902,7 +902,7 @@ static void node_init(EpmdVars *g)
/* We have got a close on a connection and it may be a
- EPMD_ALIVE_CLOSE_REQ. Note that this call shouild be called
+ EPMD_ALIVE_CLOSE_REQ. Note that this call should be called
*before* calling conn_close() */
static int node_unreg(EpmdVars *g,char *name)
diff --git a/lib/common_test/Makefile b/lib/common_test/Makefile
index e16efd0c9d..aecec1a50d 100644
--- a/lib/common_test/Makefile
+++ b/lib/common_test/Makefile
@@ -25,12 +25,12 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
#
ifeq ($(findstring linux,$(TARGET)),linux)
-SUB_DIRECTORIES = doc/src src
+SUB_DIRECTORIES = doc/src src priv
else
ifeq ($(findstring solaris,$(TARGET)),solaris)
-SUB_DIRECTORIES = doc/src src
+SUB_DIRECTORIES = doc/src src priv
else
-SUB_DIRECTORIES = doc/src src
+SUB_DIRECTORIES = doc/src src priv
endif
endif
diff --git a/lib/common_test/doc/src/run_test.xml b/lib/common_test/doc/src/run_test.xml
index d609c4287f..2f0a94afba 100644
--- a/lib/common_test/doc/src/run_test.xml
+++ b/lib/common_test/doc/src/run_test.xml
@@ -45,6 +45,11 @@
flags start an Erlang node prepared for running Common Test in a
particular mode.</p>
+ <p>There is an interface function that corresponds to this program,
+ called <c>ct:run_test/1</c>, for starting Common Test from the Erlang
+ shell (or an Erlang program). Please see the <c>ct</c> man page for
+ details.</p>
+
<p><c>run_test</c> also accepts Erlang emulator flags. These are used
when <c>run_test</c> calls <c>erl</c> to start the Erlang node
(making it possible to e.g. add directories to the code server path,
@@ -72,6 +77,8 @@
<p>it prints all valid start flags to stdout.</p>
</description>
+ <marker id="run_test"></marker>
+
<section>
<title>Run tests from command line</title>
<pre>
@@ -83,6 +90,7 @@
[-userconfig CallbackModule1 ConfigString1 and CallbackModule2
ConfigString2 and .. and CallbackModuleN ConfigStringN]
[-decrypt_key Key] | [-decrypt_file KeyFile]
+ [-label Label]
[-logdir LogDir]
[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]
[-stylesheet CSSFile]
@@ -107,6 +115,7 @@
[-userconfig CallbackModule1 ConfigString1 and CallbackModule2
ConfigString2 and .. and CallbackModuleN ConfigStringN]
[-decrypt_key Key] | [-decrypt_file KeyFile]
+ [-label Label]
[-logdir LogDir]
[-allow_user_terms]
[-silent_connections [ConnType1 ConnType2 .. ConnTypeN]]
@@ -128,12 +137,12 @@
<title>Run tests in web based GUI</title>
<pre>
run_test -vts [-browser Browser]
+ [-dir TestDir1 TestDir2 .. TestDirN] |
+ [-suite Suite [[-group Group] [-case Case]]]
[-config ConfigFile1 ConfigFile2 .. ConfigFileN]
[-userconfig CallbackModule1 ConfigString1 and CallbackModule2
ConfigString2 and .. and CallbackModuleN ConfigStringN]
[-decrypt_key Key] | [-decrypt_file KeyFile]
- [-dir TestDir1 TestDir2 .. TestDirN] |
- [-suite Suite [[-group Group] [-case Case]]]
[-include InclDir1 InclDir2 .. InclDirN]
[-no_auto_compile]
[-muliply_timetraps Multiplier]
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index 207df7f5b5..1efff25f5b 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -21,7 +21,7 @@
</legalnotice>
- <title>Running Test Suites</title>
+ <title>Running Tests</title>
<prepared>Peter Andersson, Kenneth Lundin</prepared>
<docno></docno>
<date></date>
@@ -130,6 +130,8 @@
<p>Other flags that may be used with <c>run_test</c>:</p>
<list>
<item><c><![CDATA[-logdir <dir>]]></c>, specifies where the HTML log files are to be written.</item>
+ <item><c><![CDATA[-label <name_of_test_run>]]></c>, associates the test run with a name that gets printed
+ in the overview HTML log files.</item>
<item><c>-refresh_logs</c>, refreshes the top level HTML index files.</item>
<item><c>-vts</c>, start web based GUI (see below).</item>
<item><c>-shell</c>, start interactive shell mode (see below).</item>
@@ -335,43 +337,72 @@
<marker id="test_specifications"></marker>
<title>Using test specifications</title>
- <p>The most expressive way to specify what to test is to use a so
- called test specification. A test specification is a sequence of
- Erlang terms. The terms may be declared in a text file or passed
- to the test server at runtime as a list (see <c>run_testspec/1</c>
- in the manual page for <c>ct</c>). There are two general types
- of terms: configuration terms and test specification terms.</p>
- <p>With configuration terms it is possible to import configuration
- data (similar to <c>run_test -config</c>), specify HTML log
- directories (similar to <c>run_test -logdir</c>), give aliases
- to test nodes and test directories (to make a specification
- easier to read and maintain), enable code coverage analysis
- (see the <seealso marker="cover_chapter#cover">Code Coverage
- Analysis</seealso> chapter) and specify event_handler plugins
+ <p>The most flexible way to specify what to test, is to use a so
+ called test specification. A test specification is a sequence of
+ Erlang terms. The terms may be declared in a text file or passed
+ to the test server at runtime as a list
+ (see <c>run_testspec/1</c> in the manual page
+ for <c>ct</c>). There are two general types of terms:
+ configuration terms and test specification terms.</p>
+ <p>With configuration terms it is possible to e.g. label the test
+ run (similar to <c>run_test -label</c>), evaluate arbitrary expressions
+ before starting a test, import configuration
+ data (similar to
+ <c>run_test -config/-userconfig</c>), specify HTML log directories (similar
+ to
+ <c>run_test -logdir</c>), give aliases to test nodes and test
+ directories (to make a specification easier to read and
+ maintain), enable code coverage analysis (see
+ the <seealso marker="cover_chapter#cover">Code Coverage
+ Analysis</seealso> chapter) and specify event_handler plugins
(see the <seealso marker="event_handler_chapter#event_handling">
- Event Handling</seealso> chapter). There is also a term
- for specifying include directories that should be passed on
- to the compiler when automatic compilation is performed
- (similar to <c>run_test -include</c>, see above).</p>
- <p>With test specification terms it is possible to state exactly which
- tests should run and in which order. A test term specifies either
- one or more suites or one or more test cases. An arbitrary number of test
- terms may be declared in sequence. A test term can also specify one or
- more test suites or test cases to be skipped. Skipped suites and cases
- are not executed and show up in the HTML test log as SKIPPED.</p>
-
- <note><p>It is not yet possible to specify test case groups in
- test specifications. This will be supported in a soon upcoming
- release.</p></note>
+ Event Handling</seealso> chapter). There is also a term for
+ specifying include directories that should be passed on to the
+ compiler when automatic compilation is performed (similar
+ to <c>run_test -include</c>, see above).</p>
+ <p>With test specification terms it is possible to state exactly
+ which tests should run and in which order. A test term specifies
+ either one or more suites, one or more test case groups, or one
+ or more test cases in a group or suite.</p>
+ <p>An arbitrary number of test terms may be declared in sequence.
+ Common Test will compile the terms into one or more tests to be
+ performed in one resulting test run. Note that a term that
+ specifies a set of test cases will "swallow" one that only
+ specifies a subset of these cases. E.g. the result of merging
+ one term that specifies that all cases in suite S should be
+ executed, with another term specifying only test case X and Y in
+ S, is a test of all cases in S. However, if a term specifying
+ test case X and Y in S is merged with a term specifying case Z
+ in S, the result is a test of X, Y and Z in S.</p>
+ <p>A test term can also specify one or more test suites, groups,
+ or test cases to be skipped. Skipped suites, groups and cases
+ are not executed and show up in the HTML test log files as
+ SKIPPED.</p>
+ <p>When a test case group is specified, the resulting test
+ executes the
+ <c>init_per_group</c> function, followed by all test cases and
+ sub groups (including their configuration functions), and
+ finally the <c>end_per_group</c> function. Also if particular
+ test cases in a group are specified, <c>init_per_group</c>
+ and <c>end_per_group</c> for the group in question are
+ called. If a group which is defined (in <c>Suite:group/0</c>) to
+ be a sub group of another group, is specified (or particular test
+ cases of a sub group are), Common Test will call the configuration
+ functions for the top level groups as well as for the sub group
+ in question (making it possible to pass configuration data all
+ the way from <c>init_per_suite</c> down to the test cases in the
+ sub group).</p>
<p>Below is the test specification syntax. Test specifications can
- be used to run tests both in a single test host environment and in
- a distributed Common Test environment (Large Scale Testing). The init term,
- as well as node parameters, are only relevant in the latter (see the
- <seealso marker="ct_master_chapter#test_specifications">Large Scale Testing</seealso>
- chapter for information). For details on the event_handler term, see the
- <seealso marker="event_handler_chapter#event_handling">Event Handling</seealso>
- chapter.</p>
+ be used to run tests both in a single test host environment and
+ in a distributed Common Test environment (Large Scale
+ Testing). The node parameters in the init term are only
+ relevant in the latter (see the
+ <seealso marker="ct_master_chapter#test_specifications">Large
+ Scale Testing</seealso> chapter for information). For details on
+ the event_handler term, see the
+ <seealso marker="event_handler_chapter#event_handling">Event
+ Handling</seealso> chapter.</p>
<p>Config terms:</p>
<pre>
{node, NodeAlias, Node}.
@@ -379,11 +410,17 @@
{init, InitOptions}.
{init, [NodeAlias], InitOptions}.
+ {label, Label}.
+ {label, NodeRefs, Label}.
+
{multiply_timetraps, N}.
+ {multiply_timetraps, NodeRefs, N}.
+
{scale_timetraps, Bool}.
+ {scale_timetraps, NodeRefs, Bool}.
{cover, CoverSpecFile}.
- {cover, NodeRef, CoverSpecFile}.
+ {cover, NodeRefs, CoverSpecFile}.
{include, IncludeDirs}.
{include, NodeRefs, IncludeDirs}.
@@ -409,6 +446,12 @@
{suites, DirRef, Suites}.
{suites, NodeRefs, DirRef, Suites}.
+ {groups, DirRef, Suite, Groups}.
+ {groups, NodeRefsDirRef, Suite, Groups}.
+
+ {groups, DirRef, Suite, Group, {cases,Cases}}.
+ {groups, NodeRefsDirRef, Suite, Group, {cases,Cases}}.
+
{cases, DirRef, Suite, Cases}.
{cases, NodeRefs, DirRef, Suite, Cases}.
@@ -437,6 +480,9 @@
InitArgs = [term()]
DirRef = DirAlias | Dir
Suites = atom() | [atom()] | all
+ Suite = atom()
+ Groups = atom() | [atom()] | all
+ Group = atom()
Cases = atom() | [atom()] | all
Comment = string() | ""
</pre>
diff --git a/lib/common_test/priv/Makefile.in b/lib/common_test/priv/Makefile.in
index f144847a29..6372bbc8d5 100644
--- a/lib/common_test/priv/Makefile.in
+++ b/lib/common_test/priv/Makefile.in
@@ -56,8 +56,9 @@ ifneq ($(findstring win32,$(TARGET)),win32)
#
# Files
#
-FILES = vts.tool run_test.in
-SCRIPTS = install.sh
+FILES =
+SCRIPTS =
+IMAGES = tile1.jpg
#
# Rules
@@ -83,14 +84,12 @@ include $(ERL_TOP)/make/otp_release_targets.mk
ifeq ($(XNIX),true)
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_SCRIPT) $(SCRIPTS) $(RELSYSDIR)
- $(INSTALL_DATA) $(FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) $(RELSYSDIR)/priv
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv
else
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_SCRIPT) $(SCRIPTS) $(RELSYSDIR)
- $(INSTALL_DATA) $(FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) $(RELSYSDIR)/priv
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv
endif
release_docs_spec:
@@ -105,6 +104,7 @@ else
# Files
#
FILES = vts.tool
+IMAGES = tile1.jpg
#
# Rules
@@ -123,8 +123,8 @@ clean:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_DATA) $(FILES) $(RELSYSDIR)/priv
+ $(INSTALL_DIR) $(RELSYSDIR)/priv
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv
release_docs_spec:
diff --git a/lib/common_test/priv/tile1.jpg b/lib/common_test/priv/tile1.jpg
new file mode 100644
index 0000000000..8749383716
--- /dev/null
+++ b/lib/common_test/priv/tile1.jpg
Binary files differ
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 0d82a86e7d..8ae175f10d 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -138,10 +138,10 @@ run(TestDirs) ->
%%%-----------------------------------------------------------------
%%% @spec run_test(Opts) -> Result
%%% Opts = [OptTuples]
-%%% OptTuples = {config,CfgFiles} | {dir,TestDirs} | {suite,Suites} |
-%%% {userconfig, UserConfig} |
-%%% {testcase,Cases} | {group,Groups} | {spec,TestSpecs} |
-%%% {allow_user_terms,Bool} | {logdir,LogDir} |
+%%% OptTuples = {dir,TestDirs} | {suite,Suites} | {group,Groups} |
+%%% {testcase,Cases} | {spec,TestSpecs} | {label,Label} |
+%%% {config,CfgFiles} | {userconfig, UserConfig} |
+%%% {allow_user_terms,Bool} | {logdir,LogDir} |
%%% {silent_connections,Conns} | {stylesheet,CSSFile} |
%%% {cover,CoverSpecFile} | {step,StepOpts} |
%%% {event_handler,EventHandlers} | {include,InclDirs} |
@@ -149,15 +149,16 @@ run(TestDirs) ->
%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
%%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} |
%%% {refresh_logs,LogDir} | {basic_html,Bool}
-%%% CfgFiles = [string()] | string()
-%%% UserConfig = [{CallbackMod,CfgStrings}] | {CallbackMod,CfgStrings}
-%%% CallbackMod = atom()
-%%% CfgStrings = [string()] | string()
%%% TestDirs = [string()] | string()
%%% Suites = [string()] | string()
%%% Cases = [atom()] | atom()
%%% Groups = [atom()] | atom()
%%% TestSpecs = [string()] | string()
+%%% Label = string() | atom()
+%%% CfgFiles = [string()] | string()
+%%% UserConfig = [{CallbackMod,CfgStrings}] | {CallbackMod,CfgStrings}
+%%% CallbackMod = atom()
+%%% CfgStrings = [string()] | string()
%%% LogDir = string()
%%% Conns = all | [atom()]
%%% CSSFile = string()
@@ -177,7 +178,8 @@ run(TestDirs) ->
%%% DecryptFile = string()
%%% Result = [TestResult] | {error,Reason}
%%% @doc Run tests as specified by the combination of options in <code>Opts</code>.
-%%% The options are the same as those used with the <code>run_test</code> program.
+%%% The options are the same as those used with the
+%%% <seealso marker="run_test#run_test"><code>run_test</code></seealso> program.
%%% Note that here a <code>TestDir</code> can be used to point out the path to
%%% a <code>Suite</code>. Note also that the option <code>testcase</code>
%%% corresponds to the <code>-case</code> option in the <code>run_test</code>
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 3dd1026f13..f2ca023cff 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -27,8 +27,12 @@
-export([init_tc/3, end_tc/3, get_suite/2, report/2, warn/1]).
-export([error_notification/4]).
+-export([overview_html_header/1]).
+
-export([error_in_suite/1, ct_init_per_group/2, ct_end_per_group/2]).
+-export([make_all_conf/3, make_conf/5]).
+
-include("ct_event.hrl").
-include("ct_util.hrl").
@@ -101,7 +105,8 @@ init_tc1(Mod,Func,[Config0],DoInit) when is_list(Config0) ->
[{saved_config,{LastFunc,SavedConfig}} |
lists:keydelete(saved_config,1,Config0)];
{{LastSuite,InitOrEnd},SavedConfig} when InitOrEnd == init_per_suite ;
- InitOrEnd == end_per_suite -> % last suite
+ InitOrEnd == end_per_suite ->
+ %% last suite
[{saved_config,{LastSuite,SavedConfig}} |
lists:keydelete(saved_config,1,Config0)];
undefined ->
@@ -649,7 +654,7 @@ get_suite(Mod, all) ->
{'EXIT',_} ->
get_all(Mod, []);
GroupDefs when is_list(GroupDefs) ->
- case catch check_groups(Mod, GroupDefs) of
+ case catch find_groups(Mod, all, all, GroupDefs) of
{error,_} = Error ->
%% this makes test_server call error_in_suite as first
%% (and only) test case so we can report Error properly
@@ -664,102 +669,193 @@ get_suite(Mod, all) ->
%%!============================================================
%%! Note: The handling of sequences in get_suite/2 and get_all/2
-%%! is deprecated and should be removed after OTP R13!
+%%! is deprecated and should be removed at some point...
%%!============================================================
-get_suite(Mod, Name) ->
- %% Name may be name of a group or a test case. If it's a group,
- %% it should be expanded to list of cases (in a conf term)
+%% group
+get_suite(Mod, Group={conf,Props,_Init,TCs,_End}) ->
+ Name = proplists:get_value(name, Props),
case catch apply(Mod, groups, []) of
{'EXIT',_} ->
- get_seq(Mod, Name);
+ [Group];
GroupDefs when is_list(GroupDefs) ->
- case catch check_groups(Mod, GroupDefs) of
+ case catch find_groups(Mod, Name, TCs, GroupDefs) of
{error,_} = Error ->
%% this makes test_server call error_in_suite as first
%% (and only) test case so we can report Error properly
[{?MODULE,error_in_suite,[[Error]]}];
+ [] ->
+ {error,{invalid_group_spec,Name}};
ConfTests ->
-
- %%! --- Thu Jun 3 19:13:22 2010 --- peppe was here!
- %%! HEERE!
- %%! Must be able to search recursively for group Name,
- %%! this only handles top level groups!
-
- FindConf = fun({conf,Props,_,_,_}) ->
- case proplists:get_value(name, Props) of
- Name -> true;
- _ -> false
- end
- end,
- case lists:filter(FindConf, ConfTests) of
- [] -> % must be a test case
- get_seq(Mod, Name);
- [ConfTest|_] ->
- ConfTest
+ case lists:member(skipped, Props) of
+ true ->
+ %% a *subgroup* specified *only* as skipped (and not
+ %% as an explicit test) should not be returned, or
+ %% init/end functions for top groups will be executed
+ case catch proplists:get_value(name, element(2, hd(ConfTests))) of
+ Name -> % top group
+ ConfTests;
+ _ ->
+ []
+ end;
+ false ->
+ ConfTests
end
end;
_ ->
E = "Bad return value from "++atom_to_list(Mod)++":groups/0",
[{?MODULE,error_in_suite,[[{error,list_to_atom(E)}]]}]
- end.
+ end;
-check_groups(_Mod, []) ->
- [];
-check_groups(Mod, Defs) ->
- check_groups(Mod, Defs, Defs, []).
+%% testcase
+get_suite(Mod, Name) ->
+ get_seq(Mod, Name).
-check_groups(Mod, [TC | Gs], Defs, Levels) when is_atom(TC), length(Levels)>0 ->
- [TC | check_groups(Mod, Gs, Defs, Levels)];
+%%%-----------------------------------------------------------------
-check_groups(Mod, [{group,SubName} | Gs], Defs, Levels) when is_atom(SubName) ->
- case lists:member(SubName, Levels) of
- true ->
- E = "Cyclic reference to group "++atom_to_list(SubName)++
- " in "++atom_to_list(Mod)++":groups/0",
- throw({error,list_to_atom(E)});
- false ->
- case find_group(Mod, SubName, Defs) of
- {error,_} = Error ->
- throw(Error);
- G ->
- [check_groups(Mod, [G], Defs, Levels) |
- check_groups(Mod, Gs, Defs, Levels)]
- end
+find_groups(Mod, Name, TCs, GroupDefs) ->
+ Found = find(Mod, Name, TCs, GroupDefs, [], GroupDefs, false),
+ Trimmed = trim(Found),
+ delete_subs(Trimmed, Trimmed).
+
+find(Mod, all, _TCs, [{Name,Props,Tests} | Gs], Known, Defs, _) ->
+ cyclic_test(Mod, Name, Known),
+ [make_conf(Mod, Name, Props,
+ find(Mod, all, all, Tests, [Name | Known], Defs, true)) |
+ find(Mod, all, all, Gs, [], Defs, true)];
+
+find(Mod, Name, TCs, [{Name,Props,Tests} | _Gs], Known, Defs, false)
+ when is_atom(Name), is_list(Props), is_list(Tests) ->
+ cyclic_test(Mod, Name, Known),
+ case TCs of
+ all ->
+ [make_conf(Mod, Name, Props,
+ find(Mod, Name, TCs, Tests, [Name | Known], Defs, true))];
+ _ ->
+ Tests1 = [TC || TC <- TCs,
+ lists:member(TC, Tests) == true],
+ [make_conf(Mod, Name, Props, Tests1)]
end;
-check_groups(Mod, [{Name,Tests} | Gs], Defs, Levels) when is_atom(Name),
- is_list(Tests) ->
- check_groups(Mod, [{Name,[],Tests} | Gs], Defs, Levels);
-
-check_groups(Mod, [{Name,Props,Tests} | Gs], Defs, Levels) when is_atom(Name),
- is_list(Props),
- is_list(Tests) ->
- {TestSpec,Levels1} =
- case Levels of
- [] ->
- {check_groups(Mod, Tests, Defs, [Name]),[]};
- _ ->
- {check_groups(Mod, Tests, Defs, [Name|Levels]),Levels}
- end,
- [make_conf(Mod, Name, Props, TestSpec) |
- check_groups(Mod, Gs, Defs, Levels1)];
+find(Mod, Name, TCs, [{Name1,Props,Tests} | Gs], Known, Defs, false)
+ when is_atom(Name1), is_list(Props), is_list(Tests) ->
+ cyclic_test(Mod, Name1, Known),
+ [make_conf(Mod, Name1, Props,
+ find(Mod, Name, TCs, Tests, [Name1 | Known], Defs, false)) |
+ find(Mod, Name, TCs, Gs, [], Defs, false)];
+
+find(Mod, Name, _TCs, [{Name,_Props,_Tests} | _Gs], _Known, _Defs, true)
+ when is_atom(Name) ->
+ E = "Duplicate groups named "++atom_to_list(Name)++" in "++
+ atom_to_list(Mod)++":groups/0",
+ throw({error,list_to_atom(E)});
+
+find(Mod, Name, all, [{Name1,Props,Tests} | Gs], Known, Defs, true)
+ when is_atom(Name1), is_list(Props), is_list(Tests) ->
+ cyclic_test(Mod, Name1, Known),
+ [make_conf(Mod, Name1, Props,
+ find(Mod, Name, all, Tests, [Name1 | Known], Defs, true)) |
+ find(Mod, Name, all, Gs, [], Defs, true)];
+
+find(Mod, Name, TCs, [{group,Name1} | Gs], Known, Defs, Found) when is_atom(Name1) ->
+ find(Mod, Name, TCs, [expand(Mod, Name1, Defs) | Gs], Known, Defs, Found);
+
+find(Mod, Name, TCs, [{Name1,Tests} | Gs], Known, Defs, Found)
+ when is_atom(Name1), is_list(Tests) ->
+ find(Mod, Name, TCs, [{Name1,[],Tests} | Gs], Known, Defs, Found);
+
+find(Mod, Name, TCs, [TC | Gs], Known, Defs, false) when is_atom(TC) ->
+ find(Mod, Name, TCs, Gs, Known, Defs, false);
-check_groups(Mod, [BadTerm | _Gs], _Defs, Levels) ->
- Where = if length(Levels) == 0 ->
+find(Mod, Name, TCs, [TC | Gs], Known, Defs, true) when is_atom(TC) ->
+ [TC | find(Mod, Name, TCs, Gs, Known, Defs, true)];
+
+find(Mod, _Name, _TCs, [BadTerm | _Gs], Known, _Defs, _Found) ->
+ Where = if length(Known) == 0 ->
atom_to_list(Mod)++":groups/0";
true ->
- "group "++atom_to_list(lists:last(Levels))++
+ "group "++atom_to_list(lists:last(Known))++
" in "++atom_to_list(Mod)++":groups/0"
end,
Term = io_lib:format("~p", [BadTerm]),
E = "Bad term "++lists:flatten(Term)++" in "++Where,
throw({error,list_to_atom(E)});
-check_groups(_Mod, [], _Defs, _) ->
+find(_Mod, _Name, _TCs, [], _Known, _Defs, false) ->
+ ['$NOMATCH'];
+
+find(_Mod, _Name, _TCs, [], _Known, _Defs, _Found) ->
+ [].
+
+delete_subs([Conf | Confs], All) ->
+ All1 = delete_conf(Conf, All),
+ case is_sub(Conf, All1) of
+ true ->
+ delete_subs(Confs, All1);
+ false ->
+ delete_subs(Confs, All)
+ end;
+
+delete_subs([], All) ->
+ All.
+
+delete_conf({conf,Props,_,_,_}, Confs) ->
+ Name = proplists:get_value(name, Props),
+ [Conf || Conf = {conf,Props0,_,_,_} <- Confs,
+ Name =/= proplists:get_value(name, Props0)].
+
+is_sub({conf,Props,_,_,_}=Conf, [{conf,_,_,Tests,_} | Confs]) ->
+ Name = proplists:get_value(name, Props),
+ case lists:any(fun({conf,Props0,_,_,_}) ->
+ case proplists:get_value(name, Props0) of
+ N when N == Name ->
+ true;
+ _ ->
+ false
+ end;
+ (_) ->
+ false
+ end, Tests) of
+ true ->
+ true;
+ false ->
+ is_sub(Conf, Tests) or is_sub(Conf, Confs)
+ end;
+
+is_sub(Conf, [_TC | Tests]) ->
+ is_sub(Conf, Tests);
+
+is_sub(_Conf, []) ->
+ false.
+
+trim(['$NOMATCH' | Tests]) ->
+ trim(Tests);
+
+trim([{conf,Props,Init,Tests,End} | Confs]) ->
+ case trim(Tests) of
+ [] ->
+ trim(Confs);
+ Trimmed ->
+ [{conf,Props,Init,Trimmed,End} | trim(Confs)]
+ end;
+
+trim([TC | Tests]) ->
+ [TC | trim(Tests)];
+
+trim([]) ->
[].
-find_group(Mod, Name, Defs) ->
+cyclic_test(Mod, Name, Names) ->
+ case lists:member(Name, Names) of
+ true ->
+ E = "Cyclic reference to group "++atom_to_list(Name)++
+ " in "++atom_to_list(Mod)++":groups/0",
+ throw({error,list_to_atom(E)});
+ false ->
+ ok
+ end.
+
+expand(Mod, Name, Defs) ->
case lists:keysearch(Name, 1, Defs) of
{value,Def} ->
Def;
@@ -769,7 +865,48 @@ find_group(Mod, Name, Defs) ->
throw({error,list_to_atom(E)})
end.
+make_all_conf(Dir, Mod, _Props) ->
+ case code:is_loaded(Mod) of
+ false ->
+ code:load_abs(filename:join(Dir,atom_to_list(Mod)));
+ _ ->
+ ok
+ end,
+ make_all_conf(Mod).
+
+make_all_conf(Mod) ->
+ case catch apply(Mod, groups, []) of
+ {'EXIT',_} ->
+ {error,{invalid_group_definition,Mod}};
+ GroupDefs when is_list(GroupDefs) ->
+ case catch find_groups(Mod, all, all, GroupDefs) of
+ {error,_} = Error ->
+ %% this makes test_server call error_in_suite as first
+ %% (and only) test case so we can report Error properly
+ [{?MODULE,error_in_suite,[[Error]]}];
+ [] ->
+ {error,{invalid_group_spec,Mod}};
+ ConfTests ->
+ [{conf,Props,Init,all,End} || {conf,Props,Init,_,End} <- ConfTests]
+ end
+ end.
+
+make_conf(Dir, Mod, Name, Props, TestSpec) ->
+ case code:is_loaded(Mod) of
+ false ->
+ code:load_abs(filename:join(Dir,atom_to_list(Mod)));
+ _ ->
+ ok
+ end,
+ make_conf(Mod, Name, Props, TestSpec).
+
make_conf(Mod, Name, Props, TestSpec) ->
+ case code:is_loaded(Mod) of
+ false ->
+ code:load_file(Mod);
+ _ ->
+ ok
+ end,
{InitConf,EndConf} =
case erlang:function_exported(Mod,init_per_group,2) of
true ->
@@ -780,6 +917,7 @@ make_conf(Mod, Name, Props, TestSpec) ->
end,
{conf,[{name,Name}|Props],InitConf,TestSpec,EndConf}.
+%%%-----------------------------------------------------------------
get_all(Mod, ConfTests) ->
case catch apply(Mod, all, []) of
@@ -1095,4 +1233,31 @@ add_data_dir(File,Config) when is_list(File) ->
File
end.
+%%%-----------------------------------------------------------------
+%%% @spec overview_html_header(TestName) -> Header
+overview_html_header(TestName) ->
+ TestName1 = lists:flatten(io_lib:format("~p", [TestName])),
+ Label = case application:get_env(common_test, test_label) of
+ {ok,Lbl} when Lbl =/= undefined ->
+ "<H1><FONT color=\"green\">" ++ Lbl ++ "</FONT></H1>\n";
+ _ ->
+ ""
+ end,
+ Bgr = case ct_logs:basic_html() of
+ true ->
+ "";
+ false ->
+ CTPath = code:lib_dir(common_test),
+ TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
+ " background=\"" ++ TileFile ++ "\""
+ end,
+
+ ["<html>\n",
+ "<head><title>Test ", TestName1, " results</title>\n",
+ "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
+ "</head>\n",
+ "<body", Bgr, " bgcolor=\"white\" text=\"black\" ",
+ "link=\"blue\" vlink=\"purple\" alink=\"red\">\n",
+ Label,
+ "<H2>Results from test ", TestName1, "</H2>\n"].
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 5683d06aa7..f8ae7202e6 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -36,7 +36,8 @@
-export([make_all_suites_index/1,make_all_runs_index/1]).
%% Logging stuff directly from testcase
--export([tc_log/3,tc_print/3,tc_pal/3]).
+-export([tc_log/3,tc_print/3,tc_pal/3,
+ basic_html/0]).
%% Simulate logger process for use without ct environment running
-export([simulate/0]).
@@ -57,7 +58,7 @@
-define(table_color2,"#E4F0FE").
-define(table_color3,"#F0F8FF").
--define(testname_width, 70).
+-define(testname_width, 60).
-define(abs(Name), filename:absname(Name)).
@@ -716,7 +717,7 @@ make_last_run_index1(StartTime,IndexName) ->
[Log];
Logs ->
case read_totals_file(?totals_name) of
- {_Node,Logs0,_Totals} ->
+ {_Node,_Lbl,Logs0,_Totals} ->
insert_dirs(Logs,Logs0);
_ ->
%% someone deleted the totals file!?
@@ -728,10 +729,15 @@ make_last_run_index1(StartTime,IndexName) ->
{ok,Bin} -> binary_to_term(Bin);
_ -> []
end,
- {ok,Index0,Totals} = make_last_run_index(Logs1, index_header(StartTime),
+ Label = case application:get_env(common_test, test_label) of
+ {ok,Lbl} -> Lbl;
+ _ -> undefined
+ end,
+ {ok,Index0,Totals} = make_last_run_index(Logs1,
+ index_header(Label,StartTime),
0, 0, 0, 0, 0, Missing),
%% write current Totals to file, later to be used in all_runs log
- write_totals_file(?totals_name,Logs1,Totals),
+ write_totals_file(?totals_name,Label,Logs1,Totals),
Index = [Index0|index_footer()],
case force_write_file(IndexName, Index) of
ok ->
@@ -761,7 +767,7 @@ make_last_run_index([Name|Rest], Result, TotSucc, TotFail, UserSkip, AutoSkip,
TotNotBuilt, Missing);
LastLogDir ->
SuiteName = filename:rootname(filename:basename(Name)),
- case make_one_index_entry(SuiteName, LastLogDir, false, Missing) of
+ case make_one_index_entry(SuiteName, LastLogDir, "-", false, Missing) of
{Result1,Succ,Fail,USkip,ASkip,NotBuilt} ->
%% for backwards compatibility
AutoSkip1 = case catch AutoSkip+ASkip of
@@ -780,18 +786,18 @@ make_last_run_index([], Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuil
{ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, false)],
{TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}}.
-make_one_index_entry(SuiteName, LogDir, All, Missing) ->
+make_one_index_entry(SuiteName, LogDir, Label, All, Missing) ->
case count_cases(LogDir) of
{Succ,Fail,UserSkip,AutoSkip} ->
NotBuilt = not_built(SuiteName, LogDir, All, Missing),
- NewResult = make_one_index_entry1(SuiteName, LogDir, Succ, Fail,
+ NewResult = make_one_index_entry1(SuiteName, LogDir, Label, Succ, Fail,
UserSkip, AutoSkip, NotBuilt, All),
{NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt};
error ->
error
end.
-make_one_index_entry1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip,
+make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
NotBuilt, All) ->
LogFile = filename:join(Link, ?suitelog_name ++ ".html"),
CrashDumpName = SuiteName ++ "_erl_crash.dump",
@@ -803,7 +809,7 @@ make_one_index_entry1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip,
false ->
""
end,
- {Timestamp,Node,AllInfo} =
+ {Lbl,Timestamp,Node,AllInfo} =
case All of
{true,OldRuns} ->
[_Prefix,NodeOrDate|_] = string:tokens(Link,"."),
@@ -811,20 +817,21 @@ make_one_index_entry1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip,
0 -> "-";
_ -> NodeOrDate
end,
- N = ["<TD ALIGN=right>",Node1,"</TD>\n"],
+ N = ["<TD ALIGN=right><FONT SIZE=-1>",Node1,"</FONT></TD>\n"],
CtRunDir = filename:dirname(filename:dirname(Link)),
- T = ["<TD>",timestamp(CtRunDir),"</TD>\n"],
+ L = ["<TD ALIGN=center><FONT SIZE=-1><B>",Label,"</FONT></B></TD>\n"],
+ T = ["<TD><FONT SIZE=-1>",timestamp(CtRunDir),"</FONT></TD>\n"],
CtLogFile = filename:join(CtRunDir,?ct_log_name),
OldRunsLink =
case OldRuns of
[] -> "none";
_ -> "<A HREF=\""++?all_runs_name++"\">Old Runs</A>"
end,
- A=["<TD><A HREF=\"",CtLogFile,"\">CT Log</A></TD>\n",
- "<TD>",OldRunsLink,"</TD>\n"],
- {T,N,A};
+ A=["<TD><FONT SIZE=-1><A HREF=\"",CtLogFile,"\">CT Log</A></FONT></TD>\n",
+ "<TD><FONT SIZE=-1>",OldRunsLink,"</FONT></TD>\n"],
+ {L,T,N,A};
false ->
- {"","",""}
+ {"","","",""}
end,
NotBuiltStr =
if NotBuilt == 0 ->
@@ -851,7 +858,8 @@ make_one_index_entry1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip,
{UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr}
end,
["<TR valign=top>\n",
- "<TD><A HREF=\"",LogFile,"\">",SuiteName,"</A>",CrashDumpLink,"</TD>\n",
+ "<TD><FONT SIZE=-1><A HREF=\"",LogFile,"\">",SuiteName,"</A>",CrashDumpLink,"</FONT></TD>\n",
+ Lbl,
Timestamp,
"<TD ALIGN=right>",integer_to_list(Success),"</TD>\n",
"<TD ALIGN=right>",FailStr,"</TD>\n",
@@ -862,12 +870,14 @@ make_one_index_entry1(SuiteName, Link, Success, Fail, UserSkip, AutoSkip,
AllInfo,
"</TR>\n"].
total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) ->
- {TimestampCell,AllInfo} =
+ {Label,TimestampCell,AllInfo} =
case All of
- true ->
- {"<TD>&nbsp;</TD>\n","<TD>&nbsp;</TD>\n<TD>&nbsp;</TD>\n"};
+ true ->
+ {"<TD>&nbsp;</TD>\n",
+ "<TD>&nbsp;</TD>\n",
+ "<TD>&nbsp;</TD>\n<TD>&nbsp;</TD>\n"};
false ->
- {"",""}
+ {"","",""}
end,
{AllSkip,UserSkipStr,AutoSkipStr} =
@@ -877,6 +887,7 @@ total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) ->
end,
["<TR valign=top>\n",
"<TD><B>Total</B></TD>",
+ Label,
TimestampCell,
"<TD ALIGN=right><B>",integer_to_list(Success),"<B></TD>\n",
"<TD ALIGN=right><B>",integer_to_list(Fail),"<B></TD>\n",
@@ -937,13 +948,21 @@ term_to_text(Term) ->
%%% Headers and footers.
-index_header(StartTime) ->
- [header("Test Results " ++ format_time(StartTime)) |
+index_header(Label, StartTime) ->
+ Head =
+ case Label of
+ undefined ->
+ header("Test Results", format_time(StartTime));
+ _ ->
+ header("Test Results for \"" ++ Label ++ "\"",
+ format_time(StartTime))
+ end,
+ [Head |
["<CENTER>\n",
"<P><A HREF=\"",?ct_log_name,"\">Common Test Framework Log</A></P>",
"<TABLE border=\"3\" cellpadding=\"5\" "
"BGCOLOR=\"",?table_color3,"\">\n"
- "<th><B>Name</B></th>\n",
+ "<th><B>Test Name</B></th>\n",
"<th><font color=\"",?table_color3,"\">_</font>Ok"
"<font color=\"",?table_color3,"\">_</font></th>\n"
"<th>Failed</th>\n",
@@ -952,13 +971,17 @@ index_header(StartTime) ->
"\n"]].
all_suites_index_header() ->
+ {ok,Cwd} = file:get_cwd(),
+ LogDir = filename:basename(Cwd),
+ AllRuns = "All test runs in \"" ++ LogDir ++ "\"",
[header("Test Results") |
["<CENTER>\n",
- "<A HREF=\"",?all_runs_name,"\">All Test Runs in this directory</A>\n",
+ "<A HREF=\"",?all_runs_name,"\">",AllRuns,"</A>\n",
"<br><br>\n",
"<TABLE border=\"3\" cellpadding=\"5\" "
"BGCOLOR=\"",?table_color2,"\">\n"
- "<th>Name</th>\n",
+ "<th>Test Name</th>\n",
+ "<th>Label</th>\n",
"<th>Test Run Started</th>\n",
"<th><font color=\"",?table_color2,"\">_</font>Ok"
"<font color=\"",?table_color2,"\">_</font></th>\n"
@@ -971,13 +994,17 @@ all_suites_index_header() ->
"\n"]].
all_runs_header() ->
- [header("All test runs in current directory") |
+ {ok,Cwd} = file:get_cwd(),
+ LogDir = filename:basename(Cwd),
+ Title = "All test runs in \"" ++ LogDir ++ "\"",
+ [header(Title) |
["<CENTER><TABLE border=\"3\" cellpadding=\"5\" "
"BGCOLOR=\"",?table_color1,"\">\n"
"<th><B>History</B></th>\n"
"<th><B>Node</B></th>\n"
+ "<th><B>Label</B></th>\n"
"<th>Tests</th>\n"
- "<th><B>Names</B></th>\n"
+ "<th><B>Test Names</B></th>\n"
"<th>Total</th>\n"
"<th><font color=\"",?table_color1,"\">_</font>Ok"
"<font color=\"",?table_color1,"\">_</font></th>\n"
@@ -987,12 +1014,23 @@ all_runs_header() ->
"\n"]].
header(Title) ->
+ header1(Title, "").
+header(Title, SubTitle) ->
+ header1(Title, SubTitle).
+
+header1(Title, SubTitle) ->
+ SubTitleHTML = if SubTitle =/= "" ->
+ ["<CENTER>\n",
+ "<H2>" ++ SubTitle ++ "</H2>\n",
+ "</CENTER>\n<BR>\n"];
+ true -> "<BR>\n"
+ end,
["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
"<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
"<HTML>\n",
"<HEAD>\n",
- "<TITLE>" ++ Title ++ "</TITLE>\n",
+ "<TITLE>" ++ Title ++ " " ++ SubTitle ++ "</TITLE>\n",
"<META HTTP-EQUIV=\"CACHE-CONTROL\" CONTENT=\"NO-CACHE\">\n",
"</HEAD>\n",
@@ -1004,6 +1042,7 @@ header(Title) ->
"<CENTER>\n",
"<H1>" ++ Title ++ "</H1>\n",
"</CENTER>\n",
+ SubTitleHTML,
"<!-- ---- CONTENT ---- -->\n"].
@@ -1013,19 +1052,28 @@ index_footer() ->
footer() ->
["<P><CENTER>\n"
- "<HR>\n"
- "<P><FONT SIZE=-1>\n"
- "Copyright &copy; ", year(),
- " <A HREF=\"http://erlang.ericsson.se\">Open Telecom Platform</A><BR>\n"
- "Updated: <!date>", current_time(), "<!/date><BR>\n"
- "</FONT>\n"
- "</CENTER>\n"
- "</body>\n"].
+ "<BR><BR>\n"
+ "<HR>\n"
+ "<P><FONT SIZE=-1>\n"
+ "Copyright &copy; ", year(),
+ " <A HREF=\"http://erlang.ericsson.se\">Open Telecom Platform</A><BR>\n"
+ "Updated: <!date>", current_time(), "<!/date><BR>\n"
+ "</FONT>\n"
+ "</CENTER>\n"
+ "</body>\n"].
body_tag() ->
- "<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\""
- "vlink=\"#800080\" alink=\"#FF0000\">\n".
+ case basic_html() of
+ true ->
+ "<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" "
+ "vlink=\"#800080\" alink=\"#FF0000\">\n";
+ false ->
+ CTPath = code:lib_dir(common_test),
+ TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
+ "<body background=\"" ++ TileFile ++ "\" bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" "
+ "vlink=\"#800080\" alink=\"#FF0000\">\n"
+ end.
current_time() ->
format_time(calendar:local_time()).
@@ -1217,7 +1265,7 @@ runentry(Dir, BasicHtml) ->
TotalsFile = filename:join(Dir,?totals_name),
TotalsStr =
case read_totals_file(TotalsFile) of
- {Node,Logs,{TotSucc,TotFail,UserSkip,AutoSkip,NotBuilt}} ->
+ {Node,Label,Logs,{TotSucc,TotFail,UserSkip,AutoSkip,NotBuilt}} ->
TotFailStr =
if TotFail > 0 ->
["<FONT color=\"red\">",
@@ -1263,6 +1311,7 @@ runentry(Dir, BasicHtml) ->
end,
Total = TotSucc+TotFail+AllSkip,
A = ["<TD ALIGN=center><FONT SIZE=-1>",Node,"</FONT></TD>\n",
+ "<TD ALIGN=center><FONT SIZE=-1><B>",Label,"</B></FONT></TD>\n",
"<TD ALIGN=right>",NoOfTests,"</TD>\n"],
B = if BasicHtml ->
["<TD ALIGN=center><FONT SIZE=-1>",TestNamesTrunc,"</FONT></TD>\n"];
@@ -1283,17 +1332,19 @@ runentry(Dir, BasicHtml) ->
end,
Index = filename:join(Dir,?index_name),
["<TR>\n"
- "<TD><A HREF=\"",Index,"\">",timestamp(Dir),"</A>",TotalsStr,"</TD>\n"
+ "<TD><FONT SIZE=-1><A HREF=\"",Index,"\">",timestamp(Dir),"</A>",TotalsStr,"</FONT></TD>\n"
"</TR>\n"].
-write_totals_file(Name,Logs,Totals) ->
+write_totals_file(Name,Label,Logs,Totals) ->
AbsName = ?abs(Name),
notify_and_lock_file(AbsName),
force_write_file(AbsName,
term_to_binary({atom_to_list(node()),
- Logs,Totals})),
+ Label,Logs,Totals})),
notify_and_unlock_file(AbsName).
+%% this function needs to convert from old formats to new so that old
+%% test results (prev ct versions) can be listed together with new
read_totals_file(Name) ->
AbsName = ?abs(Name),
notify_and_lock_file(AbsName),
@@ -1303,12 +1354,23 @@ read_totals_file(Name) ->
case catch binary_to_term(Bin) of
{'EXIT',_Reason} -> % corrupt file
{"-",[],undefined};
- R = {Node,Ls,Tot} ->
+ {Node,Label,Ls,Tot} -> % all info available
+ Label1 = case Label of
+ undefined -> "-";
+ _ -> Label
+ end,
+ case Tot of
+ {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
+ {Node,Label1,Ls,Tot};
+ {TotSucc,TotFail,AllSkip,NotBuilt} ->
+ {Node,Label1,Ls,{TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
+ end;
+ {Node,Ls,Tot} -> % no label found
case Tot of
- {_,_,_,_,_} -> % latest format
- R;
+ {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
+ {Node,"-",Ls,Tot};
{TotSucc,TotFail,AllSkip,NotBuilt} ->
- {Node,Ls,{TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
+ {Node,"-",Ls,{TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
end;
%% for backwards compatibility
{Ls,Tot} -> {"-",Ls,Tot};
@@ -1411,7 +1473,7 @@ make_all_suites_index1(When,AllSuitesLogDirs) ->
make_all_suites_index2(IndexName,AllSuitesLogDirs) ->
{ok,Index0,_Totals} = make_all_suites_index3(AllSuitesLogDirs,
all_suites_index_header(),
- 0, 0, 0, 0, 0),
+ 0, 0, 0, 0, 0, []),
Index = [Index0|index_footer()],
case force_write_file(IndexName, Index) of
ok ->
@@ -1421,14 +1483,25 @@ make_all_suites_index2(IndexName,AllSuitesLogDirs) ->
end.
make_all_suites_index3([{SuiteName,[LastLogDir|OldDirs]}|Rest],
- Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt) ->
+ Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,
+ Labels) ->
[EntryDir|_] = filename:split(LastLogDir),
Missing =
case file:read_file(filename:join(EntryDir,?missing_suites_info)) of
{ok,Bin} -> binary_to_term(Bin);
_ -> []
end,
- case make_one_index_entry(SuiteName, LastLogDir, {true,OldDirs}, Missing) of
+ {Label,Labels1} =
+ case proplists:get_value(EntryDir, Labels) of
+ undefined ->
+ case read_totals_file(filename:join(EntryDir,?totals_name)) of
+ {_,Lbl,_,_} -> {Lbl,[{EntryDir,Lbl}|Labels]};
+ _ -> {"-",[{EntryDir,"-"}|Labels]}
+ end;
+ Lbl ->
+ {Lbl,Labels}
+ end,
+ case make_one_index_entry(SuiteName, LastLogDir, Label, {true,OldDirs}, Missing) of
{Result1,Succ,Fail,USkip,ASkip,NotBuilt} ->
%% for backwards compatibility
AutoSkip1 = case catch AutoSkip+ASkip of
@@ -1437,13 +1510,13 @@ make_all_suites_index3([{SuiteName,[LastLogDir|OldDirs]}|Rest],
end,
make_all_suites_index3(Rest, [Result|Result1], TotSucc+Succ,
TotFail+Fail, UserSkip+USkip, AutoSkip1,
- TotNotBuilt+NotBuilt);
+ TotNotBuilt+NotBuilt,Labels1);
error ->
make_all_suites_index3(Rest, Result, TotSucc, TotFail,
- UserSkip, AutoSkip, TotNotBuilt)
+ UserSkip, AutoSkip, TotNotBuilt,Labels1)
end;
make_all_suites_index3([], Result, TotSucc, TotFail, UserSkip, AutoSkip,
- TotNotBuilt) ->
+ TotNotBuilt,_) ->
{ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,true)],
{TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}}.
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 6a9c42d1b9..c5bfd01642 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -45,7 +45,8 @@
-define(abs(Name), filename:absname(Name)).
-define(testdir(Name, Suite), ct_util:get_testdir(Name, Suite)).
--record(opts, {vts,
+-record(opts, {label,
+ vts,
shell,
cover,
coverspec,
@@ -153,14 +154,16 @@ script_start(Args) ->
Result
end,
stop_trace(Tracing),
+ timer:sleep(1000),
Res.
script_start1(Parent, Args) ->
%% read general start flags
+ Label = get_start_opt(label, fun([Lbl]) -> Lbl end, 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),
- LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, ".", Args),
+ LogDir = get_start_opt(logdir, fun([LogD]) -> LogD end, Args),
MultTT = get_start_opt(multiply_timetraps,
fun([MT]) -> list_to_integer(MT) end, 1, Args),
ScaleTT = get_start_opt(scale_timetraps,
@@ -229,7 +232,7 @@ script_start1(Parent, Args) ->
application:set_env(common_test, basic_html, true)
end,
- StartOpts = #opts{vts = Vts, shell = Shell, cover = Cover,
+ StartOpts = #opts{label = Label, vts = Vts, shell = Shell, cover = Cover,
logdir = LogDir, event_handlers = EvHandlers,
include = IncludeDirs,
silent_connections = SilentConns,
@@ -288,6 +291,9 @@ script_start2(StartOpts = #opts{vts = undefined,
TS ->
SpecStartOpts = get_data_for_node(TS, node()),
+ Label = choose_val(StartOpts#opts.label,
+ SpecStartOpts#opts.label),
+
LogDir = choose_val(StartOpts#opts.logdir,
SpecStartOpts#opts.logdir),
@@ -303,7 +309,8 @@ script_start2(StartOpts = #opts{vts = undefined,
SpecStartOpts#opts.include]),
application:set_env(common_test, include, AllInclude),
- {TS,StartOpts#opts{testspecs = Specs,
+ {TS,StartOpts#opts{label = Label,
+ testspecs = Specs,
cover = Cover,
logdir = LogDir,
config = SpecStartOpts#opts.config,
@@ -317,29 +324,30 @@ script_start2(StartOpts = #opts{vts = undefined,
end,
%% read config/userconfig from start flags
InitConfig = ct_config:prepare_config_list(Args),
+ TheLogDir = which(logdir, Opts#opts.logdir),
case {TestSpec,Terms} of
{_,{error,_}=Error} ->
Error;
{[],_} ->
{error,no_testspec_specified};
{undefined,_} -> % no testspec used
- case check_and_install_configfiles(InitConfig,
- which(logdir,Opts#opts.logdir),
+ case check_and_install_configfiles(InitConfig, TheLogDir,
Opts#opts.event_handlers) of
ok -> % go on read tests from start flags
- script_start3(Opts#opts{config=InitConfig}, Args);
+ script_start3(Opts#opts{config=InitConfig,
+ logdir=TheLogDir}, Args);
Error ->
Error
end;
{_,_} -> % testspec used
%% merge config from start flags with config from testspec
AllConfig = merge_vals([InitConfig, Opts#opts.config]),
- case check_and_install_configfiles(AllConfig,
- which(logdir,Opts#opts.logdir),
+ case check_and_install_configfiles(AllConfig, TheLogDir,
Opts#opts.event_handlers) of
ok -> % read tests from spec
{Run,Skip} = ct_testspec:prepare_tests(Terms, node()),
- do_run(Run, Skip, Opts#opts{config=AllConfig}, Args);
+ do_run(Run, Skip, Opts#opts{config=AllConfig,
+ logdir=TheLogDir}, Args);
Error ->
Error
end
@@ -348,11 +356,12 @@ script_start2(StartOpts = #opts{vts = undefined,
script_start2(StartOpts, Args) ->
%% read config/userconfig from start flags
InitConfig = ct_config:prepare_config_list(Args),
- case check_and_install_configfiles(InitConfig,
- which(logdir,StartOpts#opts.logdir),
+ LogDir = which(logdir, StartOpts#opts.logdir),
+ case check_and_install_configfiles(InitConfig, LogDir,
StartOpts#opts.event_handlers) of
ok -> % go on read tests from start flags
- script_start3(StartOpts#opts{config=InitConfig}, Args);
+ script_start3(StartOpts#opts{config=InitConfig,
+ logdir=LogDir}, Args);
Error ->
Error
end.
@@ -427,8 +436,12 @@ script_start4(#opts{vts = true, config = Config, event_handlers = EvHandlers,
end, [], Config),
vts:init_data(ConfigFiles, EvHandlers, ?abs(LogDir), Tests);
-script_start4(#opts{shell = true, config = Config, event_handlers = EvHandlers,
+script_start4(#opts{label = Label, shell = true, config = Config,
+ event_handlers = EvHandlers,
logdir = LogDir, testspecs = Specs}, _Args) ->
+ %% label - used by ct_logs
+ application:set_env(common_test, test_label, Label),
+
InstallOpts = [{config,Config},{event_handler,EvHandlers}],
if Config == [] ->
ok;
@@ -613,9 +626,13 @@ run_test(StartOpts) when is_list(StartOpts) ->
end.
run_test1(StartOpts) ->
+ %% label
+ Label = get_start_opt(label, fun(Lbl) when is_list(Lbl) -> Lbl;
+ (Lbl) when is_atom(Lbl) -> atom_to_list(Lbl)
+ end, StartOpts),
%% logdir
LogDir = get_start_opt(logdir, fun(LD) when is_list(LD) -> LD end,
- ".", StartOpts),
+ StartOpts),
%% config & userconfig
CfgFiles = ct_config:get_config_file_list(StartOpts),
@@ -711,7 +728,8 @@ run_test1(StartOpts) ->
%% stepped execution
Step = get_start_opt(step, value, StartOpts),
- Opts = #opts{cover = Cover, step = Step, logdir = LogDir, config = CfgFiles,
+ Opts = #opts{label = Label,
+ cover = Cover, step = Step, logdir = LogDir, config = CfgFiles,
event_handlers = EvHandlers, include = Include,
silent_connections = SilentConns,
stylesheet = Stylesheet,
@@ -747,6 +765,8 @@ run_spec_file(Relaxed,
exit(CTReason);
TS ->
SpecOpts = get_data_for_node(TS, node()),
+ Label = choose_val(Opts#opts.label,
+ SpecOpts#opts.label),
LogDir = choose_val(Opts#opts.logdir,
SpecOpts#opts.logdir),
AllConfig = merge_vals([CfgFiles, SpecOpts#opts.config]),
@@ -766,8 +786,9 @@ run_spec_file(Relaxed,
which(logdir,LogDir),
AllEvHs) of
ok ->
- Opts1 = Opts#opts{cover = Cover,
- logdir = LogDir,
+ Opts1 = Opts#opts{label = Label,
+ cover = Cover,
+ logdir = which(logdir, LogDir),
config = AllConfig,
event_handlers = AllEvHs,
include = AllInclude,
@@ -775,7 +796,7 @@ run_spec_file(Relaxed,
multiply_timetraps = MultTT,
scale_timetraps = ScaleTT},
{Run,Skip} = ct_testspec:prepare_tests(TS, node()),
- do_run(Run, Skip, Opts1, StartOpts);
+ reformat_result(catch do_run(Run, Skip, Opts1, StartOpts));
{error,GCFReason} ->
exit(GCFReason)
end
@@ -785,9 +806,11 @@ run_prepared(Run, Skip, Opts = #opts{logdir = LogDir,
config = CfgFiles,
event_handlers = EvHandlers},
StartOpts) ->
- case check_and_install_configfiles(CfgFiles, LogDir, EvHandlers) of
+ LogDir1 = which(logdir, LogDir),
+ case check_and_install_configfiles(CfgFiles, LogDir1, EvHandlers) of
ok ->
- do_run(Run, Skip, Opts, StartOpts);
+ reformat_result(catch do_run(Run, Skip, Opts#opts{logdir = LogDir1},
+ StartOpts));
{error,Reason} ->
exit(Reason)
end.
@@ -816,6 +839,8 @@ check_config_file(Callback, File)->
run_dir(Opts = #opts{logdir = LogDir,
config = CfgFiles,
event_handlers = EvHandlers}, StartOpts) ->
+ LogDir1 = which(logdir, LogDir),
+ Opts1 = Opts#opts{logdir = LogDir1},
AbsCfgFiles =
lists:map(fun({Callback,FileList})->
case code:is_loaded(Callback) of
@@ -834,7 +859,7 @@ run_dir(Opts = #opts{logdir = LogDir,
check_config_file(Callback, File)
end, FileList)}
end, CfgFiles),
- case install([{config,AbsCfgFiles},{event_handler,EvHandlers}], LogDir) of
+ case install([{config,AbsCfgFiles},{event_handler,EvHandlers}], LogDir1) of
ok -> ok;
{error,IReason} -> exit(IReason)
end,
@@ -842,7 +867,7 @@ run_dir(Opts = #opts{logdir = LogDir,
{value,{_,Dirs=[Dir|_]}} when not is_integer(Dir),
length(Dirs)>1 ->
%% multiple dirs (no suite)
- do_run(tests(Dirs), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(Dirs), [], Opts1, StartOpts));
false -> % no dir
%% fun for converting suite name to {Dir,Mod} tuple
S2M = fun(S) when is_list(S) ->
@@ -857,12 +882,15 @@ run_dir(Opts = #opts{logdir = LogDir,
case listify(proplists:get_value(group, StartOpts, [])) ++
listify(proplists:get_value(testcase, StartOpts, [])) of
[] ->
- do_run(tests(Dir, listify(Mod)), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(Dir, listify(Mod)),
+ [], Opts1, StartOpts));
GsAndCs ->
- do_run(tests(Dir, Mod, GsAndCs), [], Opts, StartOpts)
+ reformat_result(catch do_run(tests(Dir, Mod, GsAndCs),
+ [], Opts1, StartOpts))
end;
{value,{_,Suites}} ->
- do_run(tests(lists:map(S2M, Suites)), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(lists:map(S2M, Suites)),
+ [], Opts1, StartOpts));
_ ->
exit(no_tests_specified)
end;
@@ -875,17 +903,22 @@ run_dir(Opts = #opts{logdir = LogDir,
case listify(proplists:get_value(group, StartOpts, [])) ++
listify(proplists:get_value(testcase, StartOpts, [])) of
[] ->
- do_run(tests(Dir, listify(Mod)), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(Dir, listify(Mod)),
+ [], Opts1, StartOpts));
GsAndCs ->
- do_run(tests(Dir, Mod, GsAndCs), [], Opts, StartOpts)
+ reformat_result(catch do_run(tests(Dir, Mod, GsAndCs),
+ [], Opts1, StartOpts))
end;
{value,{_,Suites=[Suite|_]}} when is_list(Suite) ->
Mods = lists:map(fun(Str) -> list_to_atom(Str) end, Suites),
- do_run(tests(delistify(Dir), Mods), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(delistify(Dir), Mods),
+ [], Opts1, StartOpts));
{value,{_,Suites}} ->
- do_run(tests(delistify(Dir), Suites), [], Opts, StartOpts);
+ reformat_result(catch do_run(tests(delistify(Dir), Suites),
+ [], Opts1, StartOpts));
false -> % no suite, only dir
- do_run(tests(listify(Dir)), [], Opts, StartOpts)
+ reformat_result(catch do_run(tests(listify(Dir)),
+ [], Opts1, StartOpts))
end
end.
@@ -925,28 +958,30 @@ run_testspec1(TestSpec) ->
EnvInclude++Opts#opts.include
end,
application:set_env(common_test, include, AllInclude),
-
- case check_and_install_configfiles(Opts#opts.config,
- which(logdir,Opts#opts.logdir),
+ LogDir1 = which(logdir,Opts#opts.logdir),
+ case check_and_install_configfiles(Opts#opts.config, LogDir1,
Opts#opts.event_handlers) of
ok ->
- Opts1 = Opts#opts{testspecs = [TestSpec],
+ Opts1 = Opts#opts{testspecs = [],
+ logdir = LogDir1,
include = AllInclude},
{Run,Skip} = ct_testspec:prepare_tests(TS, node()),
- do_run(Run, Skip, Opts1, []);
+ reformat_result(catch do_run(Run, Skip, Opts1, []));
{error,GCFReason} ->
exit(GCFReason)
end
end.
-get_data_for_node(#testspec{logdir=LogDirs,
- cover=CoverFs,
- config=Cfgs,
- userconfig=UsrCfgs,
- event_handler=EvHs,
- include=Incl,
- multiply_timetraps=MTs,
- scale_timetraps=STs}, Node) ->
+get_data_for_node(#testspec{label = Labels,
+ logdir = LogDirs,
+ cover = CoverFs,
+ config = Cfgs,
+ userconfig = UsrCfgs,
+ event_handler = EvHs,
+ include = Incl,
+ multiply_timetraps = MTs,
+ scale_timetraps = STs}, Node) ->
+ Label = proplists:get_value(Node, Labels),
LogDir = case proplists:get_value(Node, LogDirs) of
undefined -> ".";
Dir -> Dir
@@ -958,7 +993,8 @@ get_data_for_node(#testspec{logdir=LogDirs,
[CBF || {N,CBF} <- UsrCfgs, N==Node],
EvHandlers = [{H,A} || {N,H,A} <- EvHs, N==Node],
Include = [I || {N,I} <- Incl, N==Node],
- #opts{logdir = LogDir,
+ #opts{label = Label,
+ logdir = LogDir,
cover = Cover,
config = ConfigFiles,
event_handlers = EvHandlers,
@@ -1023,21 +1059,26 @@ delistify(E) -> E.
%%% @equiv ct:run/3
run(TestDir, Suite, Cases) ->
install([]),
- do_run(tests(TestDir, Suite, Cases), []).
+ reformat_result(catch do_run(tests(TestDir, Suite, Cases), [])).
%%%-----------------------------------------------------------------
%%% @hidden
%%% @equiv ct:run/2
run(TestDir, Suite) when is_list(TestDir), is_integer(hd(TestDir)) ->
install([]),
- do_run(tests(TestDir, Suite), []).
+ reformat_result(catch do_run(tests(TestDir, Suite), [])).
%%%-----------------------------------------------------------------
%%% @hidden
%%% @equiv ct:run/1
run(TestDirs) ->
install([]),
- do_run(tests(TestDirs), []).
+ reformat_result(catch do_run(tests(TestDirs), [])).
+
+reformat_result({user_error,Reason}) ->
+ {error,Reason};
+reformat_result(Result) ->
+ Result.
suite_to_test(Suite) ->
{filename:dirname(Suite),list_to_atom(filename:rootname(filename:basename(Suite)))}.
@@ -1092,7 +1133,17 @@ do_run(Tests, Misc, LogDir) when is_list(Misc) ->
do_run(Tests, [], Opts1#opts{logdir = LogDir}, []).
do_run(Tests, Skip, Opts, Args) ->
- #opts{cover = Cover} = Opts,
+ #opts{label = Label, cover = Cover} = Opts,
+
+ %% label - used by ct_logs
+ TestLabel =
+ if Label == undefined -> undefined;
+ is_atom(Label) -> atom_to_list(Label);
+ is_list(Label) -> Label;
+ true -> undefined
+ end,
+ application:set_env(common_test, test_label, TestLabel),
+
case code:which(test_server) of
non_existing ->
exit({error,no_path_to_test_server});
@@ -1156,10 +1207,19 @@ do_run(Tests, Skip, Opts, Args) ->
true ->
SavedErrors = save_make_errors(SuiteMakeErrors),
ct_repeat:log_loop_info(Args),
- {Tests1,Skip1} = final_tests(Tests,[],Skip,SavedErrors),
- R = do_run_test(Tests1, Skip1, Opts1),
- ct_util:stop(normal),
- R;
+
+ {Tests1,Skip1} = final_tests(Tests,Skip,SavedErrors),
+
+ R = (catch do_run_test(Tests1, Skip1, Opts1)),
+ case R of
+ {EType,_} = Error when EType == user_error ;
+ EType == error ->
+ ct_util:stop(clean),
+ exit(Error);
+ _ ->
+ ct_util:stop(normal),
+ R
+ end;
false ->
io:nl(),
ct_util:stop(clean),
@@ -1316,8 +1376,22 @@ suite_tuples([{TestDir,Suite,_} | Tests]) when is_atom(Suite) ->
suite_tuples([]) ->
[].
-final_tests([{TestDir,Suites,_}|Tests],
- Final, Skip, Bad) when is_list(Suites), is_atom(hd(Suites)) ->
+final_tests(Tests, Skip, Bad) ->
+
+ %%! --- Thu Jun 24 15:47:27 2010 --- peppe was here!
+ %%! io:format(user, "FINAL0 = ~p~nSKIP0 = ~p~n", [Tests, Skip]),
+
+ {Tests1,Skip1} = final_tests1(Tests, [], Skip, Bad),
+ Skip2 = final_skip(Skip1, []),
+
+
+ %%! --- Thu Jun 24 15:47:27 2010 --- peppe was here!
+ %%! io:format(user, "FINAL1 = ~p~nSKIP1 = ~p~n", [Tests1, Skip2]),
+
+ {Tests1,Skip2}.
+
+final_tests1([{TestDir,Suites,_}|Tests], Final, Skip, Bad) when
+ is_list(Suites), is_atom(hd(Suites)) ->
% Separate =
% fun(S,{DoSuite,Dont}) ->
% case lists:keymember({TestDir,S},1,Bad) of
@@ -1336,9 +1410,9 @@ final_tests([{TestDir,Suites,_}|Tests],
Skip1 = [{TD,S,"Make failed"} || {{TD,S},_} <- Bad, S1 <- Suites,
S == S1, TD == TestDir],
Final1 = [{TestDir,S,all} || S <- Suites],
- final_tests(Tests, lists:reverse(Final1)++Final, Skip++Skip1, Bad);
+ final_tests1(Tests, lists:reverse(Final1)++Final, Skip++Skip1, Bad);
-final_tests([{TestDir,all,all}|Tests], Final, Skip, Bad) ->
+final_tests1([{TestDir,all,all}|Tests], Final, Skip, Bad) ->
MissingSuites =
case lists:keysearch({TestDir,all}, 1, Bad) of
{value,{_,Failed}} ->
@@ -1348,26 +1422,58 @@ final_tests([{TestDir,all,all}|Tests], Final, Skip, Bad) ->
end,
Missing = [{TestDir,S,"Make failed"} || S <- MissingSuites],
Final1 = [{TestDir,all,all}|Final],
- final_tests(Tests, Final1, Skip++Missing, Bad);
+ final_tests1(Tests, Final1, Skip++Missing, Bad);
-final_tests([{TestDir,Suite,Cases}|Tests],
- Final, Skip, Bad) when Cases==[]; Cases==all ->
- final_tests([{TestDir,[Suite],all}|Tests], Final, Skip, Bad);
+final_tests1([{TestDir,Suite,Cases}|Tests], Final, Skip, Bad) when
+ Cases==[]; Cases==all ->
+ final_tests1([{TestDir,[Suite],all}|Tests], Final, Skip, Bad);
-final_tests([{TestDir,Suite,Cases}|Tests], Final, Skip, Bad) ->
+final_tests1([{TestDir,Suite,GrsOrCs}|Tests], Final, Skip, Bad) when
+ is_list(GrsOrCs) ->
case lists:keymember({TestDir,Suite}, 1, Bad) of
- false ->
- Do = {TestDir,Suite,Cases},
- final_tests(Tests, [Do|Final], Skip, Bad);
true ->
- Do = {TestDir,Suite,Cases},
- Skip1 = Skip ++ [{TestDir,Suite,Cases,"Make failed"}],
- final_tests(Tests, [Do|Final], Skip1, Bad)
+ Skip1 = Skip ++ [{TestDir,Suite,all,"Make failed"}],
+ final_tests1(Tests, [{TestDir,Suite,all}|Final], Skip1, Bad);
+ false ->
+ GrsOrCs1 =
+ lists:flatmap(
+ %% for now, only flat group defs are allowed as
+ %% start options and test spec terms
+ fun({all,all}) ->
+ ct_framework:make_all_conf(TestDir,
+ Suite, []);
+ ({skipped,Group,TCs}) ->
+ [ct_framework:make_conf(TestDir, Suite,
+ Group, [skipped], TCs)];
+ ({Group,TCs}) ->
+ [ct_framework:make_conf(TestDir, Suite,
+ Group, [], TCs)];
+ (TC) ->
+ [TC]
+ end, GrsOrCs),
+ Do = {TestDir,Suite,GrsOrCs1},
+ final_tests1(Tests, [Do|Final], Skip, Bad)
end;
-final_tests([], Final, Skip, _Bad) ->
+final_tests1([], Final, Skip, _Bad) ->
{lists:reverse(Final),Skip}.
+final_skip([{TestDir,Suite,{all,all},Reason}|Skips], Final) ->
+ SkipConf = ct_framework:make_conf(TestDir, Suite, all, [], all),
+ Skip = {TestDir,Suite,SkipConf,Reason},
+ final_skip(Skips, [Skip|Final]);
+
+final_skip([{TestDir,Suite,{Group,TCs},Reason}|Skips], Final) ->
+ Conf = ct_framework:make_conf(TestDir, Suite, Group, [], TCs),
+ Skip = {TestDir,Suite,Conf,Reason},
+ final_skip(Skips, [Skip|Final]);
+
+final_skip([Skip|Skips], Final) ->
+ final_skip(Skips, [Skip|Final]);
+
+final_skip([], Final) ->
+ lists:reverse(Final).
+
continue([]) ->
true;
continue(_MakeErrors) ->
@@ -1489,6 +1595,7 @@ do_run_test(Tests, Skip, Opts) ->
_ ->
false
end,
+
%% let test_server expand the test tuples and count no of cases
{Suites,NoOfCases} = count_test_cases(Tests, Skip),
Suites1 = delete_dups(Suites),
@@ -1544,19 +1651,30 @@ count_test_cases(Tests, Skip) ->
TSPid = test_server_ctrl:start_get_totals(SendResult),
Ref = erlang:monitor(process, TSPid),
add_jobs(Tests, Skip, #opts{}, []),
- {Suites,NoOfCases} = count_test_cases1(length(Tests), 0, [], Ref),
+ Counted = (catch count_test_cases1(length(Tests), 0, [], Ref)),
erlang:demonitor(Ref, [flush]),
- test_server_ctrl:stop_get_totals(),
- {Suites,NoOfCases}.
+ case Counted of
+ {error,{test_server_died}} = Error ->
+ throw(Error);
+ {error,Reason} ->
+ unlink(whereis(test_server_ctrl)),
+ test_server_ctrl:stop(),
+ throw({user_error,Reason});
+ Result ->
+ test_server_ctrl:stop_get_totals(),
+ Result
+ end.
count_test_cases1(0, N, Suites, _) ->
{lists:flatten(Suites), N};
count_test_cases1(Jobs, N, Suites, Ref) ->
receive
+ {_,{error,_Reason} = Error} ->
+ throw(Error);
{no_of_cases,{Ss,N1}} ->
count_test_cases1(Jobs-1, add_known(N,N1), [Ss|Suites], Ref);
- {'DOWN', Ref, _, _, _} ->
- {[],0}
+ {'DOWN', Ref, _, _, Info} ->
+ throw({error,{test_server_died,Info}})
end.
add_known(unknown, _) ->
@@ -1604,13 +1722,36 @@ add_jobs([{TestDir,Suite,all}|Tests], Skip, Opts, CleanUp) ->
Error
end;
-%% group
-add_jobs([{TestDir,Suite,[{GroupName,_Cases}]}|Tests], Skip, Opts, CleanUp) when
- is_atom(GroupName) ->
- add_jobs([{TestDir,Suite,GroupName}|Tests], Skip, Opts, CleanUp);
-add_jobs([{TestDir,Suite,{GroupName,_Cases}}|Tests], Skip, Opts, CleanUp) when
- is_atom(GroupName) ->
- add_jobs([{TestDir,Suite,GroupName}|Tests], Skip, Opts, CleanUp);
+%% group (= conf case in test_server)
+add_jobs([{TestDir,Suite,Confs}|Tests], Skip, Opts, CleanUp) when
+ element(1, hd(Confs)) == conf ->
+ Group = fun(Conf) -> proplists:get_value(name, element(2, Conf)) end,
+ TestCases = fun(Conf) -> element(4, Conf) end,
+ TCTestName = fun(all) -> "";
+ ([C]) when is_atom(C) -> "." ++ atom_to_list(C);
+ (Cs) when is_list(Cs) -> ".cases"
+ end,
+ GrTestName =
+ case Confs of
+ [Conf] ->
+ "." ++ atom_to_list(Group(Conf)) ++ TCTestName(TestCases(Conf));
+ _ ->
+ ".groups"
+ end,
+ TestName = get_name(TestDir) ++ "." ++ atom_to_list(Suite) ++ GrTestName,
+ case maybe_interpret(Suite, init_per_group, Opts) of
+ ok ->
+ case catch test_server_ctrl:add_conf_with_skip(TestName, Suite, Confs,
+ skiplist(TestDir,Skip)) of
+ {'EXIT',_} ->
+ CleanUp;
+ _ ->
+ wait_for_idle(),
+ add_jobs(Tests, Skip, Opts, [Suite|CleanUp])
+ end;
+ Error ->
+ Error
+ end;
%% test case
add_jobs([{TestDir,Suite,[Case]}|Tests], Skip, Opts, CleanUp) when is_atom(Case) ->
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index 0f68b062f6..f5069427a2 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -185,7 +185,15 @@ prepare_cases(Node,Dir,Suite,Cases) ->
{[{{Node,Dir},{Suite,all}}],SkipAll};
Skipped ->
%% note: this adds a test even if only skip is specified
- PrepC = lists:foldr(fun({C,{skip,_Cmt}},Acc) ->
+ PrepC = lists:foldr(fun({{G,Cs},{skip,_Cmt}}, Acc) when
+ is_atom(G) ->
+ case lists:keymember(G, 1, Cases) of
+ true ->
+ Acc;
+ false ->
+ [{skipped,G,Cs}|Acc]
+ end;
+ ({C,{skip,_Cmt}},Acc) ->
case lists:member(C,Cases) of
true ->
Acc;
@@ -194,7 +202,7 @@ prepare_cases(Node,Dir,Suite,Cases) ->
end;
(C,Acc) -> [C|Acc]
end, [], Cases),
- {{{Node,Dir},{Suite,PrepC}},Skipped}
+ {{{Node,Dir},{Suite,PrepC}},Skipped}
end.
get_skipped_suites(Node,Dir,Suites) ->
@@ -210,7 +218,7 @@ get_skipped_cases(Node,Dir,Suite,Cases) ->
case lists:keysearch(all,1,Cases) of
{value,{all,{skip,Cmt}}} ->
[{{Node,Dir},{Suite,Cmt}}];
- false ->
+ _ ->
get_skipped_cases1(Node,Dir,Suite,Cases)
end.
@@ -432,6 +440,15 @@ save_nodes(Nodes,Spec=#testspec{nodes=NodeRefs}) ->
list_nodes(#testspec{nodes=NodeRefs}) ->
lists:map(fun({_Ref,Node}) -> Node end, NodeRefs).
+
+
+%% ---------------------------------------------------------
+%% / \
+%% | When adding tests, remember to update valid_terms/0 also! |
+%% \ /
+%% ---------------------------------------------------------
+
+
%% Associate a "global" logdir with all nodes
%% except those with specific logdir, e.g:
%% ["/tmp/logdir",{ct1@finwe,"/tmp/logdir2"}]
@@ -457,6 +474,24 @@ add_tests([{logdir,Node,Dir}|Ts],Spec) ->
add_tests([{logdir,Dir}|Ts],Spec) ->
add_tests([{logdir,all_nodes,Dir}|Ts],Spec);
+%% --- label ---
+add_tests([{label,all_nodes,Lbl}|Ts],Spec) ->
+ Labels = Spec#testspec.label,
+ Tests = [{label,N,Lbl} || N <- list_nodes(Spec),
+ lists:keymember(ref2node(N,Spec#testspec.nodes),
+ 1,Labels) == false],
+ add_tests(Tests++Ts,Spec);
+add_tests([{label,Nodes,Lbl}|Ts],Spec) when is_list(Nodes) ->
+ Ts1 = separate(Nodes,label,[Lbl],Ts,Spec#testspec.nodes),
+ add_tests(Ts1,Spec);
+add_tests([{label,Node,Lbl}|Ts],Spec) ->
+ Labels = Spec#testspec.label,
+ Labels1 = [{ref2node(Node,Spec#testspec.nodes),Lbl} |
+ lists:keydelete(ref2node(Node,Spec#testspec.nodes),1,Labels)],
+ add_tests(Ts,Spec#testspec{label=Labels1});
+add_tests([{label,Lbl}|Ts],Spec) ->
+ add_tests([{label,all_nodes,Lbl}|Ts],Spec);
+
%% --- cover ---
add_tests([{cover,all_nodes,File}|Ts],Spec) ->
Tests = lists:map(fun(N) -> {cover,N,File} end, list_nodes(Spec)),
@@ -878,8 +913,13 @@ skip_suites(_Node,_Dir,[],_Cmt,Tests) ->
skip_suites(Node,Dir,S,Cmt,Tests) ->
skip_suites(Node,Dir,[S],Cmt,Tests).
-skip_groups(Node,Dir,Suite,Group,Case,Cmt,Tests) when is_atom(Group) ->
- skip_groups(Node,Dir,Suite,[Group],[Case],Cmt,Tests);
+skip_groups(Node,Dir,Suite,Group,all,Cmt,Tests) when is_atom(Group) ->
+ skip_groups(Node,Dir,Suite,[Group],all,Cmt,Tests);
+skip_groups(Node,Dir,Suite,Group,Cases,Cmt,Tests) when is_atom(Group) ->
+ skip_groups(Node,Dir,Suite,[Group],Cases,Cmt,Tests);
+skip_groups(Node,Dir,Suite,Groups,Case,Cmt,Tests) when is_atom(Case),
+ Case =/= all ->
+ skip_groups(Node,Dir,Suite,Groups,[Case],Cmt,Tests);
skip_groups(Node,Dir,Suite,Groups,Cases,Cmt,Tests) when
((Cases == all) or is_list(Cases)) and is_list(Groups) ->
Suites =
@@ -1001,22 +1041,34 @@ valid_terms() ->
{cover,3},
{config,2},
{config,3},
- {userconfig, 2},
- {userconfig, 3},
+ {userconfig,2},
+ {userconfig,3},
{alias,3},
{logdir,2},
{logdir,3},
+ {label,2},
+ {label,3},
{event_handler,2},
{event_handler,3},
{event_handler,4},
+ {multiply_timetraps,2},
+ {multiply_timetraps,3},
+ {scale_timetraps,2},
+ {scale_timetraps,3},
{include,2},
{include,3},
{suites,3},
{suites,4},
+ {groups,4},
+ {groups,5},
+ {groups,6},
{cases,4},
{cases,5},
{skip_suites,4},
{skip_suites,5},
+ {skip_groups,5},
+ {skip_groups,6},
+ {skip_groups,7},
{skip_cases,5},
{skip_cases,6}
].
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index eddaf4c8b9..0a434666fa 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -619,7 +619,6 @@ get_testdir(Dir, Suite) when is_list(Suite) ->
get_testdir(Dir, _) ->
get_testdir(Dir, all).
-
%%%-----------------------------------------------------------------
%%% @spec
%%%
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index 54eed29415..ee973f6220 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -30,6 +30,7 @@
-record(testspec, {spec_dir,
nodes=[],
init=[],
+ label=[],
logdir=["."],
cover=[],
config=[],
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index 97ded5eb9a..3fb0d627a0 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -32,6 +32,7 @@ MODULES= \
ct_event_handler_SUITE \
ct_groups_test_1_SUITE \
ct_groups_test_2_SUITE \
+ ct_testspec_1_SUITE \
ct_skip_SUITE \
ct_error_SUITE \
ct_test_server_if_1_SUITE \
diff --git a/lib/common_test/test/ct_groups_test_1_SUITE_data/groups_1/test/groups_11_SUITE.erl b/lib/common_test/test/ct_groups_test_1_SUITE_data/groups_1/test/groups_11_SUITE.erl
index c6d50443d0..c69400e938 100644
--- a/lib/common_test/test/ct_groups_test_1_SUITE_data/groups_1/test/groups_11_SUITE.erl
+++ b/lib/common_test/test/ct_groups_test_1_SUITE_data/groups_1/test/groups_11_SUITE.erl
@@ -99,6 +99,7 @@ init_per_group(Group, Config) ->
{Grs,_} = grs_and_tcs(),
case lists:member(Group, Grs) of
true ->
+ ct:comment(Group),
init = ?config(suite,Config),
[{Group,Group} | Config];
false ->
@@ -109,6 +110,7 @@ end_per_group(Group, Config) ->
{Grs,_} = grs_and_tcs(),
case lists:member(Group, Grs) of
true ->
+ ct:comment(Group),
init = ?config(suite,Config),
Group = ?config(Group,Config),
ok;
diff --git a/lib/common_test/test/ct_groups_test_2_SUITE.erl b/lib/common_test/test/ct_groups_test_2_SUITE.erl
index 56e0ac30c7..c4371501b3 100644
--- a/lib/common_test/test/ct_groups_test_2_SUITE.erl
+++ b/lib/common_test/test/ct_groups_test_2_SUITE.erl
@@ -60,7 +60,7 @@ all(doc) ->
["Run smoke tests of Common Test."];
all(suite) ->
- [missing_conf, testspec_1, repeat_1].
+ [missing_conf, repeat_1].
%%--------------------------------------------------------------------
%% TEST CASES
@@ -88,25 +88,6 @@ missing_conf(Config) when is_list(Config) ->
%%%-----------------------------------------------------------------
%%%
-testspec_1(Config) when is_list(Config) ->
- DataDir = ?config(data_dir, Config),
-
- TestSpec = filename:join(DataDir, "specs/groups_2.1.spec"),
-
- {Opts,ERPid} = setup({spec,TestSpec}, Config),
- ok = ct_test_support:run(Opts, Config),
- Events = ct_test_support:get_events(ERPid, Config),
-
- ct_test_support:log_events(testspec_1,
- reformat(Events, ?eh),
- ?config(priv_dir, Config)),
-
- TestEvents = events_to_check(testspec_1),
- ok = ct_test_support:verify_events(TestEvents, Events, Config).
-
-%%%-----------------------------------------------------------------
-%%%
-
repeat_1(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
@@ -173,9 +154,6 @@ test_events(missing_conf) ->
{?eh,stop_logging,[]}
];
-test_events(testspec_1) ->
- [];
-
test_events(repeat_1) ->
[
{?eh,start_logging,{'DEF','RUNDIR'}},
diff --git a/lib/common_test/test/ct_groups_test_2_SUITE_data/specs/groups_2.1.spec b/lib/common_test/test/ct_groups_test_2_SUITE_data/specs/groups_2.1.spec
deleted file mode 100644
index 24d778ac44..0000000000
--- a/lib/common_test/test/ct_groups_test_2_SUITE_data/specs/groups_2.1.spec
+++ /dev/null
@@ -1,26 +0,0 @@
-
-{config, "../cfgs/groups_2.1.cfg"}.
-{alias, groups_2, "../groups_2"}.
-
-{suites, groups_2, groups_21_SUITE}.
-%{skip_groups, groups_2, groups_21_SUITE,
-% [test_group_1b, test_group_7], "Skip tg_1b & tg_7"}.
-{skip_cases, groups_2, groups_21_SUITE,
- [testcase_1b, testcase_3a], "Skip tc_1b & tc_3a"}.
-
-{groups, groups_2, groups_22_SUITE,
- test_group_1a}.
-{skip_cases, groups_2, groups_22_SUITE,
- testcase_1a, "Skip tc_1a"}.
-
-{groups, groups_2, groups_22_SUITE,
- test_group_1b}.
-{skip_cases, groups_2, groups_22_SUITE,
- testcase_1b, "Skip tc_1b"}.
-%{skip_groups, groups_2, groups_21_SUITE,
-% [test_group_3], "Skip tg_3"}.
-
-{groups, groups_2, groups_22_SUITE,
- test_group_5}.
-{skip_cases, groups_2, groups_22_SUITE,
- [testcase_7a, testcase_7b], "Skip tc_7a & tc_7b"}.
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index 6a75c8f789..7bfb9ffb49 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -23,7 +23,7 @@
%%%
-module(ct_test_support).
--include("test_server.hrl").
+-include_lib("test_server/include/test_server.hrl").
-include_lib("common_test/include/ct_event.hrl").
-export([init_per_suite/1, init_per_suite/2, end_per_suite/1,
@@ -111,8 +111,9 @@ init_per_testcase(_TestCase, Config) ->
case lists:keysearch(master, 1, Config) of
false->
test_server:format("See Common Test logs here:\n\n"
- "<a href=\"file://~s/all_runs.html\">~s/all_runs.html</a>",
- [LogDir,LogDir]);
+ "<a href=\"file://~s/all_runs.html\">~s/all_runs.html</a>\n"
+ "<a href=\"file://~s/index.html\">~s/index.html</a>",
+ [LogDir,LogDir,LogDir,LogDir]);
{value, _}->
test_server:format("See CT Master Test logs here:\n\n"
"<a href=\"file://~s/master_runs.html\">~s/master_runs.html</a>",
diff --git a/lib/common_test/test/ct_testspec_1_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE.erl
new file mode 100644
index 0000000000..dc399bfb4c
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE.erl
@@ -0,0 +1,433 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_testspec_1_SUITE
+%%%
+%%% Description:
+%%% Test test specifications
+%%%
+%%% The suites used for the test are located in the data directory.
+%%%-------------------------------------------------------------------
+-module(ct_testspec_1_SUITE).
+
+-compile(export_all).
+
+-include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ Config1 = ct_test_support:init_per_suite(Config),
+ Config1.
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+all(doc) ->
+ ["Run smoke tests of Common Test."];
+
+all(suite) ->
+ [all_suites, skip_all_suites,
+ suite, skip_suite,
+ all_testcases, skip_all_testcases,
+ testcase, skip_testcase,
+ all_groups, skip_all_groups,
+ group, skip_group,
+ group_all_testcases, skip_group_all_testcases,
+ group_testcase, skip_group_testcase,
+ topgroup,
+ subgroup, skip_subgroup,
+ subgroup_all_testcases, skip_subgroup_all_testcases,
+ subgroup_testcase, skip_subgroup_testcase,
+ sub_skipped_by_top,
+ testcase_in_multiple_groups].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+
+all_suites(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{label,"all_suites"},
+ {suites,TestDir,all}],
+
+ setup_and_execute(all_suites, TestSpec, Config).
+
+skip_all_suites(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{label,skip_all_suites},
+ {suites,TestDir,all},
+ {skip_suites,TestDir,all,"SKIPPED!"}],
+
+ setup_and_execute(skip_all_suites, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+suite(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{label,undefined},
+ {suites,TestDir,simple_1_SUITE}],
+
+ setup_and_execute(suite, TestSpec, Config).
+
+skip_suite(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{suites,TestDir,[simple_1_SUITE,simple_2_SUITE]},
+ {skip_suites,TestDir,simple_1_SUITE,"SKIPPED!"}],
+
+ setup_and_execute(skip_suite, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{cases,TestDir,simple_1_SUITE,all}],
+
+ setup_and_execute(all_testcases, TestSpec, Config).
+
+skip_all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{suites,TestDir,[simple_1_SUITE]},
+ {skip_cases,TestDir,simple_1_SUITE,all,"SKIPPED!"}],
+
+ setup_and_execute(skip_all_testcases, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{cases,TestDir,simple_1_SUITE,tc1}],
+
+ setup_and_execute(testcase, TestSpec, Config).
+
+skip_testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "suites_1"),
+ TestSpec = [{cases,TestDir,simple_1_SUITE,[tc1,tc2]},
+ {cases,TestDir,simple_2_SUITE,[tc2,tc1]},
+ {skip_cases,TestDir,simple_1_SUITE,[tc1],"SKIPPED!"},
+ {skip_cases,TestDir,simple_2_SUITE,tc2,"SKIPPED!"}],
+
+ setup_and_execute(skip_testcase, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+all_groups(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,all}],
+
+ setup_and_execute(all_groups, TestSpec, Config).
+
+skip_all_groups(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,all},
+ {skip_groups,TestDir,groups_11_SUITE,all,"SKIPPED!"}],
+
+ setup_and_execute(skip_all_groups, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+group(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,test_group_1a}],
+
+ setup_and_execute(group, TestSpec, Config).
+
+skip_group(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,[test_group_1a,
+ test_group_1b]},
+ {skip_groups,TestDir,groups_11_SUITE,
+ [test_group_1b,test_group_2,test_group_7],"SKIPPED!"}],
+
+ setup_and_execute(skip_group, TestSpec, Config).
+
+
+%%%-----------------------------------------------------------------
+%%%
+
+group_all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,test_group_1a,{cases,all}}],
+
+ setup_and_execute(group_all_testcases, TestSpec, Config).
+
+skip_group_all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,[test_group_1a,
+ test_group_1b]},
+ {skip_groups,TestDir,groups_11_SUITE,
+ test_group_1b,{cases,all},"SKIPPED!"},
+ {skip_groups,TestDir,groups_11_SUITE,
+ test_group_1a,{cases,all},"SKIPPED!"}],
+
+ setup_and_execute(skip_group_all_testcases, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+group_testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,test_group_1a,{cases,testcase_1a}}],
+
+ setup_and_execute(group_testcase, TestSpec, Config).
+
+skip_group_testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,test_group_1a,
+ {cases,[testcase_1a,testcase_1b]}},
+ {groups,TestDir,groups_11_SUITE,test_group_1b,
+ {cases,[testcase_1b,testcase_1a]}},
+ {skip_groups,TestDir,groups_11_SUITE,
+ test_group_1a,{cases,testcase_1b},"SKIPPED!"},
+ {skip_groups,TestDir,groups_11_SUITE,
+ test_group_1b,{cases,[testcase_1a]},"SKIPPED!"}],
+
+ setup_and_execute(skip_group_testcase, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+topgroup(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,test_group_2},
+ {groups,TestDir,groups_12_SUITE,test_group_4}],
+
+ setup_and_execute(topgroup, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+subgroup(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,test_group_3}],
+
+ setup_and_execute(subgroup, TestSpec, Config).
+
+skip_subgroup(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,[test_group_4]},
+ {skip_groups,TestDir,groups_12_SUITE,
+ test_group_8,"SKIPPED!"}],
+
+ setup_and_execute(skip_subgroup, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+subgroup_all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,
+ test_group_5,{cases,all}},
+ {groups,TestDir,groups_12_SUITE,
+ test_group_3,{cases,all}}],
+
+ setup_and_execute(subgroup_all_testcases, TestSpec, Config).
+
+skip_subgroup_all_testcases(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,test_group_4},
+ {skip_groups,TestDir,groups_12_SUITE,
+ test_group_5,{cases,all},"SKIPPED!"}],
+
+ setup_and_execute(skip_subgroup_all_testcases, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+subgroup_testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,
+ test_group_7,{cases,testcase_7a}},
+ {groups,TestDir,groups_12_SUITE,
+ test_group_3,{cases,testcase_3b}}],
+
+ setup_and_execute(subgroup_testcase, TestSpec, Config).
+
+skip_subgroup_testcase(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,test_group_5},
+ {skip_groups,TestDir,groups_12_SUITE,
+ test_group_7,{cases,[testcase_7a,testcase_7b]},"SKIPPED!"}],
+
+ setup_and_execute(skip_subgroup_testcase, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+%%!
+%%! Somewhat weird result from this one:
+%%!
+sub_skipped_by_top(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_12_SUITE,test_group_5},
+ {skip_groups,TestDir,groups_12_SUITE,test_group_4,"SKIPPED!"}],
+
+ setup_and_execute(sub_skipped_by_top, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%%
+
+testcase_in_multiple_groups(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{cases,TestDir,groups_12_SUITE,[testcase_1a,testcase_1b]},
+ {skip_cases,TestDir,groups_12_SUITE,[testcase_1b],"SKIPPED!"}],
+
+ setup_and_execute(testcase_in_multiple_groups, TestSpec, Config).
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+setup_and_execute(TCName, TestSpec, Config) ->
+ SpecFile = create_spec_file(?config(priv_dir, Config),
+ TCName, TestSpec),
+ TestTerms =
+ case lists:keymember(label, 1, TestSpec) of
+ true -> [{spec,SpecFile}];
+ false -> [{spec,SpecFile},{label,TCName}]
+ end,
+ {Opts,ERPid} = setup(TestTerms, Config),
+ ok = ct_test_support:run(Opts, Config),
+ TestSpec1 = [{logdir,proplists:get_value(logdir,Opts)},
+ {label,proplists:get_value(label,TestTerms)} | TestSpec],
+ ok = ct_test_support:run(ct, run_testspec, [TestSpec1], Config),
+ Events = ct_test_support:get_events(ERPid, Config),
+
+ ct_test_support:log_events(TCName,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config)),
+
+ TestEvents = events_to_check(TCName),
+ ok = ct_test_support:verify_events(TestEvents, Events, Config).
+
+create_spec_file(SpecDir, TCName, TestSpec) ->
+ FileName = filename:join(SpecDir,
+ atom_to_list(TCName)++".spec"),
+ {ok,Dev} = file:open(FileName, [write]),
+ [io:format(Dev, "~p.~n", [Term]) || Term <- TestSpec],
+ file:close(Dev),
+ io:format("~nTest spec created here~n~n<a href=\"file://~s\">~s</a>~n",
+ [FileName,FileName]),
+ FileName.
+
+setup(Test, Config) when is_tuple(Test) ->
+ setup([Test], Config);
+setup(Tests, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ Tests ++ [{event_handler,{?eh,EvHArgs}}],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+%reformat(Events, _EH) ->
+% Events.
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+events_to_check(Test) ->
+ %% 2 tests (ct:run_test + script_start) is default
+ events_to_check(Test, 2).
+
+events_to_check(_, 0) ->
+ [];
+events_to_check(Test, N) ->
+ test_events(Test) ++ events_to_check(Test, N-1).
+
+test_events(_) ->
+ [
+ ].
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl
new file mode 100644
index 0000000000..4f11d8a0e8
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl
@@ -0,0 +1,281 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(groups_11_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%====================================================================
+%% COMMON TEST CALLBACK FUNCTIONS
+%%====================================================================
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+groups() ->
+ [
+ {test_group_1a, [testcase_1a,testcase_1b]},
+
+ {test_group_1b, [], [testcase_1a,testcase_1b]},
+
+ {test_group_2, [], [testcase_2a,
+
+ {test_group_3, [], [testcase_3a,
+ testcase_3b]},
+ testcase_2b]},
+
+ {test_group_4, [{test_group_5, [], [testcase_5a,
+
+ {group, test_group_6},
+
+ testcase_5b]}]},
+ {test_group_6, [{group, test_group_7}]},
+
+ {test_group_7, [testcase_7a,testcase_7b]}
+ ].
+
+all() ->
+ [testcase_1,
+ {group, test_group_1a},
+ {group, test_group_1b},
+ testcase_2,
+ {group, test_group_2},
+ testcase_3,
+ {group, test_group_4}].
+
+%% this func only for internal test purposes
+grs_and_tcs() ->
+ {[
+ test_group_1a, test_group_1b,
+ test_group_2, test_group_3,
+ test_group_4, test_group_5,
+ test_group_6, test_group_7
+ ],
+ [
+ testcase_1,
+ testcase_1a, testcase_1b,
+ testcase_2,
+ testcase_2a, testcase_2b,
+ testcase_3a, testcase_3b,
+ testcase_3,
+ testcase_5a, testcase_5b,
+ testcase_7a, testcase_7b
+ ]}.
+
+%%--------------------------------------------------------------------
+%% Suite Configuration
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ [{suite,init}|Config].
+
+end_per_suite(Config) ->
+ init = ?config(suite,Config).
+
+%%--------------------------------------------------------------------
+%% Group Configuration
+%%--------------------------------------------------------------------
+
+init_per_group(Group, Config) ->
+ [{name,Group}] = ?config(tc_group_properties,Config),
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ ct:comment(Group),
+ init = ?config(suite,Config),
+ [{Group,Group} | Config];
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+end_per_group(Group, Config) ->
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ ct:comment(Group),
+ init = ?config(suite,Config),
+ Group = ?config(Group,Config),
+ ok;
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+%%--------------------------------------------------------------------
+%% Testcase Configuration
+%%--------------------------------------------------------------------
+
+init_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ [{TestCase,TestCase} | Config];
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+end_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ TestCase = ?config(TestCase,Config),
+ ok;
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Testcases
+%%--------------------------------------------------------------------
+
+testcase_1() ->
+ [].
+testcase_1(Config) ->
+ init = ?config(suite,Config),
+ testcase_1 = ?config(testcase_1,Config),
+ ok.
+
+testcase_1a() ->
+ [].
+testcase_1a(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ testcase_1a = ?config(testcase_1a,Config),
+ ok.
+testcase_1b() ->
+ [].
+testcase_1b(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1a,Config),
+ testcase_1b = ?config(testcase_1b,Config),
+ ok.
+
+testcase_2() ->
+ [].
+testcase_2(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_1a,Config),
+ undefined = ?config(test_group_1b,Config),
+ testcase_2 = ?config(testcase_2,Config),
+ ok.
+
+testcase_2a() ->
+ [].
+testcase_2a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ testcase_2a = ?config(testcase_2a,Config),
+ ok.
+testcase_2b() ->
+ [].
+testcase_2b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ undefined = ?config(testcase_2a,Config),
+ testcase_2b = ?config(testcase_2b,Config),
+ ok.
+
+testcase_3a() ->
+ [].
+testcase_3a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_2b,Config),
+ testcase_3a = ?config(testcase_3a,Config),
+ ok.
+testcase_3b() ->
+ [].
+testcase_3b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_3a,Config),
+ testcase_3b = ?config(testcase_3b,Config),
+ ok.
+
+testcase_3() ->
+ [].
+testcase_3(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_2,Config),
+ undefined = ?config(test_group_3,Config),
+ testcase_3 = ?config(testcase_3,Config),
+ ok.
+
+testcase_5a() ->
+ [].
+testcase_5a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_3,Config),
+ testcase_5a = ?config(testcase_5a,Config),
+ ok.
+testcase_5b() ->
+ [].
+testcase_5b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_5a,Config),
+ testcase_5b = ?config(testcase_5b,Config),
+ ok.
+
+testcase_7a() ->
+ [].
+testcase_7a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ testcase_7a = ?config(testcase_7a,Config),
+ ok.
+testcase_7b() ->
+ [].
+testcase_7b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ undefined = ?config(testcase_7a,Config),
+ testcase_7b = ?config(testcase_7b,Config),
+ ok.
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_12_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_12_SUITE.erl
new file mode 100644
index 0000000000..69c06f9b83
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_12_SUITE.erl
@@ -0,0 +1,344 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(groups_12_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%====================================================================
+%% COMMON TEST CALLBACK FUNCTIONS
+%%====================================================================
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+groups() ->
+ [
+ {test_group_1a, [shuffle], [testcase_1a,testcase_1b,testcase_1c]},
+
+ {test_group_1b, [parallel], [testcase_1a,testcase_1b]},
+
+ {test_group_2, [parallel], [testcase_2a,
+
+ {test_group_3, [{repeat,2}],
+ [testcase_3a, testcase_3b]},
+
+ testcase_2b]},
+
+ {test_group_4, [{test_group_5, [parallel], [testcase_5a,
+
+ {group, test_group_6},
+
+ testcase_5b]}]},
+
+ {test_group_6, [parallel], [{group, test_group_7},
+ {group, test_group_8}]},
+
+ {test_group_7, [sequence], [testcase_7a,testcase_7b]},
+
+ {test_group_8, [shuffle,sequence], [testcase_8a,testcase_8b]}
+ ].
+
+all() ->
+ [{group, test_group_1a},
+ {group, test_group_1b},
+ testcase_1,
+ testcase_2,
+ {group, test_group_2},
+ testcase_3,
+ {group, test_group_4}].
+
+%% this func only for internal test purposes
+grs_and_tcs() ->
+ {[
+ test_group_1a, test_group_1b,
+ test_group_2, test_group_3,
+ test_group_4, test_group_5,
+ test_group_6, test_group_7,
+ test_group_8
+ ],
+ [
+ testcase_1a, testcase_1b, testcase_1c,
+ testcase_1,
+ testcase_2,
+ testcase_2a, testcase_2b,
+ testcase_3a, testcase_3b,
+ testcase_3,
+ testcase_5a, testcase_5b,
+ testcase_7a, testcase_7b,
+ testcase_8a, testcase_8b
+ ]}.
+
+%%--------------------------------------------------------------------
+%% Suite Configuration
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ [{suite,init}|Config].
+
+end_per_suite(Config) ->
+ init = ?config(suite,Config).
+
+%%--------------------------------------------------------------------
+%% Group Configuration
+%%--------------------------------------------------------------------
+
+init_per_group(Group, Config) ->
+ Cmt =
+ case {Group,?config(tc_group_properties,Config)} of
+ {test_group_1a,[{shuffle,S},{name,test_group_1a}]} ->
+ io_lib:format("shuffled, ~w", [S]);
+ {test_group_1b,[{name,test_group_1b},parallel]} -> "parallel";
+ {test_group_2,[{name,test_group_2},parallel]} -> "parallel";
+ {test_group_3,[{name,test_group_3},{repeat,2}]} -> "repeat 2";
+ {test_group_3,[{name,test_group_3}]} -> "repeat 1";
+ {test_group_4,[{name,test_group_4}]} -> ok;
+ {test_group_5,[{name,test_group_5},parallel]} -> "parallel";
+ {test_group_6,[{name,test_group_6},parallel]} -> "parallel";
+ {test_group_7,[{name,test_group_7},sequence]} -> "sequence";
+ {test_group_8,[{shuffle,_},{name,test_group_8},sequence]} ->
+ "shuffle & sequence"
+ end,
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ init = ?config(suite,Config),
+ ct:comment(io_lib:format("~w, ~s", [Group,Cmt])),
+ [{Group,Group} | Config];
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+end_per_group(Group, Config) ->
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ init = ?config(suite,Config),
+ Group = ?config(Group,Config),
+ ok;
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+%%--------------------------------------------------------------------
+%% Testcase Configuration
+%%--------------------------------------------------------------------
+
+init_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ [{TestCase,TestCase} | Config];
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+end_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ TestCase = ?config(TestCase,Config),
+ ok;
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Testcases
+%%--------------------------------------------------------------------
+
+testcase_1a() ->
+ [].
+testcase_1a(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ testcase_1a = ?config(testcase_1a,Config),
+ ok.
+testcase_1b() ->
+ [].
+testcase_1b(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1a,Config),
+ testcase_1b = ?config(testcase_1b,Config),
+ ok.
+
+testcase_1c() ->
+ [].
+testcase_1c(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1b,Config),
+ testcase_1c = ?config(testcase_1c,Config),
+ ok.
+
+testcase_1() ->
+ [].
+testcase_1(Config) ->
+ init = ?config(suite,Config),
+ testcase_1 = ?config(testcase_1,Config),
+ ok.
+
+testcase_2() ->
+ [].
+testcase_2(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_1a,Config),
+ undefined = ?config(test_group_1b,Config),
+ testcase_2 = ?config(testcase_2,Config),
+ ok.
+
+testcase_2a() ->
+ [].
+testcase_2a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ testcase_2a = ?config(testcase_2a,Config),
+ ok.
+testcase_2b() ->
+ [].
+testcase_2b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ undefined = ?config(testcase_2a,Config),
+ testcase_2b = ?config(testcase_2b,Config),
+ ok.
+
+testcase_3a() ->
+ [].
+testcase_3a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_2b,Config),
+ testcase_3a = ?config(testcase_3a,Config),
+ ok.
+testcase_3b() ->
+ [].
+testcase_3b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_3a,Config),
+ testcase_3b = ?config(testcase_3b,Config),
+ ok.
+
+testcase_3() ->
+ [].
+testcase_3(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_2,Config),
+ undefined = ?config(test_group_3,Config),
+ testcase_3 = ?config(testcase_3,Config),
+ ok.
+
+testcase_5a() ->
+ [].
+testcase_5a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_3,Config),
+ testcase_5a = ?config(testcase_5a,Config),
+ %% increase chance the done event will come
+ %% during execution of subgroup (could be
+ %% tricky to handle)
+ timer:sleep(3),
+ ok.
+testcase_5b() ->
+ [].
+testcase_5b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_5a,Config),
+ testcase_5b = ?config(testcase_5b,Config),
+ ok.
+
+testcase_7a() ->
+ [].
+testcase_7a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ testcase_7a = ?config(testcase_7a,Config),
+ ok.
+testcase_7b() ->
+ [].
+testcase_7b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ undefined = ?config(testcase_7a,Config),
+ testcase_7b = ?config(testcase_7b,Config),
+ ok.
+
+testcase_8a() ->
+ [].
+testcase_8a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_8 = ?config(test_group_8,Config),
+ testcase_8a = ?config(testcase_8a,Config),
+ ok.
+testcase_8b() ->
+ [].
+testcase_8b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_8 = ?config(test_group_8,Config),
+ undefined = ?config(testcase_8a,Config),
+ testcase_8b = ?config(testcase_8b,Config),
+ ok.
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_21_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_21_SUITE.erl
new file mode 100644
index 0000000000..2533ac8e84
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_21_SUITE.erl
@@ -0,0 +1,281 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(groups_21_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%====================================================================
+%% COMMON TEST CALLBACK FUNCTIONS
+%%====================================================================
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+groups() ->
+ [
+ {test_group_1a, [testcase_1a,testcase_1b]},
+
+ {test_group_1b, [], [testcase_1a,testcase_1b]},
+
+ {test_group_2, [], [testcase_2a,
+
+ {test_group_3, [], [testcase_3a,
+ testcase_3b]},
+ testcase_2b]},
+
+ {test_group_4, [{test_group_5, [], [testcase_5a,
+
+ {group, test_group_6},
+
+ testcase_5b]}]},
+
+ {test_group_6, [{group, test_group_7}]},
+
+ {test_group_7, [testcase_7a,testcase_7b]}
+ ].
+
+all() ->
+ [testcase_1,
+ {group, test_group_1a},
+ {group, test_group_1b},
+ testcase_2,
+ {group, test_group_2},
+ testcase_3,
+ {group, test_group_4}].
+
+%% this func only for internal test purposes
+grs_and_tcs() ->
+ {[
+ test_group_1a, test_group_1b,
+ test_group_2, test_group_3,
+ test_group_4, test_group_5,
+ test_group_6, test_group_7
+ ],
+ [
+ testcase_1,
+ testcase_1a, testcase_1b,
+ testcase_2,
+ testcase_2a, testcase_2b,
+ testcase_3a, testcase_3b,
+ testcase_3,
+ testcase_5a, testcase_5b,
+ testcase_7a, testcase_7b
+ ]}.
+
+%%--------------------------------------------------------------------
+%% Suite Configuration
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ [{suite,init}|Config].
+
+end_per_suite(Config) ->
+ init = ?config(suite,Config).
+
+%%--------------------------------------------------------------------
+%% Group Configuration
+%%--------------------------------------------------------------------
+
+init_per_group(Group, Config) ->
+ [{name,Group}] = ?config(tc_group_properties,Config),
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ ct:comment(io_lib:format("~w", [Group])),
+ init = ?config(suite,Config),
+ [{Group,Group} | Config];
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+end_per_group(Group, Config) ->
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ init = ?config(suite,Config),
+ Group = ?config(Group,Config),
+ ok;
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+%%--------------------------------------------------------------------
+%% Testcase Configuration
+%%--------------------------------------------------------------------
+
+init_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ [{TestCase,TestCase} | Config];
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+end_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ TestCase = ?config(TestCase,Config),
+ ok;
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Testcases
+%%--------------------------------------------------------------------
+
+testcase_1() ->
+ [].
+testcase_1(Config) ->
+ init = ?config(suite,Config),
+ testcase_1 = ?config(testcase_1,Config),
+ ok.
+
+testcase_1a() ->
+ [].
+testcase_1a(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ testcase_1a = ?config(testcase_1a,Config),
+ ok.
+testcase_1b() ->
+ [].
+testcase_1b(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1a,Config),
+ testcase_1b = ?config(testcase_1b,Config),
+ ok.
+
+testcase_2() ->
+ [].
+testcase_2(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_1a,Config),
+ undefined = ?config(test_group_1b,Config),
+ testcase_2 = ?config(testcase_2,Config),
+ ok.
+
+testcase_2a() ->
+ [].
+testcase_2a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ testcase_2a = ?config(testcase_2a,Config),
+ ok.
+testcase_2b() ->
+ [].
+testcase_2b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ undefined = ?config(testcase_2a,Config),
+ testcase_2b = ?config(testcase_2b,Config),
+ ok.
+
+testcase_3a() ->
+ [].
+testcase_3a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_2b,Config),
+ testcase_3a = ?config(testcase_3a,Config),
+ ok.
+testcase_3b() ->
+ [].
+testcase_3b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_3a,Config),
+ testcase_3b = ?config(testcase_3b,Config),
+ ok.
+
+testcase_3() ->
+ [].
+testcase_3(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_2,Config),
+ undefined = ?config(test_group_3,Config),
+ testcase_3 = ?config(testcase_3,Config),
+ ok.
+
+testcase_5a() ->
+ [].
+testcase_5a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_3,Config),
+ testcase_5a = ?config(testcase_5a,Config),
+ ok.
+testcase_5b() ->
+ [].
+testcase_5b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_5a,Config),
+ testcase_5b = ?config(testcase_5b,Config),
+ ok.
+
+testcase_7a() ->
+ [].
+testcase_7a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ testcase_7a = ?config(testcase_7a,Config),
+ ok.
+testcase_7b() ->
+ [].
+testcase_7b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ undefined = ?config(testcase_7a,Config),
+ testcase_7b = ?config(testcase_7b,Config),
+ ok.
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_22_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_22_SUITE.erl
new file mode 100644
index 0000000000..cd517876df
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_2/groups_22_SUITE.erl
@@ -0,0 +1,314 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(groups_22_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%====================================================================
+%% COMMON TEST CALLBACK FUNCTIONS
+%%====================================================================
+
+suite() ->
+ [{timetrap,{minutes,1}}].
+
+groups() ->
+ [
+ {test_group_1a, [shuffle], [testcase_1a,testcase_1b,testcase_1c]},
+
+ {test_group_1b, [parallel], [testcase_1a,testcase_1b]},
+
+ {test_group_2, [parallel], [testcase_2a,
+
+ {test_group_3, [{repeat,1}],
+ [testcase_3a, testcase_3b]},
+
+ testcase_2b]},
+
+ {test_group_4, [{test_group_5, [parallel], [testcase_5a,
+
+ {group, test_group_6},
+
+ testcase_5b]}]},
+
+ {test_group_6, [parallel], [{group, test_group_7}]},
+
+ {test_group_7, [sequence], [testcase_7a,testcase_7b]}
+ ].
+
+all() ->
+ [{group, test_group_1a},
+ {group, test_group_1b},
+ testcase_1,
+ testcase_2,
+ {group, test_group_2},
+ testcase_3,
+ {group, test_group_4}].
+
+%% this func only for internal test purposes
+grs_and_tcs() ->
+ {[
+ test_group_1a, test_group_1b,
+ test_group_2, test_group_3,
+ test_group_4, test_group_5,
+ test_group_6, test_group_7
+ ],
+ [
+ testcase_1a, testcase_1b, testcase_1c,
+ testcase_1,
+ testcase_2,
+ testcase_2a, testcase_2b,
+ testcase_3a, testcase_3b,
+ testcase_3,
+ testcase_5a, testcase_5b,
+ testcase_7a, testcase_7b
+ ]}.
+
+%%--------------------------------------------------------------------
+%% Suite Configuration
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ [{suite,init}|Config].
+
+end_per_suite(Config) ->
+ init = ?config(suite,Config).
+
+%%--------------------------------------------------------------------
+%% Group Configuration
+%%--------------------------------------------------------------------
+
+init_per_group(Group, Config) ->
+ Cmt =
+ case {Group,?config(tc_group_properties,Config)} of
+ {test_group_1a,[{shuffle,S},{name,test_group_1a}]} ->
+ io_lib:format("shuffled, ~w", [S]);
+ {test_group_1b,[{name,test_group_1b},parallel]} -> "parallel";
+ {test_group_2,[{name,test_group_2},parallel]} -> "parallel";
+ {test_group_3,[{name,test_group_3},{repeat,1}]} -> "repeat 1";
+ {test_group_3,[{name,test_group_3}]} -> "repeat 0";
+ {test_group_4,[{name,test_group_4}]} -> ok;
+ {test_group_5,[{name,test_group_5},parallel]} -> "parallel";
+ {test_group_6,[{name,test_group_6},parallel]} -> "parallel";
+ {test_group_7,[{name,test_group_7},sequence]} -> "sequence"
+ end,
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ init = ?config(suite,Config),
+ ct:comment(io_lib:format("~w, ~s", [Group,Cmt])),
+ [{Group,Group} | Config];
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+end_per_group(Group, Config) ->
+ {Grs,_} = grs_and_tcs(),
+ case lists:member(Group, Grs) of
+ true ->
+ init = ?config(suite,Config),
+ Group = ?config(Group,Config),
+ ok;
+ false ->
+ ct:fail({bad_group,Group})
+ end.
+
+%%--------------------------------------------------------------------
+%% Testcase Configuration
+%%--------------------------------------------------------------------
+
+init_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ [{TestCase,TestCase} | Config];
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+end_per_testcase(TestCase, Config) ->
+ {_,TCs} = grs_and_tcs(),
+ case lists:member(TestCase, TCs) of
+ true ->
+ init = ?config(suite,Config),
+ TestCase = ?config(TestCase,Config),
+ ok;
+ false ->
+ ct:fail({unknown_testcase,TestCase})
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Testcases
+%%--------------------------------------------------------------------
+
+testcase_1a() ->
+ [].
+testcase_1a(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ testcase_1a = ?config(testcase_1a,Config),
+ ok.
+testcase_1b() ->
+ [].
+testcase_1b(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1a,Config),
+ testcase_1b = ?config(testcase_1b,Config),
+ ok.
+
+testcase_1c() ->
+ [].
+testcase_1c(Config) ->
+ init = ?config(suite,Config),
+ case ?config(test_group_1a,Config) of
+ test_group_1a -> ok;
+ _ ->
+ case ?config(test_group_1b,Config) of
+ test_group_1b -> ok;
+ _ -> ct:fail(no_group_data)
+ end
+ end,
+ undefined = ?config(testcase_1b,Config),
+ testcase_1c = ?config(testcase_1c,Config),
+ ok.
+
+testcase_1() ->
+ [].
+testcase_1(Config) ->
+ init = ?config(suite,Config),
+ testcase_1 = ?config(testcase_1,Config),
+ ok.
+
+testcase_2() ->
+ [].
+testcase_2(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_1a,Config),
+ undefined = ?config(test_group_1b,Config),
+ testcase_2 = ?config(testcase_2,Config),
+ ok.
+
+testcase_2a() ->
+ [].
+testcase_2a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ testcase_2a = ?config(testcase_2a,Config),
+ ok.
+testcase_2b() ->
+ [].
+testcase_2b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ undefined = ?config(testcase_2a,Config),
+ testcase_2b = ?config(testcase_2b,Config),
+ ok.
+
+testcase_3a() ->
+ [].
+testcase_3a(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_2b,Config),
+ testcase_3a = ?config(testcase_3a,Config),
+ ok.
+testcase_3b() ->
+ [].
+testcase_3b(Config) ->
+ init = ?config(suite,Config),
+ test_group_2 = ?config(test_group_2,Config),
+ test_group_3 = ?config(test_group_3,Config),
+ undefined = ?config(testcase_3a,Config),
+ testcase_3b = ?config(testcase_3b,Config),
+ ok.
+
+testcase_3() ->
+ [].
+testcase_3(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_2,Config),
+ undefined = ?config(test_group_3,Config),
+ testcase_3 = ?config(testcase_3,Config),
+ ok.
+
+testcase_5a() ->
+ [].
+testcase_5a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_3,Config),
+ testcase_5a = ?config(testcase_5a,Config),
+ %% increase chance the done event will come
+ %% during execution of subgroup (could be
+ %% tricky to handle)
+ timer:sleep(3),
+ ok.
+testcase_5b() ->
+ [].
+testcase_5b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ undefined = ?config(testcase_5a,Config),
+ testcase_5b = ?config(testcase_5b,Config),
+ ok.
+
+testcase_7a() ->
+ [].
+testcase_7a(Config) ->
+ init = ?config(suite,Config),
+ undefined = ?config(test_group_3,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ testcase_7a = ?config(testcase_7a,Config),
+ ok.
+testcase_7b() ->
+ [].
+testcase_7b(Config) ->
+ init = ?config(suite,Config),
+ test_group_4 = ?config(test_group_4,Config),
+ test_group_5 = ?config(test_group_5,Config),
+ test_group_6 = ?config(test_group_6,Config),
+ test_group_7 = ?config(test_group_7,Config),
+ undefined = ?config(testcase_7a,Config),
+ testcase_7b = ?config(testcase_7b,Config),
+ ok.
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_1_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_1_SUITE.erl
new file mode 100644
index 0000000000..b789851134
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_1_SUITE.erl
@@ -0,0 +1,146 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(simple_1_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% COMMON TEST CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Function: suite() -> Info
+%%
+%% Info = [tuple()]
+%% List of key/value pairs.
+%%
+%% Description: Returns list of tuples to set default properties
+%% for the suite.
+%%
+%% Note: The suite/0 function is only meant to be used to return
+%% default data values, not perform any other operations.
+%%--------------------------------------------------------------------
+suite() ->
+ [
+ {timetrap,{seconds,10}}
+ ].
+
+%%--------------------------------------------------------------------
+%% Function: init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%%
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Reason = term()
+%% The reason for skipping the suite.
+%%
+%% Description: Initialization before the suite.
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ [{ips,ips_data} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
+%%
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Cleanup after the suite.
+%%--------------------------------------------------------------------
+end_per_suite(Config) ->
+ ips_data = ?config(ips, Config).
+
+%%--------------------------------------------------------------------
+%% Function: init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%%
+%% TestCase = atom()
+%% Name of the test case that is about to run.
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Reason = term()
+%% The reason for skipping the test case.
+%%
+%% Description: Initialization before each test case.
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_testcase(TestCase, Config) ->
+ [{TestCase,{TestCase,data}} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1}
+%%
+%% TestCase = atom()
+%% Name of the test case that is finished.
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Cleanup after each test case.
+%%--------------------------------------------------------------------
+end_per_testcase(TestCase, Config) ->
+ {TestCase,data} = ?config(TestCase, Config).
+
+%%--------------------------------------------------------------------
+%% Function: all() -> TestCases | {skip,Reason}
+%%
+%% TestCases = [TestCase | {sequence,SeqName}]
+%% TestCase = atom()
+%% Name of a test case.
+%% SeqName = atom()
+%% Name of a test case sequence.
+%% Reason = term()
+%% The reason for skipping all test cases.
+%%
+%% Description: Returns the list of test cases that are to be executed.
+%%--------------------------------------------------------------------
+all() ->
+ [tc1,
+ tc2].
+
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+tc1() ->
+ [{userdata,{info, "This is a testcase"}}].
+
+tc1(Config) ->
+ ips_data = ?config(ips, Config),
+ {tc1,data} = ?config(tc1, Config),
+ ok.
+
+tc2() ->
+ [{timetrap,5000}].
+
+tc2(Config) ->
+ ips_data = ?config(ips, Config),
+ undefined = ?config(tc1, Config),
+ {tc2,data} = ?config(tc2, Config),
+ ok.
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_2_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_2_SUITE.erl
new file mode 100644
index 0000000000..eb7e9cdf7b
--- /dev/null
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/suites_1/simple_2_SUITE.erl
@@ -0,0 +1,146 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(simple_2_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% COMMON TEST CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Function: suite() -> Info
+%%
+%% Info = [tuple()]
+%% List of key/value pairs.
+%%
+%% Description: Returns list of tuples to set default properties
+%% for the suite.
+%%
+%% Note: The suite/0 function is only meant to be used to return
+%% default data values, not perform any other operations.
+%%--------------------------------------------------------------------
+suite() ->
+ [
+ {timetrap,{seconds,10}}
+ ].
+
+%%--------------------------------------------------------------------
+%% Function: init_per_suite(Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%%
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Reason = term()
+%% The reason for skipping the suite.
+%%
+%% Description: Initialization before the suite.
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ [{ips,ips_data} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
+%%
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Cleanup after the suite.
+%%--------------------------------------------------------------------
+end_per_suite(Config) ->
+ ips_data = ?config(ips, Config).
+
+%%--------------------------------------------------------------------
+%% Function: init_per_testcase(TestCase, Config0) ->
+%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
+%%
+%% TestCase = atom()
+%% Name of the test case that is about to run.
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Reason = term()
+%% The reason for skipping the test case.
+%%
+%% Description: Initialization before each test case.
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_testcase(TestCase, Config) ->
+ [{TestCase,{TestCase,data}} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_testcase(TestCase, Config0) ->
+%% void() | {save_config,Config1}
+%%
+%% TestCase = atom()
+%% Name of the test case that is finished.
+%% Config0 = Config1 = [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Cleanup after each test case.
+%%--------------------------------------------------------------------
+end_per_testcase(TestCase, Config) ->
+ {TestCase,data} = ?config(TestCase, Config).
+
+%%--------------------------------------------------------------------
+%% Function: all() -> TestCases | {skip,Reason}
+%%
+%% TestCases = [TestCase | {sequence,SeqName}]
+%% TestCase = atom()
+%% Name of a test case.
+%% SeqName = atom()
+%% Name of a test case sequence.
+%% Reason = term()
+%% The reason for skipping all test cases.
+%%
+%% Description: Returns the list of test cases that are to be executed.
+%%--------------------------------------------------------------------
+all() ->
+ [tc1,
+ tc2].
+
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+tc1() ->
+ [{userdata,{info, "This is a testcase"}}].
+
+tc1(Config) ->
+ ips_data = ?config(ips, Config),
+ {tc1,data} = ?config(tc1, Config),
+ ok.
+
+tc2() ->
+ [{timetrap,5000}].
+
+tc2(Config) ->
+ ips_data = ?config(ips, Config),
+ undefined = ?config(tc1, Config),
+ {tc2,data} = ?config(tc2, Config),
+ ok.
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index 2947c6a152..413ef21df3 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1,3 +1,3 @@
-COMMON_TEST_VSN = 1.5
+COMMON_TEST_VSN = 1.5.1
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl
index 4ffe8bc606..9164259a94 100644
--- a/lib/compiler/src/beam_dict.erl
+++ b/lib/compiler/src/beam_dict.erl
@@ -33,7 +33,7 @@
exports = [] :: [{label(), arity(), label()}],
locals = [] :: [{label(), arity(), label()}],
imports = gb_trees:empty() :: gb_tree(), %{{M,F,A},Index}
- strings = [] :: [string()], %String pool
+ strings = [] :: string(), %String pool
lambdas = [], %[{...}]
literals = dict:new() :: dict(), %Format: {Literal,Number}
next_atom = 1 :: pos_integer(),
@@ -219,7 +219,7 @@ my_term_to_binary(Term) ->
%% Search for string Str in the string pool Pool.
%% old_string(Str, Pool) -> none | Index
--spec old_string(string(), [string()]) -> 'none' | pos_integer().
+-spec old_string(string(), string()) -> 'none' | pos_integer().
old_string([C|Str]=Str0, [C|Pool]) ->
case lists:prefix(Str, Pool) of
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 4642fb68b3..ed7a9144a8 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -41,8 +41,7 @@
-type option() :: atom() | {atom(), term()} | {'d', atom(), term()}.
--type line() :: integer().
--type err_info() :: {line(), module(), term()}. %% ErrorDescriptor
+-type err_info() :: {erl_scan:line(), module(), term()}. %% ErrorDescriptor
-type errors() :: [{file:filename(), [err_info()]}].
-type warnings() :: [{file:filename(), [err_info()]}].
-type mod_ret() :: {'ok', module()}
@@ -70,7 +69,7 @@
file(File) -> file(File, ?DEFAULT_OPTIONS).
--spec file(module() | file:filename(), [option()]) -> comp_ret().
+-spec file(module() | file:filename(), [option()] | option()) -> comp_ret().
file(File, Opts) when is_list(Opts) ->
do_compile({file,File}, Opts++env_default_opts());
@@ -88,6 +87,8 @@ forms(Forms, Opt) when is_atom(Opt) ->
%% would have generated a Beam file, false otherwise (if only a binary or a
%% listing file would have been generated).
+-spec output_generated([option()]) -> boolean().
+
output_generated(Opts) ->
noenv_output_generated(Opts++env_default_opts()).
@@ -96,6 +97,8 @@ output_generated(Opts) ->
%% for default options.
%%
+-spec noenv_file(module() | file:filename(), [option()] | option()) -> comp_ret().
+
noenv_file(File, Opts) when is_list(Opts) ->
do_compile({file,File}, Opts);
noenv_file(File, Opt) ->
@@ -106,6 +109,8 @@ noenv_forms(Forms, Opts) when is_list(Opts) ->
noenv_forms(Forms, Opt) when is_atom(Opt) ->
noenv_forms(Forms, [Opt|?DEFAULT_OPTIONS]).
+-spec noenv_output_generated([option()]) -> boolean().
+
noenv_output_generated(Opts) ->
any(fun ({save_binary,_F}) -> true;
(_Other) -> false
@@ -216,16 +221,16 @@ format_error({module_name,Mod,Filename}) ->
[Mod,Filename]).
%% The compile state record.
--record(compile, {filename="",
- dir="",
- base="",
- ifile="",
- ofile="",
+-record(compile, {filename="" :: file:filename(),
+ dir="" :: file:filename(),
+ base="" :: file:filename(),
+ ifile="" :: file:filename(),
+ ofile="" :: file:filename(),
module=[],
code=[],
core_code=[],
abstract_code=[], %Abstract code for debugger.
- options=[],
+ options=[] :: [option()],
errors=[],
warnings=[]}).
@@ -362,7 +367,7 @@ mpf(Ms) ->
[{File,[M || {F,M} <- Ms, F =:= File]} ||
File <- lists:usort([F || {F,_} <- Ms])].
-%% passes(form|file, [Option]) -> [{Name,PassFun}]
+%% passes(forms|file, [Option]) -> [{Name,PassFun}]
%% Figure out which passes that need to be run.
passes(forms, Opts) ->
@@ -828,7 +833,6 @@ get_core_transforms(Opts) -> [M || {core_transform,M} <- Opts].
core_transforms(St) ->
%% The options field holds the complete list of options at this
-
Ts = get_core_transforms(St#compile.options),
foldl_core_transforms(St, Ts).
@@ -1172,12 +1176,12 @@ write_binary(Name, Bin, St) ->
%% report_errors(State) -> ok
%% report_warnings(State) -> ok
-report_errors(St) ->
- case member(report_errors, St#compile.options) of
+report_errors(#compile{options=Opts,errors=Errors}) ->
+ case member(report_errors, Opts) of
true ->
foreach(fun ({{F,_L},Eds}) -> list_errors(F, Eds);
({F,Eds}) -> list_errors(F, Eds) end,
- St#compile.errors);
+ Errors);
false -> ok
end.
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 39512d27e1..19fa495b7d 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -195,8 +195,8 @@ sha_final(_Context) -> ?nif_stub.
%%
%% MD5_MAC
%%
--spec md5_mac(iodata(), iodata()) -> binary.
--spec md5_mac_96(iodata(), iodata()) -> binary.
+-spec md5_mac(iodata(), iodata()) -> binary().
+-spec md5_mac_96(iodata(), iodata()) -> binary().
md5_mac(Key, Data) ->
md5_mac_n(Key,Data,16).
@@ -209,8 +209,8 @@ md5_mac_n(_Key,_Data,_MacSz) -> ?nif_stub.
%%
%% SHA_MAC
%%
--spec sha_mac(iodata(), iodata()) -> binary.
--spec sha_mac_96(iodata(), iodata()) -> binary.
+-spec sha_mac(iodata(), iodata()) -> binary().
+-spec sha_mac_96(iodata(), iodata()) -> binary().
sha_mac(Key, Data) ->
sha_mac_n(Key,Data,20).
diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl
index 7ccb9793a3..a26b16c82d 100644
--- a/lib/debugger/src/dbg_icmd.erl
+++ b/lib/debugger/src/dbg_icmd.erl
@@ -94,7 +94,7 @@ break_p(Mod, Line, Le, Bs) ->
Bool = case Cond of
null -> true;
{CM, CN} ->
- try apply(CM, CN, [Bs]) of
+ try CM:CN(Bs) of
true -> true;
false -> false;
_Term -> false
@@ -245,7 +245,7 @@ handle_int_msg({attached, AttPid}, Status, _Bs,
%% Tell attached process in which module evalution is located
if
- Le==1 ->
+ Le =:= 1 ->
tell_attached({attached, undefined, -1, get(trace)});
true ->
tell_attached({attached, M, Line, get(trace)}),
@@ -269,7 +269,7 @@ handle_int_msg(detached, _Status, _Bs, _Ieval) ->
handle_int_msg({old_code,Mod}, Status, Bs,
#ieval{level=Le,module=M}=Ieval) ->
if
- Status==idle, Le==1 ->
+ Status =:= idle, Le =:= 1 ->
erase([Mod|db]),
put(cache, []);
true ->
@@ -352,9 +352,9 @@ set_stack_trace(true) ->
set_stack_trace(all);
set_stack_trace(Flag) ->
if
- Flag==false ->
+ Flag =:= false ->
put(stack, []);
- Flag==no_tail; Flag==all ->
+ Flag =:= no_tail; Flag =:= all ->
ignore
end,
put(trace_stack, Flag),
@@ -367,7 +367,7 @@ bindings(Bs, nostack) ->
Bs;
bindings(Bs, SP) ->
case dbg_ieval:stack_level() of
- Le when SP>Le ->
+ Le when SP > Le ->
Bs;
_ ->
dbg_ieval:bindings(SP)
@@ -377,7 +377,6 @@ messages() ->
{messages, Msgs} = erlang:process_info(get(self), messages),
Msgs.
-
%%====================================================================
%% Evaluating expressions within process context
%%====================================================================
@@ -398,7 +397,7 @@ eval_restricted({From,_Mod,Cmd,SP}, Bs) ->
From ! {self(), {eval_rsp, Rsp}}
end.
-eval_nonrestricted({From,Mod,Cmd,SP}, Bs, #ieval{level=Le}) when SP<Le->
+eval_nonrestricted({From,Mod,Cmd,SP}, Bs, #ieval{level=Le}) when SP < Le->
%% Evaluate in stack
eval_restricted({From, Mod, Cmd, SP}, Bs),
Bs;
@@ -424,15 +423,15 @@ eval_nonrestricted({From, _Mod, Cmd, _SP}, Bs,
eval_nonrestricted_1({match,_,{var,_,Var},Expr}, Bs, Ieval) ->
{value,Res,Bs2} =
dbg_ieval:eval_expr(Expr, Bs, Ieval#ieval{last_call=false}),
- Bs3 = case lists:keysearch(Var, 1, Bs) of
- {value, {Var,_Value}} ->
+ Bs3 = case lists:keyfind(Var, 1, Bs) of
+ {Var,_Value} ->
lists:keyreplace(Var, 1, Bs2, {Var,Res});
false -> [{Var,Res} | Bs2]
end,
{Res,Bs3};
eval_nonrestricted_1({var,_,Var}, Bs, _Ieval) ->
- Res = case lists:keysearch(Var, 1, Bs) of
- {value, {Var, Value}} -> Value;
+ Res = case lists:keyfind(Var, 1, Bs) of
+ {Var, Value} -> Value;
false -> unbound
end,
{Res,Bs};
@@ -458,7 +457,6 @@ parse_cmd(Cmd, LineNo) ->
{ok,Forms} = erl_parse:parse_exprs(Tokens),
Forms.
-
%%====================================================================
%% Library functions for attached process handling
%%====================================================================
@@ -470,13 +468,12 @@ tell_attached(Msg) ->
AttPid ! {self(), Msg}
end.
-
%%====================================================================
%% get_binding/2
%%====================================================================
get_binding(Var, Bs) ->
- case lists:keysearch(Var, 1, Bs) of
- {value, {Var, Value}} -> {value, Value};
+ case lists:keyfind(Var, 1, Bs) of
+ {Var, Value} -> {value, Value};
false -> unbound
end.
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index c13fda7ac1..476dfd8796 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -120,9 +120,9 @@ check_exit_msg({'EXIT', Int, Reason}, _Bs, #ieval{level=Le}) ->
%% This *must* be interpreter which has terminated,
%% we are not linked to anyone else
if
- Le==1 ->
+ Le =:= 1 ->
exit(Reason);
- Le>1 ->
+ Le > 1 ->
exit({Int, Reason})
end;
check_exit_msg({'DOWN',_,_,_,Reason}, Bs,
@@ -139,9 +139,9 @@ check_exit_msg({'DOWN',_,_,_,Reason}, Bs,
%% importance in this case
%% If we don't save them, however, post-mortem analysis
%% of the process isn't possible
- undefined when Le==1 -> % died outside interpreted code
+ undefined when Le =:= 1 -> % died outside interpreted code
{};
- undefined when Le>1 ->
+ undefined when Le > 1 ->
StackBin = term_to_binary(get(stack)),
{{Mod, Li}, Bs, StackBin};
@@ -152,9 +152,9 @@ check_exit_msg({'DOWN',_,_,_,Reason}, Bs,
dbg_iserver:cast(get(int), {set_exit_info,self(),ExitInfo}),
if
- Le==1 ->
+ Le =:= 1 ->
exit(Reason);
- Le>1 ->
+ Le > 1 ->
exit({get(self), Reason})
end;
check_exit_msg(_Msg, _Bs, _Ieval) ->
@@ -271,7 +271,7 @@ meta_loop(Debugged, Bs, #ieval{level=Le} = Ieval) ->
end;
%% Re-entry to Meta from non-interpreted code
- {re_entry, Debugged, {eval,{M,F,As}}} when Le==1 ->
+ {re_entry, Debugged, {eval,{M,F,As}}} when Le =:= 1 ->
%% Reset process dictionary
%% This is really only necessary if the process left
%% interpreted code at a call level > 1
@@ -346,7 +346,7 @@ push(MFA, Bs, #ieval{level=Le,module=Cm,line=Li,last_call=Lc}) ->
[] -> put(stack, [Entry]);
[_Entry|Entries] -> put(stack, [Entry|Entries])
end;
- _ -> % all | no_tail when Lc==false
+ _ -> % all | no_tail when Lc =:= false
put(stack, [Entry|get(stack)])
end.
@@ -413,10 +413,10 @@ sublist(L, Start, Length) ->
lists:sublist(L, Start, Length).
fix_stacktrace2([{_,{{M,F,As1},_,_}}, {_,{{M,F,As2},_,_}}|_])
- when length(As1)==length(As2) ->
+ when length(As1) =:= length(As2) ->
[{M,F,As1}];
fix_stacktrace2([{_,{{Fun,As1},_,_}}, {_,{{Fun,As2},_,_}}|_])
- when length(As1)==length(As2) ->
+ when length(As1) =:= length(As2) ->
[{Fun,As1}];
fix_stacktrace2([{_,{MFA,_,_}}|Entries]) ->
[MFA|fix_stacktrace2(Entries)];
@@ -465,9 +465,9 @@ stack_frame(SP, Dir, [{SP, _}|Stack]) ->
case Stack of
[{Le, {_MFA,Where,Bs}}|_] ->
{Le, Where, Bs};
- [] when Dir==up ->
+ [] when Dir =:= up ->
top;
- [] when Dir==down ->
+ [] when Dir =:= down ->
bottom
end;
stack_frame(SP, Dir, [_Entry|Stack]) ->
@@ -509,7 +509,7 @@ trace(What, Args, true) ->
end,
io_lib:format(" (~w) receive " ++ Tail, [Le]);
- received when Args==null ->
+ received when Args =:= null ->
io_lib:format("~n", []);
received -> % Args=Msg
io_lib:format("~n<== ~p~n", [Args]);
@@ -586,8 +586,8 @@ eval_mfa(Debugged, M, F, As, Ieval) ->
end.
eval_function(Mod, Fun, As0, Bs0, _Called, Ieval) when is_function(Fun);
- Mod==?MODULE,
- Fun==eval_fun ->
+ Mod =:= ?MODULE,
+ Fun =:= eval_fun ->
#ieval{level=Le, line=Li, last_call=Lc} = Ieval,
case lambda(Fun, As0) of
{Cs,Module,Name,As,Bs} ->
@@ -657,7 +657,7 @@ eval_function(Mod, Name, As0, Bs0, Called, Ieval) ->
lambda(eval_fun, [Cs,As,Bs,{Mod,Name}=F]) ->
%% Fun defined in interpreted code, called from outside
if
- length(element(3,hd(Cs))) == length(As) ->
+ length(element(3,hd(Cs))) =:= length(As) ->
db_ref(Mod), %% Adds ref between module and process
{Cs,Mod,Name,As,Bs};
true ->
@@ -672,7 +672,7 @@ lambda(Fun, As) when is_function(Fun) ->
{env, [{Mod,Name},Bs,Cs]} = erlang:fun_info(Fun, env),
{arity, Arity} = erlang:fun_info(Fun, arity),
if
- length(As) == Arity ->
+ length(As) =:= Arity ->
db_ref(Mod), %% Adds ref between module and process
{Cs,Mod,Name,As,Bs};
true ->
@@ -731,7 +731,7 @@ db_ref(Mod) ->
ModDb ->
Node = node(get(int)),
DbRef = if
- Node/=node() -> {Node,ModDb};
+ Node =/= node() -> {Node,ModDb};
true -> ModDb
end,
put([Mod|db], DbRef),
@@ -741,13 +741,12 @@ db_ref(Mod) ->
DbRef
end.
-
cache(Key, Data) ->
put(cache, lists:sublist([{Key,Data}|get(cache)], 5)).
cached(Key) ->
- case lists:keysearch(Key, 1, get(cache)) of
- {value,{Key,Data}} -> Data;
+ case lists:keyfind(Key, 1, get(cache)) of
+ {Key,Data} -> Data;
false -> false
end.
@@ -844,7 +843,7 @@ expr({'try',Line,Es,CaseCs,CatchCs,[]}, Bs0, Ieval0) ->
case_clauses(Val, CaseCs, Bs, try_clause, Ieval)
end
catch
- Class:Reason when CatchCs=/=[] ->
+ Class:Reason when CatchCs =/= [] ->
catch_clauses({Class,Reason,[]}, CatchCs, Bs0, Ieval)
end;
expr({'try',Line,Es,CaseCs,CatchCs,As}, Bs0, Ieval0) ->
@@ -1498,10 +1497,7 @@ guard(Gs, Bs) -> or_guard(Gs, Bs).
or_guard([G|Gs], Bs) ->
%% Short-circuit OR.
- case and_guard(G, Bs) of
- true -> true;
- false -> or_guard(Gs, Bs)
- end;
+ and_guard(G, Bs) orelse or_guard(Gs, Bs);
or_guard([], _) -> false.
and_guard([G|Gs], Bs) ->
@@ -1598,8 +1594,7 @@ match1({bin,_,Fs}, B, Bs0, BBs0) when is_bitstring(B) ->
try eval_bits:match_bits(Fs, B, Bs1, BBs,
fun(L, R, Bs) -> match1(L, R, Bs, BBs) end,
fun(E, Bs) -> expr(E, Bs, #ieval{}) end,
- false) of
- Match -> Match
+ false)
catch
_:_ -> throw(nomatch)
end;
@@ -1687,7 +1682,7 @@ merge_bindings([{Name,V}|B1s], B2s, Ieval) ->
case binding(Name, B2s) of
{value,V} -> % Already there, and the same
merge_bindings(B1s, B2s, Ieval);
- {value,_} when Name=='_' -> % Already there, but anonymous
+ {value,_} when Name =:= '_' -> % Already there, but anonymous
B2s1 = lists:keydelete('_', 1, B2s),
[{Name,V}|merge_bindings(B1s, B2s1, Ieval)];
{value,_} -> % Already there, but different => badmatch
diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl
index ec54c646c8..2ae0c333da 100644
--- a/lib/debugger/src/dbg_iload.erl
+++ b/lib/debugger/src/dbg_iload.erl
@@ -26,7 +26,7 @@
%%--------------------------------------------------------------------
%% load_mod(Mod, File, Binary, Db) -> {ok, Mod}
-%% Mod = atom()
+%% Mod = module()
%% File = string() Source file (including path)
%% Binary = binary()
%% Db = ETS identifier
@@ -408,8 +408,7 @@ expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,fault}},[_]=As}) ->
{dbg,Line,fault,expr_list(As)};
expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,exit}},[_]=As}) ->
{dbg,Line,exit,expr_list(As)};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,apply}},As0})
- when length(As0) == 3 ->
+expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,apply}},[_,_,_]=As0}) ->
As = expr_list(As0),
{apply,Line,As};
expr({call,Line,{remote,_,{atom,_,Mod},{atom,_,Func}},As0}) ->
@@ -517,15 +516,9 @@ expr(Other) ->
%% here as sys_pre_expand has transformed source.
is_guard_test({op,_,Op,L,R}) ->
- case erl_internal:comp_op(Op, 2) of
- true -> is_gexpr_list([L,R]);
- false -> false
- end;
+ erl_internal:comp_op(Op, 2) andalso is_gexpr_list([L,R]);
is_guard_test({call,_,{remote,_,{atom,_,erlang},{atom,_,Test}},As}) ->
- case erl_internal:type_test(Test, length(As)) of
- true -> is_gexpr_list(As);
- false -> false
- end;
+ erl_internal:type_test(Test, length(As)) andalso is_gexpr_list(As);
is_guard_test({atom,_,true}) -> true;
is_guard_test(_) -> false.
@@ -542,22 +535,12 @@ is_gexpr({call,_,{remote,_,{atom,_,erlang},{atom,_,F}},As}) ->
Ar = length(As),
case erl_internal:guard_bif(F, Ar) of
true -> is_gexpr_list(As);
- false ->
- case erl_internal:arith_op(F, Ar) of
- true -> is_gexpr_list(As);
- false -> false
- end
+ false -> erl_internal:arith_op(F, Ar) andalso is_gexpr_list(As)
end;
is_gexpr({op,_,Op,A}) ->
- case erl_internal:arith_op(Op, 1) of
- true -> is_gexpr(A);
- false -> false
- end;
+ erl_internal:arith_op(Op, 1) andalso is_gexpr(A);
is_gexpr({op,_,Op,A1,A2}) ->
- case erl_internal:arith_op(Op, 2) of
- true -> is_gexpr_list([A1,A2]);
- false -> false
- end;
+ erl_internal:arith_op(Op, 2) andalso is_gexpr_list([A1,A2]);
is_gexpr(_) -> false.
is_gexpr_list(Es) -> lists:all(fun (E) -> is_gexpr(E) end, Es).
diff --git a/lib/debugger/src/dbg_iserver.erl b/lib/debugger/src/dbg_iserver.erl
index 4c1e9ccb7b..59188d83a2 100644
--- a/lib/debugger/src/dbg_iserver.erl
+++ b/lib/debugger/src/dbg_iserver.erl
@@ -155,11 +155,8 @@ handle_call(get_stack_trace, _From, State) ->
%% Retrieving information
handle_call(snapshot, _From, State) ->
- Reply = lists:map(fun(Proc) ->
- {Proc#proc.pid, Proc#proc.function,
- Proc#proc.status, Proc#proc.info}
- end,
- State#state.procs),
+ Reply = [{Proc#proc.pid, Proc#proc.function,
+ Proc#proc.status, Proc#proc.info} || Proc <- State#state.procs],
{reply, Reply, State};
handle_call({get_meta, Pid}, _From, State) ->
Reply = case get_proc({pid, Pid}, State#state.procs) of
@@ -181,21 +178,21 @@ handle_call({get_attpid, Pid}, _From, State) ->
%% Breakpoint handling
handle_call({new_break, Point, Options}, _From, State) ->
- case lists:keysearch(Point, 1, State#state.breaks) of
+ case lists:keymember(Point, 1, State#state.breaks) of
false ->
Break = {Point, Options},
send_all([subscriber, meta, attached],
{new_break, Break}, State),
Breaks = keyinsert(Break, 1, State#state.breaks),
{reply, ok, State#state{breaks=Breaks}};
- {value, _Break} ->
+ true ->
{reply, {error, break_exists}, State}
end;
handle_call(all_breaks, _From, State) ->
{reply, State#state.breaks, State};
handle_call({all_breaks, Mod}, _From, State) ->
Reply = lists:filter(fun({{M,_L}, _Options}) ->
- if M==Mod -> true; true -> false end
+ M =/= Mod
end,
State#state.breaks),
{reply, Reply, State};
@@ -276,7 +273,7 @@ handle_call({contents, Mod, Pid}, _From, State) ->
Db = State#state.db,
[{{Mod, refs}, ModDbs}] = ets:lookup(Db, {Mod, refs}),
ModDb = if
- Pid==any -> hd(ModDbs);
+ Pid =:= any -> hd(ModDbs);
true ->
lists:foldl(fun(T, not_found) ->
[{T, Pids}] = ets:lookup(Db, T),
@@ -295,7 +292,7 @@ handle_call({raw_contents, Mod, Pid}, _From, State) ->
Db = State#state.db,
[{{Mod, refs}, ModDbs}] = ets:lookup(Db, {Mod, refs}),
ModDb = if
- Pid==any -> hd(ModDbs);
+ Pid =:= any -> hd(ModDbs);
true ->
lists:foldl(fun(T, not_found) ->
[{T, Pids}] = ets:lookup(Db, T),
@@ -360,15 +357,15 @@ handle_cast({set_stack_trace, Flag}, State) ->
%% Retrieving information
handle_cast(clear, State) ->
Procs = lists:filter(fun(#proc{status=Status}) ->
- if Status==exit -> false; true -> true end
+ Status =/= exit
end,
State#state.procs),
{noreply, State#state{procs=Procs}};
%% Breakpoint handling
handle_cast({delete_break, Point}, State) ->
- case lists:keysearch(Point, 1, State#state.breaks) of
- {value, _Break} ->
+ case lists:keymember(Point, 1, State#state.breaks) of
+ true ->
send_all([subscriber, meta, attached],
{delete_break, Point}, State),
Breaks = lists:keydelete(Point, 1, State#state.breaks),
@@ -377,8 +374,8 @@ handle_cast({delete_break, Point}, State) ->
{noreply, State}
end;
handle_cast({break_option, Point, Option, Value}, State) ->
- case lists:keysearch(Point, 1, State#state.breaks) of
- {value, {Point, Options}} ->
+ case lists:keyfind(Point, 1, State#state.breaks) of
+ {Point, Options} ->
N = case Option of
status -> 1;
action -> 2;
@@ -399,7 +396,7 @@ handle_cast(no_break, State) ->
handle_cast({no_break, Mod}, State) ->
send_all([subscriber, meta, attached], {no_break, Mod}, State),
Breaks = lists:filter(fun({{M, _L}, _O}) ->
- if M==Mod -> false; true -> true end
+ M =/= Mod
end,
State#state.breaks),
{noreply, State#state{breaks=Breaks}};
@@ -409,7 +406,7 @@ handle_cast({set_status, Meta, Status, Info}, State) ->
{true, Proc} = get_proc({meta, Meta}, State#state.procs),
send_all(subscriber, {new_status, Proc#proc.pid, Status, Info}, State),
if
- Status==break ->
+ Status =:= break ->
auto_attach(break, State#state.auto, Proc);
true -> ignore
end,
@@ -526,11 +523,10 @@ code_change(_OldVsn, State, _Extra) ->
%% Internal functions
%%====================================================================
-auto_attach(Why, Auto, Proc) when is_record(Proc, proc) ->
- case Proc#proc.attpid of
- AttPid when is_pid(AttPid) -> ignore;
- undefined ->
- auto_attach(Why, Auto, Proc#proc.pid)
+auto_attach(Why, Auto, #proc{attpid = Attpid, pid = Pid}) ->
+ case Attpid of
+ undefined -> auto_attach(Why, Auto, Pid);
+ _ when is_pid(Attpid) -> ignore
end;
auto_attach(Why, Auto, Pid) when is_pid(Pid) ->
case Auto of
@@ -545,7 +541,7 @@ auto_attach(Why, Auto, Pid) when is_pid(Pid) ->
keyinsert(Tuple1, N, [Tuple2|Tuples]) ->
if
- element(N, Tuple1)<element(N, Tuple2) ->
+ element(N, Tuple1) < element(N, Tuple2) ->
[Tuple1, Tuple2|Tuples];
true ->
[Tuple2 | keyinsert(Tuple1, N, Tuples)]
@@ -576,7 +572,7 @@ send_all([], _Msg, _State) -> ok;
send_all(subscriber, Msg, State) ->
send_all(State#state.subs, Msg);
send_all(meta, Msg, State) ->
- Metas = lists:map(fun(Proc) -> Proc#proc.meta end, State#state.procs),
+ Metas = [Proc#proc.meta || Proc <- State#state.procs],
send_all(Metas, Msg);
send_all(attached, Msg, State) ->
AttPids= mapfilter(fun(Proc) ->
@@ -600,7 +596,7 @@ get_proc({Type, Pid}, Procs) ->
meta -> #proc.meta;
attpid -> #proc.attpid
end,
- case lists:keysearch(Pid, Index, Procs) of
- {value, Proc} -> {true, Proc};
- false -> false
+ case lists:keyfind(Pid, Index, Procs) of
+ false -> false;
+ Proc -> {true, Proc}
end.
diff --git a/lib/debugger/src/dbg_ui_break_win.erl b/lib/debugger/src/dbg_ui_break_win.erl
index a56fe36828..0c1e25e703 100644
--- a/lib/debugger/src/dbg_ui_break_win.erl
+++ b/lib/debugger/src/dbg_ui_break_win.erl
@@ -268,12 +268,7 @@ handle_event({gs, _Id, click, _Data, ["Ok"|_]}, WinInfo) ->
IndexL ->
Funcs = WinInfo#winInfo.funcs,
Breaks =
- lists:map(fun(Index) ->
- Func = lists:nth(Index+1,
- Funcs),
- [Mod | Func]
- end,
- IndexL),
+ [[Mod|lists:nth(Index+1, Funcs)] || Index <- IndexL],
{break, Breaks, enable}
end
end;
diff --git a/lib/debugger/src/dbg_ui_filedialog_win.erl b/lib/debugger/src/dbg_ui_filedialog_win.erl
index f7d76076a5..79ccf20946 100644
--- a/lib/debugger/src/dbg_ui_filedialog_win.erl
+++ b/lib/debugger/src/dbg_ui_filedialog_win.erl
@@ -202,8 +202,7 @@ handle_event({gs, 'Files', doubleclick, _Data, _Arg}, WinInfo) ->
handle_event({gs, _Id, click, select, _Arg}, _WinInfo) ->
{select, gs:read('Selection', text)};
handle_event({gs, _Id, click, multiselect, _Arg}, WinInfo) ->
- Files = lists:map(fun(File) -> untag(File) end,
- gs:read('Files', items)),
+ Files = [untag(File) || File <- gs:read('Files', items)],
{multiselect, WinInfo#winInfo.cwd, Files};
handle_event({gs, _Id, click, filter, _Arg}, WinInfo) ->
{Cwd, Pattern} = update_win(gs:read('Filter', text),
@@ -286,7 +285,7 @@ max_existing([Name | Names]) ->
max_existing(Dir, [Name | Names]) ->
Dir2 = filename:join(Dir, Name),
case filelib:is_file(Dir2, erl_prim_loader) of
- true when Names==[] -> {Dir2, []};
+ true when Names =:= [] -> {Dir2, []};
true -> max_existing(Dir2, Names);
false -> {Dir, [Name | Names]}
end.
@@ -309,11 +308,8 @@ extra_filter([], _Dir, _Fun) -> [].
get_subdirs(Dir) ->
case erl_prim_loader:list_dir(Dir) of
{ok, FileNames} ->
- X = lists:filter(fun(FileName) ->
- File = filename:join(Dir, FileName),
- filelib:is_dir(File, erl_prim_loader)
- end,
- FileNames),
+ X = [FN || FN <- FileNames,
+ filelib:is_dir(filename:join(Dir, FN), erl_prim_loader)],
lists:sort(X);
_Error ->
[]
@@ -335,4 +331,3 @@ compare([], [$/|File]) ->
File;
compare(_, _) ->
error.
-
diff --git a/lib/debugger/src/dbg_ui_mon.erl b/lib/debugger/src/dbg_ui_mon.erl
index 8888075124..82fe210968 100644
--- a/lib/debugger/src/dbg_ui_mon.erl
+++ b/lib/debugger/src/dbg_ui_mon.erl
@@ -162,7 +162,7 @@ init2(CallingPid, Mode, SFile, GS) ->
CallingPid ! {initialization_complete, self()},
if
- SFile==default ->
+ SFile =:= default ->
loop(State3);
true ->
loop(load_settings(SFile, State3))
@@ -226,7 +226,7 @@ loop(State) ->
gui_cmd(stopped, State);
%% From the GUI
- GuiEvent when is_tuple(GuiEvent), element(1, GuiEvent)==gs ->
+ GuiEvent when is_tuple(GuiEvent), element(1, GuiEvent) =:= gs ->
Cmd = dbg_ui_mon_win:handle_event(GuiEvent,State#state.win),
State2 = gui_cmd(Cmd, State),
loop(State2);
@@ -269,7 +269,7 @@ gui_cmd(ignore, State) ->
State;
gui_cmd(stopped, State) ->
if
- State#state.starter==true -> int:stop();
+ State#state.starter =:= true -> int:stop();
true -> int:auto_attach(false)
end,
exit(stop);
@@ -413,9 +413,9 @@ gui_cmd({'Trace Window', TraceWin}, State) ->
State2;
gui_cmd({'Auto Attach', When}, State) ->
if
- When==[] -> int:auto_attach(false);
+ When =:= [] -> int:auto_attach(false);
true ->
- Flags = lists:map(fun(Name) -> map(Name) end, When),
+ Flags = [map(Name) || Name <- When],
int:auto_attach(Flags, trace_function(State))
end,
State;
@@ -676,7 +676,7 @@ load_settings2(Settings, State) ->
Break,
int:break(Mod, Line),
if
- Status==inactive ->
+ Status =:= inactive ->
int:disable_break(Mod, Line);
true -> ignore
end,
@@ -700,12 +700,8 @@ save_settings(SFile, State) ->
int:auto_attach(),
int:stack_trace(),
State#state.backtrace,
- lists:map(fun(Mod) ->
- int:file(Mod)
- end,
- int:interpreted()),
+ [int:file(Mod) || Mod <- int:interpreted()],
int:all_breaks()},
-
Binary = term_to_binary({debugger_settings, Settings}),
case file:write_file(SFile, Binary) of
ok ->
@@ -720,13 +716,12 @@ save_settings(SFile, State) ->
%%====================================================================
registered_name(Pid) ->
-
%% Yield in order to give Pid more time to register its name
timer:sleep(200),
Node = node(Pid),
if
- Node==node() ->
+ Node =:= node() ->
case erlang:process_info(Pid, registered_name) of
{registered_name, Name} -> Name;
_ -> undefined
diff --git a/lib/debugger/src/dbg_ui_mon_win.erl b/lib/debugger/src/dbg_ui_mon_win.erl
index ba2f94c550..66e59a822a 100644
--- a/lib/debugger/src/dbg_ui_mon_win.erl
+++ b/lib/debugger/src/dbg_ui_mon_win.erl
@@ -224,8 +224,7 @@ select(MenuItem, Bool) ->
%%--------------------------------------------------------------------
add_module(WinInfo, Menu, Mod) ->
Modules = WinInfo#winInfo.modules,
- case lists:keysearch(Mod, #moduleInfo.module, Modules) of
- {value, _ModInfo} -> WinInfo;
+ case lists:keymember(Mod, #moduleInfo.module, Modules) of
false ->
%% Create a menu for the module
Font = dbg_ui_win:font(normal),
@@ -244,7 +243,8 @@ add_module(WinInfo, Menu, Mod) ->
gs:config(WinInfo#winInfo.listbox, {add, Mod}),
ModInfo = #moduleInfo{module=Mod, menubtn=MenuBtn},
- WinInfo#winInfo{modules=[ModInfo | Modules]}
+ WinInfo#winInfo{modules=[ModInfo | Modules]};
+ true -> WinInfo
end.
%%--------------------------------------------------------------------
@@ -491,14 +491,13 @@ handle_event({gs, _Id, click, autoattach, _Arg}, WinInfo) ->
%% Process grid
handle_event({gs, _Id, keypress, _Data, [Key|_]}, WinInfo) when
- Key=='Up'; Key=='Down' ->
- Dir = if Key=='Up' -> up; Key=='Down' -> down end,
+ Key =:= 'Up'; Key =:= 'Down' ->
+ Dir = if Key =:= 'Up' -> up; Key =:= 'Down' -> down end,
Row = move(WinInfo, Dir),
-
if Row>1 ->
WinInfo2 = highlight(WinInfo, Row),
- {value, #procInfo{pid=Pid}} =
- lists:keysearch(Row, #procInfo.row, WinInfo#winInfo.processes),
+ #procInfo{pid=Pid} =
+ lists:keyfind(Row, #procInfo.row, WinInfo#winInfo.processes),
{focus, Pid, WinInfo2};
true ->
ignore
@@ -515,10 +514,9 @@ handle_event(_GSEvent, _WinInfo) ->
move(WinInfo, Dir) ->
Row = WinInfo#winInfo.focus,
Last = WinInfo#winInfo.row,
-
if
- Dir==up, Row>1 -> Row-1;
- Dir==down, Row<Last -> Row+1;
+ Dir =:= up, Row > 1 -> Row-1;
+ Dir =:= down, Row < Last -> Row+1;
true -> Row
end.
@@ -533,7 +531,6 @@ highlight(WinInfo, Row) ->
GridLine2 = gs:read(Grid, {obj_at_row, Row}),
gs:config(GridLine2, {fg, white}),
WinInfo#winInfo{focus=Row}.
-
%%====================================================================
%% Internal functions
@@ -545,7 +542,7 @@ configure(WinInfo, {W, H}) ->
Dx = NewW - gs:read(Grid, width),
Dy = H-42 - gs:read(Grid, height),
if
- (Dx+Dy)=/=0 ->
+ (Dx+Dy) =/= 0 ->
gs:config(Grid, [{width, NewW}, {height, H-30}]),
Cols = calc_columnwidths(NewW),
gs:config(Grid, Cols);
@@ -555,10 +552,9 @@ configure(WinInfo, {W, H}) ->
calc_columnwidths(Width) ->
W = if
- Width=<?Wg -> ?Wg;
+ Width =< ?Wg -> ?Wg;
true -> Width
end,
- First = lists:map(fun (X) -> round(X) end,
- [0.13*W, 0.27*W, 0.18*W, 0.18*W]),
+ First = [round(X) || X <- [0.13*W, 0.27*W, 0.18*W, 0.18*W]],
Last = W - lists:sum(First) - 30,
{columnwidths, First++[Last]}.
diff --git a/lib/debugger/src/dbg_ui_trace_win.erl b/lib/debugger/src/dbg_ui_trace_win.erl
index c6f041a63d..82d4199630 100644
--- a/lib/debugger/src/dbg_ui_trace_win.erl
+++ b/lib/debugger/src/dbg_ui_trace_win.erl
@@ -147,17 +147,17 @@ configure(WinInfo, TraceWin) ->
H = gs:read(Win, height),
H2 = if
- Bu1==close, Bu2==open ->
+ Bu1 =:= close, Bu2 =:= open ->
resize_button_area(open, width, W-4),
gs:config('ButtonArea', {height, 30}),
H+30;
- Bu1==open, Bu2==close ->
+ Bu1 =:= open, Bu2 =:= close ->
gs:config('ButtonArea', [{width, 0}, {height, 0}]),
H-30;
true -> H
end,
H3 = if
- Ev1==close, Ev2==open, Bi1==open ->
+ Ev1 =:= close, Ev2 =:= open, Bi1 =:= open ->
Wnew1 = round((W-10-4)/2), % W = window/2 - rb - pads
Hbi1 = gs:read('BindArea', height), % H = bind area h
resize_eval_area(open, width, Wnew1),
@@ -167,25 +167,25 @@ configure(WinInfo, TraceWin) ->
resize_bind_area(open, width,
Wnew1-gs:read('BindArea', width)),
H2;
- Ev1==close, Ev2==open, Bi1==close ->
+ Ev1 =:= close, Ev2 =:= open, Bi1 =:= close ->
resize_eval_area(open, width, W-4),
resize_eval_area(open, height, 200),
H2+200;
- Ev1==open, Ev2==close, Bi1==open ->
+ Ev1 =:= open, Ev2 =:= close, Bi1 =:= open ->
gs:config('EvalArea', [{width,0}, {height,0}]),
gs:config('RB3', [{width, 0}, {height, 0}]),
Wnew2 = W-4,
resize_bind_area(open, width,
Wnew2-gs:read('BindArea', width)),
H2;
- Ev1==open, Ev2==close, Bi1==close ->
+ Ev1 =:= open, Ev2 =:= close, Bi1 =:= close ->
Hs1 = gs:read('EvalArea', height),
gs:config('EvalArea', [{width, 0}, {height, 0}]),
H2-Hs1;
true -> H2
end,
H4 = if
- Bi1==close, Bi2==open, Ev2==open ->
+ Bi1 =:= close, Bi2 =:= open, Ev2 =:= open ->
Wnew3 = round((W-10-4)/2), % W = window/2 - rb - pads
Hs2 = gs:read('EvalArea', height), % H = eval area h
resize_bind_area(open, width, Wnew3),
@@ -194,29 +194,29 @@ configure(WinInfo, TraceWin) ->
resize_eval_area(open, width,
Wnew3-gs:read('EvalArea', width)),
H3;
- Bi1==close, Bi2==open, Ev2==close ->
+ Bi1 =:= close, Bi2 =:= open, Ev2 =:= close ->
resize_bind_area(open, width, W-4),
resize_bind_area(open, height, 200),
H3+200;
- Bi1==open, Bi2==close, Ev2==open ->
+ Bi1 =:= open, Bi2 =:= close, Ev2 =:= open ->
gs:config('BindArea', [{width, 0}, {height, 0}]),
gs:config('RB3', [{width, 0}, {height, 0}]),
Wnew4 = W-4,
resize_eval_area(open, width,
Wnew4-gs:read('EvalArea', width)),
H3;
- Bi1==open, Bi2==close, Ev2==close ->
+ Bi1 =:= open, Bi2 =:= close, Ev2 =:= close ->
Hbi2 = gs:read('BindArea', height),
gs:config('BindArea', [{width, 0}, {height, 0}]),
H3-Hbi2;
true -> H3
end,
H5 = if
- Tr1==close, Tr2==open ->
+ Tr1 =:= close, Tr2 =:= open ->
resize_trace_area(open, width, W-4),
resize_trace_area(open, height, 200),
H4+200;
- Tr1==open, Tr2==close ->
+ Tr1 =:= open, Tr2 =:= close ->
Hf = gs:read('TraceArea', height),
gs:config('TraceArea', [{width, 0}, {height, 0}]),
H4-Hf;
@@ -226,10 +226,10 @@ configure(WinInfo, TraceWin) ->
RB1old = rb1(OldFlags), RB1new = rb1(NewFlags),
if
- RB1old==close, RB1new==open ->
+ RB1old =:= close, RB1new =:= open ->
gs:config('RB1', [{width, W-4}, {height, 10}]),
gs:config(Win, {height, gs:read(Win, height)+10});
- RB1old==open, RB1new==close ->
+ RB1old =:= open, RB1new =:= close ->
gs:config('RB1', [{width, 0}, {height, 0}, lower]),
gs:config(Win, {height, gs:read(Win, height)-10});
true -> ignore
@@ -237,10 +237,10 @@ configure(WinInfo, TraceWin) ->
RB2old = rb2(OldFlags), RB2new = rb2(NewFlags),
if
- RB2old==close, RB2new==open ->
+ RB2old =:= close, RB2new =:= open ->
gs:config('RB2', [{width, W-4}, {height, 10}]),
gs:config(Win, {height,gs:read(Win, height)+10});
- RB2old==open, RB2new==close ->
+ RB2old =:= open, RB2new =:= close ->
gs:config('RB2', [{width, 0}, {height, 0}, lower]),
gs:config(Win, {height, gs:read(Win, height)-10});
true -> ignore
@@ -301,15 +301,15 @@ select(MenuItem, Bool) ->
%% Cond = null | {Mod, Func}
%%--------------------------------------------------------------------
add_break(WinInfo, Menu, {{Mod,Line},[Status|_Options]}=Break) ->
- case lists:keysearch(Mod, 1, WinInfo#winInfo.editors) of
- {value, {Mod, Editor}} ->
+ case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
+ {Mod, Editor} ->
add_break_to_code(Editor, Line, Status);
false -> ignore
end,
add_break_to_menu(WinInfo, Menu, Break).
add_break_to_code(Editor, Line, Status) ->
- Color = if Status==active -> red; Status==inactive -> blue end,
+ Color = if Status =:= active -> red; Status =:= inactive -> blue end,
config_editor(Editor, [{overwrite,{{Line,0},"-@- "}},
{fg,{{{Line,0},{Line,lineend}}, Color}}]).
@@ -330,8 +330,8 @@ add_break_to_menu(WinInfo, Menu, {Point, [Status|_Options]=Options}) ->
%% Cond = null | {Mod, Func}
%%--------------------------------------------------------------------
update_break(WinInfo, {{Mod,Line},[Status|_Options]}=Break) ->
- case lists:keysearch(Mod, 1, WinInfo#winInfo.editors) of
- {value, {Mod, Editor}} ->
+ case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
+ {Mod, Editor} ->
add_break_to_code(Editor, Line, Status);
false -> ignore
end,
@@ -352,8 +352,8 @@ update_break_in_menu(WinInfo, {Point, [Status|_Options]=Options}) ->
%% Point = {Mod, Line}
%%--------------------------------------------------------------------
delete_break(WinInfo, {Mod,Line}=Point) ->
- case lists:keysearch(Mod, 1, WinInfo#winInfo.editors) of
- {value, {Mod, Editor}} -> delete_break_from_code(Editor, Line);
+ case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
+ {Mod, Editor} -> delete_break_from_code(Editor, Line);
false -> ignore
end,
delete_break_from_menu(WinInfo, Point).
@@ -379,11 +379,11 @@ clear_breaks(WinInfo) ->
clear_breaks(WinInfo, all).
clear_breaks(WinInfo, Mod) ->
Remove = if
- Mod==all -> WinInfo#winInfo.breaks;
+ Mod =:= all -> WinInfo#winInfo.breaks;
true ->
lists:filter(fun(#breakInfo{point={Mod2,_L}}) ->
if
- Mod2==Mod -> true;
+ Mod2 =:= Mod -> true;
true -> false
end
end,
@@ -450,8 +450,8 @@ display(Arg) ->
%% Note: remove_code/2 should not be used for currently shown module.
%%--------------------------------------------------------------------
is_shown(WinInfo, Mod) ->
- case lists:keysearch(Mod, 1, WinInfo#winInfo.editors) of
- {value, {Mod, Editor}} ->
+ case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
+ {Mod, Editor} ->
gs:config(Editor, raise),
{true, WinInfo#winInfo{editor={Mod, Editor}}};
false -> false
@@ -459,24 +459,22 @@ is_shown(WinInfo, Mod) ->
show_code(WinInfo, Mod, Contents) ->
Editors = WinInfo#winInfo.editors,
- {Flag, Editor} = case lists:keysearch(Mod, 1, Editors) of
- {value, {Mod, Ed}} -> {existing, Ed};
+ {Flag, Editor} = case lists:keyfind(Mod, 1, Editors) of
+ {Mod, Ed} -> {existing, Ed};
false -> {new, code_editor()}
end,
-
%% Insert code and update breakpoints, if any
config_editor(Editor, [raise, clear]),
show_code(Editor, Contents),
lists:foreach(fun(BreakInfo) ->
case BreakInfo#breakInfo.point of
- {Mod2, Line} when Mod2==Mod ->
+ {Mod2, Line} when Mod2 =:= Mod ->
Status = BreakInfo#breakInfo.status,
add_break_to_code(Editor, Line,Status);
_Point -> ignore
end
end,
WinInfo#winInfo.breaks),
-
case Flag of
existing ->
WinInfo#winInfo{editor={Mod, Editor}};
@@ -485,7 +483,7 @@ show_code(WinInfo, Mod, Contents) ->
editors=[{Mod, Editor} | Editors]}
end.
-show_code(Editor, Text) when length(Text)>1500 ->
+show_code(Editor, Text) when length(Text) > 1500 ->
%% Add some text at a time so that other processes may get scheduled
Str = string:sub_string(Text, 1, 1500),
config_editor(Editor, {insert,{'end', Str}}),
@@ -494,21 +492,19 @@ show_code(Editor, Text) ->
config_editor(Editor, {insert,{'end',Text}}).
show_no_code(WinInfo) ->
- {value, {'$top', Editor}} =
- lists:keysearch('$top', 1, WinInfo#winInfo.editors),
+ {'$top', Editor} = lists:keyfind('$top', 1, WinInfo#winInfo.editors),
gs:config(Editor, raise),
WinInfo#winInfo{editor={'$top', Editor}}.
remove_code(WinInfo, Mod) ->
Editors = WinInfo#winInfo.editors,
- case lists:keysearch(Mod, 1, Editors) of
- {value, {Mod, Editor}} ->
+ case lists:keyfind(Mod, 1, Editors) of
+ {Mod, Editor} ->
gs:destroy(Editor),
WinInfo#winInfo{editors=lists:keydelete(Mod, 1, Editors)};
false ->
WinInfo
end.
-
%%--------------------------------------------------------------------
%% mark_line(WinInfo, Line, How) -> WinInfo
@@ -522,7 +518,7 @@ mark_line(WinInfo, Line, How) ->
mark_line2(Editor, WinInfo#winInfo.marked_line, false),
mark_line2(Editor, Line, How),
if
- Line/=0 -> config_editor(Editor, {vscrollpos, Line-5});
+ Line =/= 0 -> config_editor(Editor, {vscrollpos, Line-5});
true -> ignore
end,
WinInfo#winInfo{marked_line=Line}.
@@ -537,7 +533,7 @@ mark_line2(Editor, Line, How) ->
false -> " "
end,
Font = if
- How==false -> dbg_ui_win:font(normal);
+ How =:= false -> dbg_ui_win:font(normal);
true -> dbg_ui_win:font(bold)
end,
config_editor(Editor, [{overwrite, {{Line,5}, Prefix}},
@@ -558,10 +554,10 @@ select_line(WinInfo, Line) ->
%% help window, it must be checked that it is correct
Size = gs:read(Editor, size),
if
- Line==0 ->
+ Line =:= 0 ->
select_line(Editor, WinInfo#winInfo.selected_line, false),
WinInfo#winInfo{selected_line=0};
- Line<Size ->
+ Line < Size ->
select_line(Editor, Line, true),
config_editor(Editor, {vscrollpos, Line-5}),
WinInfo#winInfo{selected_line=Line};
@@ -712,10 +708,10 @@ handle_event({gs, Editor, buttonpress, code_editor, _Arg}, WinInfo) ->
{Row, _} ->
{Mod, _Editor} = WinInfo#winInfo.editor,
Point = {Mod, Row},
- case lists:keysearch(Point, #breakInfo.point,
+ case lists:keymember(Point, #breakInfo.point,
WinInfo#winInfo.breaks) of
- {value, _BreakInfo} -> {break, Point, delete};
- false -> {break, Point, add}
+ false -> {break, Point, add};
+ true -> {break, Point, delete}
end;
{Row2, _} ->
select_line(Editor, Row2, true),
@@ -776,7 +772,7 @@ code_editor() ->
code_editor(Name, W, H) ->
Editor = if
- Name==null -> gs:editor('CodeArea', []);
+ Name =:= null -> gs:editor('CodeArea', []);
true -> gs:editor(Name, 'CodeArea', [])
end,
gs:config(Editor, [{x,5}, {y,30}, {width,W}, {height,H},
@@ -814,8 +810,8 @@ buttons() ->
{'Where','WhereButton'}, {'Up','UpButton'}, {'Down','DownButton'}].
is_button(Name) ->
- case lists:keysearch(Name, 1, buttons()) of
- {value, {Name, Button}} -> {true, Button};
+ case lists:keyfind(Name, 1, buttons()) of
+ {Name, Button} -> {true, Button};
false -> false
end.
@@ -847,7 +843,7 @@ resize_button_area(open, width, Diff) ->
eval_area({Ev,Bi}, X, Y, FrameOpts, Win) ->
{W,H} = if
- Ev==open -> {289,200};
+ Ev =:= open -> {289,200};
true -> {0,0}
end,
Font = dbg_ui_win:font(normal),
@@ -870,7 +866,7 @@ eval_area({Ev,Bi}, X, Y, FrameOpts, Win) ->
{font_style,{{{1,0},'end'},Font}}]),
gs:config('EvalEditor', {enable, false}),
if
- Ev==open, Bi==close -> resize_eval_area(Ev, width, 257);
+ Ev =:= open, Bi =:= close -> resize_eval_area(Ev, width, 257);
true -> ignore
end.
@@ -891,7 +887,7 @@ resize_eval_area(open, Key, Diff) ->
bind_area({Ev,Bi}, X, Y, FrameOpts, Win) ->
{W,H} = if
- Bi==open -> {249,200};
+ Bi =:= open -> {249,200};
true -> {0,0}
end,
gs:frame('BindArea', Win,
@@ -908,7 +904,7 @@ bind_area({Ev,Bi}, X, Y, FrameOpts, Win) ->
{text,{1,"Name"}}, {text,{2,"Value"}}, {font,Font}]),
gs:config('BindGrid', {rows,{1,1}}),
if
- Bi==open, Ev==close -> resize_bind_area(Bi, width, 297);
+ Bi =:= open, Ev =:= close -> resize_bind_area(Bi, width, 297);
true -> ignore
end.
@@ -993,15 +989,15 @@ resizebar(Flag, Name, X, Y, W, H, Obj) ->
rb1({_Bu,Ev,Bi,Tr}) ->
if
- Ev==close, Bi==close, Tr==close -> close;
+ Ev =:= close, Bi =:= close, Tr =:= close -> close;
true -> open
end.
rb2({_Bu,Ev,Bi,Tr}) ->
if
- Tr==open ->
+ Tr =:= open ->
if
- Ev==close, Bi==close -> close;
+ Ev =:= close, Bi =:= close -> close;
true -> open
end;
true -> close
@@ -1009,7 +1005,7 @@ rb2({_Bu,Ev,Bi,Tr}) ->
rb3({_Bu,Ev,Bi,_Tr}) ->
if
- Ev==open, Bi==open -> open;
+ Ev =:= open, Bi =:= open -> open;
true -> close
end.
@@ -1067,7 +1063,7 @@ configure(WinInfo, NewW, NewH) ->
%% Adjust width unless it is unchanged or less than minimum width
if
- OldW/=NewW ->
+ OldW =/= NewW ->
{Dcode,Deval,Dbind} = configure_widths(OldW,NewW,Flags),
resize_code_area(WinInfo, width, Dcode),
case rb1(Flags) of
@@ -1090,7 +1086,7 @@ configure(WinInfo, NewW, NewH) ->
%% Adjust height unless it is unchanged or less than minimum height
if
- OldH/=NewH ->
+ OldH =/= NewH ->
{Dcode2,Deval2,Dtrace} = configure_heights(OldH,NewH,Flags),
resize_code_area(WinInfo, height, Dcode2),
resize_eval_area(Ev, height, Deval2),
@@ -1117,11 +1113,11 @@ configure_widths(OldW, NewW, Flags) ->
%% Check how much the frames can be resized in reality
Limits = if
%% Window larger
- NewW>OldW ->
+ NewW > OldW ->
if
- Ev==open,Bi==open -> {0,Diff,Diff};
- Ev==open -> {0,Diff,0};
- Bi==open -> {0,0,Diff};
+ Ev =:= open, Bi =:= open -> {0,Diff,Diff};
+ Ev =:= open -> {0,Diff,0};
+ Bi =:= open -> {0,0,Diff};
true -> {Diff,0,0}
end;
@@ -1129,12 +1125,12 @@ configure_widths(OldW, NewW, Flags) ->
%% and current size
OldW>NewW ->
if
- Ev==open,Bi==open ->
+ Ev =:= open, Bi =:= open ->
{0,
gs:read('EvalArea',width)-204,
gs:read('BindArea',width)-112};
- Ev==open -> {0,Diff,0};
- Bi==open -> {0,0,Diff};
+ Ev =:= open -> {0,Diff,0};
+ Bi =:= open -> {0,0,Diff};
true -> {Diff,0,0}
end
end,
@@ -1142,13 +1138,13 @@ configure_widths(OldW, NewW, Flags) ->
case Limits of
%% No Shell or Bind frame, larger window
- {T,0,0} when NewW>OldW -> {T,0,0};
+ {T,0,0} when NewW > OldW -> {T,0,0};
%% No Shell or Bind frame, smaller window
- {T,0,0} when OldW>NewW -> {-T,0,0};
+ {T,0,0} when OldW > NewW -> {-T,0,0};
%% Window larger; divide Diff among the frames and return result
- {_,Sf,B} when NewW>OldW ->
+ {_,Sf,B} when NewW > OldW ->
{_,Sf2,B2} = divide([{0,0},{0,Sf},{0,B}],Diff),
{Sf2+B2,Sf2,B2};
@@ -1171,33 +1167,33 @@ configure_heights(OldH, NewH, Flags) ->
%% Check how much the frames can be resized in reality
{T,Sf,Ff} = if
%% Window larger
- NewH>OldH ->
+ NewH > OldH ->
{Diff,
if
- Ev==close, Bi==close -> 0;
+ Ev =:= close, Bi =:= close -> 0;
true -> Diff
end,
if
- Tr==open -> Diff;
+ Tr =:= open -> Diff;
true -> 0
end};
%% Window smaller; get difference between min size
%% and current size
- OldH>NewH ->
+ OldH > NewH ->
{gs:read('CodeArea',height)-100,
if
- Ev==close, Bi==close -> 0;
+ Ev =:= close, Bi =:= close -> 0;
true ->
if
- Ev==open ->
+ Ev =:= open ->
gs:read('EvalArea',height)-100;
- Bi==open ->
+ Bi =:= open ->
gs:read('BindArea',height)-100
end
end,
if
- Tr==open -> gs:read('TraceArea',height)-100;
+ Tr =:= open -> gs:read('TraceArea',height)-100;
true -> 0
end}
end,
@@ -1251,10 +1247,8 @@ divide(L, Diff) ->
if
%% All of Diff has been distributed
- D==0 -> {T,S,F};
-
+ D =:= 0 -> {T,S,F};
true ->
-
%% For each element, try to add as much as possible of D
{NewT,Dt} = divide2(D,T,Tmax),
{NewS,Ds} = divide2(D,S,Smax),
@@ -1296,25 +1290,25 @@ resize(WinInfo, ResizeBar) ->
rblimits('RB2',W,H),
rblimits('RB3',W,H)).
-resizeloop(WI, RB, Prev, {Min1,Max1},{Min2,Max2},{Min3,Max3}) ->
+resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3}) ->
receive
- {gs,_,motion,_,[_,Y]} when RB=='RB1', Y>Min1,Y<Max1 ->
+ {gs,_,motion,_,[_,Y]} when RB =:= 'RB1', Y > Min1, Y < Max1 ->
gs:config('RB1', {y,Y}),
- resizeloop(WI, RB, Y, {Min1,Max1},{Min2,Max2},{Min3,Max3});
- {gs,_,motion,_,_} when RB=='RB1' ->
- resizeloop(WI, RB, Prev,{Min1,Max1},{Min2,Max2},{Min3,Max3});
+ resizeloop(WI, RB, Y, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
+ {gs,_,motion,_,_} when RB =:= 'RB1' ->
+ resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
- {gs,_,motion,_,[_,Y]} when RB=='RB2', Y>Min2,Y<Max2 ->
+ {gs,_,motion,_,[_,Y]} when RB =:= 'RB2', Y > Min2, Y < Max2 ->
gs:config('RB2', {y,Y}),
- resizeloop(WI, RB, Y, {Min1,Max1},{Min2,Max2},{Min3,Max3});
- {gs,_,motion,_,_} when RB=='RB2' ->
- resizeloop(WI, RB, Prev,{Min1,Max1},{Min2,Max2},{Min3,Max3});
+ resizeloop(WI, RB, Y, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
+ {gs,_,motion,_,_} when RB =:= 'RB2' ->
+ resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
- {gs,_,motion,_,[X,_]} when RB=='RB3', X>Min3,X<Max3 ->
+ {gs,_,motion,_,[X,_]} when RB =:= 'RB3', X > Min3, X < Max3 ->
gs:config('RB3', {x,X}),
- resizeloop(WI, RB, X, {Min1,Max1},{Min2,Max2},{Min3,Max3});
- {gs,_,motion,_,_} when RB=='RB3' ->
- resizeloop(WI, RB, Prev,{Min1,Max1},{Min2,Max2},{Min3,Max3});
+ resizeloop(WI, RB, X, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
+ {gs,_,motion,_,_} when RB =:= 'RB3' ->
+ resizeloop(WI, RB, Prev, {Min1,Max1}, {Min2,Max2}, {Min3,Max3});
{gs,_,buttonrelease,_,_} ->
resize_win(WI, RB, Prev)
@@ -1329,7 +1323,7 @@ resize_win(WinInfo, 'RB1', Y) ->
%% Resize Code, Evaluator and Binding areas
resize_code_area(WinInfo, height, -Diff),
if
- S==close, Bi==close, F==open ->
+ S =:= close, Bi =:= close, F =:= open ->
resize_trace_area(open, height, Diff);
true ->
resize_eval_area(S, height, Diff),
@@ -1388,7 +1382,7 @@ rblimits('RB1',_W,H) ->
RB2 = gs:read('RB2',height),
FF = gs:read('TraceArea',height),
Max = case RB2 of
- 0 when FF/=0 ->
+ 0 when FF =/= 0 ->
H-112;
_ ->
Y = gs:read('RB2',y),
@@ -1397,18 +1391,14 @@ rblimits('RB1',_W,H) ->
{Min,Max};
rblimits('RB2',_W,H) ->
-
- %% TraceFrame should not have height <100
+ %% TraceFrame should not have height < 100
Max = H-112,
-
%% Min is decided by a minimum distance to 'RB1'
Y = gs:read('RB1',y),
Min = erlang:min(Max,Y+140),
-
{Min,Max};
rblimits('RB3',W,_H) ->
-
%% Neither CodeArea nor BindArea should occupy
%% less than 1/3 of the total window width and EvalFrame should
%% be at least 289 pixels wide
@@ -1484,7 +1474,7 @@ helpwin_action(gotoline, default, AttPid, _Editor, Data, Win) ->
end,
Data;
helpwin_action(search, case_sensitive, _AttPid, _Ed, {Pos, CS}, _Win) ->
- Bool = if CS==true -> false; CS==false -> true end,
+ Bool = if CS =:= true -> false; CS =:= false -> true end,
{Pos, Bool};
helpwin_action(search, default, _AttPid, Editor, {Pos, CS}, Win) ->
gs:config(lbl(Win), {label, {text, ""}}),
@@ -1517,13 +1507,9 @@ search(Str, Editor, Max, {Row, Col}, CS) ->
lowercase(true, Str) -> Str;
lowercase(false, Str) ->
- lists:map(fun(Char) ->
- if
- Char>=$A, Char=<$Z -> Char+32;
- true -> Char
- end
- end,
- Str).
+ [if Char >= $A, Char =< $Z -> Char+32;
+ true -> Char
+ end || Char <- Str].
mark_string(Editor, {Row, Col}, Str) ->
Between = {{Row,Col}, {Row,Col+length(Str)}},
@@ -1540,10 +1526,9 @@ unmark_string(Editor, {Row, Col}) ->
{fg, {Between, black}}]).
helpwin(Type, GS, {X, Y}) ->
- W = 200, Pad=10, Wbtn = 50,
+ W = 200, Pad = 10, Wbtn = 50,
- Title =
- case Type of search -> "Search"; gotoline -> "Go To Line" end,
+ Title = case Type of search -> "Search"; gotoline -> "Go To Line" end,
Win = gs:window(GS, [{title, Title}, {x, X}, {y, Y}, {width, W},
{destroy, true}]),
diff --git a/lib/debugger/src/dbg_ui_view.erl b/lib/debugger/src/dbg_ui_view.erl
index 075275f196..7350a830a8 100644
--- a/lib/debugger/src/dbg_ui_view.erl
+++ b/lib/debugger/src/dbg_ui_view.erl
@@ -21,9 +21,6 @@
%% External exports
-export([start/2]).
-%% Internal exports
--export([init/3]).
-
-record(state, {gs, % term() Graphics system id
win, % term() Attach process window data
coords, % {X,Y} Mouse point position
@@ -42,7 +39,7 @@ start(GS, Mod) ->
Title = "View Module " ++ atom_to_list(Mod),
case dbg_ui_winman:is_started(Title) of
true -> ignore;
- false -> spawn(?MODULE, init, [GS, Mod, Title])
+ false -> spawn(fun () -> init(GS, Mod, Title) end)
end.
@@ -51,7 +48,6 @@ start(GS, Mod) ->
%%====================================================================
init(GS, Mod, Title) ->
-
%% Subscribe to messages from the interpreter
int:subscribe(),
diff --git a/lib/debugger/src/dbg_ui_win.erl b/lib/debugger/src/dbg_ui_win.erl
index 74ff2503ab..9bed6a1ec5 100644
--- a/lib/debugger/src/dbg_ui_win.erl
+++ b/lib/debugger/src/dbg_ui_win.erl
@@ -24,7 +24,6 @@
create_menus/2, select/2, selected/1,
add_break/2, update_break/2, delete_break/1,
motion/2
-
]).
-record(break, {mb, smi, emi, dimi, demi}).
@@ -49,11 +48,11 @@ init() ->
font(Style) ->
GS = init(),
Style2 = if
- Style==normal -> [];
+ Style =:= normal -> [];
true -> [Style]
end,
case gs:read(GS, {choose_font, {screen,Style2,12}}) of
- Font when element(1, Font)==screen ->
+ Font when element(1, Font) =:= screen ->
Font;
_ ->
gs:read(GS, {choose_font, {courier,Style2,12}})
@@ -168,8 +167,7 @@ select(MenuItem, Bool) ->
%%--------------------------------------------------------------------
selected(Menu) ->
Children = gs:read(Menu, children),
- Selected = lists:filter(fun(Child) -> gs:read(Child, select) end,
- Children),
+ Selected = [gs:read(Child, select) || Child <- Children],
lists:map(fun(Child) ->
{text, Name} = gs:read(Child, label),
list_to_atom(Name)
diff --git a/lib/debugger/src/dbg_ui_winman.erl b/lib/debugger/src/dbg_ui_winman.erl
index 71023cd0d6..398735a7ca 100644
--- a/lib/debugger/src/dbg_ui_winman.erl
+++ b/lib/debugger/src/dbg_ui_winman.erl
@@ -120,9 +120,9 @@ init(_Arg) ->
{ok, #state{}}.
handle_call({is_started, Title}, _From, State) ->
- Reply = case lists:keysearch(Title, #win.title, State#state.wins) of
- {value, Win} -> {true, Win#win.win};
- false -> false
+ Reply = case lists:keyfind(Title, #win.title, State#state.wins) of
+ false -> false;
+ Win -> {true, Win#win.win}
end,
{reply, Reply, State}.
@@ -134,8 +134,8 @@ handle_cast({insert, Pid, Title, Win}, State) ->
handle_cast({clear_process, Title}, State) ->
OldWins = State#state.wins,
- Wins = case lists:keysearch(Title, #win.title, OldWins) of
- {value, #win{owner=Pid}} ->
+ Wins = case lists:keyfind(Title, #win.title, OldWins) of
+ #win{owner=Pid} ->
Msg = {dbg_ui_winman, destroy},
Pid ! Msg,
lists:keydelete(Title, #win.title, OldWins);
@@ -147,7 +147,7 @@ handle_cast({clear_process, Title}, State) ->
handle_info({'EXIT', Pid, _Reason}, State) ->
[Mon | _Wins] = State#state.wins,
if
- Pid==Mon#win.owner -> {stop, normal, State};
+ Pid =:= Mon#win.owner -> {stop, normal, State};
true ->
Wins2 = lists:keydelete(Pid, #win.owner, State#state.wins),
inform_all(Wins2),
diff --git a/lib/debugger/src/dbg_wx_break_win.erl b/lib/debugger/src/dbg_wx_break_win.erl
index 5dafb0fbe6..78733c98c8 100644
--- a/lib/debugger/src/dbg_wx_break_win.erl
+++ b/lib/debugger/src/dbg_wx_break_win.erl
@@ -206,11 +206,7 @@ handle_event(#wx{id=OKorListBox, event=#wxCommand{type=OkorDoubleClick}},
OkorDoubleClick =:= command_listbox_doubleclicked ->
Mod = wxComboBox:getValue(Text),
{_, IndexL} = wxListBox:getSelections(LB),
- Breaks = lists:map(fun(Index) ->
- Func = lists:nth(Index+1, Funcs),
- [list_to_atom(Mod) | Func]
- end,
- IndexL),
+ Breaks = [[list_to_atom(Mod)|lists:nth(Index+1, Funcs)] || Index <- IndexL],
wxDialog:destroy(Win),
{break, Breaks, enable};
handle_event(#wx{id=?wxID_OK},#winInfo{win=Win,text=Text, entries=Es, trigger=Trigger}) ->
diff --git a/lib/debugger/src/dbg_wx_interpret.erl b/lib/debugger/src/dbg_wx_interpret.erl
index f711ba679d..ffcfbcf36b 100644
--- a/lib/debugger/src/dbg_wx_interpret.erl
+++ b/lib/debugger/src/dbg_wx_interpret.erl
@@ -115,11 +115,11 @@ interpret_all(Dir, [File0|Files], Mode, Window, Errors) ->
interpret_all(_Dir, [], _Mode, _Window, []) ->
true;
interpret_all(Dir, [], _Mode, Window, Errors) ->
- Msg = lists:map(fun(Name) ->
- File = filename:join(Dir, Name),
- Error = format_error(int:interpretable(File)),
- ["\n ",Name,": ",Error]
- end, Errors),
+ Msg = [begin
+ File = filename:join(Dir, Name),
+ Error = format_error(int:interpretable(File)),
+ ["\n ",Name,": ",Error]
+ end || Name <- Errors],
All = ["Error when interpreting: ", Msg],
dbg_wx_win:confirm(Window, lists:flatten(All)),
true.
diff --git a/lib/debugger/src/dbg_wx_mon.erl b/lib/debugger/src/dbg_wx_mon.erl
index 3f55c38d35..6bdec994b1 100644
--- a/lib/debugger/src/dbg_wx_mon.erl
+++ b/lib/debugger/src/dbg_wx_mon.erl
@@ -170,7 +170,7 @@ init2(CallingPid, Mode, SFile, GS) ->
CallingPid ! {initialization_complete, self()},
if
- SFile==default ->
+ SFile =:= default ->
loop(State3);
true ->
loop(load_settings(SFile, State3))
@@ -268,7 +268,7 @@ gui_cmd(ignore, State) ->
State;
gui_cmd(stopped, State) ->
if
- State#state.starter==true -> int:stop();
+ State#state.starter =:= true -> int:stop();
true -> int:auto_attach(false)
end,
exit(stop);
@@ -420,9 +420,9 @@ gui_cmd({'Trace Window', TraceWin}, State) ->
State2;
gui_cmd({'Auto Attach', When}, State) ->
if
- When==[] -> int:auto_attach(false);
+ When =:= [] -> int:auto_attach(false);
true ->
- Flags = lists:map(fun(Name) -> map(Name) end, When),
+ Flags = [map(Name) || Name <- When],
int:auto_attach(Flags, trace_function(State))
end,
State;
@@ -691,12 +691,12 @@ load_settings2(Settings, State) ->
Break,
int:break(Mod, Line),
if
- Status==inactive ->
+ Status =:= inactive ->
int:disable_break(Mod, Line);
true -> ignore
end,
if
- Action/=enable ->
+ Action =/= enable ->
int:action_at_break(Mod,Line,Action);
true -> ignore
end,
@@ -715,10 +715,7 @@ save_settings(SFile, State) ->
int:auto_attach(),
int:stack_trace(),
State#state.backtrace,
- lists:map(fun(Mod) ->
- int:file(Mod)
- end,
- int:interpreted()),
+ [int:file(Mod) || Mod <- int:interpreted()],
int:all_breaks()},
Binary = term_to_binary({debugger_settings, Settings}),
@@ -741,7 +738,7 @@ registered_name(Pid) ->
Node = node(Pid),
if
- Node==node() ->
+ Node =:= node() ->
case erlang:process_info(Pid, registered_name) of
{registered_name, Name} -> Name;
_ -> undefined
diff --git a/lib/debugger/src/dbg_wx_mon_win.erl b/lib/debugger/src/dbg_wx_mon_win.erl
index 8ad4f4213f..04c3501b8c 100644
--- a/lib/debugger/src/dbg_wx_mon_win.erl
+++ b/lib/debugger/src/dbg_wx_mon_win.erl
@@ -266,8 +266,7 @@ select(MenuItem, Bool) ->
add_module(WinInfo, MenuName, Mod) ->
Win = WinInfo#winInfo.window,
Modules = WinInfo#winInfo.modules,
- case lists:keysearch(Mod, #moduleInfo.module, Modules) of
- {value, _ModInfo} -> WinInfo;
+ case lists:keymember(Mod, #moduleInfo.module, Modules) of
false ->
%% Create a menu for the module
Menu = get(MenuName),
@@ -284,8 +283,9 @@ add_module(WinInfo, MenuName, Mod) ->
wxListBox:append(WinInfo#winInfo.listbox, atom_to_list(Mod)),
ModInfo = #moduleInfo{module=Mod, menubtn={Menu,MenuBtn}},
- WinInfo#winInfo{modules=[ModInfo | Modules]}
- end.
+ WinInfo#winInfo{modules=[ModInfo | Modules]};
+ true -> WinInfo
+ end.
%%--------------------------------------------------------------------
%% delete_module(WinInfo, Mod) -> WinInfo
@@ -559,8 +559,7 @@ handle_event(#wx{event=#wxCommand{type=command_checkbox_clicked}},
handle_event(#wx{event=#wxList{type=command_list_item_selected,
itemIndex=Row}}, WinInfo) ->
#winInfo{processes=Pids} = WinInfo,
- {value, #procInfo{pid=Pid}} =
- lists:keysearch(Row, #procInfo.row, Pids),
+ #procInfo{pid=Pid} = lists:keyfind(Row, #procInfo.row, Pids),
{focus, Pid, WinInfo#winInfo{focus=Row}};
handle_event(#wx{event=#wxList{type=command_list_item_activated}},
_WinInfo) ->
diff --git a/lib/debugger/src/dbg_wx_trace.erl b/lib/debugger/src/dbg_wx_trace.erl
index f9fdf593c4..6675ea33e7 100644
--- a/lib/debugger/src/dbg_wx_trace.erl
+++ b/lib/debugger/src/dbg_wx_trace.erl
@@ -180,12 +180,12 @@ init_contents(Breaks, State) ->
State#state{win=Win}.
-loop(#state{meta=Meta} = State) ->
+loop(#state{meta=Meta, win=Win} = State) ->
receive
%% From the GUI main window
- GuiEvent when element(1, GuiEvent)==wx ->
+ GuiEvent when element(1, GuiEvent) =:= wx ->
Cmd = wx:batch(fun() ->
- dbg_wx_trace_win:handle_event(GuiEvent,State#state.win)
+ dbg_wx_trace_win:handle_event(GuiEvent,Win)
end),
State2 = gui_cmd(Cmd, State),
loop(State2);
@@ -211,11 +211,11 @@ loop(#state{meta=Meta} = State) ->
%% From the dbg_wx_winman process (Debugger window manager)
{dbg_ui_winman, update_windows_menu, Data} ->
- Window = dbg_wx_trace_win:get_window(State#state.win),
+ Window = dbg_wx_trace_win:get_window(Win),
dbg_wx_winman:update_windows_menu(Window,Data),
loop(State);
{dbg_ui_winman, destroy} ->
- dbg_wx_trace_win:stop(State#state.win),
+ dbg_wx_trace_win:stop(Win),
exit(stop)
end.
@@ -269,7 +269,7 @@ gui_cmd('Continue', State) ->
int:meta(State#state.meta, continue),
{Status, Mod, Line} = State#state.status,
if
- Status==wait_break ->
+ Status =:= wait_break ->
Win = dbg_wx_trace_win:unmark_line(State#state.win),
gui_enable_functions(wait_running),
State#state{win=Win, status={wait_running,Mod,Line}};
@@ -291,7 +291,7 @@ gui_cmd('Stop', State) ->
int:meta(State#state.meta, stop),
{Status, Mod, Line} = State#state.status,
if
- Status==wait_running ->
+ Status =:= wait_running ->
Win = dbg_wx_trace_win:mark_line(State#state.win, Line,
break),
gui_enable_functions(wait_break),
@@ -421,7 +421,7 @@ gui_cmd('Function Break...', State) ->
gui_cmd('Enable All', State) ->
Breaks = int:all_breaks(),
ThisMod = State#state.cm,
- lists:foreach(fun ({{Mod, Line}, _Options}) when Mod==ThisMod ->
+ lists:foreach(fun ({{Mod, Line}, _Options}) when Mod =:= ThisMod ->
int:enable_break(Mod, Line);
(_Break) ->
ignore
@@ -431,7 +431,7 @@ gui_cmd('Enable All', State) ->
gui_cmd('Disable All', State) ->
Breaks = int:all_breaks(),
ThisMod = State#state.cm,
- lists:foreach(fun ({{Mod, Line}, _Options}) when Mod==ThisMod ->
+ lists:foreach(fun ({{Mod, Line}, _Options}) when Mod =:= ThisMod ->
int:disable_break(Mod, Line);
(_Break) ->
ignore
@@ -458,7 +458,7 @@ gui_cmd({'Trace Window', TraceWin}, State) ->
Win = dbg_wx_trace_win:configure(State#state.win, TraceWin),
{Status,_,_} = State#state.status,
if
- Status==break; Status==wait_break ->
+ Status =:= break; Status =:= wait_break ->
gui_enable_btrace(Trace, State#state.stack_trace);
true -> ignore
end,
@@ -467,7 +467,7 @@ gui_cmd({'Stack Trace', [Name]}, State) ->
int:meta(State#state.meta, stack_trace, map(Name)),
{Status,_,_} = State#state.status,
if
- Status==break; Status==wait_break ->
+ Status =:= break; Status =:= wait_break ->
gui_enable_btrace(State#state.trace, map(Name));
true -> ignore
end,
@@ -490,9 +490,9 @@ gui_cmd('Debugger', State) ->
gui_cmd({user_command, Cmd}, State) ->
{Status, _Mod, _Line} = State#state.status,
if
- Status==break;
- Status==wait_break;
- Status==wait_running ->
+ Status =:= break;
+ Status =:= wait_break;
+ Status =:= wait_running ->
Cm = State#state.cm,
Arg = case State#state.stack of
{Cur, Max} when Cur<Max -> {Cm, Cmd, Cur};
@@ -531,14 +531,14 @@ add_break(WI, Coords, Type, Mod, Line) ->
int_cmd({interpret, Mod}, State) ->
if
- Mod==State#state.cm ->
+ Mod =:= State#state.cm ->
State#state{cm_obsolete=true};
true ->
State
end;
int_cmd({no_interpret, Mod}, State) ->
if
- Mod==State#state.cm ->
+ Mod =:= State#state.cm ->
State#state{cm_obsolete=true};
true ->
Win = dbg_wx_trace_win:remove_code(State#state.win, Mod),
@@ -584,7 +584,7 @@ meta_cmd({re_entry, dbg_ieval, eval_fun}, State) ->
meta_cmd({re_entry, Mod, _Func}, State) ->
Obs = State#state.cm_obsolete,
case State#state.cm of
- Mod when Obs==true ->
+ Mod when Obs =:= true ->
Win = gui_load_module(State#state.win, Mod,State#state.pid),
State#state{win=Win, cm_obsolete=false};
Mod -> State;
@@ -630,11 +630,11 @@ meta_cmd({func_at, Mod, Line, Cur}, State) ->
gui_enable_functions(idle),
dbg_wx_trace_win:display(State#state.win, idle),
State#state{win=Win, cm=Mod, status={idle,Mod,Line}, stack=Stack};
-meta_cmd({wait_at, Mod, Line, Cur}, #state{status={Status,_,_}}=State)
- when Status/=init, Status/=break ->
+meta_cmd({wait_at, Mod, Line, Cur}, #state{status={Status,_,_}, win=Win}=State)
+ when Status =/= init, Status =/= break ->
Stack = {Cur,Cur},
gui_enable_functions(wait_running),
- dbg_wx_trace_win:display(State#state.win, {wait,Mod,Line}),
+ dbg_wx_trace_win:display(Win, {wait,Mod,Line}),
State#state{status={wait_running,Mod,Line}, stack=Stack};
meta_cmd({wait_at, Mod, Line, Cur}, State) ->
Stack = {Cur,Cur},
@@ -675,7 +675,7 @@ meta_cmd({stack_trace, Flag}, State) ->
gui_enable_updown(Flag, State#state.stack),
{Status,_,_} = State#state.status,
if
- Status==break; Status==wait_break ->
+ Status =:= break; Status =:= wait_break ->
gui_enable_btrace(State#state.trace, Flag);
true -> ignore
end,
@@ -813,7 +813,7 @@ gui_enable_functions(Status) ->
gui_enable_updown(Flag, Stack) ->
{Enable, Disable} =
if
- Flag==false -> {[], ['Up', 'Down']};
+ Flag =:= false -> {[], ['Up', 'Down']};
true ->
case Stack of
{1,1} -> {[], ['Up', 'Down']};
@@ -826,14 +826,14 @@ gui_enable_updown(Flag, Stack) ->
dbg_wx_trace_win:enable(Enable, true),
dbg_wx_trace_win:enable(Disable, false),
if
- Enable==[] -> dbg_wx_trace_win:enable(['Where'], false);
+ Enable =:= [] -> dbg_wx_trace_win:enable(['Where'], false);
true -> dbg_wx_trace_win:enable(['Where'], true)
end.
gui_enable_btrace(Trace, StackTrace) ->
Bool = if
- Trace==false -> false;
- StackTrace==false -> false;
+ Trace =:= false -> false;
+ StackTrace =:= false -> false;
true -> true
end,
dbg_wx_trace_win:enable(['Back Trace'], Bool).
diff --git a/lib/debugger/src/dbg_wx_trace_win.erl b/lib/debugger/src/dbg_wx_trace_win.erl
index 2b4a1164ad..720b913024 100755
--- a/lib/debugger/src/dbg_wx_trace_win.erl
+++ b/lib/debugger/src/dbg_wx_trace_win.erl
@@ -410,11 +410,11 @@ clear_breaks(WinInfo) ->
clear_breaks(WinInfo, all).
clear_breaks(WinInfo, Mod) ->
Remove = if
- Mod==all -> WinInfo#winInfo.breaks;
+ Mod =:= all -> WinInfo#winInfo.breaks;
true ->
lists:filter(fun(#breakInfo{point={Mod2,_L}}) ->
if
- Mod2==Mod -> true;
+ Mod2 =:= Mod -> true;
true -> false
end
end,
@@ -481,8 +481,8 @@ display(#winInfo{window=Win, sb=Sb},Arg) ->
%% Note: remove_code/2 should not be used for currently shown module.
%%--------------------------------------------------------------------
is_shown(WinInfo, Mod) ->
- case lists:keysearch(Mod, 1, WinInfo#winInfo.editors) of
- {value, {Mod, Editor}} ->
+ case lists:keyfind(Mod, 1, WinInfo#winInfo.editors) of
+ {Mod, Editor} ->
gs:config(Editor, raise), %% BUGBUG
{true, WinInfo#winInfo{editor={Mod, Editor}}};
false -> false
@@ -494,7 +494,7 @@ show_code(WinInfo = #winInfo{editor={_, Ed}}, Mod, Contents) ->
lists:foreach(fun(BreakInfo) ->
case BreakInfo#breakInfo.point of
- {Mod2, Line} when Mod2==Mod ->
+ {Mod2, Line} when Mod2 =:= Mod ->
Status = BreakInfo#breakInfo.status,
dbg_wx_code:add_break_to_code(Ed, Line,Status);
_Point -> ignore
@@ -540,10 +540,10 @@ select_line(WinInfo, Line) ->
%% help window, it must be checked that it is correct
Size = dbg_wx_code:get_no_lines(Ed),
if
- Line==0 ->
+ Line =:= 0 ->
dbg_wx_code:goto_line(Ed,1),
WinInfo#winInfo{selected_line=0};
- Line<Size ->
+ Line < Size ->
dbg_wx_code:goto_line(Ed,Line),
WinInfo#winInfo{selected_line=Line};
true ->
@@ -764,8 +764,8 @@ handle_event(#wx{event=#wxStyledText{type=stc_doubleclick}},
WinInfo = #winInfo{editor={Mod,Ed}}) ->
Line = wxStyledTextCtrl:getCurrentLine(Ed),
Point = {Mod, Line+1},
- case lists:keysearch(Point, #breakInfo.point,WinInfo#winInfo.breaks) of
- {value, _BreakInfo} -> {break, Point, delete};
+ case lists:keymember(Point, #breakInfo.point, WinInfo#winInfo.breaks) of
+ true -> {break, Point, delete};
false -> {break, Point, add}
end;
@@ -837,7 +837,7 @@ handle_event(#wx{id=?SEARCH_ENTRY, event=#wxCommand{cmdString=Str}},
%% Button area
handle_event(#wx{id=ID, event=#wxCommand{type=command_button_clicked}},_Wi) ->
- {value, {Button, _}} = lists:keysearch(ID, 2, buttons()),
+ {Button, _} = lists:keyfind(ID, 2, buttons()),
Button;
%% Evaluator area
@@ -908,8 +908,8 @@ buttons() ->
{'Where',?WhereButton}, {'Up',?UpButton}, {'Down',?DownButton}].
is_button(Name) ->
- case lists:keysearch(Name, 1, buttons()) of
- {value, {Name, Button}} -> {true, Button};
+ case lists:keyfind(Name, 1, buttons()) of
+ {Name, Button} -> {true, Button};
false -> false
end.
diff --git a/lib/debugger/src/dbg_wx_view.erl b/lib/debugger/src/dbg_wx_view.erl
index 6d34e5650c..8ff89a4847 100644
--- a/lib/debugger/src/dbg_wx_view.erl
+++ b/lib/debugger/src/dbg_wx_view.erl
@@ -23,9 +23,6 @@
%% External exports
-export([start/2]).
-%% Internal exports
--export([init/4]).
-
-record(state, {gs, % term() Graphics system id
win, % term() Attach process window data
coords, % {X,Y} Mouse point position
@@ -46,7 +43,7 @@ start(GS, Mod) ->
true -> ignore;
false ->
Env = wx:get_env(),
- spawn_link(?MODULE, init, [GS, Env, Mod, Title])
+ spawn_link(fun () -> init(GS, Env, Mod, Title) end)
end.
@@ -84,7 +81,7 @@ loop(State) ->
receive
%% From the GUI main window
- GuiEvent when element(1, GuiEvent)==wx ->
+ GuiEvent when element(1, GuiEvent) =:= wx ->
Cmd = wx:batch(fun() ->
dbg_wx_trace_win:handle_event(GuiEvent, State#state.win)
end),
@@ -167,7 +164,7 @@ gui_cmd('Function Break...', State) ->
gui_cmd('Enable All', State) ->
Breaks = int:all_breaks(),
ThisMod = State#state.mod,
- lists:foreach(fun ({{Mod, Line}, _Options}) when Mod==ThisMod ->
+ lists:foreach(fun ({{Mod, Line}, _Options}) when Mod =:= ThisMod ->
int:enable_break(Mod, Line);
(_Break) ->
ignore
@@ -177,7 +174,7 @@ gui_cmd('Enable All', State) ->
gui_cmd('Disable All', State) ->
Breaks = int:all_breaks(),
ThisMod = State#state.mod,
- lists:foreach(fun ({{Mod, Line}, _Options}) when Mod==ThisMod ->
+ lists:foreach(fun ({{Mod, Line}, _Options}) when Mod =:= ThisMod ->
int:disable_break(Mod, Line);
(_Break) ->
ignore
@@ -214,21 +211,19 @@ add_break(GS, Coords, Type, Mod, Line) ->
%%--Commands from the interpreter-------------------------------------
-int_cmd({new_break, {{Mod,_Line},_Options}=Break}, #state{mod=Mod}=State) ->
- Win = dbg_wx_trace_win:add_break(State#state.win, 'Break', Break),
- State#state{win=Win};
-int_cmd({delete_break, {Mod,_Line}=Point}, #state{mod=Mod}=State) ->
- Win = dbg_wx_trace_win:delete_break(State#state.win, Point),
- State#state{win=Win};
-int_cmd({break_options, {{Mod,_Line},_Options}=Break}, #state{mod=Mod}=State) ->
- Win = dbg_wx_trace_win:update_break(State#state.win, Break),
- State#state{win=Win};
-int_cmd(no_break, State) ->
- Win = dbg_wx_trace_win:clear_breaks(State#state.win),
- State#state{win=Win};
-int_cmd({no_break, _Mod}, State) ->
- Win = dbg_wx_trace_win:clear_breaks(State#state.win),
- State#state{win=Win};
+int_cmd({new_break, {{Mod,_Line},_Options}=Break},
+ #state{mod = Mod, win = Win}=State) ->
+ State#state{win = dbg_wx_trace_win:add_break(Win, 'Break', Break)};
+int_cmd({delete_break, {Mod,_Line}=Point},
+ #state{mod = Mod, win = Win}=State) ->
+ State#state{win = dbg_wx_trace_win:delete_break(Win, Point)};
+int_cmd({break_options, {{Mod,_Line},_Options}=Break},
+ #state{mod = Mod, win = Win}=State) ->
+ State#state{win = dbg_wx_trace_win:update_break(Win, Break)};
+int_cmd(no_break, #state{win = Win}=State) ->
+ State#state{win = dbg_wx_trace_win:clear_breaks(Win)};
+int_cmd({no_break, _Mod}, #state{win = Win}=State) ->
+ State#state{win = dbg_wx_trace_win:clear_breaks(Win)};
int_cmd(_, State) ->
State.
diff --git a/lib/debugger/src/dbg_wx_winman.erl b/lib/debugger/src/dbg_wx_winman.erl
index 1daabe3435..d0ddfeb51a 100755
--- a/lib/debugger/src/dbg_wx_winman.erl
+++ b/lib/debugger/src/dbg_wx_winman.erl
@@ -118,9 +118,9 @@ init([]) ->
{ok, #state{}}.
handle_call({is_started, Title}, _From, State) ->
- Reply = case lists:keysearch(Title, #win.title, State#state.wins) of
- {value, Win} -> {true, Win#win.win};
- false -> false
+ Reply = case lists:keyfind(Title, #win.title, State#state.wins) of
+ false -> false;
+ Win -> {true, Win#win.win}
end,
{reply, Reply, State}.
@@ -132,8 +132,8 @@ handle_cast({insert, Pid, Title, Win}, State) ->
handle_cast({clear_process, Title}, State) ->
OldWins = State#state.wins,
- Wins = case lists:keysearch(Title, #win.title, OldWins) of
- {value, #win{owner=Pid}} ->
+ Wins = case lists:keyfind(Title, #win.title, OldWins) of
+ #win{owner=Pid} ->
Msg = {dbg_ui_winman, destroy},
Pid ! Msg,
lists:keydelete(Title, #win.title, OldWins);
@@ -145,7 +145,7 @@ handle_cast({clear_process, Title}, State) ->
handle_info({'EXIT', Pid, _Reason}, State) ->
[Mon | _Wins] = State#state.wins,
if
- Pid==Mon#win.owner -> {stop, normal, State};
+ Pid =:= Mon#win.owner -> {stop, normal, State};
true ->
Wins2 = lists:keydelete(Pid, #win.owner, State#state.wins),
inform_all(Wins2),
diff --git a/lib/debugger/src/i.erl b/lib/debugger/src/i.erl
index 7c2fb22946..476a53482e 100644
--- a/lib/debugger/src/i.erl
+++ b/lib/debugger/src/i.erl
@@ -31,7 +31,6 @@
iv() ->
Vsn = string:substr(filename:basename(code:lib_dir(debugger)), 10),
list_to_atom(Vsn).
-
%% -------------------------------------------
%% Start a new graphical monitor.
@@ -288,10 +287,9 @@ ia(X,Y,Z) ->
%% -------------------------------------------
ia(Pid,Fnk) ->
- case lists:keysearch(Pid, 1, int:snapshot()) of
- {value, _PidTuple} ->
- int:attach(Pid,Fnk);
- false -> no_proc
+ case lists:keymember(Pid, 1, int:snapshot()) of
+ false -> no_proc;
+ true -> int:attach(Pid,Fnk)
end.
ia(X,Y,Z,Fnk) ->
diff --git a/lib/debugger/src/int.erl b/lib/debugger/src/int.erl
index eeb4df4a8e..9ee2102a19 100644
--- a/lib/debugger/src/int.erl
+++ b/lib/debugger/src/int.erl
@@ -261,7 +261,7 @@ del_break_in(Mod, Func, Arity) when is_atom(Mod), is_atom(Func), is_integer(Arit
end.
first_lines(Clauses) ->
- lists:map(fun(Clause) -> first_line(Clause) end, Clauses).
+ [first_line(Clause) || Clause <- Clauses].
first_line({clause,_L,_Vars,_,Exprs}) ->
first_line(Exprs);
@@ -469,10 +469,10 @@ contents(Mod, Pid) ->
%% Arity = integer()
%%--------------------------------------------------------------------
functions(Mod) ->
- lists:filter(fun([module_info, _Arity]) -> false;
- (_Func) -> true
- end,
- dbg_iserver:call({functions, Mod})).
+ [F || F <- dbg_iserver:call({functions, Mod}), functions_1(F)].
+
+functions_1([module_info, _Arity]) -> false;
+functions_1(_Func) -> true.
%%====================================================================
diff --git a/lib/docbuilder/src/docb_edoc_xml_cb.erl b/lib/docbuilder/src/docb_edoc_xml_cb.erl
index 4dba843341..f5cfc0fe18 100644
--- a/lib/docbuilder/src/docb_edoc_xml_cb.erl
+++ b/lib/docbuilder/src/docb_edoc_xml_cb.erl
@@ -478,31 +478,29 @@ otp_xmlify_a_href("#"++_ = Marker, Es0) -> % <seealso marker="#what">
otp_xmlify_a_href("http:"++_ = URL, Es0) -> % external URL
{URL, Es0};
otp_xmlify_a_href("OTPROOT"++AppRef, Es0) -> % <.. marker="App:FileRef
- case split(AppRef, "/") of
- [AppS, "doc", FileRef1] ->
- FileRef = AppS++":"++otp_xmlify_a_fileref(FileRef1, AppS),
- [#xmlText{value=Str0} = T] = Es0,
- Str = case split(Str0, "/") of
- %% //Application
- [AppS2] ->
- %% AppS2 can differ from AppS
- %% Example: xmerl/XMerL
- AppS2;
- [_AppS,ModRef] ->
- case split(ModRef, ":") of
- %% //Application/Module
- [Module] ->
- Module++"(3)";
- %% //Application/Module:Type()
- [_Module,_Type] ->
- ModRef
- end;
- %% //Application/Module:Function/Arity
- [_AppS,ModFunc,Arity] ->
- ModFunc++"/"++Arity
- end,
- {FileRef, [T#xmlText{value=Str}]}
- end;
+ [AppS, "doc", FileRef1] = split(AppRef, "/"),
+ FileRef = AppS++":"++otp_xmlify_a_fileref(FileRef1, AppS),
+ [#xmlText{value=Str0} = T] = Es0,
+ Str = case split(Str0, "/") of
+ %% //Application
+ [AppS2] ->
+ %% AppS2 can differ from AppS
+ %% Example: xmerl/XMerL
+ AppS2;
+ [_AppS,ModRef] ->
+ case split(ModRef, ":") of
+ %% //Application/Module
+ [Module] ->
+ Module++"(3)";
+ %% //Application/Module:Type()
+ [_Module,_Type] ->
+ ModRef
+ end;
+ %% //Application/Module:Function/Arity
+ [_AppS,ModFunc,Arity] ->
+ ModFunc++"/"++Arity
+ end,
+ {FileRef, [T#xmlText{value=Str}]};
otp_xmlify_a_href("../"++File, Es0) ->
%% Special case: This kind of relative path is used on some
%% places within i.e. EDoc and refers to a file within the same
@@ -639,13 +637,13 @@ otp_xmlify_table([#xmlText{} = E|Es]) ->
[E | otp_xmlify_table(Es)];
otp_xmlify_table([#xmlElement{name=tbody} = E|Es]) ->
otp_xmlify_table(E#xmlElement.content)++otp_xmlify_table(Es);
-otp_xmlify_table([#xmlElement{name=tr} = E|Es]) ->
+otp_xmlify_table([#xmlElement{name=tr, content=Content}|Es]) ->
%% Insert newlines between table rows
- otp_xmlify_table(E#xmlElement.content)++[{br,[]}]++otp_xmlify_table(Es);
-otp_xmlify_table([#xmlElement{name=th} = E|Es]) ->
- [{em, E#xmlElement.content} | otp_xmlify_table(Es)];
-otp_xmlify_table([#xmlElement{name=td} = E|Es]) ->
- otp_xmlify_e(E#xmlElement.content) ++ otp_xmlify_table(Es);
+ otp_xmlify_table(Content)++[{br,[]}]++otp_xmlify_table(Es);
+otp_xmlify_table([#xmlElement{name=th, content=Content}|Es]) ->
+ [{em, Content} | otp_xmlify_table(Es)];
+otp_xmlify_table([#xmlElement{name=td, content=Content}|Es]) ->
+ otp_xmlify_e(Content) ++ otp_xmlify_table(Es);
otp_xmlify_table([]) ->
[].
@@ -1155,8 +1153,8 @@ get_text(#xmlElement{content=[E]}) ->
%% text_only(Es) -> Ts
%% Takes a list of xmlElement and xmlText and return a lists of xmlText.
-text_only([#xmlElement{} = E |Es]) ->
- text_only(E#xmlElement.content) ++ text_only(Es);
+text_only([#xmlElement{content = Content}|Es]) ->
+ text_only(Content) ++ text_only(Es);
text_only([#xmlText{} = E |Es]) ->
[E | text_only(Es)];
text_only([]) ->
diff --git a/lib/docbuilder/src/docb_html.erl b/lib/docbuilder/src/docb_html.erl
index 9aea4c8a66..bdfc5ea876 100644
--- a/lib/docbuilder/src/docb_html.erl
+++ b/lib/docbuilder/src/docb_html.erl
@@ -283,16 +283,16 @@ rule([term|_], {_, [ID], _}, Opts) ->
ID,
"</strong></em> "]}, Opts};
TermList ->
- case lists:keysearch(ID, 1, TermList) of
+ case lists:keyfind(ID, 1, TermList) of
false ->
{{drop, ["<em><strong>", ID,
"</strong></em> "]},
Opts};
- {value, {ID, Name, _Description, _Resp}} ->
+ {ID, Name, _Description, _Resp} ->
{{drop, ["<em><strong>", Name,
"</strong></em> "]},
Opts};
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
{{drop, [ "<em><strong>", Name,
"</strong></em> "]},
Opts}
@@ -306,16 +306,16 @@ rule([term|_], {_, [ID], _}, Opts) ->
TermList ->
PartApplication =
docb_util:lookup_option(part_application, Opts),
- case lists:keysearch(ID, 1, TermList) of
+ case lists:keyfind(ID, 1, TermList) of
false ->
{{drop, ["<a href=\"", PartApplication,
"_term.html#", ID, "\">", ID,
"</a> "]}, Opts};
- {value, {ID, Name, _Description, _Resp}} ->
+ {ID, Name, _Description, _Resp} ->
{{drop, ["<a href=\"", PartApplication,
"_term.html#", ID, "\">", Name,
"</a> "]}, Opts};
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
{{drop, ["<a href=\"", PartApplication,
"_term.html#", ID, "\">", Name,
"</a> "]}, Opts}
@@ -331,17 +331,16 @@ rule([cite|_], {_, [ID], _}, Opts) ->
{{drop, ["<em><strong>", ID, "</strong></em> "]},
Opts};
CiteList ->
- case lists:keysearch(ID, 1, CiteList) of
+ case lists:keyfind(ID, 1, CiteList) of
false ->
{{drop,
["<em><strong>", ID, "</strong></em> "]},
Opts};
-
- {value, {ID, Name, _Description, _Resp}} ->
+ {ID, Name, _Description, _Resp} ->
{{drop, ["<em><strong>", Name,
"</strong></em> "]},
Opts};
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
{{drop, ["<em><strong>", Name,
"</strong></em> "]},
Opts}
@@ -355,18 +354,18 @@ rule([cite|_], {_, [ID], _}, Opts) ->
CiteList ->
PartApp =
docb_util:lookup_option(part_application, Opts),
- case lists:keysearch(ID, 1, CiteList) of
+ case lists:keyfind(ID, 1, CiteList) of
false ->
{{drop, ["<a href=\"", PartApp,
"_cite.html#", ID, "\">", ID,
"</a> "]},
Opts};
- {value, {ID, Name, _Description, _Resp}} ->
+ {ID, Name, _Description, _Resp} ->
{{drop, ["<a href=\"", PartApp,
"_cite.html#", ID, "\">", Name,
"</a> "]},
Opts};
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
{{drop, ["<a href=\"", PartApp,
"_cite.html#", ID, "\">", Name,
"</a> "]},
@@ -376,7 +375,7 @@ rule([cite|_], {_, [ID], _}, Opts) ->
end;
rule([code|_], {_, [Type], [{pcdata, _, Code}]}, Opts) ->
- case lists:member(Type,["ERL","C","NONE"]) of
+ case lists:member(Type, ["ERL","C","NONE"]) of
true ->
{{drop, ["\n<div class=\"example\"><pre>\n", docb_html_util:element_cdata_to_html(Code),
"\n</pre></div>\n"]}, Opts};
diff --git a/lib/docbuilder/src/docb_html_util.erl b/lib/docbuilder/src/docb_html_util.erl
index b2951706ea..02ce8b52a7 100644
--- a/lib/docbuilder/src/docb_html_util.erl
+++ b/lib/docbuilder/src/docb_html_util.erl
@@ -136,7 +136,6 @@ copy_pics(Src, Dest, Opts) ->
Dir = code:lib_dir(docbuilder),
InFile = filename:join([Dir, "etc", Src]),
OutFile = docb_util:outfile(Dest, "", Opts),
-
case filelib:last_modified(OutFile) of
0 -> % File doesn't exist
file:copy(InFile, OutFile);
@@ -156,10 +155,10 @@ copy_pics(Src, Dest, Opts) ->
%%--Resolve header data-------------------------------------------------
extract_header_data(Key, {header, [], List}) ->
- case lists:keysearch(Key, 1, List) of
- {value, {Key, [], []}} ->
+ case lists:keyfind(Key, 1, List) of
+ {Key, [], []} ->
"";
- {value, {Key, [], [{pcdata, [], Value}]}} ->
+ {Key, [], [{pcdata, [], Value}]} ->
pcdata_to_html(Value);
false ->
""
@@ -253,7 +252,7 @@ make_anchor_href(HRef) ->
{ok, [HRef]} ->
%% No `#' in HRef, i.e. only path
make_anchor_href(HRef, "");
- {ok, [Path, Fragment]}->
+ {ok, [Path, Fragment]} ->
make_anchor_href(Path, Fragment)
end.
@@ -398,10 +397,10 @@ count_sections([]) ->
%%--Make a ToC----------------------------------------------------------
format_toc(Toc) ->
- lists:map(fun({Number, Title}) ->
- [Number, " <a href = \"#", Number,
- "\">", Title, "</a><br/>\n"]
- end, Toc).
+ [format_toc1(T) || T <- Toc].
+
+format_toc1({Number, Title}) ->
+ [Number, " <a href = \"#", Number, "\">", Title, "</a><br/>\n"].
%%--Convert HTML ISO Latin 1 characters to ordinary characters----------
diff --git a/lib/docbuilder/src/docb_main.erl b/lib/docbuilder/src/docb_main.erl
index ef21f65557..87a1401a02 100644
--- a/lib/docbuilder/src/docb_main.erl
+++ b/lib/docbuilder/src/docb_main.erl
@@ -55,7 +55,7 @@ process(File, Opts) ->
%% If no target format is specified, assume HTML:
Tos = if
- Tos0==[] -> [html];
+ Tos0 =:= [] -> [html];
true -> Tos0
end,
@@ -327,12 +327,8 @@ verify(Tree) -> verify(Tree, [], 1).
verify({pcdata, Optional, _}, Path, Level) ->
verify_optional(Optional, Path, Level);
verify({Tag, Optional, Args}, Path, Level) when is_list(Args) ->
- case verify_optional(Optional, Path, Level) of
- true ->
- verify_list(Args, [Tag|Path], Level);
- false ->
- false
- end;
+ verify_optional(Optional, Path, Level)
+ andalso verify_list(Args, [Tag|Path], Level);
verify(Other, Path, Level) ->
verify_error(Other, Path, Level).
@@ -342,12 +338,7 @@ verify_error(X, Path, Level) ->
false.
verify_list([H|T], Path, Level) ->
- case verify(H, Path, Level) of
- true ->
- verify_list(T, Path, Level +1);
- false ->
- false
- end;
+ verify(H, Path, Level) andalso verify_list(T, Path, Level + 1);
verify_list([], _, _) ->
true.
@@ -419,7 +410,7 @@ edit1_list(_Tag, [], _Op) ->
%% Actual transformation of tree structure to desired format.
transform(From, To, Opts, File, Tree) ->
Filter = if
- To==html; To==kwic ->
+ To =:= html; To =:= kwic ->
list_to_atom("docb_tr_" ++ atom_to_list(From) ++
[$2|atom_to_list(To)]);
true ->
@@ -427,7 +418,7 @@ transform(From, To, Opts, File, Tree) ->
[$2|atom_to_list(To)])
end,
- case catch apply(Filter, transform, [File, Tree, Opts]) of
+ case catch Filter:transform(File, Tree, Opts) of
%% R5C
{'EXIT', {undef, [{Filter, transform, [File, Tree, Opts]}|_]}}->
@@ -459,9 +450,9 @@ transform(From, To, Opts, File, Tree) ->
finish_transform(Tree, File, Opts, Filter) ->
{Str, NewOpts} = pp(Tree, [], 1, Filter, Opts),
Extension =
- case catch apply(Filter, extension, [NewOpts]) of
+ case catch Filter:extension(NewOpts) of
{'EXIT', _} ->
- apply(Filter, extension, []);
+ Filter:extension();
Others ->
Others
end,
@@ -606,7 +597,7 @@ include_all(Fd) ->
eof ->
[];
ListOfChars ->
- lists:append(ListOfChars, include_all(Fd))
+ ListOfChars ++ include_all(Fd)
end.
extract(File, Fd, StartTag, StopTag, State) ->
diff --git a/lib/docbuilder/src/docb_pretty_format.erl b/lib/docbuilder/src/docb_pretty_format.erl
index 0c4fb0507b..25dcd8987b 100644
--- a/lib/docbuilder/src/docb_pretty_format.erl
+++ b/lib/docbuilder/src/docb_pretty_format.erl
@@ -47,7 +47,7 @@ term(Term) ->
%% the next line to need an "extra" indent!).
term([], Indent) ->
{Indent, [$[,$]]};
-term(L, Indent) when list(L) ->
+term(L, Indent) when is_list(L) ->
case is_string(L) of
true ->
{Indent, io_lib:write_string(L)};
@@ -59,7 +59,7 @@ term(L, Indent) when list(L) ->
write_simple_list(L, Indent)
end
end;
-term(T, Indent) when tuple(T) ->
+term(T, Indent) when is_tuple(T) ->
case complex_tuple(T) of
true ->
write_complex_tuple(T, Indent);
diff --git a/lib/docbuilder/src/docb_tr_application2html.erl b/lib/docbuilder/src/docb_tr_application2html.erl
index 4084cfe6ba..d8cb214d0a 100644
--- a/lib/docbuilder/src/docb_tr_application2html.erl
+++ b/lib/docbuilder/src/docb_tr_application2html.erl
@@ -119,8 +119,8 @@ transform(File, {application, _Attrs, [Header|Rest]}, Opts0) ->
case docb_main:parse1("fascicules", Opts0) of
{ok, Parse} ->
FascData = get_fasc_data(Parse),
- case lists:keysearch(File, 1, FascData) of
- {value, {_, _, "YES", _}} ->
+ case lists:keyfind(File, 1, FascData) of
+ {_, _, "YES", _} ->
OrigFile =
docb_util:outfile(File++"_frame",
".html", Opts0),
@@ -167,7 +167,7 @@ concat_files([File|Rest], Body, Opts) ->
%% Remove the reference manual header
[{Ref, [], [_Hdr| NewBody]}] = NewParse,
RefParse = [{Ref, [], NewBody}],
- lists:append(Body, concat_files(Rest, RefParse, Opts));
+ Body ++ concat_files(Rest, RefParse, Opts);
errors ->
errors
end;
@@ -216,7 +216,7 @@ make_toc([{lib, Attrs, More}|Rest]) ->
make_toc([{com, Attrs, More}|Rest]) ->
[{com, Attrs, More}|make_toc(Rest)];
make_toc([{_Tag, _Attrs, More}|Rest]) ->
- lists:append(make_toc(More), make_toc(Rest)).
+ make_toc(More) ++ make_toc(Rest).
rule([module|_], {_, [File], _}) ->
{"<small><a target=\"document\" href=\"" ++
@@ -280,9 +280,7 @@ get_fasc_data({fascicules, _, Fascs}) ->
Fascs).
get_avals(Atts) ->
- lists:map(fun(Tuple) ->
- element(3, Tuple) end,
- Atts).
+ [element(3, Tuple) || Tuple <- Atts].
get_pc_text([{pcdata, _, Text}]) ->
Text.
diff --git a/lib/docbuilder/src/docb_tr_cite2html.erl b/lib/docbuilder/src/docb_tr_cite2html.erl
index 4ecbfa4e91..77f1c4e636 100644
--- a/lib/docbuilder/src/docb_tr_cite2html.erl
+++ b/lib/docbuilder/src/docb_tr_cite2html.erl
@@ -39,24 +39,22 @@ purge_body([], _) ->
purge_body([{pcdata,_Attrs,_More}|Rest], CiteList) ->
purge_body(Rest, CiteList);
purge_body([{cite,[{"ID","CDATA",ID}],More}|Rest], CiteList) ->
- case lists:keysearch(ID, 1, CiteList) of
+ case lists:keyfind(ID, 1, CiteList) of
false ->
[{cite, [{"NAME","CDATA",ID}, {"ID","CDATA",ID}], More}|
purge_body(Rest, CiteList)];
- {value, {ID, Name, _Description, _Responsible}} ->
+ {ID, Name, _Description, _Responsible} ->
[{cite, [{"NAME","CDATA",Name}, {"ID","CDATA",ID}], More}|
purge_body(Rest, CiteList)];
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
[{cite, [{"NAME","CDATA",Name}, {"ID","CDATA",ID}], More}|
purge_body(Rest, CiteList)]
end;
purge_body([{_Tag,_Attrs,More}|Rest], CiteList) ->
- lists:append(purge_body(More, CiteList),
- purge_body(Rest, CiteList)).
+ purge_body(More, CiteList) ++ purge_body(Rest, CiteList).
rule([header|_], _) ->
{drop, ""};
-
rule(_, _) ->
{drop, ""}.
@@ -91,19 +89,19 @@ rule([cite|_], {_,[Name,ID], [{citedef,[],[{pcdata,[],Def}]}]}, Opts) ->
false -> [];
Value -> Value
end,
- case lists:keysearch(ID, 1, CiteList) of
+ case lists:keyfind(ID, 1, CiteList) of
false ->
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Def) ++ "\n</dd>\n"}, Opts};
- {value, {ID, Name, Description, _Responsible}} ->
+ {ID, Name, Description, _Responsible} ->
docb_util:message(warning,
"Global cite ~s overriding local", [ID]),
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
Opts};
- {value, {ID, Name, Description}} ->
+ {ID, Name, Description} ->
docb_util:message(warning,
"Global cite ~s overriding local", [ID]),
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
@@ -117,19 +115,19 @@ rule([cite|_], {_,[Name,ID],_}, Opts) ->
false -> [];
Value -> Value
end,
- case lists:keysearch(ID, 1, CiteList) of
+ case lists:keyfind(ID, 1, CiteList) of
false ->
docb_util:message(error,
"The cite ~s has no definition", [ID]),
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
"??" ++ "\n</dd>\n"}, Opts};
- {value, {ID, Name, Description, _Responsible}} ->
+ {ID, Name, Description, _Responsible} ->
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
Opts};
- {value, {ID, Name, Description}} ->
+ {ID, Name, Description} ->
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
diff --git a/lib/docbuilder/src/docb_tr_index2html.erl b/lib/docbuilder/src/docb_tr_index2html.erl
index bbf419f3ef..312342add2 100644
--- a/lib/docbuilder/src/docb_tr_index2html.erl
+++ b/lib/docbuilder/src/docb_tr_index2html.erl
@@ -73,9 +73,7 @@ prune_flat([], _) ->
[].
keep_pcdata(Trees) ->
- lists:filter(fun({pcdata, _, _}) -> true;
- (_) -> false
- end, Trees).
+ [T || T = {pcdata, _, _} <- Trees].
new_trees(FileFuncs) ->
Files0 = [{File, RefType} || {File, RefType, _} <- FileFuncs],
diff --git a/lib/docbuilder/src/docb_tr_part2html.erl b/lib/docbuilder/src/docb_tr_part2html.erl
index dd44c4a8df..30befe8432 100644
--- a/lib/docbuilder/src/docb_tr_part2html.erl
+++ b/lib/docbuilder/src/docb_tr_part2html.erl
@@ -93,8 +93,8 @@ transform(File, {part, _Attrs, [Header| Rest]}, Opts0) ->
case docb_main:parse1("fascicules", Opts0) of
{ok, Parse} ->
FascData = get_fasc_data(Parse),
- case lists:keysearch(File, 1, FascData) of
- {value, {_, _, "YES", _}} ->
+ case lists:keyfind(File, 1, FascData) of
+ {_, _, "YES", _} ->
OrigFile =
docb_util:outfile(File++"_frame",
".html", Opts0),
@@ -137,7 +137,7 @@ concat_files([File | Rest], Body, ChLevel, Opts, TP, TOpts, Ext) ->
case docb_main:parse1(File, Opts) of
{ok, Parse} ->
{TopTag, Attrs, [Header = {header, _, HeaderContents} | More]} = Parse,
- {value,{title,_,Title}} = lists:keysearch(title,1,HeaderContents),
+ {title,_,Title} = lists:keyfind(title,1,HeaderContents),
NewMore = [{section, [], [{title, [], Title}| More]}],
NewParse = {TopTag, Attrs, [Header| NewMore]},
if
@@ -156,9 +156,8 @@ concat_files([File | Rest], Body, ChLevel, Opts, TP, TOpts, Ext) ->
docb_html_util:number(NewParse,
integer_to_list(ChLevel), File),
{_, [], [_| NewBody]} = NumberTree,
- lists:append(Body,
- concat_files(Rest, NewBody, ChLevel+1, Opts,
- TP, TOpts, Ext));
+ Body ++ concat_files(Rest, NewBody, ChLevel+1, Opts,
+ TP, TOpts, Ext);
errors ->
throw({error,"Parse error when building chapter "++File})
end;
@@ -232,9 +231,7 @@ get_fasc_data({fascicules, _, Fascs}) ->
Fascs).
get_avals(Atts) ->
- lists:map(fun(Tuple) ->
- element(3, Tuple) end,
- Atts).
+ [element(3, Tuple) || Tuple <- Atts].
get_pc_text([{pcdata, _, Text}]) ->
Text.
diff --git a/lib/docbuilder/src/docb_tr_term2html.erl b/lib/docbuilder/src/docb_tr_term2html.erl
index 0a993cebb1..a3c4a5312a 100644
--- a/lib/docbuilder/src/docb_tr_term2html.erl
+++ b/lib/docbuilder/src/docb_tr_term2html.erl
@@ -39,24 +39,22 @@ purge_body([], _) ->
purge_body([{pcdata,_Attrs,_More}|Rest], TermList) ->
purge_body(Rest, TermList);
purge_body([{term,[{"ID","CDATA",ID}],More}|Rest], TermList) ->
- case lists:keysearch(ID, 1, TermList) of
+ case lists:keyfind(ID, 1, TermList) of
false ->
[{term,[{"NAME","CDATA",ID},{"ID","CDATA",ID}],More}|
purge_body(Rest, TermList)];
- {value, {ID, Name, _Description, _Responsible}} ->
+ {ID, Name, _Description, _Responsible} ->
[{term,[{"NAME","CDATA",Name},{"ID","CDATA",ID}],More}|
purge_body(Rest, TermList)];
- {value, {ID, Name, _Description}} ->
+ {ID, Name, _Description} ->
[{term,[{"NAME","CDATA",Name},{"ID","CDATA",ID}],More}|
purge_body(Rest, TermList)]
end;
purge_body([{_Tag,_Attrs,More}|Rest], TermList) ->
- lists:append(purge_body(More, TermList),
- purge_body(Rest, TermList)).
+ purge_body(More, TermList) ++ purge_body(Rest, TermList).
rule([header|_], _) ->
{drop, ""};
-
rule(_, _) ->
{drop, ""}.
@@ -82,19 +80,19 @@ rule([term|_], {_,[Name,ID],[{termdef,[],[{pcdata,[],Def}]}]}, Opts) ->
false -> [];
Value -> Value
end,
- case lists:keysearch(ID, 1, TermList) of
+ case lists:keyfind(ID, 1, TermList) of
false ->
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ ID ++ "</strong></a>\n</dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Def) ++ "\n</dd>\n"}, Opts};
- {value, {ID, Name, Description, _Responsible}} ->
+ {ID, Name, Description, _Responsible} ->
docb_util:message(warning,
"Global term ~s overriding local", [ID]),
{{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
Opts};
- {value, {ID, Name, Description}} ->
+ {ID, Name, Description} ->
docb_util:message(warning,
"Global term ~s overriding local", [ID]),
{{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
@@ -107,19 +105,19 @@ rule([term|_], {_,[Name,ID],_}, Opts) ->
false -> [];
Value -> Value
end,
- case lists:keysearch(ID, 1, TermList) of
+ case lists:keyfind(ID, 1, TermList) of
false ->
docb_util:message(error,
"The term ~s has no definition", [ID]),
{{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
"??" ++ "\n</dd>\n"}, Opts};
- {value, {ID, Name, Description, _Responsible}} ->
+ {ID, Name, Description, _Responsible} ->
{{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
Opts};
- {value, {ID, Name, Description}} ->
+ {ID, Name, Description} ->
{{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
"<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
diff --git a/lib/docbuilder/src/docb_transform.erl b/lib/docbuilder/src/docb_transform.erl
index a432038adf..9c7561b07b 100644
--- a/lib/docbuilder/src/docb_transform.erl
+++ b/lib/docbuilder/src/docb_transform.erl
@@ -135,8 +135,8 @@ parse([Opt | _RawOpts], _Opts) ->
get_defs(Type, File, Opts) ->
Key = {defs,Type},
{PrevDefs, Opts2} =
- case lists:keysearch(Key, 1, Opts) of
- {value, {_, Defs0}} ->
+ case lists:keyfind(Key, 1, Opts) of
+ {_, Defs0} ->
{Defs0, lists:keydelete(Key, 1, Opts)};
false ->
{[], Opts}
diff --git a/lib/docbuilder/src/docb_util.erl b/lib/docbuilder/src/docb_util.erl
index 59673ef3a4..9b2eec7733 100644
--- a/lib/docbuilder/src/docb_util.erl
+++ b/lib/docbuilder/src/docb_util.erl
@@ -61,7 +61,7 @@ html_snippet(What, Opts) ->
case lookup_option(html_mod, Opts) of
false -> "";
Module ->
- case catch apply(Module, What, []) of
+ case catch Module:What() of
HTML when is_list(HTML) ->
HTML;
{'EXIT', {undef, _}} ->
@@ -82,7 +82,7 @@ html_snippet(What, Arg, Opts) ->
case lookup_option(html_mod, Opts) of
false -> "";
Module ->
- case catch apply(Module, What, [Arg]) of
+ case catch Module:What(Arg) of
HTML when is_list(HTML) ->
HTML;
{'EXIT', {undef, _}} ->
@@ -106,8 +106,8 @@ html_snippet(What, Arg, Opts) ->
%% lookup_option(Opt, Opts) -> Value | false
lookup_option(Opt, Opts) ->
- case lists:keysearch(Opt, 1, Opts) of
- {value, {Opt,Value}} -> Value;
+ case lists:keyfind(Opt, 1, Opts) of
+ {Opt,Value} -> Value;
false -> false
end.
diff --git a/lib/docbuilder/src/docb_xmerl_tree_cb.erl b/lib/docbuilder/src/docb_xmerl_tree_cb.erl
index d57f55bff8..bc62069230 100644
--- a/lib/docbuilder/src/docb_xmerl_tree_cb.erl
+++ b/lib/docbuilder/src/docb_xmerl_tree_cb.erl
@@ -188,8 +188,8 @@ attrs(DTD, Tag, GivenAttrs) ->
merge_attrs(Tag, default_attrs(DTD, Tag), GivenAttrs).
merge_attrs(Tag, [{NameA, Type, DefVal}|Default], GivenAttrs) ->
- Val = case lists:keysearch(NameA, #xmlAttribute.name, GivenAttrs) of
- {value, #xmlAttribute{value=Val0}} -> Val0;
+ Val = case lists:keyfind(NameA, #xmlAttribute.name, GivenAttrs) of
+ #xmlAttribute{value=Val0} -> Val0;
false -> DefVal
end,
Attr = {attr_name(NameA), Type, attr_val(Type, Val)},
diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c
index c57c552b90..18315bfbd3 100644
--- a/lib/erl_interface/src/legacy/erl_marshal.c
+++ b/lib/erl_interface/src/legacy/erl_marshal.c
@@ -26,6 +26,7 @@
#include <ctype.h>
#include <sys/types.h>
#include <string.h>
+#include <limits.h>
#include "erl_interface.h"
#include "erl_marshal.h"
@@ -178,26 +179,14 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
return 0;
case ERL_INTEGER:
- i = ep->uval.ival.i;
- /* ERL_SMALL_BIG */
- if ((i > ERL_MAX) || (i < ERL_MIN)) {
- *(*ext)++ = ERL_SMALL_BIG_EXT;
- *(*ext)++ = 4; /* four bytes */
- if ((*(*ext)++ = ((i>>31) & 0x01))) /* sign byte */
- i = -i;
- *(*ext)++ = i & 0xff; /* LSB first */
- *(*ext)++ = (i >> 8) & 0xff;
- *(*ext)++ = (i >> 16) & 0xff;
- *(*ext)++ = (i >> 24) & 0x7f; /* Don't include the sign bit */
- return 0;
- }
+ i = ep->uval.ival.i;
/* SMALL_INTEGER */
if ((i < 256) && (i >= 0)) {
*(*ext)++ = ERL_SMALL_INTEGER_EXT;
*(*ext)++ = i & 0xff;
return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (i >> 24) & 0xff;
*(*ext)++ = (i >> 16) & 0xff;
@@ -208,23 +197,23 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
case ERL_U_INTEGER:
u = ep->uval.uival.u;
/* ERL_U_SMALL_BIG */
- if (u > ERL_MAX) {
- *(*ext)++ = ERL_SMALL_BIG_EXT;
- *(*ext)++ = 4; /* four bytes */
- *(*ext)++ = 0; /* sign byte */
- *(*ext)++ = u & 0xff; /* LSB first */
- *(*ext)++ = (u >> 8) & 0xff;
- *(*ext)++ = (u >> 16) & 0xff;
- *(*ext)++ = (u >> 24) & 0xff;
- return 0;
+ if ((int)u < 0) {
+ *(*ext)++ = ERL_SMALL_BIG_EXT;
+ *(*ext)++ = 4; /* four bytes */
+ *(*ext)++ = 0; /* sign byte */
+ *(*ext)++ = u & 0xff; /* LSB first */
+ *(*ext)++ = (u >> 8) & 0xff;
+ *(*ext)++ = (u >> 16) & 0xff;
+ *(*ext)++ = (u >> 24) & 0xff;
+ return 0;
}
/* SMALL_INTEGER */
- if ((u < 256) && (u >= 0)) {
+ if (u < 256) {
*(*ext)++ = ERL_SMALL_INTEGER_EXT;
*(*ext)++ = u & 0xff;
return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (u >> 24) & 0xff;
*(*ext)++ = (u >> 16) & 0xff;
@@ -234,29 +223,28 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
case ERL_LONGLONG:
l = ep->uval.llval.i;
/* ERL_SMALL_BIG */
- if ((l > ((long long) ERL_MAX)) ||
- (l < ((long long) ERL_MIN))) {
- *(*ext)++ = ERL_SMALL_BIG_EXT;
- *(*ext)++ = 8; /* eight bytes */
- if ((*(*ext)++ = ((l>>63) & 0x01))) /* sign byte */
+ if (l > ((long long) INT_MAX) || l < ((long long) INT_MIN)) {
+ *(*ext)++ = ERL_SMALL_BIG_EXT;
+ *(*ext)++ = 8;
+ if ((*(*ext)++ = (l<0))) /* sign byte */
l = -l;
- *(*ext)++ = l & 0xff; /* LSB first */
+ *(*ext)++ = l & 0xff; /* LSB first */
*(*ext)++ = (l >> 8) & 0xff;
*(*ext)++ = (l >> 16) & 0xff;
- *(*ext)++ = (l >> 24) & 0xff;
- *(*ext)++ = (l >> 32) & 0xff;
- *(*ext)++ = (l >> 40) & 0xff;
- *(*ext)++ = (l >> 48) & 0xff;
- *(*ext)++ = (l >> 56) & 0x7f; /* Don't include the sign bit */
+ *(*ext)++ = (l >> 24) & 0xff;
+ *(*ext)++ = (l >> 32) & 0xff;
+ *(*ext)++ = (l >> 40) & 0xff;
+ *(*ext)++ = (l >> 48) & 0xff;
+ *(*ext)++ = (l >> 56) & 0xff;
return 0;
}
/* SMALL_INTEGER */
if ((l < 256) && (l >= 0)) {
- *(*ext)++ = ERL_SMALL_INTEGER_EXT;
- *(*ext)++ = l & 0xff;
- return 0;
+ *(*ext)++ = ERL_SMALL_INTEGER_EXT;
+ *(*ext)++ = l & 0xff;
+ return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (l >> 24) & 0xff;
*(*ext)++ = (l >> 16) & 0xff;
@@ -267,7 +255,7 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
case ERL_U_LONGLONG:
ul = ep->uval.ullval.u;
/* ERL_U_SMALL_BIG */
- if (ul > ((unsigned long long) ERL_MAX)) {
+ if (ul > ((unsigned long long) INT_MAX)) {
*(*ext)++ = ERL_SMALL_BIG_EXT;
*(*ext)++ = 8; /* eight bytes */
*(*ext)++ = 0; /* sign byte */
@@ -287,7 +275,7 @@ int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
*(*ext)++ = ul & 0xff;
return 0;
}
- /* INTEGER */
+ /* R14B: Use all 32 bits of INTEGER_EXT */
*(*ext)++ = ERL_INTEGER_EXT;
*(*ext)++ = (ul >> 24) & 0xff;
*(*ext)++ = (ul >> 16) & 0xff;
@@ -732,11 +720,6 @@ static ETERM *erl_decode_it(unsigned char **ext)
if (arity > 8)
goto big_truncate;
- if (arity == 8 && ((*ext)[7] & 0x80) && sign) {
- /* MSB already occupied ! */
- goto big_truncate;
- }
-
if (arity == 4 && ((*ext)[3] & 0x80) && !sign) {
/* It will fit into an unsigned int !! */
u = (((*ext)[3] << 24)|((*ext)[2])<< 16|((*ext)[1]) << 8 |(**ext));
@@ -747,14 +730,10 @@ static ETERM *erl_decode_it(unsigned char **ext)
return ep;
} else if (arity == 4 && !((*ext)[3] & 0x80)) {
/* It will fit into an int !!
- * Note: It comes in "one's-complement notation"
*/
- if (sign)
- i = (int) (~(((*ext)[3] << 24) | ((*ext)[2])<< 16 |
- ((*ext)[1]) << 8 | (**ext)) | (unsigned int) sign);
- else
- i = (int) (((*ext)[3] << 24) | ((*ext)[2])<< 16 |
- ((*ext)[1]) << 8 | (**ext));
+ i = (int) (((*ext)[3] << 24) | ((*ext)[2])<< 16 |
+ ((*ext)[1]) << 8 | (**ext));
+ if (sign) i = -i;
ERL_TYPE(ep) = ERL_INTEGER;
ep->uval.ival.i = i;
*ext += arity;
@@ -780,8 +759,10 @@ static ETERM *erl_decode_it(unsigned char **ext)
for(x = 0 ; x < arity ; x++) {
l |= ((long long)(*ext)[x]) << ((long long)(8*x));
}
-
- if (sign) l = (long long) (~l | (unsigned long long) sign);
+ if (sign) {
+ l = -l;
+ if (l > 0) goto big_truncate;
+ }
ERL_TYPE(ep) = ERL_LONGLONG;
ep->uval.llval.i = l;
diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl
index c6858b45ad..09a37409f2 100644
--- a/lib/erl_interface/test/ei_decode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_SUITE.erl
@@ -222,14 +222,16 @@ send_integers(P) ->
?line send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*)
?line send_term_as_binary(P,-1), % INTEGER_EXT largest neg
- ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT largest (28 bits)
- ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT smallest
- ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT smallest pos(*)
- ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT largest neg (*)
-
- ?line send_term_as_binary(P, 16#7fffffff), % SMALL_BIG_EXT largest i32
- ?line send_term_as_binary(P,-16#80000000), % SMALL_BIG_EXT smallest i32
-
+ ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT old largest (28 bits)
+ ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT old smallest
+ ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT old smallest pos(*)
+ ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT old largest neg (*)
+
+ ?line send_term_as_binary(P, 16#7fffffff), % INTEGER_EXT new largest (32 bits)
+ ?line send_term_as_binary(P,-16#80000000), % INTEGER_EXT new smallest (32 bis)
+ ?line send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*)
+ ?line send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*)
+
case erlang:system_info(wordsize) of
4 ->
?line send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32
@@ -266,15 +268,17 @@ send_integers2(P) ->
?line send_term_as_binary(P,255), % SMALL_INTEGER_EXT largest
?line send_term_as_binary(P,256), % INTEGER_EXT smallest pos (*)
?line send_term_as_binary(P,-1), % INTEGER_EXT largest neg
+
+ ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT old largest (28 bits)
+ ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT old smallest
+ ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT old smallest pos(*)
+ ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT old largest neg (*)
- ?line send_term_as_binary(P, 16#07ffffff), % INTEGER_EXT largest (28 bits)
- ?line send_term_as_binary(P,-16#08000000), % INTEGER_EXT smallest
- ?line send_term_as_binary(P, 16#08000000), % SMALL_BIG_EXT smallest pos(*)
- ?line send_term_as_binary(P,-16#08000001), % SMALL_BIG_EXT largest neg (*)
+ ?line send_term_as_binary(P, 16#7fffffff), % INTEGER_EXT new largest (32 bits)
+ ?line send_term_as_binary(P,-16#80000000), % INTEGER_EXT new smallest
+ ?line send_term_as_binary(P, 16#80000000), % SMALL_BIG_EXT new smallest pos(*)
+ ?line send_term_as_binary(P,-16#80000001), % SMALL_BIG_EXT new largest neg (*)
- ?line send_term_as_binary(P, 16#7fffffff), % SMALL_BIG_EXT largest i32
- ?line send_term_as_binary(P,-16#80000000), % SMALL_BIG_EXT smallest i32
- ?line send_term_as_binary(P, 16#80000000),% SMALL_BIG_EXT u32
?line send_term_as_binary(P, 16#ffffffff),% SMALL_BIG_EXT largest u32
?line send_term_as_binary(P, 16#7fffffffffff), % largest i48
diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
index 5447e2deb3..b349138ae9 100644
--- a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
+++ b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
@@ -246,13 +246,23 @@ TESTCASE(test_ei_decode_long)
EI_DECODE_2 (decode_long, 5, long, 256);
EI_DECODE_2 (decode_long, 5, long, -1);
+ /* Old 28 bit limits for INTEGER_EXT */
EI_DECODE_2 (decode_long, 5, long, 0x07ffffff);
EI_DECODE_2 (decode_long, 5, long, -0x08000000);
- EI_DECODE_2 (decode_long, 7, long, 0x08000000);
- EI_DECODE_2 (decode_long, 7, long, -0x08000001);
+ EI_DECODE_2 (decode_long, 5, long, 0x08000000);
+ EI_DECODE_2 (decode_long, 5, long, -0x08000001);
- EI_DECODE_2 (decode_long, 7, long, 0x7fffffff);
- EI_DECODE_2 (decode_long, 7, long, -ll(0x80000000)); /* Strange :-( */
+ /* New 32 bit limits for INTEGER_EXT */
+ EI_DECODE_2 (decode_long, 5, long, 0x7fffffff);
+ EI_DECODE_2 (decode_long, 5, long, -ll(0x80000000)); /* Strange :-( */
+ if (sizeof(long) > 4) {
+ EI_DECODE_2(decode_long, 7, long, 0x80000000);
+ EI_DECODE_2(decode_long, 7, long, -ll(0x80000001));
+ }
+ else {
+ EI_DECODE_2_FAIL(decode_long, 7, long, 0x80000000);
+ EI_DECODE_2_FAIL(decode_long, 7, long, -ll(0x80000001));
+ }
EI_DECODE_2_FAIL(decode_long, 7, long, 0x80000000);
EI_DECODE_2_FAIL(decode_long, 7, long, 0xffffffff);
@@ -280,11 +290,13 @@ TESTCASE(test_ei_decode_ulong)
EI_DECODE_2 (decode_ulong, 5, unsigned long, 0x07ffffff);
EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -0x08000000);
- EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x08000000);
- EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -0x08000001);
+ EI_DECODE_2 (decode_ulong, 5, unsigned long, 0x08000000);
+ EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -0x08000001);
- EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x7fffffff);
- EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -ll(0x80000000));
+ EI_DECODE_2 (decode_ulong, 5, unsigned long, 0x7fffffff);
+ EI_DECODE_2_FAIL(decode_ulong, 5, unsigned long, -ll(0x80000000));
+ EI_DECODE_2 (decode_ulong, 7, unsigned long, 0x80000000);
+ EI_DECODE_2_FAIL(decode_ulong, 7, unsigned long, -ll(0x80000001));
if (sizeof(long) > 4) {
EI_DECODE_2 (decode_ulong, 11, unsigned long, ll(0x8000000000000000));
@@ -319,13 +331,14 @@ TESTCASE(test_ei_decode_longlong)
EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 0x07ffffff);
EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -0x08000000);
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x08000000);
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -0x08000001);
-
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x7fffffff);
- EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -ll(0x80000000));
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 0x08000000);
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -0x08000001);
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, 0x7fffffff);
+ EI_DECODE_2 (decode_longlong, 5, EI_LONGLONG, -ll(0x80000000));
EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0x80000000);
+ EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, -ll(0x80000001));
+
EI_DECODE_2 (decode_longlong, 7, EI_LONGLONG, 0xffffffff);
EI_DECODE_2 (decode_longlong, 9, EI_LONGLONG, ll(0x7fffffffffff));
@@ -352,13 +365,14 @@ TESTCASE(test_ei_decode_ulonglong)
EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 0x07ffffff);
EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -0x08000000);
- EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x08000000);
- EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -0x08000001);
-
- EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x7fffffff);
- EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -ll(0x80000000));
+ EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 0x08000000);
+ EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -0x08000001);
+ EI_DECODE_2 (decode_ulonglong, 5, EI_ULONGLONG, 0x7fffffff);
+ EI_DECODE_2_FAIL(decode_ulonglong, 5, EI_ULONGLONG, -ll(0x80000000));
EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0x80000000);
+ EI_DECODE_2_FAIL(decode_ulonglong, 7, EI_ULONGLONG, -0x80000001);
+
EI_DECODE_2 (decode_ulonglong, 7, EI_ULONGLONG, 0xffffffff);
EI_DECODE_2 (decode_ulonglong, 9, EI_ULONGLONG, ll(0x7fffffffffff));
diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
index 6b2ec8f766..f273efd532 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
+++ b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
@@ -63,32 +63,108 @@ TESTCASE(build_terms)
report(1);
}
+static int abs_and_sign(ETERM* v, unsigned long long* av, int* sign)
+{
+ long long sv;
+ switch (ERL_TYPE(v)) {
+ case ERL_INTEGER: sv = ERL_INT_VALUE(v); break;
+ case ERL_U_INTEGER: *av = ERL_INT_UVALUE(v); *sign = 0; return 1;
+ case ERL_LONGLONG: sv = ERL_LL_VALUE(v); break;
+ case ERL_U_LONGLONG: *av = ERL_LL_UVALUE(v); *sign = 0; return 1;
+ default: return 0;
+ }
+ if (sv < 0) {
+ *av = -sv;
+ *sign = 1;
+ }
+ else {
+ *av = sv;
+ *sign = 0;
+ }
+ return 1;
+}
+
+/* Shouldn't erl_match() cope with this?
+*/
+static int eq_ints(ETERM* a, ETERM* b)
+{
+ unsigned long long a_abs, b_abs;
+ int a_sign, b_sign;
+ return abs_and_sign(a, &a_abs, &a_sign) && abs_and_sign(b, &b_abs, &b_sign)
+ && (a_abs == b_abs) && (a_sign == b_sign);
+}
+
+static void encode_decode(ETERM* original, const char* text)
+{
+ static unsigned char encoded[16*1024];
+ ETERM* new_terms;
+ int bytes = erl_encode(original, encoded);
+
+ if (bytes == 0) {
+ fail("failed to encode terms");
+ }
+ else if (bytes > sizeof(encoded)) {
+ fail("encoded terms buffer overflow");
+ }
+ else if ((new_terms = erl_decode(encoded)) == NULL) {
+ fail("failed to decode terms");
+ }
+ else if (!erl_match(original, new_terms) && !eq_ints(original, new_terms)) {
+ erl_print_term(stderr, original);
+ fprintf(stderr, "(%i) != (%i)", ERL_TYPE(original), ERL_TYPE(new_terms));
+ erl_print_term(stderr, new_terms);
+ fprintf(stderr, " [%s]\r\n", text);
+ fail("decoded terms didn't match original");
+ }
+ erl_free_term(original);
+ erl_free_term(new_terms);
+}
/*
* Converts an Erlang term to the external term format and back again.
*/
TESTCASE(round_trip_conversion)
{
- ETERM* original;
- ETERM* new_terms;
- char encoded[16*1024];
- int n;
+ int n, i;
erl_init(NULL, 0);
- original = all_types();
- if (erl_encode(original, encoded) == 0)
+ encode_decode(all_types(), "ALL");
+
{
- fail("failed to encode terms");
- } else if ((new_terms = erl_decode(encoded)) == NULL)
+ int v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_int(v+i), "INT");
+ encode_decode(erl_mk_int(-(v+i)), "NEG INT");
+ }
+ }
+ }
{
- fail("failed to decode terms");
- } else if (!erl_match(original, new_terms))
+ unsigned int v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_uint(v+i), "UINT");
+ }
+ }
+ }
{
- fail("decoded terms didn't match original");
+ long long v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_longlong(v+i), "LONGLONG");
+ encode_decode(erl_mk_longlong(-(v+i)), "NEG LONGLONG");
+ }
+ }
+ }
+ {
+ unsigned long long v;
+ for (v = 8; v; v <<= 1) {
+ for (i=-4; i<4; i++) {
+ encode_decode(erl_mk_ulonglong(v+i), "ULONGLONG");
+ }
+ }
}
- erl_free_term(original);
- erl_free_term(new_terms);
report(1);
}
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 9df3dedb45..1f0247a040 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -2337,8 +2337,7 @@ type(lists, flatten, 1, Xs) ->
t_list();
false ->
X2 = type(lists, flatten, 1, [t_inf(X1, t_list())]),
- t_sup(t_list(t_subtract(X1, t_list())),
- X2)
+ t_sup(t_list(t_subtract(X1, t_list())), X2)
end
end
end);
@@ -2349,10 +2348,20 @@ type(lists, flatmap, 2, Xs) ->
true -> t_nil();
false ->
case check_fun_application(F, [t_list_elements(List)]) of
- ok ->
- case t_is_cons(List) of
- true -> t_nonempty_list(t_list_elements(t_fun_range(F)));
- false -> t_list(t_list_elements(t_fun_range(F)))
+ ok ->
+ R = t_fun_range(F),
+ case t_is_nil(R) of
+ true -> t_nil();
+ false ->
+ Elems = t_list_elements(R),
+ case t_is_cons(List) of
+ true ->
+ case t_is_subtype(t_nil(), R) of
+ true -> t_list(Elems);
+ false -> t_nonempty_list(Elems)
+ end;
+ false -> t_list(Elems)
+ end
end;
error ->
case t_is_cons(List) of
diff --git a/lib/jinterface/java_src/Makefile b/lib/jinterface/java_src/Makefile
index 37a57352ad..22c55328b8 100644
--- a/lib/jinterface/java_src/Makefile
+++ b/lib/jinterface/java_src/Makefile
@@ -35,7 +35,21 @@ VSN=$(JINTERFACE_VSN)
SPECIAL_TARGETS =
+TARGET_FILES= $(POM_TARGET)
+SPECIAL_TARGETS =
+
+POM_FILE= pom.xml
+
+POM_TARGET= ../$(POM_FILE)
+POM_SRC= $(POM_FILE).src
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+$(POM_TARGET): $(POM_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
# ----------------------------------------------------
# Default Subdir Targets
@@ -43,7 +57,7 @@ SPECIAL_TARGETS =
.PHONY: debug opt instr release docs release_docs tests release_tests clean depend
-debug opt instr release docs release_docs tests release_tests clean depend:
+debug opt instr release docs release_docs tests release_tests clean depend: $(TARGET_FILES)
set -e; set -x; \
case "$(MAKE)" in *clearmake*) tflag="-T";; *) tflag="";; esac; \
if test -f com/ericsson/otp/erlang/ignore_config_record.inf; then xflag=$$tflag; fi; \
diff --git a/lib/jinterface/java_src/pom.xml.src b/lib/jinterface/java_src/pom.xml.src
new file mode 100644
index 0000000000..cef49b735a
--- /dev/null
+++ b/lib/jinterface/java_src/pom.xml.src
@@ -0,0 +1,106 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.erlang.otp</groupId>
+ <artifactId>jinterface</artifactId>
+ <packaging>jar</packaging>
+ <version>%VSN%</version>
+ <name>jinterface</name>
+ <description>
+ Jinterface Java package contains java classes, which help you integrate programs written in Java with Erlang.
+ Erlang is a programming language designed at the Ericsson Computer Science Laboratory.
+ </description>
+ <url>http://erlang.org/</url>
+ <licenses>
+ <license>
+ <name>ERLANG PUBLIC LICENSE 1.1</name>
+ <url>http://www.erlang.org/EPLICENSE</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <connection>git://github.com/erlang/otp.git</connection>
+ <developerConnection>git://github.com/erlang/otp.git</developerConnection>
+ <url>http://github.com/erlang/otp</url>
+ </scm>
+ <developers>
+ <developer>
+ <email>[email protected]</email>
+ </developer>
+ </developers>
+ <organization>
+ <name>Open Source Erlang</name>
+ <url>http://www.erlang.org/</url>
+ </organization>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>java_src</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <distributionManagement>
+ <repository>
+ <id>ossrh</id>
+ <url>http://oss.sonatype.org/service/local/staging/deploy/maven2</url>
+ </repository>
+ <snapshotRepository>
+ <id>ossrh</id>
+ <url>http://oss.sonatype.org/content/repositories/snapshots</url>
+ </snapshotRepository>
+ </distributionManagement>
+ <profiles>
+ <profile>
+ <id>release-sign-artifacts</id>
+ <activation>
+ <property>
+ <name>performRelease</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.0-alpha-4</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+</project>
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index a9ceac0bcf..2044b074ee 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -1229,7 +1229,7 @@ f.txt: {person, "kalle", 25}.
</item>
<tag><c>{no_translation, unicode, latin1}</c></tag>
<item>
- <p>The file is was opened with another <c>encoding</c> than <c>latin1</c> and the data on the file can not be translated to the byte-oriented data that this function returns.</p>
+ <p>The file was opened with another <c>encoding</c> than <c>latin1</c> and the data in the file can not be translated to the byte-oriented data that this function returns.</p>
</item>
</taglist>
</desc>
diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl
index 7fe30ae828..5c7fe2421d 100644
--- a/lib/kernel/src/auth.erl
+++ b/lib/kernel/src/auth.erl
@@ -50,6 +50,8 @@
%% Exported functions
%%----------------------------------------------------------------------
+-spec start_link() -> {'ok',pid()} | {'error', term()} | 'ignore'.
+
start_link() ->
gen_server:start_link({local, auth}, auth, [], []).
@@ -134,7 +136,9 @@ init([]) ->
%% The net kernel will let all message to the auth server
%% through as is
--type calls() :: 'echo' | 'sync_cookie' | {'set_cookie', node(), term()}.
+-type calls() :: 'echo' | 'sync_cookie'
+ | {'get_cookie', node()}
+ | {'set_cookie', node(), term()}.
-spec handle_call(calls(), {pid(), term()}, state()) ->
{'reply', 'hello' | 'true' | 'nocookie' | cookie(), state()}.
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index bd5685952e..fa1991872b 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -34,12 +34,12 @@
-export([send_to_closed/1,
buffer_size/1, binary_passive_recv/1, bad_address/1,
- read_packets/1, open_fd/1]).
+ read_packets/1, open_fd/1, connect/1]).
all(suite) ->
[send_to_closed,
buffer_size, binary_passive_recv, bad_address, read_packets,
- open_fd].
+ open_fd, connect].
init_per_testcase(_Case, Config) ->
?line Dog=test_server:timetrap(?default_timeout),
@@ -408,3 +408,20 @@ start_node(Name) ->
stop_node(Node) ->
?t:stop_node(Node).
+
+
+connect(suite) ->
+ [];
+connect(doc) ->
+ ["Test that connect/3 has effect"];
+connect(Config) when is_list(Config) ->
+ Addr = {127,0,0,1},
+ {ok,S1} = gen_udp:open(0),
+ {ok,P1} = inet:port(S1),
+ {ok,S2} = gen_udp:open(0),
+ ok = inet:setopts(S2, [{active,false}]),
+ ok = gen_udp:close(S1),
+ ok = gen_udp:connect(S2, Addr, P1),
+ ok = gen_udp:send(S2, <<16#deadbeef:32>>),
+ {error,econnrefused} = gen_udp:recv(S2, 0, 5),
+ ok.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 3811906d77..fcc30f6137 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -304,9 +304,15 @@ certificate_verify(Signature, {_, PublicKey, _}, Version,
end;
certificate_verify(Signature, {_, PublicKey, PublicKeyParams}, Version,
MasterSecret, dhe_dss = Algorithm, {_, Hashes0}) ->
- Hashes = calc_certificate_verify(Version, MasterSecret,
- Algorithm, Hashes0),
- public_key:verify_signature(Hashes, sha, Signature, PublicKey, PublicKeyParams).
+ Hashes = calc_certificate_verify(Version, MasterSecret,
+ Algorithm, Hashes0),
+ case public_key:verify_signature(Hashes, none, Signature, PublicKey, PublicKeyParams) of
+ true ->
+ valid;
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
+ end.
+
%%--------------------------------------------------------------------
-spec certificate_request(#connection_states{}, certdb_ref()) ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 40715dbf30..dd0818827a 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -325,6 +325,10 @@ make_dsa_cert(Config) ->
[{server_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_dsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
{client_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index d2a4ca8db5..75cfce0052 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -309,7 +309,7 @@ tls1_erlang_server_openssl_client_dsa_cert(suite) ->
tls1_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ?config(client_dsa_opts, Config),
- ServerOpts = ?config(server_dsa_opts, Config),
+ ServerOpts = ?config(server_dsa_verify_opts, Config),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
@@ -398,7 +398,7 @@ ssl3_erlang_server_openssl_client_dsa_cert(suite) ->
ssl3_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ?config(client_dsa_opts, Config),
- ServerOpts = ?config(server_dsa_opts, Config),
+ ServerOpts = ?config(server_dsa_verify_opts, Config),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 74b1cf4c78..254ee8b986 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -17,12 +17,14 @@
# %CopyrightEnd%
#
-SSL_VSN = 4.0
+SSL_VSN = 4.0.1
-TICKETS = OTP-8587\
- OTP-8695
+TICKETS = OTP-8721
-#TICKETS = OTP-8679 \
+#TICKETS_4.0 = OTP-8587\
+# OTP-8695
+
+#TICKETS_3.11.1 = OTP-8679 \
# OTP-7047 \
# OTP-7049 \
# OTP-8568 \
diff --git a/lib/stdlib/doc/src/beam_lib.xml b/lib/stdlib/doc/src/beam_lib.xml
index 27308e02f3..adc411e272 100644
--- a/lib/stdlib/doc/src/beam_lib.xml
+++ b/lib/stdlib/doc/src/beam_lib.xml
@@ -341,6 +341,7 @@ chunkref() = chunkname() | chunkid()</code>
<v>Beam1 = Beam2 = beam()</v>
<v>Reason = {modules_different, Module1, Module2}</v>
<v>&nbsp;&nbsp;| {chunks_different, ChunkId}</v>
+ <v>&nbsp;&nbsp;| different_chunks</v>
<v>&nbsp;&nbsp;| Reason1 -- see info/1</v>
<v>&nbsp;Module1 = Module2 = atom()</v>
<v>&nbsp;ChunkId = chunkid()</v>
diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml
index 034fff3c25..1b34e71490 100644
--- a/lib/stdlib/doc/src/timer.xml
+++ b/lib/stdlib/doc/src/timer.xml
@@ -202,19 +202,33 @@
</func>
<func>
<name>tc(Module, Function, Arguments) -> {Time, Value}</name>
- <fsummary>Measure the real time it takes to evaluate <c>apply(Module, Function, Arguments)</c></fsummary>
+ <name>tc(Fun, Arguments) -> {Time, Value}</name>
+ <fsummary>Measure the real time it takes to evaluate <c>apply(Module,
+ Function, Arguments)</c> or <c>apply(Fun, Arguments)</c></fsummary>
<type>
<v>Module = Function = atom()</v>
+ <v>Fun = fun()</v>
<v>Arguments = [term()]</v>
<v>Time = integer() in microseconds</v>
<v>Value = term()</v>
</type>
<desc>
- <p>Evaluates <c>apply(Module, Function, Arguments)</c> and measures
- the elapsed real time as reported by <c>now/0</c>.
- Returns <c>{Time, Value}</c>, where
- <c>Time</c> is the elapsed real time in <em>microseconds</em>,
- and <c>Value</c> is what is returned from the apply.</p>
+ <p></p>
+ <taglist>
+ <tag><c>tc/3</c></tag>
+ <item>
+ <p>Evaluates <c>apply(Module, Function, Arguments)</c> and measures
+ the elapsed real time as reported by <c>now/0</c>.
+ Returns <c>{Time, Value}</c>, where
+ <c>Time</c> is the elapsed real time in <em>microseconds</em>,
+ and <c>Value</c> is what is returned from the apply.</p>
+ </item>
+ <tag><c>tc/2</c></tag>
+ <item>
+ <p>Evaluates <c>apply(Fun, Arguments)</c>. Otherwise works
+ like <c>tc/3</c>.</p>
+ </item>
+ </taglist>
</desc>
</func>
<func>
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index 91ff2438c6..e612bf71e7 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -105,6 +105,7 @@
| info_rsn().
-type cmp_rsn() :: {'modules_different', module(), module()}
| {'chunks_different', chunkid()}
+ | 'different_chunks'
| info_rsn().
%%-------------------------------------------------------------------------
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index d26443f277..99e454f593 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -24,35 +24,41 @@
%% Internal API.
-export([start/0, start/1]).
--include_lib("kernel/include/file.hrl").
+%%-----------------------------------------------------------------------
-define(SHEBANG, "/usr/bin/env escript").
-define(COMMENT, "This is an -*- erlang -*- file").
--record(state, {file,
- module,
+%%-----------------------------------------------------------------------
+
+-type mode() :: 'compile' | 'debug' | 'interpret' | 'run'.
+-type source() :: 'archive' | 'beam' | 'text'.
+
+-record(state, {file :: file:filename(),
+ module :: module(),
forms_or_bin,
- source,
- n_errors,
- mode,
- exports_main,
- has_records}).
--record(sections, {type,
- shebang,
- comment,
- emu_args,
- body}).
--record(extract_options, {compile_source}).
+ source :: source(),
+ n_errors :: non_neg_integer(),
+ mode :: mode(),
+ exports_main :: boolean(),
+ has_records :: boolean()}).
-type shebang() :: string().
-type comment() :: string().
-type emu_args() :: string().
--type escript_filename() :: string().
--type filename() :: string().
+
+-record(sections, {type,
+ shebang :: shebang(),
+ comment :: comment(),
+ emu_args :: emu_args(),
+ body}).
+
+-record(extract_options, {compile_source}).
+
-type zip_file() ::
- filename()
- | {filename(), binary()}
- | {filename(), binary(), #file_info{}}.
+ file:filename()
+ | {file:filename(), binary()}
+ | {file:filename(), binary(), file:file_info()}.
-type zip_create_option() :: term().
-type section() ::
shebang
@@ -60,13 +66,15 @@
| comment
| {comment, comment()}
| {emu_args, emu_args()}
- | {source, filename() | binary()}
- | {beam, filename() | binary()}
- | {archive, filename() | binary()}
+ | {source, file:filename() | binary()}
+ | {beam, file:filename() | binary()}
+ | {archive, file:filename() | binary()}
| {archive, [zip_file()], [zip_create_option()]}.
+%%-----------------------------------------------------------------------
+
%% Create a complete escript file with both header and body
--spec create(escript_filename() | binary, [section()]) ->
+-spec create(file:filename() | binary, [section()]) ->
ok | {ok, binary()} | {error, term()}.
create(File, Options) when is_list(Options) ->
@@ -149,7 +157,9 @@ prepare(BadOptions, _) ->
-type section_name() :: shebang | comment | emu_args | body .
-type extract_option() :: compile_source | {section, [section_name()]}.
--spec extract(filename(), [extract_option()]) -> {ok, [section()]} | {error, term()}.
+-spec extract(file:filename(), [extract_option()]) ->
+ {ok, [section()]} | {error, term()}.
+
extract(File, Options) when is_list(File), is_list(Options) ->
try
EO = parse_extract_options(Options,
@@ -239,6 +249,7 @@ normalize_section(Name, Chars) ->
{Name, Chars}.
-spec script_name() -> string().
+
script_name() ->
[ScriptName|_] = init:get_plain_arguments(),
ScriptName.
@@ -248,10 +259,12 @@ script_name() ->
%%
-spec start() -> no_return().
+
start() ->
start([]).
-spec start([string()]) -> no_return().
+
start(EscriptOptions) ->
try
%% Commands run using -run or -s are run in a process
@@ -484,18 +497,12 @@ find_first_body_line(Fd, HeaderSz0, LineNo, KeepFirst, Sections) ->
classify_line(Line) ->
case Line of
- [$\#, $\! | _] ->
- shebang;
- [$P, $K | _] ->
- archive;
- [$F, $O, $R, $1 | _] ->
- beam;
- [$%, $%, $\! | _] ->
- emu_args;
- [$% | _] ->
- comment;
- _ ->
- undefined
+ "#!" ++ _ -> shebang;
+ "PK" ++ _ -> archive;
+ "FOR1" ++ _ -> beam;
+ "%%!" ++ _ -> emu_args;
+ "%" ++ _ -> comment;
+ _ -> undefined
end.
guess_type(Line) ->
@@ -531,7 +538,6 @@ parse_archive(S, File, HeaderSz) ->
end,
list_to_atom(lists:reverse(RevBase2))
end,
-
S#state{source = archive,
mode = run,
module = Mod,
@@ -587,8 +593,8 @@ parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly) ->
epp_parse_file2(Epp, S2, [ModForm, FileForm], OptModRes);
{error, _} ->
epp_parse_file2(Epp, S2, [FileForm], OptModRes);
- {eof,LastLine} ->
- S#state{forms_or_bin = [FileForm, {eof,LastLine}]}
+ {eof, _LastLine} = Eof ->
+ S#state{forms_or_bin = [FileForm, Eof]}
end,
ok = epp:close(Epp),
ok = file:close(Fd),
@@ -683,8 +689,8 @@ epp_parse_file2(Epp, S, Forms, Parsed) ->
io:format("~s:~w: ~s\n",
[S#state.file,Ln,Mod:format_error(Args)]),
epp_parse_file(Epp, S#state{n_errors = S#state.n_errors + 1}, [Form | Forms]);
- {eof,LastLine} ->
- S#state{forms_or_bin = lists:reverse([{eof, LastLine} | Forms])}
+ {eof, _LastLine} = Eof ->
+ S#state{forms_or_bin = lists:reverse([Eof | Forms])}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/stdlib/src/timer.erl b/lib/stdlib/src/timer.erl
index 6ee837c3e6..24e14caa69 100644
--- a/lib/stdlib/src/timer.erl
+++ b/lib/stdlib/src/timer.erl
@@ -22,7 +22,7 @@
send_after/3, send_after/2,
exit_after/3, exit_after/2, kill_after/2, kill_after/1,
apply_interval/4, send_interval/3, send_interval/2,
- cancel/1, sleep/1, tc/3, now_diff/2,
+ cancel/1, sleep/1, tc/2, tc/3, now_diff/2,
seconds/1, minutes/1, hours/1, hms/3]).
-export([start_link/0, start/0,
@@ -98,6 +98,17 @@ sleep(T) ->
after T -> ok
end.
+
+%%
+%% Measure the execution time (in microseconds) for Fun(Args).
+%%
+-spec tc(function(), [_]) -> {time(), term()}.
+tc(F, A) ->
+ Before = erlang:now(),
+ Val = (catch apply(F, A)),
+ After = erlang:now(),
+ {now_diff(After, Before), Val}.
+
%%
%% Measure the execution time (in microseconds) for an MFA.
%%
diff --git a/lib/stdlib/test/timer_simple_SUITE.erl b/lib/stdlib/test/timer_simple_SUITE.erl
index 021a22c61b..6aa2b7b945 100644
--- a/lib/stdlib/test/timer_simple_SUITE.erl
+++ b/lib/stdlib/test/timer_simple_SUITE.erl
@@ -224,11 +224,19 @@ cancel2(Config) when is_list(Config) ->
tc(doc) -> "Test sleep/1 and tc/3.";
tc(suite) -> [];
tc(Config) when is_list(Config) ->
- % This should both sleep and tc
- ?line {Res, ok} = timer:tc(timer, sleep, [500]),
- ?line ok = if
- Res < 500*1000 -> {too_early, Res}; % Too early
- Res > 800*1000 -> {too_late, Res}; % Too much time
+ % This should both sleep and tc/3
+ ?line {Res1, ok} = timer:tc(timer, sleep, [500]),
+ ?line ok = if
+ Res1 < 500*1000 -> {too_early, Res1}; % Too early
+ Res1 > 800*1000 -> {too_late, Res1}; % Too much time
+ true -> ok
+ end,
+
+ % This should both sleep and tc/2
+ ?line {Res2, ok} = timer:tc(fun(T) -> timer:sleep(T) end, [500]),
+ ?line ok = if
+ Res2 < 500*1000 -> {too_early, Res2}; % Too early
+ Res2 > 800*1000 -> {too_late, Res2}; % Too much time
true -> ok
end,
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index 1245c10a01..72f274d63a 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -151,10 +151,12 @@
%%% OPERATOR INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([add_spec/1, add_dir/2, add_dir/3]).
--export([add_module/1, add_module/2, add_case/2, add_case/3, add_cases/2,
- add_cases/3]).
+-export([add_module/1, add_module/2,
+ add_conf/3,
+ add_case/2, add_case/3, add_cases/2, add_cases/3]).
-export([add_dir_with_skip/3, add_dir_with_skip/4, add_tests_with_skip/3]).
-export([add_module_with_skip/2, add_module_with_skip/3,
+ add_conf_with_skip/4,
add_case_with_skip/3, add_case_with_skip/4,
add_cases_with_skip/3, add_cases_with_skip/4]).
-export([jobs/0, run_test/1, wait_finish/0, idle_notify/1,
@@ -236,9 +238,16 @@ add_dir(Name, Dir, Pattern) ->
add_module(Mod) when is_atom(Mod) ->
add_job(atom_to_list(Mod), {Mod,all}).
+
add_module(Name, Mods) when is_list(Mods) ->
add_job(cast_to_list(Name), lists:map(fun(Mod) -> {Mod,all} end, Mods)).
+add_conf(Name, Mod, Conf) when is_tuple(Conf) ->
+ add_job(cast_to_list(Name), {Mod,[Conf]});
+
+add_conf(Name, Mod, Confs) when is_list(Confs) ->
+ add_job(cast_to_list(Name), {Mod,Confs}).
+
add_case(Mod, Case) when is_atom(Mod), is_atom(Case) ->
add_job(atom_to_list(Mod), {Mod,Case}).
@@ -283,6 +292,12 @@ add_module_with_skip(Mod, Skip) when is_atom(Mod) ->
add_module_with_skip(Name, Mods, Skip) when is_list(Mods) ->
add_job(cast_to_list(Name), lists:map(fun(Mod) -> {Mod,all} end, Mods), Skip).
+add_conf_with_skip(Name, Mod, Conf, Skip) when is_tuple(Conf) ->
+ add_job(cast_to_list(Name), {Mod,[Conf]}, Skip);
+
+add_conf_with_skip(Name, Mod, Confs, Skip) when is_list(Confs) ->
+ add_job(cast_to_list(Name), {Mod,Confs}, Skip).
+
add_case_with_skip(Mod, Case, Skip) when is_atom(Mod), is_atom(Case) ->
add_job(atom_to_list(Mod), {Mod,Case}, Skip).
@@ -1549,8 +1564,8 @@ temp_nodename([Chr|Base], Acc) ->
%% of cases can not be calculated and NoOfCases = unknown.
count_test_cases(TopCases, SkipCases) when is_list(TopCases) ->
case collect_all_cases(TopCases, SkipCases) of
- {error,_} ->
- error;
+ {error,_Why} = Error ->
+ Error;
TestSpec ->
{get_suites(TestSpec, []),
case remove_conf(TestSpec) of
@@ -1656,22 +1671,31 @@ do_test_cases(TopCases, SkipCases,
put(test_server_case_num, 0),
TestSpec =
add_init_and_end_per_suite(TestSpec0, undefined, undefined),
+
TI = get_target_info(),
print(1, "Starting test~s", [print_if_known(N, {", ~w test cases",[N]},
{" (with repeated test cases)",[]})]),
- test_server_sup:framework_call(report, [tests_start,
- {get(test_server_name),N}]),
- print(html,
- "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
- "<html>\n"
- "<head><title>Test ~p results</title>\n"
- "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n"
- "</head>\n"
- "<body bgcolor=\"white\" text=\"black\" "
- "link=\"blue\" vlink=\"purple\" alink=\"red\">"
- "<h2>Results from test ~p</h2>\n",
- [get(test_server_name),get(test_server_name)]),
+ Test = get(test_server_name),
+ test_server_sup:framework_call(report, [tests_start,{Test,N}]),
+
+ Header =
+ case test_server_sup:framework_call(overview_html_header, [Test], "") of
+ "" ->
+ TestName = lists:flatten(io_lib:format("~p", [Test])),
+ ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+ "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n",
+ "<html>\n",
+ "<head><title>Test ", TestName, " results</title>\n",
+ "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
+ "</head>\n",
+ "<body bgcolor=\"white\" text=\"black\" ",
+ "link=\"blue\" vlink=\"purple\" alink=\"red\">",
+ "<h2>Results from test ", TestName, "</h2>\n"];
+ Html ->
+ ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+ "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n" | Html]
+ end,
+ print(html, Header, []),
print_timestamp(html, "Test started at "),
print(html, "<p>Host:<br>\n"),
@@ -1702,7 +1726,7 @@ do_test_cases(TopCases, SkipCases,
[?suitelog_name,?coverlog_name]),
print(html,"<p>~s"
"<p>\n"
- "<table border=3 cellpadding=5>"
+ "<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">"
"<tr><th>Num</th><th>Module</th><th>Case</th><th>Log</th>"
"<th>Time</th><th>Result</th><th>Comment</th></tr>\n",
[print_if_known(N, {"Suite contains ~p test cases.\n",[N]},
@@ -2052,10 +2076,6 @@ run_test_cases(TestSpec, Config, TimetrapData) ->
html_convert_modules(TestSpec, Config),
- %%! For readable tracing...
- %%! Config1 = [{data_dir,""},{priv_dir,""},{nodes,[]}],
- %%! run_test_cases_loop(TestSpec, [[]], TimetrapData, [], []),
-
run_test_cases_loop(TestSpec, [Config], TimetrapData, [], []),
maybe_get_privdir(),
@@ -3537,7 +3557,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
case test_server_sup:framework_call(warn, [nodes], true) of
true ->
case catch controller_call(kill_slavenodes) of
- {'EXIT',_}=Exit ->
+ {'EXIT',_} = Exit ->
print(minor,
"WARNING: There might be slavenodes left in the"
" system. I tried to kill them, but I failed: ~p\n",
@@ -4417,7 +4437,7 @@ collect_all_cases(Top, Skip) when is_list(Skip) ->
Result =
case collect_cases(Top, #cc{mod=[],skip=Skip}) of
{ok,Cases,_St} -> Cases;
- Other -> Other
+ Other -> Other
end,
Result.
@@ -4429,9 +4449,9 @@ collect_cases([Case|Cs0], St0) ->
case collect_cases(Cs0, St1) of
{ok,FlatCases2,St} ->
{ok,FlatCases1 ++ FlatCases2,St};
- {error,_Reason}=Error -> Error
+ {error,_Reason} = Error -> Error
end;
- {error,_Reason}=Error -> Error
+ {error,_Reason} = Error -> Error
end;
@@ -4467,39 +4487,55 @@ collect_cases({conf,Props,InitMF,CaseList,FinF}, St) when is_atom(FinF) ->
Props1 ->
collect_cases({conf,Props1,InitMF,CaseList,{St#cc.mod,FinF}}, St)
end;
-collect_cases({conf,Props,InitMF,CaseList,FinMF}, St0) ->
- case collect_cases(CaseList, St0) of
- {ok,[],_St}=Empty ->
- Empty;
- {ok,FlatCases,St} ->
+collect_cases({conf,Props,InitMF,CaseList,FinMF} = Conf, St) ->
+ case init_props(Props) of
+ {error,_} ->
+ {ok,[],St};
+ Props1 ->
Ref = make_ref(),
- case in_skip_list(InitMF, St#cc.skip) of
- {true,Comment} ->
+ Skips = St#cc.skip,
+ case in_skip_list({St#cc.mod,Conf}, Skips) of
+ {true,Comment} -> % conf init skipped
{ok,[{skip_case,{conf,Ref,InitMF,Comment}} |
- FlatCases ++ [{conf,Ref,[],FinMF}]],St};
+ [] ++ [{conf,Ref,[],FinMF}]],St};
+ {true,Name,Comment} when is_atom(Name) -> % all cases skipped
+ {ok,[{skip_case,{{St#cc.mod,{group,Name}},Comment}}],St};
+ {true,ToSkip,_} when is_list(ToSkip) -> % some cases skipped
+ case collect_cases(CaseList,
+ St#cc{skip=ToSkip++Skips}) of
+ {ok,[],_St} = Empty ->
+ Empty;
+ {ok,FlatCases,St1} ->
+ {ok,[{conf,Ref,Props1,InitMF} |
+ FlatCases ++ [{conf,Ref,
+ keep_name(Props1),
+ FinMF}]],St1#cc{skip=Skips}};
+ {error,_Reason} = Error ->
+ Error
+ end;
false ->
- case init_props(Props) of
- {error,_} ->
- {ok,[],St};
- Props1 ->
+ case collect_cases(CaseList, St) of
+ {ok,[],_St} = Empty ->
+ Empty;
+ {ok,FlatCases,St1} ->
{ok,[{conf,Ref,Props1,InitMF} |
FlatCases ++ [{conf,Ref,
keep_name(Props1),
- FinMF}]],St}
+ FinMF}]],St1};
+ {error,_Reason} = Error ->
+ Error
end
- end;
- {error,_Reason}=Error ->
- Error
+ end
end;
collect_cases({make,InitMFA,CaseList,FinMFA}, St0) ->
case collect_cases(CaseList, St0) of
- {ok,[],_St}=Empty -> Empty;
+ {ok,[],_St} = Empty -> Empty;
{ok,FlatCases,St} ->
Ref = make_ref(),
{ok,[{make,Ref,InitMFA}|FlatCases ++
[{make,Ref,FinMFA}]],St};
- {error,_Reason}=Error -> Error
+ {error,_Reason} = Error -> Error
end;
collect_cases({Module, Cases}, St) when is_list(Cases) ->
@@ -4517,8 +4553,11 @@ 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) ->
- {error,{bad_subtest_spec,Other}}.
+collect_cases(Other, St) ->
+ {error,{bad_subtest_spec,St#cc.mod,Other}}.
+
+collect_case({Mod,{conf,_,_,_,_}=Conf}, St) ->
+ collect_case_invoke(Mod, Conf, [], St);
collect_case(MFA, St) ->
case in_skip_list(MFA, St#cc.skip) of
@@ -4555,6 +4594,7 @@ collect_case_invoke(Mod, Case, MFA, St) ->
collect_subcases(Mod, Case, MFA, St, Suite) ->
case Suite of
[] when Case == all -> {ok,[],St};
+ [] when element(1, Case) == conf -> {ok,[],St};
[] -> {ok,[MFA],St};
%%%! --- START Kept for backwards compatibilty ---
%%%! Requirements are not used
@@ -4565,6 +4605,8 @@ collect_subcases(Mod, Case, MFA, St, Suite) ->
%%%! --- END Kept for backwards compatibilty ---
{Skip,Reason} when Skip==skip; Skip==skipped ->
{ok,[{skip_case,{MFA,Reason}}],St};
+ {error,Reason} ->
+ throw(Reason);
SubCases ->
collect_case_subcases(Mod, Case, SubCases, St)
end.
@@ -4626,6 +4668,47 @@ check_deny_req(Req, DenyList) ->
false -> granted
end.
+in_skip_list({Mod,{conf,Props,InitMF,_CaseList,_FinMF}}, SkipList) ->
+ case in_skip_list(InitMF, SkipList) of
+ {true,_} = Yes ->
+ Yes;
+ _ ->
+ case proplists:get_value(name, Props) of
+ undefined ->
+ false;
+ Name ->
+ ToSkip =
+ lists:flatmap(
+ fun({M,{conf,SProps,_,SCaseList,_},Cmt}) when
+ M == Mod ->
+ case proplists:get_value(name, SProps) of
+ all ->
+ [{M,all,Cmt}];
+ Name ->
+ case SCaseList of
+ all ->
+ [{M,all,Cmt}];
+ _ ->
+ [{M,F,Cmt} || F <- SCaseList]
+ end;
+ _ ->
+ []
+ end;
+ (_) ->
+ []
+ end, SkipList),
+ case ToSkip of
+ [] ->
+ false;
+ _ ->
+ case lists:keysearch(all, 2, ToSkip) of
+ {value,{_,_,Cmt}} -> {true,Name,Cmt};
+ _ -> {true,ToSkip,""}
+ end
+ end
+ end
+ end;
+
in_skip_list({Mod,Func,_Args}, SkipList) ->
in_skip_list({Mod,Func}, SkipList);
in_skip_list({Mod,Func}, [{Mod,Funcs,Comment}|SkipList]) when is_list(Funcs) ->
diff --git a/lib/test_server/vsn.mk b/lib/test_server/vsn.mk
index ee3c957d59..4c3df28814 100644
--- a/lib/test_server/vsn.mk
+++ b/lib/test_server/vsn.mk
@@ -1,2 +1,2 @@
-TEST_SERVER_VSN = 3.4
+TEST_SERVER_VSN = 3.4.1