Skip to content

Commit a0a0694

Browse files
author
José Valim
committed
Merge pull request #1030 from ericmj/report-setup-all-error
Report setup_all errors and mark tests as invalid
2 parents b47bae9 + 993c28a commit a0a0694

File tree

3 files changed

+115
-26
lines changed

3 files changed

+115
-26
lines changed

lib/ex_unit/lib/ex_unit.ex

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
defmodule ExUnit do
2-
defrecord Test, [:name, :case, :failure] do
2+
defrecord Test, [:name, :case, :failure, :invalid] do
33
@moduledoc """
44
A record that keeps information about the test.
55
It is received by formatters and also accessible
66
in the metadata under the key `:test`.
77
"""
88
end
99

10+
defrecord TestCase, [:name, :failure] do
11+
@moduledoc """
12+
A record that keeps information about the test case.
13+
It is received by formatters and also accessible
14+
in the metadata under the key `:case`.
15+
"""
16+
end
17+
1018
@moduledoc """
1119
Basic unit test structure for Elixir.
1220

lib/ex_unit/lib/ex_unit/cli_formatter.ex

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ defmodule ExUnit.CLIFormatter do
99
use GenServer.Behaviour
1010

1111
import Exception, only: [format_entry: 2]
12-
defrecord Config, counter: 0, failures: []
12+
defrecord Config, counter: 0, test_failures: [], case_failures: []
1313

1414
## Behaviour
1515

@@ -26,8 +26,8 @@ defmodule ExUnit.CLIFormatter do
2626
:ok
2727
end
2828

29-
def case_finished(_id, _test_case) do
30-
:ok
29+
def case_finished(id, test_case) do
30+
:gen_server.cast(id, { :case_finished, test_case })
3131
end
3232

3333
def test_started(_id, _test) do
@@ -45,14 +45,20 @@ defmodule ExUnit.CLIFormatter do
4545
end
4646

4747
def handle_call({ :suite_finished, ms }, _from, config) do
48-
print_suite(config.counter, config.failures, ms)
49-
{ :stop, :normal, length(config.failures), config }
48+
print_suite(config.counter, config.test_failures, config.case_failures, ms)
49+
{ :stop, :normal, length(config.test_failures), config }
5050
end
5151

5252
def handle_call(_, _, _) do
5353
super
5454
end
5555

56+
def handle_cast({ :test_finished, test = ExUnit.Test[failure: nil, invalid: true] }, config) do
57+
IO.write invalid("?")
58+
{ :noreply, config.update_counter(&1 + 1).
59+
update_test_failures([test|&1]) }
60+
end
61+
5662
def handle_cast({ :test_finished, ExUnit.Test[failure: nil] }, config) do
5763
IO.write success(".")
5864
{ :noreply, config.update_counter(&1 + 1) }
@@ -61,30 +67,61 @@ defmodule ExUnit.CLIFormatter do
6167
def handle_cast({ :test_finished, test }, config) do
6268
IO.write failure("F")
6369
{ :noreply, config.update_counter(&1 + 1).
64-
update_failures([test|&1]) }
70+
update_test_failures([test|&1]) }
71+
end
72+
73+
def handle_cast({ :case_finished, test_case }, config) do
74+
if test_case.failure do
75+
{ :noreply, config.update_case_failures([test_case|&1]) }
76+
else
77+
{ :noreply, config }
78+
end
6579
end
6680

6781
def handle_cast(_, _) do
6882
super
6983
end
7084

71-
defp print_suite(counter, [], ms) do
85+
defp print_suite(counter, [], [], ms) do
7286
IO.write "\n\n"
7387
IO.puts "Finished in #{format_ms ms} seconds"
7488
IO.puts success("#{counter} tests, 0 failures")
7589
end
7690

77-
defp print_suite(counter, failures, ms) do
91+
defp print_suite(counter, test_failures, case_failures, ms) do
7892
IO.write "\n\nFailures:\n\n"
79-
Enum.reduce Enum.reverse(failures), 1, print_failure(&1, &2, File.cwd!)
93+
num_fails = Enum.reduce Enum.reverse(test_failures), 1, print_test_failure(&1, &2, File.cwd!)
94+
Enum.reduce Enum.reverse(case_failures), num_fails, print_case_failure(&1, &2, File.cwd!)
95+
num_invalids = Enum.count test_failures, fn test -> test.invalid end
96+
8097
IO.puts "Finished in #{format_ms ms} seconds"
81-
IO.puts failure("#{counter} tests, #{length(failures)} failures")
98+
99+
num_fails = num_fails - 1
100+
message = "#{counter} tests, #{num_fails} failures"
101+
if num_invalids > 0, do: message = message <> ", #{num_invalids} invalid"
102+
cond do
103+
num_fails > 0 -> IO.puts failure(message)
104+
num_invalids > 0 -> IO.puts invalid(message)
105+
true -> IO.puts success(message)
106+
end
107+
end
108+
109+
defp print_test_failure(ExUnit.Test[failure: nil], acc, _cwd) do
110+
acc
111+
end
112+
113+
defp print_test_failure(ExUnit.Test[case: test_case, name: test, failure: { kind, reason, stacktrace }], acc, cwd) do
114+
IO.puts " #{acc}) #{test} (#{inspect test_case.name})"
115+
print_kind_reason(kind, reason)
116+
print_stacktrace(stacktrace, test_case.name, test, cwd)
117+
IO.write "\n"
118+
acc + 1
82119
end
83120

84-
defp print_failure(ExUnit.Test[case: test_case, name: test, failure: { kind, reason, stacktrace }], acc, cwd) do
85-
IO.puts " #{acc}) #{test} (#{inspect test_case})"
121+
defp print_case_failure(ExUnit.TestCase[name: case_name, failure: { kind, reason, stacktrace }], acc, cwd) do
122+
IO.puts " #{acc}) #{inspect case_name}"
86123
print_kind_reason(kind, reason)
87-
print_stacktrace(stacktrace, test_case, test, cwd)
124+
print_stacktrace(stacktrace, case_name, nil, cwd)
88125
IO.write "\n"
89126
acc + 1
90127
end
@@ -164,6 +201,10 @@ defmodule ExUnit.CLIFormatter do
164201
IO.ANSI.escape("%{green}" <> msg)
165202
end
166203

204+
defp invalid(msg) do
205+
IO.ANSI.escape("%{yellow}" <> msg)
206+
end
207+
167208
defp failure(msg) do
168209
IO.ANSI.escape("%{red}" <> msg)
169210
end
@@ -179,4 +220,4 @@ defmodule ExUnit.CLIFormatter do
179220
defp stacktrace_info(msg) do
180221
" " <> msg
181222
end
182-
end
223+
end

lib/ex_unit/lib/ex_unit/runner.ex

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,31 +71,71 @@ defmodule ExUnit.Runner do
7171
end
7272
end
7373

74-
defp run_tests(config, pid, test_case) do
74+
defp run_tests(config, pid, case_name) do
75+
test_case = ExUnit.TestCase[name: case_name]
7576
config.formatter.case_started(config.formatter_id, test_case)
7677

77-
try do
78-
tests = tests_for(test_case)
79-
context = test_case.__exunit__(:setup_all, [case: test_case])
80-
Enum.each tests, run_test(config, pid, test_case, &1, context)
81-
test_case.__exunit__(:teardown_all, context)
82-
after
83-
pid <- { self, :case_finished, test_case }
78+
self_pid = self
79+
{ case_pid, case_ref } = Process.spawn_monitor fn ->
80+
{ test_case, context } = try do
81+
context = case_name.__exunit__(:setup_all, [case: test_case])
82+
{ test_case, context }
83+
rescue
84+
error ->
85+
{ test_case.failure({ :error, error, filtered_stacktrace }), nil }
86+
catch
87+
kind, error ->
88+
{ test_case.failure({ kind, error, filtered_stacktrace }), nil }
89+
end
90+
91+
tests = tests_for(case_name)
92+
if test_case.failure do
93+
Enum.each tests, fn test_name ->
94+
test = ExUnit.Test[name: test_name, case: test_case, invalid: true]
95+
pid <- { self, :test_finished, test }
96+
end
97+
self_pid <- { self, :case_finished, test_case }
98+
99+
else
100+
Enum.each tests, run_test(config, pid, test_case, &1, context)
101+
102+
test_case = try do
103+
case_name.__exunit__(:teardown_all, context)
104+
test_case
105+
rescue
106+
error ->
107+
test_case.failure { :error, error, filtered_stacktrace }
108+
catch
109+
kind, error ->
110+
test_case.failure { kind, error, filtered_stacktrace }
111+
end
112+
113+
self_pid <- { self, :case_finished, test_case }
114+
end
115+
end
116+
117+
receive do
118+
{ ^case_pid, :case_finished, test_case } ->
119+
pid <- { case_pid, :case_finished, test_case }
120+
{ :DOWN, ^case_ref, :process, ^case_pid, { error, stacktrace } } ->
121+
test_case = test_case.failure { :EXIT, error, filter_stacktrace(stacktrace) }
122+
pid <- { case_pid, :case_finished, test_case }
84123
end
85124
end
86125

87126
defp run_test(config, pid, test_case, test_name, context) do
88127
test = ExUnit.Test[name: test_name, case: test_case]
128+
ExUnit.TestCase[name: case_name] = test_case
89129
config.formatter.test_started(config.formatter_id, test)
90130

91131
# Run test in a new process so that we can trap exits for a single test
92132
self_pid = self
93133
{ test_pid, test_ref } = Process.spawn_monitor fn ->
94134
test = try do
95-
context = test_case.__exunit__(:setup, Keyword.put(context, :test, test))
135+
context = case_name.__exunit__(:setup, Keyword.put(context, :test, test))
96136

97137
test = try do
98-
apply test_case, test_name, [context]
138+
apply case_name, test_name, [context]
99139
test
100140
rescue
101141
error1 ->
@@ -105,7 +145,7 @@ defmodule ExUnit.Runner do
105145
test.failure { kind1, error1, filtered_stacktrace }
106146
end
107147

108-
test_case.__exunit__(:teardown, Keyword.put(context, :test, test))
148+
case_name.__exunit__(:teardown, Keyword.put(context, :test, test))
109149
test
110150
rescue
111151
error2 ->

0 commit comments

Comments
 (0)