Koans about processes including infrastructure.
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
defmodule BlankAssertions do
|
defmodule BlankAssertions do
|
||||||
|
require ExUnit.Assertions
|
||||||
|
|
||||||
defmacro assert(expr) do
|
defmacro assert(expr) do
|
||||||
if contains_blank?(expr) do
|
if contains_blank?(expr) do
|
||||||
code = Macro.escape(expr)
|
code = Macro.escape(expr)
|
||||||
@@ -25,6 +27,19 @@ defmodule BlankAssertions do
|
|||||||
end
|
end
|
||||||
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
|
def assert(value, opts) do
|
||||||
ExUnit.Assertions.assert(value, opts)
|
ExUnit.Assertions.assert(value, opts)
|
||||||
end
|
end
|
||||||
@@ -33,6 +48,10 @@ defmodule BlankAssertions do
|
|||||||
ExUnit.Assertions.refute(value, opts)
|
ExUnit.Assertions.refute(value, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def flunk(message \\ "Flunked!") do
|
||||||
|
assert false, message: message
|
||||||
|
end
|
||||||
|
|
||||||
defp contains_blank?(expr) do
|
defp contains_blank?(expr) do
|
||||||
{_, blank} = Macro.prewalk(expr, false, &blank?/2)
|
{_, blank} = Macro.prewalk(expr, false, &blank?/2)
|
||||||
blank
|
blank
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ defmodule Display do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def display_failed_assertion(module, expr) do
|
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
|
end
|
||||||
|
|
||||||
def format_compile_error(error) do
|
def format_compile_error(error) do
|
||||||
@@ -32,9 +33,39 @@ 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], _}) do
|
defp line_number({_, [line: line], _}, in: _) do
|
||||||
line
|
line
|
||||||
end
|
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
|
defp source_file(module) do
|
||||||
module.__info__(:compile)
|
module.__info__(:compile)
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ defmodule Koans do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defmacro __using__(_) do
|
defmacro __using__(opts) do
|
||||||
quote do
|
quote do
|
||||||
import Koans
|
|
||||||
require ExUnit.Assertions
|
require ExUnit.Assertions
|
||||||
|
import Koans
|
||||||
import BlankAssertions
|
import BlankAssertions
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
53
lib/koans/10_processes.ex
Normal file
53
lib/koans/10_processes.ex
Normal 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
|
||||||
@@ -3,6 +3,8 @@ defmodule Mix.Tasks.Meditate do
|
|||||||
alias Options
|
alias Options
|
||||||
|
|
||||||
def run(args) do
|
def run(args) do
|
||||||
|
ExUnit.start
|
||||||
|
Application.ensure_all_started(:ex_unit)
|
||||||
Application.ensure_all_started(:elixir_koans)
|
Application.ensure_all_started(:elixir_koans)
|
||||||
Code.compiler_options(ignore_module_conflict: true)
|
Code.compiler_options(ignore_module_conflict: true)
|
||||||
Watcher.start
|
Watcher.start
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ defmodule Runner do
|
|||||||
Enums,
|
Enums,
|
||||||
Arithmetic,
|
Arithmetic,
|
||||||
Structs,
|
Structs,
|
||||||
PatternMatching
|
PatternMatching,
|
||||||
|
Processes
|
||||||
]
|
]
|
||||||
|
|
||||||
def run do
|
def run do
|
||||||
|
|||||||
Reference in New Issue
Block a user