Permalink
Browse files

Slightly refactor and improve doctests code

  • Loading branch information...
josevalim committed Nov 29, 2013
1 parent 9607790 commit bbc0fe0a6344f6c698e5bdfee2a7744f5097c4f4
Showing with 40 additions and 28 deletions.
  1. +40 −28 lib/ex_unit/lib/ex_unit/doc_test.ex
@@ -132,25 +132,32 @@ defmodule ExUnit.DocTest do
defmacro doctest(mod, opts // []) do
quote bind_quoted: binding do
lc { name, test } inlist ExUnit.DocTest.__doctests__(mod, opts) do
+ @file '(for doctest at) ' ++ Path.relative_to_cwd(mod.__info__(:compile)[:source])
def unquote(name)(_), do: unquote(test)
end
end
end
@doc false
def __doctests__(module, opts) do
+ do_import = Keyword.get(opts, :import, false)
+
+ extract(module)
+ |> filter_by_opts(opts)
+ |> Stream.with_index
+ |> Enum.map(fn { test, acc } ->
+ compile_test(test, module, do_import, acc + 1)
+ end)
+ end
+
+ defp filter_by_opts(tests, opts) do
only = opts[:only] || []
except = opts[:except] || []
- do_import = Keyword.get(opts, :import, false)
- tests = Enum.filter(extract(module), fn(test) ->
+ Stream.filter(tests, fn(test) ->
fa = test.fun_arity
Enum.all?(except, &(&1 != fa)) and Enum.all?(only, &(&1 == fa))
end)
-
- Enum.map_reduce(tests, 1, fn(test, acc) ->
- { compile_test(test, module, do_import, acc), acc + 1 }
- end) |> elem(0)
end
## Compilation of extracted tests
@@ -172,35 +179,40 @@ defmodule ExUnit.DocTest do
location = [line: line, file: Path.relative_to_cwd(file)]
stack = Macro.escape [{ module, :__MODULE__, 0, location }]
- exc_filter_fn = fn
- { _, {:error, _, _} } -> true
- _ -> false
+ if multiple_exceptions?(exprs) do
+ { fun, arity } = fun_arity
+ raise Error, message: "multiple exceptions in one doctest case are not supported. "
+ "Invalid doctest for #{inspect module}.#{fun}/#{arity}"
end
- exceptions_num = Enum.count exprs, exc_filter_fn
- if exceptions_num > 1 do
- # Format the info about error location as if it were a part of the stacktrace
- { fun, arity } = fun_arity
- error_info = " #{file}:#{line}: #{inspect module}.#{fun}/#{arity}"
- raise Error, message: "multiple exceptions in one doctest case are not supported.\n#{error_info}"
+ tests = Enum.map exprs, fn { expr, expected } ->
+ test_case_content(expr, expected, module, line, file, stack)
end
- { tests, whole_expr } = Enum.map_reduce exprs, "", fn {expr, expected}, acc ->
- { test_case_content(expr, expected, module, line, file, stack), acc <> expr <> "\n" }
+ quote do
+ unquote_splicing(test_import(module, do_import))
+ unquote(gen_code_for_tests(tests, whole_expr(exprs), exception_expr(exprs), stack))
end
- whole_expr = String.strip(whole_expr)
+ end
+
+ defp whole_expr(exprs) do
+ Enum.map_join(exprs, "\n", &elem(&1, 0))
+ end
- exception = case Enum.find(exprs, exc_filter_fn) do
+ defp exception_expr(exprs) do
+ Enum.find_value(exprs, "nothing", fn
{ _, {:error, exception, message} } ->
inspect(exception) <> " with message " <> message
- nil ->
- "nothing"
- end
+ _ ->
+ nil
+ end)
+ end
- quote do
- unquote_splicing(test_import(module, do_import))
- unquote(gen_code_for_tests(tests, whole_expr, exception, stack))
- end
+ defp multiple_exceptions?(exprs) do
+ Enum.count(exprs, fn
+ { _, {:error, _, _} } -> true
+ _ -> false
+ end) > 1
end
defp gen_code_for_tests(tests, whole_expr, exception, stack) do
@@ -316,13 +328,13 @@ defmodule ExUnit.DocTest do
moduledocs ++ docs
end
- defp extract_from_moduledoc({_, negative}) when negative in [false, nil], do: []
+ defp extract_from_moduledoc({_, doc}) when doc in [false, nil], do: []
defp extract_from_moduledoc({line, doc}) do
extract_tests(line, doc)
end
- defp extract_from_doc({_, _, _, _, negative}) when negative in [false, nil], do: []
+ defp extract_from_doc({_, _, _, _, doc}) when doc in [false, nil], do: []
defp extract_from_doc({ fa, line, _, _, doc}) do
lc test inlist extract_tests(line, doc) do

0 comments on commit bbc0fe0

Please sign in to comment.