Added support for top-level info and diagnostic messages.
authorStanislaw Klekot <dozzie@jarowit.net>
Thu, 18 Jun 2015 16:26:12 +0000 (18:26 +0200)
committerStanislaw Klekot <dozzie@jarowit.net>
Thu, 18 Jun 2015 16:26:12 +0000 (18:26 +0200)
src/estap.erl
src/estap_server.erl
src/estap_test.erl

index 94e9578..6727ba7 100644 (file)
@@ -248,6 +248,10 @@ test_dir(Subdir) ->
 %%   Typically, diagnostic message is a warning, but may be notice important
 %%   enough to print it along with test progress by TAP consumer.
 %%
+%%   Before first call to {@link plan/1}, {@link no_plan/0} or test functions
+%%   ({@link ok/2}, {@link is/3} etc.) message is printed at the level of
+%%   parent test. After any of those, it's printed at sub-test level.
+%%
 %%   Normally diagnostic output goes to <i>STDERR</i>, but under TODO tests it
 %%   goes to <i>STDOUT</i>.
 %%
@@ -257,13 +261,17 @@ test_dir(Subdir) ->
   ok.
 
 diag(Message) ->
-  TestRun = get_test_run(),
+  TestRun = get_test_run_or_parent(),
   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.
 %%
+%%   Before first call to {@link plan/1}, {@link no_plan/0} or test functions
+%%   ({@link ok/2}, {@link is/3} etc.) message is printed at the level of
+%%   parent test. After any of those, it's printed at sub-test level.
+%%
 %%   Normally diagnostic output goes to <i>STDERR</i>, but under TODO tests it
 %%   goes to <i>STDOUT</i>.
 %%
@@ -273,26 +281,34 @@ diag(Message) ->
   ok.
 
 diag(Message, Info) ->
-  TestRun = get_test_run(),
+  TestRun = get_test_run_or_parent(),
   InfoLines = [["  ", format_info(I), "\n"] || I <- Info],
   estap_server:warning(TestRun, [Message, "\n", InfoLines]).
 
 %% @doc Print a message.
+%%
+%%   Before first call to {@link plan/1}, {@link no_plan/0} or test functions
+%%   ({@link ok/2}, {@link is/3} etc.) message is printed at the level of
+%%   parent test. After any of those, it's printed at sub-test level.
 
 -spec info(message()) ->
   ok.
 
 info(Message) ->
-  TestRun = get_test_run(),
+  TestRun = get_test_run_or_parent(),
   estap_server:info(TestRun, Message).
 
 %% @doc Print a message with some context.
+%%
+%%   Before first call to {@link plan/1}, {@link no_plan/0} or test functions
+%%   ({@link ok/2}, {@link is/3} etc.) message is printed at the level of
+%%   parent test. After any of those, it's printed at sub-test level.
 
 -spec info(message(), [info()]) ->
   ok.
 
 info(Message, Info) ->
-  TestRun = get_test_run(),
+  TestRun = get_test_run_or_parent(),
   InfoLines = [["  ", format_info(I), "\n"] || I <- Info],
   estap_server:info(TestRun, [Message, "\n", InfoLines]).
 
@@ -340,5 +356,17 @@ get_test_run() ->
       TestRun
   end.
 
+%% @doc Get associated {@link estap_server} or parent one if none is started
+%%   yet. Necessary for top-level {@link info/1} and {@link diag/1} to work.
+
+get_test_run_or_parent() ->
+  case get(estap_server) of
+    undefined ->
+      % XXX: this must be set in `estap_test:run()'
+      get(estap_server_parent);
+    TestRun when is_pid(TestRun) ->
+      TestRun
+  end.
+
 %%%---------------------------------------------------------------------------
 %%% vim:ft=erlang:foldmethod=marker
index a78ad17..ff46bbb 100644 (file)
@@ -369,7 +369,10 @@ print(Format, Args, _State = #state{level = Level}) ->
   ok.
 
 print_info(Format, Args, _State = #state{level = Level}) ->
-  Indent = ["    # " || _ <- lists:seq(1, Level)],
+  Indent = case Level > 0 of
+    true -> ["    # " || _ <- lists:seq(1, Level)];
+    false -> "# "
+  end,
   print(standard_io, Indent, Format, Args).
 
 %% @doc Print diagnostic (warning) message to screen.
@@ -378,7 +381,10 @@ print_info(Format, Args, _State = #state{level = Level}) ->
   ok.
 
 print_warning(Format, Args, _State = #state{level = Level}) ->
-  Indent = ["    # " || _ <- lists:seq(1, Level)],
+  Indent = case Level > 0 of
+    true -> ["    # " || _ <- lists:seq(1, Level)];
+    false -> "# "
+  end,
   print(standard_error, Indent, Format, Args).
 
 %% @doc Print message to specified IO device, each line indented.
index 254cb95..5d84394 100644 (file)
@@ -11,7 +11,7 @@
 -export([success_or_failure/1]).
 
 %% private interface
--export([call/4]).
+-export([call/5]).
 
 -export_type([test/0, test_plan/0]).
 
@@ -56,10 +56,10 @@ run_tests(TestRun, [{TestFunSpec, Description, Status} | Rest] = _Tests) ->
   estap_server:running(TestRun, Description),
   case Status of
     run ->
-      Result = test(TestFunSpec),
+      Result = test(TestRun, TestFunSpec),
       estap_server:report_result(TestRun, Result);
     {todo, Why} ->
-      Result = test(TestFunSpec),
+      Result = test(TestRun, TestFunSpec),
       estap_server:report_result_todo(TestRun, Why, Result);
     {skip, Why} ->
       estap_server:report_skipped(TestRun, Why)
@@ -68,17 +68,18 @@ run_tests(TestRun, [{TestFunSpec, Description, Status} | Rest] = _Tests) ->
 
 %% @doc Run a single test function, according to its specification.
 
--spec test({Module :: module(), Function :: atom()}) ->
+-spec test(estap_server:test_run_id(),
+           {Module :: module(), Function :: atom()}) ->
     {success, term()}
   | {failure, term()}
   | {dubious, term()}
   | {died, term()}.
 
-test({Mod, Func} = _TestFunSpec) ->
+test(TestRun, {Mod, Func} = _TestFunSpec) ->
   Args = [],
   ResultRef = make_ref(),
   ResultTo = {self(), ResultRef},
-  {Pid, MonRef} = spawn_monitor(?MODULE, call, [ResultTo, Mod, Func, Args]),
+  {Pid, MonRef} = spawn_monitor(?MODULE, call, [ResultTo, TestRun, Mod, Func, Args]),
   receive
     {result, ResultRef, TestResult} ->
       erlang:demonitor(MonRef, [flush]),
@@ -91,10 +92,13 @@ test({Mod, Func} = _TestFunSpec) ->
 %% @doc Run the specified function, collect its result (possibly thrown) and
 %%   report it back to `ResultTo'.
 
--spec call({pid(), term()}, module(), atom(), [term()]) ->
+-spec call({pid(), term()}, estap_server:test_run_id(),
+           module(), atom(), [term()]) ->
   ok.
 
-call({Pid, Ref} = _ResultTo, Mod, Fun, Args) ->
+call({Pid, Ref} = _ResultTo, TestRun, Mod, Fun, Args) ->
+  % XXX: for `estap:info()' and `estap:diag()' to work with no sub-tests
+  put(estap_server_parent, TestRun),
   % XXX: putting `test_dir' to proc dict is an important thing for
   % `estap:test_dir()' function
   ModuleAttrs = Mod:module_info(attributes),