rspec-expectations 3.9.4 → 3.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,13 +9,20 @@ module RSpec
9
9
  class RaiseError
10
10
  include Composable
11
11
 
12
- def initialize(expected_error_or_message=nil, expected_message=nil, &block)
12
+ # Used as a sentinel value to be able to tell when the user did not pass an
13
+ # argument. We can't use `nil` for that because we need to warn when `nil` is
14
+ # passed in a different way. It's an Object, not a Module, since Module's `===`
15
+ # does not evaluate to true when compared to itself.
16
+ UndefinedValue = Object.new.freeze
17
+
18
+ def initialize(expected_error_or_message, expected_message, &block)
13
19
  @block = block
14
20
  @actual_error = nil
15
- @warn_about_bare_error = expected_error_or_message.nil?
21
+ @warn_about_bare_error = UndefinedValue === expected_error_or_message
22
+ @warn_about_nil_error = expected_error_or_message.nil?
16
23
 
17
24
  case expected_error_or_message
18
- when nil
25
+ when nil, UndefinedValue
19
26
  @expected_error = Exception
20
27
  @expected_message = expected_message
21
28
  when String
@@ -58,8 +65,11 @@ module RSpec
58
65
  end
59
66
  end
60
67
 
61
- warn_about_bare_error if warning_about_bare_error && !negative_expectation
62
- eval_block if !negative_expectation && ready_to_eval_block?
68
+ unless negative_expectation
69
+ warn_about_bare_error! if warn_about_bare_error?
70
+ warn_about_nil_error! if warn_about_nil_error?
71
+ eval_block if ready_to_eval_block?
72
+ end
63
73
 
64
74
  expectation_matched?
65
75
  end
@@ -67,7 +77,7 @@ module RSpec
67
77
 
68
78
  # @private
69
79
  def does_not_match?(given_proc)
70
- warn_for_false_positives
80
+ warn_for_negative_false_positives!
71
81
  !matches?(given_proc, :negative_expectation) && Proc === given_proc
72
82
  end
73
83
 
@@ -131,29 +141,35 @@ module RSpec
131
141
  values_match?(@expected_message, @actual_error.message.to_s)
132
142
  end
133
143
 
134
- def warn_for_false_positives
144
+ def warn_for_negative_false_positives!
135
145
  expression = if expecting_specific_exception? && @expected_message
136
146
  "`expect { }.not_to raise_error(SpecificErrorClass, message)`"
137
147
  elsif expecting_specific_exception?
138
148
  "`expect { }.not_to raise_error(SpecificErrorClass)`"
139
149
  elsif @expected_message
140
150
  "`expect { }.not_to raise_error(message)`"
151
+ elsif @warn_about_nil_error
152
+ "`expect { }.not_to raise_error(nil)`"
141
153
  end
142
154
 
143
155
  return unless expression
144
156
 
145
- warn_about_negative_false_positive expression
157
+ warn_about_negative_false_positive! expression
146
158
  end
147
159
 
148
160
  def handle_warning(message)
149
161
  RSpec::Expectations.configuration.false_positives_handler.call(message)
150
162
  end
151
163
 
152
- def warning_about_bare_error
164
+ def warn_about_bare_error?
153
165
  @warn_about_bare_error && @block.nil?
154
166
  end
155
167
 
156
- def warn_about_bare_error
168
+ def warn_about_nil_error?
169
+ @warn_about_nil_error
170
+ end
171
+
172
+ def warn_about_bare_error!
157
173
  handle_warning("Using the `raise_error` matcher without providing a specific " \
158
174
  "error or message risks false positives, since `raise_error` " \
159
175
  "will match when Ruby raises a `NoMethodError`, `NameError` or " \
@@ -166,11 +182,24 @@ module RSpec
166
182
  "_positives = :nothing`")
167
183
  end
168
184
 
169
- def warn_about_negative_false_positive(expression)
185
+ def warn_about_nil_error!
186
+ handle_warning("Using the `raise_error` matcher with a `nil` error is probably " \
187
+ "unintentional, it risks false positives, since `raise_error` " \
188
+ "will match when Ruby raises a `NoMethodError`, `NameError` or " \
189
+ "`ArgumentError`, potentially allowing the expectation to pass " \
190
+ "without even executing the method you are intending to call. " \
191
+ "#{warning}"\
192
+ "Instead consider providing a specific error class or message. " \
193
+ "This message can be suppressed by setting: " \
194
+ "`RSpec::Expectations.configuration.on_potential_false" \
195
+ "_positives = :nothing`")
196
+ end
197
+
198
+ def warn_about_negative_false_positive!(expression)
170
199
  handle_warning("Using #{expression} risks false positives, since literally " \
171
200
  "any other error would cause the expectation to pass, " \
172
- "including those raised by Ruby (e.g. NoMethodError, NameError " \
173
- "and ArgumentError), meaning the code you are intending to test " \
201
+ "including those raised by Ruby (e.g. `NoMethodError`, `NameError` " \
202
+ "and `ArgumentError`), meaning the code you are intending to test " \
174
203
  "may not even get reached. Instead consider using " \
175
204
  "`expect { }.not_to raise_error` or `expect { }.to raise_error" \
176
205
  "(DifferentSpecificErrorClass)`. This message can be suppressed by " \
@@ -1,7 +1,5 @@
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
5
3
  module RSpec
6
4
  module Matchers
7
5
  module BuiltIn
@@ -118,49 +116,15 @@ module RSpec
118
116
  end
119
117
  end
120
118
 
121
- def setup_method_signature_expectation
122
- expectation = Support::MethodSignatureExpectation.new
123
-
124
- if @expected_arity.is_a?(Range)
125
- expectation.min_count = @expected_arity.min
126
- expectation.max_count = @expected_arity.max
127
- else
128
- expectation.min_count = @expected_arity
129
- end
130
-
131
- expectation.keywords = @expected_keywords
132
- expectation.expect_unlimited_arguments = @unlimited_arguments
133
- expectation.expect_arbitrary_keywords = @arbitrary_keywords
134
-
135
- expectation
136
- end
137
-
138
119
  def matches_arity?(actual, name)
139
- expectation = setup_method_signature_expectation
140
-
141
- return true if expectation.empty?
142
-
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)
158
-
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
120
+ ArityCheck.new(@expected_arity, @expected_keywords, @arbitrary_keywords, @unlimited_arguments).matches?(actual, name)
121
+ rescue NameError
122
+ return true if @ignoring_method_signature_failure
123
+ raise ArgumentError, "The #{matcher_name} matcher requires that " \
124
+ "the actual object define the method(s) in " \
125
+ "order to check arity, but the method " \
126
+ "`#{name}` is not defined. Remove the arity " \
127
+ "check or define the method to continue."
164
128
  end
165
129
 
166
130
  def with_arity
@@ -192,8 +156,45 @@ module RSpec
192
156
  def pp_names
193
157
  @names.length == 1 ? "##{@names.first}" : description_of(@names)
194
158
  end
159
+
160
+ # @private
161
+ class ArityCheck
162
+ def initialize(expected_arity, expected_keywords, arbitrary_keywords, unlimited_arguments)
163
+ expectation = Support::MethodSignatureExpectation.new
164
+
165
+ if expected_arity.is_a?(Range)
166
+ expectation.min_count = expected_arity.min
167
+ expectation.max_count = expected_arity.max
168
+ else
169
+ expectation.min_count = expected_arity
170
+ end
171
+
172
+ expectation.keywords = expected_keywords
173
+ expectation.expect_unlimited_arguments = unlimited_arguments
174
+ expectation.expect_arbitrary_keywords = arbitrary_keywords
175
+ @expectation = expectation
176
+ end
177
+
178
+ def matches?(actual, name)
179
+ return true if @expectation.empty?
180
+ verifier_for(actual, name).with_expectation(@expectation).valid?
181
+ end
182
+
183
+ def verifier_for(actual, name)
184
+ Support::StrictSignatureVerifier.new(method_signature_for(actual, name))
185
+ end
186
+
187
+ def method_signature_for(actual, name)
188
+ method_handle = Support.method_handle_for(actual, name)
189
+
190
+ if name == :new && method_handle.owner === ::Class && ::Class === actual
191
+ Support::MethodSignature.new(actual.instance_method(:initialize))
192
+ else
193
+ Support::MethodSignature.new(method_handle)
194
+ end
195
+ end
196
+ end
195
197
  end
196
198
  end
197
199
  end
198
200
  end
199
- # rubocop:enable ClassLength
@@ -1,3 +1,5 @@
1
+ require 'rspec/matchers/built_in/count_expectation'
2
+
1
3
  RSpec::Support.require_rspec_support 'method_signature_verifier'
2
4
 
3
5
  module RSpec
@@ -97,64 +99,12 @@ module RSpec
97
99
  # Provides the implementation for `yield_control`.
98
100
  # Not intended to be instantiated directly.
99
101
  class YieldControl < BaseMatcher
100
- def initialize
101
- @expectation_type = @expected_yields_count = nil
102
- end
103
-
104
- # @api public
105
- # Specifies that the method is expected to yield once.
106
- def once
107
- exactly(1)
108
- self
109
- end
110
-
111
- # @api public
112
- # Specifies that the method is expected to yield twice.
113
- def twice
114
- exactly(2)
115
- self
116
- end
117
-
118
- # @api public
119
- # Specifies that the method is expected to yield thrice.
120
- def thrice
121
- exactly(3)
122
- self
123
- end
124
-
125
- # @api public
126
- # Specifies that the method is expected to yield the given number of times.
127
- def exactly(number)
128
- set_expected_yields_count(:==, number)
129
- self
130
- end
131
-
132
- # @api public
133
- # Specifies the maximum number of times the method is expected to yield
134
- def at_most(number)
135
- set_expected_yields_count(:<=, number)
136
- self
137
- end
138
-
139
- # @api public
140
- # Specifies the minimum number of times the method is expected to yield
141
- def at_least(number)
142
- set_expected_yields_count(:>=, number)
143
- self
144
- end
145
-
146
- # @api public
147
- # No-op. Provides syntactic sugar.
148
- def times
149
- self
150
- end
151
-
102
+ include CountExpectation
152
103
  # @private
153
104
  def matches?(block)
154
105
  @probe = YieldProbe.probe(block)
155
106
  return false unless @probe.has_block?
156
- return @probe.num_yields > 0 unless @expectation_type
157
- @probe.num_yields.__send__(@expectation_type, @expected_yields_count)
107
+ expected_count_matches?(@probe.num_yields)
158
108
  end
159
109
 
160
110
  # @private
@@ -181,46 +131,10 @@ module RSpec
181
131
 
182
132
  private
183
133
 
184
- def set_expected_yields_count(relativity, n)
185
- raise "Multiple count constraints are not supported" if @expectation_type
186
-
187
- @expectation_type = relativity
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
201
- end
202
-
203
134
  def failure_reason
204
135
  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)}"
207
- end
208
-
209
- def human_readable_expectation_type
210
- case @expectation_type
211
- when :<= then ' at most'
212
- when :>= then ' at least'
213
- else ''
214
- end
215
- end
216
-
217
- def human_readable_count(count)
218
- case count
219
- when nil then ''
220
- when 1 then ' once'
221
- when 2 then ' twice'
222
- else " #{count} times"
223
- end
136
+ return "#{count_expectation_description} but did not yield" if @probe.num_yields == 0
137
+ count_failure_reason('yielded')
224
138
  end
225
139
  end
226
140
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-expectations
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.9.4
4
+ version: 3.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Baker
@@ -45,7 +45,7 @@ cert_chain:
45
45
  ZsVDj6a7lH3cNqtWXZxrb2wO38qV5AkYj8SQK7Hj3/Yui9myUX3crr+PdetazSqQ
46
46
  F3MdtaDehhjC
47
47
  -----END CERTIFICATE-----
48
- date: 2020-10-29 00:00:00.000000000 Z
48
+ date: 2020-10-30 00:00:00.000000000 Z
49
49
  dependencies:
50
50
  - !ruby/object:Gem::Dependency
51
51
  name: rspec-support
@@ -53,14 +53,14 @@ dependencies:
53
53
  requirements:
54
54
  - - "~>"
55
55
  - !ruby/object:Gem::Version
56
- version: 3.9.0
56
+ version: 3.10.0
57
57
  type: :runtime
58
58
  prerelease: false
59
59
  version_requirements: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - "~>"
62
62
  - !ruby/object:Gem::Version
63
- version: 3.9.0
63
+ version: 3.10.0
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: diff-lcs
66
66
  requirement: !ruby/object:Gem::Requirement
@@ -172,6 +172,7 @@ files:
172
172
  - lib/rspec/matchers/built_in/change.rb
173
173
  - lib/rspec/matchers/built_in/compound.rb
174
174
  - lib/rspec/matchers/built_in/contain_exactly.rb
175
+ - lib/rspec/matchers/built_in/count_expectation.rb
175
176
  - lib/rspec/matchers/built_in/cover.rb
176
177
  - lib/rspec/matchers/built_in/eq.rb
177
178
  - lib/rspec/matchers/built_in/eql.rb
@@ -202,7 +203,7 @@ licenses:
202
203
  - MIT
203
204
  metadata:
204
205
  bug_tracker_uri: https://github.com/rspec/rspec-expectations/issues
205
- changelog_uri: https://github.com/rspec/rspec-expectations/blob/v3.9.4/Changelog.md
206
+ changelog_uri: https://github.com/rspec/rspec-expectations/blob/v3.10.0/Changelog.md
206
207
  documentation_uri: https://rspec.info/documentation/
207
208
  mailing_list_uri: https://groups.google.com/forum/#!forum/rspec
208
209
  source_code_uri: https://github.com/rspec/rspec-expectations
@@ -225,5 +226,5 @@ requirements: []
225
226
  rubygems_version: 3.1.3
226
227
  signing_key:
227
228
  specification_version: 4
228
- summary: rspec-expectations-3.9.4
229
+ summary: rspec-expectations-3.10.0
229
230
  test_files: []
metadata.gz.sig CHANGED
@@ -1,5 +1,4 @@
1
- 4 uޙ|��ߐ~�T2SE��tnM���~�zNԱ5y��as��`�ۻ&��_[`XķNp跴�S$G�̙n��
2
- GZ����Od�7ߟ��T9 /Z�ϑL�l�T�ě�(D��.�dN���!��������>���sm���d��\��z��N�
3
- �?8hBr�,sUG�H��*>�m��H���|P��� I��P!+�{[u�5gc\����,��'���x˂��w��i�JYy���4Ek{�䛔@�t�x
4
- �X{�/��Z��?��U>A��.vW�]�܁~=�Iߒ��gΠU�m�4����Woay@#+�v���A�LZ� �Z�G&V�_.����'�h�`"�`��}� s��}�
5
- ������;z�3���]��i���V�kr,�_g�u
1
+ 9 ��X@kR�������j`�O��9��^_-�����9���#DEe� �dIR�P�j5�_?�T�m�ۋ]1��c>����i��.�?� Pjj�M���B�E4�s��I��Tngŵ��3j�Lރ�Q��1|�m�!�����/�K�5|X�}��ʮrX1<���{��|
2
+ A3K��xny�T��AƳ��,_�%_C0�
3
+ �,<��=��w@"����{}]Z��U�o}]N糺!Y�.���hgwJk/���$2z_���� ��Qa ~��Ip��pC��� -$��Ƕ��q��6bᏊ�qNخ��[����P,3u��[X5Y�
4
+ ���6�4�^p�&� `H��TwO�fE��^*|���ܻ��ceW��.�d4����晬�~