Koans about processes including infrastructure.

This commit is contained in:
Felipe Sere
2016-03-06 21:27:51 +00:00
parent f2b4cec409
commit c450cc3b19
6 changed files with 111 additions and 5 deletions

View File

@@ -1,4 +1,6 @@
defmodule BlankAssertions do
require ExUnit.Assertions
defmacro assert(expr) do
if contains_blank?(expr) do
code = Macro.escape(expr)
@@ -25,6 +27,19 @@ defmodule BlankAssertions do
end
end
defmacro assert_receive(expr) do
if contains_blank?(expr) do
code = Macro.escape(expr)
quote do
raise ExUnit.AssertionError, expr: unquote(code)
end
else
quote do
ExUnit.Assertions.assert_receive(unquote(expr), 100)
end
end
end
def assert(value, opts) do
ExUnit.Assertions.assert(value, opts)
end
@@ -33,6 +48,10 @@ defmodule BlankAssertions do
ExUnit.Assertions.refute(value, opts)
end
def flunk(message \\ "Flunked!") do
assert false, message: message
end
defp contains_blank?(expr) do
{_, blank} = Macro.prewalk(expr, false, &blank?/2)
blank

View File

@@ -24,7 +24,8 @@ defmodule Display do
end
def display_failed_assertion(module, expr) do
"Assertion failed in #{source_file(module)}:#{line_number(expr)}"
file = source_file(module)
"Assertion failed in #{file}:#{line_number(expr, in: file)}"
end
def format_compile_error(error) do
@@ -32,9 +33,39 @@ defmodule Display do
IO.puts(format_red(Exception.format(:error, error, trace)))
end
defp line_number({_, [line: line], _}) do
defp line_number({_, [line: line], _}, in: _) do
line
end
defp line_number(expr, in: file) do
expression = expr_to_s(expr)
{:ok, line} = File.open(file, fn(x) ->
IO.read(x, :all)
|> String.split("\n")
|> Enum.find_index(fn(candidate) -> String.contains?(candidate, expression) end)
|> one_based
end)
line
end
defp one_based(line) when is_number(line), do: line + 1
defp one_based(nil), do: "???"
defp expr_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 expr_to_s(atom) when is_atom(atom) do
to_string(atom)
end
def to_s(x) when is_atom(x) do
":#{to_string(x)}"
end
def to_s(x), do: "\"#{x}\""
defp source_file(module) do
module.__info__(:compile)

View File

@@ -15,10 +15,10 @@ defmodule Koans do
end
end
defmacro __using__(_) do
defmacro __using__(opts) do
quote do
import Koans
require ExUnit.Assertions
import Koans
import BlankAssertions
end
end

53
lib/koans/10_processes.ex Normal file
View File

@@ -0,0 +1,53 @@
defmodule Processes do
use Koans
koan "tests run in a process!" do
assert Process.alive?(self)
end
koan "can spew out information about a process" do
information = Process.info(self)
assert information[:status] == :running
end
koan "process can send messages to itself" do
send self(), "hola!"
receive do
message -> assert message == "hola!"
end
end
koan "a spawned process is independent of the current process" do
pid = spawn(fn -> receive do
{:hello, thing} -> assert thing == "world"
_ -> assert false
end
end)
send pid, {:hello, "world"}
end
koan "a common pattern is to include the sender in the message" do
pid = spawn(fn -> receive do
{:hello, sender} -> send sender, :how_are_you?
_ -> assert false
end
end)
send pid, {:hello, self()}
assert_receive :how_are_you?
end
koan "you don't have to wait forever for messages" do
parent = self
spawn(fn -> receive do
_ -> assert false
after
10 -> send parent, {:waited_too_long, "I am inpatient"}
end
end)
assert_receive {:waited_too_long, "I am inpatient"}
end
end

View File

@@ -3,6 +3,8 @@ defmodule Mix.Tasks.Meditate do
alias Options
def run(args) do
ExUnit.start
Application.ensure_all_started(:ex_unit)
Application.ensure_all_started(:elixir_koans)
Code.compiler_options(ignore_module_conflict: true)
Watcher.start

View File

@@ -8,7 +8,8 @@ defmodule Runner do
Enums,
Arithmetic,
Structs,
PatternMatching
PatternMatching,
Processes
]
def run do