rspec-expectations 3.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +5 -0
  4. data/.document +5 -0
  5. data/.yardopts +6 -0
  6. data/Changelog.md +1156 -0
  7. data/LICENSE.md +25 -0
  8. data/README.md +305 -0
  9. data/lib/rspec/expectations.rb +82 -0
  10. data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
  11. data/lib/rspec/expectations/configuration.rb +215 -0
  12. data/lib/rspec/expectations/expectation_target.rb +127 -0
  13. data/lib/rspec/expectations/fail_with.rb +39 -0
  14. data/lib/rspec/expectations/failure_aggregator.rb +194 -0
  15. data/lib/rspec/expectations/handler.rb +170 -0
  16. data/lib/rspec/expectations/minitest_integration.rb +58 -0
  17. data/lib/rspec/expectations/syntax.rb +132 -0
  18. data/lib/rspec/expectations/version.rb +8 -0
  19. data/lib/rspec/matchers.rb +1034 -0
  20. data/lib/rspec/matchers/aliased_matcher.rb +116 -0
  21. data/lib/rspec/matchers/built_in.rb +52 -0
  22. data/lib/rspec/matchers/built_in/all.rb +86 -0
  23. data/lib/rspec/matchers/built_in/base_matcher.rb +193 -0
  24. data/lib/rspec/matchers/built_in/be.rb +288 -0
  25. data/lib/rspec/matchers/built_in/be_between.rb +77 -0
  26. data/lib/rspec/matchers/built_in/be_instance_of.rb +26 -0
  27. data/lib/rspec/matchers/built_in/be_kind_of.rb +20 -0
  28. data/lib/rspec/matchers/built_in/be_within.rb +72 -0
  29. data/lib/rspec/matchers/built_in/change.rb +428 -0
  30. data/lib/rspec/matchers/built_in/compound.rb +271 -0
  31. data/lib/rspec/matchers/built_in/contain_exactly.rb +302 -0
  32. data/lib/rspec/matchers/built_in/cover.rb +24 -0
  33. data/lib/rspec/matchers/built_in/eq.rb +40 -0
  34. data/lib/rspec/matchers/built_in/eql.rb +34 -0
  35. data/lib/rspec/matchers/built_in/equal.rb +81 -0
  36. data/lib/rspec/matchers/built_in/exist.rb +90 -0
  37. data/lib/rspec/matchers/built_in/has.rb +103 -0
  38. data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
  39. data/lib/rspec/matchers/built_in/include.rb +149 -0
  40. data/lib/rspec/matchers/built_in/match.rb +106 -0
  41. data/lib/rspec/matchers/built_in/operators.rb +128 -0
  42. data/lib/rspec/matchers/built_in/output.rb +200 -0
  43. data/lib/rspec/matchers/built_in/raise_error.rb +230 -0
  44. data/lib/rspec/matchers/built_in/respond_to.rb +165 -0
  45. data/lib/rspec/matchers/built_in/satisfy.rb +60 -0
  46. data/lib/rspec/matchers/built_in/start_or_end_with.rb +94 -0
  47. data/lib/rspec/matchers/built_in/throw_symbol.rb +132 -0
  48. data/lib/rspec/matchers/built_in/yield.rb +432 -0
  49. data/lib/rspec/matchers/composable.rb +171 -0
  50. data/lib/rspec/matchers/dsl.rb +527 -0
  51. data/lib/rspec/matchers/english_phrasing.rb +58 -0
  52. data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +73 -0
  53. data/lib/rspec/matchers/fail_matchers.rb +42 -0
  54. data/lib/rspec/matchers/generated_descriptions.rb +41 -0
  55. data/lib/rspec/matchers/matcher_delegator.rb +35 -0
  56. data/lib/rspec/matchers/matcher_protocol.rb +99 -0
  57. metadata +215 -0
  58. metadata.gz.sig +0 -0
@@ -0,0 +1,288 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `be_truthy`.
6
+ # Not intended to be instantiated directly.
7
+ class BeTruthy < BaseMatcher
8
+ # @api private
9
+ # @return [String]
10
+ def failure_message
11
+ "expected: truthy value\n got: #{actual_formatted}"
12
+ end
13
+
14
+ # @api private
15
+ # @return [String]
16
+ def failure_message_when_negated
17
+ "expected: falsey value\n got: #{actual_formatted}"
18
+ end
19
+
20
+ private
21
+
22
+ def match(_, actual)
23
+ !!actual
24
+ end
25
+ end
26
+
27
+ # @api private
28
+ # Provides the implementation for `be_falsey`.
29
+ # Not intended to be instantiated directly.
30
+ class BeFalsey < BaseMatcher
31
+ # @api private
32
+ # @return [String]
33
+ def failure_message
34
+ "expected: falsey value\n got: #{actual_formatted}"
35
+ end
36
+
37
+ # @api private
38
+ # @return [String]
39
+ def failure_message_when_negated
40
+ "expected: truthy value\n got: #{actual_formatted}"
41
+ end
42
+
43
+ private
44
+
45
+ def match(_, actual)
46
+ !actual
47
+ end
48
+ end
49
+
50
+ # @api private
51
+ # Provides the implementation for `be_nil`.
52
+ # Not intended to be instantiated directly.
53
+ class BeNil < BaseMatcher
54
+ # @api private
55
+ # @return [String]
56
+ def failure_message
57
+ "expected: nil\n got: #{actual_formatted}"
58
+ end
59
+
60
+ # @api private
61
+ # @return [String]
62
+ def failure_message_when_negated
63
+ "expected: not nil\n got: nil"
64
+ end
65
+
66
+ private
67
+
68
+ def match(_, actual)
69
+ actual.nil?
70
+ end
71
+ end
72
+
73
+ # @private
74
+ module BeHelpers
75
+ private
76
+
77
+ def args_to_s
78
+ @args.empty? ? "" : parenthesize(inspected_args.join(', '))
79
+ end
80
+
81
+ def parenthesize(string)
82
+ "(#{string})"
83
+ end
84
+
85
+ def inspected_args
86
+ @args.map { |a| RSpec::Support::ObjectFormatter.format(a) }
87
+ end
88
+
89
+ def expected_to_sentence
90
+ EnglishPhrasing.split_words(@expected)
91
+ end
92
+
93
+ def args_to_sentence
94
+ EnglishPhrasing.list(@args)
95
+ end
96
+ end
97
+
98
+ # @api private
99
+ # Provides the implementation for `be`.
100
+ # Not intended to be instantiated directly.
101
+ class Be < BaseMatcher
102
+ include BeHelpers
103
+
104
+ def initialize(*args)
105
+ @args = args
106
+ end
107
+
108
+ # @api private
109
+ # @return [String]
110
+ def failure_message
111
+ "expected #{actual_formatted} to evaluate to true"
112
+ end
113
+
114
+ # @api private
115
+ # @return [String]
116
+ def failure_message_when_negated
117
+ "expected #{actual_formatted} to evaluate to false"
118
+ end
119
+
120
+ [:==, :<, :<=, :>=, :>, :===, :=~].each do |operator|
121
+ define_method operator do |operand|
122
+ BeComparedTo.new(operand, operator)
123
+ end
124
+ end
125
+
126
+ private
127
+
128
+ def match(_, actual)
129
+ !!actual
130
+ end
131
+ end
132
+
133
+ # @api private
134
+ # Provides the implementation of `be <operator> value`.
135
+ # Not intended to be instantiated directly.
136
+ class BeComparedTo < BaseMatcher
137
+ include BeHelpers
138
+
139
+ def initialize(operand, operator)
140
+ @expected = operand
141
+ @operator = operator
142
+ @args = []
143
+ end
144
+
145
+ def matches?(actual)
146
+ @actual = actual
147
+ @actual.__send__ @operator, @expected
148
+ rescue ArgumentError, NoMethodError
149
+ false
150
+ end
151
+
152
+ # @api private
153
+ # @return [String]
154
+ def failure_message
155
+ "expected: #{@operator} #{expected_formatted}\n" \
156
+ " got: #{@operator.to_s.gsub(/./, ' ')} #{actual_formatted}"
157
+ end
158
+
159
+ # @api private
160
+ # @return [String]
161
+ def failure_message_when_negated
162
+ message = "`expect(#{actual_formatted}).not_to " \
163
+ "be #{@operator} #{expected_formatted}`"
164
+ if [:<, :>, :<=, :>=].include?(@operator)
165
+ message + " not only FAILED, it is a bit confusing."
166
+ else
167
+ message
168
+ end
169
+ end
170
+
171
+ # @api private
172
+ # @return [String]
173
+ def description
174
+ "be #{@operator} #{expected_to_sentence}#{args_to_sentence}"
175
+ end
176
+ end
177
+
178
+ # @api private
179
+ # Provides the implementation of `be_<predicate>`.
180
+ # Not intended to be instantiated directly.
181
+ class BePredicate < BaseMatcher
182
+ include BeHelpers
183
+
184
+ def initialize(*args, &block)
185
+ @expected = parse_expected(args.shift)
186
+ @args = args
187
+ @block = block
188
+ end
189
+
190
+ def matches?(actual, &block)
191
+ @actual = actual
192
+ @block ||= block
193
+ predicate_accessible? && predicate_matches?
194
+ end
195
+
196
+ def does_not_match?(actual, &block)
197
+ @actual = actual
198
+ @block ||= block
199
+ predicate_accessible? && !predicate_matches?
200
+ end
201
+
202
+ # @api private
203
+ # @return [String]
204
+ def failure_message
205
+ failure_message_expecting(true)
206
+ end
207
+
208
+ # @api private
209
+ # @return [String]
210
+ def failure_message_when_negated
211
+ failure_message_expecting(false)
212
+ end
213
+
214
+ # @api private
215
+ # @return [String]
216
+ def description
217
+ "#{prefix_to_sentence}#{expected_to_sentence}#{args_to_sentence}"
218
+ end
219
+
220
+ private
221
+
222
+ def predicate_accessible?
223
+ actual.respond_to?(predicate) || actual.respond_to?(present_tense_predicate)
224
+ end
225
+
226
+ # support 1.8.7, evaluate once at load time for performance
227
+ if String === methods.first
228
+ # :nocov:
229
+ def private_predicate?
230
+ @actual.private_methods.include? predicate.to_s
231
+ end
232
+ # :nocov:
233
+ else
234
+ def private_predicate?
235
+ @actual.private_methods.include? predicate
236
+ end
237
+ end
238
+
239
+ def predicate_matches?
240
+ method_name = actual.respond_to?(predicate) ? predicate : present_tense_predicate
241
+ @predicate_matches = actual.__send__(method_name, *@args, &@block)
242
+ end
243
+
244
+ def predicate
245
+ :"#{@expected}?"
246
+ end
247
+
248
+ def present_tense_predicate
249
+ :"#{@expected}s?"
250
+ end
251
+
252
+ def parse_expected(expected)
253
+ @prefix, expected = prefix_and_expected(expected)
254
+ expected
255
+ end
256
+
257
+ def prefix_and_expected(symbol)
258
+ Matchers::BE_PREDICATE_REGEX.match(symbol.to_s).captures.compact
259
+ end
260
+
261
+ def prefix_to_sentence
262
+ EnglishPhrasing.split_words(@prefix)
263
+ end
264
+
265
+ def failure_message_expecting(value)
266
+ validity_message ||
267
+ "expected `#{actual_formatted}.#{predicate}#{args_to_s}` to return #{value}, got #{description_of @predicate_matches}"
268
+ end
269
+
270
+ def validity_message
271
+ return nil if predicate_accessible?
272
+
273
+ msg = "expected #{actual_formatted} to respond to `#{predicate}`".dup
274
+
275
+ if private_predicate?
276
+ msg << " but `#{predicate}` is a private method"
277
+ elsif predicate == :true?
278
+ msg << " or perhaps you meant `be true` or `be_truthy`"
279
+ elsif predicate == :false?
280
+ msg << " or perhaps you meant `be false` or `be_falsey`"
281
+ end
282
+
283
+ msg
284
+ end
285
+ end
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,77 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `be_between`.
6
+ # Not intended to be instantiated directly.
7
+ class BeBetween < BaseMatcher
8
+ def initialize(min, max)
9
+ @min, @max = min, max
10
+ inclusive
11
+ end
12
+
13
+ # @api public
14
+ # Makes the between comparison inclusive.
15
+ #
16
+ # @example
17
+ # expect(3).to be_between(2, 3).inclusive
18
+ #
19
+ # @note The matcher is inclusive by default; this simply provides
20
+ # a way to be more explicit about it.
21
+ def inclusive
22
+ @less_than_operator = :<=
23
+ @greater_than_operator = :>=
24
+ @mode = :inclusive
25
+ self
26
+ end
27
+
28
+ # @api public
29
+ # Makes the between comparison exclusive.
30
+ #
31
+ # @example
32
+ # expect(3).to be_between(2, 4).exclusive
33
+ def exclusive
34
+ @less_than_operator = :<
35
+ @greater_than_operator = :>
36
+ @mode = :exclusive
37
+ self
38
+ end
39
+
40
+ # @api private
41
+ # @return [Boolean]
42
+ def matches?(actual)
43
+ @actual = actual
44
+ comparable? && compare
45
+ rescue ArgumentError
46
+ false
47
+ end
48
+
49
+ # @api private
50
+ # @return [String]
51
+ def failure_message
52
+ "#{super}#{not_comparable_clause}"
53
+ end
54
+
55
+ # @api private
56
+ # @return [String]
57
+ def description
58
+ "be between #{description_of @min} and #{description_of @max} (#{@mode})"
59
+ end
60
+
61
+ private
62
+
63
+ def comparable?
64
+ @actual.respond_to?(@less_than_operator) && @actual.respond_to?(@greater_than_operator)
65
+ end
66
+
67
+ def not_comparable_clause
68
+ ", but it does not respond to `#{@less_than_operator}` and `#{@greater_than_operator}`" unless comparable?
69
+ end
70
+
71
+ def compare
72
+ @actual.__send__(@greater_than_operator, @min) && @actual.__send__(@less_than_operator, @max)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,26 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `be_an_instance_of`.
6
+ # Not intended to be instantiated directly.
7
+ class BeAnInstanceOf < BaseMatcher
8
+ # @api private
9
+ # @return [String]
10
+ def description
11
+ "be an instance of #{expected}"
12
+ end
13
+
14
+ private
15
+
16
+ def match(expected, actual)
17
+ actual.instance_of?(expected)
18
+ rescue NoMethodError
19
+ raise ::ArgumentError, "The #{matcher_name} matcher requires that " \
20
+ "the actual object responds to #instance_of? method " \
21
+ "but a `NoMethodError` was encountered instead."
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `be_a_kind_of`.
6
+ # Not intended to be instantiated directly.
7
+ class BeAKindOf < BaseMatcher
8
+ private
9
+
10
+ def match(expected, actual)
11
+ actual.kind_of?(expected)
12
+ rescue NoMethodError
13
+ raise ::ArgumentError, "The #{matcher_name} matcher requires that " \
14
+ "the actual object responds to #kind_of? method " \
15
+ "but a `NoMethodError` was encountered instead."
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,72 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `be_within`.
6
+ # Not intended to be instantiated directly.
7
+ class BeWithin < BaseMatcher
8
+ def initialize(delta)
9
+ @delta = delta
10
+ end
11
+
12
+ # @api public
13
+ # Sets the expected value.
14
+ def of(expected)
15
+ @expected = expected
16
+ @tolerance = @delta
17
+ @unit = ''
18
+ self
19
+ end
20
+
21
+ # @api public
22
+ # Sets the expected value, and makes the matcher do
23
+ # a percent comparison.
24
+ def percent_of(expected)
25
+ @expected = expected
26
+ @tolerance = @delta * @expected.abs / 100.0
27
+ @unit = '%'
28
+ self
29
+ end
30
+
31
+ # @private
32
+ def matches?(actual)
33
+ @actual = actual
34
+ raise needs_expected unless defined? @expected
35
+ numeric? && (@actual - @expected).abs <= @tolerance
36
+ end
37
+
38
+ # @api private
39
+ # @return [String]
40
+ def failure_message
41
+ "expected #{actual_formatted} to #{description}#{not_numeric_clause}"
42
+ end
43
+
44
+ # @api private
45
+ # @return [String]
46
+ def failure_message_when_negated
47
+ "expected #{actual_formatted} not to #{description}"
48
+ end
49
+
50
+ # @api private
51
+ # @return [String]
52
+ def description
53
+ "be within #{@delta}#{@unit} of #{@expected}"
54
+ end
55
+
56
+ private
57
+
58
+ def numeric?
59
+ @actual.respond_to?(:-)
60
+ end
61
+
62
+ def needs_expected
63
+ ArgumentError.new "You must set an expected value using #of: be_within(#{@delta}).of(expected_value)"
64
+ end
65
+
66
+ def not_numeric_clause
67
+ ", but it could not be treated as a numeric value" unless numeric?
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end