Skip to content

Commit f0456b6

Browse files
committed
Refactor filter evaluation
Thanks for the help @josevalim and @christhekeele
1 parent d4729a3 commit f0456b6

File tree

2 files changed

+27
-24
lines changed

2 files changed

+27
-24
lines changed

lib/ex_unit/lib/ex_unit/runner.ex

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ defmodule ExUnit.Runner do
128128
defp run_test(config, test, context) do
129129
config.formatter.test_started(config.formatter_id, test)
130130

131-
filters = combine_filters(config.include, config.exclude)
131+
filters = combine_filters([include: config.include, exclude: config.exclude])
132132
result = evaluate_filters(filters, test.tags)
133133

134134
test = case result do
@@ -200,34 +200,39 @@ defmodule ExUnit.Runner do
200200
end
201201

202202
def evaluate_filters(filters, tags) do
203-
results = Enum.flat_map tags, fn tag ->
204-
Enum.map filters, fn filter ->
205-
{ { elem(filter, 0), elem(tag, 0) }, evaluate_filter(filter, tag) }
206-
end
203+
Enum.find_value tags, :ok, fn { tag_key, _ } = tag ->
204+
unless tag_accepted?(filters, tag), do: { :error, tag_key }
207205
end
206+
end
208207

209-
results = Enum.reduce results, HashDict.new, fn { key, evaluation }, dict ->
210-
Dict.update dict, key, evaluation, &(evaluation || &1)
211-
end
208+
defp tag_accepted?([include: include, exclude: exclude], tag) do
209+
tag_included?(include, tag) and not tag_excluded?(exclude, tag)
210+
end
212211

213-
mismatch = Enum.find Dict.to_list(results), &match?({ _, false }, &1)
212+
defp tag_included?(include, { tag_key, tag_value }) do
213+
case Dict.fetch(include, tag_key) do
214+
{ :ok, allowed } -> tag_value in allowed
215+
:error -> true
216+
end
217+
end
214218

215-
case mismatch do
216-
{ { _, tag }, _ } -> { :error, tag }
217-
_ -> :ok
219+
defp tag_excluded?(exclude, { tag_key, tag_value }) do
220+
case Dict.fetch(exclude, tag_key) do
221+
{ :ok, forbidden } -> tag_value in forbidden
222+
:error -> false
218223
end
219224
end
220225

221-
def evaluate_filter({ tag, value, :include }, { tag, value }), do: true
222-
def evaluate_filter({ tag, value, :exclude }, { tag, value }), do: false
223-
def evaluate_filter({ tag, _, :include }, { tag, _ }), do: false
224-
def evaluate_filter({ tag, _, :exclude }, { tag, _ }), do: true
225-
def evaluate_filter(_, _), do: true
226+
defp combine_filters([include: include, exclude: exclude]) do
227+
include = group_by_key(include)
228+
exclude = group_by_key(exclude)
229+
[include: include, exclude: exclude]
230+
end
226231

227-
defp combine_filters(include, exclude) do
228-
include = Enum.map(include, fn { tag, value } -> { tag, value, :include } end)
229-
exclude = Enum.map(exclude, fn { tag, value } -> { tag, value, :exclude } end)
230-
Enum.concat(include, exclude)
232+
defp group_by_key(dict) do
233+
Enum.reduce dict, HashDict.new, fn { key, value }, acc ->
234+
Dict.update acc, key, [value], &[value|&1]
235+
end
231236
end
232237

233238
defp pruned_stacktrace, do: prune_stacktrace(System.stacktrace)

lib/ex_unit/test/ex_unit/runner_test.exs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ defmodule ExUnit.RunnerTest do
44
use ExUnit.Case, async: true
55

66
test "filters with matching tags are ored and non-matching tags are anded" do
7-
filters = [ { :os, :unix, :include },
8-
{ :os, :win32, :include },
9-
{ :type, :unit, :include } ]
7+
filters = [include: [os: [:unix, :win32], type: [:unit]], exclude: []]
108

119
assert :ok = ExUnit.Runner.evaluate_filters(filters, [os: :unix])
1210
assert :ok = ExUnit.Runner.evaluate_filters(filters, [os: :unix, type: :unit])

0 commit comments

Comments
 (0)