Skip to content
This repository has been archived by the owner on Nov 30, 2024. It is now read-only.

Prevent mismatched composed use of value and block matchers #1476

Merged
merged 1 commit into from
Aug 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Bug Fixes:
* When using null object doubles, prevent typos triggering dynamic matchers.
(Eric Mueller, #1455)
* Use `RSpec.warning` for an expectation warning rather than `Kernel.warn`. (Jon Rowe, #1472)
* Prevent mismatched use of block and value matchers in compound expectations. (Phil Pirozhkov, #1476)

Enhancements:

Expand Down
5 changes: 4 additions & 1 deletion lib/rspec/matchers/built_in/compound.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,11 @@ def initialize_copy(other)
def match(_expected, actual)
evaluator_klass = if supports_block_expectations? && Proc === actual
NestedEvaluator
else
elsif supports_value_expectations?
SequentialEvaluator
else
# Can't raise an ArgumentError in this context, as it's rescued
raise "Block and value matchers can't be combined in a compound expectation (#{matcher_1.description}, #{matcher_2.description})"
end

@evaluator = evaluator_klass.new(actual, matcher_1, matcher_2)
Expand Down
15 changes: 11 additions & 4 deletions spec/rspec/matchers/built_in/compound_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,17 @@ def expect_block
end

describe "expect(...).to custom_matcher.and(other_matcher)" do
it "treats a matcher that doesn't support value expectations correctly" do
expect {
expect([1, 2]).to include(1).and raise_error(/test/)
}.to fail_with(/but was not given a block/)
if RUBY_VERSION.to_f > 1.8 # The example can be adjusted to be compatible with Ruby 1.8, but it is then not indicative of the problem
binding.eval(<<-CODE, __FILE__, __LINE__)
it "does not allow composing incompatible matchers" do
arr = []
expect {
expect { arr << :foo }
.to change { arr }.to be_one
.and change { arr }.to include(:foo) # There is a barely noticeable difference: the `.and` runs on the wrong matcher, `be_one` instead of `change`
}.to raise_error("Block and value matchers can't be combined in a compound expectation (be one, change result to include :foo)")
end
CODE
end

it "treats a matcher that does support value expectations correctly" do
Expand Down
Loading