File 0268-eunit-Allow-test-cases-to-retrieve-output-captured-b.patch of Package erlang
From d332b4565d675ab76589e6569684d29d5dd70653 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Viktor=20S=C3=B6derqvist?= <viktor@zuiderkwast.se>
Date: Sat, 19 Oct 2019 16:23:57 +0200
Subject: [PATCH] eunit: Allow test cases to retrieve output captured by EUnit
To be able to test programs or functions producing output on
standard output and to verify this output in an EUnit test
case, a new macro ?capturedOutput is defined in eunit.hrl.
---
lib/eunit/doc/overview.edoc | 20 ++++++++++++++++++++
lib/eunit/include/eunit.hrl | 10 ++++++++++
lib/eunit/src/eunit_proc.erl | 22 +++++++++++++++++++++-
lib/eunit/src/eunit_tests.erl | 7 +++++++
4 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc
index dc9f858812..8ab89fca73 100644
--- a/lib/eunit/doc/overview.edoc
+++ b/lib/eunit/doc/overview.edoc
@@ -277,6 +277,9 @@ while testing, you can write to the `user' output stream, as in
`io:format(user, "~w", [Term])'. The recommended way of doing this is to
use the EUnit {@section Debugging macros}, which make it much simpler.
+For checking the output produced by the unit under test, see
+{@section Macros for checking output}.
+
=== Writing test generating functions ===
A drawback of simple test functions is that you must write a separate
@@ -415,6 +418,7 @@ your code is compiled with testing enabled or disabled.
<li>{@section Compilation control macros}</li>
<li>{@section Utility macros}</li>
<li>{@section Assert macros}</li>
+<li>{@section Macros for checking output}</li>
<li>{@section Macros for running external commands}</li>
<li>{@section Debugging macros}</li>
</ul>
@@ -608,6 +612,22 @@ Examples:
</dd>
</dl>
+=== Macros for checking output ===
+
+The following macro can be used within a test case to retreive the
+output written to standard output.
+
+<dl>
+<dt>`capturedOutput'</dt>
+<dd>The output captured by EUnit in the current test case, as a string.
+
+Examples:
+
+```io:format("Hello~n"),
+ ?assertEqual("Hello\n", ?capturedOutput)'''
+</dd>
+</dl>
+
=== Macros for running external commands ===
Keep in mind that external commands are highly dependent on the
diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl
index 3cc36a27bc..6842147fda 100644
--- a/lib/eunit/include/eunit.hrl
+++ b/lib/eunit/include/eunit.hrl
@@ -147,6 +147,16 @@
-define(_assertNotException(Class, Term, Expr),
?_test(?assertNotException(Class, Term, Expr))).
+%% Macros for retrieving the output of a test case
+
+-ifndef(capturedOutput).
+-define(capturedOutput,
+ case ?UNDER_EUNIT of
+ true -> eunit_proc:get_output();
+ false -> ""
+ end).
+-endif.
+
%% Macros for running operating system commands. (Note that these
%% require EUnit to be present at runtime, or at least eunit_lib.)
diff --git a/lib/eunit/src/eunit_proc.erl b/lib/eunit/src/eunit_proc.erl
index 6e702543d0..fb6619a6d4 100644
--- a/lib/eunit/src/eunit_proc.erl
+++ b/lib/eunit/src/eunit_proc.erl
@@ -29,7 +29,7 @@
-include("eunit.hrl").
-include("eunit_internal.hrl").
--export([start/4]).
+-export([start/4, get_output/0]).
%% This must be exported; see new_group_leader/1 for details.
-export([group_leader_process/1]).
@@ -52,6 +52,18 @@ start(Tests, Order, Super, Reference)
order = Order},
spawn_group(local, #group{tests = Tests}, St).
+%% Fetches the output captured by the eunit group leader. This is
+%% provided to allow test cases to check the captured output.
+
+-spec get_output() -> string().
+get_output() ->
+ group_leader() ! {get_output, self()},
+ receive
+ {output, Output} -> Output
+ after 100 ->
+ %% The group leader is not an eunit_proc
+ abort_task(get_output)
+ end.
%% Status messages sent to the supervisor process. (A supervisor does
%% not have to act on these messages - it can e.g. just log them, or
@@ -594,6 +606,9 @@ group_leader_loop(Runner, Wait, Buf) ->
receive after 2 -> ok end,
process_flag(priority, low),
group_leader_loop(Runner, 0, Buf);
+ {get_output, From} ->
+ From ! {output, lists:flatten(lists:reverse(Buf))},
+ group_leader_loop(Runner, Wait, Buf);
_ ->
%% discard any other messages
group_leader_loop(Runner, Wait, Buf)
@@ -669,4 +684,9 @@ io_error_test_() ->
[?_assertMatch({error, enotsup}, io:getopts()),
?_assertMatch({error, enotsup}, io:columns()),
?_assertMatch({error, enotsup}, io:rows())].
+
+get_output_test() ->
+ io:format("Hello"),
+ Output = get_output(),
+ ?assertEqual("Hello", Output).
-endif.
diff --git a/lib/eunit/src/eunit_tests.erl b/lib/eunit/src/eunit_tests.erl
index 07a415eeb1..f43f4cca09 100644
--- a/lib/eunit/src/eunit_tests.erl
+++ b/lib/eunit/src/eunit_tests.erl
@@ -45,3 +45,10 @@ if_test_() ->
matches_test_() ->
[?_assert(?MATCHES("hel"++_, "hello")),
?_assertNot(?MATCHES("hal"++_, "hello"))].
+
+get_output_test() ->
+ io:format(<<"Hello ~p!~n">>, [eunit]),
+ ?assertEqual("Hello eunit!\n", ?capturedOutput),
+ io:format("System working?~n~s~n", ["Seems to be."]),
+ ?assertEqual("Hello eunit!\nSystem working?\nSeems to be.\n",
+ ?capturedOutput).
--
2.16.4