mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Implement ProcStub
This commit is contained in:
parent
4d5004ab4f
commit
cd177dd2ae
4 changed files with 245 additions and 2 deletions
|
@ -27,4 +27,25 @@ Spectator.describe "Stub DSL", :smoke do
|
|||
allow(dbl).to receive(:foo).and_return(:xyz)
|
||||
expect { dbl.foo }.to raise_error(TypeCastError, /Int32/)
|
||||
end
|
||||
|
||||
describe "#receive" do
|
||||
it "returns the value from the block" do
|
||||
allow(dbl).to receive(:foo) { 5 }
|
||||
expect(dbl.foo).to eq(5)
|
||||
end
|
||||
|
||||
it "accepts and calls block" do
|
||||
count = 0
|
||||
allow(dbl).to receive(:foo) { count += 1 }
|
||||
expect { dbl.foo }.to change { count }.from(0).to(1)
|
||||
end
|
||||
|
||||
it "passes the arguments to the block" do
|
||||
captured = nil.as(Spectator::AbstractArguments?)
|
||||
allow(dbl).to receive(:foo) { |a| captured = a; 0 }
|
||||
dbl.foo(3, 5, 7, bar: "baz")
|
||||
args = Spectator::Arguments.capture(3, 5, 7, bar: "baz")
|
||||
expect(captured).to eq(args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
182
spec/spectator/mocks/proc_stub_spec.cr
Normal file
182
spec/spectator/mocks/proc_stub_spec.cr
Normal file
|
@ -0,0 +1,182 @@
|
|||
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 { |args| @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
|
|
@ -308,8 +308,25 @@ module Spectator::DSL
|
|||
# allow(dbl).to receive(:foo).and_return(42)
|
||||
# expect(dbl.foo).to eq(42)
|
||||
# ```
|
||||
macro receive(method, *, _file = __FILE__, _line = __LINE__)
|
||||
::Spectator::NullStub.new({{method.id.symbolize}}, location: ::Spectator::Location.new({{_file}}, {{_line}}))
|
||||
#
|
||||
# A block can be provided to be run every time the stub is invoked.
|
||||
# The value returned by the block is returned by the stubbed method.
|
||||
#
|
||||
# ```
|
||||
# dbl = dbl(:foobar)
|
||||
# allow(dbl).to receive(:foo) { 42 }
|
||||
# expect(dbl.foo).to eq(42)
|
||||
# ```
|
||||
macro receive(method, *, _file = __FILE__, _line = __LINE__, &block)
|
||||
{% if block %}
|
||||
%proc = ->(%args : ::Spectator::AbstractArguments) {
|
||||
{% if !block.args.empty? %}{{*block.args}} = %args {% end %}
|
||||
{{block.body}}
|
||||
}
|
||||
::Spectator::ProcStub.new({{method.id.symbolize}}, %proc, location: ::Spectator::Location.new({{_file}}, {{_line}}))
|
||||
{% else %}
|
||||
::Spectator::NullStub.new({{method.id.symbolize}}, location: ::Spectator::Location.new({{_file}}, {{_line}}))
|
||||
{% end %}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
23
src/spectator/mocks/proc_stub.cr
Normal file
23
src/spectator/mocks/proc_stub.cr
Normal file
|
@ -0,0 +1,23 @@
|
|||
require "../location"
|
||||
require "./arguments"
|
||||
require "./typed_stub"
|
||||
|
||||
module Spectator
|
||||
# Stub that responds with a value returned by calling a proc.
|
||||
class ProcStub(T) < TypedStub(T)
|
||||
# Invokes the stubbed implementation.
|
||||
def call(call : MethodCall) : T
|
||||
@proc.call(call.arguments)
|
||||
end
|
||||
|
||||
# Creates the stub.
|
||||
def initialize(method : Symbol, @proc : Proc(AbstractArguments, T), constraint : AbstractArguments? = nil, location : Location? = nil)
|
||||
super(method, constraint, location)
|
||||
end
|
||||
|
||||
# Creates the stub.
|
||||
def initialize(method : Symbol, constraint : AbstractArguments? = nil, location : Location? = nil, &block : Proc(AbstractArguments, T))
|
||||
initialize(method, block, constraint, location)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue