rspec-expectations 3.0.0.beta1 → 3.0.0.beta2

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 (122) hide show
  1. data.tar.gz.sig +2 -2
  2. data/.yardopts +1 -0
  3. data/Changelog.md +138 -0
  4. data/README.md +75 -8
  5. data/features/README.md +2 -2
  6. data/features/built_in_matchers/README.md +12 -9
  7. data/features/built_in_matchers/comparisons.feature +2 -2
  8. data/features/built_in_matchers/contain_exactly.feature +46 -0
  9. data/features/built_in_matchers/expect_change.feature +2 -2
  10. data/features/built_in_matchers/include.feature +0 -48
  11. data/features/built_in_matchers/output.feature +70 -0
  12. data/features/composing_matchers.feature +250 -0
  13. data/features/compound_expectations.feature +45 -0
  14. data/features/custom_matchers/access_running_example.feature +1 -1
  15. data/features/custom_matchers/define_matcher.feature +6 -6
  16. data/features/custom_matchers/define_matcher_outside_rspec.feature +4 -8
  17. data/features/test_frameworks/{test_unit.feature → minitest.feature} +11 -11
  18. data/lib/rspec/expectations.rb +31 -42
  19. data/lib/rspec/expectations/diff_presenter.rb +141 -0
  20. data/lib/rspec/expectations/differ.rb +22 -132
  21. data/lib/rspec/expectations/encoded_string.rb +56 -0
  22. data/lib/rspec/expectations/expectation_target.rb +0 -30
  23. data/lib/rspec/expectations/fail_with.rb +2 -2
  24. data/lib/rspec/expectations/handler.rb +128 -31
  25. data/lib/rspec/expectations/minitest_integration.rb +16 -0
  26. data/lib/rspec/expectations/syntax.rb +4 -58
  27. data/lib/rspec/expectations/version.rb +1 -1
  28. data/lib/rspec/matchers.rb +298 -60
  29. data/lib/rspec/matchers/aliased_matcher.rb +35 -0
  30. data/lib/rspec/matchers/built_in.rb +37 -33
  31. data/lib/rspec/matchers/built_in/base_matcher.rb +25 -15
  32. data/lib/rspec/matchers/built_in/be.rb +23 -31
  33. data/lib/rspec/matchers/built_in/be_between.rb +55 -0
  34. data/lib/rspec/matchers/built_in/be_within.rb +15 -11
  35. data/lib/rspec/matchers/built_in/change.rb +198 -81
  36. data/lib/rspec/matchers/built_in/compound.rb +106 -0
  37. data/lib/rspec/matchers/built_in/contain_exactly.rb +245 -0
  38. data/lib/rspec/matchers/built_in/eq.rb +43 -4
  39. data/lib/rspec/matchers/built_in/eql.rb +2 -2
  40. data/lib/rspec/matchers/built_in/equal.rb +35 -18
  41. data/lib/rspec/matchers/built_in/has.rb +16 -15
  42. data/lib/rspec/matchers/built_in/include.rb +45 -23
  43. data/lib/rspec/matchers/built_in/match.rb +6 -3
  44. data/lib/rspec/matchers/built_in/operators.rb +103 -0
  45. data/lib/rspec/matchers/built_in/output.rb +108 -0
  46. data/lib/rspec/matchers/built_in/raise_error.rb +9 -15
  47. data/lib/rspec/matchers/built_in/respond_to.rb +5 -4
  48. data/lib/rspec/matchers/built_in/satisfy.rb +4 -3
  49. data/lib/rspec/matchers/built_in/start_and_end_with.rb +37 -16
  50. data/lib/rspec/matchers/built_in/throw_symbol.rb +6 -5
  51. data/lib/rspec/matchers/built_in/yield.rb +31 -29
  52. data/lib/rspec/matchers/composable.rb +138 -0
  53. data/lib/rspec/matchers/dsl.rb +330 -0
  54. data/lib/rspec/matchers/generated_descriptions.rb +6 -6
  55. data/lib/rspec/matchers/matcher_delegator.rb +33 -0
  56. data/lib/rspec/matchers/pretty.rb +13 -2
  57. data/spec/rspec/expectations/{differ_spec.rb → diff_presenter_spec.rb} +56 -36
  58. data/spec/rspec/expectations/encoded_string_spec.rb +74 -0
  59. data/spec/rspec/expectations/extensions/kernel_spec.rb +11 -11
  60. data/spec/rspec/expectations/fail_with_spec.rb +8 -8
  61. data/spec/rspec/expectations/handler_spec.rb +27 -49
  62. data/spec/rspec/expectations/minitest_integration_spec.rb +27 -0
  63. data/spec/rspec/expectations/syntax_spec.rb +17 -67
  64. data/spec/rspec/expectations_spec.rb +7 -52
  65. data/spec/rspec/matchers/aliased_matcher_spec.rb +48 -0
  66. data/spec/rspec/matchers/aliases_spec.rb +449 -0
  67. data/spec/rspec/matchers/{base_matcher_spec.rb → built_in/base_matcher_spec.rb} +24 -3
  68. data/spec/rspec/matchers/built_in/be_between_spec.rb +159 -0
  69. data/spec/rspec/matchers/{be_instance_of_spec.rb → built_in/be_instance_of_spec.rb} +0 -0
  70. data/spec/rspec/matchers/{be_kind_of_spec.rb → built_in/be_kind_of_spec.rb} +0 -0
  71. data/spec/rspec/matchers/{be_spec.rb → built_in/be_spec.rb} +76 -32
  72. data/spec/rspec/matchers/{be_within_spec.rb → built_in/be_within_spec.rb} +6 -2
  73. data/spec/rspec/matchers/{change_spec.rb → built_in/change_spec.rb} +310 -69
  74. data/spec/rspec/matchers/built_in/compound_spec.rb +292 -0
  75. data/spec/rspec/matchers/built_in/contain_exactly_spec.rb +441 -0
  76. data/spec/rspec/matchers/{cover_spec.rb → built_in/cover_spec.rb} +0 -0
  77. data/spec/rspec/matchers/built_in/eq_spec.rb +156 -0
  78. data/spec/rspec/matchers/{eql_spec.rb → built_in/eql_spec.rb} +2 -2
  79. data/spec/rspec/matchers/built_in/equal_spec.rb +106 -0
  80. data/spec/rspec/matchers/{exist_spec.rb → built_in/exist_spec.rb} +1 -1
  81. data/spec/rspec/matchers/{has_spec.rb → built_in/has_spec.rb} +39 -0
  82. data/spec/rspec/matchers/{include_spec.rb → built_in/include_spec.rb} +118 -109
  83. data/spec/rspec/matchers/{match_spec.rb → built_in/match_spec.rb} +30 -2
  84. data/spec/rspec/matchers/{operator_matcher_spec.rb → built_in/operators_spec.rb} +26 -26
  85. data/spec/rspec/matchers/built_in/output_spec.rb +165 -0
  86. data/spec/rspec/matchers/{raise_error_spec.rb → built_in/raise_error_spec.rb} +81 -11
  87. data/spec/rspec/matchers/{respond_to_spec.rb → built_in/respond_to_spec.rb} +0 -0
  88. data/spec/rspec/matchers/{satisfy_spec.rb → built_in/satisfy_spec.rb} +0 -0
  89. data/spec/rspec/matchers/{start_with_end_with_spec.rb → built_in/start_and_end_with_spec.rb} +82 -15
  90. data/spec/rspec/matchers/{throw_symbol_spec.rb → built_in/throw_symbol_spec.rb} +29 -10
  91. data/spec/rspec/matchers/{yield_spec.rb → built_in/yield_spec.rb} +90 -0
  92. data/spec/rspec/matchers/configuration_spec.rb +7 -39
  93. data/spec/rspec/matchers/description_generation_spec.rb +22 -6
  94. data/spec/rspec/matchers/dsl_spec.rb +838 -0
  95. data/spec/rspec/matchers/legacy_spec.rb +101 -0
  96. data/spec/rspec/matchers_spec.rb +74 -0
  97. data/spec/spec_helper.rb +35 -21
  98. data/spec/support/shared_examples.rb +26 -4
  99. metadata +172 -116
  100. metadata.gz.sig +3 -4
  101. checksums.yaml +0 -15
  102. checksums.yaml.gz.sig +0 -0
  103. data/features/built_in_matchers/match_array.feature +0 -37
  104. data/lib/rspec/expectations/errors.rb +0 -9
  105. data/lib/rspec/expectations/extensions.rb +0 -1
  106. data/lib/rspec/expectations/extensions/object.rb +0 -29
  107. data/lib/rspec/matchers/built_in/match_array.rb +0 -51
  108. data/lib/rspec/matchers/compatibility.rb +0 -14
  109. data/lib/rspec/matchers/matcher.rb +0 -301
  110. data/lib/rspec/matchers/method_missing.rb +0 -12
  111. data/lib/rspec/matchers/operator_matcher.rb +0 -99
  112. data/lib/rspec/matchers/test_unit_integration.rb +0 -11
  113. data/spec/rspec/matchers/eq_spec.rb +0 -60
  114. data/spec/rspec/matchers/equal_spec.rb +0 -78
  115. data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
  116. data/spec/rspec/matchers/match_array_spec.rb +0 -194
  117. data/spec/rspec/matchers/matcher_spec.rb +0 -706
  118. data/spec/rspec/matchers/matchers_spec.rb +0 -36
  119. data/spec/rspec/matchers/method_missing_spec.rb +0 -28
  120. data/spec/support/classes.rb +0 -56
  121. data/spec/support/in_sub_process.rb +0 -37
  122. data/spec/support/ruby_version.rb +0 -10
@@ -28,7 +28,7 @@ describe "expect(...).to match(expected)" do
28
28
  it "provides message, expected and actual on failure" do
29
29
  matcher = match(/rings/)
30
30
  matcher.matches?("string")
31
- expect(matcher.failure_message_for_should).to eq "expected \"string\" to match /rings/"
31
+ expect(matcher.failure_message).to eq "expected \"string\" to match /rings/"
32
32
  end
33
33
 
34
34
  it "provides a diff on failure" do
@@ -43,6 +43,22 @@ describe "expect(...).to match(expected)" do
43
43
  expect { expect("foo").to match(/bar/) }.to fail_with(failure_message_that_includes_diff)
44
44
  end
45
45
 
46
+ context "when passed a data structure with matchers" do
47
+ it 'passes when the matchers match' do
48
+ expect(["food", 1.1]).to match([ a_string_matching(/foo/), a_value_within(0.2).of(1) ])
49
+ end
50
+
51
+ it 'fails when the matchers do not match' do
52
+ expect {
53
+ expect(["fod", 1.1]).to match([ a_string_matching(/foo/), a_value_within(0.2).of(1) ])
54
+ }.to fail_with('expected ["fod", 1.1] to match [(a string matching /foo/), (a value within 0.2 of 1)]')
55
+ end
56
+
57
+ it 'provides a description' do
58
+ description = match([ a_string_matching(/foo/), a_value_within(0.2).of(1) ]).description
59
+ expect(description).to eq("match [(a string matching /foo/), (a value within 0.2 of 1)]")
60
+ end
61
+ end
46
62
  end
47
63
 
48
64
  describe "expect(...).not_to match(expected)" do
@@ -69,6 +85,18 @@ describe "expect(...).not_to match(expected)" do
69
85
  it "provides message, expected and actual on failure" do
70
86
  matcher = match(/tri/)
71
87
  matcher.matches?("string")
72
- expect(matcher.failure_message_for_should_not).to eq "expected \"string\" not to match /tri/"
88
+ expect(matcher.failure_message_when_negated).to eq "expected \"string\" not to match /tri/"
89
+ end
90
+
91
+ context "when passed a data structure with matchers" do
92
+ it 'passes when the matchers match' do
93
+ expect(["food", 1.1]).not_to match([ a_string_matching(/fod/), a_value_within(0.2).of(1) ])
94
+ end
95
+
96
+ it 'fails when the matchers do not match' do
97
+ expect {
98
+ expect(["fod", 1.1]).not_to match([ a_string_matching(/fod/), a_value_within(0.2).of(1) ])
99
+ }.to fail_with('expected ["fod", 1.1] not to match [(a string matching /fod/), (a value within 0.2 of 1)]')
100
+ end
73
101
  end
74
102
  end
@@ -18,7 +18,7 @@ describe "operator matchers", :uses_should do
18
18
  describe "should ==" do
19
19
  it "delegates message to target" do
20
20
  subject = "apple"
21
- subject.should_receive(:==).with("apple").and_return(true)
21
+ expect(subject).to receive(:==).with("apple").and_return(true)
22
22
  subject.should == "apple"
23
23
  end
24
24
 
@@ -29,7 +29,7 @@ describe "operator matchers", :uses_should do
29
29
 
30
30
  it "fails when target.==(actual) returns false" do
31
31
  subject = "apple"
32
- RSpec::Expectations.should_receive(:fail_with).with(%[expected: "orange"\n got: "apple" (using ==)], "orange", "apple")
32
+ expect(RSpec::Expectations).to receive(:fail_with).with(%[expected: "orange"\n got: "apple" (using ==)], "orange", "apple")
33
33
  subject.should == "orange"
34
34
  end
35
35
 
@@ -78,7 +78,7 @@ describe "operator matchers", :uses_should do
78
78
  describe "should_not ==" do
79
79
  it "delegates message to target" do
80
80
  subject = "orange"
81
- subject.should_receive(:==).with("apple").and_return(false)
81
+ expect(subject).to receive(:==).with("apple").and_return(false)
82
82
  subject.should_not == "apple"
83
83
  end
84
84
 
@@ -89,7 +89,7 @@ describe "operator matchers", :uses_should do
89
89
 
90
90
  it "fails when target.==(actual) returns false" do
91
91
  subject = "apple"
92
- RSpec::Expectations.should_receive(:fail_with).with(%[expected not: == "apple"\n got: "apple"], "apple", "apple")
92
+ expect(RSpec::Expectations).to receive(:fail_with).with(%[expected not: == "apple"\n got: "apple"], "apple", "apple")
93
93
  subject.should_not == "apple"
94
94
  end
95
95
  end
@@ -97,14 +97,14 @@ describe "operator matchers", :uses_should do
97
97
  describe "should ===" do
98
98
  it "delegates message to target" do
99
99
  subject = "apple"
100
- subject.should_receive(:===).with("apple").and_return(true)
100
+ expect(subject).to receive(:===).with("apple").and_return(true)
101
101
  subject.should === "apple"
102
102
  end
103
103
 
104
104
  it "fails when target.===(actual) returns false" do
105
105
  subject = "apple"
106
- subject.should_receive(:===).with("orange").and_return(false)
107
- RSpec::Expectations.should_receive(:fail_with).with(%[expected: "orange"\n got: "apple" (using ===)], "orange", "apple")
106
+ expect(subject).to receive(:===).with("orange").and_return(false)
107
+ expect(RSpec::Expectations).to receive(:fail_with).with(%[expected: "orange"\n got: "apple" (using ===)], "orange", "apple")
108
108
  subject.should === "orange"
109
109
  end
110
110
  end
@@ -112,14 +112,14 @@ describe "operator matchers", :uses_should do
112
112
  describe "should_not ===" do
113
113
  it "delegates message to target" do
114
114
  subject = "orange"
115
- subject.should_receive(:===).with("apple").and_return(false)
115
+ expect(subject).to receive(:===).with("apple").and_return(false)
116
116
  subject.should_not === "apple"
117
117
  end
118
118
 
119
119
  it "fails when target.===(actual) returns false" do
120
120
  subject = "apple"
121
- subject.should_receive(:===).with("apple").and_return(true)
122
- RSpec::Expectations.should_receive(:fail_with).with(%[expected not: === "apple"\n got: "apple"], "apple", "apple")
121
+ expect(subject).to receive(:===).with("apple").and_return(true)
122
+ expect(RSpec::Expectations).to receive(:fail_with).with(%[expected not: === "apple"\n got: "apple"], "apple", "apple")
123
123
  subject.should_not === "apple"
124
124
  end
125
125
  end
@@ -127,14 +127,14 @@ describe "operator matchers", :uses_should do
127
127
  describe "should =~" do
128
128
  it "delegates message to target" do
129
129
  subject = "foo"
130
- subject.should_receive(:=~).with(/oo/).and_return(true)
130
+ expect(subject).to receive(:=~).with(/oo/).and_return(true)
131
131
  subject.should =~ /oo/
132
132
  end
133
133
 
134
134
  it "fails when target.=~(actual) returns false" do
135
135
  subject = "fu"
136
- subject.should_receive(:=~).with(/oo/).and_return(false)
137
- RSpec::Expectations.should_receive(:fail_with).with(%[expected: /oo/\n got: "fu" (using =~)], /oo/, "fu")
136
+ expect(subject).to receive(:=~).with(/oo/).and_return(false)
137
+ expect(RSpec::Expectations).to receive(:fail_with).with(%[expected: /oo/\n got: "fu" (using =~)], /oo/, "fu")
138
138
  subject.should =~ /oo/
139
139
  end
140
140
  end
@@ -142,14 +142,14 @@ describe "operator matchers", :uses_should do
142
142
  describe "should_not =~" do
143
143
  it "delegates message to target" do
144
144
  subject = "fu"
145
- subject.should_receive(:=~).with(/oo/).and_return(false)
145
+ expect(subject).to receive(:=~).with(/oo/).and_return(false)
146
146
  subject.should_not =~ /oo/
147
147
  end
148
148
 
149
149
  it "fails when target.=~(actual) returns false" do
150
150
  subject = "foo"
151
- subject.should_receive(:=~).with(/oo/).and_return(true)
152
- RSpec::Expectations.should_receive(:fail_with).with(%[expected not: =~ /oo/\n got: "foo"], /oo/, "foo")
151
+ expect(subject).to receive(:=~).with(/oo/).and_return(true)
152
+ expect(RSpec::Expectations).to receive(:fail_with).with(%[expected not: =~ /oo/\n got: "foo"], /oo/, "foo")
153
153
  subject.should_not =~ /oo/
154
154
  end
155
155
  end
@@ -160,7 +160,7 @@ describe "operator matchers", :uses_should do
160
160
  end
161
161
 
162
162
  it "fails if > fails" do
163
- RSpec::Expectations.should_receive(:fail_with).with(%[expected: > 5\n got: 4], 5, 4)
163
+ expect(RSpec::Expectations).to receive(:fail_with).with(%[expected: > 5\n got: 4], 5, 4)
164
164
  4.should > 5
165
165
  end
166
166
  end
@@ -175,7 +175,7 @@ describe "operator matchers", :uses_should do
175
175
  end
176
176
 
177
177
  it "fails if > fails" do
178
- RSpec::Expectations.should_receive(:fail_with).with(%[expected: >= 5\n got: 4], 5, 4)
178
+ expect(RSpec::Expectations).to receive(:fail_with).with(%[expected: >= 5\n got: 4], 5, 4)
179
179
  4.should >= 5
180
180
  end
181
181
  end
@@ -186,7 +186,7 @@ describe "operator matchers", :uses_should do
186
186
  end
187
187
 
188
188
  it "fails if > fails" do
189
- RSpec::Expectations.should_receive(:fail_with).with(%[expected: < 3\n got: 4], 3, 4)
189
+ expect(RSpec::Expectations).to receive(:fail_with).with(%[expected: < 3\n got: 4], 3, 4)
190
190
  4.should < 3
191
191
  end
192
192
  end
@@ -201,7 +201,7 @@ describe "operator matchers", :uses_should do
201
201
  end
202
202
 
203
203
  it "fails if > fails" do
204
- RSpec::Expectations.should_receive(:fail_with).with(%[expected: <= 3\n got: 4], 3, 4)
204
+ expect(RSpec::Expectations).to receive(:fail_with).with(%[expected: <= 3\n got: 4], 3, 4)
205
205
  4.should <= 3
206
206
  end
207
207
  end
@@ -211,21 +211,21 @@ describe "operator matchers", :uses_should do
211
211
  let(:custom_subklass) { Class.new(custom_klass) }
212
212
 
213
213
  after {
214
- RSpec::Matchers::OperatorMatcher.unregister(custom_klass, "=~")
214
+ RSpec::Matchers::BuiltIn::OperatorMatcher.unregister(custom_klass, "=~")
215
215
  }
216
216
 
217
217
  it "allows operator matchers to be registered for types" do
218
- RSpec::Matchers::OperatorMatcher.register(custom_klass, "=~", RSpec::Matchers::BuiltIn::Match)
219
- expect(RSpec::Matchers::OperatorMatcher.get(custom_klass, "=~")).to eq(RSpec::Matchers::BuiltIn::Match)
218
+ RSpec::Matchers::BuiltIn::OperatorMatcher.register(custom_klass, "=~", RSpec::Matchers::BuiltIn::Match)
219
+ expect(RSpec::Matchers::BuiltIn::OperatorMatcher.get(custom_klass, "=~")).to eq(RSpec::Matchers::BuiltIn::Match)
220
220
  end
221
221
 
222
222
  it "considers ancestors when finding an operator matcher" do
223
- RSpec::Matchers::OperatorMatcher.register(custom_klass, "=~", RSpec::Matchers::BuiltIn::Match)
224
- expect(RSpec::Matchers::OperatorMatcher.get(custom_subklass, "=~")).to eq(RSpec::Matchers::BuiltIn::Match)
223
+ RSpec::Matchers::BuiltIn::OperatorMatcher.register(custom_klass, "=~", RSpec::Matchers::BuiltIn::Match)
224
+ expect(RSpec::Matchers::BuiltIn::OperatorMatcher.get(custom_subklass, "=~")).to eq(RSpec::Matchers::BuiltIn::Match)
225
225
  end
226
226
 
227
227
  it "returns nil if there is no matcher registered for a type" do
228
- expect(RSpec::Matchers::OperatorMatcher.get(custom_klass, "=~")).to be_nil
228
+ expect(RSpec::Matchers::BuiltIn::OperatorMatcher.get(custom_klass, "=~")).to be_nil
229
229
  end
230
230
  end
231
231
 
@@ -0,0 +1,165 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "output_to_stream" do |stream_name|
4
+ matcher_method = :"to_#{stream_name}"
5
+
6
+ define_method :matcher do |*args|
7
+ output(args.first).send(matcher_method)
8
+ end
9
+
10
+ it 'is diffable' do
11
+ expect(matcher).to be_diffable
12
+ end
13
+
14
+ context "expect { ... }.to output.#{matcher_method}" do
15
+ it "passes if the block outputs to #{stream_name}" do
16
+ expect { stream.print 'foo' }.to matcher
17
+ end
18
+
19
+ it "fails if the block does not output to #{stream_name}" do
20
+ expect {
21
+ expect { }.to matcher
22
+ }.to fail_with("expected block to output to #{stream_name}, but did not")
23
+ end
24
+ end
25
+
26
+ context "expect { ... }.not_to output.#{matcher_method}" do
27
+ it "passes if the block does not output to #{stream_name}" do
28
+ expect { }.not_to matcher
29
+ end
30
+
31
+ it "fails if the block outputs to #{stream_name}" do
32
+ expect {
33
+ expect { stream.print 'foo' }.not_to matcher
34
+ }.to fail_with("expected block to not output to #{stream_name}, but did")
35
+ end
36
+ end
37
+
38
+ context "expect { ... }.to output('string').#{matcher_method}" do
39
+ it "passes if the block outputs that string to #{stream_name}" do
40
+ expect { stream.print 'foo' }.to matcher("foo")
41
+ end
42
+
43
+ it "fails if the block does not output to #{stream_name}" do
44
+ expect {
45
+ expect { }.to matcher('foo')
46
+ }.to fail_with("expected block to output \"foo\" to #{stream_name}, but output nothing")
47
+ end
48
+
49
+ it "fails if the block outputs a different string to #{stream_name}" do
50
+ expect {
51
+ expect { stream.print 'food' }.to matcher('foo')
52
+ }.to fail_with("expected block to output \"foo\" to #{stream_name}, but output \"food\"")
53
+ end
54
+ end
55
+
56
+ context "expect { ... }.to_not output('string').#{matcher_method}" do
57
+ it "passes if the block outputs a different string to #{stream_name}" do
58
+ expect { stream.print 'food' }.to_not matcher('foo')
59
+ end
60
+
61
+ it "passes if the block does not output to #{stream_name}" do
62
+ expect { }.to_not matcher('foo')
63
+ end
64
+
65
+ it "fails if the block outputs the same string to #{stream_name}" do
66
+ expect {
67
+ expect { stream.print 'foo' }.to_not matcher('foo')
68
+ }.to fail_with("expected block to not output \"foo\" to #{stream_name}, but did")
69
+ end
70
+ end
71
+
72
+ context "expect { ... }.to output(/regex/).#{matcher_method}" do
73
+ it "passes if the block outputs a string to #{stream_name} that matches the regex" do
74
+ expect { stream.print 'foo' }.to matcher(/foo/)
75
+ end
76
+
77
+ it "fails if the block does not output to #{stream_name}" do
78
+ expect {
79
+ expect { }.to matcher(/foo/)
80
+ }.to fail_matching("expected block to output /foo/ to #{stream_name}, but output nothing\nDiff")
81
+ end
82
+
83
+ it "fails if the block outputs a string to #{stream_name} that does not match" do
84
+ expect {
85
+ expect { stream.print 'foo' }.to matcher(/food/)
86
+ }.to fail_matching("expected block to output /food/ to #{stream_name}, but output \"foo\"\nDiff")
87
+ end
88
+ end
89
+
90
+ context "expect { ... }.to_not output(/regex/).#{matcher_method}" do
91
+ it "passes if the block outputs a string to #{stream_name} that does not match the regex" do
92
+ expect { stream.print 'food' }.to_not matcher(/bar/)
93
+ end
94
+
95
+ it "passes if the block does not output to #{stream_name}" do
96
+ expect { }.to_not matcher(/foo/)
97
+ end
98
+
99
+ it "fails if the block outputs a string to #{stream_name} that matches the regex" do
100
+ expect {
101
+ expect { stream.print 'foo' }.to_not matcher(/foo/)
102
+ }.to fail_matching("expected block to not output /foo/ to #{stream_name}, but did\nDiff")
103
+ end
104
+ end
105
+
106
+ context "expect { ... }.to output(matcher).#{matcher_method}" do
107
+ it "passes if the block outputs a string to #{stream_name} that passes the given matcher" do
108
+ expect { stream.print 'foo' }.to matcher(a_string_starting_with("f"))
109
+ end
110
+
111
+ it "fails if the block outputs a string to #{stream_name} that does not pass the given matcher" do
112
+ expect {
113
+ expect { stream.print 'foo' }.to matcher(a_string_starting_with("b"))
114
+ }.to fail_matching("expected block to output a string starting with \"b\" to #{stream_name}, but output \"foo\"\nDiff")
115
+ end
116
+ end
117
+
118
+ context "expect { ... }.to_not output(matcher).#{matcher_method}" do
119
+ it "passes if the block does not output a string to #{stream_name} that passes the given matcher" do
120
+ expect { stream.print 'foo' }.to_not matcher(a_string_starting_with("b"))
121
+ end
122
+
123
+ it "fails if the block outputs a string to #{stream_name} that passes the given matcher" do
124
+ expect {
125
+ expect { stream.print 'foo' }.to_not matcher(a_string_starting_with("f"))
126
+ }.to fail_matching("expected block to not output a string starting with \"f\" to #{stream_name}, but did\nDiff")
127
+ end
128
+ end
129
+ end
130
+
131
+ module RSpec
132
+ module Matchers
133
+ describe "output.to_stderr matcher" do
134
+ it_behaves_like("an RSpec matcher", :valid_value => lambda { warn('foo') }, :invalid_value => lambda {}) do
135
+ let(:matcher) { output.to_stderr }
136
+ end
137
+
138
+ include_examples "output_to_stream", :stderr do
139
+ let(:stream) { $stderr }
140
+ end
141
+ end
142
+
143
+ describe "output.to_stdout matcher" do
144
+ it_behaves_like("an RSpec matcher", :valid_value => lambda { print 'foo' }, :invalid_value => lambda {}) do
145
+ let(:matcher) { output.to_stdout }
146
+ end
147
+
148
+ include_examples "output_to_stream", :stdout do
149
+ let(:stream) { $stdout }
150
+ end
151
+ end
152
+
153
+ describe "output (without `to_stdout` or `to_stderr`)" do
154
+ it 'raises an error explaining the use is invalid' do
155
+ expect {
156
+ expect { stream.print 'foo' }.to output
157
+ }.to raise_error(/must chain.*to_stdout.*to_stderr/)
158
+ end
159
+
160
+ it 'still provides a description (e.g. when used in a one-liner)' do
161
+ expect(output("foo").description).to eq('output "foo" to some stream')
162
+ end
163
+ end
164
+ end
165
+ end
@@ -90,8 +90,7 @@ describe "expect { ... }.not_to raise_error" do
90
90
  it "is invalid" do
91
91
  expect {
92
92
  expect {"bees"}.not_to raise_error(RuntimeError)
93
- }.to raise_error(/`expect { }\.not_to raise_error\(SpecificErrorClass\)` is not valid/)
94
-
93
+ }.to raise_error(/`expect \{ \}\.not_to raise_error\(SpecificErrorClass\)` is not valid/)
95
94
  end
96
95
  end
97
96
 
@@ -116,8 +115,8 @@ describe "expect { ... }.not_to raise_error" do
116
115
  end
117
116
 
118
117
  it 'formats the backtrace using the configured backtrace formatter' do
119
- RSpec::Matchers.configuration.backtrace_formatter.
120
- stub(:format_backtrace).
118
+ allow(RSpec::Matchers.configuration.backtrace_formatter).
119
+ to receive(:format_backtrace).
121
120
  and_return("formatted-backtrace")
122
121
 
123
122
  expect {
@@ -168,7 +167,7 @@ describe "expect { ... }.to raise_error.with_message(message)" do
168
167
  it "raises an argument error if raise_error itself expects a message" do
169
168
  expect {
170
169
  expect { }.to raise_error("bees").with_message("sup")
171
- }.to raise_error.with_message(/`expect { }\.to raise_error\(message\)\.with_message\(message\)` is not valid/)
170
+ }.to raise_error.with_message(/`expect \{ \}\.to raise_error\(message\)\.with_message\(message\)` is not valid/)
172
171
  end
173
172
 
174
173
  it "passes if RuntimeError is raised with the right message" do
@@ -200,7 +199,7 @@ describe "expect { ... }.not_to raise_error(message)" do
200
199
  it "is invalid" do
201
200
  expect {
202
201
  expect {raise 'blarg'}.not_to raise_error(/blah/)
203
- }.to raise_error(/`expect { }\.not_to raise_error\(message\)` is not valid/)
202
+ }.to raise_error(/`expect \{ \}\.not_to raise_error\(message\)` is not valid/)
204
203
  end
205
204
  end
206
205
 
@@ -232,7 +231,7 @@ describe "expect { ... }.not_to raise_error(NamedError)" do
232
231
  it "is invalid" do
233
232
  expect {
234
233
  expect { }.not_to raise_error(NameError)
235
- }.to raise_error(/`expect { }\.not_to raise_error\(SpecificErrorClass\)` is not valid/)
234
+ }.to raise_error(/`expect \{ \}\.not_to raise_error\(SpecificErrorClass\)` is not valid/)
236
235
  end
237
236
  end
238
237
 
@@ -264,7 +263,7 @@ describe "expect { ... }.not_to raise_error(NamedError, error_message) with Stri
264
263
  it "is invalid" do
265
264
  expect {
266
265
  expect {}.not_to raise_error(RuntimeError, "example message")
267
- }.to raise_error(/`expect { }\.not_to raise_error\(SpecificErrorClass, message\)` is not valid/)
266
+ }.to raise_error(/`expect \{ \}\.not_to raise_error\(SpecificErrorClass, message\)` is not valid/)
268
267
  end
269
268
  end
270
269
 
@@ -296,7 +295,7 @@ describe "expect { ... }.not_to raise_error(NamedError, error_message) with Rege
296
295
  it "is invalid" do
297
296
  expect {
298
297
  expect {}.not_to raise_error(RuntimeError, /ample mess/)
299
- }.to raise_error(/`expect { }\.not_to raise_error\(SpecificErrorClass, message\)` is not valid/)
298
+ }.to raise_error(/`expect \{ \}\.not_to raise_error\(SpecificErrorClass, message\)` is not valid/)
300
299
  end
301
300
  end
302
301
 
@@ -377,15 +376,86 @@ describe "expect { ... }.not_to raise_error(NamedError, error_message) { |err| .
377
376
  it "is invalid" do
378
377
  expect {
379
378
  expect {}.not_to raise_error(RuntimeError, "example message") { |err| }
380
- }.to raise_error(/`expect { }\.not_to raise_error\(SpecificErrorClass, message\)` is not valid/)
379
+ }.to raise_error(/`expect \{ \}\.not_to raise_error\(SpecificErrorClass, message\)` is not valid/)
381
380
  end
382
381
  end
383
382
 
384
383
  describe "misuse of raise_error, with (), not {}" do
385
384
  it "fails with warning" do
386
- ::Kernel.should_receive(:warn).with(/`raise_error` was called with non-proc object 1\.7/)
385
+ expect(::Kernel).to receive(:warn).with(/`raise_error` was called with non-proc object 1\.7/)
387
386
  expect {
388
387
  expect(Math.sqrt(3)).to raise_error
389
388
  }.to fail_with(/nothing was raised/)
390
389
  end
391
390
  end
391
+
392
+ describe "Composing matchers with `raise_error`" do
393
+ matcher :an_error_with_attribute do |attr|
394
+ chain :equal_to do |value|
395
+ @expected_value = value
396
+ end
397
+
398
+ match do |error|
399
+ error.__send__(attr) == @expected_value
400
+ end
401
+
402
+ description do
403
+ super() + " equal to #{@expected_value}"
404
+ end
405
+ end
406
+
407
+ class FooError < StandardError
408
+ def foo; :bar; end
409
+ end
410
+
411
+ describe "expect { }.to raise_error(matcher)" do
412
+ it 'passes when the matcher matches the raised error' do
413
+ expect { raise FooError }.to raise_error(an_error_with_attribute(:foo).equal_to(:bar))
414
+ end
415
+
416
+ it 'fails with a clear message when the matcher does not match the raised error' do
417
+ expect {
418
+ expect { raise FooError }.to raise_error(an_error_with_attribute(:foo).equal_to(3))
419
+ }.to fail_matching("expected an error with attribute :foo equal to 3, got #<FooError: FooError>")
420
+ end
421
+
422
+ it 'provides a description' do
423
+ description = raise_error(an_error_with_attribute(:foo).equal_to(3)).description
424
+ expect(description).to eq("raise an error with attribute :foo equal to 3")
425
+ end
426
+ end
427
+
428
+ describe "expect { }.to raise_error(ErrorClass, matcher)" do
429
+ it 'passes when the class and matcher match the raised error' do
430
+ expect { raise FooError, "food" }.to raise_error(FooError, a_string_including("foo"))
431
+ end
432
+
433
+ it 'fails with a clear message when the matcher does not match the raised error' do
434
+ expect {
435
+ expect { raise FooError, "food" }.to raise_error(FooError, a_string_including("bar"))
436
+ }.to fail_matching('expected FooError with a string including "bar", got #<FooError: food')
437
+ end
438
+
439
+ it 'provides a description' do
440
+ description = raise_error(FooError, a_string_including("foo")).description
441
+ expect(description).to eq('raise FooError with a string including "foo"')
442
+ end
443
+ end
444
+
445
+ describe "expect { }.to raise_error(ErrorClass).with_message(matcher)" do
446
+ it 'passes when the class and matcher match the raised error' do
447
+ expect { raise FooError, "food" }.to raise_error(FooError).with_message(a_string_including("foo"))
448
+ end
449
+
450
+ it 'fails with a clear message when the matcher does not match the raised error' do
451
+ expect {
452
+ expect { raise FooError, "food" }.to raise_error(FooError).with_message(a_string_including("bar"))
453
+ }.to fail_matching('expected FooError with a string including "bar", got #<FooError: food')
454
+ end
455
+
456
+ it 'provides a description' do
457
+ description = raise_error(FooError).with_message(a_string_including("foo")).description
458
+ expect(description).to eq('raise FooError with a string including "foo"')
459
+ end
460
+ end
461
+ end