Match RSpec behavior

This commit is contained in:
Michael Miller 2022-03-30 20:28:36 -06:00
parent a8e55e32d2
commit 613c969fbb
No known key found for this signature in database
GPG key ID: 32B47AE8F388A1FF
5 changed files with 59 additions and 56 deletions

View file

@ -179,7 +179,7 @@ Spectator.describe Spectator::Double do
context "without common object methods" do
subject(dbl) { EmptyDouble.new }
it "raises with undefined messages" do
it "returns original implementation with undefined messages" do
io = IO::Memory.new
pp = PrettyPrint.new(io)
hasher = Crystal::Hasher.new
@ -188,37 +188,30 @@ Spectator.describe Spectator::Double do
expect(dbl.!~(42)).to be_true
expect(dbl.==(42)).to be_false
expect(dbl.===(42)).to be_false
expect(dbl.=~(42)).to be_false
expect(dbl.class).to be_nil
expect(dbl.dup).to eq(dbl)
expect(dbl.hash(hasher)).to eq(42)
expect(dbl.hash).to eq(42)
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.inspect).to eq("foo")
expect(dbl.inspect).to contain("EmptyDouble")
expect(dbl.itself).to be(dbl)
expect(dbl.not_nil!).to be(dbl)
expect(dbl.pretty_inspect).to eq("foo")
# expect(dbl.pretty_inspect(io)).to be_nil
expect(dbl.pretty_inspect).to contain("EmptyDouble")
expect(dbl.pretty_print(pp)).to be_nil
expect(dbl.tap { nil }).to be(dbl)
expect(dbl.to_json).to eq("foo")
expect(dbl.to_json(io)).to be_nil
expect(dbl.to_pretty_json).to eq("foo")
expect(dbl.to_pretty_json(io)).to be_nil
expect(dbl.to_s).to eq("foo")
expect(dbl.to_s).to contain("EmptyDouble")
expect(dbl.to_s(io)).to be_nil
expect(dbl.to_yaml).to eq("foo")
expect(dbl.to_yaml(io)).to be_nil
expect(dbl.try { nil }).to be_nil
expect(dbl.object_id).to eq(42)
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" do
expect { dbl.same?(123) }.to raise_error(Spectator::UnexpectedMessage, /\(123\)/)
it "reports arguments when they don't match" do
expect { dbl.same?(123, :xyz) }.to raise_error(Spectator::UnexpectedMessage, /\(123, :xyz\)/)
end
end

View file

@ -155,23 +155,30 @@ Spectator.describe Spectator::NullDouble do
context "without common object methods" do
subject(dbl) { EmptyDouble.new }
it "returns self with undefined messages" do
it "returns original implementation with undefined messages" do
hasher = Crystal::Hasher.new
aggregate_failures do
# Methods that would cause type cast errors are omitted from this list.
expect(dbl.!=(42)).to be(dbl)
expect(dbl.!~(42)).to be(dbl)
expect(dbl.==(42)).to be(dbl)
expect(dbl.===(42)).to be(dbl)
expect(dbl.=~(42)).to be(dbl)
expect(dbl.class).to be(dbl)
expect(dbl.dup).to be(dbl)
expect(dbl.hash(hasher)).to be(dbl)
expect(dbl.hash).to be(dbl)
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.inspect).to contain("EmptyDouble")
expect(dbl.itself).to be(dbl)
expect(dbl.not_nil!).to be(dbl)
expect(dbl.pretty_inspect).to contain("EmptyDouble")
expect(dbl.tap { nil }).to be(dbl)
expect(dbl.try { nil }).to be(dbl)
expect(dbl.to_s).to contain("EmptyDouble")
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
@ -192,12 +199,12 @@ Spectator.describe Spectator::NullDouble do
expect(dbl.foo("foobar")).to eq("bar")
end
it "returns self when constraint unsatisfied" do
expect(dbl.foo("baz")).to be(dbl)
it "raises self 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)
it "raises self when argument count doesn't match" do
expect { dbl.foo }.to raise_error(Spectator::UnexpectedMessage, /foo/)
end
it "ignores the block argument if not in the constraint" do
@ -217,12 +224,12 @@ Spectator.describe Spectator::NullDouble do
expect(dbl.hash("foobar")).to eq(12345)
end
it "returns self when constraint unsatisfied" do
expect(dbl.hash("baz")).to be(dbl)
it "raises when constraint unsatisfied" do
expect { dbl.hash("baz") }.to raise_error(Spectator::UnexpectedMessage, /hash/)
end
it "returns self when argument count doesn't match" do
expect(dbl.hash).to be(dbl)
it "raises when argument count doesn't match" do
expect { dbl.hash }.to raise_error(Spectator::UnexpectedMessage, /hash/)
end
end
end

View file

@ -110,13 +110,8 @@ module Spectator
end
private def _spectator_stub_fallback(call : MethodCall, &)
if @stubs.any? { |stub| stub.method == call.method }
Log.info { "Stubs are defined for #{call.method.inspect}, but none matched (no argument constraints met)." }
raise UnexpectedMessage.new("#{_spectator_stubbed_name} received unexpected message #{call}")
else
Log.trace { "Fallback for #{call} - call original" }
yield
end
Log.trace { "Fallback for #{call} - call original" }
yield
end
private def _spectator_stub_fallback(call : MethodCall, _type, &)
@ -124,6 +119,12 @@ module Spectator
end
private def _spectator_abstract_stub_fallback(call : MethodCall)
Log.info do
break unless @stubs.any? { |stub| stub.method == call.method }
"Stubs are defined for #{call.method.inspect}, but none matched (no argument constraints met)."
end
raise UnexpectedMessage.new("#{_spectator_stubbed_name} received unexpected message #{call}")
end

View file

@ -31,6 +31,16 @@ module Spectator
"#<LazyDouble #{@name || "Anonymous"}>"
end
private def _spectator_stub_fallback(call : MethodCall, &)
if @stubs.any? { |stub| stub.method == call.method }
Log.info { "Stubs are defined for #{call.method.inspect}, but none matched (no argument constraints met)." }
raise UnexpectedMessage.new("#{_spectator_stubbed_name} received unexpected message #{call}")
else
Log.trace { "Fallback for #{call} - call original" }
yield
end
end
# Handles all messages.
macro method_missing(call)
Log.trace { "Got undefined method `{{call.name}}({{*call.args}}{% if call.named_args %}{% unless call.args.empty? %}, {% end %}{{*call.named_args}}{% end %}){% if call.block %} { ... }{% end %}`" }

View file

@ -23,16 +23,6 @@ module Spectator
{% end %}
end
private def _spectator_stub_fallback(call : MethodCall, &)
if @stubs.any? { |stub| stub.method == call.method }
Log.info { "Stubs are defined for #{call.method.inspect}, but none matched (no argument constraints met)." }
raise UnexpectedMessage.new("#{_spectator_stubbed_name} received unexpected message #{call}")
else
Log.trace { "Fallback for #{call} - return original" }
yield
end
end
private def _spectator_abstract_stub_fallback(call : MethodCall)
if @stubs.any? { |stub| stub.method == call.method }
Log.info { "Stubs are defined for #{call.method.inspect}, but none matched (no argument constraints met)." }
@ -43,10 +33,12 @@ module Spectator
end
end
# Specialization that matches when the return type matches self.
private def _spectator_abstract_stub_fallback(call : MethodCall, _type : self)
_spectator_abstract_stub_fallback(call)
end
# Default implementation that raises a `TypeCastError` since the return type isn't self.
private def _spectator_abstract_stub_fallback(call : MethodCall, type)
if @stubs.any? { |stub| stub.method == call.method }
Log.info { "Stubs are defined for #{call.method.inspect}, but none matched (no argument constraints met)." }