rspec-expectations 2.13.0 → 2.99.0

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.
Files changed (96) hide show
  1. checksums.yaml +15 -0
  2. data/Changelog.md +204 -23
  3. data/README.md +43 -87
  4. data/features/README.md +10 -10
  5. data/features/built_in_matchers/README.md +41 -41
  6. data/features/built_in_matchers/be.feature +40 -40
  7. data/features/built_in_matchers/be_within.feature +3 -3
  8. data/features/built_in_matchers/expect_change.feature +6 -6
  9. data/features/built_in_matchers/expect_error.feature +2 -2
  10. data/features/built_in_matchers/start_with.feature +1 -1
  11. data/features/built_in_matchers/throw_symbol.feature +11 -11
  12. data/features/built_in_matchers/yield.feature +18 -3
  13. data/features/custom_matchers/define_diffable_matcher.feature +1 -1
  14. data/features/custom_matchers/define_matcher_outside_rspec.feature +6 -6
  15. data/features/custom_matchers/define_matcher_with_fluent_interface.feature +1 -1
  16. data/features/customized_message.feature +1 -1
  17. data/features/diffing.feature +1 -1
  18. data/features/step_definitions/additional_cli_steps.rb +10 -0
  19. data/features/support/env.rb +10 -1
  20. data/features/support/rubinius.rb +6 -0
  21. data/features/syntax_configuration.feature +3 -0
  22. data/features/test_frameworks/test_unit.feature +55 -17
  23. data/lib/rspec/expectations/caller_filter.rb +60 -0
  24. data/lib/rspec/{matchers → expectations}/configuration.rb +5 -3
  25. data/lib/rspec/expectations/deprecation.rb +20 -31
  26. data/lib/rspec/expectations/differ.rb +48 -9
  27. data/lib/rspec/expectations/expectation_target.rb +81 -15
  28. data/lib/rspec/expectations/extensions/object.rb +2 -12
  29. data/lib/rspec/expectations/fail_with.rb +11 -1
  30. data/lib/rspec/expectations/handler.rb +16 -7
  31. data/lib/rspec/expectations/syntax.rb +5 -7
  32. data/lib/rspec/expectations/version.rb +1 -1
  33. data/lib/rspec/expectations.rb +28 -2
  34. data/lib/rspec/matchers/be_close.rb +4 -1
  35. data/lib/rspec/matchers/built_in/base_matcher.rb +17 -10
  36. data/lib/rspec/matchers/built_in/be.rb +69 -32
  37. data/lib/rspec/matchers/built_in/be_within.rb +9 -3
  38. data/lib/rspec/matchers/built_in/change.rb +49 -3
  39. data/lib/rspec/matchers/built_in/has.rb +40 -7
  40. data/lib/rspec/matchers/built_in/have.rb +170 -5
  41. data/lib/rspec/matchers/built_in/include.rb +3 -11
  42. data/lib/rspec/matchers/built_in/match.rb +5 -0
  43. data/lib/rspec/matchers/built_in/match_array.rb +1 -1
  44. data/lib/rspec/matchers/built_in/raise_error.rb +34 -8
  45. data/lib/rspec/matchers/built_in/respond_to.rb +7 -1
  46. data/lib/rspec/matchers/built_in/satisfy.rb +7 -1
  47. data/lib/rspec/matchers/built_in/throw_symbol.rb +10 -2
  48. data/lib/rspec/matchers/built_in/yield.rb +102 -5
  49. data/lib/rspec/matchers/built_in.rb +2 -2
  50. data/lib/rspec/matchers/differentiate_block_method_types.rb +55 -0
  51. data/lib/rspec/matchers/dsl.rb +2 -1
  52. data/lib/rspec/matchers/match_aliases.rb +22 -0
  53. data/lib/rspec/matchers/matcher.rb +131 -10
  54. data/lib/rspec/matchers/operator_matcher.rb +70 -66
  55. data/lib/rspec/matchers/pretty.rb +11 -1
  56. data/lib/rspec/matchers/test_unit_integration.rb +28 -0
  57. data/lib/rspec/matchers.rb +175 -146
  58. data/lib/rspec-expectations.rb +5 -0
  59. data/spec/rspec/{matchers → expectations}/configuration_spec.rb +78 -91
  60. data/spec/rspec/expectations/differ_spec.rb +65 -6
  61. data/spec/rspec/expectations/expectation_target_spec.rb +72 -3
  62. data/spec/rspec/expectations/extensions/kernel_spec.rb +9 -5
  63. data/spec/rspec/expectations/fail_with_spec.rb +19 -0
  64. data/spec/rspec/expectations/handler_spec.rb +43 -22
  65. data/spec/rspec/expectations/syntax_spec.rb +51 -9
  66. data/spec/rspec/expectations_spec.rb +71 -0
  67. data/spec/rspec/matchers/base_matcher_spec.rb +33 -18
  68. data/spec/rspec/matchers/be_close_spec.rb +9 -6
  69. data/spec/rspec/matchers/be_spec.rb +146 -45
  70. data/spec/rspec/matchers/be_within_spec.rb +8 -0
  71. data/spec/rspec/matchers/change_spec.rb +107 -7
  72. data/spec/rspec/matchers/description_generation_spec.rb +38 -20
  73. data/spec/rspec/matchers/differentiate_block_method_types_spec.rb +39 -0
  74. data/spec/rspec/matchers/eq_spec.rb +1 -1
  75. data/spec/rspec/matchers/equal_spec.rb +26 -0
  76. data/spec/rspec/matchers/exist_spec.rb +9 -9
  77. data/spec/rspec/matchers/has_spec.rb +25 -1
  78. data/spec/rspec/matchers/have_spec.rb +411 -3
  79. data/spec/rspec/matchers/include_matcher_integration_spec.rb +2 -2
  80. data/spec/rspec/matchers/include_spec.rb +4 -4
  81. data/spec/rspec/matchers/match_array_spec.rb +1 -1
  82. data/spec/rspec/matchers/match_spec.rb +14 -1
  83. data/spec/rspec/matchers/matcher_spec.rb +213 -24
  84. data/spec/rspec/matchers/operator_matcher_spec.rb +56 -8
  85. data/spec/rspec/matchers/pretty_spec.rb +23 -0
  86. data/spec/rspec/matchers/raise_error_spec.rb +242 -102
  87. data/spec/rspec/matchers/respond_to_spec.rb +4 -4
  88. data/spec/rspec/matchers/satisfy_spec.rb +1 -1
  89. data/spec/rspec/matchers/start_with_end_with_spec.rb +2 -2
  90. data/spec/rspec/matchers/throw_symbol_spec.rb +14 -14
  91. data/spec/rspec/matchers/yield_spec.rb +81 -4
  92. data/spec/spec_helper.rb +5 -3
  93. data/spec/support/helper_methods.rb +42 -0
  94. data/spec/support/shared_examples.rb +42 -0
  95. metadata +40 -44
  96. data/spec/rspec/matchers/matchers_spec.rb +0 -37
@@ -28,7 +28,7 @@ module RSpec
28
28
  end.new
29
29
 
30
30
  expect(actual).to eq :anything # to trigger the matches? method
31
- expect(called).to be_true
31
+ expect(called).to be_truthy
32
32
  end
33
33
 
34
34
  it "describes itself" do
@@ -24,6 +24,32 @@ module RSpec
24
24
  expect(matcher.description).to eq "equal 1"
25
25
  end
26
26
 
27
+ context "when the expected object is falsey in conditinal semantics" do
28
+ it "describes itself with the expected object" do
29
+ matcher = equal(nil)
30
+ matcher.matches?(nil)
31
+ expect(matcher.description).to eq "equal nil"
32
+ end
33
+ end
34
+
35
+ context "when the expected object's #equal? always returns true" do
36
+ let(:strange_string) do
37
+ string = "foo"
38
+
39
+ def string.equal?(other)
40
+ true
41
+ end
42
+
43
+ string
44
+ end
45
+
46
+ it "describes itself with the expected object" do
47
+ matcher = equal(strange_string)
48
+ matcher.matches?(strange_string)
49
+ expect(matcher.description).to eq 'equal "foo"'
50
+ end
51
+ end
52
+
27
53
  it "suggests the `eq` matcher on failure" do
28
54
  expected, actual = "1", "1"
29
55
  expect {
@@ -8,7 +8,7 @@ describe "exist matcher" do
8
8
  end
9
9
 
10
10
  context "when the object does not respond to #exist? or #exists?" do
11
- subject { mock }
11
+ subject { double }
12
12
 
13
13
  [:to, :not_to].each do |expect_method|
14
14
  describe "expect(...).#{expect_method} exist" do
@@ -25,12 +25,12 @@ describe "exist matcher" do
25
25
  context "when the object responds to ##{predicate}" do
26
26
  describe "expect(...).to exist" do
27
27
  it "passes if #{predicate}" do
28
- expect(mock(predicate => true)).to exist
28
+ expect(double(predicate => true)).to exist
29
29
  end
30
30
 
31
31
  it "fails if not #{predicate}" do
32
32
  expect {
33
- expect(mock(predicate => false)).to exist
33
+ expect(double(predicate => false)).to exist
34
34
  }.to fail_with(/expected .* to exist/)
35
35
  end
36
36
 
@@ -51,12 +51,12 @@ describe "exist matcher" do
51
51
 
52
52
  describe "expect(...).not_to exist" do
53
53
  it "passes if not #{predicate}" do
54
- expect(mock(predicate => false)).not_to exist
54
+ expect(double(predicate => false)).not_to exist
55
55
  end
56
56
 
57
57
  it "fails if #{predicate}" do
58
58
  expect {
59
- expect(mock(predicate => true)).not_to exist
59
+ expect(double(predicate => true)).not_to exist
60
60
  }.to fail_with(/expected .* not to exist/)
61
61
  end
62
62
  end
@@ -65,7 +65,7 @@ describe "exist matcher" do
65
65
 
66
66
  context "when the object responds to #exist? and #exists?" do
67
67
  context "when they both return falsey values" do
68
- subject { mock(:exist? => false, :exists? => nil) }
68
+ subject { double(:exist? => false, :exists? => nil) }
69
69
 
70
70
  describe "expect(...).not_to exist" do
71
71
  it "passes" do
@@ -83,7 +83,7 @@ describe "exist matcher" do
83
83
  end
84
84
 
85
85
  context "when they both return truthy values" do
86
- subject { mock(:exist? => true, :exists? => "something true") }
86
+ subject { double(:exist? => true, :exists? => "something true") }
87
87
 
88
88
  describe "expect(...).not_to exist" do
89
89
  it "fails" do
@@ -101,7 +101,7 @@ describe "exist matcher" do
101
101
  end
102
102
 
103
103
  context "when they return values with different truthiness" do
104
- subject { mock(:exist? => true, :exists? => false) }
104
+ subject { double(:exist? => true, :exists? => false) }
105
105
 
106
106
  [:to, :not_to].each do |expect_method|
107
107
  describe "expect(...).#{expect_method} exist" do
@@ -116,7 +116,7 @@ describe "exist matcher" do
116
116
  end
117
117
 
118
118
  it 'passes any provided arguments to the call to #exist?' do
119
- object = mock
119
+ object = double
120
120
  object.should_receive(:exist?).with(:foo, :bar) { true }
121
121
 
122
122
  expect(object).to exist(:foo, :bar)
@@ -48,6 +48,20 @@ describe "expect(...).to have_sym(*args)" do
48
48
  }.to raise_error(NoMethodError)
49
49
  end
50
50
 
51
+ it "warns of deprecation if #has_sym?(*args) is private" do
52
+ klass = Class.new do
53
+ def has_foo?
54
+ true
55
+ end
56
+ private :has_foo?
57
+
58
+ # prevents double deprecation
59
+ def respond_to?(_); true; end
60
+ end
61
+ expect_deprecation_with_call_site(__FILE__, __LINE__ + 1, /matching with have_foo on private method/)
62
+ expect(klass.new).to have_foo
63
+ end
64
+
51
65
  it "reraises an exception thrown in #has_sym?(*args)" do
52
66
  o = Object.new
53
67
  def o.has_sym?(*args)
@@ -57,6 +71,16 @@ describe "expect(...).to have_sym(*args)" do
57
71
  expect(o).to have_sym(:foo)
58
72
  }.to raise_error("Funky exception")
59
73
  end
74
+
75
+ it 'warns of deprecation when actual does not respond to #has_sym?' do
76
+ foo_class = Class.new do
77
+ def method_missing(method)
78
+ return true if method == :has_foo?
79
+ end
80
+ end
81
+ expect_deprecation_with_call_site(__FILE__, __LINE__ + 1, /Matching with have_foo on an object that doesn't respond to `has_foo\?`/)
82
+ expect(foo_class.new).to have_foo
83
+ end
60
84
  end
61
85
 
62
86
  describe "expect(...).not_to have_sym(*args)" do
@@ -117,6 +141,6 @@ describe "has" do
117
141
  def o.send(*args); raise "DOH! Library developers shouldn't use #send!" end
118
142
  expect {
119
143
  expect(o).to have_key(:a)
120
- }.to_not raise_error
144
+ }.not_to raise_error
121
145
  end
122
146
  end
@@ -10,7 +10,18 @@ describe "have matcher" do
10
10
  end
11
11
  end
12
12
 
13
- before(:each) { stub_const("ActiveSupport::Inflector", inflector) }
13
+ before(:each) do
14
+ stub_const("ActiveSupport::Inflector", inflector)
15
+ allow_deprecation
16
+ end
17
+
18
+ def expect_have_deprecation(expression, message)
19
+ expect_deprecation_with_type(
20
+ "`#{expression}`",
21
+ message,
22
+ 'the have matcher'
23
+ )
24
+ end
14
25
 
15
26
  def create_collection_owner_with(n)
16
27
  owner = RSpec::Expectations::Helper::CollectionOwner.new
@@ -326,13 +337,13 @@ EOF
326
337
 
327
338
  describe "have(n).items(args, block)" do
328
339
  it "passes args to target" do
329
- target = mock("target")
340
+ target = double("target")
330
341
  target.should_receive(:items).with("arg1","arg2").and_return([1,2,3])
331
342
  expect(target).to have(3).items("arg1","arg2")
332
343
  end
333
344
 
334
345
  it "passes block to target" do
335
- target = mock("target")
346
+ target = double("target")
336
347
  block = lambda { 5 }
337
348
  target.should_receive(:items).with("arg1","arg2", block).and_return([1,2,3])
338
349
  expect(target).to have(3).items("arg1","arg2", block)
@@ -402,6 +413,16 @@ EOF
402
413
  end
403
414
  end
404
415
 
416
+ if RUBY_VERSION >= '2.0'
417
+ describe RSpec::Matchers::BuiltIn::Have, "for an Enumerator whose size is nil but count is supplied" do
418
+ let(:enumerator) { %w[a b c d].to_enum(:each) }
419
+
420
+ it 'works fine' do
421
+ expect(enumerator).to have(4).items
422
+ end
423
+ end
424
+ end
425
+
405
426
  describe RSpec::Matchers::BuiltIn::Have do
406
427
  it "has method_missing as private" do
407
428
  expect(described_class.private_instance_methods).to include_method(:method_missing)
@@ -442,4 +463,391 @@ EOF
442
463
  end
443
464
  end
444
465
  end
466
+
467
+ context "deprecations for the have matcher" do
468
+ it "has the correct call site in the deprecation message" do
469
+ expect_deprecation_with_call_site(__FILE__, __LINE__ + 1)
470
+ expect([1, 2, 3]).to have(3).items
471
+ end
472
+
473
+ context "when the target is a collection" do
474
+ it "prints a specific message for the positive expectation format" do
475
+ expectation_expression = "expect(collection).to have(3).items"
476
+
477
+ message = "the rspec-collection_matchers gem " +
478
+ "or replace your expectation with something like " +
479
+ "`expect(collection.size).to eq(3)`"
480
+
481
+ expect_have_deprecation(expectation_expression, message)
482
+
483
+ expect([1, 2, 3]).to have(3).items
484
+ end
485
+
486
+ it "prints a specific message for the negative expectation format" do
487
+ expectation_expression = "expect(collection).not_to have(4).items"
488
+
489
+ message = "the rspec-collection_matchers gem " +
490
+ "or replace your expectation with something like " +
491
+ "`expect(collection.size).to_not eq(4)`"
492
+
493
+ expect_have_deprecation(expectation_expression, message)
494
+
495
+ expect([1, 2, 3]).to_not have(4).items
496
+ end
497
+ end
498
+
499
+ context "when the target owns a collection" do
500
+ class self::BagOfWords
501
+ attr_reader :words
502
+
503
+ def initialize(words)
504
+ @words = words
505
+ end
506
+ end
507
+
508
+ it "prints a specific message for the positive expectation format" do
509
+ expectation_expression = "expect(collection_owner).to have(3).words"
510
+
511
+ message = "the rspec-collection_matchers gem " +
512
+ "or replace your expectation with something like " +
513
+ "`expect(collection_owner.words.size).to eq(3)`"
514
+
515
+ expect_have_deprecation(expectation_expression, message)
516
+
517
+ target = BagOfWords.new(%w[foo bar baz])
518
+ expect(target).to have(3).words
519
+ end
520
+
521
+ it "prints a specific message for the negative expectation format" do
522
+ expectation_expression = "expect(collection_owner).not_to have(4).words"
523
+
524
+ message = "the rspec-collection_matchers gem " +
525
+ "or replace your expectation with something like " +
526
+ "`expect(collection_owner.words.size).to_not eq(4)`"
527
+
528
+ expect_have_deprecation(expectation_expression, message)
529
+
530
+ target = BagOfWords.new(%w[foo bar baz])
531
+ expect(target).to_not have(4).words
532
+ end
533
+ end
534
+
535
+ context "when the target is a Rails record" do
536
+ class TheModel
537
+ attr_reader :errors
538
+
539
+ def initialize(errors)
540
+ @errors = {}
541
+ @errors[:attr] = Array(errors)
542
+ end
543
+
544
+ def errors_on(attr, _ignore_opts = {})
545
+ Array(@errors[attr]).flatten.compact
546
+ end
547
+ alias_method :error_on, :errors_on
548
+ end
549
+
550
+ let(:message_preamble) do
551
+ "the rspec-collection_matchers gem " +
552
+ "or replace your expectation with something like "
553
+ end
554
+
555
+ before do
556
+ stub_const "RSpec::Rails", Module.new
557
+ end
558
+
559
+ it "prints a specific message for the positive expectation format" do
560
+ expectation_expression = "expect(record).to have(2).errors_on(:attr)"
561
+ message = message_preamble + <<-EOS.gsub(/^\s+\|/, '')
562
+ |
563
+ |
564
+ | record.valid?
565
+ | expect(record.errors[:attr].size).to eq(2)
566
+ |
567
+ EOS
568
+
569
+ expect_have_deprecation(expectation_expression, message)
570
+
571
+ target = TheModel.new(%w(foo bar))
572
+ expect(target).to have(2).errors_on(:attr)
573
+ end
574
+
575
+ it "prints a specific message for the negative expectation format" do
576
+ expectation_expression = "expect(record).not_to have(2).errors_on(:attr)"
577
+ message = message_preamble + <<-EOS.gsub(/^\s+\|/, '')
578
+ |
579
+ |
580
+ | record.valid?
581
+ | expect(record.errors[:attr].size).to_not eq(2)
582
+ |
583
+ EOS
584
+
585
+ expect_have_deprecation(expectation_expression, message)
586
+
587
+ target = TheModel.new('foo')
588
+ expect(target).not_to have(2).errors_on(:attr)
589
+ end
590
+
591
+ it "prints message for singular form: `error_on`" do
592
+ expectation_expression = "expect(record).to have(1).error_on(:attr)"
593
+ message = message_preamble + <<-EOS.gsub(/^\s+\|/, '')
594
+ |
595
+ |
596
+ | record.valid?
597
+ | expect(record.errors[:attr].size).to eq(1)
598
+ |
599
+ EOS
600
+
601
+ expect_have_deprecation(expectation_expression, message)
602
+
603
+ target = TheModel.new('foo')
604
+ expect(target).to have(1).error_on(:attr)
605
+ end
606
+
607
+ it "includes a validation context when provided" do
608
+ expectation_expression = "expect(record).to have(2).errors_on(:attr, :context => :spec)"
609
+ message = message_preamble + <<-EOS.gsub(/^\s+\|/, '')
610
+ |
611
+ |
612
+ | record.valid?(:spec)
613
+ | expect(record.errors[:attr].size).to eq(2)
614
+ |
615
+ EOS
616
+
617
+ expect_have_deprecation(expectation_expression, message)
618
+
619
+ target = TheModel.new(%w(foo bar))
620
+ options = {:context => :spec, :should_be_ignored => true}
621
+ expect(target).to have(2).errors_on(:attr, options)
622
+ end
623
+ end
624
+
625
+ context "when the target is an enumerator" do
626
+ it "prints a specific message for the positive expectation format" do
627
+ target = %w[a b c].to_enum(:each)
628
+
629
+ expectation_expression = "expect(collection).to have(3).letters"
630
+
631
+ message = "the rspec-collection_matchers gem " +
632
+ "or replace your expectation with something like " +
633
+ "`expect(collection.count).to eq(3)`"
634
+
635
+ expect_have_deprecation(expectation_expression, message)
636
+
637
+ expect(target).to have(3).letters
638
+ end
639
+
640
+ it "prints a specific message for the negative expectation format" do
641
+ target = %w[a b c].to_enum(:each)
642
+
643
+ expectation_expression = "expect(collection).not_to have(4).letters"
644
+
645
+ message = "the rspec-collection_matchers gem " +
646
+ "or replace your expectation with something like " +
647
+ "`expect(collection.count).to_not eq(4)`"
648
+
649
+ expect_have_deprecation(expectation_expression, message)
650
+
651
+ expect(target).to_not have(4).letters
652
+ end
653
+ end
654
+ end
655
+
656
+ context "deprecations for the have_at_most matcher" do
657
+ it "has the correct call site in the deprecation message" do
658
+ expect_deprecation_with_call_site(__FILE__, __LINE__ + 1)
659
+ expect([1, 2, 3]).to have_at_most(3).items
660
+ end
661
+
662
+ context "when the target is a collection" do
663
+ it "prints a specific message for the positive expectation format" do
664
+ expectation_expression = "expect(collection).to have_at_most(3).items"
665
+
666
+ message = "the rspec-collection_matchers gem " +
667
+ "or replace your expectation with something like " +
668
+ "`expect(collection.size).to be <= 3`"
669
+
670
+ expect_have_deprecation(expectation_expression, message)
671
+
672
+ expect([1, 2, 3]).to have_at_most(3).items
673
+ end
674
+
675
+ it "prints a specific message for the negative expectation format" do
676
+ expectation_expression = "expect(collection).not_to have_at_most(2).items"
677
+
678
+ message = "the rspec-collection_matchers gem " +
679
+ "or replace your expectation with something like " +
680
+ "`expect(collection.size).to be > 2`"
681
+
682
+ expect_have_deprecation(expectation_expression, message)
683
+
684
+ expect([1, 2, 3]).to_not have_at_most(2).items
685
+ end
686
+ end
687
+
688
+ context "when the target owns a collection" do
689
+ class self::BagOfWords
690
+ attr_reader :words
691
+
692
+ def initialize(words)
693
+ @words = words
694
+ end
695
+ end
696
+
697
+ it "prints a specific message for the positive expectation format" do
698
+ expectation_expression = "expect(collection_owner).to have_at_most(3).words"
699
+
700
+ message = "the rspec-collection_matchers gem " +
701
+ "or replace your expectation with something like " +
702
+ "`expect(collection_owner.words.size).to be <= 3`"
703
+
704
+ expect_have_deprecation(expectation_expression, message)
705
+
706
+ target = BagOfWords.new(%w[foo bar baz])
707
+ expect(target).to have_at_most(3).words
708
+ end
709
+
710
+ it "prints a specific message for the negative expectation format" do
711
+ expectation_expression = "expect(collection_owner).not_to have_at_most(2).words"
712
+
713
+ message = "the rspec-collection_matchers gem " +
714
+ "or replace your expectation with something like " +
715
+ "`expect(collection_owner.words.size).to be > 2`"
716
+
717
+ expect_have_deprecation(expectation_expression, message)
718
+
719
+ target = BagOfWords.new(%w[foo bar baz])
720
+ expect(target).to_not have_at_most(2).words
721
+ end
722
+ end
723
+
724
+ context "when the target is an enumerator" do
725
+ it "prints a specific message for the positive expectation format" do
726
+ target = %w[a b c].to_enum(:each)
727
+
728
+ expectation_expression = "expect(collection).to have_at_most(3).letters"
729
+
730
+ message = "the rspec-collection_matchers gem " +
731
+ "or replace your expectation with something like " +
732
+ "`expect(collection.count).to be <= 3`"
733
+
734
+ expect_have_deprecation(expectation_expression, message)
735
+
736
+ expect(target).to have_at_most(3).letters
737
+ end
738
+
739
+ it "prints a specific message for the negative expectation format" do
740
+ target = %w[a b c].to_enum(:each)
741
+
742
+ expectation_expression = "expect(collection).not_to have_at_most(2).letters"
743
+
744
+ message = "the rspec-collection_matchers gem " +
745
+ "or replace your expectation with something like " +
746
+ "`expect(collection.count).to be > 2`"
747
+
748
+ expect_have_deprecation(expectation_expression, message)
749
+
750
+ expect(target).to_not have_at_most(2).letters
751
+ end
752
+ end
753
+ end
754
+
755
+ context "deprecations for the have_at_least matcher" do
756
+ it "has the correct call site in the deprecation message" do
757
+ expect_deprecation_with_call_site(__FILE__, __LINE__ + 1)
758
+ expect([1, 2, 3]).to have_at_least(3).items
759
+ end
760
+
761
+ context "when the target is a collection" do
762
+ it "prints a specific message for the positive expectation format" do
763
+ expectation_expression = "expect(collection).to have_at_least(3).items"
764
+
765
+ message = "the rspec-collection_matchers gem " +
766
+ "or replace your expectation with something like " +
767
+ "`expect(collection.size).to be >= 3`"
768
+
769
+ expect_have_deprecation(expectation_expression, message)
770
+
771
+ expect([1, 2, 3]).to have_at_least(3).items
772
+ end
773
+
774
+ it "prints a specific message for the negative expectation format" do
775
+ expectation_expression = "expect(collection).not_to have_at_least(4).items"
776
+
777
+ message = "the rspec-collection_matchers gem " +
778
+ "or replace your expectation with something like " +
779
+ "`expect(collection.size).to be < 4`"
780
+
781
+ expect_have_deprecation(expectation_expression, message)
782
+
783
+ expect([1, 2, 3]).to_not have_at_least(4).items
784
+ end
785
+ end
786
+
787
+ context "when the target owns a collection" do
788
+ class BagOfWords
789
+ attr_reader :words
790
+
791
+ def initialize(words)
792
+ @words = words
793
+ end
794
+ end
795
+
796
+ it "prints a specific message for the positive expectation format" do
797
+ expectation_expression = "expect(collection_owner).to have_at_least(3).words"
798
+
799
+ message = "the rspec-collection_matchers gem " +
800
+ "or replace your expectation with something like " +
801
+ "`expect(collection_owner.words.size).to be >= 3`"
802
+
803
+ expect_have_deprecation(expectation_expression, message)
804
+
805
+ target = BagOfWords.new(%w[foo bar baz])
806
+ expect(target).to have_at_least(3).words
807
+ end
808
+
809
+ it "prints a specific message for the negative expectation format" do
810
+ expectation_expression = "expect(collection_owner).not_to have_at_least(4).words"
811
+
812
+ message = "the rspec-collection_matchers gem " +
813
+ "or replace your expectation with something like " +
814
+ "`expect(collection_owner.words.size).to be < 4`"
815
+
816
+ expect_have_deprecation(expectation_expression, message)
817
+
818
+ target = BagOfWords.new(%w[foo bar baz])
819
+ expect(target).to_not have_at_least(4).words
820
+ end
821
+ end
822
+
823
+ context "when the target is an enumerator" do
824
+ it "prints a specific message for the positive expectation format" do
825
+ target = %w[a b c].to_enum(:each)
826
+
827
+ expectation_expression = "expect(collection).to have_at_least(3).letters"
828
+
829
+ message = "the rspec-collection_matchers gem " +
830
+ "or replace your expectation with something like " +
831
+ "`expect(collection.count).to be >= 3`"
832
+
833
+ expect_have_deprecation(expectation_expression, message)
834
+
835
+ expect(target).to have_at_least(3).letters
836
+ end
837
+
838
+ it "prints a specific message for the negative expectation format" do
839
+ target = %w[a b c].to_enum(:each)
840
+
841
+ expectation_expression = "expect(collection).not_to have_at_least(4).letters"
842
+
843
+ message = "the rspec-collection_matchers gem " +
844
+ "or replace your expectation with something like " +
845
+ "`expect(collection.count).to be < 4`"
846
+
847
+ expect_have_deprecation(expectation_expression, message)
848
+
849
+ expect(target).to_not have_at_least(4).letters
850
+ end
851
+ end
852
+ end
445
853
  end
@@ -22,8 +22,8 @@ module RSpec
22
22
  end
23
23
 
24
24
  it "works with be_[some predicate]" do
25
- expect([stub("actual", :happy? => true)]).to include( be_happy )
26
- expect([stub("actual", :happy? => false)]).not_to include( be_happy )
25
+ expect([double("actual", :happy? => true)]).to include( be_happy )
26
+ expect([double("actual", :happy? => false)]).not_to include( be_happy )
27
27
  end
28
28
  end
29
29
  end
@@ -137,7 +137,7 @@ describe "#include matcher" do
137
137
  end
138
138
  end
139
139
 
140
- describe "expect(...).to_not include(expected)" do
140
+ describe "expect(...).not_to include(expected)" do
141
141
  context "for a string target" do
142
142
  it "passes if target does not include expected" do
143
143
  expect("abc").not_to include("d")
@@ -188,7 +188,7 @@ describe "#include matcher" do
188
188
 
189
189
  end
190
190
 
191
- describe "expect(...).to_not include(with, multiple, args)" do
191
+ describe "expect(...).not_to include(with, multiple, args)" do
192
192
  context "for a string target" do
193
193
  it "passes if the target does not include any of the expected" do
194
194
  expect("abc").not_to include("d", "e", "f")
@@ -280,7 +280,7 @@ describe "#include matcher" do
280
280
  end
281
281
  end
282
282
 
283
- describe "expect(...).to_not include(:key => value)" do
283
+ describe "expect(...).not_to include(:key => value)" do
284
284
  context 'for a hash target' do
285
285
  it "fails if target includes the key/value pair" do
286
286
  expect {
@@ -364,7 +364,7 @@ describe "#include matcher" do
364
364
  end
365
365
  end
366
366
 
367
- describe "expect(...).to_not include(:key1 => value1, :key2 => value2)" do
367
+ describe "expect(...).not_to include(:key1 => value1, :key2 => value2)" do
368
368
  context 'for a hash target' do
369
369
  it "fails if target includes the key/value pairs" do
370
370
  expect {
@@ -156,7 +156,7 @@ MESSAGE
156
156
  end
157
157
  end
158
158
 
159
- describe "expect(...).to_not match_array [:with, :multiple, :args]" do
159
+ describe "expect(...).not_to match_array [:with, :multiple, :args]" do
160
160
  it "is not supported" do
161
161
  expect {
162
162
  expect([1,2,3]).not_to match_array [1,2,3]
@@ -30,9 +30,22 @@ describe "expect(...).to match(expected)" do
30
30
  matcher.matches?("string")
31
31
  expect(matcher.failure_message_for_should).to eq "expected \"string\" to match /rings/"
32
32
  end
33
+
34
+ it "provides a diff on failure" do
35
+ allow(RSpec::Matchers.configuration).to receive(:color?).and_return(false)
36
+
37
+ failure_message_that_includes_diff = %r%
38
+ \s*Diff:
39
+ \s*@@ -1,2 \+1,2 @@
40
+ \s*-/bar/
41
+ \s*\+"foo"%
42
+
43
+ expect { expect("foo").to match(/bar/) }.to fail_with(failure_message_that_includes_diff)
44
+ end
45
+
33
46
  end
34
47
 
35
- describe "expect(...).to_not match(expected)" do
48
+ describe "expect(...).not_to match(expected)" do
36
49
  it "passes when target (String) matches does not match (Regexp)" do
37
50
  expect("string").not_to match(/rings/)
38
51
  end