super_diff 0.1.0 → 0.2.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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +117 -89
  3. data/lib/super_diff.rb +33 -47
  4. data/lib/super_diff/active_record.rb +41 -0
  5. data/lib/super_diff/active_record/diff_formatters.rb +10 -0
  6. data/lib/super_diff/active_record/diff_formatters/active_record_relation.rb +23 -0
  7. data/lib/super_diff/active_record/differs.rb +10 -0
  8. data/lib/super_diff/active_record/differs/active_record_relation.rb +30 -0
  9. data/lib/super_diff/active_record/object_inspection.rb +14 -0
  10. data/lib/super_diff/active_record/object_inspection/inspectors.rb +16 -0
  11. data/lib/super_diff/active_record/object_inspection/inspectors/active_record_model.rb +38 -0
  12. data/lib/super_diff/active_record/object_inspection/inspectors/active_record_relation.rb +18 -0
  13. data/lib/super_diff/active_record/object_inspection/map_extension.rb +18 -0
  14. data/lib/super_diff/active_record/operation_sequences.rb +10 -0
  15. data/lib/super_diff/active_record/operation_sequences/active_record_relation.rb +16 -0
  16. data/lib/super_diff/active_record/operational_sequencers.rb +14 -0
  17. data/lib/super_diff/active_record/operational_sequencers/active_record_model.rb +19 -0
  18. data/lib/super_diff/active_record/operational_sequencers/active_record_relation.rb +24 -0
  19. data/lib/super_diff/active_support.rb +33 -0
  20. data/lib/super_diff/active_support/diff_formatters.rb +10 -0
  21. data/lib/super_diff/active_support/diff_formatters/hash_with_indifferent_access.rb +36 -0
  22. data/lib/super_diff/active_support/differs.rb +10 -0
  23. data/lib/super_diff/active_support/differs/hash_with_indifferent_access.rb +36 -0
  24. data/lib/super_diff/active_support/object_inspection.rb +14 -0
  25. data/lib/super_diff/active_support/object_inspection/inspectors.rb +12 -0
  26. data/lib/super_diff/active_support/object_inspection/inspectors/hash_with_indifferent_access.rb +18 -0
  27. data/lib/super_diff/active_support/object_inspection/map_extension.rb +15 -0
  28. data/lib/super_diff/active_support/operation_sequences.rb +10 -0
  29. data/lib/super_diff/active_support/operation_sequences/hash_with_indifferent_access.rb +16 -0
  30. data/lib/super_diff/active_support/operational_sequencers.rb +10 -0
  31. data/lib/super_diff/active_support/operational_sequencers/hash_with_indifferent_access.rb +21 -0
  32. data/lib/super_diff/colorized_document_extensions.rb +17 -0
  33. data/lib/super_diff/csi.rb +45 -15
  34. data/lib/super_diff/csi/bold_sequence.rb +9 -0
  35. data/lib/super_diff/csi/color.rb +62 -0
  36. data/lib/super_diff/csi/color_sequence_block.rb +28 -0
  37. data/lib/super_diff/csi/colorized_document.rb +72 -0
  38. data/lib/super_diff/csi/document.rb +183 -0
  39. data/lib/super_diff/csi/eight_bit_color.rb +72 -26
  40. data/lib/super_diff/csi/four_bit_color.rb +63 -29
  41. data/lib/super_diff/csi/twenty_four_bit_color.rb +79 -18
  42. data/lib/super_diff/csi/uncolorized_document.rb +29 -0
  43. data/lib/super_diff/diff_formatter.rb +10 -15
  44. data/lib/super_diff/diff_formatters.rb +10 -1
  45. data/lib/super_diff/diff_formatters/base.rb +12 -17
  46. data/lib/super_diff/diff_formatters/collection.rb +81 -50
  47. data/lib/super_diff/diff_formatters/{object.rb → custom_object.rb} +12 -9
  48. data/lib/super_diff/diff_formatters/default_object.rb +48 -0
  49. data/lib/super_diff/diff_formatters/multiline_string.rb +31 -0
  50. data/lib/super_diff/differ.rb +35 -32
  51. data/lib/super_diff/differs.rb +16 -1
  52. data/lib/super_diff/differs/array.rb +2 -2
  53. data/lib/super_diff/differs/base.rb +11 -21
  54. data/lib/super_diff/differs/custom_object.rb +26 -0
  55. data/lib/super_diff/differs/default_object.rb +25 -0
  56. data/lib/super_diff/differs/empty.rb +1 -1
  57. data/lib/super_diff/differs/hash.rb +2 -2
  58. data/lib/super_diff/differs/{multi_line_string.rb → multiline_string.rb} +6 -5
  59. data/lib/super_diff/equality_matcher.rb +9 -22
  60. data/lib/super_diff/equality_matchers.rb +19 -1
  61. data/lib/super_diff/equality_matchers/array.rb +6 -4
  62. data/lib/super_diff/equality_matchers/base.rb +8 -16
  63. data/lib/super_diff/equality_matchers/default.rb +60 -0
  64. data/lib/super_diff/equality_matchers/hash.rb +6 -4
  65. data/lib/super_diff/equality_matchers/{multi_line_string.rb → multiline_string.rb} +9 -6
  66. data/lib/super_diff/equality_matchers/primitive.rb +34 -0
  67. data/lib/super_diff/equality_matchers/{single_line_string.rb → singleline_string.rb} +7 -5
  68. data/lib/super_diff/helpers.rb +17 -81
  69. data/lib/super_diff/no_differ_available_error.rb +22 -0
  70. data/lib/super_diff/{errors.rb → no_operational_sequencer_available_error.rb} +0 -0
  71. data/lib/super_diff/object_inspection.rb +24 -0
  72. data/lib/super_diff/object_inspection/inspection_tree.rb +144 -0
  73. data/lib/super_diff/object_inspection/inspector.rb +27 -0
  74. data/lib/super_diff/object_inspection/inspectors.rb +18 -0
  75. data/lib/super_diff/object_inspection/inspectors/array.rb +22 -0
  76. data/lib/super_diff/object_inspection/inspectors/custom_object.rb +27 -0
  77. data/lib/super_diff/object_inspection/inspectors/default_object.rb +47 -0
  78. data/lib/super_diff/object_inspection/inspectors/hash.rb +22 -0
  79. data/lib/super_diff/object_inspection/inspectors/primitive.rb +13 -0
  80. data/lib/super_diff/object_inspection/inspectors/string.rb +13 -0
  81. data/lib/super_diff/object_inspection/map.rb +28 -0
  82. data/lib/super_diff/object_inspection/nodes.rb +49 -0
  83. data/lib/super_diff/object_inspection/nodes/base.rb +86 -0
  84. data/lib/super_diff/object_inspection/nodes/break.rb +15 -0
  85. data/lib/super_diff/object_inspection/nodes/inspection.rb +15 -0
  86. data/lib/super_diff/object_inspection/nodes/nesting.rb +16 -0
  87. data/lib/super_diff/object_inspection/nodes/text.rb +15 -0
  88. data/lib/super_diff/object_inspection/nodes/when_empty.rb +30 -0
  89. data/lib/super_diff/object_inspection/nodes/when_multiline.rb +22 -0
  90. data/lib/super_diff/object_inspection/nodes/when_non_empty.rb +30 -0
  91. data/lib/super_diff/object_inspection/nodes/when_singleline.rb +24 -0
  92. data/lib/super_diff/operation_sequences.rb +9 -0
  93. data/lib/super_diff/operation_sequences/base.rb +1 -1
  94. data/lib/super_diff/operation_sequences/{object.rb → custom_object.rb} +4 -3
  95. data/lib/super_diff/operation_sequences/default_object.rb +25 -0
  96. data/lib/super_diff/operational_sequencer.rb +23 -18
  97. data/lib/super_diff/operational_sequencers.rb +12 -1
  98. data/lib/super_diff/operational_sequencers/array.rb +65 -62
  99. data/lib/super_diff/operational_sequencers/base.rb +18 -26
  100. data/lib/super_diff/operational_sequencers/custom_object.rb +35 -0
  101. data/lib/super_diff/operational_sequencers/{object.rb → default_object.rb} +21 -11
  102. data/lib/super_diff/operational_sequencers/hash.rb +8 -5
  103. data/lib/super_diff/operational_sequencers/{multi_line_string.rb → multiline_string.rb} +11 -6
  104. data/lib/super_diff/operations.rb +6 -0
  105. data/lib/super_diff/operations/binary_operation.rb +14 -34
  106. data/lib/super_diff/operations/unary_operation.rb +11 -2
  107. data/lib/super_diff/rails.rb +1 -0
  108. data/lib/super_diff/recursion_guard.rb +47 -0
  109. data/lib/super_diff/rspec-rails.rb +2 -0
  110. data/lib/super_diff/rspec.rb +52 -8
  111. data/lib/super_diff/rspec/augmented_matcher.rb +98 -0
  112. data/lib/super_diff/rspec/configuration.rb +31 -0
  113. data/lib/super_diff/rspec/differ.rb +60 -16
  114. data/lib/super_diff/rspec/differs.rb +13 -0
  115. data/lib/super_diff/rspec/differs/collection_containing_exactly.rb +23 -0
  116. data/lib/super_diff/rspec/differs/partial_array.rb +22 -0
  117. data/lib/super_diff/rspec/differs/partial_hash.rb +22 -0
  118. data/lib/super_diff/rspec/differs/partial_object.rb +22 -0
  119. data/lib/super_diff/rspec/matcher_text_builders.rb +24 -0
  120. data/lib/super_diff/rspec/matcher_text_builders/base.rb +155 -0
  121. data/lib/super_diff/rspec/matcher_text_builders/be_predicate.rb +78 -0
  122. data/lib/super_diff/rspec/matcher_text_builders/contain_exactly.rb +14 -0
  123. data/lib/super_diff/rspec/matcher_text_builders/match.rb +23 -0
  124. data/lib/super_diff/rspec/matcher_text_builders/raise_error.rb +13 -0
  125. data/lib/super_diff/rspec/matcher_text_builders/respond_to.rb +99 -0
  126. data/lib/super_diff/rspec/matcher_text_template.rb +240 -0
  127. data/lib/super_diff/rspec/monkey_patches.rb +601 -98
  128. data/lib/super_diff/rspec/object_inspection.rb +8 -0
  129. data/lib/super_diff/rspec/object_inspection/inspectors.rb +24 -0
  130. data/lib/super_diff/rspec/object_inspection/inspectors/collection_containing_exactly.rb +19 -0
  131. data/lib/super_diff/rspec/object_inspection/inspectors/partial_array.rb +22 -0
  132. data/lib/super_diff/rspec/object_inspection/inspectors/partial_hash.rb +21 -0
  133. data/lib/super_diff/rspec/object_inspection/inspectors/partial_object.rb +21 -0
  134. data/lib/super_diff/rspec/object_inspection/map_extension.rb +23 -0
  135. data/lib/super_diff/rspec/operational_sequencers.rb +22 -0
  136. data/lib/super_diff/rspec/operational_sequencers/collection_containing_exactly.rb +97 -0
  137. data/lib/super_diff/rspec/operational_sequencers/partial_array.rb +23 -0
  138. data/lib/super_diff/rspec/operational_sequencers/partial_hash.rb +32 -0
  139. data/lib/super_diff/rspec/operational_sequencers/partial_object.rb +64 -0
  140. data/lib/super_diff/version.rb +1 -1
  141. data/spec/examples.txt +328 -46
  142. data/spec/integration/rails/active_record_spec.rb +19 -0
  143. data/spec/integration/rails/hash_with_indifferent_access_spec.rb +19 -0
  144. data/spec/integration/rspec/be_falsey_matcher_spec.rb +53 -0
  145. data/spec/integration/rspec/be_matcher_spec.rb +565 -0
  146. data/spec/integration/rspec/be_nil_matcher_spec.rb +53 -0
  147. data/spec/integration/rspec/be_predicate_matcher_spec.rb +546 -0
  148. data/spec/integration/rspec/be_truthy_matcher_spec.rb +57 -0
  149. data/spec/integration/rspec/contain_exactly_matcher_spec.rb +368 -0
  150. data/spec/integration/rspec/eq_matcher_spec.rb +874 -0
  151. data/spec/integration/rspec/have_attributes_matcher_spec.rb +299 -0
  152. data/spec/integration/rspec/include_matcher_spec.rb +350 -0
  153. data/spec/integration/rspec/match_matcher_spec.rb +1258 -0
  154. data/spec/integration/rspec/raise_error_matcher_spec.rb +350 -0
  155. data/spec/integration/rspec/respond_to_matcher_spec.rb +994 -0
  156. data/spec/integration/rspec/unhandled_errors_spec.rb +94 -0
  157. data/spec/spec_helper.rb +19 -4
  158. data/spec/support/colorizer.rb +9 -0
  159. data/spec/support/command_runner.rb +4 -0
  160. data/spec/support/integration/helpers.rb +179 -0
  161. data/spec/support/integration/matchers/produce_output_when_run_matcher.rb +79 -41
  162. data/spec/support/models/a.rb +11 -0
  163. data/spec/support/models/active_record/person.rb +26 -0
  164. data/spec/support/models/active_record/shipping_address.rb +29 -0
  165. data/spec/support/models/customer.rb +24 -0
  166. data/spec/support/models/empty_class.rb +6 -0
  167. data/spec/support/models/item.rb +10 -0
  168. data/spec/support/models/order.rb +9 -0
  169. data/spec/support/models/person.rb +20 -0
  170. data/spec/support/models/player.rb +33 -0
  171. data/spec/support/models/shipping_address.rb +34 -0
  172. data/spec/support/ruby_versions.rb +7 -0
  173. data/spec/support/shared_examples/active_record.rb +338 -0
  174. data/spec/support/shared_examples/hash_with_indifferent_access.rb +233 -0
  175. data/spec/unit/equality_matcher_spec.rb +579 -171
  176. data/spec/unit/object_inspection_spec.rb +1092 -0
  177. data/spec/unit/rspec/matchers/be_compared_to_spec.rb +23 -0
  178. data/spec/unit/rspec/matchers/be_falsey_spec.rb +9 -0
  179. data/spec/unit/rspec/matchers/be_nil_spec.rb +9 -0
  180. data/spec/unit/rspec/matchers/be_predicate_spec.rb +31 -0
  181. data/spec/unit/rspec/matchers/be_spec.rb +17 -0
  182. data/spec/unit/rspec/matchers/be_truthy_spec.rb +9 -0
  183. data/spec/unit/rspec/matchers/contain_exactly_spec.rb +11 -0
  184. data/spec/unit/rspec/matchers/eq_spec.rb +9 -0
  185. data/spec/unit/rspec/matchers/have_attributes_spec.rb +11 -0
  186. data/spec/unit/rspec/matchers/include_spec.rb +21 -0
  187. data/spec/unit/rspec/matchers/match_spec.rb +9 -0
  188. data/spec/unit/rspec/matchers/raise_error_spec.rb +29 -0
  189. data/spec/unit/rspec/matchers/respond_to_spec.rb +78 -0
  190. data/super_diff.gemspec +4 -2
  191. metadata +231 -34
  192. data/lib/super_diff/csi/color_helper.rb +0 -52
  193. data/lib/super_diff/csi/eight_bit_sequence.rb +0 -27
  194. data/lib/super_diff/csi/four_bit_sequence.rb +0 -24
  195. data/lib/super_diff/csi/sequence.rb +0 -22
  196. data/lib/super_diff/csi/twenty_four_bit_sequence.rb +0 -27
  197. data/lib/super_diff/diff_formatters/multi_line_string.rb +0 -31
  198. data/lib/super_diff/differs/object.rb +0 -68
  199. data/lib/super_diff/equality_matchers/object.rb +0 -18
  200. data/lib/super_diff/value_inspection.rb +0 -11
  201. data/spec/integration/rspec_spec.rb +0 -261
  202. data/spec/support/color_helper.rb +0 -49
  203. data/spec/support/person.rb +0 -23
  204. data/spec/support/person_diff_formatter.rb +0 -15
  205. data/spec/support/person_operation_sequence.rb +0 -14
  206. data/spec/support/person_operational_sequencer.rb +0 -19
@@ -0,0 +1,1258 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Integration with RSpec's #match matcher", type: :integration do
4
+ context "when the expected value is a partial hash" do
5
+ context "that is small" do
6
+ it "produces the correct failure message when used in the positive" do
7
+ as_both_colored_and_uncolored do |color_enabled|
8
+ snippet = <<~TEST.strip
9
+ expected = a_hash_including(city: "Hill Valley")
10
+ actual = { city: "Burbank" }
11
+ expect(actual).to match(expected)
12
+ TEST
13
+ program = make_plain_test_program(
14
+ snippet,
15
+ color_enabled: color_enabled,
16
+ )
17
+
18
+ expected_output = build_expected_output(
19
+ color_enabled: color_enabled,
20
+ snippet: %|expect(actual).to match(expected)|,
21
+ expectation: proc {
22
+ line do
23
+ plain "Expected "
24
+ beta %|{ city: "Burbank" }|
25
+ plain " to match "
26
+ alpha %|#<a hash including (city: "Hill Valley")>|
27
+ plain "."
28
+ end
29
+ },
30
+ diff: proc {
31
+ plain_line %| {|
32
+ alpha_line %|- city: "Hill Valley"|
33
+ beta_line %|+ city: "Burbank"|
34
+ plain_line %| }|
35
+ },
36
+ )
37
+
38
+ expect(program).
39
+ to produce_output_when_run(expected_output).
40
+ in_color(color_enabled)
41
+ end
42
+ end
43
+
44
+ it "produces the correct failure message when used in the negative" do
45
+ as_both_colored_and_uncolored do |color_enabled|
46
+ snippet = <<~TEST.strip
47
+ expected = a_hash_including(city: "Burbank")
48
+ actual = { city: "Burbank" }
49
+ expect(actual).not_to match(expected)
50
+ TEST
51
+ program = make_plain_test_program(
52
+ snippet,
53
+ color_enabled: color_enabled,
54
+ )
55
+
56
+ expected_output = build_expected_output(
57
+ color_enabled: color_enabled,
58
+ snippet: %|expect(actual).not_to match(expected)|,
59
+ expectation: proc {
60
+ line do
61
+ plain "Expected "
62
+ beta %|{ city: "Burbank" }|
63
+ plain " not to match "
64
+ alpha %|#<a hash including (city: "Burbank")>|
65
+ plain "."
66
+ end
67
+ },
68
+ )
69
+
70
+ expect(program).
71
+ to produce_output_when_run(expected_output).
72
+ in_color(color_enabled)
73
+ end
74
+ end
75
+ end
76
+
77
+ context "that is large" do
78
+ it "produces the correct failure message when used in the positive" do
79
+ as_both_colored_and_uncolored do |color_enabled|
80
+ snippet = <<~TEST.strip
81
+ expected = a_hash_including(
82
+ city: "Hill Valley",
83
+ zip: "90382"
84
+ )
85
+ actual = {
86
+ line_1: "123 Main St.",
87
+ city: "Burbank",
88
+ state: "CA",
89
+ zip: "90210"
90
+ }
91
+ expect(actual).to match(expected)
92
+ TEST
93
+ program = make_plain_test_program(
94
+ snippet,
95
+ color_enabled: color_enabled,
96
+ )
97
+
98
+ expected_output = build_expected_output(
99
+ color_enabled: color_enabled,
100
+ snippet: %|expect(actual).to match(expected)|,
101
+ expectation: proc {
102
+ line do
103
+ plain "Expected "
104
+ beta %|{ line_1: "123 Main St.", city: "Burbank", state: "CA", zip: "90210" }|
105
+ end
106
+
107
+ line do
108
+ plain "to match "
109
+ alpha %|#<a hash including (city: "Hill Valley", zip: "90382")>|
110
+ end
111
+ },
112
+ diff: proc {
113
+ plain_line %| {|
114
+ plain_line %| line_1: "123 Main St.",|
115
+ alpha_line %|- city: "Hill Valley",|
116
+ beta_line %|+ city: "Burbank",|
117
+ plain_line %| state: "CA",|
118
+ alpha_line %|- zip: "90382"|
119
+ beta_line %|+ zip: "90210"|
120
+ plain_line %| }|
121
+ },
122
+ )
123
+
124
+ expect(program).
125
+ to produce_output_when_run(expected_output).
126
+ in_color(color_enabled)
127
+ end
128
+ end
129
+
130
+ it "produces the correct failure message when used in the negative" do
131
+ as_both_colored_and_uncolored do |color_enabled|
132
+ snippet = <<~TEST.strip
133
+ expected = a_hash_including(
134
+ city: "Burbank",
135
+ zip: "90210"
136
+ )
137
+ actual = {
138
+ line_1: "123 Main St.",
139
+ city: "Burbank",
140
+ state: "CA",
141
+ zip: "90210"
142
+ }
143
+ expect(actual).not_to match(expected)
144
+ TEST
145
+ program = make_plain_test_program(
146
+ snippet,
147
+ color_enabled: color_enabled,
148
+ )
149
+
150
+ expected_output = build_expected_output(
151
+ color_enabled: color_enabled,
152
+ snippet: %|expect(actual).not_to match(expected)|,
153
+ newline_before_expectation: true,
154
+ expectation: proc {
155
+ line do
156
+ plain " Expected "
157
+ beta %|{ line_1: "123 Main St.", city: "Burbank", state: "CA", zip: "90210" }|
158
+ end
159
+
160
+ line do
161
+ plain "not to match "
162
+ alpha %|#<a hash including (city: "Burbank", zip: "90210")>|
163
+ end
164
+ },
165
+ )
166
+
167
+ expect(program).
168
+ to produce_output_when_run(expected_output).
169
+ in_color(color_enabled)
170
+ end
171
+ end
172
+ end
173
+ end
174
+
175
+ context "when the expected value includes a partial hash" do
176
+ context "and the corresponding actual value is a hash" do
177
+ it "produces the correct failure message when used in the positive" do
178
+ as_both_colored_and_uncolored do |color_enabled|
179
+ snippet = <<~TEST.strip
180
+ expected = {
181
+ name: "Marty McFly",
182
+ address: a_hash_including(
183
+ city: "Hill Valley",
184
+ zip: "90382"
185
+ )
186
+ }
187
+ actual = {
188
+ name: "Marty McFly",
189
+ address: {
190
+ line_1: "123 Main St.",
191
+ city: "Burbank",
192
+ state: "CA",
193
+ zip: "90210"
194
+ }
195
+ }
196
+ expect(actual).to match(expected)
197
+ TEST
198
+ program = make_plain_test_program(
199
+ snippet,
200
+ color_enabled: color_enabled,
201
+ )
202
+
203
+ expected_output = build_expected_output(
204
+ color_enabled: color_enabled,
205
+ snippet: %|expect(actual).to match(expected)|,
206
+ expectation: proc {
207
+ line do
208
+ plain "Expected "
209
+ beta %|{ name: "Marty McFly", address: { line_1: "123 Main St.", city: "Burbank", state: "CA", zip: "90210" } }|
210
+ end
211
+
212
+ line do
213
+ plain "to match "
214
+ alpha %|{ name: "Marty McFly", address: #<a hash including (city: "Hill Valley", zip: "90382")> }|
215
+ end
216
+ },
217
+ diff: proc {
218
+ plain_line %| {|
219
+ plain_line %| name: "Marty McFly",|
220
+ plain_line %| address: {|
221
+ plain_line %| line_1: "123 Main St.",|
222
+ alpha_line %|- city: "Hill Valley",|
223
+ beta_line %|+ city: "Burbank",|
224
+ plain_line %| state: "CA",|
225
+ alpha_line %|- zip: "90382"|
226
+ beta_line %|+ zip: "90210"|
227
+ plain_line %| }|
228
+ plain_line %| }|
229
+ },
230
+ )
231
+
232
+ expect(program).
233
+ to produce_output_when_run(expected_output).
234
+ in_color(color_enabled)
235
+ end
236
+ end
237
+
238
+ it "produces the correct failure message when used in the negative" do
239
+ as_both_colored_and_uncolored do |color_enabled|
240
+ snippet = <<~TEST.strip
241
+ expected = {
242
+ name: "Marty McFly",
243
+ address: a_hash_including(
244
+ city: "Burbank",
245
+ zip: "90210"
246
+ )
247
+ }
248
+ actual = {
249
+ name: "Marty McFly",
250
+ address: {
251
+ line_1: "123 Main St.",
252
+ city: "Burbank",
253
+ state: "CA",
254
+ zip: "90210"
255
+ }
256
+ }
257
+ expect(actual).not_to match(expected)
258
+ TEST
259
+ program = make_plain_test_program(
260
+ snippet,
261
+ color_enabled: color_enabled,
262
+ )
263
+
264
+ expected_output = build_expected_output(
265
+ color_enabled: color_enabled,
266
+ snippet: %|expect(actual).not_to match(expected)|,
267
+ newline_before_expectation: true,
268
+ expectation: proc {
269
+ line do
270
+ plain " Expected "
271
+ beta %|{ name: "Marty McFly", address: { line_1: "123 Main St.", city: "Burbank", state: "CA", zip: "90210" } }|
272
+ end
273
+
274
+ line do
275
+ plain "not to match "
276
+ alpha %|{ name: "Marty McFly", address: #<a hash including (city: "Burbank", zip: "90210")> }|
277
+ end
278
+ },
279
+ )
280
+
281
+ expect(program).
282
+ to produce_output_when_run(expected_output).
283
+ in_color(color_enabled)
284
+ end
285
+ end
286
+ end
287
+
288
+ context "and the corresponding actual value is not a hash" do
289
+ it "produces the correct failure message" do
290
+ as_both_colored_and_uncolored do |color_enabled|
291
+ snippet = <<~TEST.strip
292
+ expected = {
293
+ name: "Marty McFly",
294
+ address: a_hash_including(
295
+ city: "Hill Valley",
296
+ zip: "90382"
297
+ )
298
+ }
299
+ actual = {
300
+ name: "Marty McFly",
301
+ address: nil
302
+ }
303
+ expect(actual).to match(expected)
304
+ TEST
305
+ program = make_plain_test_program(
306
+ snippet,
307
+ color_enabled: color_enabled,
308
+ )
309
+
310
+ expected_output = build_expected_output(
311
+ color_enabled: color_enabled,
312
+ snippet: %|expect(actual).to match(expected)|,
313
+ expectation: proc {
314
+ line do
315
+ plain "Expected "
316
+ beta %|{ name: "Marty McFly", address: nil }|
317
+ end
318
+
319
+ line do
320
+ plain "to match "
321
+ alpha %|{ name: "Marty McFly", address: #<a hash including (city: "Hill Valley", zip: "90382")> }|
322
+ end
323
+ },
324
+ diff: proc {
325
+ plain_line %! {!
326
+ plain_line %! name: "Marty McFly",!
327
+ alpha_line %!- address: #<a hash including (!
328
+ alpha_line %!- city: "Hill Valley",!
329
+ alpha_line %!- zip: "90382"!
330
+ alpha_line %!- )>!
331
+ beta_line %!+ address: nil!
332
+ plain_line %! }!
333
+ },
334
+ )
335
+
336
+ expect(program).
337
+ to produce_output_when_run(expected_output).
338
+ in_color(color_enabled)
339
+ end
340
+ end
341
+ end
342
+ end
343
+
344
+ context "when the expected value is a partial array" do
345
+ context "that is small" do
346
+ it "produces the correct failure message when used in the positive" do
347
+ as_both_colored_and_uncolored do |color_enabled|
348
+ snippet = <<~TEST.strip
349
+ expected = a_collection_including("a")
350
+ actual = ["b"]
351
+ expect(actual).to match(expected)
352
+ TEST
353
+ program = make_plain_test_program(
354
+ snippet,
355
+ color_enabled: color_enabled,
356
+ )
357
+
358
+ expected_output = build_expected_output(
359
+ color_enabled: color_enabled,
360
+ snippet: %|expect(actual).to match(expected)|,
361
+ expectation: proc {
362
+ line do
363
+ plain "Expected "
364
+ beta %|["b"]|
365
+ plain " to match "
366
+ alpha %|#<a collection including ("a")>|
367
+ plain "."
368
+ end
369
+ },
370
+ diff: proc {
371
+ plain_line %| [|
372
+ plain_line %| "b"|
373
+ # alpha_line %|- "a",| # FIXME
374
+ alpha_line %|- "a"|
375
+ plain_line %| ]|
376
+ },
377
+ )
378
+
379
+ expect(program).
380
+ to produce_output_when_run(expected_output).
381
+ in_color(color_enabled)
382
+ end
383
+ end
384
+
385
+ it "produces the correct failure message when used in the negative" do
386
+ as_both_colored_and_uncolored do |color_enabled|
387
+ snippet = <<~TEST.strip
388
+ expected = a_collection_including("b")
389
+ actual = ["b"]
390
+ expect(actual).not_to match(expected)
391
+ TEST
392
+ program = make_plain_test_program(
393
+ snippet,
394
+ color_enabled: color_enabled,
395
+ )
396
+
397
+ expected_output = build_expected_output(
398
+ color_enabled: color_enabled,
399
+ snippet: %|expect(actual).not_to match(expected)|,
400
+ expectation: proc {
401
+ line do
402
+ plain "Expected "
403
+ beta %|["b"]|
404
+ plain " not to match "
405
+ alpha %|#<a collection including ("b")>|
406
+ plain "."
407
+ end
408
+ },
409
+ )
410
+
411
+ expect(program).
412
+ to produce_output_when_run(expected_output).
413
+ in_color(color_enabled)
414
+ end
415
+ end
416
+ end
417
+
418
+ context "that is large" do
419
+ it "produces the correct failure message when used in the positive" do
420
+ as_both_colored_and_uncolored do |color_enabled|
421
+ snippet = <<~TEST.strip
422
+ expected = a_collection_including("milk", "bread")
423
+ actual = ["milk", "toast", "eggs", "cheese", "English muffins"]
424
+ expect(actual).to match(expected)
425
+ TEST
426
+ program = make_plain_test_program(
427
+ snippet,
428
+ color_enabled: color_enabled,
429
+ )
430
+
431
+ expected_output = build_expected_output(
432
+ color_enabled: color_enabled,
433
+ snippet: %|expect(actual).to match(expected)|,
434
+ expectation: proc {
435
+ line do
436
+ plain "Expected "
437
+ beta %|["milk", "toast", "eggs", "cheese", "English muffins"]|
438
+ end
439
+
440
+ line do
441
+ plain "to match "
442
+ alpha %|#<a collection including ("milk", "bread")>|
443
+ end
444
+ },
445
+ diff: proc {
446
+ plain_line %| [|
447
+ plain_line %| "milk",|
448
+ plain_line %| "toast",|
449
+ plain_line %| "eggs",|
450
+ plain_line %| "cheese",|
451
+ # plain_line %| "English muffins",| # FIXME
452
+ plain_line %| "English muffins"|
453
+ alpha_line %|- "bread"|
454
+ plain_line %| ]|
455
+ },
456
+ )
457
+
458
+ expect(program).
459
+ to produce_output_when_run(expected_output).
460
+ in_color(color_enabled)
461
+ end
462
+ end
463
+
464
+ it "produces the correct failure message when used in the negative" do
465
+ as_both_colored_and_uncolored do |color_enabled|
466
+ snippet = <<~TEST.strip
467
+ expected = a_collection_including("milk", "toast")
468
+ actual = ["milk", "toast", "eggs", "cheese", "English muffins"]
469
+ expect(actual).not_to match(expected)
470
+ TEST
471
+ program = make_plain_test_program(
472
+ snippet,
473
+ color_enabled: color_enabled,
474
+ )
475
+
476
+ expected_output = build_expected_output(
477
+ color_enabled: color_enabled,
478
+ snippet: %|expect(actual).not_to match(expected)|,
479
+ newline_before_expectation: true,
480
+ expectation: proc {
481
+ line do
482
+ plain " Expected "
483
+ beta %|["milk", "toast", "eggs", "cheese", "English muffins"]|
484
+ end
485
+
486
+ line do
487
+ plain "not to match "
488
+ alpha %|#<a collection including ("milk", "toast")>|
489
+ end
490
+ },
491
+ )
492
+
493
+ expect(program).
494
+ to produce_output_when_run(expected_output).
495
+ in_color(color_enabled)
496
+ end
497
+ end
498
+ end
499
+ end
500
+
501
+ context "when the expected value includes a partial array" do
502
+ context "and the corresponding actual value is an array" do
503
+ it "produces the correct failure message when used in the positive" do
504
+ as_both_colored_and_uncolored do |color_enabled|
505
+ snippet = <<~TEST.strip
506
+ expected = {
507
+ name: "shopping list",
508
+ contents: a_collection_including("milk", "bread")
509
+ }
510
+ actual = {
511
+ name: "shopping list",
512
+ contents: ["milk", "toast", "eggs"]
513
+ }
514
+ expect(actual).to match(expected)
515
+ TEST
516
+ program = make_plain_test_program(
517
+ snippet,
518
+ color_enabled: color_enabled,
519
+ )
520
+
521
+ expected_output = build_expected_output(
522
+ color_enabled: color_enabled,
523
+ snippet: %|expect(actual).to match(expected)|,
524
+ expectation: proc {
525
+ line do
526
+ plain "Expected "
527
+ beta %|{ name: "shopping list", contents: ["milk", "toast", "eggs"] }|
528
+ end
529
+
530
+ line do
531
+ plain "to match "
532
+ alpha %|{ name: "shopping list", contents: #<a collection including ("milk", "bread")> }|
533
+ end
534
+ },
535
+ diff: proc {
536
+ plain_line %| {|
537
+ plain_line %| name: "shopping list",|
538
+ plain_line %| contents: [|
539
+ plain_line %| "milk",|
540
+ plain_line %| "toast",|
541
+ # plain_line %| "eggs",| # FIXME
542
+ plain_line %| "eggs"|
543
+ alpha_line %|- "bread"|
544
+ plain_line %| ]|
545
+ plain_line %| }|
546
+ },
547
+ )
548
+
549
+ expect(program).
550
+ to produce_output_when_run(expected_output).
551
+ in_color(color_enabled)
552
+ end
553
+ end
554
+
555
+ it "produces the correct failure message when used in the negative" do
556
+ as_both_colored_and_uncolored do |color_enabled|
557
+ snippet = <<~TEST.strip
558
+ expected = {
559
+ name: "shopping list",
560
+ contents: a_collection_including("milk", "toast")
561
+ }
562
+ actual = {
563
+ name: "shopping list",
564
+ contents: ["milk", "toast", "eggs"]
565
+ }
566
+ expect(actual).not_to match(expected)
567
+ TEST
568
+ program = make_plain_test_program(
569
+ snippet,
570
+ color_enabled: color_enabled,
571
+ )
572
+
573
+ expected_output = build_expected_output(
574
+ color_enabled: color_enabled,
575
+ snippet: %|expect(actual).not_to match(expected)|,
576
+ newline_before_expectation: true,
577
+ expectation: proc {
578
+ line do
579
+ plain " Expected "
580
+ beta %|{ name: "shopping list", contents: ["milk", "toast", "eggs"] }|
581
+ end
582
+
583
+ line do
584
+ plain "not to match "
585
+ alpha %|{ name: "shopping list", contents: #<a collection including ("milk", "toast")> }|
586
+ end
587
+ },
588
+ )
589
+
590
+ expect(program).
591
+ to produce_output_when_run(expected_output).
592
+ in_color(color_enabled)
593
+ end
594
+ end
595
+ end
596
+
597
+ context "when the corresponding actual value is not an array" do
598
+ it "produces the correct failure message" do
599
+ as_both_colored_and_uncolored do |color_enabled|
600
+ snippet = <<~TEST.strip
601
+ expected = {
602
+ name: "shopping list",
603
+ contents: a_collection_including("milk", "bread")
604
+ }
605
+ actual = {
606
+ name: "shopping list",
607
+ contents: nil
608
+ }
609
+ expect(actual).to match(expected)
610
+ TEST
611
+ program = make_plain_test_program(
612
+ snippet,
613
+ color_enabled: color_enabled,
614
+ )
615
+
616
+ expected_output = build_expected_output(
617
+ color_enabled: color_enabled,
618
+ snippet: %|expect(actual).to match(expected)|,
619
+ expectation: proc {
620
+ line do
621
+ plain "Expected "
622
+ beta %|{ name: "shopping list", contents: nil }|
623
+ end
624
+
625
+ line do
626
+ plain "to match "
627
+ alpha %|{ name: "shopping list", contents: #<a collection including ("milk", "bread")> }|
628
+ end
629
+ },
630
+ diff: proc {
631
+ plain_line %! {!
632
+ plain_line %! name: "shopping list",!
633
+ alpha_line %!- contents: #<a collection including (!
634
+ alpha_line %!- "milk",!
635
+ alpha_line %!- "bread"!
636
+ alpha_line %!- )>!
637
+ beta_line %!+ contents: nil!
638
+ plain_line %! }!
639
+ },
640
+ )
641
+
642
+ expect(program).
643
+ to produce_output_when_run(expected_output).
644
+ in_color(color_enabled)
645
+ end
646
+ end
647
+ end
648
+ end
649
+
650
+ context "when the expected value is a partial object" do
651
+ context "that is small" do
652
+ it "produces the correct failure message when used in the positive" do
653
+ as_both_colored_and_uncolored do |color_enabled|
654
+ snippet = <<~TEST.strip
655
+ expected = an_object_having_attributes(name: "b")
656
+ actual = A.new("a")
657
+ expect(actual).to match(expected)
658
+ TEST
659
+ program = make_plain_test_program(
660
+ snippet,
661
+ color_enabled: color_enabled,
662
+ )
663
+
664
+ expected_output = build_expected_output(
665
+ color_enabled: color_enabled,
666
+ snippet: %|expect(actual).to match(expected)|,
667
+ expectation: proc {
668
+ line do
669
+ plain "Expected "
670
+ beta %|#<A name: "a">|
671
+ plain " to match "
672
+ alpha %|#<an object having attributes (name: "b")>|
673
+ plain "."
674
+ end
675
+ },
676
+ diff: proc {
677
+ plain_line %| #<A {|
678
+ # alpha_line %|- name: "b",| # FIXME
679
+ alpha_line %|- name: "b"|
680
+ beta_line %|+ name: "a"|
681
+ plain_line %| }>|
682
+ },
683
+ )
684
+
685
+ expect(program).
686
+ to produce_output_when_run(expected_output).
687
+ in_color(color_enabled)
688
+ end
689
+ end
690
+
691
+ it "produces the correct failure message when used in the negative" do
692
+ as_both_colored_and_uncolored do |color_enabled|
693
+ snippet = <<~TEST.strip
694
+ expected = an_object_having_attributes(name: "b")
695
+ actual = A.new("b")
696
+ expect(actual).not_to match(expected)
697
+ TEST
698
+ program = make_plain_test_program(
699
+ snippet,
700
+ color_enabled: color_enabled,
701
+ )
702
+
703
+ expected_output = build_expected_output(
704
+ color_enabled: color_enabled,
705
+ snippet: %|expect(actual).not_to match(expected)|,
706
+ expectation: proc {
707
+ line do
708
+ plain "Expected "
709
+ beta %|#<A name: "b">|
710
+ plain " not to match "
711
+ alpha %|#<an object having attributes (name: "b")>|
712
+ plain "."
713
+ end
714
+ },
715
+ )
716
+
717
+ expect(program).
718
+ to produce_output_when_run(expected_output).
719
+ in_color(color_enabled)
720
+ end
721
+ end
722
+ end
723
+
724
+ context "that is large" do
725
+ it "produces the correct failure message when used in the positive" do
726
+ as_both_colored_and_uncolored do |color_enabled|
727
+ snippet = <<~TEST.strip
728
+ expected = an_object_having_attributes(
729
+ line_1: "123 Main St.",
730
+ city: "Oakland",
731
+ zip: "91234",
732
+ state: "CA",
733
+ something_else: "blah"
734
+ )
735
+ actual = SuperDiff::Test::ShippingAddress.new(
736
+ line_1: "456 Ponderosa Ct.",
737
+ line_2: nil,
738
+ city: "Hill Valley",
739
+ state: "CA",
740
+ zip: "90382"
741
+ )
742
+ expect(actual).to match(expected)
743
+ TEST
744
+ program = make_plain_test_program(
745
+ snippet,
746
+ color_enabled: color_enabled,
747
+ )
748
+
749
+ expected_output = build_expected_output(
750
+ color_enabled: color_enabled,
751
+ snippet: %|expect(actual).to match(expected)|,
752
+ expectation: proc {
753
+ line do
754
+ plain "Expected "
755
+ beta %|#<SuperDiff::Test::ShippingAddress line_1: "456 Ponderosa Ct.", line_2: nil, city: "Hill Valley", state: "CA", zip: "90382">|
756
+ end
757
+
758
+ line do
759
+ plain "to match "
760
+ alpha %|#<an object having attributes (line_1: "123 Main St.", city: "Oakland", zip: "91234", state: "CA", something_else: "blah")>|
761
+ end
762
+ },
763
+ diff: proc {
764
+ plain_line %| #<SuperDiff::Test::ShippingAddress {|
765
+ alpha_line %|- line_1: "123 Main St.",|
766
+ beta_line %|+ line_1: "456 Ponderosa Ct.",|
767
+ plain_line %| line_2: nil,|
768
+ alpha_line %|- city: "Oakland",|
769
+ beta_line %|+ city: "Hill Valley",|
770
+ plain_line %| state: "CA",|
771
+ # alpha_line %|- zip: "91234",| # FIXME
772
+ # beta_line %|+ zip: "90382",| # FIXME
773
+ alpha_line %|- zip: "91234"|
774
+ beta_line %|+ zip: "90382"|
775
+ alpha_line %|- something_else: "blah"|
776
+ plain_line %| }>|
777
+ },
778
+ )
779
+
780
+ expect(program).
781
+ to produce_output_when_run(expected_output).
782
+ in_color(color_enabled)
783
+ end
784
+ end
785
+
786
+ it "produces the correct failure message when used in the negative" do
787
+ as_both_colored_and_uncolored do |color_enabled|
788
+ snippet = <<~TEST.strip
789
+ expected = an_object_having_attributes(
790
+ line_1: "123 Main St.",
791
+ city: "Oakland",
792
+ zip: "91234"
793
+ )
794
+ actual = SuperDiff::Test::ShippingAddress.new(
795
+ line_1: "123 Main St.",
796
+ line_2: nil,
797
+ city: "Oakland",
798
+ zip: "91234",
799
+ state: "CA"
800
+ )
801
+ expect(actual).not_to match(expected)
802
+ TEST
803
+ program = make_plain_test_program(
804
+ snippet,
805
+ color_enabled: color_enabled,
806
+ )
807
+
808
+ expected_output = build_expected_output(
809
+ color_enabled: color_enabled,
810
+ snippet: %|expect(actual).not_to match(expected)|,
811
+ newline_before_expectation: true,
812
+ expectation: proc {
813
+ line do
814
+ plain " Expected "
815
+ beta %|#<SuperDiff::Test::ShippingAddress line_1: "123 Main St.", line_2: nil, city: "Oakland", state: "CA", zip: "91234">|
816
+ end
817
+
818
+ line do
819
+ plain "not to match "
820
+ alpha %|#<an object having attributes (line_1: "123 Main St.", city: "Oakland", zip: "91234")>|
821
+ end
822
+ },
823
+ )
824
+
825
+ expect(program).
826
+ to produce_output_when_run(expected_output).
827
+ in_color(color_enabled)
828
+ end
829
+ end
830
+ end
831
+ end
832
+
833
+ context "when the expected value includes a partial object" do
834
+ it "produces the correct failure message when used in the positive" do
835
+ as_both_colored_and_uncolored do |color_enabled|
836
+ snippet = <<~TEST.strip
837
+ expected = {
838
+ name: "Marty McFly",
839
+ shipping_address: an_object_having_attributes(
840
+ line_1: "123 Main St.",
841
+ city: "Oakland",
842
+ state: "CA",
843
+ zip: "91234",
844
+ something_else: "blah"
845
+ )
846
+ }
847
+ actual = {
848
+ name: "Marty McFly",
849
+ shipping_address: SuperDiff::Test::ShippingAddress.new(
850
+ line_1: "456 Ponderosa Ct.",
851
+ line_2: nil,
852
+ city: "Hill Valley",
853
+ state: "CA",
854
+ zip: "90382"
855
+ )
856
+ }
857
+ expect(actual).to match(expected)
858
+ TEST
859
+ program = make_plain_test_program(
860
+ snippet,
861
+ color_enabled: color_enabled,
862
+ )
863
+
864
+ expected_output = build_expected_output(
865
+ color_enabled: color_enabled,
866
+ snippet: %|expect(actual).to match(expected)|,
867
+ expectation: proc {
868
+ line do
869
+ plain "Expected "
870
+ beta %|{ name: "Marty McFly", shipping_address: #<SuperDiff::Test::ShippingAddress line_1: "456 Ponderosa Ct.", line_2: nil, city: "Hill Valley", state: "CA", zip: "90382"> }|
871
+ end
872
+
873
+ line do
874
+ plain "to match "
875
+ alpha %|{ name: "Marty McFly", shipping_address: #<an object having attributes (line_1: "123 Main St.", city: "Oakland", state: "CA", zip: "91234", something_else: "blah")> }|
876
+ end
877
+ },
878
+ diff: proc {
879
+ plain_line %| {|
880
+ plain_line %| name: "Marty McFly",|
881
+ plain_line %| shipping_address: #<SuperDiff::Test::ShippingAddress {|
882
+ alpha_line %|- line_1: "123 Main St.",|
883
+ beta_line %|+ line_1: "456 Ponderosa Ct.",|
884
+ plain_line %| line_2: nil,|
885
+ alpha_line %|- city: "Oakland",|
886
+ beta_line %|+ city: "Hill Valley",|
887
+ plain_line %| state: "CA",|
888
+ # alpha_line %|- zip: "91234",| # FIXME
889
+ alpha_line %|- zip: "91234"|
890
+ beta_line %|+ zip: "90382"|
891
+ alpha_line %|- something_else: "blah"|
892
+ plain_line %| }>|
893
+ plain_line %| }|
894
+ },
895
+ )
896
+
897
+ expect(program).
898
+ to produce_output_when_run(expected_output).
899
+ in_color(color_enabled)
900
+ end
901
+ end
902
+
903
+ it "produces the correct failure message when used the negative" do
904
+ as_both_colored_and_uncolored do |color_enabled|
905
+ snippet = <<~TEST.strip
906
+ expected = {
907
+ name: "Marty McFly",
908
+ shipping_address: an_object_having_attributes(
909
+ line_1: "123 Main St.",
910
+ city: "Oakland",
911
+ state: "CA",
912
+ zip: "91234"
913
+ )
914
+ }
915
+ actual = {
916
+ name: "Marty McFly",
917
+ shipping_address: SuperDiff::Test::ShippingAddress.new(
918
+ line_1: "123 Main St.",
919
+ line_2: nil,
920
+ city: "Oakland",
921
+ state: "CA",
922
+ zip: "91234",
923
+ )
924
+ }
925
+ expect(actual).not_to match(expected)
926
+ TEST
927
+ program = make_plain_test_program(
928
+ snippet,
929
+ color_enabled: color_enabled,
930
+ )
931
+
932
+ expected_output = build_expected_output(
933
+ color_enabled: color_enabled,
934
+ snippet: %|expect(actual).not_to match(expected)|,
935
+ newline_before_expectation: true,
936
+ expectation: proc {
937
+ line do
938
+ plain " Expected "
939
+ beta %|{ name: "Marty McFly", shipping_address: #<SuperDiff::Test::ShippingAddress line_1: "123 Main St.", line_2: nil, city: "Oakland", state: "CA", zip: "91234"> }|
940
+ end
941
+
942
+ line do
943
+ plain "not to match "
944
+ alpha %|{ name: "Marty McFly", shipping_address: #<an object having attributes (line_1: "123 Main St.", city: "Oakland", state: "CA", zip: "91234")> }|
945
+ end
946
+ },
947
+ )
948
+
949
+ expect(program).
950
+ to produce_output_when_run(expected_output).
951
+ in_color(color_enabled)
952
+ end
953
+ end
954
+ end
955
+
956
+ context "when the expected value is an order-independent array" do
957
+ context "that is small" do
958
+ it "produces the correct failure message when used in the positive" do
959
+ as_both_colored_and_uncolored do |color_enabled|
960
+ snippet = <<~TEST.strip
961
+ expected = a_collection_containing_exactly("a")
962
+ actual = ["b"]
963
+ expect(actual).to match(expected)
964
+ TEST
965
+ program = make_plain_test_program(
966
+ snippet,
967
+ color_enabled: color_enabled,
968
+ )
969
+
970
+ expected_output = build_expected_output(
971
+ color_enabled: color_enabled,
972
+ snippet: %|expect(actual).to match(expected)|,
973
+ expectation: proc {
974
+ line do
975
+ plain "Expected "
976
+ beta %|["b"]|
977
+ plain " to match "
978
+ alpha %|#<a collection containing exactly ("a")>|
979
+ plain "."
980
+ end
981
+ },
982
+ diff: proc {
983
+ plain_line %| [|
984
+ plain_line %| "b",|
985
+ alpha_line %|- "a"|
986
+ plain_line %| ]|
987
+ },
988
+ )
989
+
990
+ expect(program).
991
+ to produce_output_when_run(expected_output).
992
+ in_color(color_enabled)
993
+ end
994
+ end
995
+
996
+ it "produces the correct failure message when used in the negative" do
997
+ as_both_colored_and_uncolored do |color_enabled|
998
+ snippet = <<~TEST.strip
999
+ expected = a_collection_containing_exactly("b")
1000
+ actual = ["b"]
1001
+ expect(actual).not_to match(expected)
1002
+ TEST
1003
+ program = make_plain_test_program(
1004
+ snippet,
1005
+ color_enabled: color_enabled,
1006
+ )
1007
+
1008
+ expected_output = build_expected_output(
1009
+ color_enabled: color_enabled,
1010
+ snippet: %|expect(actual).not_to match(expected)|,
1011
+ expectation: proc {
1012
+ line do
1013
+ plain "Expected "
1014
+ beta %|["b"]|
1015
+ plain " not to match "
1016
+ alpha %|#<a collection containing exactly ("b")>|
1017
+ plain "."
1018
+ end
1019
+ },
1020
+ )
1021
+
1022
+ expect(program).
1023
+ to produce_output_when_run(expected_output).
1024
+ in_color(color_enabled)
1025
+ end
1026
+ end
1027
+ end
1028
+
1029
+ context "that is large" do
1030
+ it "produces the correct failure message when used in the positive" do
1031
+ as_both_colored_and_uncolored do |color_enabled|
1032
+ snippet = <<~TEST.strip
1033
+ expected = a_collection_containing_exactly("milk", "bread")
1034
+ actual = ["milk", "toast", "eggs", "cheese", "English muffins"]
1035
+ expect(actual).to match(expected)
1036
+ TEST
1037
+ program = make_plain_test_program(
1038
+ snippet,
1039
+ color_enabled: color_enabled,
1040
+ )
1041
+
1042
+ expected_output = build_expected_output(
1043
+ color_enabled: color_enabled,
1044
+ snippet: %|expect(actual).to match(expected)|,
1045
+ expectation: proc {
1046
+ line do
1047
+ plain "Expected "
1048
+ beta %|["milk", "toast", "eggs", "cheese", "English muffins"]|
1049
+ end
1050
+
1051
+ line do
1052
+ plain "to match "
1053
+ alpha %|#<a collection containing exactly ("milk", "bread")>|
1054
+ end
1055
+ },
1056
+ diff: proc {
1057
+ plain_line %| [|
1058
+ plain_line %| "milk",|
1059
+ plain_line %| "toast",|
1060
+ plain_line %| "eggs",|
1061
+ plain_line %| "cheese",|
1062
+ plain_line %| "English muffins",|
1063
+ alpha_line %|- "bread"|
1064
+ plain_line %| ]|
1065
+ },
1066
+ )
1067
+
1068
+ expect(program).
1069
+ to produce_output_when_run(expected_output).
1070
+ in_color(color_enabled)
1071
+ end
1072
+ end
1073
+
1074
+ it "produces the correct failure message when used in the negative" do
1075
+ as_both_colored_and_uncolored do |color_enabled|
1076
+ snippet = <<~TEST.strip
1077
+ expected = a_collection_containing_exactly("milk", "eggs", "toast")
1078
+ actual = ["milk", "toast", "eggs"]
1079
+ expect(actual).not_to match(expected)
1080
+ TEST
1081
+ program = make_plain_test_program(
1082
+ snippet,
1083
+ color_enabled: color_enabled,
1084
+ )
1085
+
1086
+ expected_output = build_expected_output(
1087
+ color_enabled: color_enabled,
1088
+ snippet: %|expect(actual).not_to match(expected)|,
1089
+ newline_before_expectation: true,
1090
+ expectation: proc {
1091
+ line do
1092
+ plain " Expected "
1093
+ beta %|["milk", "toast", "eggs"]|
1094
+ end
1095
+
1096
+ line do
1097
+ plain "not to match "
1098
+ alpha %|#<a collection containing exactly ("milk", "eggs", "toast")>|
1099
+ end
1100
+ },
1101
+ )
1102
+
1103
+ expect(program).
1104
+ to produce_output_when_run(expected_output).
1105
+ in_color(color_enabled)
1106
+ end
1107
+ end
1108
+ end
1109
+ end
1110
+
1111
+ context "when the expected value includes an order-independent array" do
1112
+ context "and the corresponding actual value is an array" do
1113
+ it "produces the correct failure message when used in the positive" do
1114
+ as_both_colored_and_uncolored do |color_enabled|
1115
+ snippet = <<~TEST.strip
1116
+ expected = {
1117
+ name: "shopping list",
1118
+ contents: a_collection_containing_exactly("milk", "bread")
1119
+ }
1120
+ actual = {
1121
+ name: "shopping list",
1122
+ contents: ["milk", "toast", "eggs"]
1123
+ }
1124
+ expect(actual).to match(expected)
1125
+ TEST
1126
+ program = make_plain_test_program(
1127
+ snippet,
1128
+ color_enabled: color_enabled,
1129
+ )
1130
+
1131
+ expected_output = build_expected_output(
1132
+ color_enabled: color_enabled,
1133
+ snippet: %|expect(actual).to match(expected)|,
1134
+ expectation: proc {
1135
+ line do
1136
+ plain "Expected "
1137
+ beta %|{ name: "shopping list", contents: ["milk", "toast", "eggs"] }|
1138
+ end
1139
+
1140
+ line do
1141
+ plain "to match "
1142
+ alpha %|{ name: "shopping list", contents: #<a collection containing exactly ("milk", "bread")> }|
1143
+ end
1144
+ },
1145
+ diff: proc {
1146
+ plain_line %| {|
1147
+ plain_line %| name: "shopping list",|
1148
+ plain_line %| contents: [|
1149
+ plain_line %| "milk",|
1150
+ plain_line %| "toast",|
1151
+ plain_line %| "eggs",|
1152
+ alpha_line %|- "bread"|
1153
+ plain_line %| ]|
1154
+ plain_line %| }|
1155
+ },
1156
+ )
1157
+
1158
+ expect(program).
1159
+ to produce_output_when_run(expected_output).
1160
+ in_color(color_enabled)
1161
+ end
1162
+ end
1163
+
1164
+ it "produces the correct failure message when used in the negative" do
1165
+ as_both_colored_and_uncolored do |color_enabled|
1166
+ snippet = <<~TEST.strip
1167
+ expected = {
1168
+ name: "shopping list",
1169
+ contents: a_collection_containing_exactly("milk", "eggs", "toast")
1170
+ }
1171
+ actual = {
1172
+ name: "shopping list",
1173
+ contents: ["milk", "toast", "eggs"]
1174
+ }
1175
+ expect(actual).not_to match(expected)
1176
+ TEST
1177
+ program = make_plain_test_program(
1178
+ snippet,
1179
+ color_enabled: color_enabled,
1180
+ )
1181
+
1182
+ expected_output = build_expected_output(
1183
+ color_enabled: color_enabled,
1184
+ snippet: %|expect(actual).not_to match(expected)|,
1185
+ newline_before_expectation: true,
1186
+ expectation: proc {
1187
+ line do
1188
+ plain " Expected "
1189
+ beta %|{ name: "shopping list", contents: ["milk", "toast", "eggs"] }|
1190
+ end
1191
+
1192
+ line do
1193
+ plain "not to match "
1194
+ alpha %|{ name: "shopping list", contents: #<a collection containing exactly ("milk", "eggs", "toast")> }|
1195
+ end
1196
+ },
1197
+ )
1198
+
1199
+ expect(program).
1200
+ to produce_output_when_run(expected_output).
1201
+ in_color(color_enabled)
1202
+ end
1203
+ end
1204
+ end
1205
+
1206
+ context "when the corresponding actual value is not an array" do
1207
+ it "produces the correct failure message" do
1208
+ as_both_colored_and_uncolored do |color_enabled|
1209
+ snippet = <<~TEST.strip
1210
+ expected = {
1211
+ name: "shopping list",
1212
+ contents: a_collection_containing_exactly("milk", "bread")
1213
+ }
1214
+ actual = {
1215
+ name: "shopping list",
1216
+ contents: nil
1217
+ }
1218
+ expect(actual).to match(expected)
1219
+ TEST
1220
+ program = make_plain_test_program(
1221
+ snippet,
1222
+ color_enabled: color_enabled,
1223
+ )
1224
+
1225
+ expected_output = build_expected_output(
1226
+ color_enabled: color_enabled,
1227
+ snippet: %|expect(actual).to match(expected)|,
1228
+ expectation: proc {
1229
+ line do
1230
+ plain "Expected "
1231
+ beta %|{ name: "shopping list", contents: nil }|
1232
+ end
1233
+
1234
+ line do
1235
+ plain "to match "
1236
+ alpha %|{ name: "shopping list", contents: #<a collection containing exactly ("milk", "bread")> }|
1237
+ end
1238
+ },
1239
+ diff: proc {
1240
+ plain_line %! {!
1241
+ plain_line %! name: "shopping list",!
1242
+ alpha_line %!- contents: #<a collection containing exactly (!
1243
+ alpha_line %!- "milk",!
1244
+ alpha_line %!- "bread"!
1245
+ alpha_line %!- )>!
1246
+ beta_line %!+ contents: nil!
1247
+ plain_line %! }!
1248
+ },
1249
+ )
1250
+
1251
+ expect(program).
1252
+ to produce_output_when_run(expected_output).
1253
+ in_color(color_enabled)
1254
+ end
1255
+ end
1256
+ end
1257
+ end
1258
+ end