dimapa 0.1.0

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.
@@ -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