aboutsummaryrefslogtreecommitdiffstats
path: root/lib/test_server
diff options
context:
space:
mode:
Diffstat (limited to 'lib/test_server')
-rw-r--r--lib/test_server/src/Makefile2
-rw-r--r--lib/test_server/src/erl2html2.erl68
-rw-r--r--lib/test_server/src/test_server.app.src2
-rw-r--r--lib/test_server/src/test_server.erl82
-rw-r--r--lib/test_server/src/test_server_ctrl.erl582
-rw-r--r--lib/test_server/src/test_server_gl.erl16
-rw-r--r--lib/test_server/src/test_server_h.erl6
-rw-r--r--lib/test_server/src/test_server_internal.hrl2
-rw-r--r--lib/test_server/src/test_server_io.erl12
-rw-r--r--lib/test_server/src/test_server_node.erl14
-rw-r--r--lib/test_server/src/test_server_sup.erl35
-rw-r--r--lib/test_server/src/ts.erl2
-rw-r--r--lib/test_server/src/ts_install.erl13
-rw-r--r--lib/test_server/src/ts_lib.erl15
-rw-r--r--lib/test_server/test/test_server_SUITE.erl227
-rw-r--r--lib/test_server/test/test_server_SUITE_data/Makefile.src3
-rw-r--r--lib/test_server/test/test_server_SUITE_data/test_server_unicode_SUITE.erl82
-rw-r--r--lib/test_server/test/test_server_test_lib.erl66
18 files changed, 790 insertions, 439 deletions
diff --git a/lib/test_server/src/Makefile b/lib/test_server/src/Makefile
index 7251acd20b..ebc5f5b71b 100644
--- a/lib/test_server/src/Makefile
+++ b/lib/test_server/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2012. All Rights Reserved.
+# Copyright Ericsson AB 1996-2013. 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
diff --git a/lib/test_server/src/erl2html2.erl b/lib/test_server/src/erl2html2.erl
index 1729257809..9c0ca64173 100644
--- a/lib/test_server/src/erl2html2.erl
+++ b/lib/test_server/src/erl2html2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
@@ -34,16 +34,17 @@ convert(File, Dest) ->
%%
%% FIXME: The colours should *really* be set with
%% stylesheets...
+ %%
+ %% The html file is written with the same encoding as the input file.
Encoding = encoding(File),
Header = ["<!DOCTYPE HTML PUBLIC "
"\"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
+ "<!-- autogenerated by '",atom_to_list(?MODULE),"'. -->\n"
"<html>\n"
"<head>\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html;"
- "charset=",
- Encoding,"\"/>\n"
- "<title>", File, "</title>\n"
+ "charset=",html_encoding(Encoding),"\"/>\n"
+ "<title>", to_raw_list(File,Encoding), "</title>\n"
"</head>\n\n"
"<body bgcolor=\"white\" text=\"black\""
" link=\"blue\" vlink=\"purple\" alink=\"red\">\n"],
@@ -61,7 +62,7 @@ convert(File, Dest, Header) ->
case file:open(Dest,[write,raw]) of
{ok,DFd} ->
file:write(DFd,[Header,"<pre>\n"]),
- _Lines = build_html(SFd,DFd,Functions),
+ _Lines = build_html(SFd,DFd,encoding(File),Functions),
file:write(DFd,["</pre>\n",footer(),
"</body>\n</html>\n"]),
%% {_, Time2} = statistics(runtime),
@@ -121,21 +122,21 @@ parse_file(Epp,File,InCorrectFile) ->
%%%-----------------------------------------------------------------
%%% Add a link target for each line and one for each function definition.
-build_html(SFd,DFd,Functions) ->
- build_html(SFd,DFd,file:read_line(SFd),1,Functions,false).
+build_html(SFd,DFd,Encoding,Functions) ->
+ build_html(SFd,DFd,Encoding,file:read_line(SFd),1,Functions,false).
-build_html(SFd,DFd,{ok,Str},L,[{F,A,L}|Functions],_IsFuncDef) ->
+build_html(SFd,DFd,Encoding,{ok,Str},L,[{F,A,L}|Functions],_IsFuncDef) ->
FALink = http_uri:encode(F++"-"++integer_to_list(A)),
- file:write(DFd,["<a name=\"",FALink,"\"/>"]),
- build_html(SFd,DFd,{ok,Str},L,Functions,true);
-build_html(SFd,DFd,{ok,Str},L,[{clause,L}|Functions],_IsFuncDef) ->
- build_html(SFd,DFd,{ok,Str},L,Functions,true);
-build_html(SFd,DFd,{ok,Str},L,Functions,IsFuncDef) ->
+ file:write(DFd,["<a name=\"",to_raw_list(FALink,Encoding),"\"/>"]),
+ build_html(SFd,DFd,Encoding,{ok,Str},L,Functions,true);
+build_html(SFd,DFd,Encoding,{ok,Str},L,[{clause,L}|Functions],_IsFuncDef) ->
+ build_html(SFd,DFd,Encoding,{ok,Str},L,Functions,true);
+build_html(SFd,DFd,Encoding,{ok,Str},L,Functions,IsFuncDef) ->
LStr = line_number(L),
Str1 = line(Str,IsFuncDef),
file:write(DFd,[LStr,Str1]),
- build_html(SFd,DFd,file:read_line(SFd),L+1,Functions,false);
-build_html(_SFd,_DFd,eof,L,_Functions,_IsFuncDef) ->
+ build_html(SFd,DFd,Encoding,file:read_line(SFd),L+1,Functions,false);
+build_html(_SFd,_DFd,_Encoding,eof,L,_Functions,_IsFuncDef) ->
L.
line_number(L) ->
@@ -190,16 +191,35 @@ footer() ->
%%%-----------------------------------------------------------------
%%% Read encoding from source file
encoding(File) ->
- Encoding =
- case epp:read_encoding(File) of
- none ->
- epp:default_encoding();
- E ->
- E
- end,
- html_encoding(Encoding).
+ case epp:read_encoding(File) of
+ none ->
+ epp:default_encoding();
+ E ->
+ E
+ end.
+%%%-----------------------------------------------------------------
+%%% Covert encoding atom to string for use in HTML header
html_encoding(latin1) ->
"iso-8859-1";
html_encoding(utf8) ->
"utf-8".
+
+%%%-----------------------------------------------------------------
+%%% Convert a string to a list of raw printable characters in the
+%%% given encoding. This is necessary since the files (source and
+%%% destination) are both opened in raw mode (default encoding). Byte
+%%% by byte is read from source and written to the destination. This
+%%% conversion is needed when printing data that is not first read
+%%% from the source.
+%%%
+%%% Example: if the encoding of the file is utf8, and we have a string
+%%% containing "�" = [229], then we need to convert this to [195,165]
+%%% before writing. Note that this conversion is only necessary
+%%% because the destination file is not (necessarily) opened with utf8
+%%% encoding - it is opened with default encoding in order to allow
+%%% raw file mode and byte by byte copying from source.
+to_raw_list(X,latin1) when is_list(X) ->
+ X;
+to_raw_list(X,utf8) when is_list(X) ->
+ binary_to_list(unicode:characters_to_binary(X)).
diff --git a/lib/test_server/src/test_server.app.src b/lib/test_server/src/test_server.app.src
index 26330f9695..163f370a47 100644
--- a/lib/test_server/src/test_server.app.src
+++ b/lib/test_server/src/test_server.app.src
@@ -1,7 +1,7 @@
% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2013. 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
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index 37cd8fac99..43330d2c91 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. 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
@@ -123,7 +123,7 @@ cover_compile({App,all,Include,Cross}) ->
io:format("\nWARNING: All modules in \'~w\' are excluded\n"
"Only cover compiling modules in include list "
"and the modules\nin the cross cover file:\n"
- "~p\n", [App,CompileMods]),
+ "~tp\n", [App,CompileMods]),
do_cover_compile(CompileMods),
io:fwrite("done\n\n",[]),
{ok,Include}
@@ -143,7 +143,7 @@ cover_compile({App,Exclude,Include,Cross}) ->
[App,length(CompileMods)]),
io:format("\nWARNING: Can't find lib_dir for \'~w\'\n"
"Only cover compiling modules in include list: "
- "~p\n", [App,Include]),
+ "~tp\n", [App,Include]),
do_cover_compile(CompileMods),
io:fwrite("done\n\n",[]),
{ok,Include}
@@ -186,7 +186,7 @@ do_cover_compile1([M|Rest]) ->
{ok,_} ->
ok;
Error ->
- io:fwrite("\nWARNING: Could not cover compile ~w: ~p\n",
+ io:fwrite("\nWARNING: Could not cover compile ~w: ~tp\n",
[M,Error])
end,
code:stick_mod(M),
@@ -196,7 +196,7 @@ do_cover_compile1([M|Rest]) ->
{module,_} ->
do_cover_compile1([M|Rest]);
Error ->
- io:fwrite("\nWARNING: Could not load ~w: ~p\n",[M,Error]),
+ io:fwrite("\nWARNING: Could not load ~w: ~tp\n",[M,Error]),
do_cover_compile1(Rest)
end;
{false,_} ->
@@ -204,7 +204,7 @@ do_cover_compile1([M|Rest]) ->
{ok,_} ->
ok;
Error ->
- io:fwrite("\nWARNING: Could not cover compile ~w: ~p\n",
+ io:fwrite("\nWARNING: Could not cover compile ~w: ~tp\n",
[M,Error])
end,
do_cover_compile1(Rest)
@@ -286,7 +286,7 @@ cover_analyse(Analyse,Modules,Stop) ->
{ok,{M,{Cov,NotCov}}} ->
{M,{Cov,NotCov,DetailsFun(M)}};
Err ->
- io:fwrite("WARNING: Analysis failed for ~w. Reason: ~p\n",
+ io:fwrite("WARNING: Analysis failed for ~w. Reason: ~tp\n",
[M,Err]),
{M,Err}
end
@@ -436,8 +436,8 @@ run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) ->
_ ->
Args
end,
- print(minor, "Test case started with:\n~s:~s(~p)\n", [Mod,Func,Args2Print]),
- print(minor, "Current directory is ~p\n", [Cwd]),
+ print(minor, "Test case started with:\n~w:~w(~tp)\n", [Mod,Func,Args2Print]),
+ print(minor, "Current directory is ~tp\n", [Cwd]),
print_timestamp(minor,"Started at "),
print(minor, "", [], internal_raw),
TCCallback = get(test_server_testcase_callback),
@@ -498,7 +498,7 @@ run_test_case_msgloop(#st{ref=Ref,pid=Pid,end_conf_pid=EndConfPid0}=St0) ->
exit(Pid, kill),
%% here's the only place we know Reason, so we save
%% it as a comment, potentially replacing user data
- Error = lists:flatten(io_lib:format("Aborted: ~p",
+ Error = lists:flatten(io_lib:format("Aborted: ~tp",
[Reason])),
Error1 = lists:flatten([string:strip(S,left) ||
S <- string:tokens(Error,
@@ -742,8 +742,8 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
timer:sleep(1),
group_leader() ! {printout,12,
"WARNING! "
- "~p:end_per_testcase(~p, ~p)"
- " crashed!\n\tReason: ~p\n",
+ "~w:end_per_testcase(~w, ~tp)"
+ " crashed!\n\tReason: ~tp\n",
[Mod,Func,Conf,Why]};
_ ->
ok
@@ -756,8 +756,8 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
Starter ! {self(),{call_end_conf,Data,ok}};
{'EXIT',Pid,Reason} ->
group_leader() ! {printout,12,
- "WARNING! ~p:end_per_testcase(~p, ~p)"
- " failed!\n\tReason: ~p\n",
+ "WARNING! ~w:end_per_testcase(~w, ~tp)"
+ " failed!\n\tReason: ~tp\n",
[Mod,Func,Conf,Reason]},
Starter ! {self(),{call_end_conf,Data,{error,Reason}}};
{'EXIT',_OtherPid,Reason} ->
@@ -802,7 +802,7 @@ spawn_fw_call(Mod,{end_per_testcase,Func},EndConf,Pid,
{Result,E}
end,
group_leader() ! {printout,12,
- "WARNING! ~p:end_per_testcase(~p, ~p)"
+ "WARNING! ~w:end_per_testcase(~w, ~tp)"
" failed!\n\tReason: timetrap timeout"
" after ~w ms!\n", [Mod,Func,EndConf,TVal]},
FailLoc = proplists:get_value(tc_fail_loc, EndConf),
@@ -1180,7 +1180,7 @@ do_init_per_testcase(Mod, Args) ->
Bad ->
group_leader() ! {printout,12,
"ERROR! init_per_testcase has returned "
- "bad elements in Config: ~p\n",[Bad]},
+ "bad elements in Config: ~tp\n",[Bad]},
{skip,{failed,{Mod,init_per_testcase,bad_return}}}
end;
{fail,_Reason}=Res ->
@@ -1197,7 +1197,7 @@ do_init_per_testcase(Mod, Args) ->
FormattedLoc = test_server_sup:format_loc(Line),
group_leader() ! {printout,12,
"ERROR! init_per_testcase thrown!\n"
- "\tLocation: ~s\n\tReason: ~p\n",
+ "\tLocation: ~ts\n\tReason: ~tp\n",
[FormattedLoc, Other]},
{skip,{failed,{Mod,init_per_testcase,Other}}};
_:Reason0 ->
@@ -1208,7 +1208,7 @@ do_init_per_testcase(Mod, Args) ->
FormattedLoc = test_server_sup:format_loc(Line),
group_leader() ! {printout,12,
"ERROR! init_per_testcase crashed!\n"
- "\tLocation: ~s\n\tReason: ~p\n",
+ "\tLocation: ~ts\n\tReason: ~tp\n",
[FormattedLoc,Reason]},
{skip,{failed,{Mod,init_per_testcase,Reason}}}
end.
@@ -1244,13 +1244,13 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) ->
"<br />")
end,
set_loc(erlang:get_stacktrace()),
- comment(io_lib:format("~s<font color=\"red\">"
+ comment(io_lib:format("~ts<font color=\"red\">"
"WARNING: ~w thrown!"
"</font>\n",[Comment0,EndFunc])),
group_leader() ! {printout,12,
"WARNING: ~w thrown!\n"
- "Reason: ~p\n"
- "Line: ~s\n",
+ "Reason: ~tp\n"
+ "Line: ~ts\n",
[EndFunc, Other,
test_server_sup:format_loc(get_loc())]},
{failed,{Mod,end_per_testcase,Other}};
@@ -1266,13 +1266,13 @@ do_end_per_testcase(Mod,EndFunc,Func,Conf) ->
Cmt -> Cmt ++ test_server_ctrl:xhtml("<br>",
"<br />")
end,
- comment(io_lib:format("~s<font color=\"red\">"
+ comment(io_lib:format("~ts<font color=\"red\">"
"WARNING: ~w crashed!"
"</font>\n",[Comment0,EndFunc])),
group_leader() ! {printout,12,
"WARNING: ~w crashed!\n"
- "Reason: ~p\n"
- "Line: ~s\n",
+ "Reason: ~tp\n"
+ "Line: ~ts\n",
[EndFunc, Reason,
test_server_sup:format_loc(get_loc())]},
{failed,{Mod,end_per_testcase,Why}}
@@ -1351,7 +1351,7 @@ lookup_config(Key,Config) ->
{value,{Key,Val}} ->
Val;
_ ->
- io:format("Could not find element ~p in Config.~n",[Key]),
+ io:format("Could not find element ~tp in Config.~n",[Key]),
undefined
end.
@@ -1433,7 +1433,7 @@ format(Detail, Format, Args) ->
Str =
case catch io_lib:format(Format,Args) of
{'EXIT',_} ->
- io_lib:format("illegal format; ~p with args ~p.\n",
+ io_lib:format("illegal format; ~tp with args ~tp.\n",
[Format,Args]);
Valid -> Valid
end,
@@ -1564,7 +1564,7 @@ fail(Reason) ->
cast_to_list(X) when is_list(X) -> X;
cast_to_list(X) when is_atom(X) -> atom_to_list(X);
-cast_to_list(X) -> lists:flatten(io_lib:format("~p", [X])).
+cast_to_list(X) -> lists:flatten(io_lib:format("~tp", [X])).
@@ -1608,10 +1608,10 @@ break(CBM, TestCase, Comment) ->
end,
io:format(user,
"\n\n\n--- SEMIAUTOMATIC TESTING ---"
- "\nThe test case~s executes on process ~w"
- "\n\n\n~s"
+ "\nThe test case~ts executes on process ~w"
+ "\n\n\n~ts"
"\n\n\n-----------------------------\n\n"
- "Continue with --> ~w:continue(~s).\n",
+ "Continue with --> ~w:continue(~ts).\n",
[TCName,self(),Comment,CBM,CntArg]),
case whereis(PName) of
undefined ->
@@ -1735,7 +1735,7 @@ ensure_timetrap(Config) ->
Garbage ->
erase(test_server_default_timetrap),
format("=== WARNING: garbage in "
- "test_server_default_timetrap: ~p~n",
+ "test_server_default_timetrap: ~tp~n",
[Garbage])
end,
DTmo = case lists:keysearch(default_timeout,1,Config) of
@@ -1743,7 +1743,7 @@ ensure_timetrap(Config) ->
_ -> ?DEFAULT_TIMETRAP_SECS
end,
format("=== test_server setting default "
- "timetrap of ~p seconds~n",
+ "timetrap of ~tp seconds~n",
[DTmo]),
put(test_server_default_timetrap, timetrap(seconds(DTmo)))
end.
@@ -1764,7 +1764,7 @@ cancel_default_timetrap(true) ->
Garbage ->
erase(test_server_default_timetrap),
format("=== WARNING: garbage in "
- "test_server_default_timetrap: ~p~n",
+ "test_server_default_timetrap: ~tp~n",
[Garbage]),
error
end.
@@ -1773,7 +1773,7 @@ time_ms({hours,N}, _, _) -> hours(N);
time_ms({minutes,N}, _, _) -> minutes(N);
time_ms({seconds,N}, _, _) -> seconds(N);
time_ms({Other,_N}, _, _) ->
- format("=== ERROR: Invalid time specification: ~p. "
+ format("=== ERROR: Invalid time specification: ~tp. "
"Should be seconds, minutes, or hours.~n", [Other]),
exit({invalid_time_format,Other});
time_ms(Ms, _, _) when is_integer(Ms) -> Ms;
@@ -2266,14 +2266,14 @@ stop_node(Slave) ->
slave:stop(Slave),
receive
{nodedown, Slave} ->
- format(minor, "Stopped slave node: ~p", [Slave]),
- format(major, "=node_stop ~p", [Slave]),
+ format(minor, "Stopped slave node: ~w", [Slave]),
+ format(major, "=node_stop ~w", [Slave]),
if Cover -> do_cover_for_node(Slave,stop,false);
true -> ok
end,
true
after 30000 ->
- format("=== WARNING: Node ~p does not seem to terminate.",
+ format("=== WARNING: Node ~w does not seem to terminate.",
[Slave]),
erlang:monitor_node(Slave, false),
receive {nodedown, Slave} -> ok after 0 -> ok end,
@@ -2283,7 +2283,7 @@ stop_node(Slave) ->
%% Either, the node is already dead or it was started
%% with the {cleanup,false} option, or it was started
%% in some other way than test_server:start_node/3
- format("=== WARNING: Attempt to stop a nonexisting slavenode (~p)~n"
+ format("=== WARNING: Attempt to stop a nonexisting slavenode (~w)~n"
"=== Trying to kill it anyway!!!",
[Slave]),
case net_adm:ping(Slave)of
@@ -2292,14 +2292,14 @@ stop_node(Slave) ->
slave:stop(Slave),
receive
{nodedown, Slave} ->
- format(minor, "Stopped slave node: ~p", [Slave]),
- format(major, "=node_stop ~p", [Slave]),
+ format(minor, "Stopped slave node: ~w", [Slave]),
+ format(major, "=node_stop ~w", [Slave]),
if Cover -> do_cover_for_node(Slave,stop,false);
true -> ok
end,
true
after 30000 ->
- format("=== WARNING: Node ~p does not seem to terminate.",
+ format("=== WARNING: Node ~w does not seem to terminate.",
[Slave]),
erlang:monitor_node(Slave, false),
receive {nodedown, Slave} -> ok after 0 -> ok end,
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index c5c57426b4..e5d75e43c9 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2013. 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
@@ -17,7 +17,6 @@
%% %CopyrightEnd%
%%
-module(test_server_ctrl).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
%% The Erlang Test Server %%
@@ -65,6 +64,7 @@
-export([get_target_info/0]).
-export([get_hosts/0]).
-export([node_started/1]).
+-export([uri_encode/1,uri_encode/2]).
%%% DEBUGGER INTERFACE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([i/0, p/1, p/3, pi/2, pi/4, t/0, t/1]).
@@ -229,12 +229,12 @@ parse_cmd_line(['SPEC',Spec|Cmds], SpecList, Names, Param, Trc, Cov, TCCB) ->
parse_cmd_line(Cmds, TermList++SpecList, [Name|Names], Param,
Trc, Cov, TCCB);
{error,Reason} ->
- io:format("Can't open ~s: ~p\n",
- [cast_to_list(Spec), file:format_error(Reason)]),
+ io:format("Can't open ~w: ~tp\n",[Spec, file:format_error(Reason)]),
parse_cmd_line(Cmds, SpecList, Names, Param, Trc, Cov, TCCB)
end;
parse_cmd_line(['NAME',Name|Cmds], SpecList, Names, Param, Trc, Cov, TCCB) ->
- parse_cmd_line(Cmds, SpecList, [{name,Name}|Names], Param, Trc, Cov, TCCB);
+ parse_cmd_line(Cmds, SpecList, [{name,atom_to_list(Name)}|Names],
+ Param, Trc, Cov, TCCB);
parse_cmd_line(['SKIPMOD',Mod|Cmds], SpecList, Names, Param, Trc, Cov, TCCB) ->
parse_cmd_line(Cmds, [{skip,{Mod,"by command line"}}|SpecList], Names,
Param, Trc, Cov, TCCB);
@@ -242,14 +242,14 @@ parse_cmd_line(['SKIPCASE',Mod,Case|Cmds], SpecList, Names, Param, Trc, Cov, TCC
parse_cmd_line(Cmds, [{skip,{Mod,Case,"by command line"}}|SpecList], Names,
Param, Trc, Cov, TCCB);
parse_cmd_line(['DIR',Dir|Cmds], SpecList, Names, Param, Trc, Cov, TCCB) ->
- Name = cast_to_list(filename:basename(Dir)),
+ Name = filename:basename(Dir),
parse_cmd_line(Cmds, [{topcase,{dir,Name}}|SpecList], [Name|Names],
Param, Trc, Cov, TCCB);
parse_cmd_line(['MODULE',Mod|Cmds], SpecList, Names, Param, Trc, Cov, TCCB) ->
- parse_cmd_line(Cmds, [{topcase,{Mod,all}}|SpecList], [Mod|Names],
+ parse_cmd_line(Cmds,[{topcase,{Mod,all}}|SpecList],[atom_to_list(Mod)|Names],
Param, Trc, Cov, TCCB);
parse_cmd_line(['CASE',Mod,Case|Cmds], SpecList, Names, Param, Trc, Cov, TCCB) ->
- parse_cmd_line(Cmds, [{topcase,{Mod,Case}}|SpecList], [Mod|Names],
+ parse_cmd_line(Cmds,[{topcase,{Mod,Case}}|SpecList],[atom_to_list(Mod)|Names],
Param, Trc, Cov, TCCB);
parse_cmd_line(['PARAMETERS',Param|Cmds], SpecList, Names, _Param, Trc, Cov, TCCB) ->
parse_cmd_line(Cmds, SpecList, Names, Param, Trc, Cov, TCCB);
@@ -260,17 +260,17 @@ parse_cmd_line(['COVER',App,CF,Analyse|Cmds], SpecList, Names, Param, Trc, _Cov,
parse_cmd_line(['TESTCASE_CALLBACK',Mod,Func|Cmds], SpecList, Names, Param, Trc, Cov, _) ->
parse_cmd_line(Cmds, SpecList, Names, Param, Trc, Cov, {Mod,Func});
parse_cmd_line([Obj|_Cmds], _SpecList, _Names, _Param, _Trc, _Cov, _TCCB) ->
- io:format("~p: Bad argument: ~p\n", [?MODULE,Obj]),
+ io:format("~w: Bad argument: ~w\n", [?MODULE,Obj]),
io:format(" Use the `ts' module to start tests.\n", []),
io:format(" (If you ARE using `ts', there is a bug in `ts'.)\n", []),
halt(1);
parse_cmd_line([], SpecList, Names, Param, Trc, Cov, TCCB) ->
- NameList = lists:reverse(Names, [suite]),
+ NameList = lists:reverse(Names, ["suite"]),
Name = case lists:keysearch(name, 1, NameList) of
{value,{name,N}} -> N;
false -> hd(NameList)
end,
- {lists:reverse(SpecList), cast_to_list(Name), Param, Trc, Cov, TCCB}.
+ {lists:reverse(SpecList), Name, Param, Trc, Cov, TCCB}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% cast_to_list(X) -> string()
@@ -1011,9 +1011,9 @@ handle_info({'EXIT',Pid,Reason}, State) ->
normal ->
fine;
killed ->
- io:format("Suite ~s was killed\n", [Name]);
+ io:format("Suite ~ts was killed\n", [Name]);
_Other ->
- io:format("Suite ~s was killed with reason ~p\n",
+ io:format("Suite ~ts was killed with reason ~tp\n",
[Name,Reason])
end,
State2 = State#state{jobs=NewJobs},
@@ -1057,8 +1057,8 @@ handle_info({tcp,_MainSock,<<1,Request/binary>>}, State) ->
%% The local job proc will soon be killed by the closed socket or
%% because the job is finished. Then the above clause ('EXIT') will
%% handle the problem.
- io:format("Suite ~s was killed on remote target with reason"
- " ~p\n", [Name,Reason]);
+ io:format("Suite ~ts was killed on remote target with reason"
+ " ~tp\n", [Name,Reason]);
_ ->
ignore
end,
@@ -1192,10 +1192,10 @@ init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels,
{'EXIT',test_suites_done} ->
ok;
{'EXIT',_Pid,Reason} ->
- print(1, "EXIT, reason ~p", [Reason]);
+ print(1, "EXIT, reason ~tp", [Reason]);
{'EXIT',Reason} ->
report_severe_error(Reason),
- print(1, "EXIT, reason ~p", [Reason])
+ print(1, "EXIT, reason ~tp", [Reason])
end,
Time = TimeMy/1000000,
SuccessStr =
@@ -1206,13 +1206,13 @@ init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels,
{SkippedN,SkipStr} =
case get(test_server_skipped) of
{0,_} -> {0,""};
- {Skipped,_} -> {Skipped,io_lib:format(", ~p Skipped", [Skipped])}
+ {Skipped,_} -> {Skipped,io_lib:format(", ~w Skipped", [Skipped])}
end,
OkN = get(test_server_ok),
FailedN = get(test_server_failed),
print(html,"\n</tbody>\n<tfoot>\n"
"<tr><td></td><td><b>TOTAL</b></td><td></td><td></td><td></td>"
- "<td>~.3fs</td><td><b>~s</b></td><td>~p Ok, ~p Failed~s of ~p</td></tr>\n"
+ "<td>~.3fs</td><td><b>~ts</b></td><td>~w Ok, ~w Failed~ts of ~w</td></tr>\n"
"</tfoot>\n",
[Time,SuccessStr,OkN,FailedN,SkipStr,OkN+FailedN+SkippedN]),
test_server_io:stop().
@@ -1285,7 +1285,7 @@ do_spec(SpecName, TimetrapSpec) when is_list(SpecName) ->
{ok,TermList} ->
do_spec_list(TermList,TimetrapSpec);
{error,Reason} ->
- io:format("Can't open ~s: ~p\n", [SpecName,Reason]),
+ io:format("Can't open ~ts: ~tp\n", [SpecName,Reason]),
{error,{cant_open_spec,Reason}}
end.
@@ -1368,7 +1368,7 @@ do_spec_terms([{require_nodenames,NumNames}|Terms], TopCases, SkipList, Config)
do_spec_terms(Terms, TopCases, SkipList,
update_config(Config, {nodenames,NodeNames}));
do_spec_terms([Other|Terms], TopCases, SkipList, Config) ->
- io:format("** WARNING: Spec file contains unknown directive ~p\n",
+ io:format("** WARNING: Spec file contains unknown directive ~tp\n",
[Other]),
do_spec_terms(Terms, TopCases, SkipList, Config).
@@ -1387,7 +1387,7 @@ generate_nodenames(Num) ->
generate_nodenames2(0, _Hosts, Acc) ->
Acc;
generate_nodenames2(N, Hosts, Acc) ->
- Host=cast_to_list(lists:nth((N rem (length(Hosts)))+1, Hosts)),
+ Host=lists:nth((N rem (length(Hosts)))+1, Hosts),
Name=list_to_atom(temp_nodename("nod", []) ++ "@" ++ Host),
generate_nodenames2(N-1, Hosts, [Name|Acc]).
@@ -1507,7 +1507,7 @@ do_test_cases(TopCases, SkipCases,
FwMod = get_fw_mod(?MODULE),
case collect_all_cases(TopCases, SkipCases) of
{error,Why} ->
- print(1, "Error starting: ~p", [Why]),
+ print(1, "Error starting: ~tp", [Why]),
exit(test_suites_done);
TestSpec0 ->
N = case remove_conf(TestSpec0) of
@@ -1519,32 +1519,25 @@ do_test_cases(TopCases, SkipCases,
TestSpec =
add_init_and_end_per_suite(TestSpec0, undefined, undefined, FwMod),
TI = get_target_info(),
- print(1, "Starting test~s",
+ print(1, "Starting test~ts",
[print_if_known(N, {", ~w test cases",[N]},
{" (with repeated test cases)",[]})]),
Test = get(test_server_name),
TestName = if is_list(Test) ->
- lists:flatten(io_lib:format("~s", [Test]));
+ lists:flatten(io_lib:format("~ts", [Test]));
true ->
- lists:flatten(io_lib:format("~p", [Test]))
+ lists:flatten(io_lib:format("~tp", [Test]))
end,
TestDescr = "Test " ++ TestName ++ " results",
test_server_sup:framework_call(report, [tests_start,{Test,N}]),
{Header,Footer} =
- case test_server_sup:framework_call(get_html_wrapper,
+ case test_server_sup:framework_call(get_html_wrapper,
[TestDescr,true,TestDir,
{[],[2,3,4,7,8],[1,6]}], "") of
Empty when (Empty == "") ; (element(2,Empty) == "") ->
put(basic_html, true),
- {["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
- "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n",
- "<html>\n",
- "<head><title>", TestDescr, "</title>\n",
- "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
- "</head>\n",
- "<body bgcolor=\"white\" text=\"black\" ",
- "link=\"blue\" vlink=\"purple\" alink=\"red\">",
+ {[html_header(TestDescr),
"<h2>Results for test ", TestName, "</h2>\n"],
"\n</body>\n</html>\n"};
{basic_html,Html0,Html1} ->
@@ -1566,16 +1559,16 @@ do_test_cases(TopCases, SkipCases,
print(html, xhtml("\n<p><b>Host info:</b><br>\n",
"\n<p><b>Host info:</b><br />\n")),
print_who(test_server_sup:hoststr(), test_server_sup:get_username()),
- print(html, xhtml("<br>Used Erlang v~s in <tt>~s</tt></p>\n",
- "<br />Used Erlang v~s in \"~s\"</p>\n"),
+ print(html, xhtml("<br>Used Erlang v~ts in <tt>~ts</tt></p>\n",
+ "<br />Used Erlang v~ts in \"~ts\"</p>\n"),
[erlang:system_info(version), code:root_dir()]),
if FwMod == ?MODULE ->
print(html, xhtml("\n<p><b>Target Info:</b><br>\n",
"\n<p><b>Target Info:</b><br />\n")),
print_who(TI#target_info.host, TI#target_info.username),
- print(html, xhtml("<br>Used Erlang v~s in <tt>~s</tt></p>\n",
- "<br />Used Erlang v~s in \"~s\"</p>\n"),
+ print(html,xhtml("<br>Used Erlang v~ts in <tt>~ts</tt></p>\n",
+ "<br />Used Erlang v~ts in \"~ts\"</p>\n"),
[TI#target_info.version, TI#target_info.root_dir]);
true ->
case test_server_sup:framework_call(target_info, []) of
@@ -1583,7 +1576,7 @@ do_test_cases(TopCases, SkipCases,
length(TargetInfo) > 0 ->
print(html, xhtml("\n<p><b>Target info:</b><br>\n",
"\n<p><b>Target info:</b><br />\n")),
- print(html, "~s</p>\n", [TargetInfo]);
+ print(html, "~ts</p>\n", [TargetInfo]);
_ ->
ok
end
@@ -1591,39 +1584,39 @@ do_test_cases(TopCases, SkipCases,
print(html,
"<p><ul>\n"
- "<li><a href=\"~s\">Full textual log</a></li>\n"
- "<li><a href=\"~s\">Coverage log</a></li>\n"
- "<li><a href=\"~s\">Unexpected I/O log</a></li>\n</ul></p>\n",
+ "<li><a href=\"~ts\">Full textual log</a></li>\n"
+ "<li><a href=\"~ts\">Coverage log</a></li>\n"
+ "<li><a href=\"~ts\">Unexpected I/O log</a></li>\n</ul></p>\n",
[?suitelog_name,?coverlog_name,?unexpected_io_log]),
print(html,
- "<p>~s</p>\n" ++
+ "<p>~ts</p>\n" ++
xhtml("<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">",
["<table id=\"",?sortable_table_name,"\">\n",
"<thead>\n"]) ++
"<tr><th>Num</th><th>Module</th><th>Group</th>" ++
"<th>Case</th><th>Log</th><th>Time</th><th>Result</th>" ++
"<th>Comment</th></tr>\n</thead>\n<tbody>\n",
- [print_if_known(N, {"<i>Executing <b>~p</b> test cases...</i>" ++
- xhtml("\n<br>\n", "\n<br />\n"),[N]},
+ [print_if_known(N, {"<i>Executing <b>~w</b> test cases...</i>"
+ ++ xhtml("\n<br>\n", "\n<br />\n"),[N]},
{"",[]})]),
- print(major, "=cases ~p", [get(test_server_cases)]),
- print(major, "=user ~s", [TI#target_info.username]),
- print(major, "=host ~s", [TI#target_info.host]),
+ print(major, "=cases ~w", [get(test_server_cases)]),
+ print(major, "=user ~ts", [TI#target_info.username]),
+ print(major, "=host ~ts", [TI#target_info.host]),
%% If there are no hosts specified,use only the local host
case controller_call(get_hosts) of
[] ->
- print(major, "=hosts ~s", [TI#target_info.host]),
+ print(major, "=hosts ~ts", [TI#target_info.host]),
controller_call({set_hosts, [TI#target_info.host]});
Hosts ->
Str = lists:flatten(lists:map(fun(X) -> [X," "] end, Hosts)),
- print(major, "=hosts ~s", [Str])
+ print(major, "=hosts ~ts", [Str])
end,
- print(major, "=emulator_vsn ~s", [TI#target_info.version]),
- print(major, "=emulator ~s", [TI#target_info.emulator]),
- print(major, "=otp_release ~s", [TI#target_info.otp_release]),
- print(major, "=started ~s",
+ print(major, "=emulator_vsn ~ts", [TI#target_info.version]),
+ print(major, "=emulator ~ts", [TI#target_info.emulator]),
+ print(major, "=otp_release ~ts", [TI#target_info.otp_release]),
+ print(major, "=started ~ts",
[lists:flatten(timestamp_get(""))]),
put(test_server_html_footer, Footer),
@@ -1674,21 +1667,18 @@ start_log_file() ->
MkDirError2 ->
log_file_error(MkDirError2, TestDir)
end,
- ok = file:write_file(filename:join(Dir, ?last_file), TestDir1 ++ "\n"),
- ok = file:write_file(?last_file, TestDir1 ++ "\n"),
+ ok = write_file(filename:join(Dir, ?last_file), TestDir1 ++ "\n"),
+ ok = write_file(?last_file, TestDir1 ++ "\n"),
put(test_server_log_dir_base,TestDir1),
MajorName = filename:join(TestDir1, ?suitelog_name),
HtmlName = MajorName ++ ?html_ext,
UnexpectedName = filename:join(TestDir1, ?unexpected_io_log),
- {ok,Major} = file:open(MajorName, [write]),
- {ok,Html} = file:open(HtmlName, [write]),
- {ok,Unexpected} = file:open(UnexpectedName, [write]),
+ {ok,Major} = open_file(MajorName),
+ {ok,Html} = open_html_file(HtmlName),
+ {ok,Unexpected} = open_file(UnexpectedName),
test_server_io:set_fd(major, Major),
test_server_io:set_fd(html, Html),
test_server_io:set_fd(unexpected_io, Unexpected),
- put(test_server_major_fd,Major),
- put(test_server_html_fd,Html),
- put(test_server_unexpected_io, Unexpected),
make_html_link(filename:absname(?last_test ++ ?html_ext),
HtmlName, filename:basename(Dir)),
@@ -1714,21 +1704,15 @@ make_html_link(LinkName, Target, Explanation) ->
PwdL = filename:split(filename:dirname(LinkName)),
Href = case lists:prefix(PwdL, TargetL) of
true ->
- filename:join(lists:nthtail(length(PwdL), TargetL));
+ uri_encode(filename:join(lists:nthtail(length(PwdL),TargetL)));
false ->
- "file:" ++ Target
+ "file:" ++ uri_encode(Target)
end,
- H = io_lib:format("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
- "<html>\n"
- "<head><title>~s</title></head>\n"
- "<body bgcolor=\"white\" text=\"black\""
- " link=\"blue\" vlink=\"purple\" alink=\"red\">\n"
- "<h1>Last test</h1>\n"
- "<a href=\"~s\">~s</a>~n"
- "</body>\n</html>\n",
- [Explanation,Href,Explanation]),
- ok = file:write_file(LinkName, H).
+ H = [html_header(Explanation),
+ "<h1>Last test</h1>\n"
+ "<a href=\"",Href,"\">",Explanation,"</a>\n"
+ "</body>\n</html>\n"],
+ ok = write_html_file(LinkName, H).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% start_minor_log_file(Mod, Func) -> AbsName
@@ -1743,7 +1727,7 @@ make_html_link(LinkName, Target, Explanation) ->
start_minor_log_file(Mod, Func) ->
MFA = {Mod,Func,1},
LogDir = get(test_server_log_dir_base),
- Name0 = lists:flatten(io_lib:format("~s.~s~s", [Mod,Func,?html_ext])),
+ Name0 = lists:flatten(io_lib:format("~w.~w~ts", [Mod,Func,?html_ext])),
Name = downcase(Name0),
AbsName = filename:join(LogDir, Name),
case file:read_file_info(AbsName) of
@@ -1752,37 +1736,29 @@ start_minor_log_file(Mod, Func) ->
{ok,_} -> %% special case, duplicate names
{_,S,Us} = now(),
Name1_0 =
- lists:flatten(io_lib:format("~s.~s.~w.~w~s", [Mod,Func,S,
- trunc(Us/1000),
- ?html_ext])),
+ lists:flatten(io_lib:format("~w.~w.~w.~w~ts", [Mod,Func,S,
+ trunc(Us/1000),
+ ?html_ext])),
Name1 = downcase(Name1_0),
AbsName1 = filename:join(LogDir, Name1),
start_minor_log_file1(Mod, Func, LogDir, AbsName1, MFA)
end.
start_minor_log_file1(Mod, Func, LogDir, AbsName, MFA) ->
- {ok,Fd} = file:open(AbsName, [write]),
+ {ok,Fd} = open_html_file(AbsName),
Lev = get(test_server_minor_level)+1000, %% far down in the minor levels
put(test_server_minor_fd, Fd),
test_server_gl:set_minor_fd(group_leader(), Fd, MFA),
- TestDescr = io_lib:format("Test ~p:~p result", [Mod,Func]),
+ TestDescr = io_lib:format("Test ~w:~w result", [Mod,Func]),
{Header,Footer} =
- case test_server_sup:framework_call(get_html_wrapper,
+ case test_server_sup:framework_call(get_html_wrapper,
[TestDescr,false,
filename:dirname(AbsName),
undefined], "") of
Empty when (Empty == "") ; (element(2,Empty) == "") ->
put(basic_html, true),
- {["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
- "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n",
- "<html>\n",
- "<head><title>", TestDescr, "</title>\n",
- "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
- "</head>\n",
- "<body bgcolor=\"white\" text=\"black\" ",
- "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"],
- "\n</body>\n</html>\n"};
+ {html_header(TestDescr), "\n</body>\n</html>\n"};
{basic_html,Html0,Html1} ->
put(basic_html, true),
{Html0,Html1};
@@ -1791,24 +1767,21 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName, MFA) ->
{Html0,Html1}
end,
put(test_server_minor_footer, Footer),
- io:fwrite(Fd, Header, []),
+ io:put_chars(Fd, Header),
- SrcListing = downcase(cast_to_list(Mod)) ++ ?src_listing_ext,
+ SrcListing = downcase(atom_to_list(Mod)) ++ ?src_listing_ext,
case {filelib:is_file(filename:join(LogDir, SrcListing)),
lists:member(no_src, get(test_server_logopts))} of
{true,false} ->
- print(Lev, "<a href=\"~s#~s\">source code for ~p:~p/1</a>\n",
- [SrcListing,atom_to_list(Func)++"-1",Mod,Func]);
- _ -> ok
+ print(Lev, "<a href=\"~ts#~ts\">source code for ~w:~w/1</a>\n",
+ [uri_encode(SrcListing),
+ uri_encode(atom_to_list(Func)++"-1",utf8),
+ Mod,Func]);
+ _ ->
+ ok
end,
- io:fwrite(Fd, "<pre>\n", []),
-
-% Stupid BUG!
-% case catch apply(Mod, Func, [doc]) of
-% {'EXIT', _Why} -> ok;
-% Comment -> print(Lev, "Comment: ~s~n<br>", [Comment])
-% end,
+ io:put_chars(Fd, "<pre>\n"),
AbsName.
@@ -1816,8 +1789,8 @@ stop_minor_log_file() ->
test_server_gl:unset_minor_fd(group_leader()),
Fd = get(test_server_minor_fd),
Footer = get(test_server_minor_footer),
- io:fwrite(Fd, "</pre>\n" ++ Footer, []),
- file:close(Fd),
+ io:put_chars(Fd, "</pre>\n" ++ Footer),
+ ok = file:close(Fd),
put(test_server_minor_fd, undefined).
downcase(S) -> downcase(S, []).
@@ -1899,25 +1872,15 @@ html_possibly_convert(Src, SrcInfo, Dest) ->
ok; % dest file up to date
_ ->
OutDir = get(test_server_log_dir_base),
- Header =
- case test_server_sup:framework_call(get_html_wrapper,
- ["Module "++Src,false,
- OutDir,undefined], "") of
- Empty when (Empty == "") ; (element(2,Empty) == "") ->
- ["<!DOCTYPE HTML PUBLIC",
- "\"-//W3C//DTD HTML 3.2 Final//EN\">\n",
- "<!-- autogenerated by 'erl2html2' -->\n",
- "<html>\n",
- "<head><title>Module ", Src, "</title>\n",
- "<meta http-equiv=\"cache-control\" ",
- "content=\"no-cache\">\n",
- "</head>\n",
- "<body bgcolor=\"white\" text=\"black\" ",
- "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"];
- {_,Html,_} ->
- Html
- end,
- erl2html2:convert(Src, Dest, Header)
+ case test_server_sup:framework_call(get_html_wrapper,
+ ["Module "++Src,false,
+ OutDir,undefined,
+ encoding(Src)], "") of
+ Empty when (Empty == "") ; (element(2,Empty) == "") ->
+ erl2html2:convert(Src, Dest);
+ {_,Header,_} ->
+ erl2html2:convert(Src, Dest, Header)
+ end
end.
%% Copy all HTML files in InDir to OutDir.
@@ -1929,9 +1892,9 @@ copy_html_file(Src, DestDir) ->
Dest = filename:join(DestDir, filename:basename(Src)),
case file:read_file(Src) of
{ok,Bin} ->
- ok = file:write_file(Dest, Bin);
+ ok = write_file(Dest, Bin);
{error,_Reason} ->
- io:format("File ~p: read failed\n", [Src])
+ io:format("File ~tp: read failed\n", [Src])
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2106,15 +2069,15 @@ run_test_cases(TestSpec, Config, TimetrapData) ->
end,
OkN = get(test_server_ok),
FailedN = get(test_server_failed),
- print(1, "TEST COMPLETE, ~w ok, ~w failed~s of ~w test cases\n",
+ print(1, "TEST COMPLETE, ~w ok, ~w failed~ts of ~w test cases\n",
[OkN,FailedN,SkipStr,OkN+FailedN+AllSkippedN]),
test_server_sup:framework_call(report, [tests_done,
{OkN,FailedN,{UserSkipN,AutoSkipN}}]),
- print(major, "=finished ~s", [lists:flatten(timestamp_get(""))]),
- print(major, "=failed ~p", [FailedN]),
- print(major, "=successful ~p", [OkN]),
- print(major, "=user_skipped ~p", [UserSkipN]),
- print(major, "=auto_skipped ~p", [AutoSkipN]),
+ print(major, "=finished ~ts", [lists:flatten(timestamp_get(""))]),
+ print(major, "=failed ~w", [FailedN]),
+ print(major, "=successful ~w", [OkN]),
+ print(major, "=user_skipped ~w", [UserSkipN]),
+ print(major, "=auto_skipped ~w", [AutoSkipN]),
exit(test_suites_done).
@@ -2645,7 +2608,8 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
run_test_cases_loop(Cases, [NewCfg|Config],
TimetrapData, Mode, Status2);
Bad ->
- print(minor, "~n*** ~p returned bad elements in Config: ~p.~n",
+ print(minor,
+ "~n*** ~w returned bad elements in Config: ~tp.~n",
[Func,Bad]),
Reason = {failed,{Mod,init_per_suite,bad_return}},
Cases2 = skip_cases_upto(Ref, Cases, Reason, conf, CurrMode),
@@ -2660,8 +2624,9 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
stop_minor_log_file(),
run_test_cases_loop(Cases, [NewCfg|Config], TimetrapData, Mode, Status2);
{_,{framework_error,{FwMod,FwFunc},Reason},_} ->
- print(minor, "~n*** ~p failed in ~p. Reason: ~p~n", [FwMod,FwFunc,Reason]),
- print(1, "~p failed in ~p. Reason: ~p~n", [FwMod,FwFunc,Reason]),
+ print(minor, "~n*** ~w failed in ~w. Reason: ~tp~n",
+ [FwMod,FwFunc,Reason]),
+ print(1, "~w failed in ~w. Reason: ~tp~n", [FwMod,FwFunc,Reason]),
exit(framework_error);
{_,Fail,_} when element(1,Fail) == 'EXIT';
element(1,Fail) == timetrap_timeout;
@@ -2670,7 +2635,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
{Cases2,Config1,Status3} =
if StartConf ->
ReportAbortRepeat(failed),
- print(minor, "~n*** ~p failed.~n"
+ print(minor, "~n*** ~w failed.~n"
" Skipping all cases.", [Func]),
Reason = {failed,{Mod,Func,Fail}},
{skip_cases_upto(Ref, Cases, Reason, conf, CurrMode),
@@ -2687,7 +2652,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
run_test_cases_loop(Cases2, Config1, TimetrapData, Mode, Status3);
{_,{Skip,Reason},_} when StartConf and ((Skip==skip) or (Skip==skipped)) ->
ReportAbortRepeat(skipped),
- print(minor, "~n*** ~p skipped.~n"
+ print(minor, "~n*** ~w skipped.~n"
" Skipping all cases.", [Func]),
set_io_buffering(IOHandler),
stop_minor_log_file(),
@@ -2696,7 +2661,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
delete_status(Ref, Status2));
{_,{skip_and_save,Reason,_SavedConfig},_} when StartConf ->
ReportAbortRepeat(skipped),
- print(minor, "~n*** ~p skipped.~n"
+ print(minor, "~n*** ~w skipped.~n"
" Skipping all cases.", [Func]),
set_io_buffering(IOHandler),
stop_minor_log_file(),
@@ -2757,7 +2722,7 @@ run_test_cases_loop([{conf,Ref,Props,{Mod,Func}}|_Cases]=Cs0,
run_test_cases_loop([{make,Ref,{Mod,Func,Args}}|Cases0], Config, TimetrapData, Mode, Status) ->
case run_test_case(Ref, 0, Mod, Func, Args, skip_init, TimetrapData) of
{_,Why={'EXIT',_},_} ->
- print(minor, "~n*** ~p failed.~n"
+ print(minor, "~n*** ~w failed.~n"
" Skipping all cases.", [Func]),
Reason = {failed,{Mod,Func,Why}},
Cases = skip_cases_upto(Ref, Cases0, Reason, conf, Mode),
@@ -2803,8 +2768,9 @@ run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status)
run_init, TimetrapData, Mode) of
%% callback to framework module failed, exit immediately
{_,{framework_error,{FwMod,FwFunc},Reason},_} ->
- print(minor, "~n*** ~p failed in ~p. Reason: ~p~n", [FwMod,FwFunc,Reason]),
- print(1, "~p failed in ~p. Reason: ~p~n", [FwMod,FwFunc,Reason]),
+ print(minor, "~n*** ~w failed in ~w. Reason: ~tp~n",
+ [FwMod,FwFunc,Reason]),
+ print(1, "~w failed in ~w. Reason: ~tp~n", [FwMod,FwFunc,Reason]),
stop_minor_log_file(),
exit(framework_error);
%% sequential execution of test case finished
@@ -2836,8 +2802,9 @@ run_test_cases_loop([{Mod,Func,Args}|Cases], Config, TimetrapData, Mode, Status)
stop_minor_log_file(),
run_test_cases_loop(Cases, Config, TimetrapData, Mode, Status1);
true -> % skip rest of cases in sequence
- print(minor, "~n*** ~p failed.~n"
- " Skipping all other cases in sequence.", [Func]),
+ print(minor, "~n*** ~w failed.~n"
+ " Skipping all other cases in sequence.",
+ [Func]),
Reason = {failed,{Mod,Func}},
Cases2 = skip_cases_upto(Ref, Cases, Reason, tc, Mode),
stop_minor_log_file(),
@@ -2953,7 +2920,7 @@ get_data_dir(Mod, Suite) ->
end,
case code:which(UseMod) of
non_existing ->
- print(12, "The module ~p is not loaded", [Mod]),
+ print(12, "The module ~w is not loaded", [Mod]),
[];
cover_compiled ->
MainCoverNode = cover:get_main_node(),
@@ -2964,7 +2931,7 @@ get_data_dir(Mod, Suite) ->
end.
do_get_data_dir(Mod,File) ->
- filename:dirname(File) ++ "/" ++ cast_to_list(Mod) ++ ?data_dir_suffix.
+ filename:dirname(File) ++ "/" ++ atom_to_list(Mod) ++ ?data_dir_suffix.
print_conf_time(0) ->
ok;
@@ -2975,8 +2942,8 @@ print_conf_time(ConfTime) ->
print_props(_, []) ->
ok;
print_props(true, Props) ->
- print(major, "=group_props ~p", [Props]),
- print(minor, "Group properties: ~p~n", [Props]);
+ print(major, "=group_props ~tp", [Props]),
+ print(minor, "Group properties: ~tp~n", [Props]);
print_props(_, _) ->
ok.
@@ -3126,24 +3093,24 @@ skip_case1(Type, CaseNum, Mod, Func, Comment, Mode) ->
Comment1 = reason_to_string(Comment),
- print(major, "~n=case ~p:~p", [Mod,Func]),
- print(major, "=started ~s", [lists:flatten(timestamp_get(""))]),
- print(major, "=result skipped: ~s", [Comment1]),
- print(2,"*** Skipping test case #~w ~p ***", [CaseNum,{Mod,Func}]),
+ print(major, "~n=case ~w:~w", [Mod,Func]),
+ print(major, "=started ~ts", [lists:flatten(timestamp_get(""))]),
+ print(major, "=result skipped: ~ts", [Comment1]),
+ print(2,"*** Skipping test case #~w ~w ***", [CaseNum,{Mod,Func}]),
TR = xhtml("<tr valign=\"top\">", ["<tr class=\"",odd_or_even(),"\">"]),
GroupName = case get_name(Mode) of
undefined -> "";
Name -> cast_to_list(Name)
end,
print(html,
- TR ++ "<td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>"
- "<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>"
- "<td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>"
- "<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>"
+ TR ++ "<td>" ++ Col0 ++ "~ts" ++ Col1 ++ "</td>"
+ "<td>" ++ Col0 ++ "~w" ++ Col1 ++ "</td>"
+ "<td>" ++ Col0 ++ "~ts" ++ Col1 ++ "</td>"
+ "<td>" ++ Col0 ++ "~w" ++ Col1 ++ "</td>"
"<td>" ++ Col0 ++ "< >" ++ Col1 ++ "</td>"
"<td>" ++ Col0 ++ "0.000s" ++ Col1 ++ "</td>"
- "<td><font color=\"~s\">SKIPPED</font></td>"
- "<td>~s</td></tr>\n",
+ "<td><font color=\"~ts\">SKIPPED</font></td>"
+ "<td>~ts</td></tr>\n",
[num2str(CaseNum),fw_name(Mod),GroupName,Func,ResultCol,Comment1]),
if CaseNum > 0 ->
{US,AS} = get(test_server_skipped),
@@ -3325,7 +3292,7 @@ wait_and_resend(Ref, [{_,CurrPid,CaseNum,Mod,Func}|Ps] = Cases, Ok,Skip,Fail) ->
{'EXIT',CurrPid,Reason} when Reason /= normal ->
%% unexpected termination of test case process
{value,{_,_,CaseNum,Mod,Func}} = lists:keysearch(CurrPid, 2, Cases),
- print(1, "Error! Process for test case #~p (~p:~p) died! Reason: ~p",
+ print(1, "Error! Process for test case #~w (~w:~w) died! Reason: ~tp",
[CaseNum, Mod, Func, Reason]),
exit({unexpected_termination,{CaseNum,Mod,Func},{CurrPid,Reason}})
end;
@@ -3464,7 +3431,7 @@ handle_io_and_exits(Main, CurrPid, CaseNum, Mod, Func, Cases) ->
{'EXIT',TCPid,Reason} when Reason /= normal ->
test_server_io:print_buffered(CurrPid),
{value,{_,_,Num,M,F}} = lists:keysearch(TCPid, 2, Cases),
- print(1, "Error! Process for test case #~p (~p:~p) died! Reason: ~p",
+ print(1, "Error! Process for test case #~w (~w:~w) died! Reason: ~tp",
[Num, M, F, Reason]),
exit({unexpected_termination,{Num,M,F},{TCPid,Reason}})
end.
@@ -3540,11 +3507,11 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
end,
TSDir = get(test_server_dir),
- print(major, "=case ~p:~p", [Mod, Func]),
+ print(major, "=case ~w:~w", [Mod, Func]),
MinorName = start_minor_log_file(Mod, Func),
print(minor, "<a name=\"top\"></a>", [], internal_raw),
MinorBase = filename:basename(MinorName),
- print(major, "=logfile ~s", [filename:basename(MinorName)]),
+ print(major, "=logfile ~ts", [filename:basename(MinorName)]),
UpdatedArgs =
%% maybe create unique private directory for test case or config func
@@ -3552,14 +3519,13 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
auto_per_run ->
update_config(hd(Args), [{tc_logfile,MinorName}]);
PrivDirMode ->
+ %% create unique private directory for test case
RunDir = filename:dirname(MinorName),
Ext =
if Num == 0 ->
{_,S,Us} = now(),
lists:flatten(io_lib:format(".~w.~w", [S,Us]));
true ->
- %% create unique private directory for test case
- RunDir = filename:dirname(MinorName),
lists:flatten(io_lib:format(".~w", [Num]))
end,
PrivDir = filename:join(RunDir, ?priv_dir) ++ Ext,
@@ -3580,16 +3546,17 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
undefined -> "";
Name -> cast_to_list(Name)
end,
- print(major, "=started ~s", [lists:flatten(timestamp_get(""))]),
+ print(major, "=started ~ts", [lists:flatten(timestamp_get(""))]),
{{Col0,Col1},Style} = get_font_style((RunInit==run_init), Mode),
TR = xhtml("<tr valign=\"top\">", ["<tr class=\"",odd_or_even(),"\">"]),
- print(html, TR ++ "<td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>"
- "<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>"
- "<td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>"
- "<td><a href=\"~s\">~p</a></td>"
- "<td><a href=\"~s#top\"><</a> <a href=\"~s#end\">></a></td>",
- [num2str(Num),fw_name(Mod),GroupName,MinorBase,Func,
- MinorBase,MinorBase]),
+ EncMinorBase = uri_encode(MinorBase),
+ print(html, TR ++ "<td>" ++ Col0 ++ "~ts" ++ Col1 ++ "</td>"
+ "<td>" ++ Col0 ++ "~w" ++ Col1 ++ "</td>"
+ "<td>" ++ Col0 ++ "~ts" ++ Col1 ++ "</td>"
+ "<td><a href=\"~ts\">~w</a></td>"
+ "<td><a href=\"~ts#top\"><</a> <a href=\"~ts#end\">></a></td>",
+ [num2str(Num),fw_name(Mod),GroupName,EncMinorBase,Func,
+ EncMinorBase,EncMinorBase]),
do_unless_parallel(Main, fun erlang:yield/0),
@@ -3606,7 +3573,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
print(minor, "<a name=\"end\"></a>", [], internal_raw),
print(minor, "\n", [], internal_raw),
print_timestamp(minor, "Ended at "),
- print(major, "=ended ~s", [lists:flatten(timestamp_get(""))]),
+ print(major, "=ended ~ts", [lists:flatten(timestamp_get(""))]),
do_unless_parallel(Main, fun() -> file:set_cwd(filename:dirname(TSDir)) end),
@@ -3690,13 +3657,13 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit,
{'EXIT',_} = Exit ->
print(minor,
"WARNING: There might be slavenodes left in the"
- " system. I tried to kill them, but I failed: ~p\n",
+ " system. I tried to kill them, but I failed: ~tp\n",
[Exit]);
[] -> ok;
List ->
print(minor, "WARNING: ~w slave nodes in system after test"++
"case. Tried to killed them.~n"++
- " Names:~p",
+ " Names:~tp",
[length(List),List])
end;
false ->
@@ -3756,7 +3723,7 @@ progress(skip, CaseNum, Mod, Func, Loc, Reason, Time,
fun() -> {?auto_skip_color,auto_skip} end,
fun() -> {?user_skip_color,skip} end),
print(major, "=result skipped", []),
- print(1, "*** SKIPPED *** ~s",
+ print(1, "*** SKIPPED *** ~ts",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
test_server_sup:framework_call(report, [tc_done,{Mod,Func,
{skipped,Reason1}}]),
@@ -3775,24 +3742,24 @@ progress(skip, CaseNum, Mod, Func, Loc, Reason, Time,
end,
print(html,
"<td>" ++ St0 ++ "~.3fs" ++ St1 ++ "</td>"
- "<td><font color=\"~s\">SKIPPED</font></td>"
- "<td>~s~s</td></tr>\n",
+ "<td><font color=\"~ts\">SKIPPED</font></td>"
+ "<td>~ts~ts</td></tr>\n",
[Time,Color,ReasonStr2,Comment1]),
FormatLoc = test_server_sup:format_loc(Loc),
- print(minor, "=== location ~s", [FormatLoc]),
- print(minor, "=== reason = ~s", [ReasonStr1]),
+ print(minor, "=== location ~ts", [FormatLoc]),
+ print(minor, "=== reason = ~ts", [ReasonStr1]),
Ret;
progress(failed, CaseNum, Mod, Func, Loc, timetrap_timeout, T,
Comment0, {St0,St1}) ->
- print(major, "=result failed: timeout, ~p", [Loc]),
- print(1, "*** FAILED *** ~s",
+ print(major, "=result failed: timeout, ~tp", [Loc]),
+ print(1, "*** FAILED *** ~ts",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
test_server_sup:framework_call(report,
[tc_done,{Mod,Func,
{failed,timetrap_timeout}}]),
FormatLastLoc = test_server_sup:format_loc(get_last_loc(Loc)),
- ErrorReason = io_lib:format("{timetrap_timeout,~s}", [FormatLastLoc]),
+ ErrorReason = io_lib:format("{timetrap_timeout,~ts}", [FormatLastLoc]),
Comment =
case Comment0 of
"" -> "<font color=\"red\">" ++ ErrorReason ++ "</font>";
@@ -3802,23 +3769,23 @@ progress(failed, CaseNum, Mod, Func, Loc, timetrap_timeout, T,
print(html,
"<td>" ++ St0 ++ "~.3fs" ++ St1 ++ "</td>"
"<td><font color=\"red\">FAILED</font></td>"
- "<td>~s</td></tr>\n",
+ "<td>~ts</td></tr>\n",
[T/1000,Comment]),
FormatLoc = test_server_sup:format_loc(Loc),
- print(minor, "=== location ~s", [FormatLoc]),
+ print(minor, "=== location ~ts", [FormatLoc]),
print(minor, "=== reason = timetrap timeout", []),
failed;
progress(failed, CaseNum, Mod, Func, Loc, {testcase_aborted,Reason}, _T,
Comment0, {St0,St1}) ->
- print(major, "=result failed: testcase_aborted, ~p", [Loc]),
- print(1, "*** FAILED *** ~s",
+ print(major, "=result failed: testcase_aborted, ~tp", [Loc]),
+ print(1, "*** FAILED *** ~ts",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
test_server_sup:framework_call(report,
[tc_done,{Mod,Func,
{failed,testcase_aborted}}]),
FormatLastLoc = test_server_sup:format_loc(get_last_loc(Loc)),
- ErrorReason = io_lib:format("{testcase_aborted,~s}", [FormatLastLoc]),
+ ErrorReason = io_lib:format("{testcase_aborted,~ts}", [FormatLastLoc]),
Comment =
case Comment0 of
"" -> "<font color=\"red\">" ++ ErrorReason ++ "</font>";
@@ -3828,24 +3795,24 @@ progress(failed, CaseNum, Mod, Func, Loc, {testcase_aborted,Reason}, _T,
print(html,
"<td>" ++ St0 ++ "died" ++ St1 ++ "</td>"
"<td><font color=\"red\">FAILED</font></td>"
- "<td>~s</td></tr>\n",
+ "<td>~ts</td></tr>\n",
[Comment]),
FormatLoc = test_server_sup:format_loc(Loc),
- print(minor, "=== location ~s", [FormatLoc]),
- print(minor, "=== reason = {testcase_aborted,~p}", [Reason]),
+ print(minor, "=== location ~ts", [FormatLoc]),
+ print(minor, "=== reason = {testcase_aborted,~tp}", [Reason]),
failed;
progress(failed, CaseNum, Mod, Func, unknown, Reason, Time,
Comment0, {St0,St1}) ->
- print(major, "=result failed: ~p, ~p", [Reason,unknown]),
- print(1, "*** FAILED *** ~s",
+ print(major, "=result failed: ~tp, ~w", [Reason,unknown]),
+ print(1, "*** FAILED *** ~ts",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
test_server_sup:framework_call(report, [tc_done,{Mod,Func,
{failed,Reason}}]),
TimeStr = io_lib:format(if is_float(Time) -> "~.3fs";
true -> "~w"
end, [Time]),
- ErrorReason = lists:flatten(io_lib:format("~p", [Reason])),
+ ErrorReason = lists:flatten(io_lib:format("~tp", [Reason])),
ErrorReason1 = lists:flatten([string:strip(S,left) ||
S <- string:tokens(ErrorReason,[$\n])]),
ErrorReason2 =
@@ -3862,19 +3829,19 @@ progress(failed, CaseNum, Mod, Func, unknown, Reason, Time,
to_string(Comment0)
end,
print(html,
- "<td>" ++ St0 ++ "~s" ++ St1 ++ "</td>"
+ "<td>" ++ St0 ++ "~ts" ++ St1 ++ "</td>"
"<td><font color=\"red\">FAILED</font></td>"
- "<td>~s</td></tr>\n",
+ "<td>~ts</td></tr>\n",
[TimeStr,Comment]),
- print(minor, "=== location ~s", [unknown]),
+ print(minor, "=== location ~w", [unknown]),
{FStr,FormattedReason} = format_exception(Reason),
print(minor, "=== reason = " ++ FStr, [FormattedReason]),
failed;
progress(failed, CaseNum, Mod, Func, Loc, Reason, Time,
Comment0, {St0,St1}) ->
- print(major, "=result failed: ~p, ~p", [Reason,Loc]),
- print(1, "*** FAILED *** ~s",
+ print(major, "=result failed: ~tp, ~tp", [Reason,Loc]),
+ print(1, "*** FAILED *** ~ts",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
test_server_sup:framework_call(report, [tc_done,{Mod,Func,
{failed,Reason}}]),
@@ -3888,12 +3855,12 @@ progress(failed, CaseNum, Mod, Func, Loc, Reason, Time,
end,
FormatLastLoc = test_server_sup:format_loc(get_last_loc(Loc)),
print(html,
- "<td>" ++ St0 ++ "~s" ++ St1 ++ "</td>"
+ "<td>" ++ St0 ++ "~ts" ++ St1 ++ "</td>"
"<td><font color=\"red\">FAILED</font></td>"
- "<td><font color=\"red\">~s</font>~s</td></tr>\n",
+ "<td><font color=\"red\">~ts</font>~ts</td></tr>\n",
[TimeStr,FormatLastLoc,Comment]),
FormatLoc = test_server_sup:format_loc(Loc),
- print(minor, "=== location ~s", [FormatLoc]),
+ print(minor, "=== location ~ts", [FormatLoc]),
{FStr,FormattedReason} = format_exception(Reason),
print(minor, "=== reason = " ++ FStr, [FormattedReason]),
failed;
@@ -3909,7 +3876,7 @@ progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time,
HtmlCmt = test_server_sup:framework_call(format_comment,
[String],
String),
- print(major, "=result ok: ~s", [String]),
+ print(major, "=result ok: ~ts", [String]),
"<td>" ++ HtmlCmt ++ "</td>";
_ ->
print(major, "=result ok", []),
@@ -3918,13 +3885,13 @@ progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time,
_ -> "<td>" ++ to_string(Comment0) ++ "</td>"
end
end,
- print(major, "=elapsed ~p", [Time]),
+ print(major, "=elapsed ~tp", [Time]),
print(html,
"<td>" ++ St0 ++ "~.3fs" ++ St1 ++ "</td>"
"<td><font color=\"green\">Ok</font></td>"
- "~s</tr>\n",
+ "~ts</tr>\n",
[Time,Comment]),
- print(minor, "=== returned value = ~p", [RetVal]),
+ print(minor, "=== returned value = ~tp", [RetVal]),
ok.
%%--------------------------------------------------------------------
@@ -4000,12 +3967,12 @@ print_if_known(Known, {SK,AK}, {SU,AU}) ->
io_lib:format(S, A).
to_string(Term) when is_list(Term) ->
- case (catch io_lib:format("~s", [Term])) of
- {'EXIT',_} -> io_lib:format("~p", [Term]);
+ case (catch io_lib:format("~ts", [Term])) of
+ {'EXIT',_} -> lists:flatten(io_lib:format("~tp", [Term]));
String -> lists:flatten(String)
end;
to_string(Term) ->
- lists:flatten(io_lib:format("~p", [Term])).
+ lists:flatten(io_lib:format("~tp", [Term])).
get_last_loc(Loc) when is_tuple(Loc) ->
Loc;
@@ -4077,14 +4044,14 @@ format_exception(Reason={_Error,Stack}) when is_list(Stack) ->
undefined ->
case application:get_env(test_server, format_exception) of
{ok,false} ->
- {"~p",Reason};
+ {"~tp",Reason};
_ ->
do_format_exception(Reason)
end;
FW ->
case application:get_env(FW, format_exception) of
{ok,false} ->
- {"~p",Reason};
+ {"~tp",Reason};
_ ->
do_format_exception(Reason)
end
@@ -4099,10 +4066,10 @@ do_format_exception(Reason={Error,Stack}) ->
end,
case catch lib:format_exception(1, error, Error, Stack, StackFun, PF) of
{'EXIT',_} ->
- {"~p",Reason};
+ {"~tp",Reason};
Formatted ->
Formatted1 = re:replace(Formatted, "exception error: ", "", [{return,list}]),
- {"~s",lists:flatten(Formatted1)}
+ {"~ts",lists:flatten(Formatted1)}
end.
@@ -4173,7 +4140,7 @@ print_who(Host, User) ->
"" -> "";
_ -> " by " ++ User
end,
- print(html, "Run~s on ~s", [UserStr,Host]).
+ print(html, "Run~ts on ~ts", [UserStr,Host]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% format(Format) -> IoLibReturn
@@ -4208,7 +4175,7 @@ format(Detail, Format, Args) ->
Str =
case catch io_lib:format(Format, Args) of
{'EXIT',_} ->
- io_lib:format("illegal format; ~p with args ~p.\n",
+ io_lib:format("illegal format; ~tp with args ~tp.\n",
[Format,Args]);
Valid -> Valid
end,
@@ -4244,7 +4211,7 @@ odd_or_even() ->
%% date and time. The resulting string is suitable as a filename.
timestamp_filename_get(Leader) ->
timestamp_get_internal(Leader,
- "~s~w-~2.2.0w-~2.2.0w_~2.2.0w.~2.2.0w.~2.2.0w").
+ "~ts~w-~2.2.0w-~2.2.0w_~2.2.0w.~2.2.0w.~2.2.0w").
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% timestamp_get(Leader) -> string()
@@ -4254,7 +4221,7 @@ timestamp_filename_get(Leader) ->
%% date and time. The resulting string is suitable for display.
timestamp_get(Leader) ->
timestamp_get_internal(Leader,
- "~s~w-~2.2.0w-~2.2.0w ~2.2.0w:~2.2.0w:~2.2.0w").
+ "~ts~w-~2.2.0w-~2.2.0w ~2.2.0w:~2.2.0w:~2.2.0w").
timestamp_get_internal(Leader, Format) ->
{YY,MM,DD,H,M,S} = time_get(),
@@ -4588,14 +4555,18 @@ collect_files(Dir, Pattern, St) ->
Wc = filename:join([Dir1,Pattern++code:objfile_extension()]),
case catch filelib:wildcard(Wc) of
{'EXIT', Reason} ->
- io:format("Could not collect files: ~p~n", [Reason]),
+ io:format("Could not collect files: ~tp~n", [Reason]),
{error,{collect_fail,Dir,Pattern}};
Mods0 ->
Mods = [{path_to_module(Mod),all} || Mod <- lists:sort(Mods0)],
collect_cases(Mods, St)
end.
-path_to_module(Path) ->
+path_to_module(Path) when is_list(Path) ->
+ %% If this is called with a binary, then we are probably in +fnu
+ %% mode and have found a beam file with name encoded as latin1. We
+ %% will let this crash since it can not work to load such a module
+ %% anyway. It should be removed or renamed!
list_to_atom(filename:rootname(filename:basename(Path))).
collect_case_deny(Mod, Case, MFA, ReqList, SubCases, St) ->
@@ -4617,16 +4588,16 @@ check_deny([], _DenyList) -> granted;
check_deny(Req, DenyList) -> check_deny([Req], DenyList).
check_deny_req({Req,Val}, DenyList) ->
- %%io:format("ValCheck ~p=~p in ~p\n", [Req,Val,DenyList]),
+ %%io:format("ValCheck ~tp=~tp in ~tp\n", [Req,Val,DenyList]),
case lists:keysearch(Req, 1, DenyList) of
{value,{_Req,DenyVal}} when Val >= DenyVal ->
- {denied,io_lib:format("Requirement ~p=~p", [Req,Val])};
+ {denied,io_lib:format("Requirement ~tp=~tp", [Req,Val])};
_ ->
check_deny_req(Req, DenyList)
end;
check_deny_req(Req, DenyList) ->
case lists:member(Req, DenyList) of
- true -> {denied,io_lib:format("Requirement ~p", [Req])};
+ true -> {denied,io_lib:format("Requirement ~tp", [Req])};
false -> granted
end.
@@ -4727,14 +4698,14 @@ get_target_info() ->
start_node(Name, Type, Options) ->
T = 10 * ?ACCEPT_TIMEOUT * test_server:timetrap_scale_factor(),
- format(minor, "Attempt to start ~w node ~p with options ~p",
+ format(minor, "Attempt to start ~w node ~tp with options ~tp",
[Type, Name, Options]),
case controller_call({start_node,Name,Type,Options}, T) of
{{ok,Nodename}, Host, Cmd, Info, Warning} ->
format(minor,
- "Successfully started node ~p on ~p with command: ~p",
+ "Successfully started node ~w on ~tp with command: ~tp",
[Nodename, Host, Cmd]),
- format(major, "=node_start ~p", [Nodename]),
+ format(major, "=node_start ~w", [Nodename]),
case Info of
[] -> ok;
_ -> format(minor, Info)
@@ -4748,17 +4719,17 @@ start_node(Name, Type, Options) ->
{ok, Nodename};
{fail,{Ret, Host, Cmd}} ->
format(minor,
- "Failed to start node ~p on ~p with command: ~p~n"
- "Reason: ~p",
+ "Failed to start node ~tp on ~tp with command: ~tp~n"
+ "Reason: ~tp",
[Name, Host, Cmd, Ret]),
{fail,Ret};
{Ret, undefined, undefined} ->
- format(minor, "Failed to start node ~p: ~p", [Name,Ret]),
+ format(minor, "Failed to start node ~tp: ~tp", [Name,Ret]),
Ret;
{Ret, Host, Cmd} ->
format(minor,
- "Failed to start node ~p on ~p with command: ~p~n"
- "Reason: ~p",
+ "Failed to start node ~tp on ~tp with command: ~tp~n"
+ "Reason: ~tp",
[Name, Host, Cmd, Ret]),
Ret
end.
@@ -4972,11 +4943,11 @@ read_cover_file(CoverFile) ->
case check_cover_file(List, [], [], []) of
{ok,Exclude,Include,Cross} -> {Exclude,Include,Cross};
error ->
- io:fwrite("Faulty format of CoverFile ~p\n", [CoverFile]),
+ io:fwrite("Faulty format of CoverFile ~tp\n", [CoverFile]),
{[],[],[]}
end;
{error,Reason} ->
- io:fwrite("Can't read CoverFile ~p\nReason: ~p\n",
+ io:fwrite("Can't read CoverFile ~ts\nReason: ~tp\n",
[CoverFile,Reason]),
{[],[],[]}
end.
@@ -5029,11 +5000,11 @@ check_cross([]) ->
cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, Stop, TestDir) ->
write_default_cross_coverlog(TestDir),
- {ok,CoverLog} = file:open(filename:join(TestDir, ?coverlog_name), [write]),
+ {ok,CoverLog} = open_html_file(filename:join(TestDir, ?coverlog_name)),
write_coverlog_header(CoverLog),
io:fwrite(CoverLog, "<h1>Coverage for application '~w'</h1>\n", [App]),
io:fwrite(CoverLog,
- "<p><a href=\"~s\">Coverdata collected over all tests</a></p>",
+ "<p><a href=\"~ts\">Coverdata collected over all tests</a></p>",
[?cross_coverlog_name]),
{CoverFile,_Included,Excluded,Cross} =
@@ -5045,7 +5016,7 @@ cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, Stop, TestDir) ->
{Excl,Incl,Cr} = read_cover_file(File),
{File,Incl,Excl,Cr}
end,
- io:fwrite(CoverLog, "<p>CoverFile: <code>~p</code>\n", [CoverFile]),
+ io:fwrite(CoverLog, "<p>CoverFile: <code>~tp</code>\n", [CoverFile]),
write_cross_cover_info(TestDir,Cross),
case length(cover:imported_modules()) of
@@ -5056,11 +5027,11 @@ cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, Stop, TestDir) ->
ok
end,
- io:fwrite(CoverLog, "<p>Excluded module(s): <code>~p</code>\n", [Excluded]),
+ io:fwrite(CoverLog, "<p>Excluded module(s): <code>~tp</code>\n", [Excluded]),
Coverage = cover_analyse(Analyse, AnalyseMods, Stop),
- file:write_file(filename:join(TestDir,?raw_coverlog_name),
- term_to_binary(Coverage)),
+ write_file(filename:join(TestDir,?raw_coverlog_name),
+ term_to_binary(Coverage)),
case lists:filter(fun({_M,{_,_,_}}) -> false;
(_) -> true
@@ -5074,8 +5045,7 @@ cover_analyse({App,CoverInfo}, Analyse, AnalyseMods, Stop, TestDir) ->
end,
TotPercent = write_cover_result_table(CoverLog, Coverage),
- file:write_file(filename:join(TestDir, ?cover_total),
- term_to_binary(TotPercent)).
+ write_file(filename:join(TestDir, ?cover_total),term_to_binary(TotPercent)).
cover_analyse(Analyse, AnalyseMods, Stop) ->
TestDir = get(test_server_log_dir_base),
@@ -5122,25 +5092,25 @@ cross_cover_analyse(Analyse, TagDirs0) ->
write_cross_cover_info(_Dir,[]) ->
ok;
write_cross_cover_info(Dir,Cross) ->
- {ok,Fd} = file:open(filename:join(Dir,?cross_cover_info),[write]),
- lists:foreach(fun(C) -> io:format(Fd,"~p.~n",[C]) end, Cross),
- file:close(Fd).
+ {ok,Fd} = open_file(filename:join(Dir,?cross_cover_info)),
+ lists:foreach(fun(C) -> io:format(Fd,"~tp.~n",[C]) end, Cross),
+ ok = file:close(Fd).
%% For each test from which there are cross cover analysed
%% modules, write a cross cover log (cross_cover.html).
write_cross_cover_logs([{Tag,Coverage}|T],TagDirMods) ->
case lists:keyfind(Tag,1,TagDirMods) of
{_,Dir,Mods} when Mods=/=[] ->
- file:write_file(filename:join(Dir,?raw_cross_coverlog_name),
- term_to_binary(Coverage)),
+ write_file(filename:join(Dir,?raw_cross_coverlog_name),
+ term_to_binary(Coverage)),
CoverLogName = filename:join(Dir,?cross_coverlog_name),
- {ok,CoverLog} = file:open(CoverLogName, [write]),
+ {ok,CoverLog} = open_html_file(CoverLogName),
write_coverlog_header(CoverLog),
io:fwrite(CoverLog,
"<h1>Coverage results for \'~w\' from all tests</h1>\n",
[Tag]),
write_cover_result_table(CoverLog, Coverage),
- io:fwrite("Written file ~p\n", [CoverLogName]);
+ io:fwrite("Written file ~tp\n", [CoverLogName]);
_ ->
ok
end,
@@ -5224,19 +5194,11 @@ analyse_modules(_Dir, [], _DetailsFun, Acc) ->
%% Support functions for writing the cover logs (both cross and normal)
write_coverlog_header(CoverLog) ->
- case catch
- io:fwrite(CoverLog,
- "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<!-- autogenerated by '~w'. -->\n"
- "<html>\n"
- "<head><title>Coverage results</title></head>\n"
- "<body bgcolor=\"white\" text=\"black\" "
- "link=\"blue\" vlink=\"purple\" alink=\"red\">",
- [?MODULE]) of
+ case catch io:put_chars(CoverLog,html_header("Coverage results")) of
{'EXIT',Reason} ->
io:format("\n\nERROR: Could not write normal heading in coverlog.\n"
"CoverLog: ~w\n"
- "Reason: ~p\n",
+ "Reason: ~tp\n",
[CoverLog,Reason]),
io:format(CoverLog,"<html><body>\n", []);
_ ->
@@ -5251,20 +5213,22 @@ format_analyse(M,Cov,NotCov,undefined) ->
"<td align=right>~w</td></tr>\n",
[M,pc(Cov,NotCov),Cov,NotCov]);
format_analyse(M,Cov,NotCov,{file,File}) ->
- io_lib:fwrite("<tr><td><a href=\"~s\">~w</a></td>"
+ io_lib:fwrite("<tr><td><a href=\"~ts\">~w</a></td>"
"<td align=right>~w %</td>"
"<td align=right>~w</td>"
"<td align=right>~w</td></tr>\n",
- [filename:basename(File),M,pc(Cov,NotCov),Cov,NotCov]);
+ [uri_encode(filename:basename(File)),
+ M,pc(Cov,NotCov),Cov,NotCov]);
format_analyse(M,Cov,NotCov,{lines,Lines}) ->
CoverOutName = atom_to_list(M)++".COVER.html",
- {ok,CoverOut} = file:open(CoverOutName, [write]),
+ {ok,CoverOut} = open_html_file(CoverOutName),
write_not_covered(CoverOut,M,Lines),
- io_lib:fwrite("<tr><td><a href=\"~s\">~w</a></td>"
+ ok = file:close(CoverOut),
+ io_lib:fwrite("<tr><td><a href=\"~ts\">~w</a></td>"
"<td align=right>~w %</td>"
"<td align=right>~w</td>"
"<td align=right>~w</td></tr>\n",
- [CoverOutName,M,pc(Cov,NotCov),Cov,NotCov]);
+ [uri_encode(CoverOutName),M,pc(Cov,NotCov),Cov,NotCov]);
format_analyse(M,Cov,NotCov,{error,_}) ->
io_lib:fwrite("<tr><td>~w</td>"
"<td align=right>~w %</td>"
@@ -5280,8 +5244,8 @@ pc(Cov,NotCov) ->
write_not_covered(CoverOut,M,Lines) ->
+ io:put_chars(CoverOut,html_header("Coverage results for "++atom_to_list(M))),
io:fwrite(CoverOut,
- "<html>\n"
"The following lines in module ~w are not covered:\n"
"<table border=3 cellpadding=5>\n"
"<th>Line Number</th>\n",
@@ -5292,25 +5256,25 @@ write_not_covered(CoverOut,M,Lines) ->
ok
end,
Lines),
- io:fwrite(CoverOut,"</table>\n</html>\n", []).
+ io:put_chars(CoverOut,"</table>\n</body>\n</html>\n").
write_default_coverlog(TestDir) ->
- {ok,CoverLog} = file:open(filename:join(TestDir,?coverlog_name), [write]),
+ {ok,CoverLog} = open_html_file(filename:join(TestDir,?coverlog_name)),
write_coverlog_header(CoverLog),
- io:fwrite(CoverLog,"Cover tool is not used\n</body></html>\n", []),
- file:close(CoverLog).
+ io:put_chars(CoverLog,"Cover tool is not used\n</body></html>\n"),
+ ok = file:close(CoverLog).
write_default_cross_coverlog(TestDir) ->
{ok,CrossCoverLog} =
- file:open(filename:join(TestDir,?cross_coverlog_name), [write]),
+ open_html_file(filename:join(TestDir,?cross_coverlog_name)),
write_coverlog_header(CrossCoverLog),
io:put_chars(CrossCoverLog,
["No cross cover modules exist for this application,",
xhtml("<br>","<br />"),
"or cross cover analysis is not completed.\n"
"</body></html>\n"]),
- file:close(CrossCoverLog).
+ ok = file:close(CrossCoverLog).
write_cover_result_table(CoverLog,Coverage) ->
io:fwrite(CoverLog,
@@ -5321,7 +5285,7 @@ write_cover_result_table(CoverLog,Coverage) ->
{TotCov,TotNotCov} =
lists:foldl(fun({M,{Cov,NotCov,Details}},{AccCov,AccNotCov}) ->
Str = format_analyse(M,Cov,NotCov,Details),
- io:fwrite(CoverLog,"~s", [Str]),
+ io:fwrite(CoverLog,"~ts", [Str]),
{AccCov+Cov,AccNotCov+NotCov};
({_M,{error,_Reason}},{AccCov,AccNotCov}) ->
{AccCov,AccNotCov}
@@ -5336,5 +5300,81 @@ write_cover_result_table(CoverLog,Coverage) ->
"</body>\n"
"</html>\n",
[TotPercent,TotCov,TotNotCov]),
- file:close(CoverLog),
+ ok = file:close(CoverLog),
TotPercent.
+
+
+%%%-----------------------------------------------------------------
+%%% Support functions for writing files
+
+%% HTML files are always written with utf8 encoding
+html_header(Title) ->
+ ["<!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"
+ "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n"
+ "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n"
+ "</head>\n"
+ "<body bgcolor=\"white\" text=\"black\" "
+ "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"].
+
+open_html_file(File) ->
+ file:open(File,[write,{encoding,utf8}]).
+
+write_html_file(File,Content) ->
+ file:write_file(File,unicode:characters_to_binary(Content)).
+
+
+%% Text files are written with default encoding
+open_file(File) ->
+ file:open(File,[write]).
+
+write_file(File,Content) ->
+ file:write_file(File,Content).
+
+%% Encoding of hyperlinks in HTML files
+uri_encode(File) ->
+ Encoding = file:native_name_encoding(),
+ uri_encode(File,Encoding).
+
+uri_encode(File,Encoding) ->
+ Components = filename:split(File),
+ filename:join([uri_encode_comp(C,Encoding) || C <- Components]).
+
+uri_encode_comp("/",_) ->
+ "/";
+uri_encode_comp(Chars,utf8) ->
+ http_uri:encode(Chars);
+uri_encode_comp(Chars,latin1) ->
+ do_uri_encode(Chars).
+
+%% Encode a file reference to a latin1 filename so it can be inserted
+%% in a utf8 encoded HTML file.
+%% This does the same as http_uri:encode/1, except it also encodes all
+%% characters >127 - i.e. latin1 but not ASCII.
+do_uri_encode([Char|Chars]) ->
+ case Char>127 orelse sets:is_element(Char, reserved()) of
+ true ->
+ [ $% | http_util:integer_to_hexlist(Char)] ++ do_uri_encode(Chars);
+ false ->
+ [Char | do_uri_encode(Chars)]
+ end;
+do_uri_encode([]) ->
+ [].
+
+%% Copied from http_uri.erl, but slightly modified
+%% (not converting @ and :)
+reserved() ->
+ sets:from_list([$;, $&, $=, $+, $,, $/, $?,
+ $#, $[, $], $<, $>, $\", ${, $}, $|,
+ $\\, $', $^, $%, $ ]).
+
+encoding(File) ->
+ case epp:read_encoding(File) of
+ none ->
+ epp:default_encoding();
+ E ->
+ E
+ end.
diff --git a/lib/test_server/src/test_server_gl.erl b/lib/test_server/src/test_server_gl.erl
index d32c7c07dc..0ab0d58040 100644
--- a/lib/test_server/src/test_server_gl.erl
+++ b/lib/test_server/src/test_server_gl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2013. 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
@@ -223,20 +223,12 @@ do_set_props([{reject_io_reqs,Bool}|Ps], St) ->
do_set_props([], St) -> St.
io_req({put_chars,Enc,Bytes}, _, _) when Enc =:= latin1; Enc =:= unicode ->
- to_latin1(Enc, Bytes);
+ unicode:characters_to_list(Bytes, Enc);
io_req({put_chars,Encoding,Mod,Func,[Format,Args]}, _, _) ->
Str = Mod:Func(Format, Args),
- to_latin1(Encoding, Str);
+ unicode:characters_to_list(Str, Encoding);
io_req(_, _, _) -> passthrough.
-to_latin1(unicode, Str) ->
- [if C > 255 ->
- io_lib:format("\\{~.8B}", [C]);
- true ->
- C
- end || C <- unicode:characters_to_list(Str, unicode)];
-to_latin1(latin1, Str) -> Str.
-
output(Level, Str, Sender, From, St) when is_integer(Level) ->
case selected_by_level(Level, stdout, St) of
true -> output(stdout, Str, Sender, From, St);
@@ -258,7 +250,7 @@ output(Level, Str, Sender, From, St) when is_atom(Level) ->
output_to_file(Level, dress_output(Str, Sender, St), From, St).
output_to_file(minor, Data0, From, #st{tc={M,F,A},minor=none}) ->
- Data = [io_lib:format("=== ~p:~p/~p\n", [M,F,A]),Data0],
+ Data = [io_lib:format("=== ~w:~w/~w\n", [M,F,A]),Data0],
test_server_io:print(From, unexpected_io, Data),
ok;
output_to_file(minor, Data, From, #st{minor=Fd}) ->
diff --git a/lib/test_server/src/test_server_h.erl b/lib/test_server/src/test_server_h.erl
index 78daba855d..c624947306 100644
--- a/lib/test_server/src/test_server_h.erl
+++ b/lib/test_server/src/test_server_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2013. 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
@@ -140,9 +140,9 @@ report_receiver(info_report, _) -> kernel;
report_receiver(_, _) -> none.
tag({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) ->
- io:format(user, "~n=TESTCASE: ~p:~p/~p", [M,F,A]);
+ io:format(user, "~n=TESTCASE: ~w:~w/~w", [M,F,A]);
tag(Testcase) ->
- io:format(user, "~n=TESTCASE: ~p", [Testcase]).
+ io:format(user, "~n=TESTCASE: ~tp", [Testcase]).
tag_event(Event) ->
{calendar:local_time(), Event}.
diff --git a/lib/test_server/src/test_server_internal.hrl b/lib/test_server/src/test_server_internal.hrl
index d204c35293..9a11182725 100644
--- a/lib/test_server/src/test_server_internal.hrl
+++ b/lib/test_server/src/test_server_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2013. 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
diff --git a/lib/test_server/src/test_server_io.erl b/lib/test_server/src/test_server_io.erl
index 777b377201..662ee11515 100644
--- a/lib/test_server/src/test_server_io.erl
+++ b/lib/test_server/src/test_server_io.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2013. 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
@@ -235,7 +235,7 @@ handle_info(kill_group_leaders, #st{gls=Gls,stopping=From}=St) ->
gen_server:reply(From, ok),
{stop,normal,St};
handle_info(Other, St) ->
- io:format("Ignoring: ~p\n", [Other]),
+ io:format("Ignoring: ~tp\n", [Other]),
{noreply,St}.
terminate(_, _) ->
@@ -256,12 +256,12 @@ output(From, Tag, Str, #st{io_buffering=Buffered,buffered=Buf0}=St) ->
do_output(stdout, Str, #st{job_name=undefined}) ->
io:put_chars(Str);
do_output(stdout, Str0, #st{job_name=Name}) ->
- Str = io_lib:format("Testing ~s: ~s\n", [Name,Str0]),
+ Str = io_lib:format("Testing ~ts: ~ts\n", [Name,Str0]),
io:put_chars(Str);
do_output(Tag, Str, #st{fds=Fds}=St) ->
case gb_trees:lookup(Tag, Fds) of
none ->
- S = io_lib:format("\n*** ERROR: ~p, line ~p: No known '~p' log file\n",
+ S = io_lib:format("\n*** ERROR: ~w, line ~w: No known '~tp' log file\n",
[?MODULE,?LINE,Tag]),
do_output(stdout, [S,Str], St);
{value,Fd} ->
@@ -272,8 +272,8 @@ do_output(Tag, Str, #st{fds=Fds}=St) ->
_ -> ok
end
catch _:Error ->
- S = io_lib:format("\n*** ERROR: ~p, line ~p: Error writing to "
- "log file '~p': ~p\n",
+ S = io_lib:format("\n*** ERROR: ~w, line ~w: Error writing to "
+ "log file '~tp': ~tp\n",
[?MODULE,?LINE,Tag,Error]),
do_output(stdout, [S,Str], St)
end
diff --git a/lib/test_server/src/test_server_node.erl b/lib/test_server/src/test_server_node.erl
index b307d93c7d..62248af4db 100644
--- a/lib/test_server/src/test_server_node.erl
+++ b/lib/test_server/src/test_server_node.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2013. 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
@@ -249,7 +249,7 @@ print_trc(Out,{trace_ts,P,call,{M,F,A},C,Ts},N) ->
"~w: ~s~n"
"Process : ~w~n"
"Call : ~w:~w/~w~n"
- "Arguments : ~p~n"
+ "Arguments : ~tp~n"
"Caller : ~w~n~n",
[N,ts(Ts),P,M,F,length(A),A,C]);
print_trc(Out,{trace_ts,P,call,{M,F,A},Ts},N) ->
@@ -257,14 +257,14 @@ print_trc(Out,{trace_ts,P,call,{M,F,A},Ts},N) ->
"~w: ~s~n"
"Process : ~w~n"
"Call : ~w:~w/~w~n"
- "Arguments : ~p~n~n",
+ "Arguments : ~tp~n~n",
[N,ts(Ts),P,M,F,length(A),A]);
print_trc(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) ->
io:format(Out,
"~w: ~s~n"
"Process : ~w~n"
"Return from : ~w:~w/~w~n"
- "Return value : ~p~n~n",
+ "Return value : ~tp~n~n",
[N,ts(Ts),P,M,F,A,R]);
print_trc(Out,{drop,X},N) ->
io:format(Out,
@@ -274,7 +274,7 @@ print_trc(Out,Trace,N) ->
Ts = element(size(Trace),Trace),
io:format(Out,
"~w: ~s~n"
- "Trace : ~p~n~n",
+ "Trace : ~tp~n~n",
[N,ts(Ts),Trace]).
ts({_, _, Micro} = Now) ->
{{Y,M,D},{H,Min,S}} = calendar:now_to_local_time(Now),
@@ -465,8 +465,8 @@ handle_start_node_return(Version,VsnStr,{started, Node, OVersion, OVsnStr}) ->
Str = io_lib:format("WARNING: Started node "
"reports different system "
"version than current node! "
- "Current node version: ~p, ~p "
- "Started node version: ~p, ~p",
+ "Current node version: ~tp, ~tp "
+ "Started node version: ~tp, ~tp",
[Version, VsnStr,
OVersion, OVsnStr]),
Str1 = lists:flatten(Str),
diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl
index a6d426887e..cd96568970 100644
--- a/lib/test_server/src/test_server_sup.erl
+++ b/lib/test_server/src/test_server_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -72,10 +72,10 @@ timetrap(Timeout0, ReportTVal, Scale, Pid) ->
after 10000 ->
%% Pid is probably trapping exits, hit it harder...
catch error_logger:warning_msg(
- "Testcase process ~p not "
+ "Testcase process ~w not "
"responding to timetrap "
"timeout:~n"
- " ~p.~n"
+ " ~tp.~n"
"Killing testcase...~n",
[Pid, Trap]),
exit(Pid, kill)
@@ -142,11 +142,11 @@ call_crash(Time,Crash,M,F,A) ->
{'EXIT',Pid,_Reason} when Crash==any ->
ok;
{'EXIT',Reason} ->
- test_server:format(12, "Wrong crash reason. Wanted ~p, got ~p.",
+ test_server:format(12, "Wrong crash reason. Wanted ~tp, got ~tp.",
[Crash, Reason]),
exit({wrong_crash_reason,Reason});
{'EXIT',Pid,Reason} ->
- test_server:format(12, "Wrong crash reason. Wanted ~p, got ~p.",
+ test_server:format(12, "Wrong crash reason. Wanted ~tp, got ~tp.",
[Crash, Reason]),
exit({wrong_crash_reason,Reason});
{'EXIT',OtherPid,Reason} when OldTrapExit == false ->
@@ -312,7 +312,7 @@ check_dict(Dict, Reason) ->
[] ->
1; % All ok.
List ->
- io:format("** ~s (~s) ->~n~p~n",[Reason, Dict, List]),
+ io:format("** ~ts (~ts) ->~n~tp~n",[Reason, Dict, List]),
0
end.
@@ -321,7 +321,7 @@ check_dict_tolerant(Dict, Reason, Mode) ->
[] ->
1; % All ok.
List ->
- io:format("** ~s (~s) ->~n~p~n",[Reason, Dict, List]),
+ io:format("** ~ts (~ts) ->~n~tp~n",[Reason, Dict, List]),
case Mode of
pedantic ->
0;
@@ -377,7 +377,7 @@ check_new_crash_dumps() ->
ok;
Num ->
test_server_ctrl:format(minor,
- "Found ~p crash dumps:~n", [Num]),
+ "Found ~w crash dumps:~n", [Num]),
append_files_to_logfile(Dumps),
delete_files(Dumps)
end.
@@ -385,7 +385,7 @@ check_new_crash_dumps() ->
append_files_to_logfile([]) -> ok;
append_files_to_logfile([File|Files]) ->
NodeName=from($., File),
- test_server_ctrl:format(minor, "Crash dump from node ~p:~n",[NodeName]),
+ test_server_ctrl:format(minor, "Crash dump from node ~tp:~n",[NodeName]),
Fd=get(test_server_minor_fd),
case file:read_file(File) of
{ok, Bin} ->
@@ -397,22 +397,22 @@ append_files_to_logfile([File|Files]) ->
%% fail, but in that case it will throw an exception so that
%% we will be aware of the problem.
io:format(Fd, "Unable to write the crash dump "
- "to this file: ~p~n", [file:format_error(Error)])
+ "to this file: ~tp~n", [file:format_error(Error)])
end;
_Error ->
- io:format(Fd, "Failed to read: ~s\n", [File])
+ io:format(Fd, "Failed to read: ~ts\n", [File])
end,
append_files_to_logfile(Files).
delete_files([]) -> ok;
delete_files([File|Files]) ->
- io:format("Deleting file: ~s~n", [File]),
+ io:format("Deleting file: ~ts~n", [File]),
case file:delete(File) of
{error, _} ->
case file:rename(File, File++".old") of
{error, Error} ->
io:format("Could neither delete nor rename file "
- "~s: ~s.~n", [File, Error]);
+ "~ts: ~ts.~n", [File, Error]);
_ ->
ok
end;
@@ -555,7 +555,7 @@ format_loc([{Mod,LineOrFunc}]) ->
format_loc({Mod,Func}) when is_atom(Func) ->
io_lib:format("{~w,~w}",[Mod,Func]);
format_loc(Loc) ->
- io_lib:format("~p",[Loc]).
+ io_lib:format("~tp",[Loc]).
format_loc1([{Mod,Func,Line}]) ->
[" ",format_loc1({Mod,Func,Line}),"]"];
@@ -566,9 +566,10 @@ format_loc1({Mod,Func,Line}) ->
case {lists:member(no_src, get(test_server_logopts)),
lists:reverse(ModStr)} of
{false,[$E,$T,$I,$U,$S,$_|_]} ->
- io_lib:format("{~w,~w,<a href=\"~s~s#~w\">~w</a>}",
- [Mod,Func,downcase(ModStr),?src_listing_ext,
- Line,Line]);
+ io_lib:format("{~w,~w,<a href=\"~ts~ts#~w\">~w</a>}",
+ [Mod,Func,
+ test_server_ctrl:uri_encode(downcase(ModStr)),
+ ?src_listing_ext,Line,Line]);
_ ->
io_lib:format("{~w,~w,~w}",[Mod,Func,Line])
end.
diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl
index cfd7161dbd..4e5dc1b759 100644
--- a/lib/test_server/src/ts.erl
+++ b/lib/test_server/src/ts.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
diff --git a/lib/test_server/src/ts_install.erl b/lib/test_server/src/ts_install.erl
index ba8952f10f..e9e559df5d 100644
--- a/lib/test_server/src/ts_install.erl
+++ b/lib/test_server/src/ts_install.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. 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
@@ -93,7 +93,7 @@ autoconf1(_,_) ->
throw(cross_installation_failed).
autoconf2({ok, Bin}) ->
- get_vars(binary_to_list(Bin), name, [], []);
+ get_vars(ts_lib:b2s(Bin), name, [], []);
autoconf2(Error) ->
Error.
@@ -170,12 +170,12 @@ parse_xcomp_file(Filepath) ->
parse_xcomp_file([<<A:8,_/binary>> = Line|R],Envs,Flags)
when $A =< A, A =< $Z ->
[Var,Value] = binary:split(Line,<<"=">>),
- parse_xcomp_file(R,[{binary_to_list(Var),
- binary_to_list(Value)}|Envs],Flags);
+ parse_xcomp_file(R,[{ts_lib:b2s(Var),
+ ts_lib:b2s(Value)}|Envs],Flags);
parse_xcomp_file([<<"erl_xcomp_",Line/binary>>|R],Envs,Flags) ->
[Var,Value] = binary:split(Line,<<"=">>),
- parse_xcomp_file(R,Envs,[{binary_to_list(Var),
- binary_to_list(Value)}|Flags]);
+ parse_xcomp_file(R,Envs,[{ts_lib:b2s(Var),
+ ts_lib:b2s(Value)}|Flags]);
parse_xcomp_file([_|R],Envs,Flags) ->
parse_xcomp_file(R,Envs,Flags);
parse_xcomp_file([],Envs,Flags) ->
@@ -407,4 +407,3 @@ extra_platform_label() ->
[_|_]=Label -> "/" ++ Label;
false -> ""
end.
-
diff --git a/lib/test_server/src/ts_lib.erl b/lib/test_server/src/ts_lib.erl
index c0200ab67c..a00f607fc1 100644
--- a/lib/test_server/src/ts_lib.erl
+++ b/lib/test_server/src/ts_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,7 +29,8 @@
specs/1, suites/2,
subst_file/3, subst/2, print_data/1,
make_non_erlang/2,
- maybe_atom_to_list/1, progress/4
+ maybe_atom_to_list/1, progress/4,
+ b2s/1
]).
error(Reason) ->
@@ -155,7 +156,7 @@ suite_order(_) -> 200.
subst_file(In, Out, Vars) ->
case file:read_file(In) of
{ok, Bin} ->
- Subst = subst(binary_to_list(Bin), Vars, []),
+ Subst = subst(b2s(Bin), Vars, []),
case file:write_file(Out, Subst) of
ok ->
ok;
@@ -334,3 +335,11 @@ make_non_erlang_do(DataDir, Variables) ->
after
timer:sleep(100) %% maybe unnecessary now when we don't do set_cwd anymore
end.
+
+b2s(Bin) ->
+ unicode:characters_to_list(Bin,default_encoding()).
+
+default_encoding() ->
+ try epp:default_encoding()
+ catch error:undef -> latin1
+ end.
diff --git a/lib/test_server/test/test_server_SUITE.erl b/lib/test_server/test/test_server_SUITE.erl
index fb82a87fd0..bea2c0dc49 100644
--- a/lib/test_server/test/test_server_SUITE.erl
+++ b/lib/test_server/test/test_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2013. 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
@@ -31,6 +31,7 @@
-include_lib("common_test/include/ct.hrl").
-include("test_server_test_lib.hrl").
+-include_lib("kernel/include/file.hrl").
%%--------------------------------------------------------------------
%% COMMON TEST CALLBACK FUNCTIONS
@@ -68,6 +69,13 @@ init_per_testcase(_TestCase, Config) ->
%% @spec end_per_testcase(TestCase, Config0) ->
%% void() | {save_config,Config1} | {fail,Reason}
+end_per_testcase(test_server_unicode, _Config) ->
+ [_,Host] = string:tokens(atom_to_list(node()), "@"),
+ N1 = list_to_atom("test_server_tester_latin1" ++ "@" ++ Host),
+ N2 = list_to_atom("test_server_tester_utf8" ++ "@" ++ Host),
+ test_server:stop_node(N1),
+ test_server:stop_node(N2),
+ ok;
end_per_testcase(_TestCase, _Config) ->
ok.
@@ -80,7 +88,8 @@ all() ->
[test_server_SUITE, test_server_parallel01_SUITE,
test_server_conf02_SUITE, test_server_conf01_SUITE,
test_server_skip_SUITE, test_server_shuffle01_SUITE,
- test_server_break_SUITE, test_server_cover_SUITE].
+ test_server_break_SUITE, test_server_cover_SUITE,
+ test_server_unicode].
%%--------------------------------------------------------------------
@@ -171,7 +180,24 @@ test_server_cover_SUITE(Config) ->
ok
end.
+test_server_unicode(Config) ->
+ run_test_server_tests("test_server_unicode_SUITE", [],
+ 5, 0, 3, 3, 0, 0, 0, 0, 5, Config),
+
+ %% Create and run two test suites - one with filename and content
+ %% in latin1 (if the default filename mode is latin1) and one with
+ %% filename and content in utf8. Both have name and content
+ %% including letters ���. Check that all logs are generated with
+ %% utf8 encoded filenames.
+ case file:native_name_encoding() of
+ utf8 ->
+ ok;
+ latin1 ->
+ generate_and_run_unicode_test(Config,latin1)
+ end,
+ generate_and_run_unicode_test(Config,utf8).
+%%%-----------------------------------------------------------------
run_test_server_tests(SuiteName, Skip, NCases, NFail, NExpected, NSucc,
NUsrSkip, NAutoSkip,
NActualSkip, NActualFail, NActualSucc, Config) ->
@@ -182,12 +208,13 @@ run_test_server_tests(SuiteName, Skip, NCases, NFail, NExpected, NSucc,
run_test_server_tests(SuiteName, Skip, NCases, NFail, NExpected, NSucc,
NUsrSkip, NAutoSkip,
NActualSkip, NActualFail, NActualSucc, Cover, Config) ->
-
+ Node = proplists:get_value(node, Config),
+ Encoding = rpc:call(Node,file,native_name_encoding,[]),
WorkDir = proplists:get_value(work_dir, Config),
- ct:log("<a href=\"file://~s\">Test case log files</a>\n",
- [filename:join(WorkDir, SuiteName++".logs")]),
+ LogDir = filename:join(WorkDir, SuiteName++".logs"),
+ LogDirUri = test_server_ctrl:uri_encode(LogDir, Encoding),
+ ct:log("<a href=\"file://~s\">Test case log files</a>\n", [LogDirUri]),
- Node = proplists:get_value(node, Config),
{ok,_Pid} = rpc:call(Node,test_server_ctrl, start, []),
case Cover of
false ->
@@ -207,12 +234,10 @@ run_test_server_tests(SuiteName, Skip, NCases, NFail, NExpected, NSucc,
rpc:call(Node,test_server_ctrl, stop, []),
- {ok,Data} = test_server_test_lib:parse_suite(
- lists:last(
- lists:sort(
- filelib:wildcard(
- filename:join([WorkDir,SuiteName++".logs",
- "run*","suite.log"]))))),
+ LogDir1 = translate_filename(LogDir,Encoding),
+ LastRunDir = get_latest_run_dir(LogDir1),
+ LastSuiteLog = filename:join(LastRunDir,"suite.log"),
+ {ok,Data} = test_server_test_lib:parse_suite(LastSuiteLog),
check([{"Number of cases",NCases,Data#suite.n_cases},
{"Number failed",NFail,Data#suite.n_cases_failed},
{"Number expected",NExpected,Data#suite.n_cases_expected},
@@ -229,6 +254,47 @@ run_test_server_tests(SuiteName, Skip, NCases, NFail, NExpected, NSucc,
end,{0,0,0},Data#suite.cases),
Data.
+translate_filename(Filename,EncodingOnTestNode) ->
+ case {file:native_name_encoding(),EncodingOnTestNode} of
+ {X,X} -> Filename;
+ {utf8,latin1} -> list_to_binary(Filename);
+ {latin1,utf8} -> unicode:characters_to_binary(Filename)
+ end.
+
+get_latest_run_dir(Dir) ->
+ %% For the time being, filelib:wildcard can not take a binary
+ %% argument, so we avoid using this here.
+ case file:list_dir(Dir) of
+ {ok,Files} ->
+ {ok,RE} = re:compile(<<"^run.[1-2][-_\.0-9]*$">>),
+ RunDirs = lists:filter(
+ fun(F) ->
+ L = l(F),
+ case re:run(F,RE) of
+ {match,[{0,L}]} -> true;
+ _ -> false
+ end
+ end, Files),
+ case RunDirs of
+ [] ->
+ Dir;
+ [H|T] ->
+ filename:join(Dir,get_latest_dir(T,H))
+ end;
+ _ ->
+ Dir
+ end.
+
+l(X) when is_binary(X) -> size(X);
+l(X) when is_list(X) -> length(X).
+
+get_latest_dir([H|T],Latest) when H>Latest ->
+ get_latest_dir(T,H);
+get_latest_dir([_|T],Latest) ->
+ get_latest_dir(T,Latest);
+get_latest_dir([],Latest) ->
+ Latest.
+
check([{Str,Same,Same}|T], Status) ->
io:format("~s: ~p\n", [Str,Same]),
check(T, Status);
@@ -246,4 +312,139 @@ until(Fun) ->
timer:sleep(100),
until(Fun)
end.
-
+
+generate_and_run_unicode_test(Config0,Encoding) ->
+ DataDir = ?config(data_dir,Config0),
+ Suite = create_unicode_test_suite(DataDir,Encoding),
+
+ %% We can not run this test on default node since it must be
+ %% started with correct file name mode (+fnu/+fnl).
+ %% OBS: the node are stopped by end_per_testcase/2
+ Config1 = lists:keydelete(node,1,Config0),
+ Config2 = lists:keydelete(work_dir,1,Config1),
+ NodeName = list_to_atom("test_server_tester_" ++ atom_to_list(Encoding)),
+ ErtsSwitch = case Encoding of
+ latin1 -> "+fnl";
+ utf8 -> "+fnu"
+ end,
+ Config = start_node(Config2,NodeName,ErtsSwitch),
+
+ %% Compile the suite
+ Node = proplists:get_value(node,Config),
+ {ok,Mod} = rpc:call(Node,compile,file,[Suite,[{outdir,DataDir}]]),
+ ModStr = atom_to_list(Mod),
+
+ %% Clean logdir
+ LogDir0 = filename:join(DataDir,ModStr++".logs"),
+ LogDir = translate_filename(LogDir0,Encoding),
+ rm_dir(LogDir),
+
+ %% Run the test
+ run_test_server_tests(ModStr, [], 3, 0, 1, 1, 0, 0, 0, 0, 3, Config),
+
+ %% Check that all logs are created with utf8 encoded filenames
+ true = filelib:is_dir(LogDir),
+
+ RunDir = get_latest_run_dir(LogDir),
+ true = filelib:is_dir(RunDir),
+
+ LowerModStr = string:to_lower(ModStr),
+ SuiteHtml = translate_filename(LowerModStr++".src.html",Encoding),
+ true = filelib:is_regular(filename:join(RunDir,SuiteHtml)),
+
+ TCLog = translate_filename(LowerModStr++".tc_���.html",Encoding),
+ true = filelib:is_regular(filename:join(RunDir,TCLog)),
+ ok.
+
+%% Same as test_server_test_lib:start_slave, but starts a peer with
+%% additional arguments.
+%% The reason for this is that we need to start nodes with +fnu/+fnl,
+%% and that will not work well with a slave node since slave nodes run
+%% remote file system on master - i.e. they will use same file name
+%% mode as the master.
+start_node(Config,Name,Args) ->
+ [_,Host] = string:tokens(atom_to_list(node()), "@"),
+ ct:log("Trying to start ~w@~s~n",[Name,Host]),
+ case test_server:start_node(Name, peer, [{args,Args}]) of
+ {error,Reason} ->
+ test_server:fail(Reason);
+ {ok,Node} ->
+ ct:log("Node ~p started~n", [Node]),
+ test_server_test_lib:prepare_tester_node(Node,Config)
+ end.
+
+create_unicode_test_suite(Dir,Encoding) ->
+ ModStr = "test_server_"++atom_to_list(Encoding)++"_���_SUITE",
+ File = filename:join(Dir,ModStr++".erl"),
+ Suite =
+ ["%% -*- ",epp:encoding_to_string(Encoding)," -*-\n",
+ "-module(",ModStr,").\n"
+ "\n"
+ "-export([all/1, init_per_suite/1, end_per_suite/1]).\n"
+ "-export([init_per_testcase/2, end_per_testcase/2]).\n"
+ "-export([tc_���/1]).\n"
+ "\n"
+ "-include_lib(\"test_server/include/test_server.hrl\").\n"
+ "\n"
+ "all(suite) ->\n"
+ " [tc_���].\n"
+ "\n"
+ "init_per_suite(Config) ->\n"
+ " Config.\n"
+ "\n"
+ "end_per_suite(_Config) ->\n"
+ " ok.\n"
+ "\n"
+ "init_per_testcase(_Case,Config) ->\n"
+ " init_timetrap(500,Config).\n"
+ "\n"
+ "init_timetrap(T,Config) ->\n"
+ " Dog = ?t:timetrap(T),\n"
+ " [{watchdog, Dog}|Config].\n"
+ "\n"
+ "end_per_testcase(_Case,Config) ->\n"
+ " cancel_timetrap(Config).\n"
+ "\n"
+ "cancel_timetrap(Config) ->\n"
+ " Dog=?config(watchdog, Config),\n"
+ " ?t:timetrap_cancel(Dog),\n"
+ " ok.\n"
+ "\n"
+ "tc_���(Config) when is_list(Config) ->\n"
+ " true = filelib:is_dir(?config(priv_dir,Config)),\n"
+ " ok.\n"],
+ {ok,Fd} = file:open(raw_filename(File,Encoding),[write,{encoding,Encoding}]),
+ io:put_chars(Fd,Suite),
+ ok = file:close(Fd),
+ File.
+
+raw_filename(Name,latin1) -> list_to_binary(Name);
+raw_filename(Name,utf8) -> unicode:characters_to_binary(Name).
+
+rm_dir(Dir) ->
+ case file:list_dir(Dir) of
+ {error,enoent} ->
+ ok;
+ {ok,Files} ->
+ rm_files([filename:join(Dir, F) || F <- Files]),
+ file:del_dir(Dir)
+ end.
+
+rm_files([F | Fs]) ->
+ case file:read_file_info(F) of
+ {ok,#file_info{type=directory}} ->
+ rm_dir(F),
+ rm_files(Fs);
+ {ok,_Regular} ->
+ case file:delete(F) of
+ ok ->
+ rm_files(Fs);
+ {error,Errno} ->
+ exit({del_failed,F,Errno})
+ end
+ end;
+rm_files([]) ->
+ ok.
+
+erts_switch(latin1) -> "+fnl";
+erts_switch(utf8) -> "+fnu".
diff --git a/lib/test_server/test/test_server_SUITE_data/Makefile.src b/lib/test_server/test/test_server_SUITE_data/Makefile.src
index c770627f04..5aeb035572 100644
--- a/lib/test_server/test/test_server_SUITE_data/Makefile.src
+++ b/lib/test_server/test/test_server_SUITE_data/Makefile.src
@@ -7,4 +7,5 @@ all:
erlc test_server_skip_SUITE.erl
erlc test_server_break_SUITE.erl
erlc test_server_cover_SUITE.erl
- erlc +debug_info test_server_cover_SUITE_data/cover_helper.erl \ No newline at end of file
+ erlc +debug_info test_server_cover_SUITE_data/cover_helper.erl
+ erlc test_server_unicode_SUITE.erl
diff --git a/lib/test_server/test/test_server_SUITE_data/test_server_unicode_SUITE.erl b/lib/test_server/test/test_server_SUITE_data/test_server_unicode_SUITE.erl
new file mode 100644
index 0000000000..662adedd4c
--- /dev/null
+++ b/lib/test_server/test/test_server_SUITE_data/test_server_unicode_SUITE.erl
@@ -0,0 +1,82 @@
+%% -*- coding: utf-8 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. 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(test_server_unicode_SUITE).
+
+-export([all/1, init_per_suite/1, end_per_suite/1]).
+-export([init_per_testcase/2, end_per_testcase/2]).
+-export([':#"|@\\ difficult_case_name_äöå'/1,
+ print_and_log_unicode/1,
+ print_and_log_latin1/1]).
+
+-include_lib("test_server/include/test_server.hrl").
+
+all(suite) ->
+ [':#"|@\\ difficult_case_name_äöå',
+ print_and_log_unicode,
+ print_and_log_latin1].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_Case,Config) ->
+ init_timetrap(500,Config).
+
+init_timetrap(T,Config) ->
+ Dog = ?t:timetrap(T),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(_Case,Config) ->
+ cancel_timetrap(Config).
+
+cancel_timetrap(Config) ->
+ Dog=?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+
+':#"|@\\ difficult_case_name_äöå'(Config) when is_list(Config) ->
+ ok.
+
+print_and_log_unicode(Config) when is_list(Config) ->
+ String = "שלום-שלום+של 日本語",
+ test_server:comment(String),
+ test_server:capture_start(),
+ io:format("String with ts: ~ts",[String]),
+ test_server:capture_stop(),
+ "String with ts: "++String = lists:flatten(test_server:capture_get()),
+ ok.
+
+print_and_log_latin1(Config) when is_list(Config) ->
+ String = "æøå",
+ test_server:comment(String),
+ test_server:capture_start(),
+ io:format("String with s: ~s",[String]),
+ io:format("String with ts: ~ts",[String]),
+ test_server:capture_stop(),
+ ["String with s: "++String,
+ "String with ts: "++String] =
+ [lists:flatten(L) || L<- test_server:capture_get()],
+ ok.
diff --git a/lib/test_server/test/test_server_test_lib.erl b/lib/test_server/test/test_server_test_lib.erl
index d466aa0110..cd6804f7ad 100644
--- a/lib/test_server/test/test_server_test_lib.erl
+++ b/lib/test_server/test/test_server_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2013. 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
@@ -20,6 +20,9 @@
-export([parse_suite/1]).
-export([init/2, pre_init_per_testcase/3, post_end_per_testcase/4]).
+%% for test_server_SUITE when node can not be started as slave
+-export([prepare_tester_node/2]).
+
-include("test_server_test_lib.hrl").
%% The CTH hooks all tests
@@ -49,38 +52,41 @@ start_slave(Config,_Level) ->
ct:log("Node ~p started~n", [Node]),
IsCover = test_server:is_cover(),
if IsCover ->
- cover:start(Node);
- true->
- ok
+ cover:start(Node);
+ true->
+ ok
end,
- DataDir = proplists:get_value(data_dir, Config),
- %% We would normally use priv_dir for temporary data,
- %% but the pathnames gets too long on Windows.
- %% Until the run-time system can support long pathnames,
- %% use the data dir.
- WorkDir = DataDir,
-
- %% WorkDir as well as directory of Test Server suites
- %% have to be in code path on Test Server node.
- [_ | Parts] = lists:reverse(filename:split(DataDir)),
- TSDir = filename:join(lists:reverse(Parts)),
- AddPathDirs = case proplists:get_value(path_dirs, Config) of
- undefined -> [];
- Ds -> Ds
- end,
- PathDirs = [WorkDir,TSDir | AddPathDirs],
- [true = rpc:call(Node, code, add_patha, [D]) || D <- PathDirs],
- io:format("Dirs added to code path (on ~w):~n",
- [Node]),
- [io:format("~s~n", [D]) || D <- PathDirs],
-
- true = rpc:call(Node, os, putenv,
- ["TEST_SERVER_FRAMEWORK", "undefined"]),
-
- ok = rpc:call(Node, file, set_cwd, [WorkDir]),
- [{node,Node}, {work_dir,WorkDir} | Config]
+ prepare_tester_node(Node,Config)
end.
+prepare_tester_node(Node,Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ %% We would normally use priv_dir for temporary data,
+ %% but the pathnames gets too long on Windows.
+ %% Until the run-time system can support long pathnames,
+ %% use the data dir.
+ WorkDir = DataDir,
+
+ %% WorkDir as well as directory of Test Server suites
+ %% have to be in code path on Test Server node.
+ [_ | Parts] = lists:reverse(filename:split(DataDir)),
+ TSDir = filename:join(lists:reverse(Parts)),
+ AddPathDirs = case proplists:get_value(path_dirs, Config) of
+ undefined -> [];
+ Ds -> Ds
+ end,
+ PathDirs = [WorkDir,TSDir | AddPathDirs],
+ [true = rpc:call(Node, code, add_patha, [D]) || D <- PathDirs],
+ io:format("Dirs added to code path (on ~w):~n",
+ [Node]),
+ [io:format("~s~n", [D]) || D <- PathDirs],
+
+ true = rpc:call(Node, os, putenv,
+ ["TEST_SERVER_FRAMEWORK", "undefined"]),
+
+ ok = rpc:call(Node, file, set_cwd, [WorkDir]),
+ [{node,Node}, {work_dir,WorkDir} | Config].
+
post_end_per_testcase(_TC, Config, Return, State) ->
Node = proplists:get_value(node, Config),
Cover = test_server:is_cover(),