shard-spectator/spec/matchers/receive_matcher_spec.cr
2022-07-14 20:46:52 -06:00

515 lines
15 KiB
Crystal

require "../spec_helper"
Spectator.describe Spectator::Matchers::ReceiveMatcher do
let(stub) { Spectator::NullStub.new(:test_method) }
subject(matcher) { described_class.new(stub) }
let(args) { Spectator::Arguments.capture(1, "test", Symbol, foo: /bar/) }
let(args_stub) { Spectator::NullStub.new(:test_method, args) }
let(args_matcher) { described_class.new(args_stub) }
let(no_args_stub) { Spectator::NullStub.new(:test_method, Spectator::Arguments.none) }
let(no_args_matcher) { described_class.new(no_args_stub) }
double(:dbl, test_method: nil, irrelevant: nil)
let(dbl) { double(:dbl) }
let(actual) { Spectator::Value.new(dbl, "dbl") }
def successful_match
Spectator::Matchers::SuccessfulMatchData
end
def failed_match
Spectator::Matchers::FailedMatchData
end
describe "#description" do
subject { matcher.description }
it "includes the method name" do
is_expected.to contain("test_method")
end
context "without an argument constraint" do
it "mentions it accepts any arguments" do
is_expected.to contain("any args")
end
end
context "with no arguments" do
let(matcher) { no_args_matcher }
it "mentions there are none" do
is_expected.to contain("no args")
end
end
context "with arguments" do
let(matcher) { args_matcher }
it "lists the arguments" do
is_expected.to contain("1, \"test\", Symbol, foo: #{/bar/.inspect}")
end
end
end
describe "#with" do
subject { matcher.with(1, 2, 3, bar: /baz/) }
it "applies a constraint on arguments" do
dbl.test_method
expect(&.match(actual)).to be_a(failed_match)
dbl.test_method(1, 2, 3, bar: "foobarbaz")
expect(&.match(actual)).to be_a(successful_match)
end
end
describe "#match" do
subject(match_data) { matcher.match(actual) }
post_condition { expect(match_data.description).to contain("dbl received #test_method") }
let(failure_message) { match_data.as(Spectator::Matchers::FailedMatchData).failure_message }
context "with no argument constraint" do
post_condition { expect(&.description).to contain("(any args)") }
it "matches with no arguments" do
dbl.test_method
is_expected.to be_a(successful_match)
end
it "matches with any arguments" do
dbl.test_method("foo")
is_expected.to be_a(successful_match)
end
it "doesn't match with no calls" do
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl did not receive #test_method(any args)")
end
it "doesn't match with different calls" do
dbl.irrelevant("foo")
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl did not receive #test_method(any args)")
end
end
context "with a \"no arguments\" constraint" do
let(matcher) { no_args_matcher }
post_condition { expect(&.description).to contain("(no args)") }
it "matches with no arguments" do
dbl.test_method
is_expected.to be_a(successful_match)
end
it "doesn't match with arguments" do
dbl.test_method("foo")
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl did not receive #test_method(no args)")
end
it "doesn't match with no calls" do
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl did not receive #test_method(no args)")
end
it "doesn't match with different calls" do
dbl.irrelevant("foo")
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl did not receive #test_method(no args)")
end
end
context "with an arguments constraint" do
let(matcher) { args_matcher }
post_condition { expect(&.description).to contain("(1, \"test\", Symbol, foo: #{/bar/.inspect})") }
it "doesn't match with no arguments" do
dbl.test_method
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl did not receive #test_method(1, \"test\", Symbol, foo: #{/bar/.inspect})")
end
it "matches with matching arguments" do
dbl.test_method(1, "test", :xyz, foo: "foobarbaz")
is_expected.to be_a(successful_match)
end
it "doesn't match with differing arguments" do
dbl.test_method(1, "wrong", 42, foo: "wrong")
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl did not receive #test_method(1, \"test\", Symbol, foo: #{/bar/.inspect})")
end
it "doesn't match with no calls" do
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl did not receive #test_method(1, \"test\", Symbol, foo: #{/bar/.inspect})")
end
it "doesn't match with different calls" do
dbl.irrelevant("foo")
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl did not receive #test_method(1, \"test\", Symbol, foo: #{/bar/.inspect})")
end
end
describe "the match data values" do
let(matcher) { args_matcher }
subject(values) { match_data.as(Spectator::Matchers::FailedMatchData).values }
pre_condition { expect(match_data).to be_a(failed_match) }
it "has the expected call listed" do
is_expected.to contain({:expected, "#test_method(1, \"test\", Symbol, foo: #{/bar/.inspect})"})
end
context "with method calls" do
before_each do
dbl.test_method
dbl.test_method(1, "wrong", :xyz, foo: "foobarbaz")
dbl.irrelevant("foo")
end
it "has the list of called methods" do
is_expected.to contain({
:actual,
<<-SIGNATURES
#test_method(no args)
#test_method(1, "wrong", :xyz, foo: "foobarbaz")
#irrelevant("foo")
SIGNATURES
})
end
end
context "with no method calls" do
it "reports \"None\" for the actual value" do
is_expected.to contain({:actual, "None"})
end
end
end
end
describe "#negated_match" do
subject(match_data) { matcher.negated_match(actual) }
post_condition { expect(match_data.description).to contain("dbl did not receive #test_method") }
let(failure_message) { match_data.as(Spectator::Matchers::FailedMatchData).failure_message }
context "with no argument constraint" do
post_condition { expect(&.description).to contain("(any args)") }
it "doesn't match with no arguments" do
dbl.test_method
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl received #test_method(any args)")
end
it "doesn't match with any arguments" do
dbl.test_method("foo")
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl received #test_method(any args)")
end
it "matches with no calls" do
is_expected.to be_a(successful_match)
end
it "matches with different calls" do
dbl.irrelevant("foo")
is_expected.to be_a(successful_match)
end
end
context "with a \"no arguments\" constraint" do
let(matcher) { no_args_matcher }
post_condition { expect(&.description).to contain("(no args)") }
it "doesn't match with no arguments" do
dbl.test_method
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl received #test_method(no args)")
end
it "matches with arguments" do
dbl.test_method("foo")
is_expected.to be_a(successful_match)
end
it "matches with no calls" do
is_expected.to be_a(successful_match)
end
it "matches with different calls" do
dbl.irrelevant("foo")
is_expected.to be_a(successful_match)
end
end
context "with an arguments constraint" do
let(matcher) { args_matcher }
post_condition { expect(&.description).to contain("(1, \"test\", Symbol, foo: #{/bar/.inspect})") }
it "matches with no arguments" do
dbl.test_method
is_expected.to be_a(successful_match)
end
it "doesn't match with matching arguments" do
dbl.test_method(1, "test", :xyz, foo: "foobarbaz")
is_expected.to be_a(failed_match)
expect(failure_message).to eq("dbl received #test_method(1, \"test\", Symbol, foo: #{/bar/.inspect})")
end
it "matches with differing arguments" do
dbl.test_method(1, "wrong", 42, foo: "wrong")
is_expected.to be_a(successful_match)
end
it "matches with no calls" do
is_expected.to be_a(successful_match)
end
it "matches with different calls" do
dbl.irrelevant("foo")
is_expected.to be_a(successful_match)
end
end
describe "the match data values" do
subject(values) { match_data.as(Spectator::Matchers::FailedMatchData).values }
pre_condition { expect(match_data).to be_a(failed_match) }
before_each do
dbl.test_method
dbl.test_method(1, "test", :xyz, foo: "foobarbaz")
dbl.irrelevant("foo")
end
it "has the expected call listed" do
is_expected.to contain({:expected, "Not #{stub}"})
end
it "has the list of called methods" do
is_expected.to contain({
:actual,
<<-SIGNATURES
#test_method(no args)
#test_method(1, "test", :xyz, foo: "foobarbaz")
#irrelevant("foo")
SIGNATURES
})
end
end
end
describe "#once" do
let(matcher) { super.once }
subject(match_data) { matcher.match(actual) }
it "matches when the stub is called once" do
dbl.test_method
is_expected.to be_a(successful_match)
end
it "doesn't match when the stub isn't called" do
is_expected.to be_a(failed_match)
end
it "doesn't match when the stub is called twice" do
2.times { dbl.test_method }
is_expected.to be_a(failed_match)
end
end
describe "#twice" do
let(matcher) { super.twice }
subject(match_data) { matcher.match(actual) }
it "matches when the stub is called twice" do
2.times { dbl.test_method }
is_expected.to be_a(successful_match)
end
it "doesn't match when the stub isn't called" do
is_expected.to be_a(failed_match)
end
it "doesn't match when the stub is called once" do
dbl.test_method
is_expected.to be_a(failed_match)
end
it "doesn't match when the stub is called thrice" do
3.times { dbl.test_method }
is_expected.to be_a(failed_match)
end
end
describe "#exactly" do
let(matcher) { super.exactly(3) }
subject(match_data) { matcher.match(actual) }
it "matches when the stub is called the exact amount" do
3.times { dbl.test_method }
is_expected.to be_a(successful_match)
end
it "doesn't match when the stub isn't called" do
is_expected.to be_a(failed_match)
end
it "doesn't match when the stub is called less than the amount" do
2.times { dbl.test_method }
is_expected.to be_a(failed_match)
end
it "doesn't match when the stub is called more than the amount" do
4.times { dbl.test_method }
is_expected.to be_a(failed_match)
end
end
describe "#at_least" do
let(matcher) { super.at_least(3) }
subject(match_data) { matcher.match(actual) }
it "matches when the stub is called the exact amount" do
3.times { dbl.test_method }
is_expected.to be_a(successful_match)
end
it "doesn't match when the stub isn't called" do
is_expected.to be_a(failed_match)
end
it "doesn't match when the stub is called less than the amount" do
2.times { dbl.test_method }
is_expected.to be_a(failed_match)
end
it "matches when the stub is called more than the amount" do
4.times { dbl.test_method }
is_expected.to be_a(successful_match)
end
end
describe "#at_most" do
let(matcher) { super.at_most(3) }
subject(match_data) { matcher.match(actual) }
it "matches when the stub is called the exact amount" do
3.times { dbl.test_method }
is_expected.to be_a(successful_match)
end
it "matches when the stub isn't called" do
is_expected.to be_a(successful_match)
end
it "matches when the stub is called less than the amount" do
2.times { dbl.test_method }
is_expected.to be_a(successful_match)
end
it "doesn't match when the stub is called more than the amount" do
4.times { dbl.test_method }
is_expected.to be_a(failed_match)
end
end
describe "#at_least_once" do
let(matcher) { super.at_least_once }
subject(match_data) { matcher.match(actual) }
it "matches when the stub is called once" do
dbl.test_method
is_expected.to be_a(successful_match)
end
it "doesn't match when the stub isn't called" do
is_expected.to be_a(failed_match)
end
it "matches when the stub is called more than once" do
2.times { dbl.test_method }
is_expected.to be_a(successful_match)
end
end
describe "#at_least_twice" do
let(matcher) { super.at_least_twice }
subject(match_data) { matcher.match(actual) }
it "doesn't match when the stub is called once" do
dbl.test_method
is_expected.to be_a(failed_match)
end
it "doesn't match when the stub isn't called" do
is_expected.to be_a(failed_match)
end
it "matches when the stub is called twice" do
2.times { dbl.test_method }
is_expected.to be_a(successful_match)
end
it "matches when the stub is called more than twice" do
3.times { dbl.test_method }
is_expected.to be_a(successful_match)
end
end
describe "#at_most_once" do
let(matcher) { super.at_most_once }
subject(match_data) { matcher.match(actual) }
it "matches when the stub is called once" do
dbl.test_method
is_expected.to be_a(successful_match)
end
it "matches when the stub isn't called" do
is_expected.to be_a(successful_match)
end
it "doesn't match when the stub is called more than once" do
2.times { dbl.test_method }
is_expected.to be_a(failed_match)
end
end
describe "#at_most_twice" do
let(matcher) { super.at_most_twice }
subject(match_data) { matcher.match(actual) }
it "matches when the stub is called once" do
dbl.test_method
is_expected.to be_a(successful_match)
end
it "matches when the stub isn't called" do
is_expected.to be_a(successful_match)
end
it "matches when the stub is called twice" do
2.times { dbl.test_method }
is_expected.to be_a(successful_match)
end
it "doesn't match when the stub is called more than twice" do
3.times { dbl.test_method }
is_expected.to be_a(failed_match)
end
end
end