Skip to content

Commit 0a51c21

Browse files
committed
Optimize ExUnit runner by short-circuiting logic and merging list passes
1 parent 7b9e907 commit 0a51c21

File tree

2 files changed

+34
-26
lines changed

2 files changed

+34
-26
lines changed

lib/ex_unit/lib/ex_unit/filters.ex

+23-18
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
defmodule ExUnit.Filters do
2-
alias ExUnit.FailuresManifest
3-
42
@moduledoc """
53
Conveniences for parsing and evaluating filters.
64
"""
5+
alias ExUnit.FailuresManifest
76

87
@type t :: list({atom, Regex.t() | String.Chars.t()} | atom)
98
@type location :: {:location, {String.t(), pos_integer | [pos_integer, ...]}}
@@ -195,26 +194,32 @@ defmodule ExUnit.Filters do
195194
@spec eval(t, t, map, [ExUnit.Test.t()]) ::
196195
:ok | {:excluded, String.t()} | {:skipped, String.t()}
197196
def eval(include, exclude, tags, collection) when is_map(tags) do
198-
excluded = Enum.find_value(exclude, &has_tag(&1, tags, collection))
199-
excluded? = excluded != nil
200-
included? = Enum.any?(include, &has_tag(&1, tags, collection))
197+
cond do
198+
Enum.any?(include, &has_tag(&1, tags, collection)) ->
199+
maybe_skipped(include, tags, collection)
200+
201+
excluded = Enum.find_value(exclude, &has_tag(&1, tags, collection)) ->
202+
{:excluded, "due to #{excluded} filter"}
201203

202-
if included? or not excluded? do
203-
skip_tag = %{skip: Map.get(tags, :skip, true)}
204-
skip_included_explicitly? = Enum.any?(include, &has_tag(&1, skip_tag, collection))
204+
true ->
205+
maybe_skipped(include, tags, collection)
206+
end
207+
end
205208

206-
case Map.fetch(tags, :skip) do
207-
{:ok, msg} when is_binary(msg) and not skip_included_explicitly? ->
208-
{:skipped, msg}
209+
defp maybe_skipped(include, tags, collection) do
210+
case tags do
211+
%{skip: skip} when is_binary(skip) or skip == true ->
212+
skip_tags = %{skip: skip}
213+
skip_included_explicitly? = Enum.any?(include, &has_tag(&1, skip_tags, collection))
209214

210-
{:ok, true} when not skip_included_explicitly? ->
211-
{:skipped, "due to skip tag"}
215+
cond do
216+
skip_included_explicitly? -> :ok
217+
is_binary(skip) -> {:skipped, skip}
218+
skip -> {:skipped, "due to skip tag"}
219+
end
212220

213-
_ ->
214-
:ok
215-
end
216-
else
217-
{:excluded, "due to #{excluded} filter"}
221+
_ ->
222+
:ok
218223
end
219224
end
220225

lib/ex_unit/lib/ex_unit/runner.ex

+11-8
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,7 @@ defmodule ExUnit.Runner do
216216
EM.module_started(config.manager, test_module)
217217

218218
# Prepare tests, selecting which ones should be run or skipped
219-
tests = prepare_tests(config, test_module.tests)
220-
{excluded_and_skipped_tests, to_run_tests} = Enum.split_with(tests, & &1.state)
219+
{to_run_tests, excluded_and_skipped_tests} = prepare_tests(config, test_module.tests)
221220

222221
for excluded_or_skipped_test <- excluded_and_skipped_tests do
223222
EM.test_started(config.manager, excluded_or_skipped_test)
@@ -257,14 +256,18 @@ defmodule ExUnit.Runner do
257256
exclude = config.exclude
258257
test_ids = config.only_test_ids
259258

260-
for test <- tests, include_test?(test_ids, test) do
261-
tags = Map.merge(test.tags, %{test: test.name, module: test.module})
259+
{to_run, to_skip} =
260+
for test <- tests, include_test?(test_ids, test), reduce: {[], []} do
261+
{to_run, to_skip} ->
262+
tags = Map.merge(test.tags, %{test: test.name, module: test.module})
262263

263-
case ExUnit.Filters.eval(include, exclude, tags, tests) do
264-
:ok -> %{test | tags: tags}
265-
excluded_or_skipped -> %{test | state: excluded_or_skipped}
264+
case ExUnit.Filters.eval(include, exclude, tags, tests) do
265+
:ok -> {[%{test | tags: tags} | to_run], to_skip}
266+
excluded_or_skipped -> {to_run, [%{test | state: excluded_or_skipped} | to_skip]}
267+
end
266268
end
267-
end
269+
270+
{Enum.reverse(to_run), Enum.reverse(to_skip)}
268271
end
269272

270273
defp include_test?(test_ids, test) do

0 commit comments

Comments
 (0)