Rely on stacktraces to get the file and line of last failure
This commit is contained in:
@@ -7,7 +7,7 @@ defmodule Display do
|
|||||||
|
|
||||||
IO.puts("Now meditate upon #{display_module(module)}")
|
IO.puts("Now meditate upon #{display_module(module)}")
|
||||||
IO.puts("---------------------------------------")
|
IO.puts("---------------------------------------")
|
||||||
IO.puts(format_cyan(display_failed_assertion(module, expr)))
|
IO.puts(format_cyan(last_failure_location))
|
||||||
IO.puts(display_koan(name))
|
IO.puts(display_koan(name))
|
||||||
IO.puts(format_red(Macro.to_string(expr)))
|
IO.puts(format_red(Macro.to_string(expr)))
|
||||||
end
|
end
|
||||||
@@ -23,9 +23,20 @@ defmodule Display do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def display_failed_assertion(module, expr) do
|
def last_failure_location do
|
||||||
file = source_file(module)
|
{file, line} = System.stacktrace
|
||||||
"Assertion failed in #{file}:#{line_number(expr, in: file)}"
|
|> Enum.drop_while(&in_ex_unit?/1)
|
||||||
|
|> List.first
|
||||||
|
|> extract_file_and_line
|
||||||
|
|
||||||
|
"Assertion failed in #{file}:#{line}"
|
||||||
|
end
|
||||||
|
|
||||||
|
defp in_ex_unit?({ExUnit.Assertions, _, _, _}), do: true
|
||||||
|
defp in_ex_unit?(_), do: false
|
||||||
|
|
||||||
|
defp extract_file_and_line({_, _, _, [file: file, line: line]}) do
|
||||||
|
{file, line}
|
||||||
end
|
end
|
||||||
|
|
||||||
def format_compile_error(error) do
|
def format_compile_error(error) do
|
||||||
@@ -33,45 +44,6 @@ defmodule Display do
|
|||||||
IO.puts(format_red(Exception.format(:error, error, trace)))
|
IO.puts(format_red(Exception.format(:error, error, trace)))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp line_number({_, [line: line], _}, in: _), do: line
|
|
||||||
defp line_number(expr, in: file) do
|
|
||||||
expr
|
|
||||||
|> to_s
|
|
||||||
|> find_in_file(file)
|
|
||||||
|> interpret
|
|
||||||
end
|
|
||||||
|
|
||||||
defp interpret({:ok, n}), do: n
|
|
||||||
|
|
||||||
defp find_in_file(line, file) do
|
|
||||||
File.open(file, fn(handle) ->
|
|
||||||
IO.read(handle, :all)
|
|
||||||
|> String.split("\n")
|
|
||||||
|> Enum.find_index(fn(candidate) -> String.contains?(candidate, line) end)
|
|
||||||
|> one_based
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp one_based(nil), do: "???"
|
|
||||||
defp one_based(line), do: line + 1
|
|
||||||
|
|
||||||
defp to_s(atom) when is_atom(atom), do: ":#{to_string(atom)}"
|
|
||||||
defp to_s(tuple) when is_tuple(tuple) do
|
|
||||||
elements = tuple
|
|
||||||
|> Tuple.to_list
|
|
||||||
|> Enum.map(fn(x) -> to_s(x) end)
|
|
||||||
|
|
||||||
"{#{Enum.join(elements, ", ")}}"
|
|
||||||
end
|
|
||||||
defp to_s(x), do: "\"#{x}\""
|
|
||||||
|
|
||||||
|
|
||||||
defp source_file(module) do
|
|
||||||
module.__info__(:compile)
|
|
||||||
|> Dict.get(:source)
|
|
||||||
|> Path.relative_to(@current_dir)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp format_red(str) do
|
defp format_red(str) do
|
||||||
Enum.join([ANSI.red, str, ANSI.reset], "")
|
Enum.join([ANSI.red, str, ANSI.reset], "")
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user