super_diff 0.3.0 → 0.5.1

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 (189) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +104 -73
  3. data/lib/super_diff.rb +20 -11
  4. data/lib/super_diff/active_record.rb +21 -23
  5. data/lib/super_diff/active_record/diff_formatters/active_record_relation.rb +3 -3
  6. data/lib/super_diff/active_record/differs/active_record_relation.rb +3 -5
  7. data/lib/super_diff/active_record/monkey_patches.rb +9 -0
  8. data/lib/super_diff/active_record/object_inspection/inspectors/active_record_model.rb +32 -22
  9. data/lib/super_diff/active_record/object_inspection/inspectors/active_record_relation.rb +17 -7
  10. data/lib/super_diff/active_record/operation_tree_builders.rb +14 -0
  11. data/lib/super_diff/active_record/{operational_sequencers → operation_tree_builders}/active_record_model.rb +2 -2
  12. data/lib/super_diff/active_record/{operational_sequencers → operation_tree_builders}/active_record_relation.rb +4 -4
  13. data/lib/super_diff/active_record/{operation_sequences.rb → operation_trees.rb} +2 -2
  14. data/lib/super_diff/active_record/{operation_sequences → operation_trees}/active_record_relation.rb +2 -2
  15. data/lib/super_diff/active_support.rb +16 -19
  16. data/lib/super_diff/active_support/diff_formatters/hash_with_indifferent_access.rb +3 -3
  17. data/lib/super_diff/active_support/differs/hash_with_indifferent_access.rb +3 -5
  18. data/lib/super_diff/active_support/object_inspection/inspectors/hash_with_indifferent_access.rb +17 -7
  19. data/lib/super_diff/active_support/operation_tree_builders.rb +10 -0
  20. data/lib/super_diff/active_support/{operational_sequencers → operation_tree_builders}/hash_with_indifferent_access.rb +2 -2
  21. data/lib/super_diff/active_support/{operation_sequences.rb → operation_trees.rb} +2 -2
  22. data/lib/super_diff/active_support/{operation_sequences → operation_trees}/hash_with_indifferent_access.rb +2 -2
  23. data/lib/super_diff/configuration.rb +60 -0
  24. data/lib/super_diff/csi.rb +4 -0
  25. data/lib/super_diff/diff_formatters.rb +3 -3
  26. data/lib/super_diff/diff_formatters/array.rb +3 -3
  27. data/lib/super_diff/diff_formatters/base.rb +3 -2
  28. data/lib/super_diff/diff_formatters/collection.rb +2 -2
  29. data/lib/super_diff/diff_formatters/custom_object.rb +3 -3
  30. data/lib/super_diff/diff_formatters/default_object.rb +6 -8
  31. data/lib/super_diff/diff_formatters/defaults.rb +10 -0
  32. data/lib/super_diff/diff_formatters/hash.rb +3 -3
  33. data/lib/super_diff/diff_formatters/main.rb +41 -0
  34. data/lib/super_diff/diff_formatters/multiline_string.rb +3 -3
  35. data/lib/super_diff/differs.rb +4 -11
  36. data/lib/super_diff/differs/array.rb +2 -11
  37. data/lib/super_diff/differs/base.rb +20 -3
  38. data/lib/super_diff/differs/custom_object.rb +2 -11
  39. data/lib/super_diff/differs/default_object.rb +2 -8
  40. data/lib/super_diff/differs/defaults.rb +12 -0
  41. data/lib/super_diff/differs/hash.rb +2 -11
  42. data/lib/super_diff/differs/main.rb +48 -0
  43. data/lib/super_diff/differs/multiline_string.rb +2 -14
  44. data/lib/super_diff/differs/time_like.rb +15 -0
  45. data/lib/super_diff/equality_matchers.rb +3 -9
  46. data/lib/super_diff/equality_matchers/array.rb +1 -7
  47. data/lib/super_diff/equality_matchers/base.rb +1 -1
  48. data/lib/super_diff/equality_matchers/default.rb +2 -8
  49. data/lib/super_diff/equality_matchers/defaults.rb +12 -0
  50. data/lib/super_diff/equality_matchers/hash.rb +1 -7
  51. data/lib/super_diff/equality_matchers/main.rb +21 -0
  52. data/lib/super_diff/equality_matchers/multiline_string.rb +1 -7
  53. data/lib/super_diff/errors.rb +16 -0
  54. data/lib/super_diff/errors/no_diff_formatter_available_error.rb +21 -0
  55. data/lib/super_diff/errors/no_differ_available_error.rb +24 -0
  56. data/lib/super_diff/errors/no_operational_sequencer_available_error.rb +22 -0
  57. data/lib/super_diff/implementation_checks.rb +19 -0
  58. data/lib/super_diff/object_inspection.rb +1 -10
  59. data/lib/super_diff/object_inspection/inspection_tree.rb +6 -2
  60. data/lib/super_diff/object_inspection/inspectors.rb +5 -1
  61. data/lib/super_diff/object_inspection/inspectors/array.rb +20 -10
  62. data/lib/super_diff/object_inspection/inspectors/base.rb +36 -0
  63. data/lib/super_diff/object_inspection/inspectors/custom_object.rb +24 -14
  64. data/lib/super_diff/object_inspection/inspectors/default_object.rb +44 -30
  65. data/lib/super_diff/object_inspection/inspectors/defaults.rb +15 -0
  66. data/lib/super_diff/object_inspection/inspectors/hash.rb +20 -10
  67. data/lib/super_diff/object_inspection/inspectors/main.rb +35 -0
  68. data/lib/super_diff/object_inspection/inspectors/primitive.rb +20 -5
  69. data/lib/super_diff/object_inspection/inspectors/string.rb +15 -5
  70. data/lib/super_diff/object_inspection/inspectors/time_like.rb +23 -0
  71. data/lib/super_diff/object_inspection/nodes/inspection.rb +9 -2
  72. data/lib/super_diff/operation_tree_builders.rb +18 -0
  73. data/lib/super_diff/{operational_sequencers → operation_tree_builders}/array.rb +38 -59
  74. data/lib/super_diff/operation_tree_builders/base.rb +98 -0
  75. data/lib/super_diff/{operational_sequencers → operation_tree_builders}/custom_object.rb +3 -3
  76. data/lib/super_diff/{operational_sequencers → operation_tree_builders}/default_object.rb +8 -3
  77. data/lib/super_diff/operation_tree_builders/defaults.rb +5 -0
  78. data/lib/super_diff/operation_tree_builders/hash.rb +226 -0
  79. data/lib/super_diff/operation_tree_builders/main.rb +42 -0
  80. data/lib/super_diff/{operational_sequencers → operation_tree_builders}/multiline_string.rb +3 -3
  81. data/lib/super_diff/operation_tree_builders/time_like.rb +34 -0
  82. data/lib/super_diff/operation_trees.rb +13 -0
  83. data/lib/super_diff/{operation_sequences → operation_trees}/array.rb +5 -1
  84. data/lib/super_diff/operation_trees/base.rb +31 -0
  85. data/lib/super_diff/{operation_sequences → operation_trees}/custom_object.rb +5 -1
  86. data/lib/super_diff/{operation_sequences → operation_trees}/default_object.rb +10 -8
  87. data/lib/super_diff/operation_trees/defaults.rb +5 -0
  88. data/lib/super_diff/{operation_sequences → operation_trees}/hash.rb +5 -1
  89. data/lib/super_diff/operation_trees/main.rb +35 -0
  90. data/lib/super_diff/operation_trees/multiline_string.rb +18 -0
  91. data/lib/super_diff/operations/unary_operation.rb +3 -0
  92. data/lib/super_diff/rspec.rb +54 -22
  93. data/lib/super_diff/rspec/augmented_matcher.rb +1 -1
  94. data/lib/super_diff/rspec/differ.rb +2 -17
  95. data/lib/super_diff/rspec/differs.rb +9 -3
  96. data/lib/super_diff/rspec/differs/collection_containing_exactly.rb +3 -8
  97. data/lib/super_diff/rspec/differs/collection_including.rb +18 -0
  98. data/lib/super_diff/rspec/differs/hash_including.rb +18 -0
  99. data/lib/super_diff/rspec/differs/object_having_attributes.rb +17 -0
  100. data/lib/super_diff/rspec/matcher_text_builders.rb +4 -0
  101. data/lib/super_diff/rspec/matcher_text_builders/be_predicate.rb +26 -7
  102. data/lib/super_diff/rspec/matcher_text_builders/have_predicate.rb +61 -0
  103. data/lib/super_diff/rspec/matcher_text_builders/match.rb +1 -1
  104. data/lib/super_diff/rspec/matcher_text_builders/raise_error.rb +13 -1
  105. data/lib/super_diff/rspec/matcher_text_builders/respond_to.rb +1 -1
  106. data/lib/super_diff/rspec/matcher_text_template.rb +1 -1
  107. data/lib/super_diff/rspec/monkey_patches.rb +226 -115
  108. data/lib/super_diff/rspec/object_inspection.rb +0 -1
  109. data/lib/super_diff/rspec/object_inspection/inspectors.rb +22 -6
  110. data/lib/super_diff/rspec/object_inspection/inspectors/collection_containing_exactly.rb +17 -8
  111. data/lib/super_diff/rspec/object_inspection/inspectors/collection_including.rb +28 -0
  112. data/lib/super_diff/rspec/object_inspection/inspectors/hash_including.rb +31 -0
  113. data/lib/super_diff/rspec/object_inspection/inspectors/instance_of.rb +23 -0
  114. data/lib/super_diff/rspec/object_inspection/inspectors/kind_of.rb +23 -0
  115. data/lib/super_diff/rspec/object_inspection/inspectors/object_having_attributes.rb +31 -0
  116. data/lib/super_diff/rspec/object_inspection/inspectors/primitive.rb +13 -0
  117. data/lib/super_diff/rspec/object_inspection/inspectors/value_within.rb +29 -0
  118. data/lib/super_diff/rspec/operation_tree_builders.rb +22 -0
  119. data/lib/super_diff/rspec/{operational_sequencers → operation_tree_builders}/collection_containing_exactly.rb +6 -6
  120. data/lib/super_diff/rspec/{operational_sequencers/partial_array.rb → operation_tree_builders/collection_including.rb} +4 -3
  121. data/lib/super_diff/rspec/operation_tree_builders/hash_including.rb +25 -0
  122. data/lib/super_diff/rspec/{operational_sequencers/partial_object.rb → operation_tree_builders/object_having_attributes.rb} +5 -11
  123. data/lib/super_diff/version.rb +1 -1
  124. data/spec/examples.txt +5 -350
  125. data/spec/integration/rails/active_record_spec.rb +1 -1
  126. data/spec/integration/rails/hash_with_indifferent_access_spec.rb +1 -1
  127. data/spec/integration/rspec/be_predicate_matcher_spec.rb +111 -59
  128. data/spec/integration/rspec/eq_matcher_spec.rb +1 -1
  129. data/spec/integration/rspec/have_attributes_matcher_spec.rb +354 -227
  130. data/spec/integration/rspec/have_predicate_matcher_spec.rb +484 -0
  131. data/spec/integration/rspec/include_matcher_spec.rb +2 -2
  132. data/spec/integration/rspec/match_array_matcher_spec.rb +372 -0
  133. data/spec/integration/rspec/match_matcher_spec.rb +8 -8
  134. data/spec/integration/rspec/raise_error_matcher_spec.rb +605 -226
  135. data/spec/integration/rspec/third_party_matcher_spec.rb +241 -0
  136. data/spec/integration/rspec/unhandled_errors_spec.rb +110 -58
  137. data/spec/spec_helper.rb +18 -7
  138. data/spec/support/command_runner.rb +3 -0
  139. data/spec/support/integration/helpers.rb +14 -90
  140. data/spec/support/integration/matchers.rb +143 -0
  141. data/spec/support/integration/matchers/produce_output_when_run_matcher.rb +14 -29
  142. data/spec/support/integration/test_programs/base.rb +120 -0
  143. data/spec/support/integration/test_programs/plain.rb +13 -0
  144. data/spec/support/integration/test_programs/rspec_active_record.rb +17 -0
  145. data/spec/support/integration/test_programs/rspec_rails.rb +17 -0
  146. data/spec/support/models/active_record/person.rb +4 -11
  147. data/spec/support/models/active_record/query.rb +15 -0
  148. data/spec/support/models/active_record/shipping_address.rb +10 -14
  149. data/spec/support/object_id.rb +27 -0
  150. data/spec/support/ruby_versions.rb +4 -0
  151. data/spec/support/shared_examples/active_record.rb +71 -0
  152. data/spec/support/shared_examples/hash_with_indifferent_access.rb +724 -208
  153. data/spec/unit/{equality_matcher_spec.rb → equality_matchers/main_spec.rb} +165 -9
  154. data/spec/unit/object_inspection_spec.rb +94 -18
  155. data/spec/unit/rspec/matchers/have_predicate_spec.rb +21 -0
  156. data/spec/unit/rspec/matchers/match_array_spec.rb +11 -0
  157. data/spec/unit/rspec/matchers/raise_error_spec.rb +16 -0
  158. data/super_diff.gemspec +4 -6
  159. metadata +99 -82
  160. data/lib/super_diff/active_record/object_inspection/map_extension.rb +0 -18
  161. data/lib/super_diff/active_record/operational_sequencers.rb +0 -14
  162. data/lib/super_diff/active_support/object_inspection/map_extension.rb +0 -15
  163. data/lib/super_diff/active_support/operational_sequencers.rb +0 -10
  164. data/lib/super_diff/diff_formatter.rb +0 -32
  165. data/lib/super_diff/differ.rb +0 -51
  166. data/lib/super_diff/differs/time.rb +0 -24
  167. data/lib/super_diff/equality_matcher.rb +0 -32
  168. data/lib/super_diff/no_differ_available_error.rb +0 -22
  169. data/lib/super_diff/no_operational_sequencer_available_error.rb +0 -20
  170. data/lib/super_diff/object_inspection/inspector.rb +0 -27
  171. data/lib/super_diff/object_inspection/inspectors/time.rb +0 -13
  172. data/lib/super_diff/object_inspection/map.rb +0 -30
  173. data/lib/super_diff/operation_sequences.rb +0 -9
  174. data/lib/super_diff/operation_sequences/base.rb +0 -11
  175. data/lib/super_diff/operational_sequencer.rb +0 -48
  176. data/lib/super_diff/operational_sequencers.rb +0 -17
  177. data/lib/super_diff/operational_sequencers/base.rb +0 -89
  178. data/lib/super_diff/operational_sequencers/hash.rb +0 -85
  179. data/lib/super_diff/operational_sequencers/time_like.rb +0 -30
  180. data/lib/super_diff/rspec/configuration.rb +0 -31
  181. data/lib/super_diff/rspec/differs/partial_array.rb +0 -22
  182. data/lib/super_diff/rspec/differs/partial_hash.rb +0 -22
  183. data/lib/super_diff/rspec/differs/partial_object.rb +0 -22
  184. data/lib/super_diff/rspec/object_inspection/inspectors/partial_array.rb +0 -22
  185. data/lib/super_diff/rspec/object_inspection/inspectors/partial_hash.rb +0 -21
  186. data/lib/super_diff/rspec/object_inspection/inspectors/partial_object.rb +0 -21
  187. data/lib/super_diff/rspec/object_inspection/map_extension.rb +0 -23
  188. data/lib/super_diff/rspec/operational_sequencers.rb +0 -22
  189. data/lib/super_diff/rspec/operational_sequencers/partial_hash.rb +0 -32
@@ -0,0 +1,484 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Integration with RSpec's #have_<predicate> matcher", type: :integration do
4
+ context "when the predicate method doesn't exist on the object" do
5
+ context "when the predicate method doesn't exist on the object" do
6
+ it "produces the correct failure message" do
7
+ as_both_colored_and_uncolored do |color_enabled|
8
+ snippet = %|expect(:words).to have_power|
9
+ program = make_plain_test_program(
10
+ snippet,
11
+ color_enabled: color_enabled,
12
+ )
13
+
14
+ expected_output = build_expected_output(
15
+ color_enabled: color_enabled,
16
+ snippet: snippet,
17
+ expectation: proc {
18
+ line do
19
+ plain "Expected "
20
+ beta %|:words|
21
+ plain " to respond to "
22
+ alpha %|has_power?|
23
+ plain "."
24
+ end
25
+ },
26
+ )
27
+
28
+ expect(program).
29
+ to produce_output_when_run(expected_output).
30
+ in_color(color_enabled)
31
+ end
32
+ end
33
+ end
34
+
35
+ context "when the inspected version of the actual value is long" do
36
+ it "produces the correct failure message" do
37
+ as_both_colored_and_uncolored do |color_enabled|
38
+ snippet = <<~TEST.strip
39
+ hash = { a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }
40
+ expect(hash).to have_mapping
41
+ TEST
42
+ program = make_plain_test_program(
43
+ snippet,
44
+ color_enabled: color_enabled,
45
+ )
46
+
47
+ expected_output = build_expected_output(
48
+ color_enabled: color_enabled,
49
+ snippet: %|expect(hash).to have_mapping|,
50
+ newline_before_expectation: true,
51
+ expectation: proc {
52
+ line do
53
+ plain " Expected "
54
+ beta %|{ a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }|
55
+ end
56
+
57
+ line do
58
+ plain "to respond to "
59
+ alpha %|has_mapping?|
60
+ end
61
+ },
62
+ )
63
+
64
+ expect(program).
65
+ to produce_output_when_run(expected_output).
66
+ in_color(color_enabled)
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ context "when the predicate method exists on the object" do
73
+ context "but is private" do
74
+ context "when the inspected version of the actual value is short" do
75
+ it "produces the correct failure message" do
76
+ as_both_colored_and_uncolored do |color_enabled|
77
+ snippet = <<~TEST.strip
78
+ class Robot
79
+ private def has_arms?; end
80
+ end
81
+
82
+ expect(Robot.new).to have_arms
83
+ TEST
84
+ program = make_plain_test_program(
85
+ snippet,
86
+ color_enabled: color_enabled,
87
+ )
88
+
89
+ expected_output = build_expected_output(
90
+ color_enabled: color_enabled,
91
+ snippet: %|expect(Robot.new).to have_arms|,
92
+ expectation: proc {
93
+ line do
94
+ plain "Expected "
95
+ beta %|#<Robot>|
96
+ plain " to have a public method "
97
+ alpha %|has_arms?|
98
+ plain "."
99
+ end
100
+ },
101
+ )
102
+
103
+ expect(program).
104
+ to produce_output_when_run(expected_output).
105
+ in_color(color_enabled).
106
+ removing_object_ids
107
+ end
108
+ end
109
+ end
110
+
111
+ context "when the inspected version of the actual value is long" do
112
+ it "produces the correct failure message" do
113
+ as_both_colored_and_uncolored do |color_enabled|
114
+ snippet = <<~TEST.strip
115
+ hash = { a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }
116
+
117
+ class << hash
118
+ private def has_mapping?; end
119
+ end
120
+
121
+ expect(hash).to have_mapping
122
+ TEST
123
+ program = make_plain_test_program(
124
+ snippet,
125
+ color_enabled: color_enabled,
126
+ )
127
+
128
+ expected_output = build_expected_output(
129
+ color_enabled: color_enabled,
130
+ snippet: %|expect(hash).to have_mapping|,
131
+ newline_before_expectation: true,
132
+ expectation: proc {
133
+ line do
134
+ plain " Expected "
135
+ beta %|{ a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }|
136
+ end
137
+
138
+ line do
139
+ plain "to have a public method "
140
+ alpha %|has_mapping?|
141
+ end
142
+ },
143
+ )
144
+
145
+ expect(program).
146
+ to produce_output_when_run(expected_output).
147
+ in_color(color_enabled).
148
+ removing_object_ids
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ context "and is public" do
155
+ context "and returns false" do
156
+ context "and takes arguments" do
157
+ context "when the inspected version of the actual value is short" do
158
+ it "produces the correct failure message" do
159
+ as_both_colored_and_uncolored do |color_enabled|
160
+ snippet = <<~TEST.strip
161
+ class Drink
162
+ def has_ingredients?(*); false; end
163
+ end
164
+
165
+ expect(Drink.new).to have_ingredients(:vodka)
166
+ TEST
167
+ program = make_plain_test_program(
168
+ snippet,
169
+ color_enabled: color_enabled,
170
+ )
171
+
172
+ expected_output = build_expected_output(
173
+ color_enabled: color_enabled,
174
+ snippet: %|expect(Drink.new).to have_ingredients(:vodka)|,
175
+ expectation: proc {
176
+ line do
177
+ plain "Expected "
178
+ beta %|#<Drink>|
179
+ plain " to return a truthy result for "
180
+ alpha %|has_ingredients?(:vodka)|
181
+ plain "."
182
+ end
183
+ },
184
+ )
185
+
186
+ expect(program).
187
+ to produce_output_when_run(expected_output).
188
+ in_color(color_enabled).
189
+ removing_object_ids
190
+ end
191
+ end
192
+ end
193
+
194
+ context "when the inspected version of the actual value is long" do
195
+ it "produces the correct failure message" do
196
+ as_both_colored_and_uncolored do |color_enabled|
197
+ snippet = <<~TEST.strip
198
+ hash = { a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }
199
+
200
+ class << hash
201
+ def has_contents?(*args); false; end
202
+ end
203
+
204
+ expect(hash).to have_contents("keys", "upon", "keys")
205
+ TEST
206
+ program = make_plain_test_program(
207
+ snippet,
208
+ color_enabled: color_enabled,
209
+ )
210
+
211
+ expected_output = build_expected_output(
212
+ color_enabled: color_enabled,
213
+ snippet: %|expect(hash).to have_contents("keys", "upon", "keys")|,
214
+ newline_before_expectation: true,
215
+ expectation: proc {
216
+ line do
217
+ plain " Expected "
218
+ beta %|{ a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }|
219
+ end
220
+
221
+ line do
222
+ plain "to return a truthy result for "
223
+ alpha %|has_contents?("keys", "upon", "keys")|
224
+ end
225
+ },
226
+ )
227
+
228
+ expect(program).
229
+ to produce_output_when_run(expected_output).
230
+ in_color(color_enabled).
231
+ removing_object_ids
232
+ end
233
+ end
234
+ end
235
+ end
236
+
237
+ context "and takes no arguments" do
238
+ context "when the inspected version of the actual value is short" do
239
+ it "produces the correct failure message" do
240
+ as_both_colored_and_uncolored do |color_enabled|
241
+ snippet = <<~TEST.strip
242
+ class Robot
243
+ def has_arms?; false; end
244
+ end
245
+
246
+ expect(Robot.new).to have_arms
247
+ TEST
248
+ program = make_plain_test_program(
249
+ snippet,
250
+ color_enabled: color_enabled,
251
+ )
252
+
253
+ expected_output = build_expected_output(
254
+ color_enabled: color_enabled,
255
+ snippet: %|expect(Robot.new).to have_arms|,
256
+ expectation: proc {
257
+ line do
258
+ plain "Expected "
259
+ beta %|#<Robot>|
260
+ plain " to return a truthy result for "
261
+ alpha %|has_arms?|
262
+ plain "."
263
+ end
264
+ },
265
+ )
266
+
267
+ expect(program).
268
+ to produce_output_when_run(expected_output).
269
+ in_color(color_enabled).
270
+ removing_object_ids
271
+ end
272
+ end
273
+ end
274
+
275
+ context "when the inspected version of the actual value is long" do
276
+ it "produces the correct failure message" do
277
+ as_both_colored_and_uncolored do |color_enabled|
278
+ snippet = <<~TEST.strip
279
+ hash = { a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }
280
+
281
+ class << hash
282
+ def has_mapping?; false; end
283
+ end
284
+
285
+ expect(hash).to have_mapping
286
+ TEST
287
+ program = make_plain_test_program(
288
+ snippet,
289
+ color_enabled: color_enabled,
290
+ )
291
+
292
+ expected_output = build_expected_output(
293
+ color_enabled: color_enabled,
294
+ snippet: %|expect(hash).to have_mapping|,
295
+ newline_before_expectation: true,
296
+ expectation: proc {
297
+ line do
298
+ plain " Expected "
299
+ beta %|{ a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }|
300
+ end
301
+
302
+ line do
303
+ plain "to return a truthy result for "
304
+ alpha %|has_mapping?|
305
+ end
306
+ },
307
+ )
308
+
309
+ expect(program).
310
+ to produce_output_when_run(expected_output).
311
+ in_color(color_enabled).
312
+ removing_object_ids
313
+ end
314
+ end
315
+ end
316
+ end
317
+ end
318
+
319
+ context "and returns true" do
320
+ context "and takes arguments" do
321
+ context "when the inspected version of the actual value is short" do
322
+ it "produces the correct failure message" do
323
+ as_both_colored_and_uncolored do |color_enabled|
324
+ snippet = <<~TEST.strip
325
+ class Drink
326
+ def has_ingredients?(*); true; end
327
+ end
328
+
329
+ expect(Drink.new).not_to have_ingredients(:vodka)
330
+ TEST
331
+ program = make_plain_test_program(
332
+ snippet,
333
+ color_enabled: color_enabled,
334
+ )
335
+
336
+ expected_output = build_expected_output(
337
+ color_enabled: color_enabled,
338
+ snippet: %|expect(Drink.new).not_to have_ingredients(:vodka)|,
339
+ expectation: proc {
340
+ line do
341
+ plain "Expected "
342
+ beta %|#<Drink>|
343
+ plain " not to return a truthy result for "
344
+ alpha %|has_ingredients?(:vodka)|
345
+ plain "."
346
+ end
347
+ },
348
+ )
349
+
350
+ expect(program).
351
+ to produce_output_when_run(expected_output).
352
+ in_color(color_enabled).
353
+ removing_object_ids
354
+ end
355
+ end
356
+ end
357
+
358
+ context "when the inspected version of the actual value is long" do
359
+ it "produces the correct failure message" do
360
+ as_both_colored_and_uncolored do |color_enabled|
361
+ snippet = <<~TEST.strip
362
+ hash = { a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }
363
+
364
+ class << hash
365
+ def has_contents?(*args); true; end
366
+ end
367
+
368
+ expect(hash).not_to have_contents("keys", "upon", "keys")
369
+ TEST
370
+ program = make_plain_test_program(
371
+ snippet,
372
+ color_enabled: color_enabled,
373
+ )
374
+
375
+ expected_output = build_expected_output(
376
+ color_enabled: color_enabled,
377
+ snippet: %|expect(hash).not_to have_contents("keys", "upon", "keys")|,
378
+ newline_before_expectation: true,
379
+ expectation: proc {
380
+ line do
381
+ plain " Expected "
382
+ beta %|{ a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }|
383
+ end
384
+
385
+ line do
386
+ plain "not to return a truthy result for "
387
+ alpha %|has_contents?("keys", "upon", "keys")|
388
+ end
389
+ },
390
+ )
391
+
392
+ expect(program).
393
+ to produce_output_when_run(expected_output).
394
+ in_color(color_enabled).
395
+ removing_object_ids
396
+ end
397
+ end
398
+ end
399
+ end
400
+
401
+ context "and takes no arguments" do
402
+ context "when the inspected version of the actual value is short" do
403
+ it "produces the correct failure message when used in the negative" do
404
+ as_both_colored_and_uncolored do |color_enabled|
405
+ snippet = <<~TEST.strip
406
+ class Robot
407
+ def has_arms?; true; end
408
+ end
409
+
410
+ expect(Robot.new).not_to have_arms
411
+ TEST
412
+ program = make_plain_test_program(
413
+ snippet,
414
+ color_enabled: color_enabled,
415
+ )
416
+
417
+ expected_output = build_expected_output(
418
+ color_enabled: color_enabled,
419
+ snippet: %|expect(Robot.new).not_to have_arms|,
420
+ expectation: proc {
421
+ line do
422
+ plain "Expected "
423
+ beta %|#<Robot>|
424
+ plain " not to return a truthy result for "
425
+ alpha %|has_arms?|
426
+ plain "."
427
+ end
428
+ },
429
+ )
430
+
431
+ expect(program).
432
+ to produce_output_when_run(expected_output).
433
+ in_color(color_enabled).
434
+ removing_object_ids
435
+ end
436
+ end
437
+ end
438
+
439
+ context "when the inspected version of the actual value is long" do
440
+ it "produces the correct failure message when used in the negative" do
441
+ as_both_colored_and_uncolored do |color_enabled|
442
+ snippet = <<~TEST.strip
443
+ hash = { a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }
444
+
445
+ class << hash
446
+ def has_mapping?; true; end
447
+ end
448
+
449
+ expect(hash).not_to have_mapping
450
+ TEST
451
+ program = make_plain_test_program(
452
+ snippet,
453
+ color_enabled: color_enabled,
454
+ )
455
+
456
+ expected_output = build_expected_output(
457
+ color_enabled: color_enabled,
458
+ snippet: %|expect(hash).not_to have_mapping|,
459
+ newline_before_expectation: true,
460
+ expectation: proc {
461
+ line do
462
+ plain " Expected "
463
+ beta %|{ a: "lot", of: "keys", and: "things", like: "that", lets: "add", more: "keys" }|
464
+ end
465
+
466
+ line do
467
+ plain "not to return a truthy result for "
468
+ alpha %|has_mapping?|
469
+ end
470
+ },
471
+ )
472
+
473
+ expect(program).
474
+ to produce_output_when_run(expected_output).
475
+ in_color(color_enabled).
476
+ removing_object_ids
477
+ end
478
+ end
479
+ end
480
+ end
481
+ end
482
+ end
483
+ end
484
+ end