super_diff 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -1
  3. data/lib/super_diff.rb +27 -6
  4. data/lib/super_diff/active_record.rb +7 -7
  5. data/lib/super_diff/active_record/differs/active_record_relation.rb +3 -13
  6. data/lib/super_diff/active_record/object_inspection.rb +2 -6
  7. data/lib/super_diff/active_record/object_inspection/inspection_tree_builders.rb +16 -0
  8. data/lib/super_diff/active_record/object_inspection/{inspectors → inspection_tree_builders}/active_record_model.rb +19 -20
  9. data/lib/super_diff/active_record/object_inspection/{inspectors → inspection_tree_builders}/active_record_relation.rb +9 -8
  10. data/lib/super_diff/active_record/operation_tree_flatteners.rb +10 -0
  11. data/lib/super_diff/active_record/operation_tree_flatteners/active_record_relation.rb +17 -0
  12. data/lib/super_diff/active_record/operation_trees/active_record_relation.rb +8 -7
  13. data/lib/super_diff/active_support.rb +8 -8
  14. data/lib/super_diff/active_support/differs/hash_with_indifferent_access.rb +3 -13
  15. data/lib/super_diff/active_support/object_inspection.rb +2 -6
  16. data/lib/super_diff/active_support/object_inspection/{inspectors.rb → inspection_tree_builders.rb} +2 -2
  17. data/lib/super_diff/active_support/object_inspection/inspection_tree_builders/hash_with_indifferent_access.rb +37 -0
  18. data/lib/super_diff/active_support/operation_tree_builders/hash_with_indifferent_access.rb +17 -0
  19. data/lib/super_diff/active_support/operation_tree_flatteners.rb +10 -0
  20. data/lib/super_diff/active_support/operation_tree_flatteners/hash_with_indifferent_access.rb +17 -0
  21. data/lib/super_diff/active_support/operation_trees/hash_with_indifferent_access.rb +4 -7
  22. data/lib/super_diff/colorized_document_extensions.rb +9 -6
  23. data/lib/super_diff/configuration.rb +81 -8
  24. data/lib/super_diff/csi.rb +1 -2
  25. data/lib/super_diff/csi/four_bit_color.rb +0 -2
  26. data/lib/super_diff/differs/array.rb +1 -1
  27. data/lib/super_diff/differs/base.rb +3 -21
  28. data/lib/super_diff/differs/custom_object.rb +1 -1
  29. data/lib/super_diff/differs/default_object.rb +1 -1
  30. data/lib/super_diff/differs/hash.rb +1 -1
  31. data/lib/super_diff/differs/main.rb +1 -7
  32. data/lib/super_diff/differs/multiline_string.rb +1 -1
  33. data/lib/super_diff/differs/time_like.rb +1 -1
  34. data/lib/super_diff/equality_matchers/array.rb +2 -2
  35. data/lib/super_diff/equality_matchers/default.rb +2 -2
  36. data/lib/super_diff/equality_matchers/hash.rb +2 -2
  37. data/lib/super_diff/equality_matchers/multiline_string.rb +2 -2
  38. data/lib/super_diff/equality_matchers/primitive.rb +4 -7
  39. data/lib/super_diff/equality_matchers/singleline_string.rb +2 -2
  40. data/lib/super_diff/helpers.rb +52 -2
  41. data/lib/super_diff/line.rb +83 -0
  42. data/lib/super_diff/object_inspection.rb +12 -1
  43. data/lib/super_diff/object_inspection/inspection_tree.rb +183 -81
  44. data/lib/super_diff/object_inspection/inspection_tree_builders.rb +44 -0
  45. data/lib/super_diff/object_inspection/inspection_tree_builders/array.rb +38 -0
  46. data/lib/super_diff/object_inspection/inspection_tree_builders/base.rb +27 -0
  47. data/lib/super_diff/object_inspection/inspection_tree_builders/custom_object.rb +37 -0
  48. data/lib/super_diff/object_inspection/inspection_tree_builders/default_object.rb +63 -0
  49. data/lib/super_diff/object_inspection/{inspectors → inspection_tree_builders}/defaults.rb +1 -2
  50. data/lib/super_diff/object_inspection/inspection_tree_builders/hash.rb +46 -0
  51. data/lib/super_diff/object_inspection/{inspectors → inspection_tree_builders}/main.rb +5 -10
  52. data/lib/super_diff/object_inspection/inspection_tree_builders/primitive.rb +21 -0
  53. data/lib/super_diff/object_inspection/{inspectors → inspection_tree_builders}/time_like.rb +19 -18
  54. data/lib/super_diff/object_inspection/nodes.rb +33 -32
  55. data/lib/super_diff/object_inspection/nodes/as_lines_when_rendering_to_lines.rb +97 -0
  56. data/lib/super_diff/object_inspection/nodes/as_prefix_when_rendering_to_lines.rb +27 -0
  57. data/lib/super_diff/object_inspection/nodes/as_prelude_when_rendering_to_lines.rb +27 -0
  58. data/lib/super_diff/object_inspection/nodes/as_single_line.rb +33 -0
  59. data/lib/super_diff/object_inspection/nodes/base.rb +55 -20
  60. data/lib/super_diff/object_inspection/nodes/inspection.rb +47 -7
  61. data/lib/super_diff/object_inspection/nodes/nesting.rb +16 -5
  62. data/lib/super_diff/object_inspection/nodes/only_when.rb +54 -0
  63. data/lib/super_diff/object_inspection/nodes/text.rb +16 -2
  64. data/lib/super_diff/object_inspection/nodes/when_empty.rb +21 -6
  65. data/lib/super_diff/object_inspection/nodes/when_non_empty.rb +20 -5
  66. data/lib/super_diff/object_inspection/nodes/when_rendering_to_lines.rb +27 -0
  67. data/lib/super_diff/object_inspection/nodes/when_rendering_to_string.rb +27 -0
  68. data/lib/super_diff/object_inspection/prefix_for_next_node.rb +6 -0
  69. data/lib/super_diff/object_inspection/prelude_for_next_node.rb +6 -0
  70. data/lib/super_diff/operation_tree_builders/array.rb +7 -10
  71. data/lib/super_diff/operation_tree_builders/base.rb +6 -6
  72. data/lib/super_diff/operation_tree_builders/custom_object.rb +5 -2
  73. data/lib/super_diff/operation_tree_builders/default_object.rb +1 -1
  74. data/lib/super_diff/operation_tree_builders/hash.rb +0 -7
  75. data/lib/super_diff/operation_tree_builders/multiline_string.rb +2 -6
  76. data/lib/super_diff/operation_tree_flatteners.rb +20 -0
  77. data/lib/super_diff/operation_tree_flatteners/array.rb +15 -0
  78. data/lib/super_diff/operation_tree_flatteners/base.rb +54 -0
  79. data/lib/super_diff/operation_tree_flatteners/collection.rb +139 -0
  80. data/lib/super_diff/operation_tree_flatteners/custom_object.rb +28 -0
  81. data/lib/super_diff/operation_tree_flatteners/default_object.rb +32 -0
  82. data/lib/super_diff/operation_tree_flatteners/hash.rb +41 -0
  83. data/lib/super_diff/operation_tree_flatteners/multiline_string.rb +17 -0
  84. data/lib/super_diff/operation_trees/array.rb +4 -7
  85. data/lib/super_diff/operation_trees/base.rb +39 -16
  86. data/lib/super_diff/operation_trees/custom_object.rb +4 -8
  87. data/lib/super_diff/operation_trees/default_object.rb +28 -13
  88. data/lib/super_diff/operation_trees/hash.rb +4 -7
  89. data/lib/super_diff/operation_trees/main.rb +1 -1
  90. data/lib/super_diff/operation_trees/multiline_string.rb +4 -7
  91. data/lib/super_diff/operations/binary_operation.rb +1 -6
  92. data/lib/super_diff/operations/unary_operation.rb +2 -30
  93. data/lib/super_diff/recursion_guard.rb +3 -3
  94. data/lib/super_diff/rspec.rb +12 -13
  95. data/lib/super_diff/rspec/monkey_patches.rb +2 -2
  96. data/lib/super_diff/rspec/object_inspection.rb +4 -1
  97. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders.rb +44 -0
  98. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/collection_containing_exactly.rb +9 -8
  99. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/collection_including.rb +9 -8
  100. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/double.rb +103 -0
  101. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/hash_including.rb +36 -0
  102. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/instance_of.rb +3 -5
  103. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/kind_of.rb +3 -5
  104. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/object_having_attributes.rb +10 -12
  105. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/primitive.rb +10 -0
  106. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/value_within.rb +33 -0
  107. data/lib/super_diff/rspec/operation_tree_builders/collection_containing_exactly.rb +0 -3
  108. data/lib/super_diff/tiered_lines.rb +4 -0
  109. data/lib/super_diff/tiered_lines_elider.rb +490 -0
  110. data/lib/super_diff/tiered_lines_formatter.rb +79 -0
  111. data/lib/super_diff/version.rb +1 -1
  112. data/spec/examples.txt +407 -410
  113. data/spec/integration/rails/active_support_spec.rb +19 -0
  114. data/spec/integration/rspec/contain_exactly_matcher_spec.rb +12 -6
  115. data/spec/integration/rspec/eq_matcher_spec.rb +22 -88
  116. data/spec/integration/rspec/have_attributes_matcher_spec.rb +6 -7
  117. data/spec/integration/rspec/match_array_matcher_spec.rb +14 -7
  118. data/spec/integration/rspec/match_matcher_spec.rb +10 -5
  119. data/spec/spec_helper.rb +1 -0
  120. data/spec/support/command_runner.rb +15 -25
  121. data/spec/support/helpers.rb +21 -0
  122. data/spec/support/integration/helpers.rb +2 -0
  123. data/spec/support/integration/matchers/produce_output_when_run_matcher.rb +3 -3
  124. data/spec/support/integration/test_programs/base.rb +36 -10
  125. data/spec/support/shared_examples/active_record.rb +3 -2
  126. data/spec/support/shared_examples/active_support.rb +65 -0
  127. data/spec/support/shared_examples/elided_diffs.rb +914 -0
  128. data/spec/support/shared_examples/hash_with_indifferent_access.rb +16 -16
  129. data/spec/support/unit/helpers.rb +15 -0
  130. data/spec/support/unit/matchers/match_output.rb +41 -0
  131. data/spec/unit/active_record/object_inspection_spec.rb +273 -0
  132. data/spec/unit/equality_matchers/main_spec.rb +51 -71
  133. data/spec/unit/helpers_spec.rb +61 -0
  134. data/spec/unit/operation_tree_flatteners/array_spec.rb +604 -0
  135. data/spec/unit/operation_tree_flatteners/custom_object_spec.rb +667 -0
  136. data/spec/unit/operation_tree_flatteners/default_object_spec.rb +687 -0
  137. data/spec/unit/operation_tree_flatteners/hash_spec.rb +632 -0
  138. data/spec/unit/operation_tree_flatteners/multiline_string_spec.rb +121 -0
  139. data/spec/unit/rspec/object_inspection_spec.rb +446 -0
  140. data/spec/unit/super_diff_spec.rb +1488 -846
  141. data/spec/unit/tiered_lines_elider_spec.rb +6356 -0
  142. data/spec/unit/tiered_lines_formatter_spec.rb +193 -0
  143. metadata +88 -50
  144. data/lib/super_diff/active_record/diff_formatters.rb +0 -10
  145. data/lib/super_diff/active_record/diff_formatters/active_record_relation.rb +0 -23
  146. data/lib/super_diff/active_record/object_inspection/inspectors.rb +0 -16
  147. data/lib/super_diff/active_support/diff_formatters.rb +0 -10
  148. data/lib/super_diff/active_support/diff_formatters/hash_with_indifferent_access.rb +0 -36
  149. data/lib/super_diff/active_support/object_inspection/inspectors/hash_with_indifferent_access.rb +0 -28
  150. data/lib/super_diff/diff_formatters.rb +0 -14
  151. data/lib/super_diff/diff_formatters/array.rb +0 -21
  152. data/lib/super_diff/diff_formatters/base.rb +0 -33
  153. data/lib/super_diff/diff_formatters/custom_object.rb +0 -30
  154. data/lib/super_diff/diff_formatters/default_object.rb +0 -46
  155. data/lib/super_diff/diff_formatters/defaults.rb +0 -10
  156. data/lib/super_diff/diff_formatters/hash.rb +0 -34
  157. data/lib/super_diff/diff_formatters/main.rb +0 -41
  158. data/lib/super_diff/object_inspection/inspectors.rb +0 -23
  159. data/lib/super_diff/object_inspection/inspectors/array.rb +0 -32
  160. data/lib/super_diff/object_inspection/inspectors/base.rb +0 -36
  161. data/lib/super_diff/object_inspection/inspectors/custom_object.rb +0 -37
  162. data/lib/super_diff/object_inspection/inspectors/default_object.rb +0 -61
  163. data/lib/super_diff/object_inspection/inspectors/hash.rb +0 -32
  164. data/lib/super_diff/object_inspection/inspectors/primitive.rb +0 -28
  165. data/lib/super_diff/object_inspection/inspectors/string.rb +0 -23
  166. data/lib/super_diff/object_inspection/nodes/break.rb +0 -15
  167. data/lib/super_diff/object_inspection/nodes/when_multiline.rb +0 -22
  168. data/lib/super_diff/object_inspection/nodes/when_singleline.rb +0 -24
  169. data/lib/super_diff/rspec/object_inspection/inspectors.rb +0 -40
  170. data/lib/super_diff/rspec/object_inspection/inspectors/hash_including.rb +0 -36
  171. data/lib/super_diff/rspec/object_inspection/inspectors/primitive.rb +0 -13
  172. data/lib/super_diff/rspec/object_inspection/inspectors/value_within.rb +0 -29
  173. data/spec/support/object_id.rb +0 -27
  174. data/spec/support/ruby_versions.rb +0 -11
@@ -0,0 +1,687 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe SuperDiff::OperationTreeFlatteners::DefaultObject do
4
+ context "given an empty tree" do
5
+ it "returns a set of lines which are simply the open token and close token" do
6
+ operation_tree = SuperDiff::OperationTrees::DefaultObject.new(
7
+ [],
8
+ underlying_object: underlying_object,
9
+ )
10
+
11
+ flattened_operation_tree = described_class.call(operation_tree)
12
+
13
+ expect(flattened_operation_tree).to match([
14
+ an_object_having_attributes(
15
+ type: :noop,
16
+ indentation_level: 0,
17
+ prefix: "",
18
+ value: a_string_matching(
19
+ %r(#<SuperDiff::Test::Item:0x[0-9a-f]+ \{),
20
+ ),
21
+ collection_bookend: :open,
22
+ complete_bookend: :open,
23
+ ),
24
+ an_object_having_attributes(
25
+ type: :noop,
26
+ indentation_level: 0,
27
+ prefix: "",
28
+ value: %(}>),
29
+ collection_bookend: :close,
30
+ complete_bookend: :close,
31
+ ),
32
+ ])
33
+ end
34
+ end
35
+
36
+ context "given a tree of only noops" do
37
+ it "returns a series of lines from inspecting each value, creating multiple lines upon encountering inner data structures" do
38
+ collection = Array.new(3) { :some_value }
39
+ operation_tree = SuperDiff::OperationTrees::DefaultObject.new(
40
+ [
41
+ double(
42
+ :operation,
43
+ name: :noop,
44
+ collection: collection,
45
+ key: :foo,
46
+ value: "bar",
47
+ index: 0,
48
+ ),
49
+ double(
50
+ :operation,
51
+ name: :noop,
52
+ collection: collection,
53
+ key: :baz,
54
+ value: SuperDiff::Test::Item.new(name: 'spatula', quantity: 3),
55
+ index: 1,
56
+ ),
57
+ double(
58
+ :operation,
59
+ name: :noop,
60
+ collection: collection,
61
+ key: :qux,
62
+ value: "blargh",
63
+ index: 2,
64
+ ),
65
+ ],
66
+ underlying_object: underlying_object
67
+ )
68
+
69
+ flattened_operation_tree = described_class.call(operation_tree)
70
+
71
+ expect(flattened_operation_tree).to match([
72
+ an_object_having_attributes(
73
+ type: :noop,
74
+ indentation_level: 0,
75
+ prefix: "",
76
+ value: a_string_matching(
77
+ %r(#<SuperDiff::Test::Item:0x[0-9a-f]+ \{),
78
+ ),
79
+ collection_bookend: :open,
80
+ complete_bookend: :open,
81
+ add_comma: false,
82
+ ),
83
+ an_object_having_attributes(
84
+ type: :noop,
85
+ indentation_level: 1,
86
+ prefix: %(@foo=),
87
+ value: %("bar"),
88
+ add_comma: true,
89
+ ),
90
+ an_object_having_attributes(
91
+ type: :noop,
92
+ indentation_level: 1,
93
+ prefix: %(@baz=),
94
+ value: a_string_matching(
95
+ %r(#<SuperDiff::Test::Item:0x[0-9a-f]+ \{),
96
+ ),
97
+ collection_bookend: :open,
98
+ complete_bookend: nil,
99
+ add_comma: false,
100
+ ),
101
+ an_object_having_attributes(
102
+ type: :noop,
103
+ indentation_level: 2,
104
+ prefix: %(@name=),
105
+ value: %("spatula"),
106
+ add_comma: true,
107
+ ),
108
+ an_object_having_attributes(
109
+ type: :noop,
110
+ indentation_level: 2,
111
+ prefix: %(@quantity=),
112
+ value: %(3),
113
+ add_comma: false,
114
+ ),
115
+ an_object_having_attributes(
116
+ type: :noop,
117
+ indentation_level: 1,
118
+ prefix: "",
119
+ value: %(}>),
120
+ collection_bookend: :close,
121
+ complete_bookend: nil,
122
+ add_comma: true,
123
+ ),
124
+ an_object_having_attributes(
125
+ type: :noop,
126
+ indentation_level: 1,
127
+ prefix: %(@qux=),
128
+ value: %("blargh"),
129
+ add_comma: false,
130
+ ),
131
+ an_object_having_attributes(
132
+ type: :noop,
133
+ indentation_level: 0,
134
+ prefix: "",
135
+ value: %(}>),
136
+ collection_bookend: :close,
137
+ complete_bookend: :close,
138
+ add_comma: false,
139
+ ),
140
+ ])
141
+ end
142
+ end
143
+
144
+ context "given a one-dimensional tree of noops, inserts, and deletes" do
145
+ it "returns a series of lines from inspecting each value, creating multiple lines upon encountering inner data structures" do
146
+ expected = Array.new(3) { :some_value }
147
+ actual = Array.new(4) { :some_value }
148
+ operation_tree = SuperDiff::OperationTrees::DefaultObject.new(
149
+ [
150
+ double(
151
+ :operation,
152
+ name: :delete,
153
+ collection: expected,
154
+ key: :foo,
155
+ value: "bar",
156
+ index: 0,
157
+ ),
158
+ double(
159
+ :operation,
160
+ name: :insert,
161
+ collection: actual,
162
+ key: :foo,
163
+ value: "czar",
164
+ index: 0,
165
+ ),
166
+ double(
167
+ :operation,
168
+ name: :noop,
169
+ collection: actual,
170
+ key: :baz,
171
+ value: SuperDiff::Test::Item.new(name: 'spatula', quantity: 3),
172
+ index: 1,
173
+ ),
174
+ double(
175
+ :operation,
176
+ name: :noop,
177
+ collection: actual,
178
+ key: :qux,
179
+ value: "blargh",
180
+ index: 2,
181
+ ),
182
+ double(
183
+ :operation,
184
+ name: :insert,
185
+ collection: actual,
186
+ key: :sing,
187
+ value: "song",
188
+ index: 3,
189
+ ),
190
+ ],
191
+ underlying_object: underlying_object
192
+ )
193
+
194
+ flattened_operation_tree = described_class.call(operation_tree)
195
+
196
+ expect(flattened_operation_tree).to match([
197
+ an_object_having_attributes(
198
+ type: :noop,
199
+ indentation_level: 0,
200
+ prefix: "",
201
+ value: a_string_matching(
202
+ %r(#<SuperDiff::Test::Item:0x[0-9a-f]+ \{),
203
+ ),
204
+ collection_bookend: :open,
205
+ complete_bookend: :open,
206
+ add_comma: false,
207
+ ),
208
+ an_object_having_attributes(
209
+ type: :delete,
210
+ indentation_level: 1,
211
+ prefix: %(@foo=),
212
+ value: %("bar"),
213
+ add_comma: true,
214
+ ),
215
+ an_object_having_attributes(
216
+ type: :insert,
217
+ indentation_level: 1,
218
+ prefix: %(@foo=),
219
+ value: %("czar"),
220
+ add_comma: true,
221
+ ),
222
+ an_object_having_attributes(
223
+ type: :noop,
224
+ indentation_level: 1,
225
+ prefix: %(@baz=),
226
+ value: a_string_matching(
227
+ %r(#<SuperDiff::Test::Item:0x[0-9a-f]+ \{),
228
+ ),
229
+ collection_bookend: :open,
230
+ complete_bookend: nil,
231
+ add_comma: false,
232
+ ),
233
+ an_object_having_attributes(
234
+ type: :noop,
235
+ indentation_level: 2,
236
+ prefix: %(@name=),
237
+ value: %("spatula"),
238
+ add_comma: true,
239
+ ),
240
+ an_object_having_attributes(
241
+ type: :noop,
242
+ indentation_level: 2,
243
+ prefix: %(@quantity=),
244
+ value: %(3),
245
+ add_comma: false,
246
+ ),
247
+ an_object_having_attributes(
248
+ type: :noop,
249
+ indentation_level: 1,
250
+ prefix: "",
251
+ value: %(}>),
252
+ collection_bookend: :close,
253
+ complete_bookend: nil,
254
+ add_comma: true,
255
+ ),
256
+ an_object_having_attributes(
257
+ type: :noop,
258
+ indentation_level: 1,
259
+ prefix: %(@qux=),
260
+ value: %("blargh"),
261
+ add_comma: true,
262
+ ),
263
+ an_object_having_attributes(
264
+ type: :insert,
265
+ indentation_level: 1,
266
+ prefix: %(@sing=),
267
+ value: %("song"),
268
+ add_comma: false,
269
+ ),
270
+ an_object_having_attributes(
271
+ type: :noop,
272
+ indentation_level: 0,
273
+ prefix: "",
274
+ value: %(}>),
275
+ collection_bookend: :close,
276
+ complete_bookend: :close,
277
+ add_comma: false,
278
+ ),
279
+ ])
280
+ end
281
+ end
282
+
283
+ context "given a multi-dimensional tree of operations" do
284
+ it "splits change operations into multiple lines" do
285
+ collection = Array.new(3) { :some_value }
286
+ subcollection = Array.new(2) { :some_value }
287
+ operation_tree = SuperDiff::OperationTrees::DefaultObject.new(
288
+ [
289
+ double(
290
+ :operation,
291
+ name: :noop,
292
+ collection: collection,
293
+ key: :foo,
294
+ value: "bar",
295
+ index: 0,
296
+ ),
297
+ double(
298
+ :operation,
299
+ name: :change,
300
+ left_collection: collection,
301
+ left_key: :baz,
302
+ left_index: 1,
303
+ right_collection: collection,
304
+ right_key: :baz,
305
+ right_index: 1,
306
+ children: SuperDiff::OperationTrees::DefaultObject.new(
307
+ [
308
+ double(
309
+ :operation,
310
+ name: :noop,
311
+ collection: subcollection,
312
+ key: :one,
313
+ value: "fish",
314
+ index: 0,
315
+ ),
316
+ double(
317
+ :operation,
318
+ name: :delete,
319
+ collection: subcollection,
320
+ key: :two,
321
+ value: "fish",
322
+ index: 1,
323
+ ),
324
+ double(
325
+ :operation,
326
+ name: :insert,
327
+ collection: subcollection,
328
+ key: :blue,
329
+ value: "fish",
330
+ index: 1,
331
+ ),
332
+ ],
333
+ underlying_object: underlying_object,
334
+ ),
335
+ ),
336
+ double(
337
+ :operation,
338
+ name: :noop,
339
+ collection: collection,
340
+ key: :qux,
341
+ value: "blargh",
342
+ index: 2,
343
+ ),
344
+ ],
345
+ underlying_object: underlying_object
346
+ )
347
+
348
+ flattened_operation_tree = described_class.call(operation_tree)
349
+
350
+ expect(flattened_operation_tree).to match([
351
+ an_object_having_attributes(
352
+ type: :noop,
353
+ indentation_level: 0,
354
+ prefix: "",
355
+ value: a_string_matching(
356
+ %r(#<SuperDiff::Test::Item:0x[0-9a-f]+ \{),
357
+ ),
358
+ collection_bookend: :open,
359
+ complete_bookend: :open,
360
+ add_comma: false,
361
+ ),
362
+ an_object_having_attributes(
363
+ type: :noop,
364
+ indentation_level: 1,
365
+ prefix: %(@foo=),
366
+ value: %("bar"),
367
+ add_comma: true,
368
+ ),
369
+ an_object_having_attributes(
370
+ type: :noop,
371
+ indentation_level: 1,
372
+ prefix: %(@baz=),
373
+ value: a_string_matching(
374
+ %r(#<SuperDiff::Test::Item:0x[0-9a-f]+ \{),
375
+ ),
376
+ collection_bookend: :open,
377
+ complete_bookend: nil,
378
+ add_comma: false,
379
+ ),
380
+ an_object_having_attributes(
381
+ type: :noop,
382
+ indentation_level: 2,
383
+ prefix: %(@one=),
384
+ value: %("fish"),
385
+ add_comma: true,
386
+ ),
387
+ an_object_having_attributes(
388
+ type: :delete,
389
+ indentation_level: 2,
390
+ prefix: %(@two=),
391
+ value: %("fish"),
392
+ add_comma: false,
393
+ ),
394
+ an_object_having_attributes(
395
+ type: :insert,
396
+ indentation_level: 2,
397
+ prefix: %(@blue=),
398
+ value: %("fish"),
399
+ add_comma: false,
400
+ ),
401
+ an_object_having_attributes(
402
+ type: :noop,
403
+ indentation_level: 1,
404
+ prefix: "",
405
+ value: %(}>),
406
+ collection_bookend: :close,
407
+ complete_bookend: nil,
408
+ add_comma: true,
409
+ ),
410
+ an_object_having_attributes(
411
+ type: :noop,
412
+ indentation_level: 1,
413
+ prefix: %(@qux=),
414
+ value: %("blargh"),
415
+ add_comma: false,
416
+ ),
417
+ an_object_having_attributes(
418
+ type: :noop,
419
+ indentation_level: 0,
420
+ prefix: "",
421
+ value: %(}>),
422
+ collection_bookend: :close,
423
+ complete_bookend: :close,
424
+ add_comma: false,
425
+ ),
426
+ ])
427
+ end
428
+ end
429
+
430
+ context "given a single-dimensional tree that contains a reference to itself" do
431
+ it "replaces the reference with a static placeholder" do
432
+ left_collection = Array.new(3) { :some_value }
433
+ right_collection = Array.new(2) { :some_value }.tap do |collection|
434
+ collection << right_collection
435
+ end
436
+
437
+ operation_tree = SuperDiff::OperationTrees::DefaultObject.new(
438
+ [
439
+ double(
440
+ :operation,
441
+ name: :noop,
442
+ collection: right_collection,
443
+ key: :foo,
444
+ value: "bar",
445
+ index: 0,
446
+ ),
447
+ double(
448
+ :operation,
449
+ name: :noop,
450
+ collection: right_collection,
451
+ key: :baz,
452
+ value: "qux",
453
+ index: 1,
454
+ ),
455
+ double(
456
+ :operation,
457
+ name: :delete,
458
+ collection: left_collection,
459
+ key: :blargh,
460
+ value: "zig",
461
+ index: 2,
462
+ ),
463
+ double(
464
+ :operation,
465
+ name: :insert,
466
+ collection: right_collection,
467
+ key: :blargh,
468
+ value: right_collection,
469
+ index: 2,
470
+ ),
471
+ ],
472
+ underlying_object: underlying_object,
473
+ )
474
+
475
+ flattened_operation_tree = described_class.call(operation_tree)
476
+
477
+ expect(flattened_operation_tree).to match([
478
+ an_object_having_attributes(
479
+ type: :noop,
480
+ indentation_level: 0,
481
+ prefix: "",
482
+ value: a_string_matching(
483
+ %r(#<SuperDiff::Test::Item:0x[0-9a-f]+ \{),
484
+ ),
485
+ collection_bookend: :open,
486
+ complete_bookend: :open,
487
+ add_comma: false,
488
+ ),
489
+ an_object_having_attributes(
490
+ type: :noop,
491
+ indentation_level: 1,
492
+ prefix: %(@foo=),
493
+ value: %("bar"),
494
+ add_comma: true,
495
+ ),
496
+ an_object_having_attributes(
497
+ type: :noop,
498
+ indentation_level: 1,
499
+ prefix: %(@baz=),
500
+ value: %("qux"),
501
+ add_comma: true,
502
+ ),
503
+ an_object_having_attributes(
504
+ type: :delete,
505
+ indentation_level: 1,
506
+ prefix: %(@blargh=),
507
+ value: %("zig"),
508
+ add_comma: false,
509
+ ),
510
+ an_object_having_attributes(
511
+ type: :insert,
512
+ indentation_level: 1,
513
+ prefix: %(@blargh=),
514
+ value: %(∙∙∙),
515
+ add_comma: false,
516
+ ),
517
+ an_object_having_attributes(
518
+ type: :noop,
519
+ indentation_level: 0,
520
+ prefix: "",
521
+ value: %(}>),
522
+ collection_bookend: :close,
523
+ complete_bookend: :close,
524
+ add_comma: false,
525
+ ),
526
+ ])
527
+ end
528
+ end
529
+
530
+ context "given a multi-dimensional tree that contains a reference to itself in an inner level" do
531
+ it "replaces the reference with a static placeholder" do
532
+ collection = Array.new(3) { :some_value }
533
+ left_subcollection = Array.new(2) { :some_value }
534
+ right_subcollection = Array.new(1) { :some_value }.tap do |coll|
535
+ coll << right_subcollection
536
+ end
537
+
538
+ operation_tree = SuperDiff::OperationTrees::DefaultObject.new(
539
+ [
540
+ double(
541
+ :operation,
542
+ name: :noop,
543
+ collection: collection,
544
+ key: :foo,
545
+ value: "bar",
546
+ index: 0,
547
+ ),
548
+ double(
549
+ :operation,
550
+ name: :change,
551
+ left_collection: collection,
552
+ left_key: :baz,
553
+ left_index: 1,
554
+ right_collection: collection,
555
+ right_key: :baz,
556
+ right_index: 1,
557
+ children: SuperDiff::OperationTrees::DefaultObject.new(
558
+ [
559
+ double(
560
+ :operation,
561
+ name: :noop,
562
+ collection: right_subcollection,
563
+ key: :one,
564
+ value: "fish",
565
+ index: 0,
566
+ ),
567
+ double(
568
+ :operation,
569
+ name: :delete,
570
+ collection: left_subcollection,
571
+ key: :two,
572
+ value: "fish",
573
+ index: 1,
574
+ ),
575
+ double(
576
+ :operation,
577
+ name: :insert,
578
+ collection: right_subcollection,
579
+ key: :two,
580
+ value: right_subcollection,
581
+ index: 1,
582
+ ),
583
+ ],
584
+ underlying_object: underlying_object,
585
+ ),
586
+ ),
587
+ double(
588
+ :operation,
589
+ name: :noop,
590
+ collection: collection,
591
+ key: :qux,
592
+ value: "blargh",
593
+ index: 2,
594
+ ),
595
+ ],
596
+ underlying_object: underlying_object,
597
+ )
598
+
599
+ flattened_operation_tree = described_class.call(operation_tree)
600
+
601
+ expect(flattened_operation_tree).to match([
602
+ an_object_having_attributes(
603
+ type: :noop,
604
+ indentation_level: 0,
605
+ prefix: "",
606
+ value: a_string_matching(
607
+ %r(#<SuperDiff::Test::Item:0x[0-9a-f]+ \{),
608
+ ),
609
+ collection_bookend: :open,
610
+ complete_bookend: :open,
611
+ add_comma: false,
612
+ ),
613
+ an_object_having_attributes(
614
+ type: :noop,
615
+ indentation_level: 1,
616
+ prefix: %(@foo=),
617
+ value: %("bar"),
618
+ add_comma: true,
619
+ ),
620
+ an_object_having_attributes(
621
+ type: :noop,
622
+ indentation_level: 1,
623
+ prefix: %(@baz=),
624
+ value: a_string_matching(
625
+ %r(#<SuperDiff::Test::Item:0x[0-9a-f]+ \{),
626
+ ),
627
+ collection_bookend: :open,
628
+ complete_bookend: nil,
629
+ add_comma: false,
630
+ ),
631
+ an_object_having_attributes(
632
+ type: :noop,
633
+ indentation_level: 2,
634
+ prefix: %(@one=),
635
+ value: %("fish"),
636
+ add_comma: true,
637
+ ),
638
+ an_object_having_attributes(
639
+ type: :delete,
640
+ indentation_level: 2,
641
+ prefix: %(@two=),
642
+ value: %("fish"),
643
+ add_comma: false,
644
+ ),
645
+ an_object_having_attributes(
646
+ type: :insert,
647
+ indentation_level: 2,
648
+ prefix: %(@two=),
649
+ value: %(∙∙∙),
650
+ add_comma: false,
651
+ ),
652
+ an_object_having_attributes(
653
+ type: :noop,
654
+ indentation_level: 1,
655
+ prefix: "",
656
+ value: %(}>),
657
+ collection_bookend: :close,
658
+ complete_bookend: nil,
659
+ add_comma: true,
660
+ ),
661
+ an_object_having_attributes(
662
+ type: :noop,
663
+ indentation_level: 1,
664
+ prefix: %(@qux=),
665
+ value: %("blargh"),
666
+ add_comma: false,
667
+ ),
668
+ an_object_having_attributes(
669
+ type: :noop,
670
+ indentation_level: 0,
671
+ prefix: "",
672
+ value: %(}>),
673
+ collection_bookend: :close,
674
+ complete_bookend: :close,
675
+ add_comma: false,
676
+ ),
677
+ ])
678
+ end
679
+ end
680
+
681
+ def underlying_object
682
+ @_underlying_object ||= SuperDiff::Test::Item.new(
683
+ name: 'whatever',
684
+ quantity: 999,
685
+ )
686
+ end
687
+ end