Skip to content

Commit

Permalink
Allowed generated examples
Browse files Browse the repository at this point in the history
Examples can be generated via loops:
  subject 1..5

  Enum.map 1..3, fn(n) ->
    it do: is_expected().to have(unquote(n))
  end

Examples descriptions can contain interpolations:
  subject(24)

  Enum.map 2..4, fn(n) ->
    it "is divisible by #{n}" do
      expect(rem(subject(), unquote(n))).to be(0)
    end
  end
  • Loading branch information
andrei-mihaila committed Mar 5, 2017
1 parent 181815d commit cbacb36
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 11 deletions.
28 changes: 17 additions & 11 deletions lib/espec/example_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,36 @@ defmodule ESpec.ExampleHelpers do
Sends `shared`' variable to the example block.
"""
defmacro example(description, opts, do: block) do
function = random_atom(description)
quote do
block =
quote do
unquote(block)
end
|> Macro.escape(unquote: true)

quote bind_quoted: [description: description, opts: opts, block: block] do
f_name = random_atom(description)
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,
@examples %ESpec.Example{description: description, module: __MODULE__, function: f_name,
opts: opts, file: __ENV__.file, line: __ENV__.line, context: context,
shared: @shared}

def unquote(function)(var!(shared)) do
def unquote(f_name)(var!(shared)) do
var!(shared)
unquote(block)
end
end
end

@doc "Example with description only."
defmacro example(description, do: block) when is_binary(description) do
quote do: example(unquote(description), [], do: unquote(block))
end

@doc "Example options only"
defmacro example(opts, do: block) when is_list(opts) do
quote do: example("", unquote(opts), do: unquote(block))
end

@doc "Example with description only."
defmacro example(description, do: block) do
quote do: example(unquote(description), [], do: unquote(block))
end

@doc "Defines the simplest example."
defmacro example(do: block) do
quote do: example("", [], do: unquote(block))
Expand Down Expand Up @@ -145,7 +151,7 @@ defmodule ESpec.ExampleHelpers do
quote do: it_behaves_like(unquote(module), unquote(lets))
end

defp random_atom(arg) do
def random_atom(arg) do
String.to_atom("example_#{ESpec.Support.word_chars(arg)}_#{ESpec.Support.random_string}")
end
end
19 changes: 19 additions & 0 deletions spec/generated_examples_spec.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
defmodule GeneratedExamplesSpec do
use ESpec, async: true

subject 1..5

Enum.map 1..3, fn(n) ->
it do: is_expected().to have(unquote(n))
end

context "with description" do
subject(24)

Enum.map 2..4, fn(n) ->
it "is divisible by #{n}" do
expect(rem(subject(), unquote(n))).to be(0)
end
end
end
end
34 changes: 34 additions & 0 deletions test/generated_examples_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
defmodule GeneratedExamplesTest do
use ExUnit.Case, async: true

defmodule SomeSpec do
use ESpec

Enum.map 1..3, fn(idx) ->
it "fails, same name" do
expect(unquote(idx)) |> to(eq(0))
end

it "fails, different name #{idx}" do
expect(unquote(idx)) |> to(eq(-1))
end
end
end

setup_all do
ESpec.Runner.Queue.start(:input)
ESpec.Runner.Queue.start(:output)
:ok
end

test "runs all of them and they fail with the appropriate message" do
examples = ESpec.SuiteRunner.run(SomeSpec, %{}, false)

assert(Enum.map(examples, fn(e) -> e.error.message end) ==
Enum.map(3..1, fn(idx) ->
["Expected (==) `-1`, but got: `#{idx}`",
"Expected (==) `0`, but got: `#{idx}`"]
end)
|> List.flatten)
end
end

0 comments on commit cbacb36

Please sign in to comment.