rspec-expectations 3.0.0.beta2 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -2
  4. data/.yardopts +0 -1
  5. data/Changelog.md +115 -35
  6. data/README.md +2 -2
  7. data/lib/rspec/expectations.rb +13 -8
  8. data/lib/rspec/{matchers → expectations}/configuration.rb +38 -13
  9. data/lib/rspec/expectations/expectation_target.rb +72 -8
  10. data/lib/rspec/expectations/fail_with.rb +10 -52
  11. data/lib/rspec/expectations/handler.rb +9 -11
  12. data/lib/rspec/expectations/syntax.rb +37 -35
  13. data/lib/rspec/expectations/version.rb +1 -1
  14. data/lib/rspec/matchers.rb +60 -9
  15. data/lib/rspec/matchers/aliased_matcher.rb +6 -0
  16. data/lib/rspec/matchers/built_in.rb +9 -1
  17. data/lib/rspec/matchers/built_in/all.rb +78 -0
  18. data/lib/rspec/matchers/built_in/base_matcher.rb +39 -1
  19. data/lib/rspec/matchers/built_in/be.rb +117 -42
  20. data/lib/rspec/matchers/built_in/be_between.rb +22 -0
  21. data/lib/rspec/matchers/built_in/be_instance_of.rb +11 -3
  22. data/lib/rspec/matchers/built_in/be_kind_of.rb +5 -0
  23. data/lib/rspec/matchers/built_in/be_within.rb +26 -6
  24. data/lib/rspec/matchers/built_in/change.rb +89 -13
  25. data/lib/rspec/matchers/built_in/compound.rb +19 -3
  26. data/lib/rspec/matchers/built_in/contain_exactly.rb +17 -6
  27. data/lib/rspec/matchers/built_in/cover.rb +3 -0
  28. data/lib/rspec/matchers/built_in/eq.rb +20 -5
  29. data/lib/rspec/matchers/built_in/eql.rb +15 -3
  30. data/lib/rspec/matchers/built_in/equal.rb +23 -6
  31. data/lib/rspec/matchers/built_in/exist.rb +74 -10
  32. data/lib/rspec/matchers/built_in/has.rb +58 -3
  33. data/lib/rspec/matchers/built_in/include.rb +16 -1
  34. data/lib/rspec/matchers/built_in/match.rb +14 -4
  35. data/lib/rspec/matchers/built_in/operators.rb +16 -0
  36. data/lib/rspec/matchers/built_in/output.rb +47 -5
  37. data/lib/rspec/matchers/built_in/raise_error.rb +40 -23
  38. data/lib/rspec/matchers/built_in/respond_to.rb +37 -16
  39. data/lib/rspec/matchers/built_in/satisfy.rb +15 -0
  40. data/lib/rspec/matchers/built_in/start_and_end_with.rb +29 -14
  41. data/lib/rspec/matchers/built_in/throw_symbol.rb +32 -3
  42. data/lib/rspec/matchers/built_in/yield.rb +148 -44
  43. data/lib/rspec/matchers/composable.rb +48 -7
  44. data/lib/rspec/matchers/dsl.rb +45 -17
  45. data/lib/rspec/matchers/generated_descriptions.rb +7 -0
  46. data/lib/rspec/matchers/matcher_delegator.rb +6 -2
  47. data/lib/rspec/matchers/pretty.rb +15 -19
  48. metadata +33 -236
  49. metadata.gz.sig +0 -0
  50. data/features/README.md +0 -48
  51. data/features/Upgrade.md +0 -53
  52. data/features/built_in_matchers/README.md +0 -96
  53. data/features/built_in_matchers/be.feature +0 -175
  54. data/features/built_in_matchers/be_within.feature +0 -48
  55. data/features/built_in_matchers/comparisons.feature +0 -97
  56. data/features/built_in_matchers/contain_exactly.feature +0 -46
  57. data/features/built_in_matchers/cover.feature +0 -47
  58. data/features/built_in_matchers/end_with.feature +0 -48
  59. data/features/built_in_matchers/equality.feature +0 -136
  60. data/features/built_in_matchers/exist.feature +0 -45
  61. data/features/built_in_matchers/expect_change.feature +0 -59
  62. data/features/built_in_matchers/expect_error.feature +0 -144
  63. data/features/built_in_matchers/include.feature +0 -126
  64. data/features/built_in_matchers/match.feature +0 -51
  65. data/features/built_in_matchers/output.feature +0 -70
  66. data/features/built_in_matchers/predicates.feature +0 -161
  67. data/features/built_in_matchers/respond_to.feature +0 -84
  68. data/features/built_in_matchers/satisfy.feature +0 -33
  69. data/features/built_in_matchers/start_with.feature +0 -48
  70. data/features/built_in_matchers/throw_symbol.feature +0 -91
  71. data/features/built_in_matchers/types.feature +0 -116
  72. data/features/built_in_matchers/yield.feature +0 -161
  73. data/features/composing_matchers.feature +0 -250
  74. data/features/compound_expectations.feature +0 -45
  75. data/features/custom_matchers/access_running_example.feature +0 -53
  76. data/features/custom_matchers/define_diffable_matcher.feature +0 -27
  77. data/features/custom_matchers/define_matcher.feature +0 -340
  78. data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -34
  79. data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
  80. data/features/customized_message.feature +0 -39
  81. data/features/diffing.feature +0 -85
  82. data/features/implicit_docstrings.feature +0 -52
  83. data/features/step_definitions/additional_cli_steps.rb +0 -22
  84. data/features/support/env.rb +0 -21
  85. data/features/support/rubinius.rb +0 -6
  86. data/features/syntax_configuration.feature +0 -71
  87. data/features/test_frameworks/minitest.feature +0 -44
  88. data/lib/rspec-expectations.rb +0 -1
  89. data/lib/rspec/expectations/diff_presenter.rb +0 -141
  90. data/lib/rspec/expectations/differ.rb +0 -44
  91. data/lib/rspec/expectations/encoded_string.rb +0 -56
  92. data/spec/rspec/expectations/diff_presenter_spec.rb +0 -249
  93. data/spec/rspec/expectations/encoded_string_spec.rb +0 -74
  94. data/spec/rspec/expectations/expectation_target_spec.rb +0 -82
  95. data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
  96. data/spec/rspec/expectations/fail_with_spec.rb +0 -114
  97. data/spec/rspec/expectations/handler_spec.rb +0 -205
  98. data/spec/rspec/expectations/minitest_integration_spec.rb +0 -27
  99. data/spec/rspec/expectations/syntax_spec.rb +0 -89
  100. data/spec/rspec/expectations_spec.rb +0 -12
  101. data/spec/rspec/matchers/aliased_matcher_spec.rb +0 -48
  102. data/spec/rspec/matchers/aliases_spec.rb +0 -449
  103. data/spec/rspec/matchers/built_in/base_matcher_spec.rb +0 -83
  104. data/spec/rspec/matchers/built_in/be_between_spec.rb +0 -159
  105. data/spec/rspec/matchers/built_in/be_instance_of_spec.rb +0 -63
  106. data/spec/rspec/matchers/built_in/be_kind_of_spec.rb +0 -41
  107. data/spec/rspec/matchers/built_in/be_spec.rb +0 -592
  108. data/spec/rspec/matchers/built_in/be_within_spec.rb +0 -141
  109. data/spec/rspec/matchers/built_in/change_spec.rb +0 -808
  110. data/spec/rspec/matchers/built_in/compound_spec.rb +0 -292
  111. data/spec/rspec/matchers/built_in/contain_exactly_spec.rb +0 -441
  112. data/spec/rspec/matchers/built_in/cover_spec.rb +0 -69
  113. data/spec/rspec/matchers/built_in/eq_spec.rb +0 -156
  114. data/spec/rspec/matchers/built_in/eql_spec.rb +0 -41
  115. data/spec/rspec/matchers/built_in/equal_spec.rb +0 -106
  116. data/spec/rspec/matchers/built_in/exist_spec.rb +0 -124
  117. data/spec/rspec/matchers/built_in/has_spec.rb +0 -161
  118. data/spec/rspec/matchers/built_in/include_spec.rb +0 -540
  119. data/spec/rspec/matchers/built_in/match_spec.rb +0 -102
  120. data/spec/rspec/matchers/built_in/operators_spec.rb +0 -252
  121. data/spec/rspec/matchers/built_in/output_spec.rb +0 -165
  122. data/spec/rspec/matchers/built_in/raise_error_spec.rb +0 -461
  123. data/spec/rspec/matchers/built_in/respond_to_spec.rb +0 -292
  124. data/spec/rspec/matchers/built_in/satisfy_spec.rb +0 -44
  125. data/spec/rspec/matchers/built_in/start_and_end_with_spec.rb +0 -253
  126. data/spec/rspec/matchers/built_in/throw_symbol_spec.rb +0 -135
  127. data/spec/rspec/matchers/built_in/yield_spec.rb +0 -627
  128. data/spec/rspec/matchers/configuration_spec.rb +0 -213
  129. data/spec/rspec/matchers/description_generation_spec.rb +0 -191
  130. data/spec/rspec/matchers/dsl_spec.rb +0 -895
  131. data/spec/rspec/matchers/legacy_spec.rb +0 -101
  132. data/spec/rspec/matchers_spec.rb +0 -74
  133. data/spec/spec_helper.rb +0 -85
  134. data/spec/support/matchers.rb +0 -22
  135. data/spec/support/shared_examples.rb +0 -35
@@ -1,292 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module RSpec::Matchers::BuiltIn
4
- describe Compound do
5
- context "when used as a composable matcher" do
6
- it 'can pass' do
7
- expect(["food", "barn"]).to include(
8
- a_string_starting_with("f").and(ending_with("d")),
9
- a_string_starting_with("b").and(ending_with("n"))
10
- )
11
- end
12
-
13
- it 'can fail' do
14
- expect {
15
- expect(["foo", "bar"]).to include(
16
- a_string_starting_with("f").and(ending_with("d")),
17
- a_string_starting_with("b").and(ending_with("n"))
18
- )
19
- }.to fail_matching('expected ["foo", "bar"] to include (a string starting with "f" and ending with "d") and (a string starting with "b" and ending with "n")')
20
- end
21
-
22
- it 'provides a description' do
23
- matcher = include(
24
- a_string_starting_with("f").and(ending_with("d")),
25
- a_string_starting_with("b").and(ending_with("n"))
26
- )
27
-
28
- expect(matcher.description).to eq('include (a string starting with "f" and ending with "d") and (a string starting with "b" and ending with "n")')
29
- end
30
- end
31
-
32
- describe "expect(...).to matcher.and(other_matcher)" do
33
-
34
- it_behaves_like "an RSpec matcher", :valid_value => 3, :invalid_value => 4 do
35
- let(:matcher) { eq(3).and be <= 3 }
36
- end
37
-
38
- context 'when both matchers pass' do
39
- it 'passes' do
40
- expect(3).to eq(3).and be >= 2
41
- end
42
- end
43
-
44
- it 'has a description composed of both matcher descriptions' do
45
- matcher = eq(3).and be >= 2
46
- expect(3).to matcher
47
- expect(matcher.description).to eq("eq 3 and be >= 2")
48
- end
49
-
50
- context 'when only the first matcher fails' do
51
- it "fails with the first matcher's failure message" do
52
- expect {
53
- expect(3).to eq(4).and be >= 2
54
- }.to fail_with(dedent <<-EOS)
55
- |
56
- |expected: 4
57
- | got: 3
58
- |
59
- |(compared using ==)
60
- |
61
- EOS
62
- end
63
- end
64
-
65
- context 'when only the second matcher fails' do
66
- it "fails with the second matcher's failure message" do
67
- expect {
68
- expect(3).to be_kind_of(Integer).and eq(4)
69
- }.to fail_with(dedent <<-EOS)
70
- |
71
- |expected: 4
72
- | got: 3
73
- |
74
- |(compared using ==)
75
- |
76
- EOS
77
- end
78
- end
79
-
80
- context "when both mathers fail" do
81
- context "when both matchers have multi-line failure messages" do
82
- it 'fails with a well formatted message containing both sub-messages' do
83
- expect {
84
- expect(3).to eq(4).and be >= 8
85
- }.to fail_with(dedent <<-EOS)
86
- |
87
- | expected: 4
88
- | got: 3
89
- |
90
- | (compared using ==)
91
- |
92
- |...and:
93
- |
94
- | expected: >= 8
95
- | got: 3
96
- EOS
97
- end
98
- end
99
-
100
- context "when both matchers have single-line failure messages" do
101
- it 'fails with a single-line failure message' do
102
- expect {
103
- expect("foo").to start_with("a").and end_with("z")
104
- }.to fail_with('expected "foo" to start with "a" and expected "foo" to end with "z"')
105
- end
106
- end
107
-
108
- context "when the first matcher has a multi-line failure message" do
109
- it 'fails with a well formatted message containing both sub-messages' do
110
- expect {
111
- expect("foo").to eq(4).and end_with("z")
112
- }.to fail_with(dedent <<-EOS)
113
- |
114
- | expected: 4
115
- | got: "foo"
116
- |
117
- | (compared using ==)
118
- |
119
- |...and:
120
- |
121
- | expected "foo" to end with "z"
122
- EOS
123
- end
124
- end
125
-
126
- context "when the second matcher has a multi-line failure message" do
127
- it 'fails with a well formatted message containing both sub-messages' do
128
- expect {
129
- expect("foo").to end_with("z").and eq(4)
130
- }.to fail_with(dedent <<-EOS)
131
- | expected "foo" to end with "z"
132
- |
133
- |...and:
134
- |
135
- | expected: 4
136
- | got: "foo"
137
- |
138
- | (compared using ==)
139
- |
140
- EOS
141
- end
142
- end
143
- end
144
- end
145
-
146
- describe "expect(...).not_to matcher.and(other_matcher)" do
147
- it "is not supported" do
148
- expect {
149
- expect(3).not_to eq(2).and be > 2
150
- }.to raise_error(NotImplementedError, /matcher.and matcher` is not supported/)
151
- end
152
- end
153
-
154
- describe "expect(...).to matcher.or(other_matcher)" do
155
- it_behaves_like "an RSpec matcher", :valid_value => 3, :invalid_value => 5 do
156
- let(:matcher) { eq(3).or eq(4) }
157
- end
158
-
159
- it 'has a description composed of both matcher descriptions' do
160
- matcher = eq(3).or eq(4)
161
- expect(3).to matcher
162
- expect(matcher.description).to eq("eq 3 or eq 4")
163
- end
164
-
165
- context 'when both matchers pass' do
166
- it 'passes' do
167
- expect("foo").to start_with("f").or end_with("o")
168
- end
169
- end
170
-
171
- context 'when only the first matcher passes' do
172
- it 'passes' do
173
- expect("foo").to start_with("f").or end_with("z")
174
- end
175
- end
176
-
177
- context 'when only the last matcher passes' do
178
- it 'passes' do
179
- expect("foo").to start_with("a").or end_with("o")
180
- end
181
- end
182
-
183
- context 'when both matchers fail' do
184
- context "when both matchers have multi-line failure messages" do
185
- it 'fails with a well formatted message containing both sub-messages' do
186
- expect {
187
- expect(3).to eq(4).or be >= 8
188
- }.to fail_with(dedent <<-EOS)
189
- |
190
- | expected: 4
191
- | got: 3
192
- |
193
- | (compared using ==)
194
- |
195
- |...or:
196
- |
197
- | expected: >= 8
198
- | got: 3
199
- EOS
200
- end
201
- end
202
-
203
- context "when both matchers have single-line failure messages" do
204
- it 'fails with a single-line failure message' do
205
- expect {
206
- expect("foo").to start_with("a").or end_with("z")
207
- }.to fail_with('expected "foo" to start with "a" or expected "foo" to end with "z"')
208
- end
209
- end
210
-
211
- context "when the first matcher has a multi-line failure message" do
212
- it 'fails with a well formatted message containing both sub-messages' do
213
- expect {
214
- expect("foo").to eq(4).or end_with("z")
215
- }.to fail_with(dedent <<-EOS)
216
- |
217
- | expected: 4
218
- | got: "foo"
219
- |
220
- | (compared using ==)
221
- |
222
- |...or:
223
- |
224
- | expected "foo" to end with "z"
225
- EOS
226
- end
227
- end
228
-
229
- context "when the second matcher has a multi-line failure message" do
230
- it 'fails with a well formatted message containing both sub-messages' do
231
- expect {
232
- expect("foo").to end_with("z").or eq(4)
233
- }.to fail_with(dedent <<-EOS)
234
- | expected "foo" to end with "z"
235
- |
236
- |...or:
237
- |
238
- | expected: 4
239
- | got: "foo"
240
- |
241
- | (compared using ==)
242
- |
243
- EOS
244
- end
245
- end
246
- end
247
- end
248
-
249
- context "when chaining many matchers together" do
250
- it 'can pass appropriately' do
251
- matcher = start_with("f").and end_with("z").or end_with("o")
252
- expect("foo").to matcher
253
- expect(matcher.description).to eq('start with "f" and end with "z" or end with "o"')
254
- end
255
-
256
- it 'fails with a complete message' do
257
- expect {
258
- expect(3).to eq(1).and eq(2).and eq(3).and eq(4)
259
- }.to fail_with(dedent <<-EOS)
260
- |
261
- | expected: 1
262
- | got: 3
263
- |
264
- | (compared using ==)
265
- |
266
- |...and:
267
- |
268
- | expected: 2
269
- | got: 3
270
- |
271
- | (compared using ==)
272
- |
273
- | ...and:
274
- |
275
- | expected: 4
276
- | got: 3
277
- |
278
- | (compared using ==)
279
- |
280
- EOS
281
- end
282
- end
283
-
284
- describe "expect(...).not_to matcher.or(other_matcher)" do
285
- it "is not supported" do
286
- expect {
287
- expect(3).not_to eq(2).or be > 2
288
- }.to raise_error(NotImplementedError, /matcher.or matcher` is not supported/)
289
- end
290
- end
291
- end
292
- end
@@ -1,441 +0,0 @@
1
- require 'spec_helper'
2
- require 'timeout'
3
-
4
- class UnsortableObject
5
- def initialize(id)
6
- @id = id
7
- end
8
-
9
- def inspect
10
- @id.to_s
11
- end
12
-
13
- def ==(other)
14
- false
15
- end
16
- end
17
-
18
- # AR::Relation is meant to act like a collection, but does
19
- # not include `Enumerable`. It does implement `to_ary`.
20
- class FakeActiveRecordRelation
21
- def initialize(records)
22
- @records = records
23
- end
24
-
25
- def to_ary
26
- @records
27
- end
28
- end
29
-
30
- describe "should =~ array", :uses_should do
31
- it "passes a valid positive expectation" do
32
- [1, 2].should =~ [2, 1]
33
- end
34
-
35
- it "fails an invalid positive expectation" do
36
- expect {
37
- [1, 2, 3].should =~ [2, 1]
38
- }.to fail_with(/expected collection contained/)
39
- end
40
-
41
- context "when the array defines a `=~` method" do
42
- it 'delegates to that method rather than using the contain_exactly matcher' do
43
- array = []
44
- def array.=~(other)
45
- other == :foo
46
- end
47
-
48
- array.should =~ :foo
49
- expect {
50
- array.should =~ :bar
51
- }.to fail_with(/expected: :bar/)
52
- end
53
- end
54
-
55
- context 'when the array defines a `send` method' do
56
- it 'still works' do
57
- array = [1, 2]
58
- def array.send; :sent; end
59
-
60
- array.should =~ array
61
- end
62
- end
63
- end
64
-
65
- describe "should_not =~ [:with, :multiple, :args]", :uses_should do
66
- it "is not supported" do
67
- expect {
68
- [1,2,3].should_not =~ [1,2,3]
69
- }.to fail_with(/`contain_exactly` does not support negation/)
70
- end
71
- end
72
-
73
- describe "using contain_exactly with expect" do
74
- it "passes a valid positive expectation" do
75
- expect([1, 2]).to contain_exactly(2, 1)
76
- end
77
-
78
- it "fails an invalid positive expectation" do
79
- expect {
80
- expect([1, 2, 3]).to contain_exactly(2, 1)
81
- }.to fail_with(/expected collection contained/)
82
- end
83
- end
84
-
85
- describe "expect(array).to contain_exactly(*other_array)" do
86
- it_behaves_like "an RSpec matcher", :valid_value => [1, 2], :invalid_value => [1] do
87
- let(:matcher) { contain_exactly(2, 1) }
88
- end
89
-
90
- it 'is also exposed as `match_array` (with unsplatted args)' do
91
- expect([1, 2, 3]).to match_array([3, 2, 1])
92
- end
93
-
94
- it "passes if target contains all items" do
95
- expect([1,2,3]).to contain_exactly(1,2,3)
96
- end
97
-
98
- it "passes if target contains all items out of order" do
99
- expect([1,3,2]).to contain_exactly(1,2,3)
100
- end
101
-
102
- def timeout_if_not_debugging(time)
103
- return yield if defined?(::Debugger)
104
- Timeout.timeout(time) { yield }
105
- end
106
-
107
- it 'fails a match of 11 items with duplicates in a reasonable amount of time' do
108
- timeout_if_not_debugging(0.1) do
109
- expected = [0, 1, 1, 3, 3, 3, 4, 4, 8, 8, 9 ]
110
- actual = [ 1, 2, 3, 3, 3, 3, 7, 8, 8, 9, 9]
111
-
112
- expect {
113
- expect(actual).to contain_exactly(*expected)
114
- }.to fail_matching("the missing elements were: [0, 1, 4, 4]")
115
- end
116
- end
117
-
118
- it "fails if target includes extra items" do
119
- expect {
120
- expect([1,2,3,4]).to contain_exactly(1,2,3)
121
- }.to fail_with(<<-MESSAGE)
122
- expected collection contained: [1, 2, 3]
123
- actual collection contained: [1, 2, 3, 4]
124
- the extra elements were: [4]
125
- MESSAGE
126
- end
127
-
128
- it "fails if target is missing items" do
129
- expect {
130
- expect([1,2]).to contain_exactly(1,2,3)
131
- }.to fail_with(<<-MESSAGE)
132
- expected collection contained: [1, 2, 3]
133
- actual collection contained: [1, 2]
134
- the missing elements were: [3]
135
- MESSAGE
136
- end
137
-
138
- it "fails if target is missing items and has extra items" do
139
- expect {
140
- expect([1,2,4]).to contain_exactly(1,2,3)
141
- }.to fail_with(<<-MESSAGE)
142
- expected collection contained: [1, 2, 3]
143
- actual collection contained: [1, 2, 4]
144
- the missing elements were: [3]
145
- the extra elements were: [4]
146
- MESSAGE
147
- end
148
-
149
- it "sorts items in the error message if they all respond to <=>" do
150
- expect {
151
- expect([6,2,1,5]).to contain_exactly(4,1,2,3)
152
- }.to fail_with(<<-MESSAGE)
153
- expected collection contained: [1, 2, 3, 4]
154
- actual collection contained: [1, 2, 5, 6]
155
- the missing elements were: [3, 4]
156
- the extra elements were: [5, 6]
157
- MESSAGE
158
- end
159
-
160
- it "does not sort items in the error message if they don't all respond to <=>" do
161
- expect {
162
- expect([UnsortableObject.new(2), UnsortableObject.new(1)]).to contain_exactly(UnsortableObject.new(4), UnsortableObject.new(3))
163
- }.to fail_with(<<-MESSAGE)
164
- expected collection contained: [4, 3]
165
- actual collection contained: [2, 1]
166
- the missing elements were: [4, 3]
167
- the extra elements were: [2, 1]
168
- MESSAGE
169
- end
170
-
171
- it "accurately reports extra elements when there are duplicates" do
172
- expect {
173
- expect([1,1,1,5]).to contain_exactly(1,5)
174
- }.to fail_with(<<-MESSAGE)
175
- expected collection contained: [1, 5]
176
- actual collection contained: [1, 1, 1, 5]
177
- the extra elements were: [1, 1]
178
- MESSAGE
179
- end
180
-
181
- it "accurately reports missing elements when there are duplicates" do
182
- expect {
183
- expect([1,5]).to contain_exactly(1,1,5)
184
- }.to fail_with(<<-MESSAGE)
185
- expected collection contained: [1, 1, 5]
186
- actual collection contained: [1, 5]
187
- the missing elements were: [1]
188
- MESSAGE
189
- end
190
- end
191
-
192
- describe "expect(...).not_to contain_exactly(:with, :multiple, :args]" do
193
- it "is not supported" do
194
- expect {
195
- expect([1,2,3]).not_to contain_exactly(1,2,3)
196
- }.to fail_with(/`contain_exactly` does not support negation/)
197
- end
198
- end
199
-
200
- describe "matching against things that aren't arrays" do
201
- it "fails with nil and the expected error message is given" do
202
- expect {
203
- expect(nil).to contain_exactly(1, 2, 3)
204
- }.to fail_with(/expected a collection/)
205
- end
206
-
207
- it "fails with a float and the expected error message is given" do
208
- expect {
209
- expect(3.7).to contain_exactly(1, 2, 3)
210
- }.to fail_with(/expected a collection/)
211
- end
212
-
213
- it "fails with a string and the expected error message is given" do
214
- expect {
215
- expect("I like turtles").to contain_exactly(1, 2, 3)
216
- }.to fail_with(/expected a collection/)
217
- end
218
-
219
- it 'works with other collection types' do
220
- expect(Set.new([3, 2, 1])).to contain_exactly(1, 2, 3)
221
- expect {
222
- expect(Set.new([3, 2, 1])).to contain_exactly(1, 2)
223
- }.to fail_matching("expected collection contained: [1, 2]")
224
- end
225
-
226
- it 'works with non-enumerables that implement `to_ary`' do
227
- relation = FakeActiveRecordRelation.new([1, 2, 3])
228
- expect(relation).to contain_exactly(2, 1, 3)
229
- expect {
230
- expect(relation).to contain_exactly(1, 2)
231
- }.to fail_matching("expected collection contained: [1, 2]")
232
- end
233
- end
234
-
235
- describe "Composing `contain_exactly` with other matchers" do
236
- describe "expect(...).to contain_exactly(matcher, matcher])" do
237
- it 'passes when the array matches the matchers in the same order' do
238
- expect(["food", "barn"]).to contain_exactly(
239
- a_string_matching(/foo/),
240
- a_string_matching(/bar/)
241
- )
242
- end
243
-
244
- it 'passes when the array matches the matchers in a different order' do
245
- expect(["food", "barn"]).to contain_exactly(
246
- a_string_matching(/bar/),
247
- a_string_matching(/foo/)
248
- )
249
- end
250
-
251
- it 'fails with a useful message when there is an extra element' do
252
- expect {
253
- expect(["food", "barn", "goo"]).to contain_exactly(
254
- a_string_matching(/bar/),
255
- a_string_matching(/foo/)
256
- )
257
- }.to fail_with(dedent <<-EOS)
258
- |expected collection contained: [(a string matching /bar/), (a string matching /foo/)]
259
- |actual collection contained: ["barn", "food", "goo"]
260
- |the extra elements were: ["goo"]
261
- |
262
- EOS
263
- end
264
-
265
- it 'fails with a useful message when there is a missing element' do
266
- expect {
267
- expect(["food", "barn"]).to contain_exactly(
268
- a_string_matching(/bar/),
269
- a_string_matching(/foo/),
270
- a_string_matching(/goo/)
271
- )
272
- }.to fail_with(dedent <<-EOS)
273
- |expected collection contained: [(a string matching /bar/), (a string matching /foo/), (a string matching /goo/)]
274
- |actual collection contained: ["barn", "food"]
275
- |the missing elements were: [(a string matching /goo/)]
276
- |
277
- EOS
278
- end
279
-
280
- it 'pairs up the items in order to minimize the number of unpaired items' do
281
- expect {
282
- expect(["fool", "food", "good"]).to contain_exactly(/foo/, /fool/, /poo/)
283
- }.to fail_with(dedent <<-EOS)
284
- |expected collection contained: [/foo/, /fool/, /poo/]
285
- |actual collection contained: ["food", "fool", "good"]
286
- |the missing elements were: [/poo/]
287
- |the extra elements were: ["good"]
288
- |
289
- EOS
290
- end
291
-
292
- it 'provides a description' do
293
- description = contain_exactly(a_string_matching(/bar/), a_string_matching(/foo/)).description
294
- expect(description).to eq("contain exactly (a string matching /bar/) and (a string matching /foo/)")
295
- end
296
-
297
- context 'when an earlier matcher matches more strictly than a later matcher' do
298
- it 'works when the actual items match in the same order' do
299
- expect(["food", "fool"]).to contain_exactly(a_string_matching(/foo/), a_string_matching(/fool/))
300
- end
301
-
302
- it 'works when the actual items match in reverse order' do
303
- expect(["fool", "food"]).to contain_exactly(a_string_matching(/foo/), a_string_matching(/fool/))
304
- end
305
-
306
- it 'can handle multiple sets of overlapping matches' do
307
- expect(["fool", "barn", "bare", "food"]).to contain_exactly(
308
- a_string_matching(/bar/),
309
- a_string_matching(/barn/),
310
- a_string_matching(/foo/),
311
- a_string_matching(/fool/)
312
- )
313
- end
314
- end
315
-
316
- it "can use `a_value_within` and `a_string_starting_with` against multiple types of values" do
317
- expect(["barn", 2.45]).to contain_exactly(
318
- a_value_within(0.1).of(2.5),
319
- a_string_starting_with("bar")
320
- )
321
- end
322
-
323
- context 'when a later matcher matches more strictly than an earlier matcher' do
324
- it 'works when the actual items match in the same order' do
325
- expect(["fool", "food"]).to contain_exactly(a_string_matching(/fool/), a_string_matching(/foo/))
326
- end
327
-
328
- it 'works when the actual items match in reverse order' do
329
- expect(["food", "fool"]).to contain_exactly(a_string_matching(/fool/), a_string_matching(/foo/))
330
- end
331
- end
332
- end
333
- end
334
-
335
- module RSpec
336
- module Matchers
337
- module BuiltIn
338
- class ContainExactly
339
- describe PairingsMaximizer do
340
- it 'finds unmatched expected indexes' do
341
- maximizer = PairingsMaximizer.new({ 0 => [], 1 => [0] }, { 0 => [1] })
342
- expect(maximizer.solution.unmatched_expected_indexes).to eq([0])
343
- end
344
-
345
- it 'finds unmatched actual indexes' do
346
- maximizer = PairingsMaximizer.new({ 0 => [0] }, { 0 => [0], 1 => [] })
347
- expect(maximizer.solution.unmatched_actual_indexes).to eq([1])
348
- end
349
-
350
- describe "finding indeterminate indexes" do
351
- it 'does not include unmatched indexes' do
352
- maximizer = PairingsMaximizer.new({ 0 => [], 1 => [0] }, { 0 => [1], 1 => [] })
353
-
354
- expect(maximizer.solution.indeterminate_expected_indexes).not_to include(0)
355
- expect(maximizer.solution.indeterminate_actual_indexes).not_to include(1)
356
- end
357
-
358
- it 'does not include indexes that are reciprocally to exactly one index' do
359
- maximizer = PairingsMaximizer.new({ 0 => [], 1 => [0] }, { 0 => [1], 1 => [0] })
360
-
361
- expect(maximizer.solution.indeterminate_expected_indexes).not_to include(1)
362
- expect(maximizer.solution.indeterminate_actual_indexes).not_to include(0)
363
- end
364
-
365
- it 'includes indexes that have multiple matches' do
366
- maximizer = PairingsMaximizer.new({ 0 => [0, 2], 1 => [0, 2], 2 => [] },
367
- { 0 => [0, 1], 1 => [], 2 => [0, 1] })
368
-
369
-
370
- expect(maximizer.solution.indeterminate_expected_indexes).to include(0, 1)
371
- expect(maximizer.solution.indeterminate_actual_indexes).to include(0, 2)
372
- end
373
-
374
- it 'includes indexes that have one match which has multiple matches' do
375
- maximizer = PairingsMaximizer.new({ 0 => [0], 1 => [0], 2 => [1, 2] },
376
- { 0 => [0, 1], 1 => [2], 2 => [2] })
377
-
378
- expect(maximizer.solution.indeterminate_expected_indexes).to include(0, 1)
379
- expect(maximizer.solution.indeterminate_actual_indexes).to include(1, 2)
380
- end
381
- end
382
-
383
- describe "#unmatched_item_count" do
384
- it 'returns the count of unmatched items' do
385
- maximizer = PairingsMaximizer.new({ 0 => [1], 1 => [0] },
386
- { 0 => [1], 1 => [0] })
387
- expect(maximizer.solution.unmatched_item_count).to eq(0)
388
-
389
- maximizer = PairingsMaximizer.new({ 0 => [1], 1 => [0] },
390
- { 0 => [1], 1 => [0], 2 => [] })
391
- expect(maximizer.solution.unmatched_item_count).to eq(1)
392
- end
393
- end
394
-
395
- describe "#find_best_solution" do
396
- matcher :produce_result do |unmatched_expected, unmatched_actual|
397
- match do |result|
398
- result.candidate? &&
399
- result.unmatched_expected_indexes == unmatched_expected &&
400
- result.unmatched_actual_indexes == unmatched_actual
401
- end
402
-
403
- failure_message do |result|
404
- if result.candidate_result?
405
- "expected a complete solution, but still had indeterminate indexes: " +
406
- "expected: #{result.indeterminate_expected_indexes.inspect}; " +
407
- "actual: #{result.indeterminate_actual_indexes.inspect}"
408
- elsif result.unmatched_expected_indexes != unmatched_expected
409
- "expected unmatched_expected_indexes: #{unmatched_expected.inspect} " +
410
- "but got: #{result.unmatched_expected_indexes.inspect}"
411
- elsif result.unmatched_actual_indexes != unmatched_actual
412
- "expected unmatched_actual_indexes: #{unmatched_actual.inspect} " +
413
- "but got: #{result.unmatched_actual_indexes.inspect}"
414
- end
415
- end
416
- end
417
-
418
- it 'returns no unmatched indexes when everything reciprocally matches one item' do
419
- maximizer = PairingsMaximizer.new({ 0 => [1], 1 => [0] },
420
- { 0 => [1], 1 => [0] })
421
- expect(maximizer.find_best_solution).to produce_result([], [])
422
- end
423
-
424
- it 'returns unmatched indexes for everything that has no matches' do
425
- maximizer = PairingsMaximizer.new({ 0 => [], 1 => [0] },
426
- { 0 => [1], 1 => [] })
427
- expect(maximizer.find_best_solution).to produce_result([0], [1])
428
- end
429
-
430
- it 'searches the solution space for a perfectly matching solution' do
431
- maximizer = PairingsMaximizer.new({ 0 => [0, 1], 1 => [0] },
432
- { 0 => [0, 1], 1 => [0] })
433
- expect(maximizer.find_best_solution).to produce_result([], [])
434
- end
435
- end
436
- end
437
- end
438
- end
439
- end
440
- end
441
-