Current section
Files
Jump to
Current section
Files
lib/mix/tasks/test/notify.ex
defmodule Mix.Tasks.Test.Notify do
use Mix.Task
@shortdoc "Run mix tests and send an OSX notification."
def run(_args) do
{ output, _exit_code } = System.cmd("mix", ["test"], stderr_to_stdout: true)
Mix.shell.info(output)
output
|> compile_error_check
|> notify
end
def notify({:error, type, error}) do
{type, error}
|> sanitize_error
|> error_applescript(sound)
|> run_applescript
end
def notify({:compiles, output}) do
[tests, failures] =
output
|> get_tests_failures
|> get_integers
successes = tests - failures
completed_test_applescript(successes, failures, sound())
|> run_applescript
end
defp sanitize_error({type, error}), do:
{type, Regex.replace(~r/"/, error, "\\\"")}
defp error_applescript({type, error}, false), do:
"display notification \"#{error}\" with title \"#{type} Error\""
defp error_applescript({type, error}, true), do:
error_applescript({type, error}, false) <> " sound name \"#{fail_sound}\""
defp run_applescript(applescript), do:
System.cmd("osascript", ["-e", applescript])
def compile_error_check(value) when is_bitstring(value), do:
{ Regex.run(compile_error_regex, value), value } |> compile_error_check
def compile_error_check({results, _output}) when is_list(results), do:
{:error, Enum.at(results, 1), Enum.at(results, 2)}
def compile_error_check({nil, output}), do: #!!ADRIAN
{:compiles, output}
def get_tests_failures(nil), do: raise "Invalid input"
def get_tests_failures(value) when is_list(value), do: Enum.drop(value, 1)
def get_tests_failures(value) when is_bitstring(value), do:
mix_test_regex |> Regex.run(value) |> get_tests_failures
def title(0), do: win_title
def title(_failures), do: fail_title
def message(successes, failures), do: "#{successes} Passed, #{failures} Failed"
def config_or_default(item, default) when is_atom(item) and not is_nil(item) and not is_boolean(item), do:
config_or_default(Application.get_env(:mix_test_notify, item), default)
def config_or_default(nil, default), do: default
def config_or_default(item, _default), do: item
def completed_test_applescript(successes, 0, true), do:
applescript_with_sound(successes, 0, win_sound)
def completed_test_applescript(successes, failures, true), do:
applescript_with_sound(successes, failures, fail_sound)
def completed_test_applescript(successes, failures, _sound), do:
"display notification \"#{message(successes, failures)}\"" <>
" with title \"#{title(failures)}\""
defp applescript_with_sound(successes, failures, name), do:
completed_test_applescript(successes, failures, nil) <> " sound name \"#{name}\""
defp get_integers(list = [_tests, _failures]) do
list |> Enum.map(fn(x) -> x |> Integer.parse |> elem(0) end)
end
defp sound, do: config_or_default(:sound, false)
defp win_sound, do: config_or_default(:win_sound, "Blow")
defp fail_sound, do: config_or_default(:fail_sound, "Basso")
defp win_title, do: config_or_default(:win_title, "Win")
defp fail_title, do: config_or_default(:fail_title, "Fail")
defp mix_test_regex, do: ~r/Finished in .* seconds.*\n(\d+) tests, (\d+) failure/
defp compile_error_regex, do: ~r/\((Compile|Syntax|Key)Error\) (.*:\d*:|key .* not found)/
end