Added printing messages (info + warning).
authorStanislaw Klekot <dozzie@jarowit.net>
Tue, 16 Jun 2015 00:21:05 +0000 (02:21 +0200)
committerStanislaw Klekot <dozzie@jarowit.net>
Tue, 16 Jun 2015 00:21:05 +0000 (02:21 +0200)
examples/04_diagnostics.t [new file with mode: 0644]
src/estap.erl
src/estap_server.erl

diff --git a/examples/04_diagnostics.t b/examples/04_diagnostics.t
new file mode 100644 (file)
index 0000000..b148e27
--- /dev/null
@@ -0,0 +1,50 @@
+#!bin/estap
+
+-plan(5).
+
+-test("info simple").
+info() ->
+  estap:plan(2),
+  estap:ok(true, "one pass"),
+  estap:info("this is an informational message"),
+  estap:ok(true, "two pass"),
+  estap:all_ok().
+
+-test("warning simple").
+warning() ->
+  estap:plan(2),
+  estap:ok(true, "one pass"),
+  estap:diag("this is a warning message"),
+  estap:ok(true, "two pass"),
+  estap:all_ok().
+
+-test("info with context").
+info_2() ->
+  estap:plan(2),
+  estap:ok(true, "one pass"),
+  estap:info("info", [{atom, second_atom}, {"string", "second string"}]),
+  estap:info("info", ["additional context (should be indented)"]),
+  estap:ok(true, "two pass"),
+  estap:all_ok().
+
+-test("warning with context").
+warning_2() ->
+  estap:plan(2),
+  estap:ok(true, "one pass"),
+  estap:diag("warn", [{atom, second_atom}, {"string", "second string"}]),
+  estap:diag("warn", ["additional context (should be indented)"]),
+  estap:ok(true, "two pass"),
+  estap:all_ok().
+
+-test("explain").
+explain() ->
+  estap:plan(2),
+  estap:ok(true, "one pass"),
+  estap:info("info", [
+    {one, estap:explain(dict:new())},
+    {two, estap:explain(sets:new())}
+  ]),
+  estap:ok(true, "two pass"),
+  estap:all_ok().
+
+%% vim:ft=erlang
index 07a9f21..0d8d7ed 100644 (file)
@@ -18,7 +18,7 @@
 %% public interface
 -export([ok/2, is/3, isnt/3, eq/3, ne/3, cmp/4, like/3, unlike/3, matches/3]).
 -export([bail_out/1, no_plan/0, plan/1, all_ok/0]).
--export([diag/1, diag/2, note/1, note/2, explain/1]).
+-export([diag/1, diag/2, info/1, info/2, explain/1]).
 -export([test_dir/0, test_dir/1]).
 
 -export_type([value/0, cmp/0, regexp/0, match_fun/0]).
@@ -38,7 +38,8 @@
 
 -type description() :: iolist().
 
--type info() :: term(). % TODO: more detailed definition
+-type info() :: atom() | iolist() |
+                {FieldName :: atom() | iolist(), Value :: atom() | iolist()}.
 
 %%% }}}
 %%%---------------------------------------------------------------------------
@@ -236,58 +237,79 @@ test_dir(_Subdir) ->
 
 %%%---------------------------------------------------------------------------
 
-%% @doc Print a warning.
+%% @doc Print a diagnostic message.
+%%   Typically, diagnostic message is a warning, but may be notice important
+%%   enough to print it along with test progress by TAP consumer.
 %%
-%% @TODO Implement this function.
+%%   Normally diagnostic output goes to <i>STDERR</i>, but under TODO tests it
+%%   goes to <i>STDOUT</i>.
+%%
+%% @TODO Make the diagnostic output go to <i>STDOUT</i> under TODO
 
 -spec diag(message()) ->
-  'TODO'.
+  ok.
 
-diag(_Message) ->
-  'TODO'.
+diag(Message) ->
+  TestRun = get_test_run(),
+  estap_server:warning(TestRun, Message).
 
 %% @doc Print a warning with some context.
+%%   Typically, diagnostic message is a warning, but may be notice important
+%%   enough to print it along with test progress by TAP consumer.
 %%
-%% @TODO Implement this function.
+%%   Normally diagnostic output goes to <i>STDERR</i>, but under TODO tests it
+%%   goes to <i>STDOUT</i>.
+%%
+%% @TODO Make the diagnostic output go to <i>STDOUT</i> under TODO
 
 -spec diag(message(), [info()]) ->
-  'TODO'.
+  ok.
 
-diag(_Message, _Info) ->
-  'TODO'.
+diag(Message, Info) ->
+  TestRun = get_test_run(),
+  InfoLines = [["  ", format_info(I), "\n"] || I <- Info],
+  estap_server:warning(TestRun, [Message, "\n", InfoLines]).
 
 %% @doc Print a message.
-%%
-%% @TODO Implement this function.
 
--spec note(message()) ->
-  'TODO'.
+-spec info(message()) ->
+  ok.
 
-note(_Message) ->
-  'TODO'.
+info(Message) ->
+  TestRun = get_test_run(),
+  estap_server:info(TestRun, Message).
 
 %% @doc Print a message with some context.
-%%
-%% @TODO Implement this function.
 
--spec note(message(), [info()]) ->
-  'TODO'.
+-spec info(message(), [info()]) ->
+  ok.
 
-note(_Message, _Info) ->
-  'TODO'.
+info(Message, Info) ->
+  TestRun = get_test_run(),
+  InfoLines = [["  ", format_info(I), "\n"] || I <- Info],
+  estap_server:info(TestRun, [Message, "\n", InfoLines]).
+
+%% @doc Format a single info entry for printing it on screen.
+
+-spec format_info(info()) ->
+  iolist().
+
+format_info(Info) when is_list(Info); is_binary(Info) ->
+  iolist_to_binary(Info);
+format_info(Info) when is_atom(Info) ->
+  atom_to_binary(Info, unicode);
+format_info({K, V} = _Info) ->
+  [format_info(K), ": ", format_info(V)].
 
 %% @doc Format term so it can be printed to screen.
 %%   Convenience wrapper for {@link io_lib:format/2}.
-%% @spec explain(term()) ->
-%%   iolist()
-%%
-%% @TODO Implement this function.
 
 -spec explain(term()) ->
-  'TODO'.
+  iolist().
 
-explain(_Term) ->
-  'TODO'.
+explain(Term) ->
+  % no term should weigh 1MB
+  io_lib:print(Term, 1, 1024 * 1024, -1).
 
 %%%---------------------------------------------------------------------------
 
index 907c1ce..a78ad17 100644 (file)
@@ -11,6 +11,7 @@
 %% public interface
 -export([no_plan/0, plan/1, subplan/2, done/1]).
 -export([get_status/1]).
+-export([info/2, warning/2]).
 -export([running/2, report_result/2, report_result_todo/3, report_skipped/2]).
 
 %% supervision tree API
@@ -49,6 +50,9 @@
 %%% public interface
 %%%---------------------------------------------------------------------------
 
+%%----------------------------------------------------------
+%% test plan setup {{{
+
 %% @doc "No plan" plan.
 
 -spec no_plan() ->
@@ -95,6 +99,10 @@ done(TestRunId) ->
 get_status(TestRunId) ->
   gen_server:call(TestRunId, status).
 
+%% }}}
+%%----------------------------------------------------------
+%% test plan execution {{{
+
 %% @doc Mark the beginning of new test.
 
 -spec running(test_run_id(), string()) ->
@@ -147,6 +155,30 @@ report_result_todo(TestRunId, Why, {died, Reason} = _TestResult) ->
 report_skipped(TestRunId, Why) ->
   gen_server:call(TestRunId, {skipped, Why}).
 
+%% }}}
+%%----------------------------------------------------------
+%% printing messages {{{
+
+%% @doc Print a regular message to test output.
+
+-spec info(test_run_id(), iolist()) ->
+  ok.
+
+info(TestRunId, Message) ->
+  gen_server:call(TestRunId, {info, Message}).
+
+%% @doc Print a diagnostic message (warning) to output, typically
+%%   <i>STDERR</i>.
+
+-spec warning(test_run_id(), iolist()) ->
+  ok.
+
+warning(TestRunId, Message) ->
+  gen_server:call(TestRunId, {warning, Message}).
+
+%% }}}
+%%----------------------------------------------------------
+
 %%%---------------------------------------------------------------------------
 %%% supervision tree API
 %%%---------------------------------------------------------------------------
@@ -268,6 +300,14 @@ handle_call(status = _Request, _From, State = #state{counters = Counters}) ->
   TODO = Counters#counters.todo_failures,
   {reply, {Planned, Total, Failed, TODO}, State};
 
+handle_call({info, Message} = _Request, _From, State) ->
+  print_info("~s", [Message], State),
+  {reply, ok, State};
+
+handle_call({warning, Message} = _Request, _From, State) ->
+  print_warning("~s", [Message], State),
+  {reply, ok, State};
+
 %% unknown calls
 handle_call(_Request, _From, State) ->
   {reply, {error, unknown_call}, State}.
@@ -299,6 +339,11 @@ code_change(_OldVsn, State, _Extra) ->
 %% }}}
 %%----------------------------------------------------------
 
+%%----------------------------------------------------------
+%% helper functions
+%%----------------------------------------------------------
+%% printing messages {{{
+
 %% @doc Format term for printing to screen.
 
 -spec format(term()) ->
@@ -308,7 +353,7 @@ format(Term) ->
   % no term should weigh 1MB
   io_lib:print(Term, 1, 1024 * 1024, -1).
 
-%% @doc Print message to screen.
+%% @doc Print text to screen.
 %%   The message doesn't need to end with NL character.
 
 -spec print(string(), [term()], #state{}) ->
@@ -316,12 +361,40 @@ format(Term) ->
 
 print(Format, Args, _State = #state{level = Level}) ->
   Indent = ["    " || _ <- lists:seq(1, Level)],
+  print(standard_io, Indent, Format, Args).
+
+%% @doc Print informational message to screen.
+
+-spec print_info(string(), [term()], #state{}) ->
+  ok.
+
+print_info(Format, Args, _State = #state{level = Level}) ->
+  Indent = ["    # " || _ <- lists:seq(1, Level)],
+  print(standard_io, Indent, Format, Args).
+
+%% @doc Print diagnostic (warning) message to screen.
+
+-spec print_warning(string(), [term()], #state{}) ->
+  ok.
+
+print_warning(Format, Args, _State = #state{level = Level}) ->
+  Indent = ["    # " || _ <- lists:seq(1, Level)],
+  print(standard_error, Indent, Format, Args).
+
+%% @doc Print message to specified IO device, each line indented.
+
+-spec print(io:device(), iolist(), string(), [term()]) ->
+  ok.
+
+print(Output, Indent, Format, Args) ->
   Text = iolist_to_binary(io_lib:format(Format, Args)),
   Lines = binary:split(Text, <<"\n">>, [global, trim]),
-  [io:put_chars([Indent, L, "\n"]) || L <- Lines],
+  [io:put_chars(Output, [Indent, L, "\n"]) || L <- Lines],
   ok.
 
+%% }}}
 %%----------------------------------------------------------
+%% `#counter{}' handling {{{
 
 %% @doc Add 1 to skipped tests counter.
 
@@ -365,6 +438,7 @@ add_todo({died, _} = _Result,
          Counters = #counters{tests = T, todo_failures = N}) ->
   _NewCounters = Counters#counters{tests = T + 1, todo_failures = N + 1}.
 
+%% }}}
 %%----------------------------------------------------------
 
 %%%---------------------------------------------------------------------------