Merge pull request #44 from ukutaht/extract_answers

Extract answers
This commit is contained in:
Uku Taht
2016-03-17 16:59:36 +00:00
12 changed files with 412 additions and 173 deletions

View File

@@ -27,15 +27,14 @@ 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
def assert_receive(expr) do
if expr == :__ do
raise ExUnit.AssertionError, expr: expr
else
quote do
ExUnit.Assertions.assert_receive(unquote(expr), 100)
receive do
^expr -> true
after
100 -> flunk("No message matching #{expr} found in mailbox")
end
end
end
@@ -48,10 +47,8 @@ defmodule BlankAssertions do
ExUnit.Assertions.refute(value, opts)
end
defmacro flunk(message \\ "Flunked!") do
quote do
assert false, message: unquote(message)
end
def flunk(message \\ "Flunked!") do
ExUnit.Assertions.flunk(message)
end
defp contains_blank?(expr) do

View File

@@ -4,62 +4,62 @@ defmodule Maps do
koan "Maps represent structured data, like a person" do
assert %{ :name => "Jon",
:last_name => "Snow",
:age => 27 } == %{ :name => "Jon",
:age => 27 } == %{ :name => :__,
:last_name => "Snow",
:age => 27 }
end
koan "You can get all the keys from the map" do
assert Map.keys(%{ :name => "Jon", :last_name => "Snow", :age => 27 }) == [:age, :last_name, :name]
assert Map.keys(%{ :name => "Jon", :last_name => "Snow", :age => 27 }) == :__
end
koan "Or you can also get all the values from it" do
assert Map.values(%{ :name => "Jon", :last_name => "Snow", :age => 27 }) == [27, "Snow", "Jon"]
assert Map.values(%{ :name => "Jon", :last_name => "Snow", :age => 27 }) == :__
end
koan "Fetching a value returns a touple with ok when it exists..." do
assert Map.fetch(%{ :name => "Jon", :last_name => "Snow", :age => 27 }, :age) == {:ok, 27}
assert Map.fetch(%{ :name => "Jon", :last_name => "Snow", :age => 27 }, :age) == :__
end
koan "...or the atom :error when it doesnt." do
assert Map.fetch(%{ :name => "Jon", :last_name => "Snow", :age => 27 }, :family) == :error
assert Map.fetch(%{ :name => "Jon", :last_name => "Snow", :age => 27 }, :family) == :__
end
koan "Extending a map is a simple as put'ing in a new pair" do
assert Map.put(%{ :name => "Jon", :last_name => "Snow"}, :age, 27) == %{ :name => "Jon", :last_name => "Snow", :age => 27 }
assert Map.put(%{ :name => "Jon", :last_name => "Snow"}, :age, 27) == :__
end
koan "Put can also overwrite existing values" do
assert Map.put(%{ :name => "Jon", :last_name => "Snow", :age => 15}, :age, 27) == %{ :name => "Jon", :last_name => "Snow", :age => 27 }
assert Map.put(%{ :name => "Jon", :last_name => "Snow", :age => 15}, :age, 27) == :__
end
koan "Or you can use some syntactic sugar for exiting elements." do
initial = %{ :name => "Jon", :last_name => "Snow", :age => 15}
assert %{ initial | :age => 27 } == %{ :name => "Jon", :last_name => "Snow", :age => 27 }
initial = %{ :name => "Jon", :last_name => "Snow", :age => 16}
assert %{ initial | :age => 27 } == :__
end
koan "Can remove pairs by key" do
assert Map.delete(%{ :name => "Jon", :last_name => "Snow", :age => 15}, :age) == %{ :name => "Jon", :last_name => "Snow"}
assert Map.delete(%{ :name => "Jon", :last_name => "Snow", :age => 15}, :age) == :__
end
koan "If you have a list of pairs, you can turn them into a map" do
assert Map.new( [{:name, "Jon"}, {:last_name, "Snow"}, {:age, 27}] ) == %{ :name => "Jon", :last_name => "Snow", :age => 27 }
assert Map.new( [{:name, "Jon"}, {:last_name, "Snow"}, {:age, 27}] ) == :__
end
koan "Going back to a list of pairs is just as easy." do
assert Map.to_list(%{ :name => "Jon", :last_name => "Snow", :age => 27 }) == [age: 27, last_name: "Snow", name: "Jon" ]
assert Map.to_list(%{ :name => "Jon", :last_name => "Snow", :age => 27 }) == :__
end
koan "Can merge maps" do
assert Map.merge(%{:name => "Jon"}, %{ :last_name => "Snow"}) == %{:name => "Jon", :last_name => "Snow"}
assert Map.merge(%{:name => "Jon"}, %{ :last_name => "Snow"}) == :__
end
koan "When merging, the last map wins" do
assert Map.merge(%{:name => "Robert", :last_name => "Snow"}, %{ :last_name => "Baratheon"}) == %{:name => "Robert", :last_name => "Baratheon"}
assert Map.merge(%{:name => "Robert", :last_name => "Snow"}, %{ :last_name => "Baratheon"}) == :__
end
koan "You can also select sub-maps out of a larger map" do
initial = %{ :name => "Jon", :last_name => "Snow", :age => 15}
assert Map.take(initial, [:name, :last_name]) == %{ :name => "Jon", :last_name => "Snow"}
assert Map.take(initial, [:name, :last_name]) == :__
end
end

View File

@@ -2,38 +2,38 @@ defmodule Strings do
use Koans
koan "Strings are there to represent text" do
assert "hello" == "hello"
assert "hello" == :__
end
koan "They can be put together" do
assert "hello world" == "hello " <> "world"
assert "hello world" == :__ <> "world"
end
koan "Or pulled apart when needed" do
assert ["hello", "world"] == String.split("hello world")
assert :__ == String.split("hello world")
end
koan "Be careful, a message may be altered" do
assert "An awful day" == String.replace("An incredible day", "incredible", "awful")
assert :__ == String.replace("An incredible day", "incredible", "awful")
end
koan "But strings never lie about themselves" do
assert true == String.contains?("An incredible day", "incredible")
assert true == String.contains?("An incredible day", :__)
end
koan "Sometimes you want just the opposite of what is given" do
assert "banana" == String.reverse("ananab")
assert :__ == String.reverse("ananab")
end
koan "Other times a little cleaning is in order" do
assert "banana" == String.strip(" \n banana\n ")
assert :__ == String.strip(" \n banana\n ")
end
koan "Repetition is the mother of learning" do
assert "StringStringString" == String.duplicate("String", 3)
assert "StringStringString" == String.duplicate(:__, 3)
end
koan "Strings can be louder when necessary" do
assert "LISTEN" == String.upcase("listen")
assert "LISTEN" == String.upcase(:__)
end
end

View File

@@ -6,12 +6,12 @@ defmodule Functions do
end
# A function starts with 'def', has a 'do-end' pair
koan "it returns the last statement that was called" do
assert inside() == :light
assert inside() == :__
end
def quick_inline_product(a, b), do: a * b
koan "Short functions can be defined in a single line, but mind the comman and colon!" do
assert quick_inline_product(2,3) == 6
assert quick_inline_product(2,:__) == 6
end
# A function can have an argument between parentheses, after the name
@@ -23,9 +23,12 @@ defmodule Functions do
end
end
koan "Can return different things" do
assert will_change(true) == :it_was_truthy
assert will_change(false) == "It really wasn't"
koan "Can return atoms..." do
assert will_change(true) == :__
end
koan "..or strings from the same function!" do
assert will_change(false) == :__
end
def repeat(times, message) do
@@ -33,64 +36,73 @@ defmodule Functions do
end
koan "Functions can have more than one arguement" do
assert repeat(3, "Hello ") == "Hello Hello Hello "
assert repeat(3, "Hello ") == :__
end
def repeat_again(times \\ 3, message) do
def repeat_again(times \\ 5, message) do
String.duplicate(message, times)
end
koan "But sometimes, you may want to default some arguments" do
assert repeat_again("Hello ") == "Hello Hello Hello "
assert repeat_again("Hello ") == :__
end
def first(foo, bar), do: "#{foo} and #{bar}"
def first(foo), do: "only #{foo}"
koan "Functions are distinguished by name and arity - the number of arguments" do
assert first("One", "Two") == "One and Two"
assert first("One") == "only One"
koan "functions with the same name are distinguished by arity" do
assert first("One", "Two") == :__
end
koan "the name stays - the number of arguments varies" do
assert first("One") == :__
end
def sum_up(thing) when is_list(thing), do: :entire_list
def sum_up(_thing), do: :single_thing
koan "You can 'guard' functions against their arguments" do
assert sum_up([1,2,3]) == :entire_list
assert sum_up(1) == :single_thing
koan "You can 'guard' functions from their arguments" do
assert sum_up([1,2,3]) == :__
end
koan "no guard means just that - anything" do
assert sum_up(1) == :__
end
def bigger(a,b) when a > b, do: "#{a} is bigger than #{b}"
def bigger(a,b) when a <= b, do: "#{a} is not bigger than #{b}"
koan "You can also create intricate guards based on the values" do
assert bigger(10, 5) == "10 is bigger than 5"
assert bigger(4, 27) == "4 is not bigger than 27"
koan "You can also create intricate guards based on the values..." do
assert bigger(10, 5) == :__
end
koan "...to make the body of the function clearer" do
assert bigger(4, 27) == :__
end
def the_length(0), do: "It was zero"
def the_length(number), do: "The length was #{number}"
koan "You can also 'guard' with concrete values" do
assert the_length(0) == "It was zero"
assert the_length(5) == "The length was 5"
assert the_length(0) == :__
end
koan "Or just let the argument roll" do
assert the_length(5) == :__
end
koan "You can also define inline functions and call them with .()" do
multiply = fn (a,b) -> a * b end
assert multiply.(2,3) == 6
assert multiply.(2,3) == :__
end
koan "You can even go shorter, by using &(..) and positional arguments" do
multiply = &(&1 * &2)
assert multiply.(2,3) == 6
assert multiply.(2,3) == :__
end
def two_arguments(_first, second), do: second
koan "You can also show that certain arguments are ignored in the body by adding an underscore" do
assert two_arguments(:hi_there, "the other one") == "the other one"
assert two_arguments(:hi_there, "the other one") == :__
end
def multiply_then_call(number, fun), do: fun.(number*5)
def square(number), do: number * number
koan "You can 'capture' functions if you want to pass them around as values" do
assert multiply_then_call(2, &square/1) == 100
assert multiply_then_call(2, &square/1) == :__
end
koan "functions can be combined elegantly with the pipe operator" do
@@ -99,6 +111,6 @@ defmodule Functions do
|> Enum.map(&(String.capitalize(&1)))
|> Enum.join(" ")
assert result == "Full Name"
assert result == :__
end
end

View File

@@ -2,121 +2,119 @@ defmodule Enums do
use Koans
koan "knowing how many elements are in a list is important for book-keeping!" do
assert Enum.count([1,2,3,4]) == 4
assert Enum.count([1,2,3,4]) == :__
end
koan "..the same applies for counting elements in a map..." do
assert Enum.count(%{ :a => 1, :b => 2, :c => 3, :d => 4}) == 4
assert Enum.count(%{ :a => 1, :b => 2, :c => 3, :d => 4}) == :__
end
koan "..or a keyword list..." do
assert Enum.count([a: 1, b: 2, c: 3, d: 4]) == 4
assert Enum.count([a: 1, b: 2, c: 3, d: 4]) == :__
end
koan "all? can tell you if all your element have something in common!" do
assert Enum.all?([1,2,3], fn element -> element < 5 end)
koan "Elements can have a lot in common" do
assert Enum.all?([1,2,3], fn element -> element < 5 end) == :__
end
koan "the key aspec is _all_ : if one if different, all? will let you know!" do
refute Enum.all?([1, 2, 3], fn element -> element <= 2 end)
koan "If one if different, all elements are not alike" do
assert Enum.all?([1, 2, 3], fn element -> element <= 2 end) == :__
end
koan "sometimes you you just want to know if there is _some_ element with a certain trait." do
assert Enum.any?([1,2,3], fn element -> rem(element, 2) == 0 end)
koan "sometimes you you just want to know if there are any elements with a certain trait" do
assert Enum.any?([1,2,3], fn element -> rem(element, 2) == 0 end) == :__
end
koan "if not a single element fits the bill, any? returns false" do
refute Enum.any?([1,2,3], fn element -> rem(element, 5) == 0 end)
assert Enum.any?([1,2,3], fn element -> rem(element, 5) == 0 end) == :__
end
koan "Sometimes you just want to know if an element is part of the party" do
assert Enum.member?([1,2,3], 1)
assert Enum.member?([1,2,3], 1) == :__
end
koan "And sometimes your invited guests don't show up and miss the party" do
refute Enum.member?([1,2,3], 30)
assert Enum.member?([1,2,3], 30) == :__
end
koan "map converts each element of a list by running some function with it" do
assert Enum.map([1,2,3], fn element -> element * 10 end) == [10,20,30]
assert Enum.map([1,2,3], fn element -> element * 10 end) == :__
end
koan "You can even return a list with entirely different types!" do
assert Enum.map([1,2,3], fn element -> rem(element, 2) == 0 end) == [false, true, false]
koan "You can even return a list with entirely different types" do
assert Enum.map([1,2,3], fn element -> rem(element, 2) == 0 end) == :__
end
koan "But keep in mind that the original list remains unchanged!" do
koan "But keep in mind that the original list remains unchanged" do
input = [1,2,3]
assert Enum.map(input, fn element -> rem(element, 2) == 0 end) == [false, true, false]
assert input == [1,2,3]
assert input == :__
end
koan "Filter allows you to only keep what you really care about." do
assert Enum.filter([1,2,3], fn element -> rem(element, 2) == 1 end) == [1,3]
koan "Filter allows you to only keep what you really care about" do
assert Enum.filter([1,2,3], fn element -> rem(element, 2) == 1 end) == :__
end
koan "Reject will help you throw out unwanted cruft." do
assert Enum.reject([1,2,3], fn element -> rem(element, 2) == 1 end) == [2]
assert Enum.reject([1,2,3], fn element -> rem(element, 2) == 1 end) == :__
end
koan "You three there, follow me!" do
assert Enum.take([1,2,3,4,5], 3) == [1,2,3]
assert Enum.take([1,2,3,4,5], 3) == :__
end
koan "...you can ask for a lot, but Enum won't hand you more than you give" do
assert Enum.take([1,2,3,4,5], 10) == [1,2,3,4,5]
koan "You can ask for a lot, but Enum won't hand you more than you give" do
assert Enum.take([1,2,3,4,5], 10) == :__
end
koan "Take what you can..." do
assert Enum.take_while([1,2,3,4,5], fn element -> element < 4 end) == [1,2,3]
assert Enum.take_while([1,2,3,4,5], fn element -> element < 4 end) == :__
end
koan "Just like taking, you can also drop elements" do
assert Enum.drop([-1,0,1,2,3], 2) == [1,2,3]
assert Enum.drop([-1,0,1,2,3], 2) == :__
end
koan "...and drop elements until you are happy." do
assert Enum.drop_while([-1,0,1,2,3], fn element -> element <= 0 end) == [1,2,3]
koan "Drop elements until you are happy" do
assert Enum.drop_while([-1,0,1,2,3], fn element -> element <= 0 end) == :__
end
koan "Forming groups makes uns stronger" do
odd_or_even = fn element -> if rem(element, 2) == 0 do :even else :odd end end
assert Enum.group_by([1,2,3,4], odd_or_even) == %{ :odd => [3,1], :even => [4,2] }
assert Enum.group_by([1,2,3,4], odd_or_even) == :__
end
koan "You get as many groups as you can have different results" do
assert Enum.group_by([1,2,3,4,5,6], fn element -> rem(element, 3) end) == %{ 0 => [6, 3], 1 => [4, 1], 2 => [5, 2]}
assert Enum.group_by([1,2,3,4,5,6], fn element -> rem(element, 3) end) == :__
end
koan "Zip-up in pairs!" do
numbers = [1,2,3]
letters = [:a, :b, :c]
assert Enum.zip(numbers, letters) == [{1, :a}, {2, :b}, {3, :c}]
assert Enum.zip(numbers, letters) == :__
end
koan "Sorry, but if you don't have a pair you are left out" do
more_numbers = [1,2,3] ++ [4,5]
letters = [:a, :b, :c]
assert Enum.zip(more_numbers, letters) == [{1, :a}, {2, :b}, {3, :c}]
assert Enum.zip(more_numbers, letters) == :__
end
koan "When you want to find that one pesky element..." do
assert Enum.find([1,2,3], fn element -> rem(element,2) == 0 end) == 2
koan "When you want to find that one pesky element" do
assert Enum.find([1,2,3], fn element -> rem(element,2) == 0 end) == :__
end
koan "...but you don't quite find it..." do
assert Enum.find([1,2,3], fn element -> rem(element,5) == 0 end) == nil
assert Enum.find([1,2,3], fn element -> rem(element,5) == 0 end) == :__
end
koan "...you can settle for a consolation prize" do
assert Enum.find([1,2,3], :no_such_element, fn element -> rem(element,5) == 0 end) == :no_such_element
assert Enum.find([1,2,3], :no_such_element, fn element -> rem(element,5) == 0 end) == :__
end
koan "Collapse an entire list of elements down to a single one by repeating a function." do
assert Enum.reduce([1,2,3], 0, fn(element, accumulator) -> element + accumulator end) == 6
assert Enum.reduce(["1", "2", "3"], "", fn(element, accumulator) -> element <> accumulator end) == "321"
assert Enum.reduce([1,2,3], 0, fn(element, accumulator) -> element + accumulator end) == :__
end
end

View File

@@ -2,53 +2,51 @@ defmodule Arithmetic do
use Koans
koan "it can add numbers" do
assert 3 + 4 == 7
assert 3 + :__ == 7
end
koan "it can substract numbers" do
assert 7 - 4 == 3
assert 7 - 4 == :__
end
koan "it can multiply" do
assert 3 * 4 == 12
assert 3 * 4 == :__
end
koan "floats and integers can be equal..." do
assert 3.0 == 3
assert 3.0 == :__
end
koan "..unless they are not precisely the same" do
assert 3.2 != 3
assert 3.2 != :__
end
koan "it does floating point division" do
assert 5 / 2 == 2.5
assert 5 / 2 == :__
end
koan "it does integer division" do
numerator = 5
denominator = 2
assert div(numerator, denominator) == 2
assert div(numerator, denominator) == :__
end
koan "it calculates the remainder of a division" do
numerator = 5
denominator = 2
assert rem(numerator, denominator) == 1
assert rem(numerator, denominator) == :__
end
koan "it finds the maximum in a list" do
assert Enum.max([1,2,3,4]) == 4
end
koan "it can compare numbers" do
assert 5 > 2
assert 5 >= 5
assert 3 < 7
assert 5 <= 5
assert Enum.max([1,2,3,4]) == :__
end
koan "it finds the minimum in a list" do
assert Enum.min([1,2,3,4]) == 1
assert Enum.min([1,2,3,4]) == :__
end
koan "it can compare numbers" do
assert 5 > :__
end
end

View File

@@ -7,36 +7,34 @@ defmodule Structs do
koan "structs are defined and named after a module" do
person = %Person{}
assert person == %Person{}
assert person == :__
end
koan "you can access the fields of a struct" do
nobody = %Person{}
assert nobody.age == nil
assert nobody.name == nil
assert nobody.age == :__
end
koan "You can pass initial values to structs" do
joe = %Person{name: "Joe", age: 23}
assert joe.age == 23
assert joe.name == "Joe"
assert joe.name == :__
end
koan "update fields with the pipe '|' operator" do
joe = %Person{name: "Joe", age: 23}
older = %{ joe | age: joe.age + 10}
assert older.age == 33
assert older.age == :__
end
koan "the original struct is not affected by updates" do
joe = %Person{name: "Joe", age: 23}
assert %{ joe | age: joe.age + 10}.age == 33
assert joe.age == 23
assert joe.age == :__
end
koan "you can pattern match into the fields of a struct" do
%Person{age: age} = %Person{age: 22, name: "Silvia"}
assert age == 22
assert age == :__
end
defmodule Plane do
@@ -44,16 +42,14 @@ defmodule Structs do
end
koan "or onto the type of the struct itself" do
assert is_a_plane(%Plane{passengers: 417, maker: :boeing})
refute is_a_plane(%Person{age: 22, name: "Silvia"})
assert is_a_plane(%Plane{passengers: 417, maker: :boeing}) == :__
end
def is_a_plane(%Plane{}), do: true
def is_a_plane(_), do: false
koan "are basically maps" do
silvia = %Person{age: 22, name: "Silvia"}
assert Map.fetch!(silvia, :age) == 22
assert Map.fetch!(silvia, :age) == :__
end
end

View File

@@ -2,56 +2,60 @@ defmodule PatternMatching do
use Koans
koan "one matches one" do
assert match?(1, 1)
assert match?(1, :__)
end
koan "a pattern can change" do
a = 1
assert a = 2
assert a = :__
end
# TODO not sure about this koan?
koan "a pattern can also be strict" do
a = 1
assert ^a = 2
assert ^a = :__
end
koan "patterns can be used to pull things apart" do
[head | tail] = [1,2,3,4]
[head | _tail] = [1,2,3,4]
assert head == 1
assert tail == [2,3,4]
assert head == :__
end
koan "or put them back together" do
koan "...whichever side you actually need" do
[_head | tail] = [1,2,3,4]
assert tail == :__
end
koan "and then put them back together" do
head = 1
tail = [2,3,4]
assert [1,2,3,4] == [head | tail]
assert :__ == [head | tail]
end
koan "Some values can be irrelevant" do
[_first, _second, third, _fourth] = [1,2,3,4]
assert third == 3
assert third == :__
end
koan "strings come apart just a easily" do
"Shopping list: " <> items = "Shopping list: eggs, milk"
assert items == "eggs, milk"
assert items == :__
end
koan "patterns show what you really care about" do
%{make: make} = %{type: "car", year: 2016, make: "Honda", color: "black"}
assert make == "Honda"
assert make == :__
end
koan "the pattern can make assertions about what it expects" do
the_list = [1, 2, 3]
assert match?([1, _, _], the_list)
refute match?([2, _, _], the_list)
assert match?([1, _, _], :__)
end
def make_noise(%{type: "cat"}), do: "Meow"
@@ -60,20 +64,26 @@ defmodule PatternMatching do
koan "functions can declare what kind of arguments they accept" do
dog = %{type: "dog", legs: 4, age: 9, color: "brown"}
cat = %{type: "cat", legs: 4, age: 3, color: "grey"}
snake = %{type: "snake", legs: 0, age: 20, color: "black"}
assert make_noise(dog) == "Woof"
assert make_noise(cat) == "Meow"
assert make_noise(snake) == "Eh?"
assert make_noise(dog) == :__
end
koan "...and for cats..." do
cat = %{type: "cat", legs: 4, age: 3, color: "grey"}
assert make_noise(cat) == :__
end
koan "...and for snakes..." do
snake = %{type: "snake", legs: 0, age: 20, color: "black"}
assert make_noise(snake) == :__
end
koan "errors are shaped differently than sucessful results" do
result = case Map.fetch(%{}, :obviously_not_a_key) do
{:ok, val} -> val
:error -> "not present"
_ -> flunk("I should not happen")
end
assert result == "not present"
assert result == :__
end
end

View File

@@ -2,18 +2,18 @@ defmodule Processes do
use Koans
koan "tests run in a process!" do
assert Process.alive?(self)
assert Process.alive?(:__)
end
koan "can spew out information about a process" do
information = Process.info(self)
assert information[:status] == :running
assert information[:status] == :__
end
koan "process can send messages to itself" do
send self(), "hola!"
assert_receive "hola!"
assert_receive :__
end
koan "a common pattern is to include the sender in the message" do
@@ -24,7 +24,7 @@ defmodule Processes do
end)
send pid, {:hello, self()}
assert_receive :how_are_you?
assert_receive :__
end
koan "you don't have to wait forever for messages" do
@@ -36,22 +36,20 @@ defmodule Processes do
end
end)
assert_receive {:waited_too_long, "I am inpatient"}
assert_receive :__
end
koan "killing a process will terminate it" do
pid = spawn(fn -> Process.exit(self(), :kill) end)
:timer.sleep(500)
refute Process.alive?(pid)
assert Process.alive?(pid) == :__
end
koan "killing a process kills it for good" do
pid = spawn(fn -> receive do
end
end)
pid = spawn(fn -> receive do end end)
assert Process.alive?(pid)
Process.exit(pid, :kill)
refute Process.alive?(pid)
assert Process.alive?(pid) == :__
end
koan "can trap a signal in a child process" do
@@ -66,8 +64,7 @@ defmodule Processes do
wait()
Process.exit(pid, :random_reason)
assert_receive {:exited, :random_reason}
refute Process.alive?(pid)
assert_receive :__
end
koan "quitting normally has no effect" do
@@ -75,7 +72,7 @@ defmodule Processes do
end
end)
Process.exit(pid, :normal)
assert Process.alive?(pid)
assert Process.alive?(pid) == :__
end
koan "quititing your own process normally does terminate it though" do
@@ -84,10 +81,9 @@ defmodule Processes do
end
end)
assert Process.alive?(pid)
send pid, :bye
:timer.sleep(100)
refute Process.alive?(pid)
assert Process.alive?(pid) == :__
end
koan "linked processes are informed about exit signals of children when trapping those signals" do
@@ -100,7 +96,7 @@ defmodule Processes do
end
end)
assert_receive {:exited, :normal}
assert_receive :__
end
koan "monitoring processes are informed via messages without having trapping" do
@@ -112,7 +108,7 @@ defmodule Processes do
end
end)
assert_receive {:exited, :normal}
assert_receive :__
end
def wait do

View File

@@ -4,20 +4,19 @@ defmodule Tasks do
koan "Tasks can be used for asynchronous computations with results" do
task = Task.async(fn -> 3 *3 end)
do_other_stuff()
assert Task.await(task) + 1 == 10
assert Task.await(task) + 1 == :__
end
koan "if you don't need a result, use start_link/1" do
{:ok, _pid} = Task.start_link(fn -> 1+1 end)
end
koan "yield returns nil if the task isn't done yet" do
koan "yield returns nothing if the task isn't done yet" do
handle = Task.async(fn ->
:timer.sleep(100)
3 * 3
end)
assert Task.yield(handle, 10) == nil
assert Task.await(handle) == 9
assert Task.yield(handle, 10) == :__
end
koan "tasks can be aborted with shutdown" do
@@ -25,13 +24,13 @@ defmodule Tasks do
:timer.sleep(100)
3 * 3
end)
refute Task.shutdown(handle)
assert Task.shutdown(handle) == :__
end
koan "shutdown will give you an answer if it has it" do
handle = Task.async(fn -> 3 * 3 end)
:timer.sleep(10)
assert Task.shutdown(handle) == {:ok, 9}
assert Task.shutdown(handle) == {:ok, :__}
end
koan "you can yield to multiple tasks at once and extract the results" do
@@ -40,7 +39,7 @@ defmodule Tasks do
|> Task.yield_many(100)
|> Enum.map(fn({_task,{:ok, result}}) -> result end)
assert squares == [1,4,9,16]
assert squares == :__
end
def do_other_stuff do

35
lib/koans/12_tuples.ex Normal file
View File

@@ -0,0 +1,35 @@
defmodule Tuples do
use Koans
koan "tuples have a size" do
assert tuple_size({:a, :b, :c}) == :__
end
koan "tuples can contain different things" do
assert {:a, 1, "hi"} == :__
end
koan "you can pull out individual elements" do
assert elem({:a, "hi"}, 1) == :__
end
koan "you can change individual elements of a tuple" do
assert put_elem({:a, "hi"}, 1, "bye") == :__
end
koan "you can also simply extend a tuple with new stuff" do
assert Tuple.insert_at({:a, "hi"}, 1, :new_thing) == :__
end
koan "add things at the end" do
assert Tuple.append({"Huey", "Dewey"}, "Louie") == :__
end
koan "or also remove them" do
assert Tuple.delete_at({:this, :is, :not, :awesome}, 2) == :__
end
koan "turn it into a list in case you need it" do
assert Tuple.to_list({:this, :can, :be, :a, :list}) == :__
end
end

View File

@@ -34,6 +34,204 @@ defmodule KoansHarnessTest do
test_all(Lists, answers)
end
test "Maps" do
answers = [
"Jon",
[:age, :last_name, :name],
[27, "Snow", "Jon"],
{:ok, 27},
:error,
%{ :name => "Jon", :last_name => "Snow", :age => 27 },
%{ :name => "Jon", :last_name => "Snow", :age => 27 },
%{ :name => "Jon", :last_name => "Snow", :age => 27 },
%{ :name => "Jon", :last_name => "Snow"},
%{ :name => "Jon", :last_name => "Snow", :age => 27 },
[age: 27, last_name: "Snow", name: "Jon" ],
%{:name => "Jon", :last_name => "Snow"},
%{:name => "Robert", :last_name => "Baratheon"},
%{ :name => "Jon", :last_name => "Snow"}
]
test_all(Maps, answers)
end
test "String" do
answers = [
"hello",
"hello ",
["hello", "world"],
"An awful day",
"incredible",
"banana",
"banana",
"String",
"listen"
]
test_all(Strings, answers)
end
test "Functions" do
answers = [
:light,
3,
:it_was_truthy,
"It really wasn't",
"Hello Hello Hello ",
"Hello Hello Hello Hello Hello ",
"One and Two",
"only One",
:entire_list,
:single_thing,
"10 is bigger than 5",
"4 is not bigger than 27",
"It was zero",
"The length was 5",
6,
6,
"the other one",
100,
"Full Name"
]
test_all(Functions, answers)
end
test "Enum" do
answers = [
4,
4,
4,
true,
false,
true,
false,
true,
false,
[10,20,30],
[false, true, false],
[1,2,3],
[1,3],
[2],
[1,2,3],
[1,2,3,4,5],
[1,2,3],
[1,2,3],
[1,2,3],
%{ :odd => [3,1], :even => [4,2] },
%{ 0 => [6, 3], 1 => [4, 1], 2 => [5, 2]},
[{1, :a}, {2, :b}, {3, :c}],
[{1, :a}, {2, :b}, {3, :c}],
2,
nil,
:no_such_element,
6
]
test_all(Enums, answers)
end
test "Arithmetic" do
answers = [
4,
3,
12,
3,
3,
2.5,
2,
1,
4,
1,
2
]
test_all(Arithmetic, answers)
end
test "Structs" do
answers = [
%Structs.Person{},
nil,
"Joe",
33,
23,
22,
true,
22,
]
test_all(Structs, answers)
end
test "Pattern Matching" do
answers = [
1,
2,
1,
1,
[2,3,4],
[1,2,3,4],
3,
"eggs, milk",
"Honda",
[1,2,3],
"Woof",
"Meow",
"Eh?",
"not present"
]
test_all(PatternMatching, answers)
end
test "Processes" do
answers = [
self,
:running,
"hola!",
:how_are_you?,
{:waited_too_long, "I am inpatient"},
false,
false,
{:exited, :random_reason},
true,
false,
{:exited, :normal},
{:exited, :normal}
]
test_all(Processes, answers)
end
test "Tasks" do
answers = [
10,
:todo,
nil,
nil,
9,
[1,4,9,16]
]
test_all(Tasks, answers)
end
test "Tuples" do
answers = [
3,
{:a, 1, "hi"},
"hi",
{:a, "bye"},
{:a, :new_thing, "hi"},
{"Huey", "Dewey", "Louie"},
{:this, :is, :awesome},
[:this, :can, :be, :a, :list]
]
test_all(Tuples, answers)
end
def test_all(module, answers) do
module.all_koans
|> Enum.zip(answers)