Skip to content

Commit c01658b

Browse files
committed
Add doctest metadata as tags
1 parent fdf96ad commit c01658b

File tree

4 files changed

+49
-40
lines changed

4 files changed

+49
-40
lines changed

lib/ex_unit/lib/ex_unit/case.ex

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ defmodule ExUnit.Case do
156156
157157
* `:describe_line` - the line the describe block begins on
158158
159+
* `:doctest` - the module or the file being doctested (if a doctest)
160+
161+
* `:doctest_line` - the line the doctest was defined (if a doctest)
162+
159163
The following tags customize how tests behave:
160164
161165
* `:capture_log` - see the "Log Capture" section below
@@ -167,8 +171,8 @@ defmodule ExUnit.Case do
167171
168172
* `:tmp_dir` - (since v1.11.0) see the "Tmp Dir" section below
169173
170-
The `:test_type` tag is automatically set by ExUnit, but is **not** reserved.
171-
This tag is available for users to customize if they desire.
174+
* `:test_type` - the test type used when printing test results.
175+
It is set by ExUnit to `:test`, `:doctest` and so on, but is customizable.
172176
173177
## Filters
174178
@@ -476,10 +480,16 @@ defmodule ExUnit.Case do
476480
end
477481

478482
@doc false
479-
defmacro __before_compile__(_) do
483+
defmacro __before_compile__(env) do
484+
tests =
485+
env.module
486+
|> Module.get_attribute(:ex_unit_tests)
487+
|> Enum.reverse()
488+
|> Macro.escape()
489+
480490
quote do
481491
def __ex_unit__ do
482-
%ExUnit.TestModule{file: __ENV__.file, name: __MODULE__, tests: @ex_unit_tests}
492+
%ExUnit.TestModule{file: __ENV__.file, name: __MODULE__, tests: unquote(tests)}
483493
end
484494
end
485495
end
@@ -581,6 +591,7 @@ defmodule ExUnit.Case do
581591
This function is deprecated in favor of `register_test/6` which performs
582592
better under tight loops by avoiding `__ENV__`.
583593
"""
594+
# TODO: Deprecate on Elixir v1.17
584595
@doc deprecated: "Use register_test/6 instead"
585596
def register_test(%{module: mod, file: file, line: line}, test_type, name, tags) do
586597
register_test(mod, file, line, test_type, name, tags)
@@ -758,8 +769,9 @@ defmodule ExUnit.Case do
758769

759770
defp normalize_tags(tags) do
760771
Enum.reduce(Enum.reverse(tags), %{}, fn
772+
{key, value}, acc -> Map.put(acc, key, value)
761773
tag, acc when is_atom(tag) -> Map.put(acc, tag, true)
762-
tag, acc when is_list(tag) -> tag |> Enum.into(acc)
774+
tag, acc when is_list(tag) -> Enum.into(tag, acc)
763775
end)
764776
end
765777
end

lib/ex_unit/lib/ex_unit/doc_test.ex

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -193,25 +193,27 @@ defmodule ExUnit.DocTest do
193193
This macro is auto-imported with every `ExUnit.Case`.
194194
"""
195195
defmacro doctest(module, opts \\ []) do
196+
caller = __CALLER__
197+
196198
require =
197-
if is_atom(Macro.expand(module, __CALLER__)) do
199+
if is_atom(Macro.expand(module, caller)) do
198200
quote do
199201
require unquote(module)
200202
end
201203
end
202204

203205
tests =
204-
quote bind_quoted: [module: module, opts: opts] do
205-
env = __ENV__
206+
quote bind_quoted: [
207+
module: module,
208+
opts: opts,
209+
env_line: caller.line,
210+
env_file: caller.file
211+
] do
206212
file = ExUnit.DocTest.__file__(module)
207213

208-
for {name, test} <- ExUnit.DocTest.__doctests__(module, opts) do
209-
if tags = Keyword.get(opts, :tags) do
210-
@tag tags
211-
end
212-
214+
for {name, test, tags} <- ExUnit.DocTest.__doctests__(module, opts) do
213215
@file file
214-
doc = ExUnit.Case.register_test(env, :doctest, name, [])
216+
doc = ExUnit.Case.register_test(__MODULE__, env_file, env_line, :doctest, name, tags)
215217
def unquote(doc)(_), do: unquote(test)
216218
end
217219
end
@@ -230,28 +232,25 @@ defmodule ExUnit.DocTest do
230232

231233
@doc false
232234
def __doctests__(module, opts) do
233-
do_import = Keyword.get(opts, :import, false)
235+
tags = [doctest: module] ++ Keyword.get(opts, :tags, [])
236+
import = Keyword.get(opts, :import, false)
237+
file = module.module_info(:compile)[:source] |> Path.relative_to_cwd()
234238

235239
extract(module)
236240
|> filter_by_opts(module, opts)
237-
|> Stream.with_index()
241+
|> Stream.with_index(1)
238242
|> Enum.map(fn {test, acc} ->
239-
compile_test(test, module, do_import, acc + 1)
243+
compile_test(test, module, import, acc, file, tags)
240244
end)
241245
end
242246

243247
defp filter_by_opts(tests, module, opts) do
244248
except = Keyword.get(opts, :except, [])
245249

246250
case Keyword.fetch(opts, :only) do
247-
{:ok, []} ->
248-
[]
249-
250-
{:ok, only} ->
251-
filter_tests(module, tests, except, only)
252-
253-
:error ->
254-
Stream.reject(tests, &(&1.fun_arity in except))
251+
{:ok, []} -> []
252+
{:ok, only} -> filter_tests(module, tests, except, only)
253+
:error -> Stream.reject(tests, &(&1.fun_arity in except))
255254
end
256255
end
257256

@@ -287,8 +286,9 @@ defmodule ExUnit.DocTest do
287286

288287
## Compilation of extracted tests
289288

290-
defp compile_test(test, module, do_import, n) do
291-
{test_name(test, module, n), test_content(test, module, do_import)}
289+
defp compile_test(test, module, do_import, n, file, tags) do
290+
tags = [doctest_line: test.line] ++ tags
291+
{test_name(test, module, n), test_content(test, module, do_import, file), tags}
292292
end
293293

294294
defp test_name(%{fun_arity: :moduledoc}, m, n) do
@@ -299,8 +299,7 @@ defmodule ExUnit.DocTest do
299299
"#{inspect(m)}.#{f}/#{a} (#{n})"
300300
end
301301

302-
defp test_content(%{exprs: exprs, line: line}, module, do_import) do
303-
file = module.module_info(:compile)[:source] |> Path.relative_to_cwd()
302+
defp test_content(%{exprs: exprs, line: line}, module, do_import, file) do
304303
location = [line: line, file: file]
305304
stack = Macro.escape([{module, :__MODULE__, 0, location}])
306305

lib/ex_unit/lib/ex_unit/runner.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ defmodule ExUnit.Runner do
571571
end
572572

573573
defp shuffle(%{seed: 0}, list) do
574-
Enum.reverse(list)
574+
list
575575
end
576576

577577
defp shuffle(%{seed: seed}, list) do

lib/ex_unit/test/ex_unit/doc_test_test.exs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -865,18 +865,16 @@ defmodule ExUnit.DocTestTest do
865865
end
866866
end
867867

868-
test "doctests type" do
869-
defmodule DoctestType do
870-
use ExUnit.Case
871-
doctest ExUnit.DocTestTest.NoImport
872-
873-
setup test do
874-
assert test.test_type == :doctest
875-
:ok
876-
end
868+
test "doctests built-in tags" do
869+
alias ExUnit.DocTestTest.NoImport
870+
defmodule DoctestTags do
871+
use ExUnit.Case, register: false
872+
doctest NoImport
877873
end
878874

879-
assert capture_io(fn -> ExUnit.run() end) =~ "2 doctests, 0 failures"
875+
assert %ExUnit.TestModule{tests: [test1, test2]} = DoctestTags.__ex_unit__()
876+
assert %{test_type: :doctest, doctest: NoImport, doctest_line: 129} = test1.tags
877+
assert %{test_type: :doctest, doctest: NoImport, doctest_line: 132} = test2.tags
880878
end
881879

882880
test "multiple exceptions in one test case is not supported" do

0 commit comments

Comments
 (0)