File: reraising_eager_raises_spec.rb

package info (click to toggle)
ruby-rspec 3.13.0c0e0m0s1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,856 kB
  • sloc: ruby: 70,868; sh: 1,423; makefile: 99
file content (158 lines) | stat: -rw-r--r-- 5,222 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
require "spec_helper"

RSpec.describe "Reraising eager raises during the verify step" do
  it "does not reraise when a double receives a message that hasn't been allowed/expected" do
    with_unfulfilled_double do |dbl|
      expect { dbl.foo }.to fail
      expect { verify_all }.not_to raise_error
    end
  end

  context "when a negative expectation receives a call" do
    it "reraises during verification" do
      with_unfulfilled_double do |dbl|
        expect(dbl).not_to receive(:foo)
        expect { dbl.foo }.to fail
        expect { verify_all }.to fail_with(/expected: 0 times with any arguments/)
      end
    end

    it 'notifies both exceptions using the same `:source_id` so `aggregate_failures` can de-dup' do
      with_unfulfilled_double do |dbl|
        expect(dbl).not_to receive(:foo)
        expect { dbl.foo }.to notify_with_same_source_id_as_later_verification
      end
    end

    it 'notifies with a different `source_id` than that for the same double and a different message' do
      with_unfulfilled_double do |dbl|
        expect(dbl).not_to receive(:foo)

        expect {
          dbl.foo # should trigger first source_id
          reset(dbl)

          # Prepare a failing expectation for a different message
          expect(dbl).not_to receive(:bar)
          RSpec::Support.with_failure_notifier(Proc.new {}) { dbl.bar }
        }.not_to notify_with_same_source_id_as_later_verification
      end
    end

    it 'notifies with a different `source_id` than a different double expecting that message' do
      with_unfulfilled_double do |dbl_1|
        with_unfulfilled_double do |dbl_2|
          expect(dbl_1).not_to receive(:foo)
          expect(dbl_2).not_to receive(:foo)

          expect { dbl_2.foo }.to fail
          expect { dbl_1.foo; reset(dbl_1) }.not_to notify_with_same_source_id_as_later_verification
        end
      end
    end
  end

  context "when an expectation with a count is exceeded" do
    def prepare(dbl)
      expect(dbl).to receive(:foo).exactly(2).times

      dbl.foo
      dbl.foo
    end

    it "reraises during verification" do
      with_unfulfilled_double do |dbl|
        prepare dbl

        expect { dbl.foo }.to fail
        expect { verify_all }.to fail_with(/expected: 2 times with any arguments/)
      end
    end

    it 'notifies both exceptions using the same `:source_id` so `aggregate_failures` can de-dup' do
      with_unfulfilled_double do |dbl|
        prepare dbl
        expect { dbl.foo }.to notify_with_same_source_id_as_later_verification
      end
    end
  end

  context "when an expectation is called with the wrong arguments" do
    it "reraises during verification" do
      with_unfulfilled_double do |dbl|
        expect(dbl).to receive(:foo).with(1, 2, 3)
        expect { dbl.foo(1, 2, 4) }.to fail
        expect { verify_all }.to fail_with(/expected: 1 time with arguments: \(1, 2, 3\)/)
      end
    end

    it 'notifies both exceptions using the same `:source_id` so `aggregate_failures` can de-dup' do
      with_unfulfilled_double do |dbl|
        expect(dbl).to receive(:foo).with(1, 2, 3)
        expect { dbl.foo(1, 2, 4) }.to notify_with_same_source_id_as_later_verification
      end
    end
  end

  context "when an expectation is called out of order",
          :pending => "Says bar was called 0 times when it was, see: http://git.io/pjTq" do
    it "reraises during verification" do
      with_unfulfilled_double do |dbl|
        expect(dbl).to receive(:foo).ordered
        expect(dbl).to receive(:bar).ordered
        expect { dbl.bar }.to fail
        dbl.foo # satisfy the `foo` expectation so that only the bar one fails below
        expect { verify_all }.to fail_with(/received :bar out of order/)
      end
    end
  end

  RSpec::Matchers.define :notify_with_same_source_id_as_later_verification do
    attr_reader :block

    match do |block|
      @block = block
      block_source_id == verify_all_source_id && block_source_id
    end

    match_when_negated do |block|
      @block = block
      block_source_id && verify_all_source_id && (
        block_source_id != verify_all_source_id
      )
    end

    supports_block_expectations

    failure_message do
      if block_source_id.nil?
        "expected it to notify with a non-nil source id"
      else
        "expected `verify_all` to notify with source_id: #{block_source_id.inspect} but notified with source_id: #{verify_all_source_id.inspect}"
      end
    end

    failure_message_when_negated do
      if block_source_id.nil?
        "expected it to notify with a non-nil source id"
      else
        "expected `verify_all` to notify with a different source_id but got the same one: #{block_source_id.inspect} / #{verify_all_source_id.inspect}"
      end
    end

    def block_source_id
      @block_source_id ||= capture_notified_source_id(&block)
    end

    def verify_all_source_id
      @verify_all_source_id ||= capture_notified_source_id { verify_all }
    end

    def capture_notified_source_id(&block)
      source_id = nil
      notifier = Proc.new { |_err, opt| source_id = opt.fetch(:source_id) }
      RSpec::Support.with_failure_notifier(notifier, &block)
      source_id
    end
  end
end