Skip to content

Commit

Permalink
Check let in runtime antonmi#89
Browse files Browse the repository at this point in the history
  • Loading branch information
antonmi committed Apr 4, 2016
1 parent 8a7babd commit cb4023d
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 70 deletions.
2 changes: 2 additions & 0 deletions lib/espec.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ defmodule ESpec do
import ESpec.Context
@context [%ESpec.Context{ description: inspect(__MODULE__), module: __MODULE__, line: __ENV__.line, opts: unquote(args) }]
@defined_lets []

import ESpec.ExampleHelpers
import ESpec.DocTest, only: [doctest: 1, doctest: 2]

Expand All @@ -42,6 +43,7 @@ defmodule ESpec do
defmacro __before_compile__(_env) do
quote do
def examples, do: Enum.reverse(@examples)
def defined_lets, do: @defined_lets
end
end

Expand Down
3 changes: 1 addition & 2 deletions lib/espec/example_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ defmodule ESpec.ExampleHelpers do
opts: unquote(opts), file: __ENV__.file, line: __ENV__.line, context: context,
shared: @shared}

ESpec.Let.Checker.check(@context, @defined_lets, unquote(escaped_block))

def unquote(function)(var!(shared)) do
ESpec.Let.Checker.check(@context, __MODULE__, unquote(escaped_block))
var!(shared)
unquote(block)
end
Expand Down
3 changes: 2 additions & 1 deletion lib/espec/let/checker.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
defmodule ESpec.Let.Checker do
def check(context, defined_lets, escaped_block) do
def check(context, module, escaped_block) do
defined_lets = module.defined_lets
context_lets = context_lets(context)

diff = Enum.uniq(defined_lets) -- context_lets
Expand Down
79 changes: 52 additions & 27 deletions test/let/leaking_let_test.exs
Original file line number Diff line number Diff line change
@@ -1,39 +1,64 @@
defmodule LeakingLetTest do
use ExUnit.Case

@code1 (quote do
defmodule SomeSpec do
use ESpec
describe "first" do
let :a, do: 1
it do: expect a |> to(eq 1)
end
describe "second" do
it do: expect a |> to(eq 1)
end
defmodule SomeSpec do
use ESpec
describe "first" do
let :a, do: 1
it do: expect a |> to(eq 1)
end
end)

@code2 (quote do
defmodule SomeSpec do
use ESpec
describe "first" do
let :a, do: 1
it do: expect a |> to(eq 1)
end
describe "second" do
it do: expect a |> to(eq 1)
end
end)
it do: expect a |> to(eq 1)
end

test "code1" do
assert_raise ESpec.LetError, "The let function `a/0` is not defined in the current scope!", fn ->
Code.compile_quoted(@code1)
defmodule SomeSpec2 do
use ESpec
describe "second" do
it do: a |> should(eq 1)
end
describe "first" do
let :a, do: 1
it do: a |> should(eq 1)
end
end

test "code2" do
assert_raise ESpec.LetError, "The let function `a/0` is not defined in the current scope!", fn ->
Code.compile_quoted(@code2)
end
setup_all do
{:ok,
ex1: Enum.at(SomeSpec.examples, 0),
ex2: Enum.at(SomeSpec.examples, 1),
ex3: Enum.at(SomeSpec.examples, 2),

ex4: Enum.at(SomeSpec2.examples, 0),
ex5: Enum.at(SomeSpec2.examples, 1),
}
end

test "runs ex1 then ex2", context do
example = ESpec.ExampleRunner.run(context[:ex1])
assert example.status == :success

example = ESpec.ExampleRunner.run(context[:ex2])
assert example.status == :failure
assert example.error.message =~ "The let function `a/0` is not defined in the current scope!"
end

test "runs ex1 then ex3", context do
example = ESpec.ExampleRunner.run(context[:ex1])
assert example.status == :success

example = ESpec.ExampleRunner.run(context[:ex3])
assert example.status == :failure
assert example.error.message =~ "The let function `a/0` is not defined in the current scope!"
end

test "runs ex5 then ex4", context do
example = ESpec.ExampleRunner.run(context[:ex5])
assert example.status == :success

example = ESpec.ExampleRunner.run(context[:ex4])
assert example.status == :failure
assert example.error.message =~ "The let function `a/0` is not defined in the current scope!"
end
end
100 changes: 60 additions & 40 deletions test/let/leaking_subject_test.exs
Original file line number Diff line number Diff line change
@@ -1,58 +1,78 @@
defmodule LeakingSubjectTest do
use ExUnit.Case

@code1 (quote do
defmodule SomeSpec do
use ESpec
describe "first" do
subject do: []
it "is empty by default", do: should be_empty
end
defmodule SomeSpec do
use ESpec

it do: should be_empty
end
end)
describe "first" do
subject do: []

@code2 (quote do
defmodule SomeSpec do
use ESpec
describe "first" do
subject do: []
it "is empty by default", do: should be_empty
end
it "is empty by default", do: should be_empty
end

describe "second" do
it do: should be_empty
it do: is_expected |> to(be_empty)
it do: is_expected.to be_empty
end
end)

@code3 (quote do
defmodule SomeSpec do
use ESpec
describe "first" do
subject do: []
it "is empty by default", do: should be_empty
end
end

it do: is_expected.to be_empty
defmodule SomeSpec2 do
use ESpec
describe "second" do
it do: should(eq 1)
end
describe "first" do
subject do: 1
it do: should(eq 1)
end
end)
end

setup_all do
{:ok,
ex1: Enum.at(SomeSpec.examples, 0),
ex2: Enum.at(SomeSpec.examples, 1),
ex3: Enum.at(SomeSpec.examples, 2),
ex4: Enum.at(SomeSpec.examples, 3),

test "code1" do
assert_raise ESpec.LetError, "The subject is not defined in the current scope!", fn ->
Code.compile_quoted(@code1)
end
ex5: Enum.at(SomeSpec2.examples, 0),
ex6: Enum.at(SomeSpec2.examples, 1),
}
end

test "code2" do
assert_raise ESpec.LetError, "The subject is not defined in the current scope!", fn ->
Code.compile_quoted(@code2)
end
test "runs ex1 then ex2", context do
example = ESpec.ExampleRunner.run(context[:ex1])
assert example.status == :success

example = ESpec.ExampleRunner.run(context[:ex2])
assert example.status == :failure
assert example.error.message =~ "The subject is not defined in the current scope!"
end

test "code3" do
assert_raise ESpec.LetError, "The subject is not defined in the current scope!", fn ->
Code.compile_quoted(@code3)
end
test "runs ex1 then ex3", context do
example = ESpec.ExampleRunner.run(context[:ex1])
assert example.status == :success

example = ESpec.ExampleRunner.run(context[:ex3])
assert example.status == :failure
assert example.error.message =~ "The subject is not defined in the current scope!"
end

test "runs ex1 then ex4", context do
example = ESpec.ExampleRunner.run(context[:ex1])
assert example.status == :success

example = ESpec.ExampleRunner.run(context[:ex4])
assert example.status == :failure
assert example.error.message =~ "The subject is not defined in the current scope!"
end

test "runs ex6 then ex5", context do
example = ESpec.ExampleRunner.run(context[:ex6])
assert example.status == :success

example = ESpec.ExampleRunner.run(context[:ex5])
assert example.status == :failure
assert example.error.message =~ "The subject is not defined in the current scope!"
end
end

0 comments on commit cb4023d

Please sign in to comment.