rspec-expectations 3.8.5 → 3.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,7 +23,7 @@ module RSpec
23
23
  # a percent comparison.
24
24
  def percent_of(expected)
25
25
  @expected = expected
26
- @tolerance = @delta * @expected.abs / 100.0
26
+ @tolerance = @expected.abs * @delta / 100.0
27
27
  @unit = '%'
28
28
  self
29
29
  end
@@ -50,7 +50,7 @@ module RSpec
50
50
  # @api private
51
51
  # @return [String]
52
52
  def description
53
- "be within #{@delta}#{@unit} of #{@expected}"
53
+ "be within #{@delta}#{@unit} of #{expected_formatted}"
54
54
  end
55
55
 
56
56
  private
@@ -77,11 +77,6 @@ module RSpec
77
77
  true
78
78
  end
79
79
 
80
- # @private
81
- def supports_value_expectations?
82
- false
83
- end
84
-
85
80
  private
86
81
 
87
82
  def initialize(receiver=nil, message=nil, &block)
@@ -112,10 +107,12 @@ module RSpec
112
107
  end
113
108
 
114
109
  def positive_failure_reason
110
+ return "was not given a block" unless Proc === @event_proc
115
111
  "is still #{@actual_before_description}"
116
112
  end
117
113
 
118
114
  def negative_failure_reason
115
+ return "was not given a block" unless Proc === @event_proc
119
116
  "did change from #{@actual_before_description} " \
120
117
  "to #{description_of change_details.actual_after}"
121
118
  end
@@ -161,14 +158,10 @@ module RSpec
161
158
  true
162
159
  end
163
160
 
164
- # @private
165
- def supports_value_expectations?
166
- false
167
- end
168
-
169
161
  private
170
162
 
171
163
  def failure_reason
164
+ return "was not given a block" unless Proc === @event_proc
172
165
  "was changed by #{description_of @change_details.actual_delta}"
173
166
  end
174
167
  end
@@ -197,6 +190,7 @@ module RSpec
197
190
 
198
191
  # @private
199
192
  def failure_message
193
+ return not_given_a_block_failure unless Proc === @event_proc
200
194
  return before_value_failure unless @matches_before
201
195
  return did_not_change_failure unless @change_details.changed?
202
196
  after_value_failure
@@ -207,11 +201,6 @@ module RSpec
207
201
  true
208
202
  end
209
203
 
210
- # @private
211
- def supports_value_expectations?
212
- false
213
- end
214
-
215
204
  private
216
205
 
217
206
  def perform_change(event_proc)
@@ -253,6 +242,11 @@ module RSpec
253
242
  "did change from #{@actual_before_description} " \
254
243
  "to #{description_of @change_details.actual_after}"
255
244
  end
245
+
246
+ def not_given_a_block_failure
247
+ "expected #{@change_details.value_representation} to have changed " \
248
+ "#{change_description}, but was not given a block"
249
+ end
256
250
  end
257
251
 
258
252
  # @api private
@@ -284,6 +278,7 @@ module RSpec
284
278
 
285
279
  # @private
286
280
  def failure_message_when_negated
281
+ return not_given_a_block_failure unless Proc === @event_proc
287
282
  return before_value_failure unless @matches_before
288
283
  did_change_failure
289
284
  end
@@ -26,19 +26,11 @@ module RSpec
26
26
  "#{matcher_1.description} #{conjunction} #{matcher_2.description}"
27
27
  end
28
28
 
29
- # @api private
30
29
  def supports_block_expectations?
31
30
  matcher_supports_block_expectations?(matcher_1) &&
32
31
  matcher_supports_block_expectations?(matcher_2)
33
32
  end
34
33
 
35
- # @api private
36
- def supports_value_expectations?
37
- matcher_supports_value_expectations?(matcher_1) &&
38
- matcher_supports_value_expectations?(matcher_2)
39
- end
40
-
41
- # @api private
42
34
  def expects_call_stack_jump?
43
35
  NestedEvaluator.matcher_expects_call_stack_jump?(matcher_1) ||
44
36
  NestedEvaluator.matcher_expects_call_stack_jump?(matcher_2)
@@ -110,12 +102,6 @@ module RSpec
110
102
  false
111
103
  end
112
104
 
113
- def matcher_supports_value_expectations?(matcher)
114
- matcher.supports_value_expectations?
115
- rescue NoMethodError
116
- true
117
- end
118
-
119
105
  def matcher_is_diffable?(matcher)
120
106
  matcher.diffable?
121
107
  rescue NoMethodError
@@ -168,7 +154,12 @@ module RSpec
168
154
  end
169
155
 
170
156
  def matcher_matches?(matcher)
171
- @match_results.fetch(matcher)
157
+ @match_results.fetch(matcher) do
158
+ raise ArgumentError, "Your #{matcher.description} has no match " \
159
+ "results, this can occur when an unexpected call stack or " \
160
+ "local jump occurs. Prehaps one of your matchers needs to " \
161
+ "declare `expects_call_stack_jump?` as `true`?"
162
+ end
172
163
  end
173
164
 
174
165
  private
@@ -5,8 +5,16 @@ module RSpec
5
5
  # Provides the implementation for `has_<predicate>`.
6
6
  # Not intended to be instantiated directly.
7
7
  class Has < BaseMatcher
8
- def initialize(method_name, *args, &block)
9
- @method_name, @args, @block = method_name, args, block
8
+ if RSpec::Support::RubyFeatures.kw_args_supported?
9
+ binding.eval(<<-CODE, __FILE__, __LINE__)
10
+ def initialize(method_name, *args, **kwargs, &block)
11
+ @method_name, @args, @kwargs, @block = method_name, args, kwargs, block
12
+ end
13
+ CODE
14
+ else
15
+ def initialize(method_name, *args, &block)
16
+ @method_name, @args, @block = method_name, args, block
17
+ end
10
18
  end
11
19
 
12
20
  # @private
@@ -64,8 +72,20 @@ module RSpec
64
72
  @actual.respond_to? predicate
65
73
  end
66
74
 
67
- def predicate_matches?
68
- @actual.__send__(predicate, *@args, &@block)
75
+ if RSpec::Support::RubyFeatures.kw_args_supported?
76
+ binding.eval(<<-CODE, __FILE__, __LINE__)
77
+ def predicate_matches?
78
+ if @kwargs.empty?
79
+ @actual.__send__(predicate, *@args, &@block)
80
+ else
81
+ @actual.__send__(predicate, *@args, **@kwargs, &@block)
82
+ end
83
+ end
84
+ CODE
85
+ else
86
+ def predicate_matches?
87
+ @actual.__send__(predicate, *@args, &@block)
88
+ end
69
89
  end
70
90
 
71
91
  def predicate
@@ -93,7 +93,7 @@ module RSpec
93
93
  end
94
94
 
95
95
  def respond_to_matcher
96
- @respond_to_matcher ||= RespondTo.new(*expected.keys).with(0).arguments
96
+ @respond_to_matcher ||= RespondTo.new(*expected.keys).with(0).arguments.tap { |m| m.ignoring_method_signature_failure! }
97
97
  end
98
98
 
99
99
  def respond_to_failure_message_or
@@ -94,13 +94,6 @@ module RSpec
94
94
  true
95
95
  end
96
96
 
97
- # @api private
98
- # Indicates this matcher matches against a block only.
99
- # @return [False]
100
- def supports_value_expectations?
101
- false
102
- end
103
-
104
97
  private
105
98
 
106
99
  def captured?
@@ -108,11 +101,13 @@ module RSpec
108
101
  end
109
102
 
110
103
  def positive_failure_reason
104
+ return "was not a block" unless Proc === @block
111
105
  return "output #{actual_output_description}" if @expected
112
106
  "did not"
113
107
  end
114
108
 
115
109
  def negative_failure_reason
110
+ return "was not a block" unless Proc === @block
116
111
  "output #{actual_output_description}"
117
112
  end
118
113
 
@@ -76,12 +76,6 @@ module RSpec
76
76
  true
77
77
  end
78
78
 
79
- # @private
80
- def supports_value_expectations?
81
- false
82
- end
83
-
84
- # @private
85
79
  def expects_call_stack_jump?
86
80
  true
87
81
  end
@@ -205,6 +199,7 @@ module RSpec
205
199
  end
206
200
 
207
201
  def given_error
202
+ return " but was not given a block" unless Proc === @given_proc
208
203
  return " but nothing was raised" unless @actual_error
209
204
 
210
205
  backtrace = format_backtrace(@actual_error.backtrace)
@@ -1,5 +1,7 @@
1
1
  RSpec::Support.require_rspec_support "method_signature_verifier"
2
2
 
3
+ # TODO: Refactor this file to be under our class length
4
+ # rubocop:disable ClassLength
3
5
  module RSpec
4
6
  module Matchers
5
7
  module BuiltIn
@@ -11,6 +13,7 @@ module RSpec
11
13
  @names = names
12
14
  @expected_arity = nil
13
15
  @expected_keywords = []
16
+ @ignoring_method_signature_failure = false
14
17
  @unlimited_arguments = nil
15
18
  @arbitrary_keywords = nil
16
19
  end
@@ -100,6 +103,12 @@ module RSpec
100
103
  "respond to #{pp_names}#{with_arity}"
101
104
  end
102
105
 
106
+ # @api private
107
+ # Used by other matchers to suppress a check
108
+ def ignoring_method_signature_failure!
109
+ @ignoring_method_signature_failure = true
110
+ end
111
+
103
112
  private
104
113
 
105
114
  def find_failing_method_names(actual, filter_method)
@@ -109,7 +118,7 @@ module RSpec
109
118
  end
110
119
  end
111
120
 
112
- def matches_arity?(actual, name)
121
+ def setup_method_signature_expectation
113
122
  expectation = Support::MethodSignatureExpectation.new
114
123
 
115
124
  if @expected_arity.is_a?(Range)
@@ -123,11 +132,35 @@ module RSpec
123
132
  expectation.expect_unlimited_arguments = @unlimited_arguments
124
133
  expectation.expect_arbitrary_keywords = @arbitrary_keywords
125
134
 
135
+ expectation
136
+ end
137
+
138
+ def matches_arity?(actual, name)
139
+ expectation = setup_method_signature_expectation
140
+
126
141
  return true if expectation.empty?
127
142
 
128
- signature = Support::MethodSignature.new(Support.method_handle_for(actual, name))
143
+ begin
144
+ Support::StrictSignatureVerifier.new(method_signature_for(actual, name)).
145
+ with_expectation(expectation).valid?
146
+ rescue NameError
147
+ return true if @ignoring_method_signature_failure
148
+ raise ArgumentError, "The #{matcher_name} matcher requires that " \
149
+ "the actual object define the method(s) in " \
150
+ "order to check arity, but the method " \
151
+ "`#{name}` is not defined. Remove the arity " \
152
+ "check or define the method to continue."
153
+ end
154
+ end
155
+
156
+ def method_signature_for(actual, name)
157
+ method_handle = Support.method_handle_for(actual, name)
129
158
 
130
- Support::StrictSignatureVerifier.new(signature).with_expectation(expectation).valid?
159
+ if name == :new && method_handle.owner === ::Class && ::Class === actual
160
+ Support::MethodSignature.new(actual.instance_method(:initialize))
161
+ else
162
+ Support::MethodSignature.new(method_handle)
163
+ end
131
164
  end
132
165
 
133
166
  def with_arity
@@ -163,3 +196,4 @@ module RSpec
163
196
  end
164
197
  end
165
198
  end
199
+ # rubocop:enable ClassLength
@@ -88,16 +88,12 @@ module RSpec
88
88
  end
89
89
 
90
90
  # @api private
91
+ # Indicates this matcher matches against a block.
92
+ # @return [True]
91
93
  def supports_block_expectations?
92
94
  true
93
95
  end
94
96
 
95
- # @api private
96
- def supports_value_expectations?
97
- false
98
- end
99
-
100
- # @api private
101
97
  def expects_call_stack_jump?
102
98
  true
103
99
  end
@@ -105,6 +101,7 @@ module RSpec
105
101
  private
106
102
 
107
103
  def actual_result
104
+ return "but was not a block" unless Proc === @block
108
105
  "got #{caught}"
109
106
  end
110
107
 
@@ -10,6 +10,7 @@ module RSpec
10
10
  class YieldProbe
11
11
  def self.probe(block, &callback)
12
12
  probe = new(block, &callback)
13
+ return probe unless probe.has_block?
13
14
  probe.probe
14
15
  end
15
16
 
@@ -23,6 +24,10 @@ module RSpec
23
24
  self.yielded_args = []
24
25
  end
25
26
 
27
+ def has_block?
28
+ Proc === @block
29
+ end
30
+
26
31
  def probe
27
32
  assert_valid_expect_block!
28
33
  @block.call(self)
@@ -93,7 +98,7 @@ module RSpec
93
98
  # Not intended to be instantiated directly.
94
99
  class YieldControl < BaseMatcher
95
100
  def initialize
96
- at_least(:once)
101
+ @expectation_type = @expected_yields_count = nil
97
102
  end
98
103
 
99
104
  # @api public
@@ -147,12 +152,14 @@ module RSpec
147
152
  # @private
148
153
  def matches?(block)
149
154
  @probe = YieldProbe.probe(block)
155
+ return false unless @probe.has_block?
156
+ return @probe.num_yields > 0 unless @expectation_type
150
157
  @probe.num_yields.__send__(@expectation_type, @expected_yields_count)
151
158
  end
152
159
 
153
160
  # @private
154
161
  def does_not_match?(block)
155
- !matches?(block)
162
+ !matches?(block) && @probe.has_block?
156
163
  end
157
164
 
158
165
  # @api private
@@ -172,42 +179,47 @@ module RSpec
172
179
  true
173
180
  end
174
181
 
175
- # @private
176
- def supports_value_expectations?
177
- false
178
- end
179
-
180
182
  private
181
183
 
182
184
  def set_expected_yields_count(relativity, n)
185
+ raise "Multiple count constraints are not supported" if @expectation_type
186
+
183
187
  @expectation_type = relativity
184
- @expected_yields_count = case n
185
- when Numeric then n
186
- when :once then 1
187
- when :twice then 2
188
- when :thrice then 3
189
- end
188
+ @expected_yields_count = count_constraint_to_number(n)
189
+ end
190
+
191
+ def count_constraint_to_number(n)
192
+ case n
193
+ when Numeric then n
194
+ when :once then 1
195
+ when :twice then 2
196
+ when :thrice then 3
197
+ else
198
+ raise ArgumentError, "Expected a number, :once, :twice or :thrice," \
199
+ " but got #{n}"
200
+ end
190
201
  end
191
202
 
192
203
  def failure_reason
193
- return '' unless @expected_yields_count
194
- " #{human_readable_expectation_type}#{human_readable_count(@expected_yields_count)}" \
195
- " but yielded #{human_readable_count(@probe.num_yields)}"
204
+ return ' but was not a block' unless @probe.has_block?
205
+ "#{human_readable_expectation_type}#{human_readable_count(@expected_yields_count)}" \
206
+ " but yielded#{human_readable_count(@probe.num_yields)}"
196
207
  end
197
208
 
198
209
  def human_readable_expectation_type
199
210
  case @expectation_type
200
- when :<= then 'at most '
201
- when :>= then 'at least '
211
+ when :<= then ' at most'
212
+ when :>= then ' at least'
202
213
  else ''
203
214
  end
204
215
  end
205
216
 
206
217
  def human_readable_count(count)
207
218
  case count
208
- when 1 then 'once'
209
- when 2 then 'twice'
210
- else "#{count} times"
219
+ when nil then ''
220
+ when 1 then ' once'
221
+ when 2 then ' twice'
222
+ else " #{count} times"
211
223
  end
212
224
  end
213
225
  end
@@ -219,12 +231,13 @@ module RSpec
219
231
  # @private
220
232
  def matches?(block)
221
233
  @probe = YieldProbe.probe(block)
234
+ return false unless @probe.has_block?
222
235
  @probe.yielded_once?(:yield_with_no_args) && @probe.single_yield_args.empty?
223
236
  end
224
237
 
225
238
  # @private
226
239
  def does_not_match?(block)
227
- !matches?(block)
240
+ !matches?(block) && @probe.has_block?
228
241
  end
229
242
 
230
243
  # @private
@@ -242,19 +255,16 @@ module RSpec
242
255
  true
243
256
  end
244
257
 
245
- # @private
246
- def supports_value_expectations?
247
- false
248
- end
249
-
250
258
  private
251
259
 
252
260
  def positive_failure_reason
261
+ return 'was not a block' unless @probe.has_block?
253
262
  return 'did not yield' if @probe.num_yields.zero?
254
263
  "yielded with arguments: #{description_of @probe.single_yield_args}"
255
264
  end
256
265
 
257
266
  def negative_failure_reason
267
+ return 'was not a block' unless @probe.has_block?
258
268
  'did'
259
269
  end
260
270
  end
@@ -275,13 +285,14 @@ module RSpec
275
285
  @actual_formatted = actual_formatted
276
286
  @args_matched_when_yielded &&= args_currently_match?
277
287
  end
288
+ return false unless @probe.has_block?
278
289
  @probe.probe
279
290
  @probe.yielded_once?(:yield_with_args) && @args_matched_when_yielded
280
291
  end
281
292
 
282
293
  # @private
283
294
  def does_not_match?(block)
284
- !matches?(block)
295
+ !matches?(block) && @probe.has_block?
285
296
  end
286
297
 
287
298
  # @private
@@ -306,14 +317,10 @@ module RSpec
306
317
  true
307
318
  end
308
319
 
309
- # @private
310
- def supports_value_expectations?
311
- false
312
- end
313
-
314
320
  private
315
321
 
316
322
  def positive_failure_reason
323
+ return 'was not a block' unless @probe.has_block?
317
324
  return 'did not yield' if @probe.num_yields.zero?
318
325
  @positive_args_failure
319
326
  end
@@ -323,7 +330,9 @@ module RSpec
323
330
  end
324
331
 
325
332
  def negative_failure_reason
326
- if @args_matched_when_yielded && !@expected.empty?
333
+ if !@probe.has_block?
334
+ 'was not a block'
335
+ elsif @args_matched_when_yielded && !@expected.empty?
327
336
  'yielded with expected arguments' \
328
337
  "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \
329
338
  "\n got: #{@actual_formatted}"
@@ -375,11 +384,12 @@ module RSpec
375
384
  yield_count += 1
376
385
  end
377
386
 
387
+ return false unless @probe.has_block?
378
388
  args_matched_when_yielded && yield_count == @expected.length
379
389
  end
380
390
 
381
391
  def does_not_match?(block)
382
- !matches?(block)
392
+ !matches?(block) && @probe.has_block?
383
393
  end
384
394
 
385
395
  # @private
@@ -404,11 +414,6 @@ module RSpec
404
414
  true
405
415
  end
406
416
 
407
- # @private
408
- def supports_value_expectations?
409
- false
410
- end
411
-
412
417
  private
413
418
 
414
419
  def expected_arg_description
@@ -416,12 +421,16 @@ module RSpec
416
421
  end
417
422
 
418
423
  def positive_failure_reason
424
+ return 'was not a block' unless @probe.has_block?
425
+
419
426
  'yielded with unexpected arguments' \
420
427
  "\nexpected: #{surface_descriptions_in(@expected).inspect}" \
421
428
  "\n got: [#{@actual_formatted.join(", ")}]"
422
429
  end
423
430
 
424
431
  def negative_failure_reason
432
+ return 'was not a block' unless @probe.has_block?
433
+
425
434
  'yielded with expected arguments' \
426
435
  "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \
427
436
  "\n got: [#{@actual_formatted.join(", ")}]"