dimapa 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +13 -0
- data/LICENSE +23 -0
- data/README.md +78 -0
- data/Rakefile +22 -0
- data/lib/diff_methods.rb +132 -0
- data/lib/dimapa.rb +1522 -0
- data/lib/patch_obj.rb +54 -0
- data/scripts/speedtest.rb +13 -0
- data/scripts/speedtest/speedtest1.txt +230 -0
- data/scripts/speedtest/speedtest2.txt +188 -0
- data/test/helper.rb +1 -0
- data/test/test_dimapa.rb +1196 -0
- metadata +98 -0
data/test/helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "minitest/autorun"
|
data/test/test_dimapa.rb
ADDED
@@ -0,0 +1,1196 @@
|
|
1
|
+
require_relative "./helper"
|
2
|
+
require_relative "../lib/dimapa"
|
3
|
+
|
4
|
+
class DiffTest < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@dmp = DiMaPa.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_diff_common_prefix
|
10
|
+
# Detect any common prefix.
|
11
|
+
# Null case.
|
12
|
+
assert_equal(0, @dmp.diff_common_prefix("abc", "xyz"))
|
13
|
+
|
14
|
+
# Non-null case.
|
15
|
+
assert_equal(4, @dmp.diff_common_prefix("1234abcdef", "1234xyz"))
|
16
|
+
|
17
|
+
# Whole case.
|
18
|
+
assert_equal(4, @dmp.diff_common_prefix("1234", "1234xyz"))
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_diff_common_suffix
|
22
|
+
# Detect any common suffix.
|
23
|
+
# Null case.
|
24
|
+
assert_equal(0, @dmp.diff_common_suffix("abc", "xyz"))
|
25
|
+
|
26
|
+
# Non-null case.
|
27
|
+
assert_equal(4, @dmp.diff_common_suffix("abcdef1234", "xyz1234"))
|
28
|
+
|
29
|
+
# Whole case.
|
30
|
+
assert_equal(4, @dmp.diff_common_suffix("1234", "xyz1234"))
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_diff_common_overlap
|
34
|
+
# Detect any suffix/prefix overlap.
|
35
|
+
# Null case.
|
36
|
+
assert_equal(0, @dmp.diff_common_overlap("", "abcd"))
|
37
|
+
|
38
|
+
# Whole case.
|
39
|
+
assert_equal(3, @dmp.diff_common_overlap("abc", "abcd"))
|
40
|
+
|
41
|
+
# No overlap.
|
42
|
+
assert_equal(0, @dmp.diff_common_overlap("123456", "abcd"))
|
43
|
+
|
44
|
+
# Overlap.
|
45
|
+
assert_equal(3, @dmp.diff_common_overlap("123456xxx", "xxxabcd"))
|
46
|
+
|
47
|
+
# Unicode.
|
48
|
+
# Some overly clever languages (C#) may treat ligatures as equal to their
|
49
|
+
# component letters. E.g. U+FB01 == 'fi'
|
50
|
+
assert_equal(0, @dmp.diff_common_overlap("fi", '\ufb01i'))
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_diff_half_match
|
54
|
+
# Detect a halfmatch.
|
55
|
+
@dmp.diff_timeout = 1
|
56
|
+
# No match.
|
57
|
+
assert_nil(@dmp.diff_half_match("1234567890", "abcdef"))
|
58
|
+
|
59
|
+
assert_nil(@dmp.diff_half_match("12345", "23"))
|
60
|
+
|
61
|
+
# Single Match.
|
62
|
+
assert_equal(
|
63
|
+
["12", "90", "a", "z", "345678"],
|
64
|
+
@dmp.diff_half_match("1234567890", "a345678z")
|
65
|
+
)
|
66
|
+
|
67
|
+
assert_equal(
|
68
|
+
["a", "z", "12", "90", "345678"],
|
69
|
+
@dmp.diff_half_match("a345678z", "1234567890")
|
70
|
+
)
|
71
|
+
|
72
|
+
assert_equal(
|
73
|
+
["abc", "z", "1234", "0", "56789"],
|
74
|
+
@dmp.diff_half_match("abc56789z", "1234567890")
|
75
|
+
)
|
76
|
+
|
77
|
+
assert_equal(
|
78
|
+
["a", "xyz", "1", "7890", "23456"],
|
79
|
+
@dmp.diff_half_match("a23456xyz", "1234567890")
|
80
|
+
)
|
81
|
+
|
82
|
+
# Multiple Matches.
|
83
|
+
assert_equal(
|
84
|
+
["12123", "123121", "a", "z", "1234123451234"],
|
85
|
+
@dmp.diff_half_match("121231234123451234123121", "a1234123451234z")
|
86
|
+
)
|
87
|
+
|
88
|
+
assert_equal(
|
89
|
+
["", "-=-=-=-=-=", "x", "", "x-=-=-=-=-=-=-="],
|
90
|
+
@dmp.diff_half_match("x-=-=-=-=-=-=-=-=-=-=-=-=", "xx-=-=-=-=-=-=-=")
|
91
|
+
)
|
92
|
+
|
93
|
+
assert_equal(
|
94
|
+
["-=-=-=-=-=", "", "", "y", "-=-=-=-=-=-=-=y"],
|
95
|
+
@dmp.diff_half_match("-=-=-=-=-=-=-=-=-=-=-=-=y", "-=-=-=-=-=-=-=yy")
|
96
|
+
)
|
97
|
+
|
98
|
+
# Non-optimal halfmatch.
|
99
|
+
# Optimal diff would be -q+x=H-i+e=lloHe+Hu=llo-Hew+y
|
100
|
+
# not -qHillo+x=HelloHe-w+Hulloy
|
101
|
+
assert_equal(
|
102
|
+
["qHillo", "w", "x", "Hulloy", "HelloHe"],
|
103
|
+
@dmp.diff_half_match("qHilloHelloHew", "xHelloHeHulloy")
|
104
|
+
)
|
105
|
+
|
106
|
+
# Optimal no halfmatch.
|
107
|
+
@dmp.diff_timeout = 0
|
108
|
+
assert_nil(@dmp.diff_half_match("qHilloHelloHew", "xHelloHeHulloy"))
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_diff_lines_to_chars
|
112
|
+
# Convert lines down to characters.
|
113
|
+
assert_equal(
|
114
|
+
["\x01\x02\x01", "\x02\x01\x02", ["", "alpha\n", "beta\n"]],
|
115
|
+
@dmp.diff_lines_to_chars("alpha\nbeta\nalpha\n", "beta\nalpha\nbeta\n")
|
116
|
+
)
|
117
|
+
|
118
|
+
assert_equal(
|
119
|
+
["", "\x01\x02\x03\x03", ["", "alpha\r\n", "beta\r\n", "\r\n"]],
|
120
|
+
@dmp.diff_lines_to_chars("", "alpha\r\nbeta\r\n\r\n\r\n")
|
121
|
+
)
|
122
|
+
|
123
|
+
assert_equal(
|
124
|
+
["\x01", "\x02", ["", "a", "b"]],
|
125
|
+
@dmp.diff_lines_to_chars("a", "b")
|
126
|
+
)
|
127
|
+
|
128
|
+
# More than 256 to reveal any 8-bit limitations.
|
129
|
+
n = 300
|
130
|
+
line_list = (1..n).map { |x| x.to_s + "\n" }
|
131
|
+
char_list = (1..n).map { |x| x.chr(Encoding::UTF_8) }
|
132
|
+
assert_equal(n, line_list.length)
|
133
|
+
lines = line_list.join
|
134
|
+
chars = char_list.join
|
135
|
+
assert_equal(n, chars.length)
|
136
|
+
line_list.unshift("")
|
137
|
+
assert_equal([chars, "", line_list], @dmp.diff_lines_to_chars(lines, ""))
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_diff_chars_to_lines
|
141
|
+
# Convert chars up to lines.
|
142
|
+
diffs = [[:equal, "\x01\x02\x01"], [:insert, "\x02\x01\x02"]]
|
143
|
+
@dmp.diff_chars_to_lines(diffs, ["", "alpha\n", "beta\n"])
|
144
|
+
assert_equal(
|
145
|
+
[[:equal, "alpha\nbeta\nalpha\n"], [:insert, "beta\nalpha\nbeta\n"]],
|
146
|
+
diffs
|
147
|
+
)
|
148
|
+
|
149
|
+
# More than 256 to reveal any 8-bit limitations.
|
150
|
+
n = 300
|
151
|
+
line_list = (1..n).map { |x| x.to_s + "\n" }
|
152
|
+
char_list = (1..n).map { |x| x.chr(Encoding::UTF_8) }
|
153
|
+
assert_equal(n, line_list.length)
|
154
|
+
lines = line_list.join
|
155
|
+
chars = char_list.join
|
156
|
+
assert_equal(n, chars.length)
|
157
|
+
line_list.unshift("")
|
158
|
+
|
159
|
+
diffs = [[:delete, chars]]
|
160
|
+
@dmp.diff_chars_to_lines(diffs, line_list)
|
161
|
+
assert_equal([[:delete, lines]], diffs)
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_diff_cleanup_merge
|
165
|
+
# Cleanup a messy diff.
|
166
|
+
# Null case.
|
167
|
+
diffs = []
|
168
|
+
@dmp.diff_cleanup_merge(diffs)
|
169
|
+
assert_equal([], diffs)
|
170
|
+
|
171
|
+
# No change case.
|
172
|
+
diffs = [[:equal, "a"], [:delete, "b"], [:insert, "c"]]
|
173
|
+
@dmp.diff_cleanup_merge(diffs)
|
174
|
+
assert_equal([[:equal, "a"], [:delete, "b"], [:insert, "c"]], diffs)
|
175
|
+
|
176
|
+
# Merge equalities.
|
177
|
+
diffs = [[:equal, "a"], [:equal, "b"], [:equal, "c"]]
|
178
|
+
@dmp.diff_cleanup_merge(diffs)
|
179
|
+
assert_equal([[:equal, "abc"]], diffs)
|
180
|
+
|
181
|
+
# Merge deletions.
|
182
|
+
diffs = [[:delete, "a"], [:delete, "b"], [:delete, "c"]]
|
183
|
+
@dmp.diff_cleanup_merge(diffs)
|
184
|
+
assert_equal([[:delete, "abc"]], diffs)
|
185
|
+
|
186
|
+
# Merge insertions.
|
187
|
+
diffs = [[:insert, "a"], [:insert, "b"], [:insert, "c"]]
|
188
|
+
@dmp.diff_cleanup_merge(diffs)
|
189
|
+
assert_equal([[:insert, "abc"]], diffs)
|
190
|
+
|
191
|
+
# Merge interweave.
|
192
|
+
diffs = [
|
193
|
+
[:delete, "a"], [:insert, "b"], [:delete, "c"],
|
194
|
+
[:insert, "d"], [:equal, "e"], [:equal, "f"]
|
195
|
+
]
|
196
|
+
@dmp.diff_cleanup_merge(diffs)
|
197
|
+
assert_equal([[:delete, "ac"], [:insert, "bd"], [:equal, "ef"]], diffs)
|
198
|
+
|
199
|
+
# Prefix and suffix detection.
|
200
|
+
diffs = [[:delete, "a"], [:insert, "abc"], [:delete, "dc"]]
|
201
|
+
@dmp.diff_cleanup_merge(diffs)
|
202
|
+
assert_equal(
|
203
|
+
[[:equal, "a"], [:delete, "d"], [:insert, "b"], [:equal, "c"]],
|
204
|
+
diffs
|
205
|
+
)
|
206
|
+
|
207
|
+
# Prefix and suffix detection with equalities.
|
208
|
+
diffs = [
|
209
|
+
[:equal, "x"], [:delete, "a"], [:insert, "abc"],
|
210
|
+
[:delete, "dc"], [:equal, "y"]
|
211
|
+
]
|
212
|
+
@dmp.diff_cleanup_merge(diffs)
|
213
|
+
assert_equal(
|
214
|
+
[[:equal, "xa"], [:delete, "d"], [:insert, "b"], [:equal, "cy"]],
|
215
|
+
diffs
|
216
|
+
)
|
217
|
+
|
218
|
+
# Slide edit left.
|
219
|
+
diffs = [[:equal, "a"], [:insert, "ba"], [:equal, "c"]]
|
220
|
+
@dmp.diff_cleanup_merge(diffs)
|
221
|
+
assert_equal([[:insert, "ab"], [:equal, "ac"]], diffs)
|
222
|
+
|
223
|
+
# Slide edit right.
|
224
|
+
diffs = [[:equal, "c"], [:insert, "ab"], [:equal, "a"]]
|
225
|
+
@dmp.diff_cleanup_merge(diffs)
|
226
|
+
assert_equal([[:equal, "ca"], [:insert, "ba"]], diffs)
|
227
|
+
|
228
|
+
# Slide edit left recursive.
|
229
|
+
diffs = [
|
230
|
+
[:equal, "a"], [:delete, "b"], [:equal, "c"],
|
231
|
+
[:delete, "ac"], [:equal, "x"]
|
232
|
+
]
|
233
|
+
@dmp.diff_cleanup_merge(diffs)
|
234
|
+
assert_equal([[:delete, "abc"], [:equal, "acx"]], diffs)
|
235
|
+
|
236
|
+
# Slide edit right recursive.
|
237
|
+
diffs = [
|
238
|
+
[:equal, "x"], [:delete, "ca"], [:equal, "c"],
|
239
|
+
[:delete, "b"], [:equal, "a"]
|
240
|
+
]
|
241
|
+
@dmp.diff_cleanup_merge(diffs)
|
242
|
+
assert_equal([[:equal, "xca"], [:delete, "cba"]], diffs)
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_diff_cleanup_semantic_lossless
|
246
|
+
# Slide diffs to match logical boundaries.
|
247
|
+
# Null case.
|
248
|
+
diffs = []
|
249
|
+
@dmp.diff_cleanup_semantic_lossless(diffs)
|
250
|
+
assert_equal([], diffs)
|
251
|
+
|
252
|
+
# Blank lines.
|
253
|
+
diffs = [
|
254
|
+
[:equal, "AAA\r\n\r\nBBB"],
|
255
|
+
[:insert, "\r\nDDD\r\n\r\nBBB"],
|
256
|
+
[:equal, "\r\nEEE"]
|
257
|
+
]
|
258
|
+
@dmp.diff_cleanup_semantic_lossless(diffs)
|
259
|
+
assert_equal([
|
260
|
+
[:equal, "AAA\r\n\r\n"],
|
261
|
+
[:insert, "BBB\r\nDDD\r\n\r\n"],
|
262
|
+
[:equal, "BBB\r\nEEE"]
|
263
|
+
],
|
264
|
+
diffs)
|
265
|
+
|
266
|
+
# Line boundaries.
|
267
|
+
diffs = [[:equal, "AAA\r\nBBB"], [:insert, " DDD\r\nBBB"], [:equal, " EEE"]]
|
268
|
+
@dmp.diff_cleanup_semantic_lossless(diffs)
|
269
|
+
assert_equal(
|
270
|
+
[[:equal, "AAA\r\n"], [:insert, "BBB DDD\r\n"], [:equal, "BBB EEE"]],
|
271
|
+
diffs
|
272
|
+
)
|
273
|
+
|
274
|
+
# Word boundaries.
|
275
|
+
diffs = [[:equal, "The c"], [:insert, "ow and the c"], [:equal, "at."]]
|
276
|
+
@dmp.diff_cleanup_semantic_lossless(diffs)
|
277
|
+
assert_equal(
|
278
|
+
[[:equal, "The "], [:insert, "cow and the "], [:equal, "cat."]],
|
279
|
+
diffs
|
280
|
+
)
|
281
|
+
|
282
|
+
# Alphanumeric boundaries.
|
283
|
+
diffs = [[:equal, "The-c"], [:insert, "ow-and-the-c"], [:equal, "at."]]
|
284
|
+
@dmp.diff_cleanup_semantic_lossless(diffs)
|
285
|
+
assert_equal(
|
286
|
+
[[:equal, "The-"], [:insert, "cow-and-the-"], [:equal, "cat."]],
|
287
|
+
diffs
|
288
|
+
)
|
289
|
+
|
290
|
+
# Hitting the start.
|
291
|
+
diffs = [[:equal, "a"], [:delete, "a"], [:equal, "ax"]]
|
292
|
+
@dmp.diff_cleanup_semantic_lossless(diffs)
|
293
|
+
assert_equal([[:delete, "a"], [:equal, "aax"]], diffs)
|
294
|
+
|
295
|
+
# Hitting the end.
|
296
|
+
diffs = [[:equal, "xa"], [:delete, "a"], [:equal, "a"]]
|
297
|
+
@dmp.diff_cleanup_semantic_lossless(diffs)
|
298
|
+
assert_equal([[:equal, "xaa"], [:delete, "a"]], diffs)
|
299
|
+
end
|
300
|
+
|
301
|
+
def test_diff_cleanup_semantic
|
302
|
+
# Cleanup semantically trivial equalities.
|
303
|
+
# Null case.
|
304
|
+
diffs = []
|
305
|
+
@dmp.diff_cleanup_semantic(diffs)
|
306
|
+
assert_equal([], diffs)
|
307
|
+
|
308
|
+
# No elimination #1.
|
309
|
+
diffs = [[:delete, "ab"], [:insert, "cd"], [:equal, "12"], [:delete, "e"]]
|
310
|
+
@dmp.diff_cleanup_semantic(diffs)
|
311
|
+
assert_equal(
|
312
|
+
[[:delete, "ab"], [:insert, "cd"], [:equal, "12"], [:delete, "e"]],
|
313
|
+
diffs
|
314
|
+
)
|
315
|
+
|
316
|
+
# No elimination #2.
|
317
|
+
diffs = [
|
318
|
+
[:delete, "abc"], [:insert, "ABC"],
|
319
|
+
[:equal, "1234"], [:delete, "wxyz"]
|
320
|
+
]
|
321
|
+
@dmp.diff_cleanup_semantic(diffs)
|
322
|
+
assert_equal(
|
323
|
+
[[:delete, "abc"], [:insert, "ABC"], [:equal, "1234"], [:delete, "wxyz"]],
|
324
|
+
diffs
|
325
|
+
)
|
326
|
+
|
327
|
+
# Simple elimination.
|
328
|
+
diffs = [[:delete, "a"], [:equal, "b"], [:delete, "c"]]
|
329
|
+
@dmp.diff_cleanup_semantic(diffs)
|
330
|
+
assert_equal([[:delete, "abc"], [:insert, "b"]], diffs)
|
331
|
+
|
332
|
+
# Backpass elimination.
|
333
|
+
diffs = [
|
334
|
+
[:delete, "ab"], [:equal, "cd"], [:delete, "e"],
|
335
|
+
[:equal, "f"], [:insert, "g"]
|
336
|
+
]
|
337
|
+
@dmp.diff_cleanup_semantic(diffs)
|
338
|
+
assert_equal([[:delete, "abcdef"], [:insert, "cdfg"]], diffs)
|
339
|
+
|
340
|
+
# Multiple eliminations.
|
341
|
+
diffs = [
|
342
|
+
[:insert, "1"], [:equal, "A"], [:delete, "B"],
|
343
|
+
[:insert, "2"], [:equal, "_"], [:insert, "1"],
|
344
|
+
[:equal, "A"], [:delete, "B"], [:insert, "2"]
|
345
|
+
]
|
346
|
+
@dmp.diff_cleanup_semantic(diffs)
|
347
|
+
assert_equal([[:delete, "AB_AB"], [:insert, "1A2_1A2"]], diffs)
|
348
|
+
|
349
|
+
# Word boundaries.
|
350
|
+
diffs = [[:equal, "The c"], [:delete, "ow and the c"], [:equal, "at."]]
|
351
|
+
@dmp.diff_cleanup_semantic(diffs)
|
352
|
+
assert_equal(
|
353
|
+
[[:equal, "The "], [:delete, "cow and the "], [:equal, "cat."]],
|
354
|
+
diffs
|
355
|
+
)
|
356
|
+
|
357
|
+
# No overlap elimination.
|
358
|
+
diffs = [[:delete, "abcxx"], [:insert, "xxdef"]]
|
359
|
+
@dmp.diff_cleanup_semantic(diffs)
|
360
|
+
assert_equal([[:delete, "abcxx"], [:insert, "xxdef"]], diffs)
|
361
|
+
|
362
|
+
# Overlap elimination.
|
363
|
+
diffs = [[:delete, "abcxxx"], [:insert, "xxxdef"]]
|
364
|
+
@dmp.diff_cleanup_semantic(diffs)
|
365
|
+
assert_equal([[:delete, "abc"], [:equal, "xxx"], [:insert, "def"]], diffs)
|
366
|
+
|
367
|
+
# Two overlap eliminations.
|
368
|
+
diffs = [
|
369
|
+
[:delete, "abcd1212"], [:insert, "1212efghi"], [:equal, "----"],
|
370
|
+
[:delete, "A3"], [:insert, "3BC"]
|
371
|
+
]
|
372
|
+
@dmp.diff_cleanup_semantic(diffs)
|
373
|
+
assert_equal([
|
374
|
+
[:delete, "abcd"], [:equal, "1212"], [:insert, "efghi"],
|
375
|
+
[:equal, "----"], [:delete, "A"], [:equal, "3"], [:insert, "BC"]
|
376
|
+
],
|
377
|
+
diffs)
|
378
|
+
end
|
379
|
+
|
380
|
+
def test_diff_cleanup_efficiency
|
381
|
+
# Cleanup operationally trivial equalities.
|
382
|
+
@dmp.diff_edit_cost = 4
|
383
|
+
# Null case.
|
384
|
+
diffs = []
|
385
|
+
@dmp.diff_cleanup_efficiency(diffs)
|
386
|
+
assert_equal([], diffs)
|
387
|
+
|
388
|
+
# No elimination.
|
389
|
+
diffs = [
|
390
|
+
[:delete, "ab"], [:insert, "12"], [:equal, "wxyz"],
|
391
|
+
[:delete, "cd"], [:insert, "34"]
|
392
|
+
]
|
393
|
+
@dmp.diff_cleanup_efficiency(diffs)
|
394
|
+
assert_equal([
|
395
|
+
[:delete, "ab"], [:insert, "12"], [:equal, "wxyz"],
|
396
|
+
[:delete, "cd"], [:insert, "34"]
|
397
|
+
],
|
398
|
+
diffs)
|
399
|
+
|
400
|
+
# Four-edit elimination.
|
401
|
+
diffs = [
|
402
|
+
[:delete, "ab"], [:insert, "12"], [:equal, "xyz"],
|
403
|
+
[:delete, "cd"], [:insert, "34"]
|
404
|
+
]
|
405
|
+
@dmp.diff_cleanup_efficiency(diffs)
|
406
|
+
assert_equal([[:delete, "abxyzcd"], [:insert, "12xyz34"]], diffs)
|
407
|
+
|
408
|
+
# Three-edit elimination.
|
409
|
+
diffs = [[:insert, "12"], [:equal, "x"], [:delete, "cd"], [:insert, "34"]]
|
410
|
+
@dmp.diff_cleanup_efficiency(diffs)
|
411
|
+
assert_equal([[:delete, "xcd"], [:insert, "12x34"]], diffs)
|
412
|
+
|
413
|
+
# Backpass elimination.
|
414
|
+
diffs = [
|
415
|
+
[:delete, "ab"], [:insert, "12"], [:equal, "xy"], [:insert, "34"],
|
416
|
+
[:equal, "z"], [:delete, "cd"], [:insert, "56"]
|
417
|
+
]
|
418
|
+
@dmp.diff_cleanup_efficiency(diffs)
|
419
|
+
assert_equal([[:delete, "abxyzcd"], [:insert, "12xy34z56"]], diffs)
|
420
|
+
|
421
|
+
# High cost elimination.
|
422
|
+
@dmp.diff_edit_cost = 5
|
423
|
+
diffs = [
|
424
|
+
[:delete, "ab"], [:insert, "12"], [:equal, "wxyz"],
|
425
|
+
[:delete, "cd"], [:insert, "34"]
|
426
|
+
]
|
427
|
+
@dmp.diff_cleanup_efficiency(diffs)
|
428
|
+
assert_equal([[:delete, "abwxyzcd"], [:insert, "12wxyz34"]], diffs)
|
429
|
+
@dmp.diff_edit_cost = 4
|
430
|
+
end
|
431
|
+
|
432
|
+
def test_diff_pretty_html
|
433
|
+
# Pretty print.
|
434
|
+
diffs = [[:equal, 'a\n'], [:delete, "<B>b</B>"], [:insert, "c&d"]]
|
435
|
+
assert_equal(
|
436
|
+
'<span>a¶<br></span><del style="background:#ffe6e6;"><B>' \
|
437
|
+
'b</B></del><ins style="background:#e6ffe6;">c&d</ins>',
|
438
|
+
@dmp.diff_pretty_html(diffs)
|
439
|
+
)
|
440
|
+
end
|
441
|
+
|
442
|
+
def test_diff_text
|
443
|
+
# Compute the source and destination texts.
|
444
|
+
diffs = [
|
445
|
+
[:equal, "jump"], [:delete, "s"], [:insert, "ed"], [:equal, " over "],
|
446
|
+
[:delete, "the"], [:insert, "a"], [:equal, " lazy"]
|
447
|
+
]
|
448
|
+
assert_equal("jumps over the lazy", @dmp.diff_text1(diffs))
|
449
|
+
assert_equal("jumped over a lazy", @dmp.diff_text2(diffs))
|
450
|
+
end
|
451
|
+
|
452
|
+
def test_diff_delta
|
453
|
+
# Convert a diff into delta string.
|
454
|
+
diffs = [
|
455
|
+
[:equal, "jump"], [:delete, "s"], [:insert, "ed"], [:equal, " over "],
|
456
|
+
[:delete, "the"], [:insert, "a"], [:equal, " lazy"], [:insert, "old dog"]
|
457
|
+
]
|
458
|
+
text1 = @dmp.diff_text1(diffs)
|
459
|
+
assert_equal("jumps over the lazy", text1)
|
460
|
+
|
461
|
+
delta = @dmp.diff_to_delta(diffs)
|
462
|
+
assert_equal("=4\t-1\t+ed\t=6\t-3\t+a\t=5\t+old dog", delta)
|
463
|
+
|
464
|
+
# Convert delta string into a diff.
|
465
|
+
assert_equal(diffs, @dmp.diff_from_delta(text1, delta))
|
466
|
+
|
467
|
+
# Generates error (19 != 20).
|
468
|
+
assert_raises ArgumentError do
|
469
|
+
@dmp.diff_from_delta(text1 + "x", delta)
|
470
|
+
end
|
471
|
+
|
472
|
+
# Generates error (19 != 18)
|
473
|
+
assert_raises ArgumentError do
|
474
|
+
@dmp.diff_from_delta(text1[1..-1], delta)
|
475
|
+
end
|
476
|
+
|
477
|
+
# Test deltas with special characters.
|
478
|
+
diffs = [
|
479
|
+
[:equal, "\u0680 \x00 \t %"],
|
480
|
+
[:delete, "\u0681 \x01 \n ^"],
|
481
|
+
[:insert, "\u0682 \x02 \\ |"]
|
482
|
+
]
|
483
|
+
text1 = @dmp.diff_text1(diffs)
|
484
|
+
assert_equal("\u0680 \x00 \t %\u0681 \x01 \n ^", text1)
|
485
|
+
|
486
|
+
delta = @dmp.diff_to_delta(diffs)
|
487
|
+
assert_equal("=7\t-7\t+%DA%82 %02 %5C %7C", delta)
|
488
|
+
|
489
|
+
# Convert delta string into a diff.
|
490
|
+
assert_equal(diffs, @dmp.diff_from_delta(text1, delta))
|
491
|
+
|
492
|
+
# Verify pool of unchanged characters.
|
493
|
+
diffs = [[:insert, "A-Z a-z 0-9 - _ . ! ~ * \' ( ) / ? : @ & = + $ , # "]]
|
494
|
+
text2 = @dmp.diff_text2(diffs)
|
495
|
+
assert_equal("A-Z a-z 0-9 - _ . ! ~ * \' ( ) / ? : @ & = + $ , # ", text2)
|
496
|
+
|
497
|
+
delta = @dmp.diff_to_delta(diffs)
|
498
|
+
assert_equal("+A-Z a-z 0-9 - _ . ! ~ * \' ( ) / ? : @ & = + $ , # ", delta)
|
499
|
+
|
500
|
+
# Convert delta string into a diff.
|
501
|
+
assert_equal(diffs, @dmp.diff_from_delta("", delta))
|
502
|
+
end
|
503
|
+
|
504
|
+
def test_diff_x_index
|
505
|
+
# Translate a location in text1 to text2.
|
506
|
+
# Translation on equality.
|
507
|
+
diffs = [[:delete, "a"], [:insert, "1234"], [:equal, "xyz"]]
|
508
|
+
assert_equal(5, @dmp.diff_x_index(diffs, 2))
|
509
|
+
|
510
|
+
# Translation on deletion.
|
511
|
+
diffs = [[:equal, "a"], [:delete, "1234"], [:equal, "xyz"]]
|
512
|
+
assert_equal(1, @dmp.diff_x_index(diffs, 3))
|
513
|
+
end
|
514
|
+
|
515
|
+
def test_diff_levenshtein
|
516
|
+
# Levenshtein with trailing equality.
|
517
|
+
diffs = [[:delete, "abc"], [:insert, "1234"], [:equal, "xyz"]]
|
518
|
+
assert_equal(4, @dmp.diff_levenshtein(diffs))
|
519
|
+
# Levenshtein with leading equality.
|
520
|
+
diffs = [[:equal, "xyz"], [:delete, "abc"], [:insert, "1234"]]
|
521
|
+
assert_equal(4, @dmp.diff_levenshtein(diffs))
|
522
|
+
# Levenshtein with middle equality.
|
523
|
+
diffs = [[:delete, "abc"], [:equal, "xyz"], [:insert, "1234"]]
|
524
|
+
assert_equal(7, @dmp.diff_levenshtein(diffs))
|
525
|
+
end
|
526
|
+
|
527
|
+
def test_diff_bisect
|
528
|
+
# Normal.
|
529
|
+
a = "cat"
|
530
|
+
b = "map"
|
531
|
+
# Since the resulting diff hasn't been normalized, it would be ok if
|
532
|
+
# the insertion and deletion pairs are swapped.
|
533
|
+
# If the order changes, tweak this test as required.
|
534
|
+
diffs = [
|
535
|
+
[:delete, "c"], [:insert, "m"], [:equal, "a"],
|
536
|
+
[:delete, "t"], [:insert, "p"]
|
537
|
+
]
|
538
|
+
assert_equal(diffs, @dmp.diff_bisect(a, b, nil))
|
539
|
+
|
540
|
+
# Timeout.
|
541
|
+
assert_equal(
|
542
|
+
[[:delete, "cat"], [:insert, "map"]],
|
543
|
+
@dmp.diff_bisect(a, b, Time.now - 1)
|
544
|
+
)
|
545
|
+
end
|
546
|
+
|
547
|
+
def test_diff_main
|
548
|
+
# Perform a trivial diff.
|
549
|
+
# Null case.
|
550
|
+
assert_equal([], @dmp.diff_main("", "", false))
|
551
|
+
|
552
|
+
# Equality.
|
553
|
+
assert_equal([[:equal, "abc"]], @dmp.diff_main("abc", "abc", false))
|
554
|
+
|
555
|
+
# Simple insertion.
|
556
|
+
assert_equal(
|
557
|
+
[[:equal, "ab"], [:insert, "123"], [:equal, "c"]],
|
558
|
+
@dmp.diff_main("abc", "ab123c", false)
|
559
|
+
)
|
560
|
+
|
561
|
+
# Simple deletion.
|
562
|
+
assert_equal(
|
563
|
+
[[:equal, "a"], [:delete, "123"], [:equal, "bc"]],
|
564
|
+
@dmp.diff_main("a123bc", "abc", false)
|
565
|
+
)
|
566
|
+
|
567
|
+
# Two insertions.
|
568
|
+
assert_equal([
|
569
|
+
[:equal, "a"], [:insert, "123"], [:equal, "b"],
|
570
|
+
[:insert, "456"], [:equal, "c"]
|
571
|
+
],
|
572
|
+
@dmp.diff_main("abc", "a123b456c", false))
|
573
|
+
|
574
|
+
# Two deletions.
|
575
|
+
assert_equal([
|
576
|
+
[:equal, "a"], [:delete, "123"], [:equal, "b"],
|
577
|
+
[:delete, "456"], [:equal, "c"]
|
578
|
+
],
|
579
|
+
@dmp.diff_main("a123b456c", "abc", false))
|
580
|
+
|
581
|
+
# Perform a real diff.
|
582
|
+
# Switch off the timeout.
|
583
|
+
@dmp.diff_timeout = 0
|
584
|
+
# Simple cases.
|
585
|
+
assert_equal(
|
586
|
+
[[:delete, "a"], [:insert, "b"]],
|
587
|
+
@dmp.diff_main("a", "b", false)
|
588
|
+
)
|
589
|
+
|
590
|
+
assert_equal([
|
591
|
+
[:delete, "Apple"], [:insert, "Banana"], [:equal, "s are a"],
|
592
|
+
[:insert, "lso"], [:equal, " fruit."]
|
593
|
+
],
|
594
|
+
@dmp.diff_main("Apples are a fruit.", "Bananas are also fruit.", false))
|
595
|
+
|
596
|
+
assert_equal([
|
597
|
+
[:delete, "a"], [:insert, "\u0680"], [:equal, "x"],
|
598
|
+
[:delete, "\t"], [:insert, "\0"]
|
599
|
+
],
|
600
|
+
@dmp.diff_main("ax\t", "\u0680x\0", false))
|
601
|
+
|
602
|
+
# Overlaps.
|
603
|
+
assert_equal([
|
604
|
+
[:delete, "1"], [:equal, "a"], [:delete, "y"],
|
605
|
+
[:equal, "b"], [:delete, "2"], [:insert, "xab"]
|
606
|
+
],
|
607
|
+
@dmp.diff_main("1ayb2", "abxab", false))
|
608
|
+
|
609
|
+
assert_equal(
|
610
|
+
[[:insert, "xaxcx"], [:equal, "abc"], [:delete, "y"]],
|
611
|
+
@dmp.diff_main("abcy", "xaxcxabc", false)
|
612
|
+
)
|
613
|
+
|
614
|
+
assert_equal([
|
615
|
+
[:delete, "ABCD"], [:equal, "a"], [:delete, "="], [:insert, "-"],
|
616
|
+
[:equal, "bcd"], [:delete, "="], [:insert, "-"],
|
617
|
+
[:equal, "efghijklmnopqrs"], [:delete, "EFGHIJKLMNOefg"]
|
618
|
+
],
|
619
|
+
@dmp.diff_main(
|
620
|
+
"ABCDa=bcd=efghijklmnopqrsEFGHIJKLMNOefg",
|
621
|
+
"a-bcd-efghijklmnopqrs",
|
622
|
+
false
|
623
|
+
))
|
624
|
+
|
625
|
+
# Large equality.
|
626
|
+
assert_equal(
|
627
|
+
[
|
628
|
+
[:insert, " "], [:equal, "a"], [:insert, "nd"],
|
629
|
+
[:equal, " [[Pennsylvania]]"], [:delete, " and [[New"]
|
630
|
+
],
|
631
|
+
@dmp.diff_main(
|
632
|
+
"a [[Pennsylvania]] and [[New", " and [[Pennsylvania]]", false
|
633
|
+
)
|
634
|
+
)
|
635
|
+
|
636
|
+
# Timeout.
|
637
|
+
@dmp.diff_timeout = 0.1 # 100ms
|
638
|
+
a = "`Twas brillig, and the slithy toves\nDid gyre and gimble in the " \
|
639
|
+
"wabe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe.\n"
|
640
|
+
b = "I am the very model of a modern major general,\nI\'ve information " \
|
641
|
+
"vegetable, animal, and mineral,\nI know the kings of England, and " \
|
642
|
+
"I quote the fights historical,\nFrom Marathon to Waterloo, in " \
|
643
|
+
"order categorical.\n"
|
644
|
+
# Increase the text lengths by 1024 times to ensure a timeout.
|
645
|
+
a *= 1024
|
646
|
+
b *= 1024
|
647
|
+
start_time = Time.now
|
648
|
+
@dmp.diff_main(a, b)
|
649
|
+
end_time = Time.now
|
650
|
+
# Test that we took at least the timeout period.
|
651
|
+
assert_equal(true, @dmp.diff_timeout <= end_time - start_time)
|
652
|
+
# Test that we didn't take forever (be forgiving).
|
653
|
+
# Theoretically this test could fail very occasionally if the
|
654
|
+
# OS task swaps or locks up for a second at the wrong moment.
|
655
|
+
assert_equal(true, @dmp.diff_timeout * 1000 * 2 > end_time - start_time)
|
656
|
+
@dmp.diff_timeout = 0
|
657
|
+
|
658
|
+
# Test the linemode speedup.
|
659
|
+
# Must be long to pass the 100 char cutoff.
|
660
|
+
# Simple line-mode.
|
661
|
+
a = "1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n" \
|
662
|
+
"1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n" \
|
663
|
+
"1234567890\n1234567890\n1234567890\n"
|
664
|
+
b = "abcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\n" \
|
665
|
+
"abcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\n" \
|
666
|
+
"abcdefghij\nabcdefghij\nabcdefghij\n"
|
667
|
+
assert_equal(@dmp.diff_main(a, b, false), @dmp.diff_main(a, b, true))
|
668
|
+
|
669
|
+
# Single line-mode.
|
670
|
+
a = "123456789012345678901234567890123456789012345678901234567890" \
|
671
|
+
"123456789012345678901234567890123456789012345678901234567890" \
|
672
|
+
"1234567890"
|
673
|
+
b = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij" \
|
674
|
+
"abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij"
|
675
|
+
assert_equal(@dmp.diff_main(a, b, false), @dmp.diff_main(a, b, true))
|
676
|
+
|
677
|
+
# Overlap line-mode.
|
678
|
+
a = "1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n" \
|
679
|
+
"1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n" \
|
680
|
+
"1234567890\n1234567890\n1234567890\n"
|
681
|
+
b = "abcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n" \
|
682
|
+
"1234567890\n1234567890\n1234567890\nabcdefghij\n1234567890\n" \
|
683
|
+
"1234567890\n1234567890\nabcdefghij\n"
|
684
|
+
|
685
|
+
diffs_linemode = @dmp.diff_main(a, b, false)
|
686
|
+
diffs_textmode = @dmp.diff_main(a, b, true)
|
687
|
+
|
688
|
+
assert_equal(
|
689
|
+
@dmp.diff_text1(diffs_linemode),
|
690
|
+
@dmp.diff_text1(diffs_textmode)
|
691
|
+
)
|
692
|
+
|
693
|
+
assert_equal(
|
694
|
+
@dmp.diff_text2(diffs_linemode),
|
695
|
+
@dmp.diff_text2(diffs_textmode)
|
696
|
+
)
|
697
|
+
|
698
|
+
# Test null inputs.
|
699
|
+
assert_raises ArgumentError do
|
700
|
+
@dmp.diff_main(nil, nil)
|
701
|
+
end
|
702
|
+
end
|
703
|
+
|
704
|
+
def test_match_alphabet
|
705
|
+
# Initialise the bitmasks for Bitap.
|
706
|
+
# Unique.
|
707
|
+
assert_equal({"a" => 4, "b" => 2, "c" => 1}, @dmp.match_alphabet("abc"))
|
708
|
+
|
709
|
+
# Duplicates.
|
710
|
+
assert_equal({"a" => 37, "b" => 18, "c" => 8}, @dmp.match_alphabet("abcaba"))
|
711
|
+
end
|
712
|
+
|
713
|
+
def test_match_bitap
|
714
|
+
# Bitap algorithm.
|
715
|
+
@dmp.match_distance = 100
|
716
|
+
@dmp.match_threshold = 0.5
|
717
|
+
# Exact matches.
|
718
|
+
assert_equal(5, @dmp.match_bitap("abcdefghijk", "fgh", 5))
|
719
|
+
|
720
|
+
assert_equal(5, @dmp.match_bitap("abcdefghijk", "fgh", 0))
|
721
|
+
|
722
|
+
# Fuzzy matches.
|
723
|
+
assert_equal(4, @dmp.match_bitap("abcdefghijk", "efxhi", 0))
|
724
|
+
|
725
|
+
assert_equal(2, @dmp.match_bitap("abcdefghijk", "cdefxyhijk", 5))
|
726
|
+
|
727
|
+
assert_equal(-1, @dmp.match_bitap("abcdefghijk", "bxy", 1))
|
728
|
+
|
729
|
+
# Overflow.
|
730
|
+
assert_equal(2, @dmp.match_bitap("123456789xx0", "3456789x0", 2))
|
731
|
+
|
732
|
+
# Threshold test.
|
733
|
+
@dmp.match_threshold = 0.4
|
734
|
+
assert_equal(4, @dmp.match_bitap("abcdefghijk", "efxyhi", 1))
|
735
|
+
|
736
|
+
@dmp.match_threshold = 0.3
|
737
|
+
assert_equal(-1, @dmp.match_bitap("abcdefghijk", "efxyhi", 1))
|
738
|
+
|
739
|
+
@dmp.match_threshold = 0.0
|
740
|
+
assert_equal(1, @dmp.match_bitap("abcdefghijk", "bcdef", 1))
|
741
|
+
@dmp.match_threshold = 0.5
|
742
|
+
|
743
|
+
# Multiple select.
|
744
|
+
assert_equal(0, @dmp.match_bitap("abcdexyzabcde", "abccde", 3))
|
745
|
+
|
746
|
+
assert_equal(8, @dmp.match_bitap("abcdexyzabcde", "abccde", 5))
|
747
|
+
|
748
|
+
# Distance test.
|
749
|
+
@dmp.match_distance = 10 # Strict location.
|
750
|
+
assert_equal(
|
751
|
+
-1,
|
752
|
+
@dmp.match_bitap("abcdefghijklmnopqrstuvwxyz", "abcdefg", 24)
|
753
|
+
)
|
754
|
+
|
755
|
+
assert_equal(
|
756
|
+
0,
|
757
|
+
@dmp.match_bitap("abcdefghijklmnopqrstuvwxyz", "abcdxxefg", 1)
|
758
|
+
)
|
759
|
+
|
760
|
+
@dmp.match_distance = 1000 # Loose location.
|
761
|
+
assert_equal(
|
762
|
+
0,
|
763
|
+
@dmp.match_bitap("abcdefghijklmnopqrstuvwxyz", "abcdefg", 24)
|
764
|
+
)
|
765
|
+
end
|
766
|
+
|
767
|
+
def test_match_main
|
768
|
+
# Full match.
|
769
|
+
# Shortcut matches.
|
770
|
+
assert_equal(0, @dmp.match_main("abcdef", "abcdef", 1000))
|
771
|
+
|
772
|
+
assert_equal(-1, @dmp.match_main("", "abcdef", 1))
|
773
|
+
|
774
|
+
assert_equal(3, @dmp.match_main("abcdef", "", 3))
|
775
|
+
|
776
|
+
assert_equal(3, @dmp.match_main("abcdef", "de", 3))
|
777
|
+
|
778
|
+
# Beyond end match.
|
779
|
+
assert_equal(3, @dmp.match_main("abcdef", "defy", 4))
|
780
|
+
|
781
|
+
# Oversized pattern.
|
782
|
+
assert_equal(0, @dmp.match_main("abcdef", "abcdefy", 0))
|
783
|
+
|
784
|
+
# Complex match.
|
785
|
+
assert_equal(
|
786
|
+
4,
|
787
|
+
@dmp.match_main(
|
788
|
+
"I am the very model of a modern major general.",
|
789
|
+
" that berry ",
|
790
|
+
5
|
791
|
+
)
|
792
|
+
)
|
793
|
+
|
794
|
+
# Test null inputs.
|
795
|
+
assert_raises ArgumentError do
|
796
|
+
@dmp.match_main(nil, nil, 0)
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
# Patch tests
|
801
|
+
|
802
|
+
def test_patch_obj
|
803
|
+
# Patch Object.
|
804
|
+
p = PatchObj.new
|
805
|
+
p.start1 = 20
|
806
|
+
p.start2 = 21
|
807
|
+
p.length1 = 18
|
808
|
+
p.length2 = 17
|
809
|
+
p.diffs = [
|
810
|
+
[:equal, "jump"],
|
811
|
+
[:delete, "s"],
|
812
|
+
[:insert, "ed"],
|
813
|
+
[:equal, " over "],
|
814
|
+
[:delete, "the"],
|
815
|
+
[:insert, "a"],
|
816
|
+
[:equal, "\nlaz"]
|
817
|
+
]
|
818
|
+
strp = p.to_s
|
819
|
+
assert_equal(
|
820
|
+
"@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n %0Alaz\n",
|
821
|
+
strp
|
822
|
+
)
|
823
|
+
end
|
824
|
+
|
825
|
+
def test_patch_from_text
|
826
|
+
assert_equal([], @dmp.patch_from_text(""))
|
827
|
+
|
828
|
+
[
|
829
|
+
"@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n %0Alaz\n",
|
830
|
+
"@@ -1 +1 @@\n-a\n+b\n",
|
831
|
+
"@@ -1 +1 @@\n-a\n+b\n",
|
832
|
+
"@@ -0,0 +1,3 @@\n+abc\n"
|
833
|
+
].each do |strp|
|
834
|
+
assert_equal(strp, @dmp.patch_from_text(strp).first.to_s)
|
835
|
+
end
|
836
|
+
|
837
|
+
# Generates error.
|
838
|
+
assert_raises ArgumentError do
|
839
|
+
@dmp.patch_from_text('Bad\nPatch\n')
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
def test_patch_to_text
|
844
|
+
[
|
845
|
+
"@@ -21,18 +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n laz\n",
|
846
|
+
"@@ -1,9 +1,9 @@\n-f\n+F\n oo+fooba\n@@ -7,9 +7,9 @@\n obar\n-,\n+.\n tes\n"
|
847
|
+
].each do |strp|
|
848
|
+
p = @dmp.patch_from_text(strp)
|
849
|
+
assert_equal(strp, @dmp.patch_to_text(p))
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
def test_patch_add_context
|
854
|
+
@dmp.patch_margin = 4
|
855
|
+
p = @dmp.patch_from_text("@@ -21,4 +21,10 @@\n-jump\n+somersault\n").first
|
856
|
+
@dmp.patch_add_context(p, "The quick brown fox jumps over the lazy dog.")
|
857
|
+
assert_equal(
|
858
|
+
"@@ -17,12 +17,18 @@\n fox \n-jump\n+somersault\n s ov\n",
|
859
|
+
p.to_s
|
860
|
+
)
|
861
|
+
|
862
|
+
# Same, but not enough trailing context.
|
863
|
+
p = @dmp.patch_from_text("@@ -21,4 +21,10 @@\n-jump\n+somersault\n").first
|
864
|
+
@dmp.patch_add_context(p, "The quick brown fox jumps.")
|
865
|
+
assert_equal(
|
866
|
+
"@@ -17,10 +17,16 @@\n fox \n-jump\n+somersault\n s.\n",
|
867
|
+
p.to_s
|
868
|
+
)
|
869
|
+
|
870
|
+
# Same, but not enough leading context.
|
871
|
+
p = @dmp.patch_from_text("@@ -3 +3,2 @@\n-e\n+at\n").first
|
872
|
+
@dmp.patch_add_context(p, "The quick brown fox jumps.")
|
873
|
+
assert_equal(
|
874
|
+
"@@ -1,7 +1,8 @@\n Th\n-e\n+at\n qui\n",
|
875
|
+
p.to_s
|
876
|
+
)
|
877
|
+
|
878
|
+
# Same, but with ambiguity.
|
879
|
+
p = @dmp.patch_from_text("@@ -3 +3,2 @@\n-e\n+at\n").first
|
880
|
+
@dmp.patch_add_context(
|
881
|
+
p,
|
882
|
+
"The quick brown fox jumps. The quick brown fox crashes."
|
883
|
+
)
|
884
|
+
|
885
|
+
assert_equal(
|
886
|
+
"@@ -1,27 +1,28 @@\n Th\n-e\n+at\n quick brown fox jumps. \n",
|
887
|
+
p.to_s
|
888
|
+
)
|
889
|
+
end
|
890
|
+
|
891
|
+
def test_patch_make
|
892
|
+
# Null case.
|
893
|
+
patches = @dmp.patch_make("", "")
|
894
|
+
assert_equal("", @dmp.patch_to_text(patches))
|
895
|
+
|
896
|
+
text1 = "The quick brown fox jumps over the lazy dog."
|
897
|
+
text2 = "That quick brown fox jumped over a lazy dog."
|
898
|
+
# Text2+Text1 inputs.
|
899
|
+
expected = "@@ -1,8 +1,7 @@\n Th\n-at\n+e\n qui\n@@ -21,17 +21,18 " \
|
900
|
+
"@@\n jump\n-ed\n+s\n over \n-a\n+the\n laz\n"
|
901
|
+
|
902
|
+
# The second patch must be "-21,17 +21,18",
|
903
|
+
# not "-22,17 +21,18" due to rolling context
|
904
|
+
patches = @dmp.patch_make(text2, text1)
|
905
|
+
assert_equal(expected, @dmp.patch_to_text(patches))
|
906
|
+
|
907
|
+
# Text1+Text2 inputs.
|
908
|
+
expected = "@@ -1,11 +1,12 @@\n Th\n-e\n+at\n quick b\n@@ -22,18" \
|
909
|
+
" +22,17 @@\n jump\n-s\n+ed\n over \n-the\n+a\n laz\n"
|
910
|
+
patches = @dmp.patch_make(text1, text2)
|
911
|
+
assert_equal(expected, @dmp.patch_to_text(patches))
|
912
|
+
|
913
|
+
# Diff input.
|
914
|
+
diffs = @dmp.diff_main(text1, text2, false)
|
915
|
+
patches = @dmp.patch_make(diffs)
|
916
|
+
assert_equal(expected, @dmp.patch_to_text(patches))
|
917
|
+
|
918
|
+
# Text1+Diff inputs.
|
919
|
+
patches = @dmp.patch_make(text1, diffs)
|
920
|
+
assert_equal(expected, @dmp.patch_to_text(patches))
|
921
|
+
|
922
|
+
# Text1+Text2+Diff inputs (deprecated)
|
923
|
+
patches = @dmp.patch_make(text1, text2, diffs)
|
924
|
+
assert_equal(expected, @dmp.patch_to_text(patches))
|
925
|
+
|
926
|
+
# Character encoding.
|
927
|
+
patches = @dmp.patch_make(
|
928
|
+
'`1234567890-=[]\\;\',./',
|
929
|
+
'~!@#$%^&*()_+{}|:"<>?'
|
930
|
+
)
|
931
|
+
assert_equal(
|
932
|
+
"@@ -1,21 +1,21 @@\n-%601234567890-=%5B%5D%5C;\',./\n+~!" \
|
933
|
+
"@\#$%25%5E&*()_+%7B%7D%7C:%22%3C%3E?\n",
|
934
|
+
@dmp.patch_to_text(patches)
|
935
|
+
)
|
936
|
+
|
937
|
+
# Character decoding.
|
938
|
+
diffs = [
|
939
|
+
[:delete, '`1234567890-=[]\\;\',./'],
|
940
|
+
[:insert, '~!@#$%^&*()_+{}|:"<>?']
|
941
|
+
]
|
942
|
+
assert_equal(
|
943
|
+
diffs,
|
944
|
+
@dmp.patch_from_text(
|
945
|
+
"@@ -1,21 +1,21 @@\n-%601234567890-=%5B%5D%5C;\',./\n+~!" \
|
946
|
+
"@\#$%25%5E&*()_+%7B%7D%7C:%22%3C%3E?\n"
|
947
|
+
).first.diffs
|
948
|
+
)
|
949
|
+
|
950
|
+
# Long string with repeats.
|
951
|
+
text1 = "abcdef" * 100
|
952
|
+
text2 = text1 + "123"
|
953
|
+
expected = "@@ -573,28 +573,31 @@\n cdefabcdefabcdefabcdefabcdef\n+123\n"
|
954
|
+
patches = @dmp.patch_make(text1, text2)
|
955
|
+
assert_equal(expected, @dmp.patch_to_text(patches))
|
956
|
+
|
957
|
+
# Test null inputs.
|
958
|
+
assert_raises ArgumentError do
|
959
|
+
@dmp.patch_make(nil)
|
960
|
+
end
|
961
|
+
end
|
962
|
+
|
963
|
+
def test_patch_split_max
|
964
|
+
# Assumes that dmp.Match_MaxBits is 32.
|
965
|
+
patches = @dmp.patch_make(
|
966
|
+
"abcdefghijklmnopqrstuvwxyz01234567890",
|
967
|
+
"XabXcdXefXghXijXklXmnXopXqrXstXuvXwxXyzX01X23X45X67X89X0"
|
968
|
+
)
|
969
|
+
|
970
|
+
@dmp.patch_split_max(patches)
|
971
|
+
assert_equal(
|
972
|
+
"@@ -1,32 +1,46 @@\n+X\n ab\n+X\n cd\n+X\n ef\n+X\n gh\n+X\n " \
|
973
|
+
"ij\n+X\n kl\n+X\n mn\n+X\n op\n+X\n qr\n+X\n st\n+X\n uv\n+X\n " \
|
974
|
+
"wx\n+X\n yz\n+X\n 012345\n@@ -25,13 +39,18 @@\n zX01\n+X\n 23\n+X\n " \
|
975
|
+
"45\n+X\n 67\n+X\n 89\n+X\n 0\n",
|
976
|
+
@dmp.patch_to_text(patches)
|
977
|
+
)
|
978
|
+
|
979
|
+
patches = @dmp.patch_make(
|
980
|
+
"abcdef1234567890123456789012345678901234567890" \
|
981
|
+
"123456789012345678901234567890uvwxyz",
|
982
|
+
"abcdefuvwxyz"
|
983
|
+
)
|
984
|
+
|
985
|
+
old_to_text = @dmp.patch_to_text(patches)
|
986
|
+
@dmp.patch_split_max(patches)
|
987
|
+
assert_equal(old_to_text, @dmp.patch_to_text(patches))
|
988
|
+
|
989
|
+
patches = @dmp.patch_make(
|
990
|
+
"1234567890123456789012345678901234567890123456789012345678901234567890",
|
991
|
+
"abc"
|
992
|
+
)
|
993
|
+
|
994
|
+
@dmp.patch_split_max(patches)
|
995
|
+
assert_equal(
|
996
|
+
"@@ -1,32 +1,4 @@\n-1234567890123456789012345678\n 9012\n" \
|
997
|
+
"@@ -29,32 +1,4 @@\n-9012345678901234567890123456\n 7890\n" \
|
998
|
+
"@@ -57,14 +1,3 @@\n-78901234567890\n+abc\n",
|
999
|
+
@dmp.patch_to_text(patches)
|
1000
|
+
)
|
1001
|
+
|
1002
|
+
patches = @dmp.patch_make(
|
1003
|
+
"abcdefghij , h : 0 , t : 1 abcdefghij , h : 0 , t : 1 abcdefghij , h : 0 , t : 1",
|
1004
|
+
"abcdefghij , h : 1 , t : 1 abcdefghij , h : 1 , t : 1 abcdefghij , h : 0 , t : 1"
|
1005
|
+
)
|
1006
|
+
|
1007
|
+
@dmp.patch_split_max(patches)
|
1008
|
+
assert_equal(
|
1009
|
+
"@@ -2,32 +2,32 @@\n bcdefghij , h : \n-0\n+1\n , t : 1 abcdef\n" \
|
1010
|
+
"@@ -29,32 +29,32 @@\n bcdefghij , h : \n-0\n+1\n , t : 1 abcdef\n",
|
1011
|
+
@dmp.patch_to_text(patches)
|
1012
|
+
)
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
def test_patch_add_padding
|
1016
|
+
# Both edges full.
|
1017
|
+
patches = @dmp.patch_make("", "test")
|
1018
|
+
assert_equal("@@ -0,0 +1,4 @@\n+test\n", @dmp.patch_to_text(patches))
|
1019
|
+
@dmp.patch_add_padding(patches)
|
1020
|
+
assert_equal(
|
1021
|
+
"@@ -1,8 +1,12 @@\n %01%02%03%04\n+test\n %01%02%03%04\n",
|
1022
|
+
@dmp.patch_to_text(patches)
|
1023
|
+
)
|
1024
|
+
|
1025
|
+
# Both edges partial.
|
1026
|
+
patches = @dmp.patch_make("XY", "XtestY")
|
1027
|
+
assert_equal("@@ -1,2 +1,6 @@\n X\n+test\n Y\n", @dmp.patch_to_text(patches))
|
1028
|
+
@dmp.patch_add_padding(patches)
|
1029
|
+
assert_equal(
|
1030
|
+
"@@ -2,8 +2,12 @@\n %02%03%04X\n+test\n Y%01%02%03\n",
|
1031
|
+
@dmp.patch_to_text(patches)
|
1032
|
+
)
|
1033
|
+
|
1034
|
+
# Both edges none.
|
1035
|
+
patches = @dmp.patch_make("XXXXYYYY", "XXXXtestYYYY")
|
1036
|
+
assert_equal(
|
1037
|
+
"@@ -1,8 +1,12 @@\n XXXX\n+test\n YYYY\n",
|
1038
|
+
@dmp.patch_to_text(patches)
|
1039
|
+
)
|
1040
|
+
@dmp.patch_add_padding(patches)
|
1041
|
+
assert_equal(
|
1042
|
+
"@@ -5,8 +5,12 @@\n XXXX\n+test\n YYYY\n",
|
1043
|
+
@dmp.patch_to_text(patches)
|
1044
|
+
)
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
def test_patch_apply
|
1048
|
+
@dmp.match_distance = 1000
|
1049
|
+
@dmp.match_threshold = 0.5
|
1050
|
+
@dmp.patch_delete_threshold = 0.5
|
1051
|
+
# Null case.
|
1052
|
+
patches = @dmp.patch_make("", "")
|
1053
|
+
results = @dmp.patch_apply(patches, "Hello world.")
|
1054
|
+
assert_equal(["Hello world.", []], results)
|
1055
|
+
|
1056
|
+
# Exact match.
|
1057
|
+
patches = @dmp.patch_make(
|
1058
|
+
"The quick brown fox jumps over the lazy dog.",
|
1059
|
+
"That quick brown fox jumped over a lazy dog."
|
1060
|
+
)
|
1061
|
+
|
1062
|
+
results = @dmp.patch_apply(
|
1063
|
+
patches,
|
1064
|
+
"The quick brown fox jumps over the lazy dog."
|
1065
|
+
)
|
1066
|
+
|
1067
|
+
assert_equal(
|
1068
|
+
["That quick brown fox jumped over a lazy dog.", [true, true]],
|
1069
|
+
results
|
1070
|
+
)
|
1071
|
+
|
1072
|
+
# Partial match.
|
1073
|
+
results = @dmp.patch_apply(
|
1074
|
+
patches,
|
1075
|
+
"The quick red rabbit jumps over the tired tiger."
|
1076
|
+
)
|
1077
|
+
|
1078
|
+
assert_equal(
|
1079
|
+
["That quick red rabbit jumped over a tired tiger.", [true, true]],
|
1080
|
+
results
|
1081
|
+
)
|
1082
|
+
|
1083
|
+
# Failed match.
|
1084
|
+
results = @dmp.patch_apply(
|
1085
|
+
patches,
|
1086
|
+
"I am the very model of a modern major general."
|
1087
|
+
)
|
1088
|
+
|
1089
|
+
assert_equal(
|
1090
|
+
["I am the very model of a modern major general.", [false, false]],
|
1091
|
+
results
|
1092
|
+
)
|
1093
|
+
|
1094
|
+
# Big delete, small change.
|
1095
|
+
patches = @dmp.patch_make(
|
1096
|
+
"x1234567890123456789012345678901234567890123456789012345678901234567890y",
|
1097
|
+
"xabcy"
|
1098
|
+
)
|
1099
|
+
|
1100
|
+
results = @dmp.patch_apply(
|
1101
|
+
patches,
|
1102
|
+
"x123456789012345678901234567890-----++++++++++-----" \
|
1103
|
+
"123456789012345678901234567890y"
|
1104
|
+
)
|
1105
|
+
|
1106
|
+
assert_equal(["xabcy", [true, true]], results)
|
1107
|
+
|
1108
|
+
# Big delete, big change 1.
|
1109
|
+
patches = @dmp.patch_make(
|
1110
|
+
"x1234567890123456789012345678901234567890123456789012345678901234567890y",
|
1111
|
+
"xabcy"
|
1112
|
+
)
|
1113
|
+
|
1114
|
+
results = @dmp.patch_apply(
|
1115
|
+
patches,
|
1116
|
+
"x12345678901234567890---------------++++++++++---------------" \
|
1117
|
+
"12345678901234567890y"
|
1118
|
+
)
|
1119
|
+
|
1120
|
+
assert_equal([
|
1121
|
+
"xabc12345678901234567890---------------++++++++++---------------" \
|
1122
|
+
"12345678901234567890y",
|
1123
|
+
[false, true]
|
1124
|
+
],
|
1125
|
+
results)
|
1126
|
+
|
1127
|
+
# Big delete, big change 2.
|
1128
|
+
@dmp.patch_delete_threshold = 0.6
|
1129
|
+
patches = @dmp.patch_make(
|
1130
|
+
"x1234567890123456789012345678901234567890123456789012345678901234567890y",
|
1131
|
+
"xabcy"
|
1132
|
+
)
|
1133
|
+
|
1134
|
+
results = @dmp.patch_apply(
|
1135
|
+
patches,
|
1136
|
+
"x12345678901234567890---------------++++++++++---------------" \
|
1137
|
+
"12345678901234567890y"
|
1138
|
+
)
|
1139
|
+
|
1140
|
+
assert_equal(["xabcy", [true, true]], results)
|
1141
|
+
@dmp.patch_delete_threshold = 0.5
|
1142
|
+
|
1143
|
+
# Compensate for failed patch.
|
1144
|
+
@dmp.match_threshold = 0.0
|
1145
|
+
@dmp.match_distance = 0
|
1146
|
+
patches = @dmp.patch_make(
|
1147
|
+
"abcdefghijklmnopqrstuvwxyz--------------------1234567890",
|
1148
|
+
"abcXXXXXXXXXXdefghijklmnopqrstuvwxyz--------------------" \
|
1149
|
+
"1234567YYYYYYYYYY890"
|
1150
|
+
)
|
1151
|
+
|
1152
|
+
results = @dmp.patch_apply(
|
1153
|
+
patches,
|
1154
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ--------------------1234567890"
|
1155
|
+
)
|
1156
|
+
|
1157
|
+
assert_equal([
|
1158
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ--------------------1234567YYYYYYYYYY890",
|
1159
|
+
[false, true]
|
1160
|
+
],
|
1161
|
+
results)
|
1162
|
+
@dmp.match_threshold = 0.5
|
1163
|
+
@dmp.match_distance = 1000
|
1164
|
+
|
1165
|
+
# No side effects.
|
1166
|
+
patches = @dmp.patch_make("", "test")
|
1167
|
+
patchstr = @dmp.patch_to_text(patches)
|
1168
|
+
@dmp.patch_apply(patches, "")
|
1169
|
+
assert_equal(patchstr, @dmp.patch_to_text(patches))
|
1170
|
+
|
1171
|
+
# No side effects with major delete.
|
1172
|
+
patches = @dmp.patch_make(
|
1173
|
+
"The quick brown fox jumps over the lazy dog.",
|
1174
|
+
"Woof"
|
1175
|
+
)
|
1176
|
+
|
1177
|
+
patchstr = @dmp.patch_to_text(patches)
|
1178
|
+
@dmp.patch_apply(patches, "The quick brown fox jumps over the lazy dog.")
|
1179
|
+
assert_equal(patchstr, @dmp.patch_to_text(patches))
|
1180
|
+
|
1181
|
+
# Edge exact match.
|
1182
|
+
patches = @dmp.patch_make("", "test")
|
1183
|
+
results = @dmp.patch_apply(patches, "")
|
1184
|
+
assert_equal(["test", [true]], results)
|
1185
|
+
|
1186
|
+
# Near edge exact match.
|
1187
|
+
patches = @dmp.patch_make("XY", "XtestY")
|
1188
|
+
results = @dmp.patch_apply(patches, "XY")
|
1189
|
+
assert_equal(["XtestY", [true]], results)
|
1190
|
+
|
1191
|
+
# Edge partial match.
|
1192
|
+
patches = @dmp.patch_make("y", "y123")
|
1193
|
+
results = @dmp.patch_apply(patches, "x")
|
1194
|
+
assert_equal(["x123", [true]], results)
|
1195
|
+
end
|
1196
|
+
end
|