dimapa 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ require "minitest/autorun"
@@ -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&para;<br></span><del style="background:#ffe6e6;">&lt;B&gt;' \
437
+ 'b&lt;/B&gt;</del><ins style="background:#e6ffe6;">c&amp;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