1Code.require_file("../test_helper.exs", __DIR__)
2
3defmodule ExUnit.FiltersTest do
4  use ExUnit.Case, async: true
5
6  doctest ExUnit.Filters
7
8  describe "filter precedence" do
9    setup do
10      [
11        one: %{
12          one: true,
13          numeric: true,
14          test: :"test one",
15          test_type: :test
16        },
17        two: %{
18          skip: true,
19          numeric: true,
20          test: :"test two",
21          test_type: :test,
22          two: true
23        }
24      ]
25    end
26
27    test "no filters", tags do
28      assert ExUnit.Filters.eval([], [], tags.one, []) == :ok
29      assert ExUnit.Filters.eval([], [], tags.two, []) == {:skipped, "due to skip tag"}
30    end
31
32    test "exclude tests", tags do
33      assert ExUnit.Filters.eval([], [:two], tags.one, []) == :ok
34      assert ExUnit.Filters.eval([], [:test], tags.one, []) == {:excluded, "due to test filter"}
35      assert ExUnit.Filters.eval([], [:test], tags.two, []) == {:excluded, "due to test filter"}
36
37      assert ExUnit.Filters.eval([], [:numeric], tags.one, []) ==
38               {:excluded, "due to numeric filter"}
39
40      assert ExUnit.Filters.eval([], [:unknown], tags.one, []) == :ok
41      assert ExUnit.Filters.eval([], [:unknown], tags.two, []) == {:skipped, "due to skip tag"}
42    end
43
44    test "explicitly exclude a test with the :skip tag", tags do
45      # --exclude two
46      assert ExUnit.Filters.eval([], [:two], tags.two, []) == {:excluded, "due to two filter"}
47
48      assert ExUnit.Filters.eval([], [:two, :test], tags.two, []) ==
49               {:excluded, "due to two filter"}
50    end
51
52    test "include tests", tags do
53      # use --include, exclude is missing
54      assert ExUnit.Filters.eval([:two], [], tags.one, []) == :ok
55      assert ExUnit.Filters.eval([:unknown], [], tags.one, []) == :ok
56
57      # --only
58      assert ExUnit.Filters.eval([:one], [:test], tags.one, []) == :ok
59
60      assert ExUnit.Filters.eval([:two], [:test], tags.one, []) ==
61               {:excluded, "due to test filter"}
62
63      assert ExUnit.Filters.eval([:unknown], [:test], tags.one, []) ==
64               {:excluded, "due to test filter"}
65
66      assert ExUnit.Filters.eval([:unknown], [:test], tags.two, []) ==
67               {:excluded, "due to test filter"}
68    end
69
70    test "explicitly include a test with the :skip tag", tags do
71      # --include two, exclude is missing
72      assert ExUnit.Filters.eval([:two], [], tags.two, []) == {:skipped, "due to skip tag"}
73
74      # --only two
75      assert ExUnit.Filters.eval([:two], [:test], tags.two, []) == {:skipped, "due to skip tag"}
76    end
77
78    test "exception to the rule: include tests with the :skip tag", tags do
79      # --include skip, exclude is missing
80      assert ExUnit.Filters.eval([:skip], [], tags.two, []) == :ok
81      assert ExUnit.Filters.eval([:skip], [], %{tags.two | skip: "skip me please"}, []) == :ok
82      assert ExUnit.Filters.eval([skip: ~r/alpha/], [], %{tags.two | skip: "alpha"}, []) == :ok
83
84      assert ExUnit.Filters.eval([skip: ~r/alpha/], [], %{tags.two | skip: "beta"}, []) ==
85               {:skipped, "beta"}
86
87      # --only skip
88      assert ExUnit.Filters.eval([:skip], [:test], tags.two, []) == :ok
89
90      assert ExUnit.Filters.eval([:skip], [:test], %{tags.two | skip: "skip me please"}, []) ==
91               :ok
92
93      assert ExUnit.Filters.eval([skip: ~r/alpha/], [:test], %{tags.two | skip: "alpha"}, []) ==
94               :ok
95
96      assert ExUnit.Filters.eval([skip: ~r/alpha/], [:test], %{tags.two | skip: "beta"}, []) ==
97               {:excluded, "due to test filter"}
98    end
99  end
100
101  test "evaluating filters" do
102    assert ExUnit.Filters.eval([], [:os], %{}, []) == :ok
103    assert ExUnit.Filters.eval([], [os: :win], %{os: :unix}, []) == :ok
104    assert ExUnit.Filters.eval([], [:os], %{os: :unix}, []) == {:excluded, "due to os filter"}
105
106    assert ExUnit.Filters.eval([], [os: :unix], %{os: :unix}, []) ==
107             {:excluded, "due to os filter"}
108
109    assert ExUnit.Filters.eval([os: :win], [], %{}, []) == :ok
110    assert ExUnit.Filters.eval([os: :win], [], %{os: :unix}, []) == :ok
111    assert ExUnit.Filters.eval([os: :win], [:os], %{}, []) == :ok
112    assert ExUnit.Filters.eval([os: :win], [:os], %{os: :win}, []) == :ok
113
114    assert ExUnit.Filters.eval([os: :win, os: :unix], [:os], %{os: :win}, []) == :ok
115  end
116
117  describe "evaluating filters with skip" do
118    test "regular usage" do
119      assert ExUnit.Filters.eval([], [], %{}, []) == :ok
120      assert ExUnit.Filters.eval([], [], %{skip: true}, []) == {:skipped, "due to skip tag"}
121      assert ExUnit.Filters.eval([], [], %{skip: "skipped"}, []) == {:skipped, "skipped"}
122      assert ExUnit.Filters.eval([], [:os], %{skip: "skipped"}, []) == {:skipped, "skipped"}
123    end
124
125    test "exception to the rule: explicitly including tests with the :skip tag" do
126      assert ExUnit.Filters.eval([:skip], [], %{skip: true}, []) == :ok
127      assert ExUnit.Filters.eval([:skip], [], %{skip: "skipped"}, []) == :ok
128      assert ExUnit.Filters.eval([:skip], [:test], %{skip: true}, []) == :ok
129      assert ExUnit.Filters.eval([:skip], [:test], %{skip: "skipped"}, []) == :ok
130      assert ExUnit.Filters.eval([skip: true], [:test], %{skip: true}, []) == :ok
131
132      assert ExUnit.Filters.eval([skip: ~r/skip me/], [:test], %{skip: "skip me please"}, []) ==
133               :ok
134
135      assert ExUnit.Filters.eval([skip: ~r/skip me/], [:test], %{skip: "don't skip!"}, []) ==
136               {:skipped, "don't skip!"}
137    end
138  end
139
140  test "evaluating filters matches integers" do
141    assert ExUnit.Filters.eval([int: "1"], [], %{int: 1}, []) == :ok
142    assert ExUnit.Filters.eval([int: "1"], [int: 5], %{int: 1}, []) == :ok
143    assert ExUnit.Filters.eval([int: "1"], [:int], %{int: 1}, []) == :ok
144  end
145
146  test "evaluating filter matches atoms" do
147    assert ExUnit.Filters.eval([os: "win"], [], %{os: :win}, []) == :ok
148    assert ExUnit.Filters.eval([os: "win"], [os: :unix], %{os: :win}, []) == :ok
149    assert ExUnit.Filters.eval([os: "win"], [:os], %{os: :win}, []) == :ok
150    assert ExUnit.Filters.eval([module: "Foo"], [:os], %{module: Foo}, []) == :ok
151  end
152
153  test "evaluating filter matches regexes" do
154    assert ExUnit.Filters.eval([os: ~r"win"], [], %{os: :win}, []) == :ok
155
156    assert ExUnit.Filters.eval([os: ~r"mac"], [os: :unix], %{os: :unix}, []) ==
157             {:excluded, "due to os filter"}
158  end
159
160  test "evaluating filter uses special rules for line" do
161    tests = [
162      %ExUnit.Test{tags: %{line: 3, describe_line: 2}},
163      %ExUnit.Test{tags: %{line: 5, describe_line: nil}},
164      %ExUnit.Test{tags: %{line: 8, describe_line: 7}},
165      %ExUnit.Test{tags: %{line: 10, describe_line: 7}},
166      %ExUnit.Test{tags: %{line: 13, describe_line: 12}}
167    ]
168
169    assert ExUnit.Filters.eval([line: "3"], [:line], %{line: 3, describe_line: 2}, tests) == :ok
170    assert ExUnit.Filters.eval([line: "4"], [:line], %{line: 3, describe_line: 2}, tests) == :ok
171    assert ExUnit.Filters.eval([line: "5"], [:line], %{line: 5, describe_line: nil}, tests) == :ok
172    assert ExUnit.Filters.eval([line: "6"], [:line], %{line: 5, describe_line: nil}, tests) == :ok
173    assert ExUnit.Filters.eval([line: "2"], [:line], %{line: 3, describe_line: 2}, tests) == :ok
174    assert ExUnit.Filters.eval([line: "7"], [:line], %{line: 8, describe_line: 7}, tests) == :ok
175    assert ExUnit.Filters.eval([line: "7"], [:line], %{line: 10, describe_line: 7}, tests) == :ok
176
177    assert ExUnit.Filters.eval([line: "1"], [:line], %{line: 3, describe_line: 2}, tests) ==
178             {:excluded, "due to line filter"}
179
180    assert ExUnit.Filters.eval([line: "7"], [:line], %{line: 3, describe_line: 2}, tests) ==
181             {:excluded, "due to line filter"}
182
183    assert ExUnit.Filters.eval([line: "7"], [:line], %{line: 5, describe_line: nil}, tests) ==
184             {:excluded, "due to line filter"}
185  end
186
187  test "parsing filters" do
188    assert ExUnit.Filters.parse(["run"]) == [:run]
189    assert ExUnit.Filters.parse(["run:true"]) == [run: "true"]
190    assert ExUnit.Filters.parse(["run:test"]) == [run: "test"]
191    assert ExUnit.Filters.parse(["line:9"]) == [line: "9"]
192  end
193
194  test "file paths with line numbers" do
195    assert ExUnit.Filters.parse_path("test/some/path.exs:123") ==
196             {"test/some/path.exs", [exclude: [:test], include: [line: "123"]]}
197
198    assert ExUnit.Filters.parse_path("test/some/path.exs") == {"test/some/path.exs", []}
199
200    assert ExUnit.Filters.parse_path("test/some/path.exs:123notreallyalinenumber123") ==
201             {"test/some/path.exs:123notreallyalinenumber123", []}
202
203    assert ExUnit.Filters.parse_path("C:\\some\\path.exs:123") ==
204             {"C:\\some\\path.exs", [exclude: [:test], include: [line: "123"]]}
205
206    assert ExUnit.Filters.parse_path("C:\\some\\path.exs") == {"C:\\some\\path.exs", []}
207
208    assert ExUnit.Filters.parse_path("C:\\some\\path.exs:123notreallyalinenumber123") ==
209             {"C:\\some\\path.exs:123notreallyalinenumber123", []}
210
211    assert ExUnit.Filters.parse_path("test/some/path.exs:123:456") ==
212             {"test/some/path.exs", [exclude: [:test], include: [line: "123", line: "456"]]}
213
214    assert ExUnit.Filters.parse_path("C:\\some\\path.exs:123:456") ==
215             {"C:\\some\\path.exs", [exclude: [:test], include: [line: "123", line: "456"]]}
216
217    assert ExUnit.Filters.parse_path("test/some/path.exs:123notalinenumber123:456") ==
218             {"test/some/path.exs:123notalinenumber123",
219              [exclude: [:test], include: [line: "456"]]}
220
221    assert ExUnit.Filters.parse_path("test/some/path.exs:123:456notalinenumber456") ==
222             {"test/some/path.exs:123:456notalinenumber456", []}
223
224    assert ExUnit.Filters.parse_path("C:\\some\\path.exs:123notalinenumber123:456") ==
225             {"C:\\some\\path.exs:123notalinenumber123",
226              [exclude: [:test], include: [line: "456"]]}
227
228    assert ExUnit.Filters.parse_path("C:\\some\\path.exs:123:456notalinenumber456") ==
229             {"C:\\some\\path.exs:123:456notalinenumber456", []}
230
231    output =
232      ExUnit.CaptureIO.capture_io(:stderr, fn ->
233        assert ExUnit.Filters.parse_path("test/some/path.exs:123:0:-789:456") ==
234                 {"test/some/path.exs", [exclude: [:test], include: [line: "123", line: "456"]]}
235      end)
236
237    assert output =~ "invalid line number given as ExUnit filter: 0"
238    assert output =~ "invalid line number given as ExUnit filter: -789"
239  end
240end
241