rspec-expectations 3.0.4 → 3.12.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +1 -1
  5. data/Changelog.md +530 -5
  6. data/{License.txt → LICENSE.md} +5 -4
  7. data/README.md +73 -31
  8. data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
  9. data/lib/rspec/expectations/configuration.rb +96 -1
  10. data/lib/rspec/expectations/expectation_target.rb +82 -38
  11. data/lib/rspec/expectations/fail_with.rb +11 -6
  12. data/lib/rspec/expectations/failure_aggregator.rb +229 -0
  13. data/lib/rspec/expectations/handler.rb +36 -15
  14. data/lib/rspec/expectations/minitest_integration.rb +43 -2
  15. data/lib/rspec/expectations/syntax.rb +5 -5
  16. data/lib/rspec/expectations/version.rb +1 -1
  17. data/lib/rspec/expectations.rb +15 -1
  18. data/lib/rspec/matchers/aliased_matcher.rb +79 -4
  19. data/lib/rspec/matchers/built_in/all.rb +11 -0
  20. data/lib/rspec/matchers/built_in/base_matcher.rb +111 -28
  21. data/lib/rspec/matchers/built_in/be.rb +28 -114
  22. data/lib/rspec/matchers/built_in/be_between.rb +1 -1
  23. data/lib/rspec/matchers/built_in/be_instance_of.rb +5 -1
  24. data/lib/rspec/matchers/built_in/be_kind_of.rb +5 -1
  25. data/lib/rspec/matchers/built_in/be_within.rb +5 -12
  26. data/lib/rspec/matchers/built_in/change.rb +171 -63
  27. data/lib/rspec/matchers/built_in/compound.rb +201 -30
  28. data/lib/rspec/matchers/built_in/contain_exactly.rb +73 -12
  29. data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
  30. data/lib/rspec/matchers/built_in/eq.rb +3 -38
  31. data/lib/rspec/matchers/built_in/eql.rb +2 -2
  32. data/lib/rspec/matchers/built_in/equal.rb +3 -3
  33. data/lib/rspec/matchers/built_in/exist.rb +7 -3
  34. data/lib/rspec/matchers/built_in/has.rb +93 -30
  35. data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
  36. data/lib/rspec/matchers/built_in/include.rb +133 -25
  37. data/lib/rspec/matchers/built_in/match.rb +79 -2
  38. data/lib/rspec/matchers/built_in/operators.rb +14 -5
  39. data/lib/rspec/matchers/built_in/output.rb +59 -2
  40. data/lib/rspec/matchers/built_in/raise_error.rb +130 -27
  41. data/lib/rspec/matchers/built_in/respond_to.rb +117 -15
  42. data/lib/rspec/matchers/built_in/satisfy.rb +28 -14
  43. data/lib/rspec/matchers/built_in/{start_and_end_with.rb → start_or_end_with.rb} +20 -8
  44. data/lib/rspec/matchers/built_in/throw_symbol.rb +15 -5
  45. data/lib/rspec/matchers/built_in/yield.rb +129 -156
  46. data/lib/rspec/matchers/built_in.rb +5 -3
  47. data/lib/rspec/matchers/composable.rb +24 -36
  48. data/lib/rspec/matchers/dsl.rb +203 -37
  49. data/lib/rspec/matchers/english_phrasing.rb +58 -0
  50. data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +82 -0
  51. data/lib/rspec/matchers/fail_matchers.rb +42 -0
  52. data/lib/rspec/matchers/generated_descriptions.rb +1 -2
  53. data/lib/rspec/matchers/matcher_delegator.rb +3 -4
  54. data/lib/rspec/matchers/matcher_protocol.rb +105 -0
  55. data/lib/rspec/matchers.rb +267 -144
  56. data.tar.gz.sig +0 -0
  57. metadata +71 -49
  58. metadata.gz.sig +0 -0
  59. data/lib/rspec/matchers/pretty.rb +0 -77
@@ -1,31 +1,24 @@
1
1
  require 'rspec/support'
2
+ RSpec::Support.require_rspec_support 'matcher_definition'
2
3
  RSpec::Support.define_optimized_require_for_rspec(:matchers) { |f| require_relative(f) }
3
4
 
4
5
  %w[
5
- pretty
6
+ english_phrasing
6
7
  composable
7
8
  built_in
8
9
  generated_descriptions
9
10
  dsl
10
11
  matcher_delegator
11
12
  aliased_matcher
13
+ expecteds_for_multiple_diffs
12
14
  ].each { |file| RSpec::Support.require_rspec_matchers(file) }
13
15
 
14
16
  # RSpec's top level namespace. All of rspec-expectations is contained
15
17
  # in the `RSpec::Expectations` and `RSpec::Matchers` namespaces.
16
18
  module RSpec
17
19
  # RSpec::Matchers provides a number of useful matchers we use to define
18
- # expectations. A matcher is any object that responds to the following:
19
- #
20
- # matches?(actual)
21
- # failure_message
22
- #
23
- # These methods are also part of the matcher protocol, but are optional:
24
- #
25
- # does_not_match?(actual)
26
- # failure_message_when_negated
27
- # description
28
- # supports_block_expectations?
20
+ # expectations. Any object that implements the [matcher protocol](Matchers/MatcherProtocol)
21
+ # can be used as a matcher.
29
22
  #
30
23
  # ## Predicates
31
24
  #
@@ -43,14 +36,14 @@ module RSpec
43
36
  # expect([]).to be_empty # => [].empty?() | passes
44
37
  # expect([]).not_to be_empty # => [].empty?() | fails
45
38
  #
46
- # In addtion to prefixing the predicate matchers with "be_", you can also use "be_a_"
39
+ # In addition to prefixing the predicate matchers with "be_", you can also use "be_a_"
47
40
  # and "be_an_", making your specs read much more naturally:
48
41
  #
49
42
  # expect("a string").to be_an_instance_of(String) # =>"a string".instance_of?(String) # passes
50
43
  #
51
- # expect(3).to be_a_kind_of(Fixnum) # => 3.kind_of?(Numeric) | passes
52
- # expect(3).to be_a_kind_of(Numeric) # => 3.kind_of?(Numeric) | passes
53
- # expect(3).to be_an_instance_of(Fixnum) # => 3.instance_of?(Fixnum) | passes
44
+ # expect(3).to be_a_kind_of(Integer) # => 3.kind_of?(Numeric) | passes
45
+ # expect(3).to be_a_kind_of(Numeric) # => 3.kind_of?(Numeric) | passes
46
+ # expect(3).to be_an_instance_of(Integer) # => 3.instance_of?(Integer) | passes
54
47
  # expect(3).not_to be_an_instance_of(Numeric) # => 3.instance_of?(Numeric) | fails
55
48
  #
56
49
  # RSpec will also create custom matchers for predicates like `has_key?`. To
@@ -69,6 +62,26 @@ module RSpec
69
62
  # RSpec::Matchers.alias_matcher :a_user_who_is_an_admin, :be_an_admin
70
63
  # expect(user_list).to include(a_user_who_is_an_admin)
71
64
  #
65
+ # ## Alias Matchers
66
+ #
67
+ # With {RSpec::Matchers.alias_matcher}, you can easily create an
68
+ # alternate name for a given matcher.
69
+ #
70
+ # The description will also change according to the new name:
71
+ #
72
+ # RSpec::Matchers.alias_matcher :a_list_that_sums_to, :sum_to
73
+ # sum_to(3).description # => "sum to 3"
74
+ # a_list_that_sums_to(3).description # => "a list that sums to 3"
75
+ #
76
+ # or you can specify a custom description like this:
77
+ #
78
+ # RSpec::Matchers.alias_matcher :a_list_sorted_by, :be_sorted_by do |description|
79
+ # description.sub("be sorted by", "a list sorted by")
80
+ # end
81
+ #
82
+ # be_sorted_by(:age).description # => "be sorted by age"
83
+ # a_list_sorted_by(:age).description # => "a list sorted by age"
84
+ #
72
85
  # ## Custom Matchers
73
86
  #
74
87
  # When you find that none of the stock matchers provide a natural feeling
@@ -209,55 +222,88 @@ module RSpec
209
222
  # expressions, and also uses the noun-phrase wording in the matcher's `description`,
210
223
  # for readable failure messages. You can alias your custom matchers in similar fashion
211
224
  # using {RSpec::Matchers.alias_matcher}.
212
- module Matchers
225
+ #
226
+ # ## Negated Matchers
227
+ #
228
+ # Sometimes if you want to test for the opposite using a more descriptive name
229
+ # instead of using `not_to`, you can use {RSpec::Matchers.define_negated_matcher}:
230
+ #
231
+ # RSpec::Matchers.define_negated_matcher :exclude, :include
232
+ # include(1, 2).description # => "include 1 and 2"
233
+ # exclude(1, 2).description # => "exclude 1 and 2"
234
+ #
235
+ # While the most obvious negated form may be to add a `not_` prefix,
236
+ # the failure messages you get with that form can be confusing (e.g.
237
+ # "expected [actual] to not [verb], but did not"). We've found it works
238
+ # best to find a more positive name for the negated form, such as
239
+ # `avoid_changing` rather than `not_change`.
240
+ #
241
+ module Matchers # rubocop:disable Metrics/ModuleLength
242
+ extend ::RSpec::Matchers::DSL
243
+
244
+ # @!macro [attach] alias_matcher
245
+ # @!parse
246
+ # alias $1 $2
247
+ # @!visibility private
248
+ # We define this override here so we can attach a YARD macro to it.
249
+ # It ensures that our docs list all the matcher aliases.
250
+ def self.alias_matcher(*args, &block)
251
+ super(*args, &block)
252
+ end
253
+
254
+ # @!method self.alias_matcher(new_name, old_name, options={}, &description_override)
255
+ # Extended from {RSpec::Matchers::DSL#alias_matcher}.
256
+
257
+ # @!method self.define(name, &declarations)
258
+ # Extended from {RSpec::Matchers::DSL#define}.
259
+
260
+ # @!method self.define_negated_matcher(negated_name, base_name, &description_override)
261
+ # Extended from {RSpec::Matchers::DSL#define_negated_matcher}.
262
+
213
263
  # @method expect
214
264
  # Supports `expect(actual).to matcher` syntax by wrapping `actual` in an
215
265
  # `ExpectationTarget`.
216
266
  # @example
217
267
  # expect(actual).to eq(expected)
218
268
  # expect(actual).not_to eq(expected)
219
- # @return [ExpectationTarget]
220
- # @see ExpectationTarget#to
221
- # @see ExpectationTarget#not_to
269
+ # @return [Expectations::ExpectationTarget]
270
+ # @see Expectations::ExpectationTarget#to
271
+ # @see Expectations::ExpectationTarget#not_to
222
272
 
223
- # Defines a matcher alias. The returned matcher's `description` will be overriden
224
- # to reflect the phrasing of the new name, which will be used in failure messages
225
- # when passed as an argument to another matcher in a composed matcher expression.
226
- #
227
- # @param new_name [Symbol] the new name for the matcher
228
- # @param old_name [Symbol] the original name for the matcher
229
- # @yield [String] optional block that, when given is used to define the overriden
230
- # description. The yielded arg is the original description. If no block is
231
- # provided, a default description override is used based on the old and
232
- # new names.
233
- #
234
- # @example
235
- #
236
- # RSpec::Matchers.alias_matcher :a_list_that_sums_to, :sum_to
237
- # sum_to(3).description # => "sum to 3"
238
- # a_list_that_sums_to(3).description # => "a list that sums to 3"
273
+ # Allows multiple expectations in the provided block to fail, and then
274
+ # aggregates them into a single exception, rather than aborting on the
275
+ # first expectation failure like normal. This allows you to see all
276
+ # failures from an entire set of expectations without splitting each
277
+ # off into its own example (which may slow things down if the example
278
+ # setup is expensive).
279
+ #
280
+ # @param label [String] label for this aggregation block, which will be
281
+ # included in the aggregated exception message.
282
+ # @param metadata [Hash] additional metadata about this failure aggregation
283
+ # block. If multiple expectations fail, it will be exposed from the
284
+ # {Expectations::MultipleExpectationsNotMetError} exception. Mostly
285
+ # intended for internal RSpec use but you can use it as well.
286
+ # @yield Block containing as many expectation as you want. The block is
287
+ # simply yielded to, so you can trust that anything that works outside
288
+ # the block should work within it.
289
+ # @raise [Expectations::MultipleExpectationsNotMetError] raised when
290
+ # multiple expectations fail.
291
+ # @raise [Expectations::ExpectationNotMetError] raised when a single
292
+ # expectation fails.
293
+ # @raise [Exception] other sorts of exceptions will be raised as normal.
239
294
  #
240
295
  # @example
241
- #
242
- # RSpec::Matchers.alias_matcher :a_list_sorted_by, :be_sorted_by do |description|
243
- # description.sub("be sorted by", "a list sorted by")
296
+ # aggregate_failures("verifying response") do
297
+ # expect(response.status).to eq(200)
298
+ # expect(response.headers).to include("Content-Type" => "text/plain")
299
+ # expect(response.body).to include("Success")
244
300
  # end
245
301
  #
246
- # be_sorted_by(:age).description # => "be sorted by age"
247
- # a_list_sorted_by(:age).description # => "a list sorted by age"
248
- #
249
- # @!macro [attach] alias_matcher
250
- # @!parse
251
- # alias $1 $2
252
- def self.alias_matcher(new_name, old_name, &description_override)
253
- description_override ||= lambda do |old_desc|
254
- old_desc.gsub(Pretty.split_words(old_name), Pretty.split_words(new_name))
255
- end
256
-
257
- define_method(new_name) do |*args, &block|
258
- matcher = __send__(old_name, *args, &block)
259
- AliasedMatcher.new(matcher, description_override)
260
- end
302
+ # @note The implementation of this feature uses a thread-local variable,
303
+ # which means that if you have an expectation failure in another thread,
304
+ # it'll abort like normal.
305
+ def aggregate_failures(label=nil, metadata={}, &block)
306
+ Expectations::FailureAggregator.new(label, metadata).aggregate(&block)
261
307
  end
262
308
 
263
309
  # Passes if actual is truthy (anything but false or nil)
@@ -270,9 +316,9 @@ module RSpec
270
316
  def be_falsey
271
317
  BuiltIn::BeFalsey.new
272
318
  end
273
- alias_matcher :be_falsy, :be_falsey
319
+ alias_matcher :be_falsy, :be_falsey
274
320
  alias_matcher :a_falsey_value, :be_falsey
275
- alias_matcher :a_falsy_value, :be_falsey
321
+ alias_matcher :a_falsy_value, :be_falsey
276
322
 
277
323
  # Passes if actual is nil
278
324
  def be_nil
@@ -303,7 +349,7 @@ module RSpec
303
349
  def be(*args)
304
350
  args.empty? ? Matchers::BuiltIn::Be.new : equal(*args)
305
351
  end
306
- alias_matcher :a_value, :be
352
+ alias_matcher :a_value, :be, :klass => AliasedMatcherWithOperatorSupport
307
353
 
308
354
  # passes if target.kind_of?(klass)
309
355
  def be_a(klass)
@@ -314,8 +360,7 @@ module RSpec
314
360
  # Passes if actual.instance_of?(expected)
315
361
  #
316
362
  # @example
317
- #
318
- # expect(5).to be_an_instance_of(Fixnum)
363
+ # expect(5).to be_an_instance_of(Integer)
319
364
  # expect(5).not_to be_an_instance_of(Numeric)
320
365
  # expect(5).not_to be_an_instance_of(Float)
321
366
  def be_an_instance_of(expected)
@@ -327,15 +372,14 @@ module RSpec
327
372
  # Passes if actual.kind_of?(expected)
328
373
  #
329
374
  # @example
330
- #
331
- # expect(5).to be_a_kind_of(Fixnum)
375
+ # expect(5).to be_a_kind_of(Integer)
332
376
  # expect(5).to be_a_kind_of(Numeric)
333
377
  # expect(5).not_to be_a_kind_of(Float)
334
378
  def be_a_kind_of(expected)
335
379
  BuiltIn::BeAKindOf.new(expected)
336
380
  end
337
381
  alias_method :be_kind_of, :be_a_kind_of
338
- alias_matcher :a_kind_of, :be_a_kind_of
382
+ alias_matcher :a_kind_of, :be_a_kind_of
339
383
 
340
384
  # Passes if actual.between?(min, max). Works with any Comparable object,
341
385
  # including String, Symbol, Time, or Numeric (Fixnum, Bignum, Integer,
@@ -345,7 +389,6 @@ module RSpec
345
389
  # but you can make it `exclusive` by chaining that off the matcher.
346
390
  #
347
391
  # @example
348
- #
349
392
  # expect(5).to be_between(1, 10)
350
393
  # expect(11).not_to be_between(1, 10)
351
394
  # expect(10).not_to be_between(1, 10).exclusive
@@ -357,14 +400,13 @@ module RSpec
357
400
  # Passes if actual == expected +/- delta
358
401
  #
359
402
  # @example
360
- #
361
403
  # expect(result).to be_within(0.5).of(3.0)
362
404
  # expect(result).not_to be_within(0.5).of(3.0)
363
405
  def be_within(delta)
364
406
  BuiltIn::BeWithin.new(delta)
365
407
  end
366
408
  alias_matcher :a_value_within, :be_within
367
- alias_matcher :within, :be_within
409
+ alias_matcher :within, :be_within
368
410
 
369
411
  # Applied to a proc, specifies that its execution will cause some value to
370
412
  # change.
@@ -382,14 +424,16 @@ module RSpec
382
424
  # You can chain any of the following off of the end to specify details
383
425
  # about the change:
384
426
  #
427
+ # * `from`
428
+ # * `to`
429
+ #
430
+ # or any one of:
431
+ #
385
432
  # * `by`
386
433
  # * `by_at_least`
387
434
  # * `by_at_most`
388
- # * `from`
389
- # * `to`
390
435
  #
391
436
  # @example
392
- #
393
437
  # expect {
394
438
  # team.add_player(player)
395
439
  # }.to change(roster, :count)
@@ -436,7 +480,10 @@ module RSpec
436
480
  # == Notes
437
481
  #
438
482
  # Evaluates `receiver.message` or `block` before and after it
439
- # evaluates the block passed to `expect`.
483
+ # evaluates the block passed to `expect`. If the value is the same
484
+ # object, its before/after `hash` value is used to see if it has changed.
485
+ # Therefore, your object needs to properly implement `hash` to work correctly
486
+ # with this matcher.
440
487
  #
441
488
  # `expect( ... ).not_to change` supports the form that specifies `from`
442
489
  # (which specifies what you expect the starting, unchanged value to be)
@@ -445,8 +492,8 @@ module RSpec
445
492
  def change(receiver=nil, message=nil, &block)
446
493
  BuiltIn::Change.new(receiver, message, &block)
447
494
  end
448
- alias_matcher :a_block_changing, :change
449
- alias_matcher :changing, :change
495
+ alias_matcher :a_block_changing, :change
496
+ alias_matcher :changing, :change
450
497
 
451
498
  # Passes if actual contains all of the expected regardless of order.
452
499
  # This works for collections. Pass in multiple args and it will only
@@ -455,11 +502,7 @@ module RSpec
455
502
  # @note This is also available using the `=~` operator with `should`,
456
503
  # but `=~` is not supported with `expect`.
457
504
  #
458
- # @note This matcher only supports positive expectations.
459
- # `expect(...).not_to contain_exactly(other_array)` is not supported.
460
- #
461
505
  # @example
462
- #
463
506
  # expect([1, 2, 3]).to contain_exactly(1, 2, 3)
464
507
  # expect([1, 2, 3]).to contain_exactly(1, 3, 2)
465
508
  #
@@ -468,7 +511,7 @@ module RSpec
468
511
  BuiltIn::ContainExactly.new(items)
469
512
  end
470
513
  alias_matcher :a_collection_containing_exactly, :contain_exactly
471
- alias_matcher :containing_exactly, :contain_exactly
514
+ alias_matcher :containing_exactly, :contain_exactly
472
515
 
473
516
  # Passes if actual covers expected. This works for
474
517
  # Ranges. You can also pass in multiple args
@@ -486,7 +529,7 @@ module RSpec
486
529
  BuiltIn::Cover.new(*values)
487
530
  end
488
531
  alias_matcher :a_range_covering, :cover
489
- alias_matcher :covering, :cover
532
+ alias_matcher :covering, :cover
490
533
 
491
534
  # Matches if the actual value ends with the expected value(s). In the case
492
535
  # of a string, matches against the last `expected.length` characters of the
@@ -494,7 +537,6 @@ module RSpec
494
537
  # `expected.length` elements of the actual array.
495
538
  #
496
539
  # @example
497
- #
498
540
  # expect("this string").to end_with "string"
499
541
  # expect([0, 1, 2, 3, 4]).to end_with 4
500
542
  # expect([0, 2, 3, 4, 4]).to end_with 3, 4
@@ -502,8 +544,8 @@ module RSpec
502
544
  BuiltIn::EndWith.new(*expected)
503
545
  end
504
546
  alias_matcher :a_collection_ending_with, :end_with
505
- alias_matcher :a_string_ending_with, :end_with
506
- alias_matcher :ending_with, :end_with
547
+ alias_matcher :a_string_ending_with, :end_with
548
+ alias_matcher :ending_with, :end_with
507
549
 
508
550
  # Passes if <tt>actual == expected</tt>.
509
551
  #
@@ -511,14 +553,13 @@ module RSpec
511
553
  # information about equality in Ruby.
512
554
  #
513
555
  # @example
514
- #
515
556
  # expect(5).to eq(5)
516
557
  # expect(5).not_to eq(3)
517
558
  def eq(expected)
518
559
  BuiltIn::Eq.new(expected)
519
560
  end
520
561
  alias_matcher :an_object_eq_to, :eq
521
- alias_matcher :eq_to, :eq
562
+ alias_matcher :eq_to, :eq
522
563
 
523
564
  # Passes if `actual.eql?(expected)`
524
565
  #
@@ -526,14 +567,13 @@ module RSpec
526
567
  # information about equality in Ruby.
527
568
  #
528
569
  # @example
529
- #
530
570
  # expect(5).to eql(5)
531
571
  # expect(5).not_to eql(3)
532
572
  def eql(expected)
533
573
  BuiltIn::Eql.new(expected)
534
574
  end
535
575
  alias_matcher :an_object_eql_to, :eql
536
- alias_matcher :eql_to, :eql
576
+ alias_matcher :eql_to, :eql
537
577
 
538
578
  # Passes if <tt>actual.equal?(expected)</tt> (object identity).
539
579
  #
@@ -541,14 +581,13 @@ module RSpec
541
581
  # information about equality in Ruby.
542
582
  #
543
583
  # @example
544
- #
545
- # expect(5).to equal(5) # Fixnums are equal
584
+ # expect(5).to equal(5) # Integers are equal
546
585
  # expect("5").not_to equal("5") # Strings that look the same are not the same object
547
586
  def equal(expected)
548
587
  BuiltIn::Equal.new(expected)
549
588
  end
550
589
  alias_matcher :an_object_equal_to, :equal
551
- alias_matcher :equal_to, :equal
590
+ alias_matcher :equal_to, :equal
552
591
 
553
592
  # Passes if `actual.exist?` or `actual.exists?`
554
593
  #
@@ -558,33 +597,57 @@ module RSpec
558
597
  BuiltIn::Exist.new(*args)
559
598
  end
560
599
  alias_matcher :an_object_existing, :exist
561
- alias_matcher :existing, :exist
600
+ alias_matcher :existing, :exist
601
+
602
+ # Passes if actual's attribute values match the expected attributes hash.
603
+ # This works no matter how you define your attribute readers.
604
+ #
605
+ # @example
606
+ # Person = Struct.new(:name, :age)
607
+ # person = Person.new("Bob", 32)
608
+ #
609
+ # expect(person).to have_attributes(:name => "Bob", :age => 32)
610
+ # expect(person).to have_attributes(:name => a_string_starting_with("B"), :age => (a_value > 30) )
611
+ #
612
+ # @note It will fail if actual doesn't respond to any of the expected attributes.
613
+ #
614
+ # @example
615
+ # expect(person).to have_attributes(:color => "red")
616
+ def have_attributes(expected)
617
+ BuiltIn::HaveAttributes.new(expected)
618
+ end
619
+ alias_matcher :an_object_having_attributes, :have_attributes
620
+ alias_matcher :having_attributes, :have_attributes
562
621
 
563
622
  # Passes if actual includes expected. This works for
564
623
  # collections and Strings. You can also pass in multiple args
565
624
  # and it will only pass if all args are found in collection.
566
625
  #
567
626
  # @example
568
- #
569
627
  # expect([1,2,3]).to include(3)
570
628
  # expect([1,2,3]).to include(2,3)
571
629
  # expect([1,2,3]).to include(2,3,4) # fails
572
630
  # expect([1,2,3]).not_to include(4)
573
631
  # expect("spread").to include("read")
574
632
  # expect("spread").not_to include("red")
633
+ # expect(:a => 1, :b => 2).to include(:a)
634
+ # expect(:a => 1, :b => 2).to include(:a, :b)
635
+ # expect(:a => 1, :b => 2).to include(:a => 1)
636
+ # expect(:a => 1, :b => 2).to include(:b => 2, :a => 1)
637
+ # expect(:a => 1, :b => 2).to include(:c) # fails
638
+ # expect(:a => 1, :b => 2).not_to include(:a => 2)
575
639
  def include(*expected)
576
640
  BuiltIn::Include.new(*expected)
577
641
  end
578
642
  alias_matcher :a_collection_including, :include
579
- alias_matcher :a_string_including, :include
580
- alias_matcher :a_hash_including, :include
581
- alias_matcher :including, :include
643
+ alias_matcher :a_string_including, :include
644
+ alias_matcher :a_hash_including, :include
645
+ alias_matcher :including, :include
582
646
 
583
- # Passes if actual all expected objects pass. This works for
584
- # any enumerable object.
647
+ # Passes if the provided matcher passes when checked against all
648
+ # elements of the collection.
585
649
  #
586
650
  # @example
587
- #
588
651
  # expect([1, 3, 5]).to all be_odd
589
652
  # expect([1, 3, 6]).to all be_odd # fails
590
653
  #
@@ -606,12 +669,10 @@ module RSpec
606
669
  # pair of elements.
607
670
  #
608
671
  # @example
609
- #
610
672
  # expect(email).to match(/^([^\s]+)((?:[-a-z0-9]+\.)+[a-z]{2,})$/i)
611
673
  # expect(email).to match("@example.com")
612
674
  #
613
675
  # @example
614
- #
615
676
  # hash = {
616
677
  # :a => {
617
678
  # :b => ["foo", 5],
@@ -623,7 +684,7 @@ module RSpec
623
684
  # :a => {
624
685
  # :b => a_collection_containing_exactly(
625
686
  # a_string_starting_with("f"),
626
- # an_instance_of(Fixnum)
687
+ # an_instance_of(Integer)
627
688
  # ),
628
689
  # :c => { :d => (a_value < 3) }
629
690
  # }
@@ -636,17 +697,16 @@ module RSpec
636
697
  def match(expected)
637
698
  BuiltIn::Match.new(expected)
638
699
  end
639
- alias_matcher :match_regex, :match
700
+ alias_matcher :match_regex, :match
640
701
  alias_matcher :an_object_matching, :match
641
- alias_matcher :a_string_matching, :match
642
- alias_matcher :matching, :match
702
+ alias_matcher :a_string_matching, :match
703
+ alias_matcher :matching, :match
643
704
 
644
705
  # An alternate form of `contain_exactly` that accepts
645
706
  # the expected contents as a single array arg rather
646
- # that splatted out as individual items.
707
+ # than splatted out as individual items.
647
708
  #
648
709
  # @example
649
- #
650
710
  # expect(results).to contain_exactly(1, 2)
651
711
  # # is identical to:
652
712
  # expect(results).to match_array([1, 2])
@@ -655,13 +715,19 @@ module RSpec
655
715
  def match_array(items)
656
716
  contain_exactly(*items)
657
717
  end
718
+ alias_matcher :an_array_matching, :match_array do |desc|
719
+ desc.sub("contain exactly", "an array containing exactly")
720
+ end
658
721
 
659
722
  # With no arg, passes if the block outputs `to_stdout` or `to_stderr`.
660
- # With a string, passes if the blocks outputs that specific string `to_stdout` or `to_stderr`.
661
- # With a regexp or matcher, passes if the blocks outputs a string `to_stdout` or `to_stderr` that matches.
723
+ # With a string, passes if the block outputs that specific string `to_stdout` or `to_stderr`.
724
+ # With a regexp or matcher, passes if the block outputs a string `to_stdout` or `to_stderr` that matches.
662
725
  #
663
- # @example
726
+ # To capture output from any spawned subprocess as well, use `to_stdout_from_any_process` or
727
+ # `to_stderr_from_any_process`. Output from any process that inherits the main process's corresponding
728
+ # standard stream will be captured.
664
729
  #
730
+ # @example
665
731
  # expect { print 'foo' }.to output.to_stdout
666
732
  # expect { print 'foo' }.to output('foo').to_stdout
667
733
  # expect { print 'foo' }.to output(/foo/).to_stdout
@@ -674,10 +740,15 @@ module RSpec
674
740
  #
675
741
  # expect { do_something }.to_not output.to_stderr
676
742
  #
677
- # @note This matcher works by temporarily replacing `$stdout` or `$stderr`,
678
- # so it's not able to intercept stream output that explicitly uses `STDOUT`/`STDERR`
743
+ # expect { system('echo foo') }.to output("foo\n").to_stdout_from_any_process
744
+ # expect { system('echo foo', out: :err) }.to output("foo\n").to_stderr_from_any_process
745
+ #
746
+ # @note `to_stdout` and `to_stderr` work by temporarily replacing `$stdout` or `$stderr`,
747
+ # so they're not able to intercept stream output that explicitly uses `STDOUT`/`STDERR`
679
748
  # or that uses a reference to `$stdout`/`$stderr` that was stored before the
680
- # matcher is used.
749
+ # matcher was used.
750
+ # @note `to_stdout_from_any_process` and `to_stderr_from_any_process` use Tempfiles, and
751
+ # are thus significantly (~30x) slower than `to_stdout` and `to_stderr`.
681
752
  def output(expected=nil)
682
753
  BuiltIn::Output.new(expected)
683
754
  end
@@ -685,29 +756,30 @@ module RSpec
685
756
 
686
757
  # With no args, matches if any error is raised.
687
758
  # With a named error, matches only if that specific error is raised.
688
- # With a named error and messsage specified as a String, matches only if both match.
689
- # With a named error and messsage specified as a Regexp, matches only if both match.
759
+ # With a named error and message specified as a String, matches only if both match.
760
+ # With a named error and message specified as a Regexp, matches only if both match.
690
761
  # Pass an optional block to perform extra verifications on the exception matched
691
762
  #
692
763
  # @example
693
- #
694
764
  # expect { do_something_risky }.to raise_error
695
765
  # expect { do_something_risky }.to raise_error(PoorRiskDecisionError)
696
766
  # expect { do_something_risky }.to raise_error(PoorRiskDecisionError) { |error| expect(error.data).to eq 42 }
767
+ # expect { do_something_risky }.to raise_error { |error| expect(error.data).to eq 42 }
697
768
  # expect { do_something_risky }.to raise_error(PoorRiskDecisionError, "that was too risky")
698
769
  # expect { do_something_risky }.to raise_error(PoorRiskDecisionError, /oo ri/)
770
+ # expect { do_something_risky }.to raise_error("that was too risky")
699
771
  #
700
772
  # expect { do_something_risky }.not_to raise_error
701
- def raise_error(error=Exception, message=nil, &block)
773
+ def raise_error(error=BuiltIn::RaiseError::UndefinedValue, message=nil, &block)
702
774
  BuiltIn::RaiseError.new(error, message, &block)
703
775
  end
704
- alias_method :raise_exception, :raise_error
776
+ alias_method :raise_exception, :raise_error
705
777
 
706
- alias_matcher :a_block_raising, :raise_error do |desc|
778
+ alias_matcher :a_block_raising, :raise_error do |desc|
707
779
  desc.sub("raise", "a block raising")
708
780
  end
709
781
 
710
- alias_matcher :raising, :raise_error do |desc|
782
+ alias_matcher :raising, :raise_error do |desc|
711
783
  desc.sub("raise", "raising")
712
784
  end
713
785
 
@@ -715,14 +787,13 @@ module RSpec
715
787
  # provided. Names can be Strings or Symbols.
716
788
  #
717
789
  # @example
718
- #
719
790
  # expect("string").to respond_to(:length)
720
791
  #
721
792
  def respond_to(*names)
722
793
  BuiltIn::RespondTo.new(*names)
723
794
  end
724
795
  alias_matcher :an_object_responding_to, :respond_to
725
- alias_matcher :responding_to, :respond_to
796
+ alias_matcher :responding_to, :respond_to
726
797
 
727
798
  # Passes if the submitted block returns true. Yields target to the
728
799
  # block.
@@ -734,14 +805,16 @@ module RSpec
734
805
  # If you do find yourself in such a situation, you could always write
735
806
  # a custom matcher, which would likely make your specs more expressive.
736
807
  #
737
- # @example
808
+ # @param description [String] optional description to be used for this matcher.
738
809
  #
810
+ # @example
739
811
  # expect(5).to satisfy { |n| n > 3 }
740
- def satisfy(&block)
741
- BuiltIn::Satisfy.new(&block)
812
+ # expect(5).to satisfy("be greater than 3") { |n| n > 3 }
813
+ def satisfy(description=nil, &block)
814
+ BuiltIn::Satisfy.new(description, &block)
742
815
  end
743
816
  alias_matcher :an_object_satisfying, :satisfy
744
- alias_matcher :satisfying, :satisfy
817
+ alias_matcher :satisfying, :satisfy
745
818
 
746
819
  # Matches if the actual value starts with the expected value(s). In the
747
820
  # case of a string, matches against the first `expected.length` characters
@@ -749,7 +822,6 @@ module RSpec
749
822
  # `expected.length` elements of the actual array.
750
823
  #
751
824
  # @example
752
- #
753
825
  # expect("this string").to start_with "this s"
754
826
  # expect([0, 1, 2, 3, 4]).to start_with 0
755
827
  # expect([0, 2, 3, 4, 4]).to start_with 0, 1
@@ -757,8 +829,8 @@ module RSpec
757
829
  BuiltIn::StartWith.new(*expected)
758
830
  end
759
831
  alias_matcher :a_collection_starting_with, :start_with
760
- alias_matcher :a_string_starting_with, :start_with
761
- alias_matcher :starting_with, :start_with
832
+ alias_matcher :a_string_starting_with, :start_with
833
+ alias_matcher :starting_with, :start_with
762
834
 
763
835
  # Given no argument, matches if a proc throws any Symbol.
764
836
  #
@@ -768,7 +840,6 @@ module RSpec
768
840
  # specified Symbol with the specified arg.
769
841
  #
770
842
  # @example
771
- #
772
843
  # expect { do_something_risky }.to throw_symbol
773
844
  # expect { do_something_risky }.to throw_symbol(:that_was_risky)
774
845
  # expect { do_something_risky }.to throw_symbol(:that_was_risky, 'culprit')
@@ -784,7 +855,7 @@ module RSpec
784
855
  desc.sub("throw", "a block throwing")
785
856
  end
786
857
 
787
- alias_matcher :throwing, :throw_symbol do |desc|
858
+ alias_matcher :throwing, :throw_symbol do |desc|
788
859
  desc.sub("throw", "throwing")
789
860
  end
790
861
 
@@ -792,25 +863,21 @@ module RSpec
792
863
  # of whether or not arguments are yielded.
793
864
  #
794
865
  # @example
795
- #
796
866
  # expect { |b| 5.tap(&b) }.to yield_control
797
867
  # expect { |b| "a".to_sym(&b) }.not_to yield_control
798
868
  #
799
869
  # @note Your expect block must accept a parameter and pass it on to
800
870
  # the method-under-test as a block.
801
- # @note This matcher is not designed for use with methods that yield
802
- # multiple times.
803
871
  def yield_control
804
872
  BuiltIn::YieldControl.new
805
873
  end
806
- alias_matcher :a_block_yielding_control, :yield_control
807
- alias_matcher :yielding_control, :yield_control
874
+ alias_matcher :a_block_yielding_control, :yield_control
875
+ alias_matcher :yielding_control, :yield_control
808
876
 
809
877
  # Passes if the method called in the expect block yields with
810
878
  # no arguments. Fails if it does not yield, or yields with arguments.
811
879
  #
812
880
  # @example
813
- #
814
881
  # expect { |b| User.transaction(&b) }.to yield_with_no_args
815
882
  # expect { |b| 5.tap(&b) }.not_to yield_with_no_args # because it yields with `5`
816
883
  # expect { |b| "a".to_sym(&b) }.not_to yield_with_no_args # because it does not yield
@@ -822,8 +889,8 @@ module RSpec
822
889
  def yield_with_no_args
823
890
  BuiltIn::YieldWithNoArgs.new
824
891
  end
825
- alias_matcher :a_block_yielding_with_no_args, :yield_with_no_args
826
- alias_matcher :yielding_with_no_args, :yield_with_no_args
892
+ alias_matcher :a_block_yielding_with_no_args, :yield_with_no_args
893
+ alias_matcher :yielding_with_no_args, :yield_with_no_args
827
894
 
828
895
  # Given no arguments, matches if the method called in the expect
829
896
  # block yields with arguments (regardless of what they are or how
@@ -837,10 +904,9 @@ module RSpec
837
904
  # operator, the matcher will pass.
838
905
  #
839
906
  # @example
840
- #
841
907
  # expect { |b| 5.tap(&b) }.to yield_with_args # because #tap yields an arg
842
908
  # expect { |b| 5.tap(&b) }.to yield_with_args(5) # because 5 == 5
843
- # expect { |b| 5.tap(&b) }.to yield_with_args(Fixnum) # because Fixnum === 5
909
+ # expect { |b| 5.tap(&b) }.to yield_with_args(Integer) # because Integer === 5
844
910
  # expect { |b| File.open("f.txt", &b) }.to yield_with_args(/txt/) # because /txt/ === "f.txt"
845
911
  #
846
912
  # expect { |b| User.transaction(&b) }.not_to yield_with_args # because it yields no args
@@ -853,8 +919,8 @@ module RSpec
853
919
  def yield_with_args(*args)
854
920
  BuiltIn::YieldWithArgs.new(*args)
855
921
  end
856
- alias_matcher :a_block_yielding_with_args, :yield_with_args
857
- alias_matcher :yielding_with_args, :yield_with_args
922
+ alias_matcher :a_block_yielding_with_args, :yield_with_args
923
+ alias_matcher :yielding_with_args, :yield_with_args
858
924
 
859
925
  # Designed for use with methods that repeatedly yield (such as
860
926
  # iterators). Passes if the method called in the expect block yields
@@ -865,7 +931,6 @@ module RSpec
865
931
  # operator, the matcher will pass.
866
932
  #
867
933
  # @example
868
- #
869
934
  # expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3)
870
935
  # expect { |b| { :a => 1, :b => 2 }.each(&b) }.to yield_successive_args([:a, 1], [:b, 2])
871
936
  # expect { |b| [1, 2, 3].each(&b) }.not_to yield_successive_args(1, 2)
@@ -875,8 +940,8 @@ module RSpec
875
940
  def yield_successive_args(*args)
876
941
  BuiltIn::YieldSuccessiveArgs.new(*args)
877
942
  end
878
- alias_matcher :a_block_yielding_successive_args, :yield_successive_args
879
- alias_matcher :yielding_successive_args, :yield_successive_args
943
+ alias_matcher :a_block_yielding_successive_args, :yield_successive_args
944
+ alias_matcher :yielding_successive_args, :yield_successive_args
880
945
 
881
946
  # Delegates to {RSpec::Expectations.configuration}.
882
947
  # This is here because rspec-core's `expect_with` option
@@ -889,8 +954,9 @@ module RSpec
889
954
 
890
955
  private
891
956
 
892
- BE_PREDICATE_REGEX = /^(be_(?:an?_)?)(.*)/
957
+ BE_PREDICATE_REGEX = /^(?:be_(?:an?_)?)(.*)/
893
958
  HAS_REGEX = /^(?:have_)(.*)/
959
+ DYNAMIC_MATCHER_REGEX = Regexp.union(BE_PREDICATE_REGEX, HAS_REGEX)
894
960
 
895
961
  def method_missing(method, *args, &block)
896
962
  case method.to_s
@@ -902,20 +968,77 @@ module RSpec
902
968
  super
903
969
  end
904
970
  end
971
+ ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
972
+
973
+ if RUBY_VERSION.to_f >= 1.9
974
+ def respond_to_missing?(method, *)
975
+ method =~ DYNAMIC_MATCHER_REGEX || super
976
+ end
977
+ else # for 1.8.7
978
+ # :nocov:
979
+ def respond_to?(method, *)
980
+ method = method.to_s
981
+ method =~ DYNAMIC_MATCHER_REGEX || super
982
+ end
983
+ public :respond_to?
984
+ # :nocov:
985
+ end
905
986
 
906
987
  # @api private
907
988
  def self.is_a_matcher?(obj)
908
989
  return true if ::RSpec::Matchers::BuiltIn::BaseMatcher === obj
909
- return false if obj.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher)
990
+ begin
991
+ return false if obj.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher)
992
+ rescue NoMethodError
993
+ # Some objects, like BasicObject, don't implemented standard
994
+ # reflection methods.
995
+ return false
996
+ end
910
997
  return false unless obj.respond_to?(:matches?)
911
998
 
912
999
  obj.respond_to?(:failure_message) ||
913
1000
  obj.respond_to?(:failure_message_for_should) # support legacy matchers
914
1001
  end
915
1002
 
1003
+ ::RSpec::Support.register_matcher_definition do |obj|
1004
+ is_a_matcher?(obj)
1005
+ end
1006
+
916
1007
  # @api private
917
1008
  def self.is_a_describable_matcher?(obj)
918
1009
  is_a_matcher?(obj) && obj.respond_to?(:description)
919
1010
  end
1011
+
1012
+ class << self
1013
+ private
1014
+
1015
+ if RSpec::Support::Ruby.mri? && RUBY_VERSION[0, 3] == '1.9'
1016
+ # Note that `included` doesn't work for this because it is triggered
1017
+ # _after_ `RSpec::Matchers` is an ancestor of the inclusion host, rather
1018
+ # than _before_, like `append_features`. It's important we check this before
1019
+ # in order to find the cases where it was already previously included.
1020
+ # @api private
1021
+ def append_features(mod)
1022
+ return super if mod < self # `mod < self` indicates a re-inclusion.
1023
+
1024
+ subclasses = ObjectSpace.each_object(Class).select { |c| c < mod && c < self }
1025
+ return super unless subclasses.any?
1026
+
1027
+ subclasses.reject! { |s| subclasses.any? { |s2| s < s2 } } # Filter to the root ancestor.
1028
+ subclasses = subclasses.map { |s| "`#{s}`" }.join(", ")
1029
+
1030
+ RSpec.warning "`#{self}` has been included in a superclass (`#{mod}`) " \
1031
+ "after previously being included in subclasses (#{subclasses}), " \
1032
+ "which can trigger infinite recursion from `super` due to an MRI 1.9 bug " \
1033
+ "(https://redmine.ruby-lang.org/issues/3351). To work around this, " \
1034
+ "either upgrade to MRI 2.0+, include a dup of the module (e.g. " \
1035
+ "`include #{self}.dup`), or find a way to include `#{self}` in `#{mod}` " \
1036
+ "before it is included in subclasses (#{subclasses}). See " \
1037
+ "https://github.com/rspec/rspec-expectations/issues/814 for more info"
1038
+
1039
+ super
1040
+ end
1041
+ end
1042
+ end
920
1043
  end
921
1044
  end