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

Commit 13ebc90

Browse files
committed
Prevent should from circumventing target check
By directly instantiating expectation handler, should/should_not was circumventing enforce_value_expectation check. subject(:action) { -> { raise } } it { should raise_error StandardError } would not print "The implicit block expectation syntax is deprecated", while subject(:action) { -> { raise } } it { is_expected.to raise_error StandardError } will. See rspec/rspec-expectations#1139
1 parent 5d8331d commit 13ebc90

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

lib/rspec/core/memoized_helpers.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ def subject
7878
# @note If you are using RSpec's newer expect-based syntax you may
7979
# want to use `is_expected.to` instead of `should`.
8080
def should(matcher=nil, message=nil)
81+
enforce_value_expectation(matcher, 'should')
8182
RSpec::Expectations::PositiveExpectationHandler.handle_matcher(subject, matcher, message)
8283
end
8384

@@ -97,6 +98,7 @@ def should(matcher=nil, message=nil)
9798
# @note If you are using RSpec's newer expect-based syntax you may
9899
# want to use `is_expected.to_not` instead of `should_not`.
99100
def should_not(matcher=nil, message=nil)
101+
enforce_value_expectation(matcher, 'should_not')
100102
RSpec::Expectations::NegativeExpectationHandler.handle_matcher(subject, matcher, message)
101103
end
102104

@@ -144,6 +146,21 @@ def __init_memoized
144146
end
145147
end
146148

149+
# @private
150+
def enforce_value_expectation(matcher, method_name)
151+
matcher_supports_value_expectations = matcher.supports_value_expectations? rescue true
152+
return if matcher_supports_value_expectations
153+
154+
RSpec.deprecate(
155+
"#{method_name} #{RSpec::Support::ObjectFormatter.format(matcher)}",
156+
:message =>
157+
"The implicit block expectation syntax is deprecated, you should pass " \
158+
"a block to `expect` to use the provided block expectation matcher " \
159+
"(#{RSpec::Support::ObjectFormatter.format(matcher)}), " \
160+
"or the matcher must implement `supports_value_expectations?`."
161+
)
162+
end
163+
147164
# @private
148165
class ThreadsafeMemoized
149166
def initialize

spec/rspec/core/memoized_helpers_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,28 @@ def hello_message; "Hello from module"; end
630630
end
631631
end
632632

633+
RSpec.describe 'implicit block expectation syntax' do
634+
matcher :block_matcher do
635+
match { |actual| true }
636+
supports_block_expectations
637+
def supports_value_expectations?
638+
false
639+
end
640+
end
641+
642+
subject { 'value or a Proc' }
643+
644+
it '`should` prints a deprecation warning when given a value' do
645+
expect_warn_deprecation(/The implicit block expectation syntax is deprecated, you should pass/)
646+
expect { should block_matcher }.not_to raise_error
647+
end
648+
649+
it '`should_not` prints a deprecation warning when given a value' do
650+
expect_warn_deprecation(/The implicit block expectation syntax is deprecated, you should pass/)
651+
expect { should_not block_matcher }.to raise_error(Exception)
652+
end
653+
end
654+
633655
RSpec.describe 'Module#define_method' do
634656
it 'retains its normal private visibility on Ruby versions where it is normally private', :if => RUBY_VERSION < '2.5' do
635657
a_module = Module.new

0 commit comments

Comments
 (0)