Remove unused specs
These use types that no longer exist. The underlying types are in the Mocks shard and are tested there.
This commit is contained in:
parent
f81350a1fc
commit
e5fb4de4ae
|
@ -1,39 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::Allow do
|
||||
let(dbl) { Spectator::LazyDouble.new(foo: 42) }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 123) }
|
||||
subject(alw) { Spectator::Allow.new(dbl) }
|
||||
|
||||
describe "#to" do
|
||||
it "applies a stub" do
|
||||
expect { alw.to(stub) }.to change { dbl.foo }.from(42).to(123)
|
||||
end
|
||||
|
||||
context "leak" do
|
||||
class Thing
|
||||
def foo
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
mock Thing
|
||||
|
||||
getter(thing : Thing) { mock(Thing) }
|
||||
|
||||
# Workaround type restrictions requiring a constant.
|
||||
def fake
|
||||
class_mock(Thing).cast(thing)
|
||||
end
|
||||
|
||||
specify do
|
||||
expect { allow(fake).to(stub) }.to change { fake.foo }.from(42).to(123)
|
||||
end
|
||||
|
||||
# This example must be run after the previous (random order may break this).
|
||||
it "clears the stub after the example completes" do
|
||||
expect { fake.foo }.to eq(42)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,284 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::Arguments do
|
||||
subject(arguments) { Spectator::Arguments.new({42, "foo"}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it "stores the arguments" do
|
||||
expect(arguments).to have_attributes(
|
||||
args: {42, "foo"},
|
||||
kwargs: {bar: "baz", qux: 123}
|
||||
)
|
||||
end
|
||||
|
||||
describe ".capture" do
|
||||
subject { Spectator::Arguments.capture(42, "foo", bar: "baz", qux: 123) }
|
||||
|
||||
it "stores the arguments and keyword arguments" do
|
||||
is_expected.to have_attributes(args: {42, "foo"}, kwargs: {bar: "baz", qux: 123})
|
||||
end
|
||||
end
|
||||
|
||||
describe "#[](index)" do
|
||||
it "returns a positional argument" do
|
||||
aggregate_failures do
|
||||
expect(arguments[0]).to eq(42)
|
||||
expect(arguments[1]).to eq("foo")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#[](symbol)" do
|
||||
it "returns a keyword argument" do
|
||||
aggregate_failures do
|
||||
expect(arguments[:bar]).to eq("baz")
|
||||
expect(arguments[:qux]).to eq(123)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_s" do
|
||||
subject { arguments.to_s }
|
||||
|
||||
it "formats the arguments" do
|
||||
is_expected.to eq("(42, \"foo\", bar: \"baz\", qux: 123)")
|
||||
end
|
||||
|
||||
context "when empty" do
|
||||
let(arguments) { Spectator::Arguments.none }
|
||||
|
||||
it "returns (no args)" do
|
||||
is_expected.to eq("(no args)")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#==" do
|
||||
subject { arguments == other }
|
||||
|
||||
context "with Arguments" do
|
||||
context "with equal arguments" do
|
||||
let(other) { arguments }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with different arguments" do
|
||||
let(other) { Spectator::Arguments.new({123, :foo, "bar"}, {opt: "foobar"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with the same kwargs in a different order" do
|
||||
let(other) { Spectator::Arguments.new(arguments.args, {qux: 123, bar: "baz"}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with a missing kwarg" do
|
||||
let(other) { Spectator::Arguments.new(arguments.args, {bar: "baz"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with an extra kwarg" do
|
||||
let(other) { Spectator::Arguments.new(arguments.args, {bar: "baz", qux: 123, extra: 0}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context "with FormalArguments" do
|
||||
context "with equal arguments" do
|
||||
let(other) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with different arguments" do
|
||||
let(other) { Spectator::FormalArguments.new({arg1: 123, arg2: :foo, arg3: "bar"}, {opt: "foobar"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with the same kwargs in a different order" do
|
||||
let(other) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, {qux: 123, bar: "baz"}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with a missing kwarg" do
|
||||
let(other) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, {bar: "baz"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with an extra kwarg" do
|
||||
let(other) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, {bar: "baz", qux: 123, extra: 0}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with different splat arguments" do
|
||||
let(other) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {1, 2, 3}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with mixed positional tuple types" do
|
||||
let(other) { Spectator::FormalArguments.new({arg1: 42}, :splat, {"foo"}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#===" do
|
||||
subject { pattern === arguments }
|
||||
|
||||
context "with Arguments" do
|
||||
context "with equal arguments" do
|
||||
let(pattern) { arguments }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with matching arguments" do
|
||||
let(pattern) { Spectator::Arguments.new({Int32, /foo/}, {bar: /baz/, qux: Int32}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with non-matching arguments" do
|
||||
let(pattern) { Spectator::Arguments.new({Float64, /bar/}, {bar: /foo/, qux: "123"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with different arguments" do
|
||||
let(pattern) { Spectator::Arguments.new({123, :foo, "bar"}, {opt: "foobar"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with the same kwargs in a different order" do
|
||||
let(pattern) { Spectator::Arguments.new(arguments.args, {qux: Int32, bar: /baz/}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with an additional kwarg" do
|
||||
let(pattern) { Spectator::Arguments.new(arguments.args, {bar: /baz/}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with a missing kwarg" do
|
||||
let(pattern) { Spectator::Arguments.new(arguments.args, {bar: /baz/, qux: Int32, extra: 0}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context "with FormalArguments" do
|
||||
let(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, {bar: "baz", qux: 123}) }
|
||||
|
||||
context "with equal arguments" do
|
||||
let(pattern) { Spectator::Arguments.new({42, "foo"}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with matching arguments" do
|
||||
let(pattern) { Spectator::Arguments.new({Int32, /foo/}, {bar: /baz/, qux: Int32}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with non-matching arguments" do
|
||||
let(pattern) { Spectator::Arguments.new({Float64, /bar/}, {bar: /foo/, qux: "123"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with different arguments" do
|
||||
let(pattern) { Spectator::Arguments.new({123, :foo, "bar"}, {opt: "foobar"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with the same kwargs in a different order" do
|
||||
let(pattern) { Spectator::Arguments.new(arguments.positional, {qux: Int32, bar: /baz/}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with an additional kwarg" do
|
||||
let(pattern) { Spectator::Arguments.new(arguments.positional, {bar: /baz/}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with a missing kwarg" do
|
||||
let(pattern) { Spectator::Arguments.new(arguments.positional, {bar: /baz/, qux: Int32, extra: 0}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with different splat arguments" do
|
||||
let(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {1, 2, 3}, super.kwargs) }
|
||||
let(pattern) { Spectator::Arguments.new({Int32, /foo/, 5}, arguments.kwargs) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with matching mixed positional tuple types" do
|
||||
let(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {1, 2, 3}, super.kwargs) }
|
||||
let(pattern) { Spectator::Arguments.new({Int32, /foo/, 1, 2, 3}, arguments.kwargs) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with non-matching mixed positional tuple types" do
|
||||
let(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {1, 2, 3}, super.kwargs) }
|
||||
let(pattern) { Spectator::Arguments.new({Float64, /bar/, 3, 2, Symbol}, arguments.kwargs) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with matching args spilling over into splat and mixed positional tuple types" do
|
||||
let(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
let(pattern) { Spectator::Arguments.capture(Int32, /foo/, Symbol, Symbol, :z, bar: /baz/, qux: Int32) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with non-matching args spilling over into splat and mixed positional tuple types" do
|
||||
let(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
let(pattern) { Spectator::Arguments.capture(Float64, /bar/, Symbol, String, :z, bar: /foo/, qux: Int32) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with matching mixed named positional and keyword arguments" do
|
||||
let(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
let(pattern) { Spectator::Arguments.capture(/foo/, Symbol, :y, Symbol, arg1: Int32, bar: /baz/, qux: 123) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with non-matching mixed named positional and keyword arguments" do
|
||||
let(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
let(pattern) { Spectator::Arguments.capture(5, Symbol, :z, Symbol, arg2: /foo/, bar: /baz/, qux: Int32) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with non-matching mixed named positional and keyword arguments" do
|
||||
let(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
let(pattern) { Spectator::Arguments.capture(/bar/, String, :y, Symbol, arg1: 0, bar: /foo/, qux: Float64) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,542 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::Double do
|
||||
Spectator::Double.define(EmptyDouble)
|
||||
Spectator::Double.define(FooBarDouble, "dbl-name", foo: 42, bar: "baz")
|
||||
|
||||
# The subject `dbl` must be carefully used in sub-contexts, otherwise it pollutes parent scopes.
|
||||
# This changes the type of `dbl` to `Double+`, which produces a union of methods and their return types.
|
||||
context "plain double" do
|
||||
subject(dbl) { FooBarDouble.new }
|
||||
|
||||
it "responds to defined messages" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to eq(42)
|
||||
expect(dbl.bar).to eq("baz")
|
||||
end
|
||||
end
|
||||
|
||||
it "fails on undefined messages" do
|
||||
expect { dbl.baz }.to raise_error(Spectator::UnexpectedMessage, /baz/)
|
||||
end
|
||||
|
||||
it "reports the name in errors" do
|
||||
expect { dbl.baz }.to raise_error(/"dbl-name"/)
|
||||
end
|
||||
|
||||
it "reports arguments" do
|
||||
expect { dbl.baz(123, "qux", field: :value) }.to raise_error(Spectator::UnexpectedMessage, /\(123, "qux", field: :value\)/)
|
||||
end
|
||||
|
||||
it "has a non-union return type" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to compile_as(Int32)
|
||||
expect(dbl.bar).to compile_as(String)
|
||||
end
|
||||
end
|
||||
|
||||
it "uses nil for undefined messages" do
|
||||
expect { dbl.baz }.to compile_as(Nil)
|
||||
end
|
||||
|
||||
context "blocks" do
|
||||
it "supports blocks" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo { nil }).to eq(42)
|
||||
expect(dbl.bar { nil }).to eq("baz")
|
||||
end
|
||||
end
|
||||
|
||||
it "supports blocks and has non-union return types" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo { nil }).to compile_as(Int32)
|
||||
expect(dbl.bar { nil }).to compile_as(String)
|
||||
end
|
||||
end
|
||||
|
||||
it "fails on undefined messages" do
|
||||
expect do
|
||||
dbl.baz { nil }
|
||||
end.to raise_error(Spectator::UnexpectedMessage, /baz/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "without a double name" do
|
||||
Spectator::Double.define(NamelessDouble, foo: 42)
|
||||
|
||||
subject(dbl) { NamelessDouble.new }
|
||||
|
||||
it "reports as anonymous" do
|
||||
expect { dbl.baz }.to raise_error(/anonymous/i)
|
||||
end
|
||||
end
|
||||
|
||||
context "with abstract stubs and return type annotations" do
|
||||
Spectator::Double.define(TestDouble) do
|
||||
stub abstract def foo(value) : String
|
||||
end
|
||||
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, "bar", arguments).as(Spectator::Stub) }
|
||||
subject(dbl) { TestDouble.new([stub]) }
|
||||
|
||||
it "enforces the return type" do
|
||||
expect(dbl.foo("foobar")).to compile_as(String)
|
||||
end
|
||||
|
||||
it "raises on non-matching arguments" do
|
||||
expect { dbl.foo("bar") }.to raise_error(Spectator::UnexpectedMessage, /foo/)
|
||||
end
|
||||
|
||||
it "raises on non-matching stub" do
|
||||
stub = Spectator::ValueStub.new(:foo, 42, arguments).as(Spectator::Stub)
|
||||
dbl._spectator_define_stub(stub)
|
||||
expect { dbl.foo("foobar") }.to raise_error(TypeCastError, /String/)
|
||||
end
|
||||
end
|
||||
|
||||
context "with nillable return type annotations" do
|
||||
Spectator::Double.define(TestDouble) do
|
||||
stub abstract def foo : String?
|
||||
stub abstract def bar : Nil
|
||||
end
|
||||
|
||||
let(foo_stub) { Spectator::ValueStub.new(:foo, nil).as(Spectator::Stub) }
|
||||
let(bar_stub) { Spectator::ValueStub.new(:bar, nil).as(Spectator::Stub) }
|
||||
subject(dbl) { TestDouble.new([foo_stub, bar_stub]) }
|
||||
|
||||
it "doesn't raise on nil" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to be_nil
|
||||
expect(dbl.bar).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a method that uses NoReturn" do
|
||||
Spectator::Double.define(NoReturnDouble) do
|
||||
stub abstract def oops : NoReturn
|
||||
end
|
||||
|
||||
subject(dbl) { NoReturnDouble.new }
|
||||
|
||||
it "raises a TypeCastError when using a value-based stub" do
|
||||
stub = Spectator::ValueStub.new(:oops, nil).as(Spectator::Stub)
|
||||
dbl._spectator_define_stub(stub)
|
||||
expect { dbl.oops }.to raise_error(TypeCastError, /NoReturn/)
|
||||
end
|
||||
|
||||
it "raises when using an exception stub" do
|
||||
exception = ArgumentError.new("bogus")
|
||||
stub = Spectator::ExceptionStub.new(:oops, exception).as(Spectator::Stub)
|
||||
dbl._spectator_define_stub(stub)
|
||||
expect { dbl.oops }.to raise_error(ArgumentError, "bogus")
|
||||
end
|
||||
end
|
||||
|
||||
context "with common object methods" do
|
||||
subject(dbl) do
|
||||
EmptyDouble.new([
|
||||
Spectator::ValueStub.new(:"!=", false),
|
||||
Spectator::ValueStub.new(:"!~", false),
|
||||
Spectator::ValueStub.new(:"==", true),
|
||||
Spectator::ValueStub.new(:"===", true),
|
||||
Spectator::ValueStub.new(:"=~", nil),
|
||||
Spectator::ValueStub.new(:class, EmptyDouble),
|
||||
Spectator::ValueStub.new(:dup, EmptyDouble.new),
|
||||
Spectator::ValueStub.new(:"in?", true),
|
||||
Spectator::ValueStub.new(:inspect, "inspect"),
|
||||
Spectator::ValueStub.new(:itself, EmptyDouble.new),
|
||||
Spectator::ValueStub.new(:"not_nil!", EmptyDouble.new),
|
||||
Spectator::ValueStub.new(:pretty_inspect, "pretty_inspect"),
|
||||
Spectator::ValueStub.new(:tap, EmptyDouble.new),
|
||||
Spectator::ValueStub.new(:to_json, "to_json"),
|
||||
Spectator::ValueStub.new(:to_pretty_json, "to_pretty_json"),
|
||||
Spectator::ValueStub.new(:to_s, "to_s"),
|
||||
Spectator::ValueStub.new(:to_yaml, "to_yaml"),
|
||||
Spectator::ValueStub.new(:try, nil),
|
||||
Spectator::ValueStub.new(:object_id, 42_u64),
|
||||
Spectator::ValueStub.new(:"same?", true),
|
||||
] of Spectator::Stub)
|
||||
end
|
||||
|
||||
it "responds with defined messages" do
|
||||
aggregate_failures do
|
||||
expect(dbl.!=(42)).to be_false
|
||||
expect(dbl.!~(42)).to be_false
|
||||
expect(dbl.==(42)).to be_true
|
||||
expect(dbl.===(42)).to be_true
|
||||
expect(dbl.=~(42)).to be_nil
|
||||
expect(dbl.class).to eq(EmptyDouble)
|
||||
expect(dbl.dup).to be_a(EmptyDouble)
|
||||
expect(dbl.in?([42])).to eq(true)
|
||||
expect(dbl.in?(1, 2, 3)).to eq(true)
|
||||
expect(dbl.inspect).to eq("inspect")
|
||||
expect(dbl.itself).to be_a(EmptyDouble)
|
||||
expect(dbl.not_nil!).to be_a(EmptyDouble)
|
||||
expect(dbl.pretty_inspect).to eq("pretty_inspect")
|
||||
expect(dbl.tap { nil }).to be_a(EmptyDouble)
|
||||
expect(dbl.to_json).to eq("to_json")
|
||||
expect(dbl.to_pretty_json).to eq("to_pretty_json")
|
||||
expect(dbl.to_s).to eq("to_s")
|
||||
expect(dbl.to_yaml).to eq("to_yaml")
|
||||
expect(dbl.try { nil }).to be_nil
|
||||
expect(dbl.object_id).to eq(42_u64)
|
||||
expect(dbl.same?(dbl)).to be_true
|
||||
expect(dbl.same?(nil)).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
it "has a non-union return type" do
|
||||
expect(dbl.inspect).to compile_as(String)
|
||||
end
|
||||
end
|
||||
|
||||
context "without common object methods" do
|
||||
subject(dbl) { EmptyDouble.new }
|
||||
|
||||
it "returns original implementation with undefined messages" do
|
||||
io = IO::Memory.new
|
||||
pp = PrettyPrint.new(io)
|
||||
hasher = Crystal::Hasher.new
|
||||
aggregate_failures do
|
||||
expect(dbl.!=(42)).to be_true
|
||||
expect(dbl.!~(42)).to be_true
|
||||
expect(dbl.==(42)).to be_false
|
||||
expect(dbl.===(42)).to be_false
|
||||
expect(dbl.=~(42)).to be_nil
|
||||
expect(dbl.class).to eq(EmptyDouble)
|
||||
expect(dbl.dup).to be_a(EmptyDouble)
|
||||
expect(dbl.hash(hasher)).to be_a(Crystal::Hasher)
|
||||
expect(dbl.hash).to be_a(UInt64)
|
||||
expect(dbl.in?([42])).to be_false
|
||||
expect(dbl.in?(1, 2, 3)).to be_false
|
||||
expect(dbl.itself).to be(dbl)
|
||||
expect(dbl.not_nil!).to be(dbl)
|
||||
expect(dbl.pretty_print(pp)).to be_nil
|
||||
expect(dbl.tap { nil }).to be(dbl)
|
||||
expect(dbl.try { nil }).to be_nil
|
||||
expect(dbl.object_id).to be_a(UInt64)
|
||||
expect(dbl.same?(dbl)).to be_true
|
||||
expect(dbl.same?(nil)).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
it "reports arguments when they don't match" do
|
||||
expect { dbl.same?(123, :xyz) }.to raise_error(Spectator::UnexpectedMessage, /\(123, :xyz\)/)
|
||||
end
|
||||
end
|
||||
|
||||
context "with arguments constraints" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
|
||||
context "without common object methods" do
|
||||
Spectator::Double.define(TestDouble) do
|
||||
stub abstract def foo(value) : String
|
||||
stub abstract def foo(value, & : -> _) : String
|
||||
end
|
||||
|
||||
let(stub) { Spectator::ValueStub.new(:foo, "bar", arguments).as(Spectator::Stub) }
|
||||
subject(dbl) { TestDouble.new([stub]) }
|
||||
|
||||
it "returns the response when constraint satisfied" do
|
||||
expect(dbl.foo("foobar")).to eq("bar")
|
||||
end
|
||||
|
||||
it "raises an error when constraint unsatisfied" do
|
||||
expect { dbl.foo("baz") }.to raise_error(Spectator::UnexpectedMessage)
|
||||
end
|
||||
|
||||
it "raises an error when argument count doesn't match" do
|
||||
expect { dbl.foo }.to raise_error(Spectator::UnexpectedMessage)
|
||||
end
|
||||
|
||||
it "has a non-union return type" do
|
||||
expect(dbl.foo("foobar")).to compile_as(String)
|
||||
end
|
||||
|
||||
it "ignores the block argument if not in the constraint" do
|
||||
expect(dbl.foo("foobar") { nil }).to eq("bar")
|
||||
end
|
||||
end
|
||||
|
||||
context "with common object methods" do
|
||||
Spectator::Double.define(TestDouble) do
|
||||
stub abstract def same?(other : Reference) : Bool
|
||||
end
|
||||
|
||||
let(stub) { Spectator::ValueStub.new(:"same?", true, arguments).as(Spectator::Stub) }
|
||||
subject(dbl) { TestDouble.new([stub]) }
|
||||
|
||||
it "returns the response when constraint satisfied" do
|
||||
expect(dbl.same?("foobar")).to eq(true)
|
||||
end
|
||||
|
||||
it "raises an error when constraint unsatisfied" do
|
||||
expect { dbl.same?("baz") }.to raise_error(Spectator::UnexpectedMessage)
|
||||
end
|
||||
|
||||
it "raises an error when argument count doesn't match" do
|
||||
expect { dbl.same? }.to raise_error(Spectator::UnexpectedMessage)
|
||||
end
|
||||
|
||||
it "has a non-union return type" do
|
||||
expect(dbl.same?("foobar")).to compile_as(Bool)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "class method stubs" do
|
||||
Spectator::Double.define(ClassDouble) do
|
||||
stub def self.foo
|
||||
:stub
|
||||
end
|
||||
|
||||
stub def self.bar(arg)
|
||||
arg
|
||||
end
|
||||
|
||||
stub def self.baz(arg, &)
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
subject(dbl) { ClassDouble }
|
||||
let(foo_stub) { Spectator::ValueStub.new(:foo, :override) }
|
||||
|
||||
after { dbl._spectator_clear_stubs }
|
||||
|
||||
it "overrides an existing method" do
|
||||
expect { dbl._spectator_define_stub(foo_stub) }.to change { dbl.foo }.from(:stub).to(:override)
|
||||
end
|
||||
|
||||
it "doesn't affect other methods" do
|
||||
expect { dbl._spectator_define_stub(foo_stub) }.to_not change { dbl.bar(42) }
|
||||
end
|
||||
|
||||
it "replaces an existing stub" do
|
||||
dbl._spectator_define_stub(foo_stub)
|
||||
stub = Spectator::ValueStub.new(:foo, :replacement)
|
||||
expect { dbl._spectator_define_stub(stub) }.to change { dbl.foo }.to(:replacement)
|
||||
end
|
||||
|
||||
it "picks the correct stub based on arguments" do
|
||||
stub1 = Spectator::ValueStub.new(:bar, :fallback)
|
||||
stub2 = Spectator::ValueStub.new(:bar, :override, Spectator::Arguments.capture(:match))
|
||||
dbl._spectator_define_stub(stub1)
|
||||
dbl._spectator_define_stub(stub2)
|
||||
aggregate_failures do
|
||||
expect(dbl.bar(:wrong)).to eq(:fallback)
|
||||
expect(dbl.bar(:match)).to eq(:override)
|
||||
end
|
||||
end
|
||||
|
||||
it "only uses a stub if an argument constraint is met" do
|
||||
stub = Spectator::ValueStub.new(:bar, :override, Spectator::Arguments.capture(:match))
|
||||
dbl._spectator_define_stub(stub)
|
||||
aggregate_failures do
|
||||
expect(dbl.bar(:original)).to eq(:original)
|
||||
expect(dbl.bar(:match)).to eq(:override)
|
||||
end
|
||||
end
|
||||
|
||||
it "ignores the block argument if not in the constraint" do
|
||||
stub1 = Spectator::ValueStub.new(:baz, 1)
|
||||
stub2 = Spectator::ValueStub.new(:baz, 2, Spectator::Arguments.capture(3))
|
||||
dbl._spectator_define_stub(stub1)
|
||||
dbl._spectator_define_stub(stub2)
|
||||
aggregate_failures do
|
||||
expect(dbl.baz(5) { 42 }).to eq(1)
|
||||
expect(dbl.baz(3) { 42 }).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe "._spectator_clear_stubs" do
|
||||
before { dbl._spectator_define_stub(foo_stub) }
|
||||
|
||||
it "removes previously defined stubs" do
|
||||
expect { dbl._spectator_clear_stubs }.to change { dbl.foo }.from(:override).to(:stub)
|
||||
end
|
||||
end
|
||||
|
||||
describe "._spectator_calls" do
|
||||
before { dbl._spectator_clear_calls }
|
||||
|
||||
# Retrieves symbolic names of methods called on a double.
|
||||
def called_method_names(dbl)
|
||||
dbl._spectator_calls.map(&.method)
|
||||
end
|
||||
|
||||
it "stores calls to stubbed methods" do
|
||||
expect { dbl.foo }.to change { called_method_names(dbl) }.from(%i[]).to(%i[foo])
|
||||
end
|
||||
|
||||
it "stores multiple calls to the same stub" do
|
||||
dbl.foo
|
||||
expect { dbl.foo }.to change { called_method_names(dbl) }.from(%i[foo]).to(%i[foo foo])
|
||||
end
|
||||
|
||||
it "stores arguments for a call" do
|
||||
dbl.bar(42)
|
||||
args = Spectator::Arguments.capture(42)
|
||||
call = dbl._spectator_calls.first
|
||||
expect(call.arguments).to eq(args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#_spectator_define_stub" do
|
||||
subject(dbl) { FooBarDouble.new }
|
||||
let(stub3) { Spectator::ValueStub.new(:foo, 3) }
|
||||
let(stub5) { Spectator::ValueStub.new(:foo, 5) }
|
||||
let(stub7) { Spectator::ValueStub.new(:foo, 7, Spectator::Arguments.capture(:lucky)) }
|
||||
|
||||
it "overrides an existing method" do
|
||||
expect { dbl._spectator_define_stub(stub3) }.to change { dbl.foo }.from(42).to(3)
|
||||
end
|
||||
|
||||
it "replaces an existing stub" do
|
||||
dbl._spectator_define_stub(stub3)
|
||||
expect { dbl._spectator_define_stub(stub5) }.to change { dbl.foo }.from(3).to(5)
|
||||
end
|
||||
|
||||
it "doesn't affect other methods" do
|
||||
expect { dbl._spectator_define_stub(stub5) }.to_not change { dbl.bar }
|
||||
end
|
||||
|
||||
it "picks the correct stub based on arguments" do
|
||||
dbl._spectator_define_stub(stub5)
|
||||
dbl._spectator_define_stub(stub7)
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to eq(5)
|
||||
expect(dbl.foo(:lucky)).to eq(7)
|
||||
end
|
||||
end
|
||||
|
||||
it "only uses a stub if an argument constraint is met" do
|
||||
dbl._spectator_define_stub(stub7)
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to eq(42)
|
||||
expect(dbl.foo(:lucky)).to eq(7)
|
||||
end
|
||||
end
|
||||
|
||||
it "ignores the block argument if not in the constraint" do
|
||||
dbl._spectator_define_stub(stub5)
|
||||
dbl._spectator_define_stub(stub7)
|
||||
aggregate_failures do
|
||||
expect(dbl.foo { nil }).to eq(5)
|
||||
expect(dbl.foo(:lucky) { nil }).to eq(7)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#_spectator_clear_stubs" do
|
||||
subject(dbl) { FooBarDouble.new }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 5) }
|
||||
|
||||
before { dbl._spectator_define_stub(stub) }
|
||||
|
||||
it "removes previously defined stubs" do
|
||||
expect { dbl._spectator_clear_stubs }.to change { dbl.foo }.from(5).to(42)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#_spectator_calls" do
|
||||
subject(dbl) { FooBarDouble.new }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 5) }
|
||||
|
||||
before { dbl._spectator_define_stub(stub) }
|
||||
|
||||
# Retrieves symbolic names of methods called on a double.
|
||||
def called_method_names(dbl)
|
||||
dbl._spectator_calls.map(&.method)
|
||||
end
|
||||
|
||||
it "stores calls to stubbed methods" do
|
||||
expect { dbl.foo }.to change { called_method_names(dbl) }.from(%i[]).to(%i[foo])
|
||||
end
|
||||
|
||||
it "stores multiple calls to the same stub" do
|
||||
dbl.foo
|
||||
expect { dbl.foo }.to change { called_method_names(dbl) }.from(%i[foo]).to(%i[foo foo])
|
||||
end
|
||||
|
||||
it "stores calls to non-stubbed methods" do
|
||||
expect { dbl.baz }.to raise_error(Spectator::UnexpectedMessage, /baz/)
|
||||
expect(called_method_names(dbl)).to contain(:baz)
|
||||
end
|
||||
|
||||
it "stores arguments for a call" do
|
||||
dbl.foo(42)
|
||||
args = Spectator::Arguments.capture(42)
|
||||
call = dbl._spectator_calls.first
|
||||
expect(call.arguments).to eq(args)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_s" do
|
||||
subject(string) { dbl.to_s }
|
||||
|
||||
context "with a name" do
|
||||
let(dbl) { FooBarDouble.new }
|
||||
|
||||
it "indicates it's a double" do
|
||||
expect(string).to contain("Double")
|
||||
end
|
||||
|
||||
it "contains the double name" do
|
||||
expect(string).to contain("dbl-name")
|
||||
end
|
||||
end
|
||||
|
||||
context "without a name" do
|
||||
let(dbl) { EmptyDouble.new }
|
||||
|
||||
it "indicates it's a double" do
|
||||
expect(string).to contain("Double")
|
||||
end
|
||||
|
||||
it "contains \"Anonymous\"" do
|
||||
expect(string).to contain("Anonymous")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#inspect" do
|
||||
subject(string) { dbl.inspect }
|
||||
|
||||
context "with a name" do
|
||||
let(dbl) { FooBarDouble.new }
|
||||
|
||||
it "indicates it's a double" do
|
||||
expect(string).to contain("Double")
|
||||
end
|
||||
|
||||
it "contains the double name" do
|
||||
expect(string).to contain("dbl-name")
|
||||
end
|
||||
|
||||
it "contains the object ID" do
|
||||
expect(string).to contain(dbl.object_id.to_s(16))
|
||||
end
|
||||
end
|
||||
|
||||
context "without a name" do
|
||||
let(dbl) { EmptyDouble.new }
|
||||
|
||||
it "indicates it's a double" do
|
||||
expect(string).to contain("Double")
|
||||
end
|
||||
|
||||
it "contains \"Anonymous\"" do
|
||||
expect(string).to contain("Anonymous")
|
||||
end
|
||||
|
||||
it "contains the object ID" do
|
||||
expect(string).to contain(dbl.object_id.to_s(16))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,166 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::ExceptionStub do
|
||||
let(method_call) { Spectator::MethodCall.capture(:foo) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(exception) { RuntimeError.new("Test exception") }
|
||||
subject(stub) { described_class.new(:foo, exception, location: location) }
|
||||
|
||||
it "stores the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "stores the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
|
||||
it "raises the specified exception" do
|
||||
expect { stub.call(method_call) }.to raise_error(RuntimeError, "Test exception")
|
||||
end
|
||||
|
||||
context Spectator::StubModifiers do
|
||||
describe "#and_return(value)" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::ExceptionStub.new(:foo, exception, arguments, location) }
|
||||
subject(stub) { original.and_return(123) }
|
||||
|
||||
it "produces a stub that returns a value" do
|
||||
expect(stub.call(method_call)).to eq(123)
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#and_return(*values)" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::ExceptionStub.new(:foo, exception, arguments, location) }
|
||||
subject(stub) { original.and_return(3, 2, 1, 0) }
|
||||
|
||||
it "produces a stub that returns values" do
|
||||
values = Array.new(5) { stub.call(method_call) }
|
||||
expect(values).to eq([3, 2, 1, 0, 0])
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#and_raise" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::ExceptionStub.new(:foo, exception, arguments, location) }
|
||||
let(new_exception) { ArgumentError.new("Test argument error") }
|
||||
subject(stub) { original.and_raise(new_exception) }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError, "Test argument error")
|
||||
end
|
||||
|
||||
context "with a class and message" do
|
||||
subject(stub) { original.and_raise(ArgumentError, "Test argument error") }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError, "Test argument error")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a message" do
|
||||
subject(stub) { original.and_raise("Test exception") }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(Exception, "Test exception")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a class" do
|
||||
subject(stub) { original.and_raise(ArgumentError) }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#===" do
|
||||
subject { stub === call }
|
||||
|
||||
context "with a matching method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "foobar") }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:bar, "foobar") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "with a constraint" do
|
||||
let(constraint) { Spectator::Arguments.capture(/foo/) }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 42, constraint) }
|
||||
|
||||
context "with a matching method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "foobar") }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
|
||||
context "with a non-matching arguments" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "baz") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:bar, "foobar") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,325 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::FormalArguments do
|
||||
subject(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it "stores the arguments" do
|
||||
expect(arguments).to have_attributes(
|
||||
args: {arg1: 42, arg2: "foo"},
|
||||
splat_name: :splat,
|
||||
splat: {:x, :y, :z},
|
||||
kwargs: {bar: "baz", qux: 123}
|
||||
)
|
||||
end
|
||||
|
||||
describe ".build" do
|
||||
subject { Spectator::FormalArguments.build({arg1: 42, arg2: "foo"}, :splat, {1, 2, 3}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it "stores the arguments and keyword arguments" do
|
||||
is_expected.to have_attributes(
|
||||
args: {arg1: 42, arg2: "foo"},
|
||||
splat_name: :splat,
|
||||
splat: {1, 2, 3},
|
||||
kwargs: {bar: "baz", qux: 123}
|
||||
)
|
||||
end
|
||||
|
||||
context "without a splat" do
|
||||
subject { Spectator::FormalArguments.build({arg1: 42, arg2: "foo"}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it "stores the arguments and keyword arguments" do
|
||||
is_expected.to have_attributes(
|
||||
args: {arg1: 42, arg2: "foo"},
|
||||
splat: nil,
|
||||
kwargs: {bar: "baz", qux: 123}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#[](index)" do
|
||||
it "returns a positional argument" do
|
||||
aggregate_failures do
|
||||
expect(arguments[0]).to eq(42)
|
||||
expect(arguments[1]).to eq("foo")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns splat arguments" do
|
||||
aggregate_failures do
|
||||
expect(arguments[2]).to eq(:x)
|
||||
expect(arguments[3]).to eq(:y)
|
||||
expect(arguments[4]).to eq(:z)
|
||||
end
|
||||
end
|
||||
|
||||
context "with named positional arguments" do
|
||||
subject(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it "returns a positional argument" do
|
||||
aggregate_failures do
|
||||
expect(arguments[0]).to eq(42)
|
||||
expect(arguments[1]).to eq("foo")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns splat arguments" do
|
||||
aggregate_failures do
|
||||
expect(arguments[2]).to eq(:x)
|
||||
expect(arguments[3]).to eq(:y)
|
||||
expect(arguments[4]).to eq(:z)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#[](symbol)" do
|
||||
it "returns a keyword argument" do
|
||||
aggregate_failures do
|
||||
expect(arguments[:bar]).to eq("baz")
|
||||
expect(arguments[:qux]).to eq(123)
|
||||
end
|
||||
end
|
||||
|
||||
context "with named positional arguments" do
|
||||
subject(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it "returns a positional argument" do
|
||||
aggregate_failures do
|
||||
expect(arguments[:arg1]).to eq(42)
|
||||
expect(arguments[:arg2]).to eq("foo")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns a keyword argument" do
|
||||
aggregate_failures do
|
||||
expect(arguments[:bar]).to eq("baz")
|
||||
expect(arguments[:qux]).to eq(123)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_s" do
|
||||
subject { arguments.to_s }
|
||||
|
||||
it "formats the arguments" do
|
||||
is_expected.to eq("(arg1: 42, arg2: \"foo\", *splat: {:x, :y, :z}, bar: \"baz\", qux: 123)")
|
||||
end
|
||||
|
||||
context "when empty" do
|
||||
let(arguments) { Spectator::FormalArguments.none }
|
||||
|
||||
it "returns (no args)" do
|
||||
is_expected.to eq("(no args)")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a splat and no arguments" do
|
||||
let(arguments) { Spectator::FormalArguments.build(NamedTuple.new, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it "omits the splat name" do
|
||||
is_expected.to eq("(:x, :y, :z, bar: \"baz\", qux: 123)")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#==" do
|
||||
subject { arguments == other }
|
||||
|
||||
context "with Arguments" do
|
||||
context "with equal arguments" do
|
||||
let(other) { Spectator::Arguments.new(arguments.positional, arguments.kwargs) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with different arguments" do
|
||||
let(other) { Spectator::Arguments.new({123, :foo, "bar"}, {opt: "foobar"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with the same kwargs in a different order" do
|
||||
let(other) { Spectator::Arguments.new(arguments.positional, {qux: 123, bar: "baz"}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with a missing kwarg" do
|
||||
let(other) { Spectator::Arguments.new(arguments.positional, {bar: "baz"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with an extra kwarg" do
|
||||
let(other) { Spectator::Arguments.new(arguments.positional, {bar: "baz", qux: 123, extra: 0}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context "with FormalArguments" do
|
||||
context "with equal arguments" do
|
||||
let(other) { arguments }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with different arguments" do
|
||||
let(other) { Spectator::FormalArguments.new({arg1: 123, arg2: :foo, arg3: "bar"}, :splat, {1, 2, 3}, {opt: "foobar"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with the same kwargs in a different order" do
|
||||
let(other) { Spectator::FormalArguments.new(arguments.args, arguments.splat_name, arguments.splat, {qux: 123, bar: "baz"}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with a missing kwarg" do
|
||||
let(other) { Spectator::FormalArguments.new(arguments.args, arguments.splat_name, arguments.splat, {bar: "baz"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with an extra kwarg" do
|
||||
let(other) { Spectator::FormalArguments.new(arguments.args, arguments.splat_name, arguments.splat, {bar: "baz", qux: 123, extra: 0}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with different splat arguments" do
|
||||
let(other) { Spectator::FormalArguments.new(arguments.args, arguments.splat_name, {1, 2, 3}, arguments.kwargs) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with mixed positional tuple types" do
|
||||
let(other) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, arguments.splat_name, arguments.splat, arguments.kwargs) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with mixed positional tuple types (flipped)" do
|
||||
let(arguments) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
let(other) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, :splat, {:x, :y, :z}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#===" do
|
||||
subject { pattern === arguments }
|
||||
|
||||
context "with Arguments" do
|
||||
let(arguments) { Spectator::Arguments.new({42, "foo"}, {bar: "baz", qux: 123}) }
|
||||
|
||||
context "with equal arguments" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: 42, arg2: "foo"}, {bar: "baz", qux: 123}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with matching arguments" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: Int32, arg2: /foo/}, {bar: /baz/, qux: Int32}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with non-matching arguments" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: Float64, arg2: /bar/}, {bar: /foo/, qux: "123"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with different arguments" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: 123, arg2: :foo, arg3: "bar"}, {opt: "foobar"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with the same kwargs in a different order" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: Int32, arg2: /foo/}, {qux: Int32, bar: /baz/}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with an additional kwarg" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: Int32, arg2: /foo/}, {bar: /baz/}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with a missing kwarg" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: Int32, arg2: /foo/}, {bar: /baz/, qux: Int32, extra: 0}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
end
|
||||
|
||||
context "with FormalArguments" do
|
||||
context "with equal arguments" do
|
||||
let(pattern) { arguments }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with matching arguments" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: Int32, arg2: /foo/}, :splat, {Symbol, Symbol, :z}, {bar: /baz/, qux: Int32}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with non-matching arguments" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: Float64, arg2: /bar/}, :splat, {String, Int32, :x}, {bar: /foo/, qux: "123"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with different arguments" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: 123, arg2: :foo, arg3: "bar"}, :splat, {1, 2, 3}, {opt: "foobar"}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with the same kwargs in a different order" do
|
||||
let(pattern) { Spectator::FormalArguments.new(arguments.args, arguments.splat_name, arguments.splat, {qux: Int32, bar: /baz/}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with an additional kwarg" do
|
||||
let(pattern) { Spectator::FormalArguments.new(arguments.args, arguments.splat_name, arguments.splat, {bar: /baz/}) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with a missing kwarg" do
|
||||
let(pattern) { Spectator::FormalArguments.new(arguments.args, arguments.splat_name, arguments.splat, {bar: /baz/, qux: Int32, extra: 0}) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with different splat arguments" do
|
||||
let(pattern) { Spectator::FormalArguments.new(arguments.args, arguments.splat_name, {1, 2, 3}, arguments.kwargs) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
|
||||
context "with matching mixed positional tuple types" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: Int32, arg2: /foo/}, arguments.splat_name, arguments.splat, arguments.kwargs) }
|
||||
|
||||
it { is_expected.to be_true }
|
||||
end
|
||||
|
||||
context "with non-matching mixed positional tuple types" do
|
||||
let(pattern) { Spectator::FormalArguments.new({arg1: Float64, arg2: /bar/}, arguments.splat_name, arguments.splat, arguments.kwargs) }
|
||||
|
||||
it { is_expected.to be_false }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,352 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::LazyDouble do
|
||||
context "plain double" do
|
||||
subject(dbl) { Spectator::LazyDouble.new("dbl-name", foo: 42, bar: "baz") }
|
||||
|
||||
it "responds to defined messages" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to eq(42)
|
||||
expect(dbl.bar).to eq("baz")
|
||||
end
|
||||
end
|
||||
|
||||
it "fails on undefined messages" do
|
||||
expect { dbl.baz }.to raise_error(Spectator::UnexpectedMessage, /baz/)
|
||||
end
|
||||
|
||||
it "reports the name in errors" do
|
||||
expect { dbl.baz }.to raise_error(/"dbl-name"/)
|
||||
end
|
||||
|
||||
it "reports arguments" do
|
||||
expect { dbl.baz(123, "qux", field: :value) }.to raise_error(Spectator::UnexpectedMessage, /\(123, "qux", field: :value\)/)
|
||||
end
|
||||
|
||||
context "blocks" do
|
||||
it "supports blocks" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo { nil }).to eq(42)
|
||||
expect(dbl.bar { nil }).to eq("baz")
|
||||
end
|
||||
end
|
||||
|
||||
it "fails on undefined messages" do
|
||||
expect do
|
||||
dbl.baz { nil }
|
||||
end.to raise_error(Spectator::UnexpectedMessage, /baz/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "without a double name" do
|
||||
subject(dbl) { Spectator::LazyDouble.new }
|
||||
|
||||
it "reports as anonymous" do
|
||||
expect { dbl.baz }.to raise_error(/anonymous/i)
|
||||
end
|
||||
end
|
||||
|
||||
context "with nillable values" do
|
||||
subject(dbl) { Spectator::LazyDouble.new(foo: nil.as(String?), bar: nil) }
|
||||
|
||||
it "doesn't raise on nil" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to be_nil
|
||||
expect(dbl.bar).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with common object methods" do
|
||||
let(dup) { double(:dup) }
|
||||
|
||||
subject(dbl) do
|
||||
Spectator::LazyDouble.new(nil, [
|
||||
Spectator::ValueStub.new(:"!=", false),
|
||||
Spectator::ValueStub.new(:"!~", false),
|
||||
Spectator::ValueStub.new(:"==", true),
|
||||
Spectator::ValueStub.new(:"===", true),
|
||||
Spectator::ValueStub.new(:"=~", nil),
|
||||
Spectator::ValueStub.new(:dup, dup),
|
||||
Spectator::ValueStub.new(:hash, 42_u64),
|
||||
Spectator::ValueStub.new(:"in?", true),
|
||||
Spectator::ValueStub.new(:inspect, "inspect"),
|
||||
Spectator::ValueStub.new(:itself, dup),
|
||||
Spectator::ValueStub.new(:"not_nil!", dup),
|
||||
Spectator::ValueStub.new(:pretty_inspect, "pretty_inspect"),
|
||||
Spectator::ValueStub.new(:tap, dup),
|
||||
Spectator::ValueStub.new(:to_json, "to_json"),
|
||||
Spectator::ValueStub.new(:to_pretty_json, "to_pretty_json"),
|
||||
Spectator::ValueStub.new(:to_s, "to_s"),
|
||||
Spectator::ValueStub.new(:to_yaml, "to_yaml"),
|
||||
Spectator::ValueStub.new(:try, nil),
|
||||
Spectator::ValueStub.new(:object_id, 42_u64),
|
||||
Spectator::ValueStub.new(:"same?", true),
|
||||
] of Spectator::Stub)
|
||||
end
|
||||
|
||||
it "responds with defined messages" do
|
||||
aggregate_failures do
|
||||
expect(dbl.!=(42)).to eq(false)
|
||||
expect(dbl.!~(42)).to eq(false)
|
||||
expect(dbl.==(42)).to eq(true)
|
||||
expect(dbl.===(42)).to eq(true)
|
||||
expect(dbl.=~(42)).to be_nil
|
||||
expect(dbl.dup).to be(dup)
|
||||
expect(dbl.hash).to eq(42_u64)
|
||||
expect(dbl.in?([42])).to eq(true)
|
||||
expect(dbl.in?(1, 2, 3)).to eq(true)
|
||||
expect(dbl.inspect).to eq("inspect")
|
||||
expect(dbl.itself).to be(dup)
|
||||
expect(dbl.not_nil!).to be(dup)
|
||||
expect(dbl.pretty_inspect).to eq("pretty_inspect")
|
||||
expect(dbl.tap { nil }).to be(dup)
|
||||
expect(dbl.to_json).to eq("to_json")
|
||||
expect(dbl.to_pretty_json).to eq("to_pretty_json")
|
||||
expect(dbl.to_s).to eq("to_s")
|
||||
expect(dbl.to_yaml).to eq("to_yaml")
|
||||
expect(dbl.try { nil }).to be_nil
|
||||
expect(dbl.object_id).to eq(42_u64)
|
||||
expect(dbl.same?(dbl)).to eq(true)
|
||||
expect(dbl.same?(nil)).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
it "has a non-union return type" do
|
||||
expect(dbl.inspect).to compile_as(String)
|
||||
end
|
||||
end
|
||||
|
||||
context "without common object methods" do
|
||||
subject(dbl) { Spectator::LazyDouble.new }
|
||||
|
||||
it "returns the original value" do
|
||||
io = IO::Memory.new
|
||||
aggregate_failures do
|
||||
expect(dbl.!=(42)).to be_true
|
||||
expect(dbl.!~(42)).to be_true
|
||||
expect(dbl.==(42)).to be_false
|
||||
expect(dbl.===(42)).to be_false
|
||||
expect(dbl.=~(42)).to be_nil
|
||||
expect(dbl.class).to be_lt(Spectator::LazyDouble)
|
||||
expect(dbl.in?([42])).to be_false
|
||||
expect(dbl.in?(1, 2, 3)).to be_false
|
||||
expect(dbl.itself).to be(dbl)
|
||||
expect(dbl.not_nil!).to be(dbl)
|
||||
expect(dbl.tap { nil }).to be(dbl)
|
||||
expect(dbl.to_s(io)).to be_nil
|
||||
expect(dbl.try { nil }).to be_nil
|
||||
expect(dbl.same?(dbl)).to be_true
|
||||
expect(dbl.same?(nil)).to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with arguments constraints" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
|
||||
context "without common object methods" do
|
||||
let(stub) { Spectator::ValueStub.new(:foo, "bar", arguments).as(Spectator::Stub) }
|
||||
subject(dbl) { Spectator::LazyDouble.new(nil, [stub], foo: "fallback") }
|
||||
|
||||
it "returns the response when constraint satisfied" do
|
||||
expect(dbl.foo("foobar")).to eq("bar")
|
||||
end
|
||||
|
||||
it "returns the fallback value when constraint unsatisfied" do
|
||||
expect { dbl.foo("baz") }.to eq("fallback")
|
||||
end
|
||||
|
||||
it "returns the fallback value when argument count doesn't match" do
|
||||
expect { dbl.foo }.to eq("fallback")
|
||||
end
|
||||
end
|
||||
|
||||
context "with common object methods" do
|
||||
let(stub) { Spectator::ValueStub.new(:"same?", true, arguments).as(Spectator::Stub) }
|
||||
subject(dbl) { Spectator::LazyDouble.new(nil, [stub]) }
|
||||
|
||||
it "returns the response when constraint satisfied" do
|
||||
expect(dbl.same?("foobar")).to eq(true)
|
||||
end
|
||||
|
||||
it "raises an error when constraint unsatisfied" do
|
||||
expect { dbl.same?("baz") }.to raise_error(Spectator::UnexpectedMessage)
|
||||
end
|
||||
|
||||
it "raises an error when argument count doesn't match" do
|
||||
expect { dbl.same? }.to raise_error(Spectator::UnexpectedMessage)
|
||||
end
|
||||
|
||||
context "with a fallback defined" do
|
||||
subject(dbl) { Spectator::LazyDouble.new(nil, [stub], "same?": true) }
|
||||
|
||||
it "returns the fallback when constraint unsatisfied" do
|
||||
expect(dbl.same?("baz")).to be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#_spectator_define_stub" do
|
||||
subject(dbl) { Spectator::LazyDouble.new(foo: 42, bar: "baz") }
|
||||
let(stub3) { Spectator::ValueStub.new(:foo, 3) }
|
||||
let(stub5) { Spectator::ValueStub.new(:foo, 5) }
|
||||
let(stub7) { Spectator::ValueStub.new(:foo, 7, Spectator::Arguments.capture(:lucky)) }
|
||||
|
||||
it "overrides an existing method" do
|
||||
expect { dbl._spectator_define_stub(stub3) }.to change { dbl.foo }.from(42).to(3)
|
||||
end
|
||||
|
||||
it "replaces an existing stub" do
|
||||
dbl._spectator_define_stub(stub3)
|
||||
expect { dbl._spectator_define_stub(stub5) }.to change { dbl.foo }.from(3).to(5)
|
||||
end
|
||||
|
||||
it "doesn't affect other methods" do
|
||||
expect { dbl._spectator_define_stub(stub5) }.to_not change { dbl.bar }
|
||||
end
|
||||
|
||||
it "picks the correct stub based on arguments" do
|
||||
dbl._spectator_define_stub(stub5)
|
||||
dbl._spectator_define_stub(stub7)
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to eq(5)
|
||||
expect(dbl.foo(:lucky)).to eq(7)
|
||||
end
|
||||
end
|
||||
|
||||
it "only uses a stub if an argument constraint is met" do
|
||||
dbl._spectator_define_stub(stub7)
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to eq(42)
|
||||
expect(dbl.foo(:lucky)).to eq(7)
|
||||
end
|
||||
end
|
||||
|
||||
it "ignores the block argument if not in the constraint" do
|
||||
dbl._spectator_define_stub(stub5)
|
||||
dbl._spectator_define_stub(stub7)
|
||||
aggregate_failures do
|
||||
expect(dbl.foo { nil }).to eq(5)
|
||||
expect(dbl.foo(:lucky) { nil }).to eq(7)
|
||||
end
|
||||
end
|
||||
|
||||
context "with previously undefined methods" do
|
||||
it "raises an error" do
|
||||
stub = Spectator::ValueStub.new(:baz, :xyz)
|
||||
expect { dbl._spectator_define_stub(stub) }.to raise_error(/stub/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#_spectator_clear_stubs" do
|
||||
subject(dbl) { Spectator::LazyDouble.new(foo: 42, bar: "baz") }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 5) }
|
||||
|
||||
before { dbl._spectator_define_stub(stub) }
|
||||
|
||||
it "removes previously defined stubs" do
|
||||
expect { dbl._spectator_clear_stubs }.to change { dbl.foo }.from(5).to(42)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#_spectator_calls" do
|
||||
subject(dbl) { Spectator::LazyDouble.new(foo: 42, bar: "baz") }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 5) }
|
||||
|
||||
before { dbl._spectator_define_stub(stub) }
|
||||
|
||||
# Retrieves symbolic names of methods called on a double.
|
||||
def called_method_names(dbl)
|
||||
dbl._spectator_calls.map(&.method)
|
||||
end
|
||||
|
||||
it "stores calls to stubbed methods" do
|
||||
expect { dbl.foo }.to change { called_method_names(dbl) }.from(%i[]).to(%i[foo])
|
||||
end
|
||||
|
||||
it "stores multiple calls to the same stub" do
|
||||
dbl.foo
|
||||
expect { dbl.foo }.to change { called_method_names(dbl) }.from(%i[foo]).to(%i[foo foo])
|
||||
end
|
||||
|
||||
it "stores calls to non-stubbed methods" do
|
||||
expect { dbl.baz }.to raise_error(Spectator::UnexpectedMessage, /baz/)
|
||||
expect(called_method_names(dbl)).to contain(:baz)
|
||||
end
|
||||
|
||||
it "stores arguments for a call" do
|
||||
dbl.foo(42)
|
||||
args = Spectator::Arguments.capture(42)
|
||||
call = dbl._spectator_calls.first
|
||||
expect(call.arguments).to eq(args)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_s" do
|
||||
subject(string) { dbl.to_s }
|
||||
|
||||
context "with a name" do
|
||||
let(dbl) { Spectator::LazyDouble.new("dbl-name") }
|
||||
|
||||
it "indicates it's a double" do
|
||||
expect(string).to contain("LazyDouble")
|
||||
end
|
||||
|
||||
it "contains the double name" do
|
||||
expect(string).to contain("dbl-name")
|
||||
end
|
||||
end
|
||||
|
||||
context "without a name" do
|
||||
let(dbl) { Spectator::LazyDouble.new }
|
||||
|
||||
it "contains the double type" do
|
||||
expect(string).to contain("LazyDouble")
|
||||
end
|
||||
|
||||
it "contains \"Anonymous\"" do
|
||||
expect(string).to contain("Anonymous")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#inspect" do
|
||||
subject(string) { dbl.inspect }
|
||||
|
||||
context "with a name" do
|
||||
let(dbl) { Spectator::LazyDouble.new("dbl-name") }
|
||||
|
||||
it "contains the double type" do
|
||||
expect(string).to contain("LazyDouble")
|
||||
end
|
||||
|
||||
it "contains the double name" do
|
||||
expect(string).to contain("dbl-name")
|
||||
end
|
||||
|
||||
it "contains the object ID" do
|
||||
expect(string).to contain(dbl.object_id.to_s(16))
|
||||
end
|
||||
end
|
||||
|
||||
context "without a name" do
|
||||
let(dbl) { Spectator::LazyDouble.new }
|
||||
|
||||
it "contains the double type" do
|
||||
expect(string).to contain("LazyDouble")
|
||||
end
|
||||
|
||||
it "contains \"Anonymous\"" do
|
||||
expect(string).to contain("Anonymous")
|
||||
end
|
||||
|
||||
it "contains the object ID" do
|
||||
expect(string).to contain(dbl.object_id.to_s(16))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::MethodCall do
|
||||
let(arguments) { Spectator::Arguments.capture(42, "foobar", foo: :bar) }
|
||||
subject(call) { Spectator::MethodCall.new(:foo, arguments) }
|
||||
|
||||
it "stores the method name" do
|
||||
expect(&.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "stores arguments" do
|
||||
expect(&.arguments).to eq(arguments)
|
||||
end
|
||||
|
||||
describe ".capture" do
|
||||
subject(call) { Spectator::MethodCall.capture(:foo, 42, "foobar", foo: :bar) }
|
||||
|
||||
it "stores the method name" do
|
||||
expect(&.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "stores arguments" do
|
||||
expect(&.arguments).to eq(arguments)
|
||||
end
|
||||
end
|
||||
end
|
File diff suppressed because it is too large
Load Diff
|
@ -1,173 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::MultiValueStub do
|
||||
let(method_call) { Spectator::MethodCall.capture(:foo) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
subject(stub) { described_class.new(:foo, [3, 5, 7], location: location) }
|
||||
|
||||
it "stores the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "stores the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
|
||||
describe "#call" do
|
||||
it "returns the values in order" do
|
||||
values = Array.new(3) { stub.call(method_call) }
|
||||
expect(values).to eq([3, 5, 7])
|
||||
end
|
||||
|
||||
it "returns the final value after exhausting other values" do
|
||||
values = Array.new(5) { stub.call(method_call) }
|
||||
expect(values).to eq([3, 5, 7, 7, 7])
|
||||
end
|
||||
end
|
||||
|
||||
context Spectator::StubModifiers do
|
||||
describe "#and_return(value)" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::MultiValueStub.new(:foo, [3, 5, 7], arguments, location) }
|
||||
subject(stub) { original.and_return(123) }
|
||||
|
||||
it "produces a stub that returns a value" do
|
||||
expect(stub.call(method_call)).to eq(123)
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#and_return(*values)" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::MultiValueStub.new(:foo, [3, 5, 7], arguments, location) }
|
||||
subject(stub) { original.and_return(3, 2, 1, 0) }
|
||||
|
||||
it "produces a stub that returns values" do
|
||||
values = Array.new(5) { stub.call(method_call) }
|
||||
expect(values).to eq([3, 2, 1, 0, 0])
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#and_raise" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::MultiValueStub.new(:foo, [3, 5, 7], arguments, location) }
|
||||
let(new_exception) { ArgumentError.new("Test argument error") }
|
||||
subject(stub) { original.and_raise(new_exception) }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError, "Test argument error")
|
||||
end
|
||||
|
||||
context "with a class and message" do
|
||||
subject(stub) { original.and_raise(ArgumentError, "Test argument error") }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError, "Test argument error")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a message" do
|
||||
subject(stub) { original.and_raise("Test exception") }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(Exception, "Test exception")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a class" do
|
||||
subject(stub) { original.and_raise(ArgumentError) }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#===" do
|
||||
subject { stub === call }
|
||||
|
||||
context "with a matching method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "foobar") }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:bar, "foobar") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "with a constraint" do
|
||||
let(constraint) { Spectator::Arguments.capture(/foo/) }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 42, constraint) }
|
||||
|
||||
context "with a matching method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "foobar") }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
|
||||
context "with a non-matching arguments" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "baz") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:bar, "foobar") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,503 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::NullDouble do
|
||||
Spectator::NullDouble.define(EmptyDouble)
|
||||
Spectator::NullDouble.define(FooBarDouble, "dbl-name", foo: 42, bar: "baz")
|
||||
|
||||
# The subject `dbl` must be carefully used in sub-contexts, otherwise it pollutes parent scopes.
|
||||
# This changes the type of `dbl` to `Double`, which produces a union of methods and their return types.
|
||||
context "plain double" do
|
||||
subject(dbl) { FooBarDouble.new }
|
||||
|
||||
it "responds to defined messages" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to eq(42)
|
||||
expect(dbl.bar).to eq("baz")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns self on undefined messages" do
|
||||
expect(dbl.baz).to be(dbl)
|
||||
end
|
||||
|
||||
it "has a non-union return type" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to compile_as(Int32)
|
||||
expect(dbl.bar).to compile_as(String)
|
||||
end
|
||||
end
|
||||
|
||||
context "blocks" do
|
||||
it "supports blocks" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo { nil }).to eq(42)
|
||||
expect(dbl.bar { nil }).to eq("baz")
|
||||
end
|
||||
end
|
||||
|
||||
it "supports blocks and has non-union return types" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo { nil }).to compile_as(Int32)
|
||||
expect(dbl.bar { nil }).to compile_as(String)
|
||||
end
|
||||
end
|
||||
|
||||
it "returns self on undefined messages" do
|
||||
expect(dbl.baz { nil }).to be(dbl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with abstract stubs and return type annotations" do
|
||||
Spectator::NullDouble.define(TestDouble2) do
|
||||
stub abstract def foo(value) : String
|
||||
end
|
||||
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, "bar", arguments).as(Spectator::Stub) }
|
||||
subject(dbl) { TestDouble2.new([stub]) }
|
||||
|
||||
it "enforces the return type" do
|
||||
expect(dbl.foo("foobar")).to compile_as(String)
|
||||
end
|
||||
|
||||
it "raises on non-matching arguments" do
|
||||
expect { dbl.foo("bar") }.to raise_error(Spectator::UnexpectedMessage, /foo/)
|
||||
end
|
||||
|
||||
it "raises on non-matching stub" do
|
||||
stub = Spectator::ValueStub.new(:foo, 42, arguments).as(Spectator::Stub)
|
||||
dbl._spectator_define_stub(stub)
|
||||
expect { dbl.foo("foobar") }.to raise_error(TypeCastError, /String/)
|
||||
end
|
||||
end
|
||||
|
||||
context "with nillable return type annotations" do
|
||||
Spectator::NullDouble.define(TestDouble) do
|
||||
stub abstract def foo : String?
|
||||
stub abstract def bar : Nil
|
||||
end
|
||||
|
||||
let(foo_stub) { Spectator::ValueStub.new(:foo, nil).as(Spectator::Stub) }
|
||||
let(bar_stub) { Spectator::ValueStub.new(:bar, nil).as(Spectator::Stub) }
|
||||
subject(dbl) { TestDouble.new([foo_stub, bar_stub]) }
|
||||
|
||||
it "doesn't raise on nil" do
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to be_nil
|
||||
expect(dbl.bar).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a method that uses NoReturn" do
|
||||
Spectator::NullDouble.define(NoReturnDouble) do
|
||||
stub abstract def oops : NoReturn
|
||||
end
|
||||
|
||||
subject(dbl) { NoReturnDouble.new }
|
||||
|
||||
it "raises a TypeCastError when using a value-based stub" do
|
||||
stub = Spectator::ValueStub.new(:oops, nil).as(Spectator::Stub)
|
||||
dbl._spectator_define_stub(stub)
|
||||
expect { dbl.oops }.to raise_error(TypeCastError, /NoReturn/)
|
||||
end
|
||||
|
||||
it "raises when using an exception stub" do
|
||||
exception = ArgumentError.new("bogus")
|
||||
stub = Spectator::ExceptionStub.new(:oops, exception).as(Spectator::Stub)
|
||||
dbl._spectator_define_stub(stub)
|
||||
expect { dbl.oops }.to raise_error(ArgumentError, "bogus")
|
||||
end
|
||||
end
|
||||
|
||||
context "with common object methods" do
|
||||
subject(dbl) do
|
||||
EmptyDouble.new([
|
||||
Spectator::ValueStub.new(:"!=", false),
|
||||
Spectator::ValueStub.new(:"!~", false),
|
||||
Spectator::ValueStub.new(:"==", true),
|
||||
Spectator::ValueStub.new(:"===", true),
|
||||
Spectator::ValueStub.new(:"=~", nil),
|
||||
Spectator::ValueStub.new(:class, EmptyDouble),
|
||||
Spectator::ValueStub.new(:dup, EmptyDouble.new),
|
||||
Spectator::ValueStub.new(:"in?", true),
|
||||
Spectator::ValueStub.new(:inspect, "inspect"),
|
||||
Spectator::ValueStub.new(:itself, EmptyDouble.new),
|
||||
Spectator::ValueStub.new(:"not_nil!", EmptyDouble.new),
|
||||
Spectator::ValueStub.new(:pretty_inspect, "pretty_inspect"),
|
||||
Spectator::ValueStub.new(:tap, EmptyDouble.new),
|
||||
Spectator::ValueStub.new(:to_json, "to_json"),
|
||||
Spectator::ValueStub.new(:to_pretty_json, "to_pretty_json"),
|
||||
Spectator::ValueStub.new(:to_s, "to_s"),
|
||||
Spectator::ValueStub.new(:to_yaml, "to_yaml"),
|
||||
Spectator::ValueStub.new(:try, nil),
|
||||
Spectator::ValueStub.new(:object_id, 42_u64),
|
||||
Spectator::ValueStub.new(:"same?", true),
|
||||
] of Spectator::Stub)
|
||||
end
|
||||
|
||||
it "responds with defined messages" do
|
||||
aggregate_failures do
|
||||
expect(dbl.!=(42)).to be_false
|
||||
expect(dbl.!~(42)).to be_false
|
||||
expect(dbl.==(42)).to be_true
|
||||
expect(dbl.===(42)).to be_true
|
||||
expect(dbl.=~(42)).to be_nil
|
||||
expect(dbl.class).to eq(EmptyDouble)
|
||||
expect(dbl.dup).to be_a(EmptyDouble)
|
||||
expect(dbl.in?([42])).to eq(true)
|
||||
expect(dbl.in?(1, 2, 3)).to eq(true)
|
||||
expect(dbl.inspect).to eq("inspect")
|
||||
expect(dbl.itself).to be_a(EmptyDouble)
|
||||
expect(dbl.not_nil!).to be_a(EmptyDouble)
|
||||
expect(dbl.pretty_inspect).to eq("pretty_inspect")
|
||||
expect(dbl.tap { nil }).to be_a(EmptyDouble)
|
||||
expect(dbl.to_json).to eq("to_json")
|
||||
expect(dbl.to_pretty_json).to eq("to_pretty_json")
|
||||
expect(dbl.to_s).to eq("to_s")
|
||||
expect(dbl.to_yaml).to eq("to_yaml")
|
||||
expect(dbl.try { nil }).to be_nil
|
||||
expect(dbl.object_id).to eq(42_u64)
|
||||
expect(dbl.same?(dbl)).to be_true
|
||||
expect(dbl.same?(nil)).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
it "has a non-union return type" do
|
||||
expect(dbl.inspect).to compile_as(String)
|
||||
end
|
||||
end
|
||||
|
||||
context "without common object methods" do
|
||||
subject(dbl) { EmptyDouble.new }
|
||||
|
||||
it "returns original implementation with undefined messages" do
|
||||
hasher = Crystal::Hasher.new
|
||||
aggregate_failures do
|
||||
expect(dbl.!=(42)).to be_true
|
||||
expect(dbl.!~(42)).to be_true
|
||||
expect(dbl.==(42)).to be_false
|
||||
expect(dbl.===(42)).to be_false
|
||||
expect(dbl.=~(42)).to be_nil
|
||||
expect(dbl.class).to eq(EmptyDouble)
|
||||
expect(dbl.dup).to be_a(EmptyDouble)
|
||||
expect(dbl.hash(hasher)).to be_a(Crystal::Hasher)
|
||||
expect(dbl.hash).to be_a(UInt64)
|
||||
expect(dbl.in?([42])).to be_false
|
||||
expect(dbl.in?(1, 2, 3)).to be_false
|
||||
expect(dbl.itself).to be(dbl)
|
||||
expect(dbl.not_nil!).to be(dbl)
|
||||
expect(dbl.tap { nil }).to be(dbl)
|
||||
expect(dbl.try { nil }).to be_nil
|
||||
expect(dbl.object_id).to be_a(UInt64)
|
||||
expect(dbl.same?(dbl)).to be_true
|
||||
expect(dbl.same?(nil)).to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with arguments constraints" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
|
||||
context "without common object methods" do
|
||||
Spectator::NullDouble.define(TestDouble) do
|
||||
stub abstract def foo(value) : String
|
||||
stub abstract def foo(value, & : -> _) : String
|
||||
end
|
||||
|
||||
let(stub) { Spectator::ValueStub.new(:foo, "bar", arguments).as(Spectator::Stub) }
|
||||
subject(dbl) { TestDouble.new([stub]) }
|
||||
|
||||
it "returns the response when constraint satisfied" do
|
||||
expect(dbl.foo("foobar")).to eq("bar")
|
||||
end
|
||||
|
||||
it "raises when constraint unsatisfied" do
|
||||
expect { dbl.foo("baz") }.to raise_error(Spectator::UnexpectedMessage, /foo/)
|
||||
end
|
||||
|
||||
it "returns self when argument count doesn't match" do
|
||||
expect(dbl.foo).to be(dbl)
|
||||
end
|
||||
|
||||
it "ignores the block argument if not in the constraint" do
|
||||
expect(dbl.foo("foobar") { nil }).to eq("bar")
|
||||
end
|
||||
end
|
||||
|
||||
context "with common object methods" do
|
||||
Spectator::NullDouble.define(TestDouble) do
|
||||
stub abstract def hash(hasher) : Crystal::Hasher
|
||||
end
|
||||
|
||||
let(hasher) { Crystal::Hasher.new }
|
||||
let(stub) { Spectator::ValueStub.new(:hash, hasher, arguments).as(Spectator::Stub) }
|
||||
subject(dbl) { TestDouble.new([stub]) }
|
||||
|
||||
it "returns the response when constraint satisfied" do
|
||||
expect(dbl.hash("foobar")).to be(hasher)
|
||||
end
|
||||
|
||||
it "raises when constraint unsatisfied" do
|
||||
expect { dbl.hash("baz") }.to raise_error(Spectator::UnexpectedMessage, /hash/)
|
||||
end
|
||||
|
||||
it "raises when argument count doesn't match" do
|
||||
expect { dbl.hash }.to raise_error(Spectator::UnexpectedMessage, /hash/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "class method stubs" do
|
||||
Spectator::NullDouble.define(ClassDouble) do
|
||||
stub def self.foo
|
||||
:stub
|
||||
end
|
||||
|
||||
stub def self.bar(arg)
|
||||
arg
|
||||
end
|
||||
|
||||
stub def self.baz(arg, &)
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
subject(dbl) { ClassDouble }
|
||||
let(foo_stub) { Spectator::ValueStub.new(:foo, :override) }
|
||||
|
||||
after { dbl._spectator_clear_stubs }
|
||||
|
||||
it "overrides an existing method" do
|
||||
expect { dbl._spectator_define_stub(foo_stub) }.to change { dbl.foo }.from(:stub).to(:override)
|
||||
end
|
||||
|
||||
it "doesn't affect other methods" do
|
||||
expect { dbl._spectator_define_stub(foo_stub) }.to_not change { dbl.bar(42) }
|
||||
end
|
||||
|
||||
it "replaces an existing stub" do
|
||||
dbl._spectator_define_stub(foo_stub)
|
||||
stub = Spectator::ValueStub.new(:foo, :replacement)
|
||||
expect { dbl._spectator_define_stub(stub) }.to change { dbl.foo }.to(:replacement)
|
||||
end
|
||||
|
||||
it "picks the correct stub based on arguments" do
|
||||
stub1 = Spectator::ValueStub.new(:bar, :fallback)
|
||||
stub2 = Spectator::ValueStub.new(:bar, :override, Spectator::Arguments.capture(:match))
|
||||
dbl._spectator_define_stub(stub1)
|
||||
dbl._spectator_define_stub(stub2)
|
||||
aggregate_failures do
|
||||
expect(dbl.bar(:wrong)).to eq(:fallback)
|
||||
expect(dbl.bar(:match)).to eq(:override)
|
||||
end
|
||||
end
|
||||
|
||||
it "only uses a stub if an argument constraint is met" do
|
||||
stub = Spectator::ValueStub.new(:bar, :override, Spectator::Arguments.capture(:match))
|
||||
dbl._spectator_define_stub(stub)
|
||||
aggregate_failures do
|
||||
expect(dbl.bar(:original)).to eq(:original)
|
||||
expect(dbl.bar(:match)).to eq(:override)
|
||||
end
|
||||
end
|
||||
|
||||
it "ignores the block argument if not in the constraint" do
|
||||
stub1 = Spectator::ValueStub.new(:baz, 1)
|
||||
stub2 = Spectator::ValueStub.new(:baz, 2, Spectator::Arguments.capture(3))
|
||||
dbl._spectator_define_stub(stub1)
|
||||
dbl._spectator_define_stub(stub2)
|
||||
aggregate_failures do
|
||||
expect(dbl.baz(5) { 42 }).to eq(1)
|
||||
expect(dbl.baz(3) { 42 }).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe "._spectator_clear_stubs" do
|
||||
before { dbl._spectator_define_stub(foo_stub) }
|
||||
|
||||
it "removes previously defined stubs" do
|
||||
expect { dbl._spectator_clear_stubs }.to change { dbl.foo }.from(:override).to(:stub)
|
||||
end
|
||||
end
|
||||
|
||||
describe "._spectator_calls" do
|
||||
before { dbl._spectator_clear_calls }
|
||||
|
||||
# Retrieves symbolic names of methods called on a double.
|
||||
def called_method_names(dbl)
|
||||
dbl._spectator_calls.map(&.method)
|
||||
end
|
||||
|
||||
it "stores calls to stubbed methods" do
|
||||
expect { dbl.foo }.to change { called_method_names(dbl) }.from(%i[]).to(%i[foo])
|
||||
end
|
||||
|
||||
it "stores multiple calls to the same stub" do
|
||||
dbl.foo
|
||||
expect { dbl.foo }.to change { called_method_names(dbl) }.from(%i[foo]).to(%i[foo foo])
|
||||
end
|
||||
|
||||
it "stores arguments for a call" do
|
||||
dbl.bar(42)
|
||||
args = Spectator::Arguments.capture(42)
|
||||
call = dbl._spectator_calls.first
|
||||
expect(call.arguments).to eq(args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#_spectator_define_stub" do
|
||||
subject(dbl) { FooBarDouble.new }
|
||||
let(stub3) { Spectator::ValueStub.new(:foo, 3) }
|
||||
let(stub5) { Spectator::ValueStub.new(:foo, 5) }
|
||||
let(stub7) { Spectator::ValueStub.new(:foo, 7, Spectator::Arguments.capture(:lucky)) }
|
||||
|
||||
it "overrides an existing method" do
|
||||
expect { dbl._spectator_define_stub(stub3) }.to change { dbl.foo }.from(42).to(3)
|
||||
end
|
||||
|
||||
it "replaces an existing stub" do
|
||||
dbl._spectator_define_stub(stub3)
|
||||
expect { dbl._spectator_define_stub(stub5) }.to change { dbl.foo }.from(3).to(5)
|
||||
end
|
||||
|
||||
it "doesn't affect other methods" do
|
||||
expect { dbl._spectator_define_stub(stub5) }.to_not change { dbl.bar }
|
||||
end
|
||||
|
||||
it "picks the correct stub based on arguments" do
|
||||
dbl._spectator_define_stub(stub5)
|
||||
dbl._spectator_define_stub(stub7)
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to eq(5)
|
||||
expect(dbl.foo(:lucky)).to eq(7)
|
||||
end
|
||||
end
|
||||
|
||||
it "only uses a stub if an argument constraint is met" do
|
||||
dbl._spectator_define_stub(stub7)
|
||||
aggregate_failures do
|
||||
expect(dbl.foo).to eq(42)
|
||||
expect(dbl.foo(:lucky)).to eq(7)
|
||||
end
|
||||
end
|
||||
|
||||
it "ignores the block argument if not in the constraint" do
|
||||
dbl._spectator_define_stub(stub5)
|
||||
dbl._spectator_define_stub(stub7)
|
||||
aggregate_failures do
|
||||
expect(dbl.foo { nil }).to eq(5)
|
||||
expect(dbl.foo(:lucky) { nil }).to eq(7)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#_spectator_clear_stubs" do
|
||||
subject(dbl) { FooBarDouble.new }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 5) }
|
||||
|
||||
before { dbl._spectator_define_stub(stub) }
|
||||
|
||||
it "removes previously defined stubs" do
|
||||
expect { dbl._spectator_clear_stubs }.to change { dbl.foo }.from(5).to(42)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#_spectator_calls" do
|
||||
subject(dbl) { FooBarDouble.new }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 5) }
|
||||
|
||||
before { dbl._spectator_define_stub(stub) }
|
||||
|
||||
# Retrieves symbolic names of methods called on a double.
|
||||
def called_method_names(dbl)
|
||||
dbl._spectator_calls.map(&.method)
|
||||
end
|
||||
|
||||
it "stores calls to stubbed methods" do
|
||||
expect { dbl.foo }.to change { called_method_names(dbl) }.from(%i[]).to(%i[foo])
|
||||
end
|
||||
|
||||
it "stores multiple calls to the same stub" do
|
||||
dbl.foo
|
||||
expect { dbl.foo }.to change { called_method_names(dbl) }.from(%i[foo]).to(%i[foo foo])
|
||||
end
|
||||
|
||||
it "stores calls to non-stubbed methods" do
|
||||
expect { dbl.baz }.to change { called_method_names(dbl) }.from(%i[]).to(%i[baz])
|
||||
end
|
||||
|
||||
it "stores arguments for a call" do
|
||||
dbl.foo(42)
|
||||
args = Spectator::Arguments.capture(42)
|
||||
call = dbl._spectator_calls.first
|
||||
expect(call.arguments).to eq(args)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_s" do
|
||||
subject(string) { dbl.to_s }
|
||||
|
||||
context "with a name" do
|
||||
let(dbl) { FooBarDouble.new }
|
||||
|
||||
it "indicates it's a double" do
|
||||
expect(string).to contain("NullDouble")
|
||||
end
|
||||
|
||||
it "contains the double name" do
|
||||
expect(string).to contain("dbl-name")
|
||||
end
|
||||
end
|
||||
|
||||
context "without a name" do
|
||||
let(dbl) { EmptyDouble.new }
|
||||
|
||||
it "contains the double type" do
|
||||
expect(string).to contain("NullDouble")
|
||||
end
|
||||
|
||||
it "contains \"Anonymous\"" do
|
||||
expect(string).to contain("Anonymous")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#inspect" do
|
||||
subject(string) { dbl.inspect }
|
||||
|
||||
context "with a name" do
|
||||
let(dbl) { FooBarDouble.new }
|
||||
|
||||
it "contains the double type" do
|
||||
expect(string).to contain("NullDouble")
|
||||
end
|
||||
|
||||
it "contains the double name" do
|
||||
expect(string).to contain("dbl-name")
|
||||
end
|
||||
|
||||
it "contains the object ID" do
|
||||
expect(string).to contain(dbl.object_id.to_s(16))
|
||||
end
|
||||
end
|
||||
|
||||
context "without a name" do
|
||||
let(dbl) { EmptyDouble.new }
|
||||
|
||||
it "contains the double type" do
|
||||
expect(string).to contain("NullDouble")
|
||||
end
|
||||
|
||||
it "contains \"Anonymous\"" do
|
||||
expect(string).to contain("Anonymous")
|
||||
end
|
||||
|
||||
it "contains the object ID" do
|
||||
expect(string).to contain(dbl.object_id.to_s(16))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,165 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::NullStub do
|
||||
let(method_call) { Spectator::MethodCall.capture(:foo) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
subject(stub) { described_class.new(:foo, location: location) }
|
||||
|
||||
it "stores the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "stores the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
|
||||
it "returns nil" do
|
||||
expect(stub.call(method_call)).to be_nil
|
||||
end
|
||||
|
||||
context Spectator::StubModifiers do
|
||||
describe "#and_return(value)" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::NullStub.new(:foo, arguments, location) }
|
||||
subject(stub) { original.and_return(42) }
|
||||
|
||||
it "produces a stub that returns a value" do
|
||||
expect(stub.call(method_call)).to eq(42)
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#and_return(*values)" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::NullStub.new(:foo, arguments, location) }
|
||||
subject(stub) { original.and_return(3, 2, 1, 0) }
|
||||
|
||||
it "produces a stub that returns values" do
|
||||
values = Array.new(5) { stub.call(method_call) }
|
||||
expect(values).to eq([3, 2, 1, 0, 0])
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#and_raise" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::NullStub.new(:foo, arguments, location) }
|
||||
let(new_exception) { ArgumentError.new("Test argument error") }
|
||||
subject(stub) { original.and_raise(new_exception) }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError, "Test argument error")
|
||||
end
|
||||
|
||||
context "with a class and message" do
|
||||
subject(stub) { original.and_raise(ArgumentError, "Test argument error") }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError, "Test argument error")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a message" do
|
||||
subject(stub) { original.and_raise("Test exception") }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(Exception, "Test exception")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a class" do
|
||||
subject(stub) { original.and_raise(ArgumentError) }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#===" do
|
||||
subject { stub === call }
|
||||
|
||||
context "with a matching method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "foobar") }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:bar, "foobar") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "with a constraint" do
|
||||
let(constraint) { Spectator::Arguments.capture(/foo/) }
|
||||
let(stub) { described_class.new(:foo, constraint) }
|
||||
|
||||
context "with a matching method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "foobar") }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
|
||||
context "with a non-matching arguments" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "baz") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:bar, "foobar") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,182 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::ProcStub do
|
||||
let(method_call) { Spectator::MethodCall.capture(:foo) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(proc) { Proc(Spectator::AbstractArguments, Int32).new { @call_count += 1 } }
|
||||
subject(stub) { described_class.new(:foo, proc, location: location) }
|
||||
|
||||
@call_count = 0
|
||||
|
||||
it "stores the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "stores the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
|
||||
it "calls the proc" do
|
||||
expect(stub.call(method_call)).to eq(1)
|
||||
end
|
||||
|
||||
it "calls the proc for each invocation" do
|
||||
stub.call(method_call)
|
||||
expect { stub.call(method_call) }.to change { @call_count }.from(1).to(2)
|
||||
end
|
||||
|
||||
it "passed the original arguments" do
|
||||
proc = Proc(Spectator::AbstractArguments, Spectator::AbstractArguments).new { |a| a }
|
||||
stub = described_class.new(:foo, proc)
|
||||
args = Spectator::Arguments.capture(42, bar: "baz")
|
||||
call = Spectator::MethodCall.new(:foo, args)
|
||||
captured = stub.call(call)
|
||||
expect(captured).to eq(args)
|
||||
end
|
||||
|
||||
context Spectator::StubModifiers do
|
||||
describe "#and_return(value)" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::ProcStub.new(:foo, proc, arguments, location) }
|
||||
subject(stub) { original.and_return(123) }
|
||||
|
||||
it "produces a stub that returns a value" do
|
||||
expect(stub.call(method_call)).to eq(123)
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#and_return(*values)" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::ProcStub.new(:foo, proc, arguments, location) }
|
||||
subject(stub) { original.and_return(3, 2, 1, 0) }
|
||||
|
||||
it "produces a stub that returns values" do
|
||||
values = Array.new(5) { stub.call(method_call) }
|
||||
expect(values).to eq([3, 2, 1, 0, 0])
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#and_raise" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::ProcStub.new(:foo, proc, arguments, location) }
|
||||
let(new_exception) { ArgumentError.new("Test argument error") }
|
||||
subject(stub) { original.and_raise(new_exception) }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError, "Test argument error")
|
||||
end
|
||||
|
||||
context "with a class and message" do
|
||||
subject(stub) { original.and_raise(ArgumentError, "Test argument error") }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError, "Test argument error")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a message" do
|
||||
subject(stub) { original.and_raise("Test exception") }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(Exception, "Test exception")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a class" do
|
||||
subject(stub) { original.and_raise(ArgumentError) }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#===" do
|
||||
subject { stub === call }
|
||||
|
||||
context "with a matching method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "foobar") }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:bar, "foobar") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "with a constraint" do
|
||||
let(constraint) { Spectator::Arguments.capture(/foo/) }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 42, constraint) }
|
||||
|
||||
context "with a matching method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "foobar") }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
|
||||
context "with a non-matching arguments" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "baz") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:bar, "foobar") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,93 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::ReferenceMockRegistry do
|
||||
subject(registry) { described_class.new }
|
||||
let(obj) { "foobar" }
|
||||
let(stub) { Spectator::ValueStub.new(:test, 42) }
|
||||
let(stubs) { [stub] of Spectator::Stub }
|
||||
let(no_stubs) { [] of Spectator::Stub }
|
||||
let(call) { Spectator::MethodCall.capture(:method2, 5) }
|
||||
let(calls) { [call] }
|
||||
let(no_calls) { [] of Spectator::MethodCall }
|
||||
|
||||
it "initially has no stubs" do
|
||||
expect(registry[obj].stubs).to be_empty
|
||||
end
|
||||
|
||||
it "initially has no calls" do
|
||||
expect(registry[obj].calls).to be_empty
|
||||
end
|
||||
|
||||
it "stores stubs for an object" do
|
||||
expect { registry[obj].stubs << stub }.to change { registry[obj].stubs }.from(no_stubs).to(stubs)
|
||||
end
|
||||
|
||||
it "stores calls for an object" do
|
||||
expect { registry[obj].calls << call }.to change { registry[obj].calls }.from(no_calls).to(calls)
|
||||
end
|
||||
|
||||
it "isolates stubs between different objects" do
|
||||
obj1 = "foo"
|
||||
obj2 = "bar"
|
||||
registry[obj2].stubs << Spectator::ValueStub.new(:obj2, 42)
|
||||
expect { registry[obj1].stubs << stub }.to_not change { registry[obj2].stubs }
|
||||
end
|
||||
|
||||
it "isolates calls between different objects" do
|
||||
obj1 = "foo"
|
||||
obj2 = "bar"
|
||||
registry[obj2].calls << Spectator::MethodCall.capture(:method1, 42)
|
||||
expect { registry[obj1].calls << call }.to_not change { registry[obj2].calls }
|
||||
end
|
||||
|
||||
describe "#fetch" do
|
||||
it "retrieves existing stubs" do
|
||||
registry[obj].stubs << stub
|
||||
expect(registry.fetch(obj) { no_stubs }.stubs).to eq(stubs)
|
||||
end
|
||||
|
||||
it "stores stubs on the first retrieval" do
|
||||
expect(registry.fetch(obj) { stubs }.stubs).to eq(stubs)
|
||||
end
|
||||
|
||||
it "isolates stubs between different objects" do
|
||||
obj1 = "foo"
|
||||
obj2 = "bar"
|
||||
registry[obj2].stubs << Spectator::ValueStub.new(:obj2, 42)
|
||||
expect { registry.fetch(obj1) { no_stubs }.stubs }.to_not change { registry[obj2].stubs }
|
||||
end
|
||||
|
||||
it "isolates calls between different objects" do
|
||||
obj1 = "foo"
|
||||
obj2 = "bar"
|
||||
registry[obj2].calls << Spectator::MethodCall.capture(:method1, 42)
|
||||
expect { registry.fetch(obj1) { no_stubs }.calls }.to_not change { registry[obj2].calls }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#delete" do
|
||||
it "clears stubs for an object" do
|
||||
registry[obj].stubs << stub
|
||||
expect { registry.delete(obj) }.to change { registry[obj].stubs }.from(stubs).to(no_stubs)
|
||||
end
|
||||
|
||||
it "doesn't clear initial stubs provided with #fetch" do
|
||||
registry[obj].stubs << Spectator::ValueStub.new(:stub2, 42)
|
||||
expect { registry.delete(obj) }.to change { registry.fetch(obj) { stubs }.stubs }.to(stubs)
|
||||
end
|
||||
|
||||
it "isolates stubs between different objects" do
|
||||
obj1 = "foo"
|
||||
obj2 = "bar"
|
||||
registry[obj2].stubs << Spectator::ValueStub.new(:obj2, 42)
|
||||
expect { registry.delete(obj1) }.to_not change { registry[obj2].stubs }
|
||||
end
|
||||
|
||||
it "isolates calls between different objects" do
|
||||
obj1 = "foo"
|
||||
obj2 = "bar"
|
||||
registry[obj2].calls << Spectator::MethodCall.capture(:method1, 42)
|
||||
expect { registry.delete(obj1) }.to_not change { registry[obj2].calls }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,93 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::ValueMockRegistry do
|
||||
subject(registry) { Spectator::ValueMockRegistry(Int32).new }
|
||||
let(obj) { 42 }
|
||||
let(stub) { Spectator::ValueStub.new(:test, 5) }
|
||||
let(stubs) { [stub] of Spectator::Stub }
|
||||
let(no_stubs) { [] of Spectator::Stub }
|
||||
let(call) { Spectator::MethodCall.capture(:method2, 5) }
|
||||
let(calls) { [call] }
|
||||
let(no_calls) { [] of Spectator::MethodCall }
|
||||
|
||||
it "initially has no stubs" do
|
||||
expect(registry[obj].stubs).to be_empty
|
||||
end
|
||||
|
||||
it "initially has no calls" do
|
||||
expect(registry[obj].calls).to be_empty
|
||||
end
|
||||
|
||||
it "stores stubs for an object" do
|
||||
expect { registry[obj].stubs << stub }.to change { registry[obj].stubs }.from(no_stubs).to(stubs)
|
||||
end
|
||||
|
||||
it "stores calls for an object" do
|
||||
expect { registry[obj].calls << call }.to change { registry[obj].calls }.from(no_calls).to(calls)
|
||||
end
|
||||
|
||||
it "isolates stubs between different objects" do
|
||||
obj1 = 1
|
||||
obj2 = 2
|
||||
registry[obj2].stubs << Spectator::ValueStub.new(:obj2, 42)
|
||||
expect { registry[obj1].stubs << stub }.to_not change { registry[obj2].stubs }
|
||||
end
|
||||
|
||||
it "isolates calls between different objects" do
|
||||
obj1 = 1
|
||||
obj2 = 2
|
||||
registry[obj2].calls << Spectator::MethodCall.capture(:method1, 42)
|
||||
expect { registry[obj1].calls << call }.to_not change { registry[obj2].calls }
|
||||
end
|
||||
|
||||
describe "#fetch" do
|
||||
it "retrieves existing stubs" do
|
||||
registry[obj].stubs << stub
|
||||
expect(registry.fetch(obj) { no_stubs }.stubs).to eq(stubs)
|
||||
end
|
||||
|
||||
it "stores stubs on the first retrieval" do
|
||||
expect(registry.fetch(obj) { stubs }.stubs).to eq(stubs)
|
||||
end
|
||||
|
||||
it "isolates stubs between different objects" do
|
||||
obj1 = 1
|
||||
obj2 = 2
|
||||
registry[obj2].stubs << Spectator::ValueStub.new(:obj2, 42)
|
||||
expect { registry.fetch(obj1) { no_stubs }.stubs }.to_not change { registry[obj2].stubs }
|
||||
end
|
||||
|
||||
it "isolates calls between different objects" do
|
||||
obj1 = 1
|
||||
obj2 = 2
|
||||
registry[obj2].calls << Spectator::MethodCall.capture(:method1, 42)
|
||||
expect { registry.fetch(obj1) { no_stubs }.calls }.to_not change { registry[obj2].calls }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#delete" do
|
||||
it "clears stubs for an object" do
|
||||
registry[obj].stubs << stub
|
||||
expect { registry.delete(obj) }.to change { registry[obj].stubs }.from(stubs).to(no_stubs)
|
||||
end
|
||||
|
||||
it "doesn't clear initial stubs provided with #fetch" do
|
||||
registry[obj].stubs << Spectator::ValueStub.new(:stub2, 42)
|
||||
expect { registry.delete(obj) }.to change { registry.fetch(obj) { stubs }.stubs }.to(stubs)
|
||||
end
|
||||
|
||||
it "isolates stubs between different objects" do
|
||||
obj1 = 1
|
||||
obj2 = 2
|
||||
registry[obj2].stubs << Spectator::ValueStub.new(:obj2, 42)
|
||||
expect { registry.delete(obj1) }.to_not change { registry[obj2].stubs }
|
||||
end
|
||||
|
||||
it "isolates calls between different objects" do
|
||||
obj1 = 1
|
||||
obj2 = 2
|
||||
registry[obj2].calls << Spectator::MethodCall.capture(:method1, 42)
|
||||
expect { registry.delete(obj1) }.to_not change { registry[obj2].calls }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,165 +0,0 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Spectator::ValueStub do
|
||||
let(method_call) { Spectator::MethodCall.capture(:foo) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
subject(stub) { described_class.new(:foo, 42, location: location) }
|
||||
|
||||
it "stores the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "stores the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
|
||||
it "stores the return value" do
|
||||
expect(stub.call(method_call)).to eq(42)
|
||||
end
|
||||
|
||||
context Spectator::StubModifiers do
|
||||
describe "#and_return(value)" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::ValueStub.new(:foo, 42, arguments, location) }
|
||||
subject(stub) { original.and_return(123) }
|
||||
|
||||
it "produces a stub that returns a value" do
|
||||
expect(stub.call(method_call)).to eq(123)
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#and_return(*values)" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::ValueStub.new(:foo, 42, arguments, location) }
|
||||
subject(stub) { original.and_return(3, 2, 1, 0) }
|
||||
|
||||
it "produces a stub that returns values" do
|
||||
values = Array.new(5) { stub.call(method_call) }
|
||||
expect(values).to eq([3, 2, 1, 0, 0])
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#and_raise" do
|
||||
let(arguments) { Spectator::Arguments.capture(/foo/) }
|
||||
let(location) { Spectator::Location.new(__FILE__, __LINE__) }
|
||||
let(original) { Spectator::ValueStub.new(:foo, 42, arguments, location) }
|
||||
let(new_exception) { ArgumentError.new("Test argument error") }
|
||||
subject(stub) { original.and_raise(new_exception) }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError, "Test argument error")
|
||||
end
|
||||
|
||||
context "with a class and message" do
|
||||
subject(stub) { original.and_raise(ArgumentError, "Test argument error") }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError, "Test argument error")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a message" do
|
||||
subject(stub) { original.and_raise("Test exception") }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(Exception, "Test exception")
|
||||
end
|
||||
end
|
||||
|
||||
context "with a class" do
|
||||
subject(stub) { original.and_raise(ArgumentError) }
|
||||
|
||||
it "produces a stub that raises" do
|
||||
expect { stub.call(method_call) }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
it "retains the method name" do
|
||||
expect(stub.method).to eq(:foo)
|
||||
end
|
||||
|
||||
it "retains the arguments constraint" do
|
||||
expect(stub.constraint).to eq(arguments)
|
||||
end
|
||||
|
||||
it "retains the location" do
|
||||
expect(stub.location).to eq(location)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#===" do
|
||||
subject { stub === call }
|
||||
|
||||
context "with a matching method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "foobar") }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:bar, "foobar") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "with a constraint" do
|
||||
let(constraint) { Spectator::Arguments.capture(/foo/) }
|
||||
let(stub) { Spectator::ValueStub.new(:foo, 42, constraint) }
|
||||
|
||||
context "with a matching method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "foobar") }
|
||||
|
||||
it "returns true" do
|
||||
is_expected.to be_true
|
||||
end
|
||||
|
||||
context "with a non-matching arguments" do
|
||||
let(call) { Spectator::MethodCall.capture(:foo, "baz") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a different method name" do
|
||||
let(call) { Spectator::MethodCall.capture(:bar, "foobar") }
|
||||
|
||||
it "returns false" do
|
||||
is_expected.to be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue