Skip to content

Commit 87dd05e

Browse files
committed
Preserve files with no line filter on mix test
Before this patch, if you invoked: mix test test/foo_test.exs:13 test/bar_test.exs We would include a location filter only for foo_test.exs and no tests in bar_test.exs would run. We now ensure that the full location of files with line filters are included as tags, as long as any file is included. Closes #14445.
1 parent 075b8ca commit 87dd05e

File tree

2 files changed

+63
-15
lines changed

2 files changed

+63
-15
lines changed

lib/ex_unit/lib/ex_unit/filters.ex

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,33 +33,32 @@ defmodule ExUnit.Filters do
3333
"""
3434
@spec parse_paths([String.t()]) :: {[String.t()], ex_unit_opts}
3535
def parse_paths(file_paths) do
36-
{parsed_paths, locations} =
37-
Enum.map_reduce(file_paths, [], fn file_path, locations ->
38-
case extract_line_numbers(file_path) do
39-
{path, []} -> {path, locations}
40-
{path, lines} -> {path, [{:location, {path, lines}} | locations]}
41-
end
36+
{parsed_paths, {lines?, locations}} =
37+
Enum.map_reduce(file_paths, {false, []}, fn file_path, {lines?, locations} ->
38+
{path, location} = extract_location(file_path)
39+
{path, {lines? or is_tuple(location), [{:location, location} | locations]}}
4240
end)
4341

4442
ex_unit_opts =
45-
if locations == [], do: [], else: [exclude: [:test], include: Enum.reverse(locations)]
43+
if lines?, do: [exclude: [:test], include: Enum.reverse(locations)], else: []
4644

4745
{parsed_paths, ex_unit_opts}
4846
end
4947

50-
defp extract_line_numbers(file_path) do
48+
defp extract_location(file_path) do
5149
case Path.relative_to_cwd(file_path) |> String.split(":") do
5250
[path] ->
53-
{path, []}
51+
{path, path}
5452

5553
[path | parts] ->
5654
{path_parts, line_numbers} = Enum.split_while(parts, &(to_line_number(&1) == nil))
5755
path = Enum.join([path | path_parts], ":") |> Path.split() |> Path.join()
5856
lines = for n <- line_numbers, valid_number = validate_line_number(n), do: valid_number
5957

6058
case lines do
61-
[line] -> {path, line}
62-
lines -> {path, lines}
59+
[] -> {path, path}
60+
[line] -> {path, {path, line}}
61+
lines -> {path, {path, lines}}
6362
end
6463
end
6564
end
@@ -145,8 +144,12 @@ defmodule ExUnit.Filters do
145144
end)
146145
end
147146

148-
defp parse_kv(:line, line) when is_binary(line), do: {:line, String.to_integer(line)}
149-
defp parse_kv(:location, loc) when is_binary(loc), do: {:location, extract_line_numbers(loc)}
147+
defp parse_kv(:line, line) when is_binary(line),
148+
do: {:line, String.to_integer(line)}
149+
150+
defp parse_kv(:location, loc) when is_binary(loc),
151+
do: {:location, extract_location(loc) |> elem(1)}
152+
150153
defp parse_kv(key, value), do: {key, value}
151154

152155
@doc """
@@ -240,7 +243,12 @@ defmodule ExUnit.Filters do
240243
end
241244
end
242245

243-
defp has_tag({:location, {path, lines}}, %{line: _, describe_line: _} = tags, collection) do
246+
defp has_tag({:location, path}, %{file: file}, _collection) when is_binary(path) do
247+
String.ends_with?(file, path)
248+
end
249+
250+
defp has_tag({:location, {path, lines}}, %{line: _, describe_line: _} = tags, collection)
251+
when is_binary(path) do
244252
String.ends_with?(tags.file, path) and
245253
lines |> List.wrap() |> Enum.any?(&has_tag({:line, &1}, tags, collection))
246254
end

lib/ex_unit/test/ex_unit/filters_test.exs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,48 @@ defmodule ExUnit.FiltersTest do
188188
{:excluded, "due to line filter"}
189189
end
190190

191+
test "evaluating filter uses special rules for location" do
192+
tests = [
193+
%ExUnit.Test{tags: %{line: 3, describe_line: 2}},
194+
%ExUnit.Test{tags: %{line: 5, describe_line: nil}}
195+
]
196+
197+
assert ExUnit.Filters.eval(
198+
[location: "foo_test.exs"],
199+
[:line],
200+
%{line: 3, describe_line: 2, file: "foo_test.exs"},
201+
tests
202+
) == :ok
203+
204+
assert ExUnit.Filters.eval(
205+
[location: "bar_test.exs"],
206+
[:line],
207+
%{line: 3, describe_line: 2, file: "foo_test.exs"},
208+
tests
209+
) == {:excluded, "due to line filter"}
210+
211+
assert ExUnit.Filters.eval(
212+
[location: {"foo_test.exs", 3}],
213+
[:line],
214+
%{line: 3, describe_line: 2, file: "foo_test.exs"},
215+
tests
216+
) == :ok
217+
218+
assert ExUnit.Filters.eval(
219+
[location: {"bar_test.exs", 3}],
220+
[:line],
221+
%{line: 3, describe_line: 2, file: "foo_test.exs"},
222+
tests
223+
) == {:excluded, "due to line filter"}
224+
end
225+
191226
test "parsing filters" do
192227
assert ExUnit.Filters.parse(["run"]) == [:run]
193228
assert ExUnit.Filters.parse(["run:true"]) == [run: "true"]
194229
assert ExUnit.Filters.parse(["run:test"]) == [run: "test"]
195230
assert ExUnit.Filters.parse(["line:9"]) == [line: 9]
231+
assert ExUnit.Filters.parse(["location:foo.exs"]) == [location: "foo.exs"]
232+
assert ExUnit.Filters.parse(["location:foo.exs:invalid"]) == [location: "foo.exs:invalid"]
196233
assert ExUnit.Filters.parse(["location:foo.exs:9"]) == [location: {"foo.exs", 9}]
197234
assert ExUnit.Filters.parse(["location:foo.exs:9:11"]) == [location: {"foo.exs", [9, 11]}]
198235
end
@@ -248,11 +285,14 @@ defmodule ExUnit.FiltersTest do
248285
fixed_path = path |> Path.split() |> Path.join()
249286
fixed_other_path = other_path |> Path.split() |> Path.join()
250287

288+
assert ExUnit.Filters.parse_paths([path, other_path]) ==
289+
{[fixed_path, fixed_other_path], []}
290+
251291
assert ExUnit.Filters.parse_paths([path, "#{other_path}:456:789"]) ==
252292
{[fixed_path, fixed_other_path],
253293
[
254294
exclude: [:test],
255-
include: [location: {fixed_other_path, [456, 789]}]
295+
include: [location: fixed_path, location: {fixed_other_path, [456, 789]}]
256296
]}
257297

258298
assert ExUnit.Filters.parse_paths(["#{path}:123", "#{other_path}:456"]) ==

0 commit comments

Comments
 (0)