diff --git a/lib/execute.ex b/lib/execute.ex new file mode 100644 index 0000000..566eb94 --- /dev/null +++ b/lib/execute.ex @@ -0,0 +1,48 @@ +defmodule Execute do + def run_module(module) do + run_until_failure(module, &run_koan/2) + end + + def run_until_failure(module, callback) do + Enum.reduce_while(module.all_koans, :passed, fn(it, _acc) -> + result = callback.(module, it) + if result == :passed do + {:cont, :passed} + else + {:halt, result} + end + end) + end + + def run_koan(module, name, args \\ []) do + parent = self() + spawn fn -> exec(module, name, args, parent) end + receive do + :ok -> :passed + error -> {:failed, error, module, name} + end + end + + def exec(module, name, args, parent) do + result = apply(module, name, args) + send parent, expand(result) + Process.exit(self(), :kill) + end + + def expand(:ok), do: :ok + def expand(error) do + {file, line} = System.stacktrace + |> Enum.drop_while(&in_ex_unit?/1) + |> List.first + |> extract_file_and_line + + %{error: error, file: file, line: 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 diff --git a/lib/runner.ex b/lib/runner.ex index 5071817..25323f9 100644 --- a/lib/runner.ex +++ b/lib/runner.ex @@ -34,50 +34,10 @@ defmodule Runner do def run_module(module) do Display.considering(module) - - koans = module.all_koans - passed = Enum.take_while(koans, fn(name) -> - case run_koan(module, name) do - :passed -> true + case Execute.run_module(module) do {:failed, error, module, name} -> Display.show_failure(error, module, name) - false - end - end) - - if Enum.count(koans) == Enum.count(passed) do - :passed - else - :failed + :failed + _ -> :passed end end - - def run_koan(module, name, args \\ []) do - parent = self() - spawn fn -> exec(module, name, args, parent) end - receive do - :ok -> :passed - error -> {:failed, error, module, name} - end - end - - def exec(module, name, args, parent) do - result = apply(module, name, args) - send parent, expand(result) - Process.exit(self(), :kill) - end - - def expand(:ok), do: :ok - def expand(error) do - {file, line} = System.stacktrace - |> Enum.drop_while(&in_ex_unit?/1) - |> List.first - |> extract_file_and_line - - %{error: error, file: file, line: 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 diff --git a/test/executor_test.exs b/test/executor_test.exs new file mode 100644 index 0000000..8c09580 --- /dev/null +++ b/test/executor_test.exs @@ -0,0 +1,13 @@ +defmodule RunnerTest do + use ExUnit.Case + + test "passes a koan" do + assert :passed == Execute.run_module(PassingKoan) + end + + test "stops at the first failing koan" do + {:failed, %{error: _, file: file, line: line}, SampleKoan, _name} = Execute.run_module(SampleKoan) + assert file == 'test/support/sample_koan.ex' + assert line == 5 + end +end diff --git a/test/koans_harness_test.exs b/test/koans_harness_test.exs index 3c2fffd..7ec6326 100644 --- a/test/koans_harness_test.exs +++ b/test/koans_harness_test.exs @@ -232,6 +232,6 @@ defmodule KoansHarnessTest do end def run_all(pairs, module) do - Enum.map(pairs, fn ({koan, answer}) -> Runner.run_koan(module, koan, [answer]) end) + Enum.map(pairs, fn ({koan, answer}) -> Execute.run_koan(module, koan, [answer]) end) end end diff --git a/test/support/passing_koan.ex b/test/support/passing_koan.ex new file mode 100644 index 0000000..24120d1 --- /dev/null +++ b/test/support/passing_koan.ex @@ -0,0 +1,7 @@ +defmodule PassingKoan do + use Koans + + koan "hi there" do + assert 1 == 1 + end +end