diff-lcs 2.0.0.beta.1 → 2.0.0.beta.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -5
- data/CONTRIBUTING.md +8 -3
- data/CONTRIBUTORS.md +19 -9
- data/Manifest.txt +88 -70
- data/README.md +13 -9
- data/Rakefile +90 -22
- data/SECURITY.md +1 -10
- data/integration/compare/array_diff_spec.rb +10 -0
- data/integration/compare/hash_diff_spec.rb +25 -0
- data/integration/compare/string_diff_spec.rb +10 -0
- data/integration/rspec_differ_spec.rb +26 -0
- data/integration/rspec_expectations_spec.rb +32 -0
- data/integration/runner +20 -0
- data/lib/diff/lcs/change.rb +21 -16
- data/lib/diff/lcs/ldiff.rb +9 -4
- data/lib/diff/lcs/version.rb +1 -1
- data/spec/hunk_spec.rb +32 -34
- data/spec/ldiff_spec.rb +7 -7
- data/spec/spec_helper.rb +4 -12
- data/test/fixtures/ldiff/output.diff-c +7 -0
- data/test/fixtures/ldiff/output.diff-u +5 -0
- data/test/fixtures/ldiff/output.diff.bin2 +1 -0
- data/test/fixtures/ldiff/output.diff.bin2-c +1 -0
- data/test/fixtures/ldiff/output.diff.bin2-e +1 -0
- data/test/fixtures/ldiff/output.diff.bin2-f +1 -0
- data/test/fixtures/ldiff/output.diff.bin2-u +1 -0
- data/{spec → test}/fixtures/ldiff/output.diff.chef-c +2 -2
- data/test/fixtures/ldiff/output.diff.chef-u +9 -0
- data/{spec → test}/fixtures/ldiff/output.diff.chef2-c +2 -2
- data/{spec → test}/fixtures/ldiff/output.diff.chef2-u +2 -2
- data/test/fixtures/ldiff/output.diff.empty.vs.four_lines-c +9 -0
- data/test/fixtures/ldiff/output.diff.empty.vs.four_lines-u +7 -0
- data/test/fixtures/ldiff/output.diff.four_lines.vs.empty-c +9 -0
- data/test/fixtures/ldiff/output.diff.four_lines.vs.empty-u +7 -0
- data/test/fixtures/ldiff/output.diff.issue95_trailing_context-c +9 -0
- data/test/fixtures/ldiff/output.diff.issue95_trailing_context-u +6 -0
- data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line1-c +2 -2
- data/test/fixtures/ldiff/output.diff.missing_new_line1-u +9 -0
- data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line2-c +2 -2
- data/test/fixtures/ldiff/output.diff.missing_new_line2-u +9 -0
- data/test/test_block.rb +34 -0
- data/test/test_change.rb +234 -0
- data/test/test_diff.rb +53 -0
- data/test/test_helper.rb +225 -0
- data/test/test_hunk.rb +72 -0
- data/test/test_issues.rb +168 -0
- data/test/test_lcs.rb +47 -0
- data/test/test_ldiff.rb +89 -0
- data/test/test_patch.rb +362 -0
- data/test/test_sdiff.rb +167 -0
- data/test/test_traverse_balanced.rb +322 -0
- data/test/test_traverse_sequences.rb +187 -0
- metadata +130 -96
- data/spec/fixtures/ldiff/output.diff-c +0 -7
- data/spec/fixtures/ldiff/output.diff-u +0 -5
- data/spec/fixtures/ldiff/output.diff.bin2 +0 -1
- data/spec/fixtures/ldiff/output.diff.bin2-c +0 -1
- data/spec/fixtures/ldiff/output.diff.bin2-e +0 -1
- data/spec/fixtures/ldiff/output.diff.bin2-f +0 -1
- data/spec/fixtures/ldiff/output.diff.bin2-u +0 -1
- data/spec/fixtures/ldiff/output.diff.chef-u +0 -9
- data/spec/fixtures/ldiff/output.diff.empty.vs.four_lines-c +0 -9
- data/spec/fixtures/ldiff/output.diff.empty.vs.four_lines-u +0 -7
- data/spec/fixtures/ldiff/output.diff.four_lines.vs.empty-c +0 -9
- data/spec/fixtures/ldiff/output.diff.four_lines.vs.empty-u +0 -7
- data/spec/fixtures/ldiff/output.diff.issue95_trailing_context-c +0 -9
- data/spec/fixtures/ldiff/output.diff.issue95_trailing_context-u +0 -6
- data/spec/fixtures/ldiff/output.diff.missing_new_line1-u +0 -9
- data/spec/fixtures/ldiff/output.diff.missing_new_line2-u +0 -9
- /data/{spec → test}/fixtures/123_x +0 -0
- /data/{spec → test}/fixtures/456_x +0 -0
- /data/{spec → test}/fixtures/aX +0 -0
- /data/{spec → test}/fixtures/bXaX +0 -0
- /data/{spec → test}/fixtures/ds1.csv +0 -0
- /data/{spec → test}/fixtures/ds2.csv +0 -0
- /data/{spec → test}/fixtures/empty +0 -0
- /data/{spec → test}/fixtures/file1.bin +0 -0
- /data/{spec → test}/fixtures/file2.bin +0 -0
- /data/{spec → test}/fixtures/four_lines +0 -0
- /data/{spec → test}/fixtures/four_lines_with_missing_new_line +0 -0
- /data/{spec → test}/fixtures/ldiff/diff.missing_new_line1-e +0 -0
- /data/{spec → test}/fixtures/ldiff/diff.missing_new_line1-f +0 -0
- /data/{spec → test}/fixtures/ldiff/diff.missing_new_line2-e +0 -0
- /data/{spec → test}/fixtures/ldiff/diff.missing_new_line2-f +0 -0
- /data/{spec → test}/fixtures/ldiff/error.diff.chef-e +0 -0
- /data/{spec → test}/fixtures/ldiff/error.diff.chef-f +0 -0
- /data/{spec → test}/fixtures/ldiff/error.diff.missing_new_line1-e +0 -0
- /data/{spec → test}/fixtures/ldiff/error.diff.missing_new_line1-f +0 -0
- /data/{spec → test}/fixtures/ldiff/error.diff.missing_new_line2-e +0 -0
- /data/{spec → test}/fixtures/ldiff/error.diff.missing_new_line2-f +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.bin1 +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.bin1-c +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.bin1-e +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.bin1-f +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.bin1-u +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.chef +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.chef2 +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.chef2-d +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.empty.vs.four_lines +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.empty.vs.four_lines-e +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.empty.vs.four_lines-f +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.four_lines.vs.empty +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.four_lines.vs.empty-e +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.four_lines.vs.empty-f +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.issue95_trailing_context +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.issue95_trailing_context-e +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.issue95_trailing_context-f +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line1 +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line1-e +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line1-f +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line2 +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line2-e +0 -0
- /data/{spec → test}/fixtures/ldiff/output.diff.missing_new_line2-f +0 -0
- /data/{spec → test}/fixtures/new-chef +0 -0
- /data/{spec → test}/fixtures/new-chef2 +0 -0
- /data/{spec → test}/fixtures/old-chef +0 -0
- /data/{spec → test}/fixtures/old-chef2 +0 -0
data/test/test_change.rb
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class TestChange < Minitest::Test
|
|
6
|
+
def test_invalid_change
|
|
7
|
+
assert_raises RuntimeError, /Invalid CHange Action/ do
|
|
8
|
+
change("~", 0, "element")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
assert_raises RuntimeError, /Invalid Position Type/ do
|
|
12
|
+
change("+", 3.5, "element")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_from_a
|
|
17
|
+
assert_kind_of Diff::LCS::Change, change_from_a(["+", 0, "element"])
|
|
18
|
+
assert_kind_of Diff::LCS::Change, change_from_a(["+", 0, "element"], Diff::LCS::ContextChange)
|
|
19
|
+
assert_kind_of Diff::LCS::ContextChange,
|
|
20
|
+
change_from_a(["!", [1, "old_element"], [2, "new_element"]])
|
|
21
|
+
assert_kind_of Diff::LCS::ContextChange,
|
|
22
|
+
change_from_a(["!", [1, "old_element"], [2, "new_element"]], Diff::LCS::ContextChange)
|
|
23
|
+
|
|
24
|
+
assert_raises RuntimeError, "Invalid change array format provided." do
|
|
25
|
+
change_from_a(["+", 0])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
assert_raises RuntimeError, "Invalid change array format provided." do
|
|
29
|
+
change_from_a(["+", 0], Diff::LCS::ContextChange)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_spaceship_reflexive
|
|
34
|
+
c1 = change("=", 5, "x")
|
|
35
|
+
c2 = change("=", 5, "x")
|
|
36
|
+
assert_equal 0, c1 <=> c2
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_spaceship_position_precedence
|
|
40
|
+
c1 = change("=", 5, "x")
|
|
41
|
+
c2 = change("=", 10, "x")
|
|
42
|
+
|
|
43
|
+
assert_equal(-1, c1 <=> c2)
|
|
44
|
+
assert_equal 1, c2 <=> c1
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_spaceship_action_precedence
|
|
48
|
+
valid_actions.each_cons(2) do |a1, a2|
|
|
49
|
+
c1 = change(a1, 5, "x")
|
|
50
|
+
c2 = change(a2, 5, "x")
|
|
51
|
+
|
|
52
|
+
assert_equal(-1, c1 <=> c2, "#{a1} should sort before #{a2}")
|
|
53
|
+
assert_equal 1, c2 <=> c1
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_spaceship_element_precedence
|
|
58
|
+
c1 = change("=", 5, "a")
|
|
59
|
+
c2 = change("=", 5, "z")
|
|
60
|
+
|
|
61
|
+
assert_equal(-1, c1 <=> c2)
|
|
62
|
+
assert_equal 1, c2 <=> c1
|
|
63
|
+
assert_equal 0, c1 <=> change("=", 5, "a")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_add
|
|
67
|
+
change = change("+", 0, "element")
|
|
68
|
+
|
|
69
|
+
assert change.adding?
|
|
70
|
+
|
|
71
|
+
refute change.deleting?
|
|
72
|
+
refute change.unchanged?
|
|
73
|
+
refute change.changed?
|
|
74
|
+
refute change.finished_a?
|
|
75
|
+
refute change.finished_b?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_delete
|
|
79
|
+
change = change("-", 0, "element")
|
|
80
|
+
|
|
81
|
+
assert change.deleting?
|
|
82
|
+
|
|
83
|
+
refute change.adding?
|
|
84
|
+
refute change.unchanged?
|
|
85
|
+
refute change.changed?
|
|
86
|
+
refute change.finished_a?
|
|
87
|
+
refute change.finished_b?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_unchanged
|
|
91
|
+
change = change("=", 0, "element")
|
|
92
|
+
|
|
93
|
+
assert change.unchanged?
|
|
94
|
+
|
|
95
|
+
refute change.deleting?
|
|
96
|
+
refute change.adding?
|
|
97
|
+
refute change.changed?
|
|
98
|
+
refute change.finished_a?
|
|
99
|
+
refute change.finished_b?
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_changed
|
|
103
|
+
change = change("!", 0, "element")
|
|
104
|
+
|
|
105
|
+
assert change.changed?
|
|
106
|
+
|
|
107
|
+
refute change.deleting?
|
|
108
|
+
refute change.adding?
|
|
109
|
+
refute change.unchanged?
|
|
110
|
+
refute change.finished_a?
|
|
111
|
+
refute change.finished_b?
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def test_finished_a
|
|
115
|
+
change = change(">", 0, "element")
|
|
116
|
+
|
|
117
|
+
assert change.finished_a?
|
|
118
|
+
|
|
119
|
+
refute change.deleting?
|
|
120
|
+
refute change.adding?
|
|
121
|
+
refute change.unchanged?
|
|
122
|
+
refute change.changed?
|
|
123
|
+
refute change.finished_b?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_finished_b
|
|
127
|
+
change = change("<", 0, "element")
|
|
128
|
+
|
|
129
|
+
assert change.finished_b?
|
|
130
|
+
|
|
131
|
+
refute change.deleting?
|
|
132
|
+
refute change.adding?
|
|
133
|
+
refute change.unchanged?
|
|
134
|
+
refute change.changed?
|
|
135
|
+
refute change.finished_a?
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def test_as_array
|
|
139
|
+
action, position, element = change("!", 0, "element")
|
|
140
|
+
assert_equal "!", action
|
|
141
|
+
assert_equal 0, position
|
|
142
|
+
assert_equal "element", element
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
class TestContextChange < Minitest::Test
|
|
147
|
+
private def change(...) = Diff::LCS::ContextChange.new(...)
|
|
148
|
+
private def simplify(...) = Diff::LCS::ContextChange.simplify(change(...))
|
|
149
|
+
|
|
150
|
+
def test_invalid_change
|
|
151
|
+
assert_raises RuntimeError, /Invalid CHange Action/ do
|
|
152
|
+
change("~", 0, "old", 0, "new")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
assert_raises RuntimeError, /Invalid Position Type/ do
|
|
156
|
+
change("+", 3.5, "old", 0, "new")
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
assert_raises RuntimeError, /Invalid Position Type/ do
|
|
160
|
+
change("+", 0, "old", 3.5, "new")
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def test_as_array
|
|
165
|
+
action, old, new = change("!", 1, "old_element", 2, "new_element")
|
|
166
|
+
|
|
167
|
+
assert_equal "!", action
|
|
168
|
+
assert_equal [1, "old_element"], old
|
|
169
|
+
assert_equal [2, "new_element"], new
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def test_spaceship_reflexive
|
|
173
|
+
c1 = change("=", 5, "x", 10, "y")
|
|
174
|
+
c2 = change("=", 5, "x", 10, "y")
|
|
175
|
+
assert_equal 0, c1 <=> c2
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def test_spaceship_position_precedence
|
|
179
|
+
c1 = change("=", 5, "x", 10, "y")
|
|
180
|
+
c2 = change("=", 15, "x", 10, "y")
|
|
181
|
+
|
|
182
|
+
assert_equal(-1, c1 <=> c2)
|
|
183
|
+
assert_equal 1, c2 <=> c1
|
|
184
|
+
|
|
185
|
+
c1 = change("=", 5, "x", 10, "y")
|
|
186
|
+
c2 = change("=", 5, "x", 20, "y")
|
|
187
|
+
|
|
188
|
+
assert_equal(-1, c1 <=> c2)
|
|
189
|
+
assert_equal 1, c2 <=> c1
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def test_spaceship_action_precedence
|
|
193
|
+
valid_actions.each_cons(2) do |a1, a2|
|
|
194
|
+
c1 = change(a1, 5, "x", 10, "y")
|
|
195
|
+
c2 = change(a2, 5, "x", 10, "y")
|
|
196
|
+
|
|
197
|
+
assert_equal(-1, c1 <=> c2, "#{a1} should sort before #{a2}")
|
|
198
|
+
assert_equal 1, c2 <=> c1
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def test_spaceship_element_precedence
|
|
203
|
+
c1 = change("=", 5, "a", 10, "y")
|
|
204
|
+
c2 = change("=", 5, "z", 10, "y")
|
|
205
|
+
|
|
206
|
+
assert_equal(-1, c1 <=> c2, "old_element precedence")
|
|
207
|
+
assert_equal 1, c2 <=> c1
|
|
208
|
+
|
|
209
|
+
c3 = change("=", 5, "x", 10, "a")
|
|
210
|
+
c4 = change("=", 5, "x", 10, "z")
|
|
211
|
+
|
|
212
|
+
assert_equal(-1, c3 <=> c4, "new_element precedence")
|
|
213
|
+
assert_equal 1, c4 <=> c3
|
|
214
|
+
assert_equal 0, c3 <=> Diff::LCS::ContextChange.new("=", 5, "x", 10, "a")
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def test_simplify
|
|
218
|
+
simplify("-", 5, "old", 10, "new") => {action:, new_element:}
|
|
219
|
+
assert_equal action, "-"
|
|
220
|
+
assert_nil new_element
|
|
221
|
+
|
|
222
|
+
simplify("<", 5, "old", 10, "new") => {action:, new_element:}
|
|
223
|
+
assert_equal action, "-"
|
|
224
|
+
assert_nil new_element
|
|
225
|
+
|
|
226
|
+
simplify("+", 5, "old", 10, "new") => {action:, old_element:}
|
|
227
|
+
assert_equal action, "+"
|
|
228
|
+
assert_nil old_element
|
|
229
|
+
|
|
230
|
+
simplify(">", 5, "old", 10, "new") => {action:, old_element:}
|
|
231
|
+
assert_equal action, "+"
|
|
232
|
+
assert_nil old_element
|
|
233
|
+
end
|
|
234
|
+
end
|
data/test/test_diff.rb
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "test_helper"
|
|
4
|
+
|
|
5
|
+
class TestDiff < Minitest::Test
|
|
6
|
+
def test_correctly_diffs_seq1_to_seq2
|
|
7
|
+
assert_equal change_diff(correct_forward_diff), diff(seq1, seq2)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_correctly_diffs_seq2_to_seq1
|
|
11
|
+
assert_equal change_diff(correct_backward_diff), diff(seq2, seq1)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_correctly_diffs_against_empty_sequence_forward
|
|
15
|
+
correct_diff = [
|
|
16
|
+
[
|
|
17
|
+
["-", 0, "abcd"],
|
|
18
|
+
["-", 1, "efgh"],
|
|
19
|
+
["-", 2, "ijkl"],
|
|
20
|
+
["-", 3, "mnopqrstuvwxyz"]
|
|
21
|
+
]
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
assert_equal change_diff(correct_diff), diff(word_sequence, [])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_correctly_diffs_against_empty_sequence_backward
|
|
28
|
+
correct_diff = [
|
|
29
|
+
[
|
|
30
|
+
["+", 0, "abcd"],
|
|
31
|
+
["+", 1, "efgh"],
|
|
32
|
+
["+", 2, "ijkl"],
|
|
33
|
+
["+", 3, "mnopqrstuvwxyz"]
|
|
34
|
+
]
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
assert_equal change_diff(correct_diff), diff([], word_sequence)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_correctly_diffs_xx_and_xaxb
|
|
41
|
+
left = "xx"
|
|
42
|
+
right = "xaxb"
|
|
43
|
+
assert_equal right, patch(left, diff(left, right))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_returns_empty_diff_with_hello_hello
|
|
47
|
+
assert_empty diff(hello, hello)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_returns_empty_diff_with_hello_ary_hello_ary
|
|
51
|
+
assert_empty diff(hello_ary, hello_ary)
|
|
52
|
+
end
|
|
53
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH.unshift File.expand_path(__dir__, "../lib")
|
|
4
|
+
|
|
5
|
+
require "minitest/autorun"
|
|
6
|
+
require "simplecov"
|
|
7
|
+
require "simplecov-lcov"
|
|
8
|
+
require "open3"
|
|
9
|
+
|
|
10
|
+
require "diff/lcs"
|
|
11
|
+
|
|
12
|
+
module Diff::LCS::TestHelper
|
|
13
|
+
def hello = "hello"
|
|
14
|
+
def hello_ary = %w[h e l l o]
|
|
15
|
+
def seq1 = %w[a b c e h j l m n p]
|
|
16
|
+
def skipped_seq1 = %w[a h n p]
|
|
17
|
+
def seq2 = %w[b c d e f j k l m r s t]
|
|
18
|
+
def skipped_seq2 = %w[d f k r s t]
|
|
19
|
+
def word_sequence = %w[abcd efgh ijkl mnopqrstuvwxyz]
|
|
20
|
+
def correct_lcs = %w[b c e j l m]
|
|
21
|
+
|
|
22
|
+
private def change(...) = Diff::LCS::Change.new(...)
|
|
23
|
+
private def change_from_a(array, klass = Diff::LCS::Change) = klass.from_a(array)
|
|
24
|
+
private def diff(...) = Diff::LCS.diff(...)
|
|
25
|
+
private def hunk(...) = Diff::LCS::Hunk.new(...)
|
|
26
|
+
private def internal_lcs(...) = Diff::LCS::Internals.lcs(...)
|
|
27
|
+
private def lcs(...) = Diff::LCS.lcs(...)
|
|
28
|
+
private def patch(...) = Diff::LCS.patch(...)
|
|
29
|
+
private def patch!(...) = Diff::LCS.patch!(...)
|
|
30
|
+
private def sdiff(...) = Diff::LCS.sdiff(...)
|
|
31
|
+
private def traverse_balanced(...) = Diff::LCS.traverse_balanced(...)
|
|
32
|
+
private def traverse_sequences(...) = Diff::LCS.traverse_sequences(...)
|
|
33
|
+
private def unpatch(...) = Diff::LCS.unpatch(...)
|
|
34
|
+
private def unpatch!(...) = Diff::LCS.unpatch!(...)
|
|
35
|
+
private def valid_actions = Diff::LCS::Change::VALID_ACTIONS
|
|
36
|
+
|
|
37
|
+
def correct_forward_diff
|
|
38
|
+
[
|
|
39
|
+
[["-", 0, "a"]],
|
|
40
|
+
[["+", 2, "d"]],
|
|
41
|
+
[["-", 4, "h"], ["+", 4, "f"]],
|
|
42
|
+
[["+", 6, "k"]],
|
|
43
|
+
[["-", 8, "n"], ["+", 9, "r"], ["-", 9, "p"], ["+", 10, "s"], ["+", 11, "t"]]
|
|
44
|
+
]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def correct_backward_diff
|
|
48
|
+
[
|
|
49
|
+
[["+", 0, "a"]],
|
|
50
|
+
[["-", 2, "d"]],
|
|
51
|
+
[["-", 4, "f"], ["+", 4, "h"]],
|
|
52
|
+
[["-", 6, "k"]],
|
|
53
|
+
[["-", 9, "r"], ["+", 8, "n"], ["-", 10, "s"], ["+", 9, "p"], ["-", 11, "t"]]
|
|
54
|
+
]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def correct_forward_sdiff
|
|
58
|
+
[
|
|
59
|
+
["-", [0, "a"], [0, nil]],
|
|
60
|
+
["=", [1, "b"], [0, "b"]],
|
|
61
|
+
["=", [2, "c"], [1, "c"]],
|
|
62
|
+
["+", [3, nil], [2, "d"]],
|
|
63
|
+
["=", [3, "e"], [3, "e"]],
|
|
64
|
+
["!", [4, "h"], [4, "f"]],
|
|
65
|
+
["=", [5, "j"], [5, "j"]],
|
|
66
|
+
["+", [6, nil], [6, "k"]],
|
|
67
|
+
["=", [6, "l"], [7, "l"]],
|
|
68
|
+
["=", [7, "m"], [8, "m"]],
|
|
69
|
+
["!", [8, "n"], [9, "r"]],
|
|
70
|
+
["!", [9, "p"], [10, "s"]],
|
|
71
|
+
["+", [10, nil], [11, "t"]]
|
|
72
|
+
]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def reverse_sdiff(forward_sdiff)
|
|
76
|
+
forward_sdiff.map { |line|
|
|
77
|
+
line[1], line[2] = line[2], line[1]
|
|
78
|
+
case line[0]
|
|
79
|
+
when "-" then line[0] = "+"
|
|
80
|
+
when "+" then line[0] = "-"
|
|
81
|
+
end
|
|
82
|
+
line
|
|
83
|
+
}
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def change_diff(diff) = map_diffs(diff, Diff::LCS::Change)
|
|
87
|
+
def context_diff(diff) = map_diffs(diff, Diff::LCS::ContextChange)
|
|
88
|
+
|
|
89
|
+
def map_diffs(diffs, klass = Diff::LCS::ContextChange)
|
|
90
|
+
diffs.map do |chunks|
|
|
91
|
+
if klass == Diff::LCS::ContextChange
|
|
92
|
+
klass.from_a(chunks)
|
|
93
|
+
else
|
|
94
|
+
chunks.map { |changes| klass.from_a(changes) }
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def balanced_traversal(s1, s2, callback_type)
|
|
100
|
+
callback = __send__(callback_type)
|
|
101
|
+
Diff::LCS.traverse_balanced(s1, s2, callback)
|
|
102
|
+
callback
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def balanced_reverse(change_result)
|
|
106
|
+
new_result = []
|
|
107
|
+
change_result.each do |line|
|
|
108
|
+
line = [line[0], line[2], line[1]]
|
|
109
|
+
case line[0]
|
|
110
|
+
when "<" then line[0] = ">"
|
|
111
|
+
when ">" then line[0] = "<"
|
|
112
|
+
end
|
|
113
|
+
new_result << line
|
|
114
|
+
end
|
|
115
|
+
new_result.sort_by { |line| [line[1], line[2]] }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def map_to_no_change(change_result)
|
|
119
|
+
new_result = []
|
|
120
|
+
change_result.each do |line|
|
|
121
|
+
case line[0]
|
|
122
|
+
when "!"
|
|
123
|
+
new_result << ["<", line[1], line[2]]
|
|
124
|
+
new_result << [">", line[1] + 1, line[2]]
|
|
125
|
+
else
|
|
126
|
+
new_result << line
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
new_result
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def assert_nil_or_match_values(ee, ii, s1, s2)
|
|
133
|
+
assert(ee.nil? || s1[ii] == s2[ee])
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def assert_correctly_maps_sequence(actual, s1, s2)
|
|
137
|
+
actual.each_index { |ii| assert_nil_or_match_values(actual[ii], ii, s1, s2) }
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
class SimpleCallback
|
|
141
|
+
attr_reader :matched_a, :matched_b, :discards_a, :discards_b, :done_a, :done_b
|
|
142
|
+
|
|
143
|
+
def initialize
|
|
144
|
+
reset
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def reset
|
|
148
|
+
@matched_a = []
|
|
149
|
+
@matched_b = []
|
|
150
|
+
@discards_a = []
|
|
151
|
+
@discards_b = []
|
|
152
|
+
@done_a = []
|
|
153
|
+
@done_b = []
|
|
154
|
+
self
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def match(event)
|
|
158
|
+
@matched_a << event.old_element
|
|
159
|
+
@matched_b << event.new_element
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def discard_b(event)
|
|
163
|
+
@discards_b << event.new_element
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def discard_a(event)
|
|
167
|
+
@discards_a << event.old_element
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def finished_a(event)
|
|
171
|
+
@done_a << [event.old_element, event.old_position, event.new_element, event.new_position]
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def finished_b(event)
|
|
175
|
+
@done_b << [event.old_element, event.old_position, event.new_element, event.new_position]
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def simple_callback = SimpleCallback.new
|
|
180
|
+
|
|
181
|
+
class SimpleCallbackNoFinishers < SimpleCallback
|
|
182
|
+
undef :finished_a
|
|
183
|
+
undef :finished_b
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def simple_callback_no_finishers = SimpleCallbackNoFinishers.new
|
|
187
|
+
|
|
188
|
+
class BalancedCallback
|
|
189
|
+
attr_reader :result
|
|
190
|
+
|
|
191
|
+
def initialize
|
|
192
|
+
reset
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def reset
|
|
196
|
+
@result = []
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def match(event)
|
|
200
|
+
@result << ["=", event.old_position, event.new_position]
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def discard_a(event)
|
|
204
|
+
@result << ["<", event.old_position, event.new_position]
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def discard_b(event)
|
|
208
|
+
@result << [">", event.old_position, event.new_position]
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def change(event)
|
|
212
|
+
@result << ["!", event.old_position, event.new_position]
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def balanced_callback = BalancedCallback.new
|
|
217
|
+
|
|
218
|
+
class BalancedCallbackNoChange < BalancedCallback
|
|
219
|
+
undef :change
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def balanced_callback_no_change = BalancedCallbackNoChange.new
|
|
223
|
+
|
|
224
|
+
Minitest::Test.send(:include, self)
|
|
225
|
+
end
|
data/test/test_hunk.rb
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
require "diff/lcs/hunk"
|
|
6
|
+
|
|
7
|
+
class TestHunk < Minitest::Test
|
|
8
|
+
def setup
|
|
9
|
+
@old_data = ["Tu a un carté avec {count} itéms".encode("UTF-16LE")]
|
|
10
|
+
@new_data = ["Tu a un carte avec {count} items".encode("UTF-16LE")]
|
|
11
|
+
@pieces = diff(@old_data, @new_data)
|
|
12
|
+
@hunk = hunk(@old_data, @new_data, @pieces[0], 3, 0)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_produces_a_unified_diff_from_the_two_pieces
|
|
16
|
+
expected = <<-EXPECTED.gsub(/^\s+/, "").encode("UTF-16LE").chomp
|
|
17
|
+
@@ -1 +1 @@
|
|
18
|
+
-Tu a un carté avec {count} itéms
|
|
19
|
+
+Tu a un carte avec {count} items
|
|
20
|
+
EXPECTED
|
|
21
|
+
|
|
22
|
+
assert_equal expected, @hunk.diff(:unified)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_produces_a_unified_diff_from_the_two_pieces_last_entry
|
|
26
|
+
expected = <<-EXPECTED.gsub(/^\s+/, "").encode("UTF-16LE").chomp
|
|
27
|
+
@@ -1 +1 @@
|
|
28
|
+
-Tu a un carté avec {count} itéms
|
|
29
|
+
+Tu a un carte avec {count} items
|
|
30
|
+
\
|
|
31
|
+
EXPECTED
|
|
32
|
+
|
|
33
|
+
assert_equal expected, @hunk.diff(:unified, true)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_produces_a_context_diff_from_the_two_pieces
|
|
37
|
+
expected = <<-EXPECTED.gsub(/^\s+/, "").encode("UTF-16LE").chomp
|
|
38
|
+
***************
|
|
39
|
+
*** 1 ****
|
|
40
|
+
! Tu a un carté avec {count} itéms
|
|
41
|
+
--- 1 ----
|
|
42
|
+
! Tu a un carte avec {count} items
|
|
43
|
+
EXPECTED
|
|
44
|
+
|
|
45
|
+
assert_equal expected, @hunk.diff(:context)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_produces_an_old_diff_from_the_two_pieces
|
|
49
|
+
expected = <<-EXPECTED.gsub(/^ +/, "").encode("UTF-16LE").chomp
|
|
50
|
+
1c1
|
|
51
|
+
< Tu a un carté avec {count} itéms
|
|
52
|
+
---
|
|
53
|
+
> Tu a un carte avec {count} items
|
|
54
|
+
|
|
55
|
+
EXPECTED
|
|
56
|
+
|
|
57
|
+
assert_equal expected, @hunk.diff(:old)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_with_empty_first_data_set_produces_a_unified_diff
|
|
61
|
+
old_data = []
|
|
62
|
+
pieces = diff(old_data, @new_data)
|
|
63
|
+
hunk = hunk(old_data, @new_data, pieces[0], 3, 0)
|
|
64
|
+
|
|
65
|
+
expected = <<-EXPECTED.gsub(/^\s+/, "").encode("UTF-16LE").chomp
|
|
66
|
+
@@ -0,0 +1 @@
|
|
67
|
+
+Tu a un carte avec {count} items
|
|
68
|
+
EXPECTED
|
|
69
|
+
|
|
70
|
+
assert_equal expected, hunk.diff(:unified)
|
|
71
|
+
end
|
|
72
|
+
end
|