Packages
espec
0.3.0
1.10.0
1.9.2
1.9.1
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.0
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.1
1.0.0
0.8.28
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.2
0.4.1
0.4.0
0.3.7
0.3.5
0.3.0
0.2.0
0.1.0
BDD testing framework for Elixir inspired by RSpec.
Current section
Files
Jump to
Current section
Files
lib/espec/example.ex
defmodule ESpec.Example do
@moduledoc """
Defines macros 'example' and 'it'.
These macros defines function with random name which will be called when example runs.
Example structs %ESpec.Example are accumulated in @examples attribute
"""
@aliases ~w(it specify)a
@skipped ~w(xit xexample xspecify)a
@focused ~w(fit fexample fspecify focus)a
@doc """
Expampe struct.
description - the description of example,
module - spec module,
function - random function name,
opts - options,
file - spec file path,
line - the line where example is defined,
context - example context. Accumulator for 'contexts' and 'lets',
status - example status (:new, :success, :failure, :pending),
result - the value returned by example block or the pending message
error - store an error
"""
defstruct description: "", module: nil, function: nil, opts: [],
file: nil, line: nil, context: [],
status: :new, result: nil, error: %ESpec.AssertionError{}
@doc """
Adds example to @examples and defines function to wrap the spec.
Sends 'double-underscore `__`' variable to the example block.
"""
defmacro example(description, opts, do: block) do
function = (random_atom(description))
quote do
context = Enum.reverse(@context)
@examples %ESpec.Example{ description: unquote(description), module: __MODULE__, function: unquote(function),
opts: unquote(opts), file: __ENV__.file, line: __ENV__.line, context: context }
def unquote(function)(var!(__)), do: unquote(block)
end
end
@doc "Example with description only"
defmacro example(description, do: block) when is_binary(description) do
quote do: unquote(__MODULE__).example(unquote(description), [], do: unquote(block))
end
@doc "Example options only"
defmacro example(opts, do: block) when is_list(opts) do
quote do: unquote(__MODULE__).example("", unquote(opts), do: unquote(block))
end
@doc "Defines the simplest example"
defmacro example(do: block) do
quote do: unquote(__MODULE__).example("", [], do: unquote(block))
end
@doc "Aliases for `example`"
Enum.each @aliases, fn(func) ->
defmacro unquote(func)(description, opts, do: block) do
quote do: unquote(__MODULE__).example(unquote(description), unquote(opts), do: unquote(block))
end
defmacro unquote(func)(description_or_opts, do: block) do
quote do: unquote(__MODULE__).example(unquote(description_or_opts), do: unquote(block))
end
defmacro unquote(func)(do: block) do
quote do: unquote(__MODULE__).example(do: unquote(block))
end
end
@doc "Macros for skipped examples"
Enum.each @skipped, fn(func) ->
defmacro unquote(func)(description, opts, do: block) do
reason = "`#{unquote(func)}`"
quote do: unquote(__MODULE__).example(unquote(description), Keyword.put(unquote(opts), :skip, unquote(reason)), do: unquote(block))
end
defmacro unquote(func)(description, do: block) when is_binary(description) do
reason = "`#{unquote(func)}`"
quote do: unquote(__MODULE__).example(unquote(description), [skip: unquote(reason)], do: unquote(block))
end
defmacro unquote(func)(opts, do: block) when is_list(opts) do
reason = "`#{unquote(func)}`"
quote do: unquote(__MODULE__).example(Keyword.put(unquote(opts), :skip, unquote(reason)), do: unquote(block))
end
defmacro unquote(func)(do: block) do
reason = "`#{unquote(func)}`"
quote do: unquote(__MODULE__).example([skip: unquote(reason)], do: unquote(block))
end
end
@doc "Macros for focused examples"
Enum.each @focused, fn(func) ->
defmacro unquote(func)(description, opts, do: block) do
quote do: unquote(__MODULE__).example(unquote(description), Keyword.put(unquote(opts), :focus, true), do: unquote(block))
end
defmacro unquote(func)(description, do: block) when is_binary(description) do
quote do: unquote(__MODULE__).example(unquote(description), [focus: true], do: unquote(block))
end
defmacro unquote(func)(opts, do: block) when is_list(opts) do
quote do: unquote(__MODULE__).example(Keyword.put(unquote(opts), :focus, true), do: unquote(block))
end
defmacro unquote(func)(do: block) do
quote do: unquote(__MODULE__).example([focus: true], do: unquote(block))
end
end
@doc "Macros for pending exaples"
Enum.each [:example, :pending] ++ @aliases, fn(func) ->
defmacro unquote(func)(description) when is_binary(description) do
quote do: unquote(__MODULE__).example(unquote(description), [pending: unquote(description)], do: nil)
end
end
@doc "Description with contexts."
def full_description(%ESpec.Example{context: context, description: description, function: _function}) do
context_description = context
|> Enum.filter(fn(struct) -> struct.__struct__ == ESpec.Context end)
|> Enum.map(&(&1.description))
context_description ++ [description]
|> Enum.join(" ")
end
@doc "Filters success examples"
def success(results) do
results |> Enum.filter(&(&1.status == :success))
end
@doc "Filters failed examples"
def failure(results) do
results |> Enum.filter(&(&1.status === :failure))
end
@doc "Filters pending examples"
def pendings(results) do
results |> Enum.filter(&(&1.status === :pending))
end
def skip_message(example, contexts) do
skipper = Enum.find(contexts, &(&1.opts[:skip])) || example
if skipper.opts[:skip] === true do
"Temporarily skipped without a reason."
else
"Temporarily skipped with: #{skipper.opts[:skip]}."
end
end
def pending_message(example, _contexts) do
if example.opts[:pending] === true do
"Pending example."
else
"Pending with message: #{example.opts[:pending]}."
end
end
defp random_atom(arg) do
String.to_atom("example_#{ESpec.Support.word_chars(arg)}_#{ESpec.Support.random_string}")
end
end