aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/common_test/doc/src/ct.xml86
-rw-r--r--lib/common_test/doc/src/write_test_chapter.xml44
-rw-r--r--lib/common_test/src/ct.erl96
-rw-r--r--lib/common_test/src/ct_logs.erl80
-rw-r--r--lib/common_test/src/test_server_gl.erl14
-rw-r--r--lib/common_test/src/test_server_io.erl6
-rw-r--r--lib/common_test/test/ct_log_SUITE.erl134
7 files changed, 315 insertions, 145 deletions
diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml
index 53ef41dd5b..ea9f956271 100644
--- a/lib/common_test/doc/src/ct.xml
+++ b/lib/common_test/doc/src/ct.xml
@@ -740,7 +740,7 @@
<v>Format = string()</v>
<v>FormatArgs = list()</v>
<v>Opts = [Opt]</v>
- <v>Opt = no_css | esc_chars</v>
+ <v>Opt = {heading,string()} | no_css | esc_chars</v>
</type>
<desc><marker id="log-5"/>
<p>Prints from a test case to the log file.</p>
@@ -798,53 +798,71 @@
<func>
<name>pal(Format) -&gt; ok</name>
- <fsummary>Equivalent to pal(default, 50, Format, []).</fsummary>
+ <fsummary>Equivalent to pal(default, 50, Format, [], []).</fsummary>
<desc><marker id="pal-1"/>
<p>Equivalent to
- <seealso marker="#pal-4"><c>ct:pal(default, 50, Format,
- [])</c></seealso>.</p>
+ <seealso marker="#pal-5"><c>ct:pal(default, 50, Format,
+ [], [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>pal(X1, X2) -&gt; ok</name>
<fsummary>Equivalent to pal(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, []).</fsummary>
<type>
<v>X1 = Category | Importance | Format</v>
<v>X2 = Format | FormatArgs</v>
</type>
<desc><marker id="pal-2"/>
- <p>Equivalent to <seealso marker="#pal-4"><c>ct:pal(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#pal-5"><c>ct:pal(Category,
+ Importance, Format, FormatArgs, [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>pal(X1, X2, X3) -&gt; ok</name>
<fsummary>Equivalent to pal(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, Opts).</fsummary>
<type>
<v>X1 = Category | Importance</v>
<v>X2 = Importance | Format</v>
- <v>X3 = Format | FormatArgs</v>
+ <v>X3 = Format | FormatArgs | Opts</v>
</type>
<desc><marker id="pal-3"/>
- <p>Equivalent to <seealso marker="#pal-4"><c>ct:pal(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#pal-5"><c>ct:pal(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>pal(X1, X2, X3, X4) -&gt; ok</name>
+ <fsummary>Equivalent to pal(Category, Importance, Format,
+ FormatArgs, Opts).</fsummary>
+ <type>
+ <v>X1 = Category | Importance</v>
+ <v>X2 = Importance | Format</v>
+ <v>X3 = Format | FormatArgs</v>
+ <v>X4 = FormatArgs | Opts</v>
+ </type>
+ <desc><marker id="pal-4"/>
+ <p>Equivalent to <seealso marker="#pal-5"><c>ct:pal(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
</desc>
</func>
<func>
- <name>pal(Category, Importance, Format, FormatArgs) -&gt; ok</name>
+ <name>pal(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
<fsummary>Prints and logs from a test case.</fsummary>
<type>
<v>Category = atom()</v>
<v>Importance = integer()</v>
<v>Format = string()</v>
<v>FormatArgs = list()</v>
+ <v>Opts = [Opt]</v>
+ <v>Opt = {heading,string()} | no_css</v>
</type>
- <desc><marker id="pal-4"/>
+ <desc><marker id="pal-5"/>
<p>Prints and logs from a test case.</p>
<p>This function is meant for printing a string from a test case,
@@ -888,52 +906,70 @@
<func>
<name>print(Format) -&gt; ok</name>
- <fsummary>Equivalent to print(default, 50, Format, []).</fsummary>
+ <fsummary>Equivalent to print(default, 50, Format, [], []).</fsummary>
<desc><marker id="print-1"/>
- <p>Equivalent to <seealso marker="#print-4"><c>ct:print(default,
- 50, Format, [])</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(default,
+ 50, Format, [], [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>print(X1, X2) -&gt; ok</name>
<fsummary>Equivalent to print(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, []).</fsummary>
<type>
<v>X1 = Category | Importance | Format</v>
<v>X2 = Format | FormatArgs</v>
</type>
<desc><marker id="print-2"/>
- <p>Equivalent to <seealso marker="#print-4"><c>ct:print(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(Category,
+ Importance, Format, FormatArgs, [])</c></seealso>.</p>
</desc>
</func>
<func>
<name>print(X1, X2, X3) -&gt; ok</name>
<fsummary>Equivalent to print(Category, Importance, Format,
- FormatArgs).</fsummary>
+ FormatArgs, Opts).</fsummary>
<type>
<v>X1 = Category | Importance</v>
<v>X2 = Importance | Format</v>
- <v>X3 = Format | FormatArgs</v>
+ <v>X3 = Format | FormatArgs | Opts</v>
</type>
<desc><marker id="print-3"/>
- <p>Equivalent to <seealso marker="#print-4"><c>ct:print(Category,
- Importance, Format, FormatArgs)</c></seealso>.</p>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>print(X1, X2, X3, X4) -&gt; ok</name>
+ <fsummary>Equivalent to print(Category, Importance, Format,
+ FormatArgs, Opts).</fsummary>
+ <type>
+ <v>X1 = Category | Importance</v>
+ <v>X2 = Importance | Format</v>
+ <v>X3 = Format | FormatArgs</v>
+ <v>X4 = FormatArgs | Opts</v>
+ </type>
+ <desc><marker id="print-4"/>
+ <p>Equivalent to <seealso marker="#print-5"><c>ct:print(Category,
+ Importance, Format, FormatArgs, Opts)</c></seealso>.</p>
</desc>
</func>
<func>
- <name>print(Category, Importance, Format, FormatArgs) -&gt; ok</name>
+ <name>print(Category, Importance, Format, FormatArgs, Opts) -&gt; ok</name>
<fsummary>Prints from a test case to the console.</fsummary>
<type>
<v>Category = atom()</v>
<v>Importance = integer()</v>
<v>Format = string()</v>
<v>FormatArgs = list()</v>
+ <v>Opts = [Opt]</v>
+ <v>Opt = {heading,string()}</v>
</type>
- <desc><marker id="print-4"/>
+ <desc><marker id="print-5"/>
<p>Prints from a test case to the console.</p>
<p>This function is meant for printing a string from a test case to
diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml
index 1d3fbb6f76..f70bdb16c5 100644
--- a/lib/common_test/doc/src/write_test_chapter.xml
+++ b/lib/common_test/doc/src/write_test_chapter.xml
@@ -986,15 +986,17 @@
<c>io:put_chars/1</c>, and so on.</p>
<p><c>Importance</c> is compared to a verbosity level set by the
- <c>verbosity</c> start flag/option. The verbosity level can be set per
- category or generally, or both. The default verbosity level,
- <c>?STD_VERBOSITY</c>, is 50, that is, all standard I/O gets printed.
- If a lower verbosity level is set, standard I/O printouts are ignored.
- <c>Common Test</c> performs the following test:</p>
+ <c>verbosity</c> start flag/option. The level can be set per
+ category or generally, or both. If <c>verbosity</c> is not set by the user,
+ a level of 100 (<c>?MAX_VERBOSITY</c> = all printouts visible) is used as
+ default value. <c>Common Test</c> performs the following test:</p>
<pre>
- Importance >= (100-VerbosityLevel)</pre>
- <p>This also means that verbosity level 0 effectively turns all logging off
- (except from printouts made by <c>Common Test</c> itself).</p>
+Importance >= (100-VerbosityLevel)</pre>
+ <p>The constant <c>?STD_VERBOSITY</c> has value 50 (see <c>ct.hrl</c>).
+ At this level, all standard I/O gets printed. If a lower verbosity level
+ is set, standard I/O printouts are ignored. Verbosity level 0 effectively
+ turns all logging off (except from printouts made by <c>Common Test</c>
+ itself).</p>
<p>The general verbosity level is not associated with any particular
category. This level sets the threshold for the standard I/O printouts,
@@ -1003,17 +1005,17 @@
<p><em>Examples:</em></p>
<p>Some printouts during test case execution:</p>
- <pre>
+ <pre>
io:format("1. Standard IO, importance = ~w~n", [?STD_IMPORTANCE]),
ct:log("2. Uncategorized, importance = ~w", [?STD_IMPORTANCE]),
- ct:log(info, "3. Categorized info, importance = ~w", [?STD_IMPORTANCE]]),
+ ct:log(info, "3. Categorized info, importance = ~w", [?STD_IMPORTANCE]),
ct:log(info, ?LOW_IMPORTANCE, "4. Categorized info, importance = ~w", [?LOW_IMPORTANCE]),
- ct:log(error, "5. Categorized error, importance = ~w", [?HI_IMPORTANCE]),
- ct:log(error, ?HI_IMPORTANCE, "6. Categorized error, importance = ~w", [?MAX_IMPORTANCE]),</pre>
+ ct:log(error, ?HI_IMPORTANCE, "5. Categorized error, importance = ~w", [?HI_IMPORTANCE]),
+ ct:log(error, ?MAX_IMPORTANCE, "6. Categorized error, importance = ~w", [?MAX_IMPORTANCE]),</pre>
- <p>If starting the test without specifying any verbosity levels as follows:</p>
+ <p>If starting the test with a general verbosity level of 50 (<c>?STD_VERBOSITY</c>):</p>
<pre>
- $ ct_run ...</pre>
+ $ ct_run -verbosity 50</pre>
<p>the following is printed:</p>
<pre>
1. Standard IO, importance = 50
@@ -1031,10 +1033,22 @@
4. Categorized info, importance = 25
6. Categorized error, importance = 99</pre>
+ <p>Note that the category argument is not required in order to only specify the
+ importance of a printout. Example:</p>
+ <pre>
+<c>ct:pal(?LOW_IMPORTANCE, "Info report: ~p", [Info])</c></pre>
+ <p>Or perhaps in combination with constants:</p>
+ <pre>
+-define(INFO, ?LOW_IMPORTANCE).
+-define(ERROR, ?HI_IMPORTANCE).
+
+ct:log(?INFO, "Info report: ~p", [Info])
+ct:pal(?ERROR, "Error report: ~p", [Error])</pre>
+
<p>The functions <seealso marker="ct#set_verbosity-2"><c>ct:set_verbosity/2</c></seealso>
and <seealso marker="ct#get_verbosity-1"><c>ct:get_verbosity/1</c></seealso> may be used
to modify and read verbosity levels during test execution.</p>
-
+
<p>The arguments <c>Format</c> and <c>FormatArgs</c> in <c>ct:log/print/pal</c> are
always passed on to the STDLIB function <c>io:format/3</c> (For details,
see the <seealso marker="stdlib:io"><c>io</c></seealso> manual page).</p>
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index f9f845e1a9..43abb91819 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -66,8 +66,8 @@
reload_config/1,
escape_chars/1, escape_chars/2,
log/1, log/2, log/3, log/4, log/5,
- print/1, print/2, print/3, print/4,
- pal/1, pal/2, pal/3, pal/4,
+ print/1, print/2, print/3, print/4, print/5,
+ pal/1, pal/2, pal/3, pal/4, pal/5,
set_verbosity/2, get_verbosity/1,
capture_start/0, capture_stop/0, capture_get/0, capture_get/1,
fail/1, fail/2, comment/1, comment/2, make_priv_dir/0,
@@ -592,7 +592,7 @@ log(X1,X2,X3,X4) ->
%%% Format = string()
%%% Args = list()
%%% Opts = [Opt]
-%%% Opt = esc_chars | no_css
+%%% Opt = {heading,string()} | esc_chars | no_css
%%%
%%% @doc Printout from a test case to the log file.
%%%
@@ -610,43 +610,61 @@ log(Category,Importance,Format,Args,Opts) ->
%%%-----------------------------------------------------------------
%%% @spec print(Format) -> ok
-%%% @equiv print(default,50,Format,[])
+%%% @equiv print(default,50,Format,[],[])
print(Format) ->
- print(default,?STD_IMPORTANCE,Format,[]).
+ print(default,?STD_IMPORTANCE,Format,[],[]).
%%%-----------------------------------------------------------------
%%% @spec print(X1,X2) -> ok
%%% X1 = Category | Importance | Format
%%% X2 = Format | Args
-%%% @equiv print(Category,Importance,Format,Args)
+%%% @equiv print(Category,Importance,Format,Args,[])
print(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
is_integer(X1) -> {default,X1,X2,[]};
is_list(X1) -> {default,?STD_IMPORTANCE,X1,X2}
end,
- print(Category,Importance,Format,Args).
+ print(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
%%% @spec print(X1,X2,X3) -> ok
+%%% X1 = Category | Importance | Format
+%%% X2 = Importance | Format | Args
+%%% X3 = Format | Args | Opts
+%%% @equiv print(Category,Importance,Format,Args,Opts)
+print(X1,X2,X3) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,[]};
+ is_integer(X1) -> {default,X1,X2,X3,[]};
+ is_list(X1), is_list(X2) -> {default,?STD_IMPORTANCE,X1,X2,X3}
+ end,
+ print(Category,Importance,Format,Args,Opts).
+
+%%%-----------------------------------------------------------------
+%%% @spec print(X1,X2,X3,X4) -> ok
%%% X1 = Category | Importance
%%% X2 = Importance | Format
%%% X3 = Format | Args
-%%% @equiv print(Category,Importance,Format,Args)
-print(X1,X2,X3) ->
- {Category,Importance,Format,Args} =
- if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[]};
- is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3};
- is_integer(X1) -> {default,X1,X2,X3}
+%%% X4 = Args | Opts
+%%% @equiv print(Category,Importance,Format,Args,Opts)
+print(X1,X2,X3,X4) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,X4};
+ is_integer(X1) -> {default,X1,X2,X3,X4}
end,
- print(Category,Importance,Format,Args).
+ print(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec print(Category,Importance,Format,Args) -> ok
+%%% @spec print(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = [Opt]
+%%% Opt = {heading,string()}
%%%
%%% @doc Printout from a test case to the console.
%%%
@@ -658,13 +676,13 @@ print(X1,X2,X3) ->
%%% and default value for <c>Args</c> is <c>[]</c>.</p>
%%% <p>Please see the User's Guide for details on <c>Category</c>
%%% and <c>Importance</c>.</p>
-print(Category,Importance,Format,Args) ->
- ct_logs:tc_print(Category,Importance,Format,Args).
+print(Category,Importance,Format,Args,Opts) ->
+ ct_logs:tc_print(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
%%% @spec pal(Format) -> ok
-%%% @equiv pal(default,50,Format,[])
+%%% @equiv pal(default,50,Format,[],[])
pal(Format) ->
pal(default,?STD_IMPORTANCE,Format,[]).
@@ -672,35 +690,53 @@ pal(Format) ->
%%% @spec pal(X1,X2) -> ok
%%% X1 = Category | Importance | Format
%%% X2 = Format | Args
-%%% @equiv pal(Category,Importance,Format,Args)
+%%% @equiv pal(Category,Importance,Format,Args,[])
pal(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
is_integer(X1) -> {default,X1,X2,[]};
is_list(X1) -> {default,?STD_IMPORTANCE,X1,X2}
end,
- pal(Category,Importance,Format,Args).
+ pal(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
%%% @spec pal(X1,X2,X3) -> ok
+%%% X1 = Category | Importance | Format
+%%% X2 = Importance | Format | Args
+%%% X3 = Format | Args | Opts
+%%% @equiv pal(Category,Importance,Format,Args,Opts)
+pal(X1,X2,X3) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,[]};
+ is_integer(X1) -> {default,X1,X2,X3,[]};
+ is_list(X1), is_list(X2) -> {default,?STD_IMPORTANCE,X1,X2,X3}
+ end,
+ pal(Category,Importance,Format,Args,Opts).
+
+%%%-----------------------------------------------------------------
+%%% @spec pal(X1,X2,X3,X4) -> ok
%%% X1 = Category | Importance
%%% X2 = Importance | Format
%%% X3 = Format | Args
-%%% @equiv pal(Category,Importance,Format,Args)
-pal(X1,X2,X3) ->
- {Category,Importance,Format,Args} =
- if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[]};
- is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3};
- is_integer(X1) -> {default,X1,X2,X3}
+%%% X4 = Args | Opts
+%%% @equiv pal(Category,Importance,Format,Args,Opts)
+pal(X1,X2,X3,X4) ->
+ {Category,Importance,Format,Args,Opts} =
+ if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
+ is_atom(X1), is_list(X2) -> {X1,?STD_IMPORTANCE,X2,X3,X4};
+ is_integer(X1) -> {default,X1,X2,X3,X4}
end,
- pal(Category,Importance,Format,Args).
+ pal(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec pal(Category,Importance,Format,Args) -> ok
+%%% @spec pal(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = [Opt]
+%%% Opt = {heading,string()} | no_css
%%%
%%% @doc Print and log from a test case.
%%%
@@ -712,8 +748,8 @@ pal(X1,X2,X3) ->
%%% and default value for <c>Args</c> is <c>[]</c>.</p>
%%% <p>Please see the User's Guide for details on <c>Category</c>
%%% and <c>Importance</c>.</p>
-pal(Category,Importance,Format,Args) ->
- ct_logs:tc_pal(Category,Importance,Format,Args).
+pal(Category,Importance,Format,Args,Opts) ->
+ ct_logs:tc_pal(Category,Importance,Format,Args,Opts).
%%%-----------------------------------------------------------------
%%% @spec set_verbosity(Category, Level) -> ok
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 0daed60dba..09ad709da5 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -45,8 +45,8 @@
%% Logging stuff directly from testcase
-export([tc_log/3, tc_log/4, tc_log/5, tc_log/6,
tc_log_async/3, tc_log_async/5,
- tc_print/3, tc_print/4,
- tc_pal/3, tc_pal/4, ct_log/3,
+ tc_print/3, tc_print/4, tc_print/5,
+ tc_pal/3, tc_pal/4, tc_pal/5, ct_log/3,
basic_html/0]).
%% Simulate logger process for use without ct environment running
@@ -447,10 +447,10 @@ tc_log(Category,Importance,Format,Args,Opts) ->
tc_log(Category,Importance,"User",Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Importance,Printer,Format,Args,Opts) -> ok
+%%% @spec tc_log(Category,Importance,Heading,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
-%%% Printer = string()
+%%% Heading = string()
%%% Format = string()
%%% Args = list()
%%% Opts = list()
@@ -460,13 +460,18 @@ tc_log(Category,Importance,Format,Args,Opts) ->
%%% <p>This function is called by <code>ct</code> when logging
%%% stuff directly from a testcase (i.e. not from within the CT
%%% framework).</p>
-tc_log(Category,Importance,Printer,Format,Args,Opts) ->
+tc_log(Category,Importance,Heading,Format,Args,Opts) ->
Data =
case lists:member(no_css, Opts) of
true ->
[{Format,Args}];
false ->
- [{hd,div_header(Category,Printer),[]},
+ Heading1 =
+ case proplists:get_value(heading, Opts) of
+ undefined -> Heading;
+ Str -> Str
+ end,
+ [{hd,div_header(Category,Heading1),[]},
{Format,Args},
{ft,div_footer(),[]}]
end,
@@ -484,7 +489,7 @@ tc_log_async(Category,Format,Args) ->
%%% @spec tc_log_async(Category,Importance,Format,Args) -> ok
%%% Category = atom()
%%% Importance = integer()
-%%% Printer = string()
+%%% Heading = string()
%%% Format = string()
%%% Args = list()
%%%
@@ -495,31 +500,38 @@ tc_log_async(Category,Format,Args) ->
%%% to avoid deadlocks when e.g. the hook that handles SASL printouts
%%% prints to the test case log file at the same time test server
%%% asks ct_logs for an html wrapper.</p>
-tc_log_async(Category,Importance,Printer,Format,Args) ->
+tc_log_async(Category,Importance,Heading,Format,Args) ->
cast({log,async,self(),group_leader(),Category,Importance,
- [{hd,div_header(Category,Printer),[]},
+ [{hd,div_header(Category,Heading),[]},
{Format,Args},
{ft,div_footer(),[]}],
true}),
ok.
%%%-----------------------------------------------------------------
%%% @spec tc_print(Category,Format,Args)
-%%% @equiv tc_print(Category,?STD_IMPORTANCE,Format,Args)
+%%% @equiv tc_print(Category,?STD_IMPORTANCE,Format,Args,[])
tc_print(Category,Format,Args) ->
- tc_print(Category,?STD_IMPORTANCE,Format,Args).
+ tc_print(Category,?STD_IMPORTANCE,Format,Args,[]).
+
+%%%-----------------------------------------------------------------
+%%% @spec tc_print(Category,Importance,Format,Args)
+%%% @equiv tc_print(Category,Importance,Format,Args,[])
+tc_print(Category,Importance,Format,Args) ->
+ tc_print(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_print(Category,Importance,Format,Args) -> ok
+%%% @spec tc_print(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = list()
%%%
%%% @doc Console printout from a testcase.
%%%
%%% <p>This function is called by <code>ct</code> when printing
%%% stuff from a testcase on the user console.</p>
-tc_print(Category,Importance,Format,Args) ->
+tc_print(Category,Importance,Format,Args,Opts) ->
VLvl = case ct_util:get_verbosity(Category) of
undefined ->
ct_util:get_verbosity('$unspecified');
@@ -531,7 +543,12 @@ tc_print(Category,Importance,Format,Args) ->
Val
end,
if Importance >= (100-VLvl) ->
- Str = lists:concat([get_heading(Category),Format,"\n\n"]),
+ Heading =
+ case proplists:get_value(heading, Opts) of
+ undefined -> atom_to_list(Category);
+ Hd -> Hd
+ end,
+ Str = lists:concat([get_header(Heading),Format,"\n\n"]),
try
io:format(?def_gl, Str, Args)
catch
@@ -543,43 +560,44 @@ tc_print(Category,Importance,Format,Args) ->
ok
end.
-get_heading(default) ->
+get_header("default") ->
io_lib:format("\n-----------------------------"
"-----------------------\n~s\n",
[log_timestamp(?now)]);
-get_heading(Category) ->
+get_header(Heading) ->
io_lib:format("\n-----------------------------"
- "-----------------------\n~s ~w\n",
- [log_timestamp(?now),Category]).
+ "-----------------------\n~s ~s\n",
+ [Heading,log_timestamp(?now)]).
%%%-----------------------------------------------------------------
%%% @spec tc_pal(Category,Format,Args) -> ok
-%%% @equiv tc_pal(Category,?STD_IMPORTANCE,Format,Args) -> ok
+%%% @equiv tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]) -> ok
tc_pal(Category,Format,Args) ->
- tc_pal(Category,?STD_IMPORTANCE,Format,Args).
+ tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]).
%%%-----------------------------------------------------------------
%%% @spec tc_pal(Category,Importance,Format,Args) -> ok
+%%% @equiv tc_pal(Category,Importance,Format,Args,[]) -> ok
+tc_pal(Category,Importance,Format,Args) ->
+ tc_pal(Category,Importance,Format,Args,[]).
+
+%%%-----------------------------------------------------------------
+%%% @spec tc_pal(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
+%%% Opts = list()
%%%
%%% @doc Print and log from a testcase.
%%%
%%% <p>This function is called by <code>ct</code> when logging
%%% stuff directly from a testcase. The info is written both in the
%%% log and on the console.</p>
-tc_pal(Category,Importance,Format,Args) ->
- tc_print(Category,Importance,Format,Args),
- cast({log,sync,self(),group_leader(),Category,Importance,
- [{hd,div_header(Category),[]},
- {Format,Args},
- {ft,div_footer(),[]}],
- true}),
- ok.
-
+tc_pal(Category,Importance,Format,Args,Opts) ->
+ tc_print(Category,Importance,Format,Args,Opts),
+ tc_log(Category,Importance,"User",Format,Args,[esc_chars|Opts]).
%%%-----------------------------------------------------------------
%%% @spec ct_log(Category,Format,Args) -> ok
@@ -608,9 +626,9 @@ int_footer() ->
div_header(Class) ->
div_header(Class,"User").
-div_header(Class,Printer) ->
+div_header(Class,Heading) ->
"\n</pre>\n<div class=\"" ++ atom_to_list(Class) ++ "\"><pre><b>*** "
- ++ Printer ++ " " ++ log_timestamp(?now) ++ " ***</b>".
+ ++ Heading ++ " " ++ log_timestamp(?now) ++ " ***</b>".
div_footer() ->
"</pre></div>\n<pre>".
diff --git a/lib/common_test/src/test_server_gl.erl b/lib/common_test/src/test_server_gl.erl
index 7d6fe64b92..4845b86dd3 100644
--- a/lib/common_test/src/test_server_gl.erl
+++ b/lib/common_test/src/test_server_gl.erl
@@ -24,7 +24,7 @@
%% through the test_server_io module/process.
-module(test_server_gl).
--export([start_link/0,stop/1,set_minor_fd/3,unset_minor_fd/1,
+-export([start_link/1,stop/1,set_minor_fd/3,unset_minor_fd/1,
get_tc_supervisor/1,print/4,set_props/2]).
-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2]).
@@ -33,6 +33,7 @@
tc :: mfa() | 'undefined', %Current test case MFA
minor :: 'none'|pid(), %Minor fd
minor_monitor, %Monitor ref for minor fd
+ tsio_monitor, %Monitor red for controlling proc
capture :: 'none'|pid(), %Capture output
reject_io :: boolean(), %Reject I/O requests...
permit_io, %... and exceptions
@@ -45,8 +46,8 @@
%% Start a new group leader process. Only to be called by
%% the test_server_io process.
-start_link() ->
- case gen_server:start_link(?MODULE, [], []) of
+start_link(TSIO) ->
+ case gen_server:start_link(?MODULE, [TSIO], []) of
{ok,Pid} ->
{ok,Pid};
Other ->
@@ -130,14 +131,16 @@ set_props(GL, PropList) ->
%%% Internal functions.
-init([]) ->
+init([TSIO]) ->
EscChars = case application:get_env(test_server, esc_chars) of
{ok,ECBool} -> ECBool;
_ -> true
end,
+ Ref = erlang:monitor(process, TSIO),
{ok,#st{tc_supervisor=none,
minor=none,
minor_monitor=none,
+ tsio_monitor=Ref,
capture=none,
reject_io=false,
permit_io=gb_sets:empty(),
@@ -176,6 +179,9 @@ handle_info({'DOWN',Ref,process,_,Reason}=D, #st{minor_monitor=Ref}=St) ->
test_server_io:print_unexpected(Data)
end,
{noreply,St#st{minor=none,minor_monitor=none}};
+handle_info({'DOWN',Ref,process,_,_}, #st{tsio_monitor=Ref}=St) ->
+ %% controlling process (test_server_io) terminated, we're done
+ {stop,normal,St};
handle_info({permit_io,Pid}, #st{permit_io=P}=St) ->
{noreply,St#st{permit_io=gb_sets:add(Pid, P)}};
handle_info({capture,Cap0}, St) ->
diff --git a/lib/common_test/src/test_server_io.erl b/lib/common_test/src/test_server_io.erl
index 3d5238052b..fdabf17b08 100644
--- a/lib/common_test/src/test_server_io.erl
+++ b/lib/common_test/src/test_server_io.erl
@@ -185,7 +185,7 @@ reset_state() ->
init([]) ->
process_flag(trap_exit, true),
Empty = gb_trees:empty(),
- {ok,Shared} = test_server_gl:start_link(),
+ {ok,Shared} = test_server_gl:start_link(self()),
{ok,#st{fds=Empty,shared_gl=Shared,gls=gb_sets:empty(),
io_buffering=gb_sets:empty(),
buffered=Empty,
@@ -200,7 +200,7 @@ req(Req) ->
gen_server:call(?MODULE, Req, infinity).
handle_call({get_gl,false}, _From, #st{gls=Gls,gl_props=Props}=St) ->
- {ok,Pid} = test_server_gl:start_link(),
+ {ok,Pid} = test_server_gl:start_link(self()),
test_server_gl:set_props(Pid, Props),
{reply,Pid,St#st{gls=gb_sets:insert(Pid, Gls)}};
handle_call({get_gl,true}, _From, #st{shared_gl=Shared}=St) ->
@@ -285,7 +285,7 @@ handle_call(reset_state, _From, #st{fds=Fds,tags=Tags,gls=Gls,
ok
end,
Empty = gb_trees:empty(),
- {ok,Shared} = test_server_gl:start_link(),
+ {ok,Shared} = test_server_gl:start_link(self()),
{reply,ok,#st{fds=Empty,shared_gl=Shared,gls=gb_sets:empty(),
io_buffering=gb_sets:empty(),
buffered=Empty,
diff --git a/lib/common_test/test/ct_log_SUITE.erl b/lib/common_test/test/ct_log_SUITE.erl
index 9bdd44cbdf..93affda398 100644
--- a/lib/common_test/test/ct_log_SUITE.erl
+++ b/lib/common_test/test/ct_log_SUITE.erl
@@ -86,18 +86,7 @@ print(Config) ->
io:format("5. Printing a pid: ~w~n", [Pid]),
io:format("6. Printing HTML: <pre>~s</pre>~n", [String]),
- %% --- API ---
- %% pal(Format) ->
- %% = ct:pal(default, 50, Format, []).
- %% pal(X1, X2) -> ok
- %% X1 = Category | Importance | Format
- %% X2 = Format | FormatArgs
- %% pal(X1, X2, X3) -> ok
- %% X1 = Category | Importance
- %% X2 = Importance | Format
- %% X3 = Format | FormatArgs
- %% pal(Category, Importance, Format, FormatArgs) -> ok
- %% ------
+ %% ct:pal
ct:pal("1. Printing nothing"),
ct:pal("2. Printing nothing", []),
ct:pal("3. Printing a string: ~s", [String]),
@@ -111,23 +100,16 @@ print(Config) ->
ct:pal(50, "11. Printing with ~s", ["importance"]),
ct:pal(ct_internal, 50, "12. Printing with ~s", ["category and importance"]),
- %% --- API ---
- %% log(Format) -> ok
- %% = ct:log(default, 50, Format, [], []).
- %% log(X1, X2) -> ok
- %% X1 = Category | Importance | Format
- %% X2 = Format | FormatArgs
- %% log(X1, X2, X3) -> ok
- %% X1 = Category | Importance
- %% X2 = Importance | Format
- %% X3 = Format | FormatArgs | Opts
- %% log(X1, X2, X3, X4) -> ok
- %% X1 = Category | Importance
- %% X2 = Importance | Format
- %% X3 = Format | FormatArgs
- %% X4 = FormatArgs | Opts
- %% log(Category, Importance, Format, FormatArgs, Opts) -> ok
- %% ------
+ ct:pal("13. Printing with heading", [],
+ [{heading,"This is a heading"}]),
+ ct:pal(ct_internal, "14. Printing with category and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:pal(50, "15. Printing with importance and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:pal(ct_internal, 50, "16. Printing with category, importance and heading", [],
+ [{heading,"This is a heading"}]),
+
+ %% ct:log
ct:log("1. Printing nothing"),
ct:log("2. Printing nothing", []),
ct:log("3. Printing a string: ~s", [String]),
@@ -153,8 +135,37 @@ print(Config) ->
ct:log(ct_internal, 50, "21. Printing a pid escaped with ~s, no_css: ~w",
["category and importance",Pid], [esc_chars,no_css]),
+ ct:log("22. Printing with heading", [],
+ [{heading,"This is a heading"}]),
+ ct:log(ct_internal, "23. Printing with category and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:log(50, "24. Printing with importance and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:log(ct_internal, 50, "25. Printing with category, importance and heading", [],
+ [{heading,"This is a heading"}]),
+
%% END mark
ct:log("LOGGING END", [], [no_css]),
+
+
+ %% ct:print
+ ct:print("1. Does this show??"),
+ ct:print("2. Does this ~s", ["show??"]),
+ ct:print("3. Is this a non-html pid?? ~w", [self()]),
+ ct:print(ct_internal, "4. Printing with category"),
+ ct:print(ct_internal, "5. Printing with ~s", ["category"]),
+ ct:print(50, "6. Printing with importance"),
+ ct:print(50, "7. Printing with ~s", ["importance"]),
+ ct:print(ct_internal, 50, "8. Printing with ~s", ["category and importance"]),
+ ct:print("9. Printing with heading", [],
+ [{heading,"This is a heading"}]),
+ ct:print(ct_internal, "10. Printing with category and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:print(50, "11. Printing with importance and heading", [],
+ [{heading,"This is a heading"}]),
+ ct:print(ct_internal, 50, "12. Printing with category, importance and heading", [],
+ [{heading,"This is a heading"}]),
+
{save_config,[{the_logfile,TcLogFile},{the_pid,Pid},{the_string,String}]}.
@@ -169,6 +180,8 @@ verify(Config) ->
{ok,Dev} = file:open(TcLogFile, [read]),
ok = read_until(Dev, "LOGGING START\n"),
+ ct:pal("VERIFYING LOG ENTRIES...", []),
+
%% io:format
match_line(Dev, "1. Printing nothing", []),
read_nl(Dev),
@@ -182,6 +195,7 @@ verify(Config) ->
read_nl(Dev),
match_line(Dev, "6. Printing HTML: &lt;pre&gt;~s&lt;/pre&gt;", [String]),
read_nl(Dev),
+
%% ct:pal
read_header(Dev),
match_line(Dev, "1. Printing nothing", []),
@@ -219,6 +233,19 @@ verify(Config) ->
read_header(Dev, "\"ct_internal\""),
match_line(Dev, "12. Printing with ~s", ["category and importance"]),
read_footer(Dev),
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "13. Printing with heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "14. Printing with category and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "15. Printing with importance and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "16. Printing with category, importance and heading", []),
+ read_footer(Dev),
+
%% ct:log
read_header(Dev),
match_line(Dev, "1. Printing nothing", []),
@@ -275,7 +302,18 @@ verify(Config) ->
read_footer(Dev),
match_line(Dev, "21. Printing a pid escaped with ~s, no_css: ~s",
["category and importance",EscPid]),
-
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "22. Printing with heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "23. Printing with category and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"default\"", "This is a heading"),
+ match_line(Dev, "24. Printing with importance and heading", []),
+ read_footer(Dev),
+ read_header(Dev, "\"ct_internal\"", "This is a heading"),
+ match_line(Dev, "25. Printing with category, importance and heading", []),
+ read_footer(Dev),
file:close(Dev),
ok.
@@ -298,29 +336,51 @@ read_until(Dev, Pat) ->
match_line(Dev, Format, Args) ->
Pat = lists:flatten(io_lib:format(Format, Args)),
Line = element(2, file:read_line(Dev)),
+
+ %% for debugging purposes:
+ ct:pal("L: ~tp", [Line], [no_css]),
+
case re:run(Line, Pat) of
{match,_} ->
ok;
nomatch ->
- ct:pal("ERROR! No match for ~p.\nLine = ~p", [Pat,Line]),
+ ct:pal("ERROR! No match for ~p", [Pat]),
file:close(Dev),
ct:fail({mismatch,Pat,Line})
end.
read_header(Dev) ->
- read_header(Dev, "\"default\"").
+ read_header(Dev, "\"default\"", "User").
read_header(Dev, Cat) ->
+ read_header(Dev, Cat, "User").
+
+read_header(Dev, Cat, Heading) ->
file:read_line(Dev), % \n
"</pre>\n" = element(2, file:read_line(Dev)),
- {match,_} =
- re:run(element(2, file:read_line(Dev)), "<div class="++Cat++"><pre><b>"
- "\\*\\*\\* User \\d{4}-\\d{2}-\\d{2} "
- "\\d{2}:\\d{2}:\\d{2}.\\d{1,} \\*\\*\\*</b>").
+ {ok,Hd} = file:read_line(Dev),
+
+ %% for debugging purposes:
+ ct:pal("H: ~tp", [Hd], [no_css]),
+
+ Pat = "<div class="++Cat++"><pre><b>"++
+ "\\*\\*\\* "++Heading++" \\d{4}-\\d{2}-\\d{2} "++
+ "\\d{2}:\\d{2}:\\d{2}.\\d{1,} \\*\\*\\*</b>",
+
+ case re:run(Hd, Pat) of
+ {match,_} ->
+ ok;
+ _ ->
+ ct:pal("ERROR! No match for ~p", [Pat]),
+ file:close(Dev),
+ ct:fail({mismatch,Pat,Hd})
+ end.
read_footer(Dev) ->
"</pre></div>\n" = element(2, file:read_line(Dev)),
- "<pre>\n" = element(2, file:read_line(Dev)).
+ "<pre>\n" = element(2, file:read_line(Dev)),
+ %% for debugging purposes:
+ ct:pal("F: </pre></div><pre>", [], [no_css]).
read_nl(Dev) ->
file:read_line(Dev).