How to use diff class

Best Atoum code snippet using diff

diff_test.go

Source:diff_test.go Github

copy

Full Screen

1// Copyright (c) 2012-2016 The go-diff authors. All rights reserved.2// https://github.com/sergi/go-diff3// See the included LICENSE file for license details.4//5// go-diff is a Go implementation of Google's Diff, Match, and Patch library6// Original library is Copyright (c) 2006 Google Inc.7// http://code.google.com/p/google-diff-match-patch/8package diffmatchpatch9import (10 "bytes"11 "fmt"12 "strconv"13 "strings"14 "testing"15 "time"16 "unicode/utf8"17 "github.com/stretchr/testify/assert"18)19func pretty(diffs []Diff) string {20 var w bytes.Buffer21 for i, diff := range diffs {22 _, _ = w.WriteString(fmt.Sprintf("%v. ", i))23 switch diff.Type {24 case DiffInsert:25 _, _ = w.WriteString("DiffIns")26 case DiffDelete:27 _, _ = w.WriteString("DiffDel")28 case DiffEqual:29 _, _ = w.WriteString("DiffEql")30 default:31 _, _ = w.WriteString("Unknown")32 }33 _, _ = w.WriteString(fmt.Sprintf(": %v\n", diff.Text))34 }35 return w.String()36}37func diffRebuildTexts(diffs []Diff) []string {38 texts := []string{"", ""}39 for _, d := range diffs {40 if d.Type != DiffInsert {41 texts[0] += d.Text42 }43 if d.Type != DiffDelete {44 texts[1] += d.Text45 }46 }47 return texts48}49func TestDiffCommonPrefix(t *testing.T) {50 type TestCase struct {51 Name string52 Text1 string53 Text2 string54 Expected int55 }56 dmp := New()57 for i, tc := range []TestCase{58 {"Null", "abc", "xyz", 0},59 {"Non-null", "1234abcdef", "1234xyz", 4},60 {"Whole", "1234", "1234xyz", 4},61 } {62 actual := dmp.DiffCommonPrefix(tc.Text1, tc.Text2)63 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))64 }65}66func BenchmarkDiffCommonPrefix(b *testing.B) {67 s := "ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"68 dmp := New()69 for i := 0; i < b.N; i++ {70 dmp.DiffCommonPrefix(s, s)71 }72}73func TestCommonPrefixLength(t *testing.T) {74 type TestCase struct {75 Text1 string76 Text2 string77 Expected int78 }79 for i, tc := range []TestCase{80 {"abc", "xyz", 0},81 {"1234abcdef", "1234xyz", 4},82 {"1234", "1234xyz", 4},83 } {84 actual := commonPrefixLength([]rune(tc.Text1), []rune(tc.Text2))85 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))86 }87}88func TestDiffCommonSuffix(t *testing.T) {89 type TestCase struct {90 Name string91 Text1 string92 Text2 string93 Expected int94 }95 dmp := New()96 for i, tc := range []TestCase{97 {"Null", "abc", "xyz", 0},98 {"Non-null", "abcdef1234", "xyz1234", 4},99 {"Whole", "1234", "xyz1234", 4},100 } {101 actual := dmp.DiffCommonSuffix(tc.Text1, tc.Text2)102 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))103 }104}105var SinkInt int // exported sink var to avoid compiler optimizations in benchmarks106func BenchmarkDiffCommonSuffix(b *testing.B) {107 s := "ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"108 dmp := New()109 b.ResetTimer()110 for i := 0; i < b.N; i++ {111 SinkInt = dmp.DiffCommonSuffix(s, s)112 }113}114func BenchmarkCommonLength(b *testing.B) {115 data := []struct {116 name string117 x, y []rune118 }{119 {name: "empty", x: nil, y: []rune{}},120 {name: "short", x: []rune("AABCC"), y: []rune("AA-CC")},121 {name: "long",122 x: []rune(strings.Repeat("A", 1000) + "B" + strings.Repeat("C", 1000)),123 y: []rune(strings.Repeat("A", 1000) + "-" + strings.Repeat("C", 1000)),124 },125 }126 b.Run("prefix", func(b *testing.B) {127 for _, d := range data {128 b.Run(d.name, func(b *testing.B) {129 for i := 0; i < b.N; i++ {130 SinkInt = commonPrefixLength(d.x, d.y)131 }132 })133 }134 })135 b.Run("suffix", func(b *testing.B) {136 for _, d := range data {137 b.Run(d.name, func(b *testing.B) {138 for i := 0; i < b.N; i++ {139 SinkInt = commonSuffixLength(d.x, d.y)140 }141 })142 }143 })144}145func TestCommonSuffixLength(t *testing.T) {146 type TestCase struct {147 Text1 string148 Text2 string149 Expected int150 }151 for i, tc := range []TestCase{152 {"abc", "xyz", 0},153 {"abcdef1234", "xyz1234", 4},154 {"1234", "xyz1234", 4},155 {"123", "a3", 1},156 } {157 actual := commonSuffixLength([]rune(tc.Text1), []rune(tc.Text2))158 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))159 }160}161func TestDiffCommonOverlap(t *testing.T) {162 type TestCase struct {163 Name string164 Text1 string165 Text2 string166 Expected int167 }168 dmp := New()169 for i, tc := range []TestCase{170 {"Null", "", "abcd", 0},171 {"Whole", "abc", "abcd", 3},172 {"Null", "123456", "abcd", 0},173 {"Null", "123456xxx", "xxxabcd", 3},174 // Some overly clever languages (C#) may treat ligatures as equal to their component letters, e.g. U+FB01 == 'fi'175 {"Unicode", "fi", "\ufb01i", 0},176 } {177 actual := dmp.DiffCommonOverlap(tc.Text1, tc.Text2)178 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))179 }180}181func TestDiffHalfMatch(t *testing.T) {182 type TestCase struct {183 Text1 string184 Text2 string185 Expected []string186 }187 dmp := New()188 dmp.DiffTimeout = 1189 for i, tc := range []TestCase{190 // No match191 {"1234567890", "abcdef", nil},192 {"12345", "23", nil},193 // Single Match194 {"1234567890", "a345678z", []string{"12", "90", "a", "z", "345678"}},195 {"a345678z", "1234567890", []string{"a", "z", "12", "90", "345678"}},196 {"abc56789z", "1234567890", []string{"abc", "z", "1234", "0", "56789"}},197 {"a23456xyz", "1234567890", []string{"a", "xyz", "1", "7890", "23456"}},198 // Multiple Matches199 {"121231234123451234123121", "a1234123451234z", []string{"12123", "123121", "a", "z", "1234123451234"}},200 {"x-=-=-=-=-=-=-=-=-=-=-=-=", "xx-=-=-=-=-=-=-=", []string{"", "-=-=-=-=-=", "x", "", "x-=-=-=-=-=-=-="}},201 {"-=-=-=-=-=-=-=-=-=-=-=-=y", "-=-=-=-=-=-=-=yy", []string{"-=-=-=-=-=", "", "", "y", "-=-=-=-=-=-=-=y"}},202 // Non-optimal halfmatch, ptimal diff would be -q+x=H-i+e=lloHe+Hu=llo-Hew+y not -qHillo+x=HelloHe-w+Hulloy203 {"qHilloHelloHew", "xHelloHeHulloy", []string{"qHillo", "w", "x", "Hulloy", "HelloHe"}},204 } {205 actual := dmp.DiffHalfMatch(tc.Text1, tc.Text2)206 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))207 }208 dmp.DiffTimeout = 0209 for i, tc := range []TestCase{210 // Optimal no halfmatch211 {"qHilloHelloHew", "xHelloHeHulloy", nil},212 } {213 actual := dmp.DiffHalfMatch(tc.Text1, tc.Text2)214 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))215 }216}217func BenchmarkDiffHalfMatch(b *testing.B) {218 s1, s2 := speedtestTexts()219 dmp := New()220 b.ResetTimer()221 for i := 0; i < b.N; i++ {222 dmp.DiffHalfMatch(s1, s2)223 }224}225func TestDiffBisectSplit(t *testing.T) {226 type TestCase struct {227 Text1 string228 Text2 string229 }230 dmp := New()231 for _, tc := range []TestCase{232 {"STUV\x05WX\x05YZ\x05[", "WĺĻļ\x05YZ\x05ĽľĿŀZ"},233 } {234 diffs := dmp.diffBisectSplit([]rune(tc.Text1),235 []rune(tc.Text2), 7, 6, time.Now().Add(time.Hour))236 for _, d := range diffs {237 assert.True(t, utf8.ValidString(d.Text))238 }239 // TODO define the expected outcome240 }241}242func TestDiffLinesToChars(t *testing.T) {243 type TestCase struct {244 Text1 string245 Text2 string246 ExpectedChars1 string247 ExpectedChars2 string248 ExpectedLines []string249 }250 dmp := New()251 for i, tc := range []TestCase{252 {"", "alpha\r\nbeta\r\n\r\n\r\n", "", "\u0001\u0002\u0003\u0003", []string{"", "alpha\r\n", "beta\r\n", "\r\n"}},253 {"a", "b", "\u0001", "\u0002", []string{"", "a", "b"}},254 // Omit final newline.255 {"alpha\nbeta\nalpha", "", "\u0001\u0002\u0003", "", []string{"", "alpha\n", "beta\n", "alpha"}},256 } {257 actualChars1, actualChars2, actualLines := dmp.DiffLinesToChars(tc.Text1, tc.Text2)258 assert.Equal(t, tc.ExpectedChars1, actualChars1, fmt.Sprintf("Test case #%d, %#v", i, tc))259 assert.Equal(t, tc.ExpectedChars2, actualChars2, fmt.Sprintf("Test case #%d, %#v", i, tc))260 assert.Equal(t, tc.ExpectedLines, actualLines, fmt.Sprintf("Test case #%d, %#v", i, tc))261 }262 // More than 256 to reveal any 8-bit limitations.263 n := 300264 lineList := []string{265 "", // Account for the initial empty element of the lines array.266 }267 var charList []rune268 for x := 1; x < n+1; x++ {269 lineList = append(lineList, strconv.Itoa(x)+"\n")270 charList = append(charList, rune(x))271 }272 lines := strings.Join(lineList, "")273 chars := string(charList)274 assert.Equal(t, n, utf8.RuneCountInString(chars))275 actualChars1, actualChars2, actualLines := dmp.DiffLinesToChars(lines, "")276 assert.Equal(t, chars, actualChars1)277 assert.Equal(t, "", actualChars2)278 assert.Equal(t, lineList, actualLines)279}280func TestDiffCharsToLines(t *testing.T) {281 type TestCase struct {282 Diffs []Diff283 Lines []string284 Expected []Diff285 }286 dmp := New()287 for i, tc := range []TestCase{288 {289 Diffs: []Diff{290 {DiffEqual, "\u0001\u0002\u0001"},291 {DiffInsert, "\u0002\u0001\u0002"},292 },293 Lines: []string{"", "alpha\n", "beta\n"},294 Expected: []Diff{295 {DiffEqual, "alpha\nbeta\nalpha\n"},296 {DiffInsert, "beta\nalpha\nbeta\n"},297 },298 },299 } {300 actual := dmp.DiffCharsToLines(tc.Diffs, tc.Lines)301 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))302 }303 // More than 256 to reveal any 8-bit limitations.304 n := 300305 lineList := []string{306 "", // Account for the initial empty element of the lines array.307 }308 charList := []rune{}309 for x := 1; x <= n; x++ {310 lineList = append(lineList, strconv.Itoa(x)+"\n")311 charList = append(charList, rune(x))312 }313 assert.Equal(t, n, len(charList))314 actual := dmp.DiffCharsToLines([]Diff{Diff{DiffDelete, string(charList)}}, lineList)315 assert.Equal(t, []Diff{Diff{DiffDelete, strings.Join(lineList, "")}}, actual)316}317func TestDiffCleanupMerge(t *testing.T) {318 type TestCase struct {319 Name string320 Diffs []Diff321 Expected []Diff322 }323 dmp := New()324 for i, tc := range []TestCase{325 {326 "Null case",327 []Diff{},328 []Diff{},329 },330 {331 "No Diff case",332 []Diff{Diff{DiffEqual, "a"}, Diff{DiffDelete, "b"}, Diff{DiffInsert, "c"}},333 []Diff{Diff{DiffEqual, "a"}, Diff{DiffDelete, "b"}, Diff{DiffInsert, "c"}},334 },335 {336 "Merge equalities",337 []Diff{Diff{DiffEqual, "a"}, Diff{DiffEqual, "b"}, Diff{DiffEqual, "c"}},338 []Diff{Diff{DiffEqual, "abc"}},339 },340 {341 "Merge deletions",342 []Diff{Diff{DiffDelete, "a"}, Diff{DiffDelete, "b"}, Diff{DiffDelete, "c"}},343 []Diff{Diff{DiffDelete, "abc"}},344 },345 {346 "Merge insertions",347 []Diff{Diff{DiffInsert, "a"}, Diff{DiffInsert, "b"}, Diff{DiffInsert, "c"}},348 []Diff{Diff{DiffInsert, "abc"}},349 },350 {351 "Merge interweave",352 []Diff{Diff{DiffDelete, "a"}, Diff{DiffInsert, "b"}, Diff{DiffDelete, "c"}, Diff{DiffInsert, "d"}, Diff{DiffEqual, "e"}, Diff{DiffEqual, "f"}},353 []Diff{Diff{DiffDelete, "ac"}, Diff{DiffInsert, "bd"}, Diff{DiffEqual, "ef"}},354 },355 {356 "Prefix and suffix detection",357 []Diff{Diff{DiffDelete, "a"}, Diff{DiffInsert, "abc"}, Diff{DiffDelete, "dc"}},358 []Diff{Diff{DiffEqual, "a"}, Diff{DiffDelete, "d"}, Diff{DiffInsert, "b"}, Diff{DiffEqual, "c"}},359 },360 {361 "Prefix and suffix detection with equalities",362 []Diff{Diff{DiffEqual, "x"}, Diff{DiffDelete, "a"}, Diff{DiffInsert, "abc"}, Diff{DiffDelete, "dc"}, Diff{DiffEqual, "y"}},363 []Diff{Diff{DiffEqual, "xa"}, Diff{DiffDelete, "d"}, Diff{DiffInsert, "b"}, Diff{DiffEqual, "cy"}},364 },365 {366 "Same test as above but with unicode (\u0101 will appear in diffs with at least 257 unique lines)",367 []Diff{Diff{DiffEqual, "x"}, Diff{DiffDelete, "\u0101"}, Diff{DiffInsert, "\u0101bc"}, Diff{DiffDelete, "dc"}, Diff{DiffEqual, "y"}},368 []Diff{Diff{DiffEqual, "x\u0101"}, Diff{DiffDelete, "d"}, Diff{DiffInsert, "b"}, Diff{DiffEqual, "cy"}},369 },370 {371 "Slide edit left",372 []Diff{Diff{DiffEqual, "a"}, Diff{DiffInsert, "ba"}, Diff{DiffEqual, "c"}},373 []Diff{Diff{DiffInsert, "ab"}, Diff{DiffEqual, "ac"}},374 },375 {376 "Slide edit right",377 []Diff{Diff{DiffEqual, "c"}, Diff{DiffInsert, "ab"}, Diff{DiffEqual, "a"}},378 []Diff{Diff{DiffEqual, "ca"}, Diff{DiffInsert, "ba"}},379 },380 {381 "Slide edit left recursive",382 []Diff{Diff{DiffEqual, "a"}, Diff{DiffDelete, "b"}, Diff{DiffEqual, "c"}, Diff{DiffDelete, "ac"}, Diff{DiffEqual, "x"}},383 []Diff{Diff{DiffDelete, "abc"}, Diff{DiffEqual, "acx"}},384 },385 {386 "Slide edit right recursive",387 []Diff{Diff{DiffEqual, "x"}, Diff{DiffDelete, "ca"}, Diff{DiffEqual, "c"}, Diff{DiffDelete, "b"}, Diff{DiffEqual, "a"}},388 []Diff{Diff{DiffEqual, "xca"}, Diff{DiffDelete, "cba"}},389 },390 } {391 actual := dmp.DiffCleanupMerge(tc.Diffs)392 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))393 }394}395func TestDiffCleanupSemanticLossless(t *testing.T) {396 type TestCase struct {397 Name string398 Diffs []Diff399 Expected []Diff400 }401 dmp := New()402 for i, tc := range []TestCase{403 {404 "Null case",405 []Diff{},406 []Diff{},407 },408 {409 "Blank lines",410 []Diff{411 Diff{DiffEqual, "AAA\r\n\r\nBBB"},412 Diff{DiffInsert, "\r\nDDD\r\n\r\nBBB"},413 Diff{DiffEqual, "\r\nEEE"},414 },415 []Diff{416 Diff{DiffEqual, "AAA\r\n\r\n"},417 Diff{DiffInsert, "BBB\r\nDDD\r\n\r\n"},418 Diff{DiffEqual, "BBB\r\nEEE"},419 },420 },421 {422 "Line boundaries",423 []Diff{424 Diff{DiffEqual, "AAA\r\nBBB"},425 Diff{DiffInsert, " DDD\r\nBBB"},426 Diff{DiffEqual, " EEE"},427 },428 []Diff{429 Diff{DiffEqual, "AAA\r\n"},430 Diff{DiffInsert, "BBB DDD\r\n"},431 Diff{DiffEqual, "BBB EEE"},432 },433 },434 {435 "Word boundaries",436 []Diff{437 Diff{DiffEqual, "The c"},438 Diff{DiffInsert, "ow and the c"},439 Diff{DiffEqual, "at."},440 },441 []Diff{442 Diff{DiffEqual, "The "},443 Diff{DiffInsert, "cow and the "},444 Diff{DiffEqual, "cat."},445 },446 },447 {448 "Alphanumeric boundaries",449 []Diff{450 Diff{DiffEqual, "The-c"},451 Diff{DiffInsert, "ow-and-the-c"},452 Diff{DiffEqual, "at."},453 },454 []Diff{455 Diff{DiffEqual, "The-"},456 Diff{DiffInsert, "cow-and-the-"},457 Diff{DiffEqual, "cat."},458 },459 },460 {461 "Hitting the start",462 []Diff{463 Diff{DiffEqual, "a"},464 Diff{DiffDelete, "a"},465 Diff{DiffEqual, "ax"},466 },467 []Diff{468 Diff{DiffDelete, "a"},469 Diff{DiffEqual, "aax"},470 },471 },472 {473 "Hitting the end",474 []Diff{475 Diff{DiffEqual, "xa"},476 Diff{DiffDelete, "a"},477 Diff{DiffEqual, "a"},478 },479 []Diff{480 Diff{DiffEqual, "xaa"},481 Diff{DiffDelete, "a"},482 },483 },484 {485 "Sentence boundaries",486 []Diff{487 Diff{DiffEqual, "The xxx. The "},488 Diff{DiffInsert, "zzz. The "},489 Diff{DiffEqual, "yyy."},490 },491 []Diff{492 Diff{DiffEqual, "The xxx."},493 Diff{DiffInsert, " The zzz."},494 Diff{DiffEqual, " The yyy."},495 },496 },497 {498 "UTF-8 strings",499 []Diff{500 Diff{DiffEqual, "The ♕. The "},501 Diff{DiffInsert, "♔. The "},502 Diff{DiffEqual, "♖."},503 },504 []Diff{505 Diff{DiffEqual, "The ♕."},506 Diff{DiffInsert, " The ♔."},507 Diff{DiffEqual, " The ♖."},508 },509 },510 {511 "Rune boundaries",512 []Diff{513 Diff{DiffEqual, "♕♕"},514 Diff{DiffInsert, "♔♔"},515 Diff{DiffEqual, "♖♖"},516 },517 []Diff{518 Diff{DiffEqual, "♕♕"},519 Diff{DiffInsert, "♔♔"},520 Diff{DiffEqual, "♖♖"},521 },522 },523 } {524 actual := dmp.DiffCleanupSemanticLossless(tc.Diffs)525 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))526 }527}528func TestDiffCleanupSemantic(t *testing.T) {529 type TestCase struct {530 Name string531 Diffs []Diff532 Expected []Diff533 }534 dmp := New()535 for i, tc := range []TestCase{536 {537 "Null case",538 []Diff{},539 []Diff{},540 },541 {542 "No elimination #1",543 []Diff{544 {DiffDelete, "ab"},545 {DiffInsert, "cd"},546 {DiffEqual, "12"},547 {DiffDelete, "e"},548 },549 []Diff{550 {DiffDelete, "ab"},551 {DiffInsert, "cd"},552 {DiffEqual, "12"},553 {DiffDelete, "e"},554 },555 },556 {557 "No elimination #2",558 []Diff{559 {DiffDelete, "abc"},560 {DiffInsert, "ABC"},561 {DiffEqual, "1234"},562 {DiffDelete, "wxyz"},563 },564 []Diff{565 {DiffDelete, "abc"},566 {DiffInsert, "ABC"},567 {DiffEqual, "1234"},568 {DiffDelete, "wxyz"},569 },570 },571 {572 "No elimination #3",573 []Diff{574 {DiffEqual, "2016-09-01T03:07:1"},575 {DiffInsert, "5.15"},576 {DiffEqual, "4"},577 {DiffDelete, "."},578 {DiffEqual, "80"},579 {DiffInsert, "0"},580 {DiffEqual, "78"},581 {DiffDelete, "3074"},582 {DiffEqual, "1Z"},583 },584 []Diff{585 {DiffEqual, "2016-09-01T03:07:1"},586 {DiffInsert, "5.15"},587 {DiffEqual, "4"},588 {DiffDelete, "."},589 {DiffEqual, "80"},590 {DiffInsert, "0"},591 {DiffEqual, "78"},592 {DiffDelete, "3074"},593 {DiffEqual, "1Z"},594 },595 },596 {597 "Simple elimination",598 []Diff{599 {DiffDelete, "a"},600 {DiffEqual, "b"},601 {DiffDelete, "c"},602 },603 []Diff{604 {DiffDelete, "abc"},605 {DiffInsert, "b"},606 },607 },608 {609 "Backpass elimination",610 []Diff{611 {DiffDelete, "ab"},612 {DiffEqual, "cd"},613 {DiffDelete, "e"},614 {DiffEqual, "f"},615 {DiffInsert, "g"},616 },617 []Diff{618 {DiffDelete, "abcdef"},619 {DiffInsert, "cdfg"},620 },621 },622 {623 "Multiple eliminations",624 []Diff{625 {DiffInsert, "1"},626 {DiffEqual, "A"},627 {DiffDelete, "B"},628 {DiffInsert, "2"},629 {DiffEqual, "_"},630 {DiffInsert, "1"},631 {DiffEqual, "A"},632 {DiffDelete, "B"},633 {DiffInsert, "2"},634 },635 []Diff{636 {DiffDelete, "AB_AB"},637 {DiffInsert, "1A2_1A2"},638 },639 },640 {641 "Word boundaries",642 []Diff{643 {DiffEqual, "The c"},644 {DiffDelete, "ow and the c"},645 {DiffEqual, "at."},646 },647 []Diff{648 {DiffEqual, "The "},649 {DiffDelete, "cow and the "},650 {DiffEqual, "cat."},651 },652 },653 {654 "No overlap elimination",655 []Diff{656 {DiffDelete, "abcxx"},657 {DiffInsert, "xxdef"},658 },659 []Diff{660 {DiffDelete, "abcxx"},661 {DiffInsert, "xxdef"},662 },663 },664 {665 "Overlap elimination",666 []Diff{667 {DiffDelete, "abcxxx"},668 {DiffInsert, "xxxdef"},669 },670 []Diff{671 {DiffDelete, "abc"},672 {DiffEqual, "xxx"},673 {DiffInsert, "def"},674 },675 },676 {677 "Reverse overlap elimination",678 []Diff{679 {DiffDelete, "xxxabc"},680 {DiffInsert, "defxxx"},681 },682 []Diff{683 {DiffInsert, "def"},684 {DiffEqual, "xxx"},685 {DiffDelete, "abc"},686 },687 },688 {689 "Two overlap eliminations",690 []Diff{691 {DiffDelete, "abcd1212"},692 {DiffInsert, "1212efghi"},693 {DiffEqual, "----"},694 {DiffDelete, "A3"},695 {DiffInsert, "3BC"},696 },697 []Diff{698 {DiffDelete, "abcd"},699 {DiffEqual, "1212"},700 {DiffInsert, "efghi"},701 {DiffEqual, "----"},702 {DiffDelete, "A"},703 {DiffEqual, "3"},704 {DiffInsert, "BC"},705 },706 },707 {708 "Test case for adapting DiffCleanupSemantic to be equal to the Python version #19",709 []Diff{710 {DiffEqual, "James McCarthy "},711 {DiffDelete, "close to "},712 {DiffEqual, "sign"},713 {DiffDelete, "ing"},714 {DiffInsert, "s"},715 {DiffEqual, " new "},716 {DiffDelete, "E"},717 {DiffInsert, "fi"},718 {DiffEqual, "ve"},719 {DiffInsert, "-yea"},720 {DiffEqual, "r"},721 {DiffDelete, "ton"},722 {DiffEqual, " deal"},723 {DiffInsert, " at Everton"},724 },725 []Diff{726 {DiffEqual, "James McCarthy "},727 {DiffDelete, "close to "},728 {DiffEqual, "sign"},729 {DiffDelete, "ing"},730 {DiffInsert, "s"},731 {DiffEqual, " new "},732 {DiffInsert, "five-year deal at "},733 {DiffEqual, "Everton"},734 {DiffDelete, " deal"},735 },736 },737 } {738 actual := dmp.DiffCleanupSemantic(tc.Diffs)739 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))740 }741}742func BenchmarkDiffCleanupSemantic(b *testing.B) {743 s1, s2 := speedtestTexts()744 dmp := New()745 diffs := dmp.DiffMain(s1, s2, false)746 b.ResetTimer()747 for i := 0; i < b.N; i++ {748 dmp.DiffCleanupSemantic(diffs)749 }750}751func TestDiffCleanupEfficiency(t *testing.T) {752 type TestCase struct {753 Name string754 Diffs []Diff755 Expected []Diff756 }757 dmp := New()758 dmp.DiffEditCost = 4759 for i, tc := range []TestCase{760 {761 "Null case",762 []Diff{},763 []Diff{},764 },765 {766 "No elimination",767 []Diff{768 Diff{DiffDelete, "ab"},769 Diff{DiffInsert, "12"},770 Diff{DiffEqual, "wxyz"},771 Diff{DiffDelete, "cd"},772 Diff{DiffInsert, "34"},773 },774 []Diff{775 Diff{DiffDelete, "ab"},776 Diff{DiffInsert, "12"},777 Diff{DiffEqual, "wxyz"},778 Diff{DiffDelete, "cd"},779 Diff{DiffInsert, "34"},780 },781 },782 {783 "Four-edit elimination",784 []Diff{785 Diff{DiffDelete, "ab"},786 Diff{DiffInsert, "12"},787 Diff{DiffEqual, "xyz"},788 Diff{DiffDelete, "cd"},789 Diff{DiffInsert, "34"},790 },791 []Diff{792 Diff{DiffDelete, "abxyzcd"},793 Diff{DiffInsert, "12xyz34"},794 },795 },796 {797 "Three-edit elimination",798 []Diff{799 Diff{DiffInsert, "12"},800 Diff{DiffEqual, "x"},801 Diff{DiffDelete, "cd"},802 Diff{DiffInsert, "34"},803 },804 []Diff{805 Diff{DiffDelete, "xcd"},806 Diff{DiffInsert, "12x34"},807 },808 },809 {810 "Backpass elimination",811 []Diff{812 Diff{DiffDelete, "ab"},813 Diff{DiffInsert, "12"},814 Diff{DiffEqual, "xy"},815 Diff{DiffInsert, "34"},816 Diff{DiffEqual, "z"},817 Diff{DiffDelete, "cd"},818 Diff{DiffInsert, "56"},819 },820 []Diff{821 Diff{DiffDelete, "abxyzcd"},822 Diff{DiffInsert, "12xy34z56"},823 },824 },825 } {826 actual := dmp.DiffCleanupEfficiency(tc.Diffs)827 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))828 }829 dmp.DiffEditCost = 5830 for i, tc := range []TestCase{831 {832 "High cost elimination",833 []Diff{834 Diff{DiffDelete, "ab"},835 Diff{DiffInsert, "12"},836 Diff{DiffEqual, "wxyz"},837 Diff{DiffDelete, "cd"},838 Diff{DiffInsert, "34"},839 },840 []Diff{841 Diff{DiffDelete, "abwxyzcd"},842 Diff{DiffInsert, "12wxyz34"},843 },844 },845 } {846 actual := dmp.DiffCleanupEfficiency(tc.Diffs)847 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))848 }849}850func TestDiffPrettyHtml(t *testing.T) {851 type TestCase struct {852 Diffs []Diff853 Expected string854 }855 dmp := New()856 for i, tc := range []TestCase{857 {858 Diffs: []Diff{859 {DiffEqual, "a\n"},860 {DiffDelete, "<B>b</B>"},861 {DiffInsert, "c&d"},862 },863 Expected: "<span>a&para;<br></span><del style=\"background:#ffe6e6;\">&lt;B&gt;b&lt;/B&gt;</del><ins style=\"background:#e6ffe6;\">c&amp;d</ins>",864 },865 } {866 actual := dmp.DiffPrettyHtml(tc.Diffs)867 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))868 }869}870func TestDiffPrettyText(t *testing.T) {871 type TestCase struct {872 Diffs []Diff873 Expected string874 }875 dmp := New()876 for i, tc := range []TestCase{877 {878 Diffs: []Diff{879 {DiffEqual, "a\n"},880 {DiffDelete, "<B>b</B>"},881 {DiffInsert, "c&d"},882 },883 Expected: "a\n\x1b[31m<B>b</B>\x1b[0m\x1b[32mc&d\x1b[0m",884 },885 } {886 actual := dmp.DiffPrettyText(tc.Diffs)887 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))888 }889}890func TestDiffText(t *testing.T) {891 type TestCase struct {892 Diffs []Diff893 ExpectedText1 string894 ExpectedText2 string895 }896 dmp := New()897 for i, tc := range []TestCase{898 {899 Diffs: []Diff{900 {DiffEqual, "jump"},901 {DiffDelete, "s"},902 {DiffInsert, "ed"},903 {DiffEqual, " over "},904 {DiffDelete, "the"},905 {DiffInsert, "a"},906 {DiffEqual, " lazy"},907 },908 ExpectedText1: "jumps over the lazy",909 ExpectedText2: "jumped over a lazy",910 },911 } {912 actualText1 := dmp.DiffText1(tc.Diffs)913 assert.Equal(t, tc.ExpectedText1, actualText1, fmt.Sprintf("Test case #%d, %#v", i, tc))914 actualText2 := dmp.DiffText2(tc.Diffs)915 assert.Equal(t, tc.ExpectedText2, actualText2, fmt.Sprintf("Test case #%d, %#v", i, tc))916 }917}918func TestDiffDelta(t *testing.T) {919 type TestCase struct {920 Name string921 Text string922 Delta string923 ErrorMessagePrefix string924 }925 dmp := New()926 for i, tc := range []TestCase{927 {"Delta shorter than text", "jumps over the lazyx", "=4\t-1\t+ed\t=6\t-3\t+a\t=5\t+old dog", "Delta length (19) is different from source text length (20)"},928 {"Delta longer than text", "umps over the lazy", "=4\t-1\t+ed\t=6\t-3\t+a\t=5\t+old dog", "Delta length (19) is different from source text length (18)"},929 {"Invalid URL escaping", "", "+%c3%xy", "invalid URL escape \"%xy\""},930 {"Invalid UTF-8 sequence", "", "+%c3xy", "invalid UTF-8 token: \"\\xc3xy\""},931 {"Invalid diff operation", "", "a", "Invalid diff operation in DiffFromDelta: a"},932 {"Invalid diff syntax", "", "-", "strconv.ParseInt: parsing \"\": invalid syntax"},933 {"Negative number in delta", "", "--1", "Negative number in DiffFromDelta: -1"},934 {"Empty case", "", "", ""},935 } {936 diffs, err := dmp.DiffFromDelta(tc.Text, tc.Delta)937 msg := fmt.Sprintf("Test case #%d, %s", i, tc.Name)938 if tc.ErrorMessagePrefix == "" {939 assert.Nil(t, err, msg)940 assert.Nil(t, diffs, msg)941 } else {942 e := err.Error()943 if strings.HasPrefix(e, tc.ErrorMessagePrefix) {944 e = tc.ErrorMessagePrefix945 }946 assert.Nil(t, diffs, msg)947 assert.Equal(t, tc.ErrorMessagePrefix, e, msg)948 }949 }950 // Convert a diff into delta string.951 diffs := []Diff{952 Diff{DiffEqual, "jump"},953 Diff{DiffDelete, "s"},954 Diff{DiffInsert, "ed"},955 Diff{DiffEqual, " over "},956 Diff{DiffDelete, "the"},957 Diff{DiffInsert, "a"},958 Diff{DiffEqual, " lazy"},959 Diff{DiffInsert, "old dog"},960 }961 text1 := dmp.DiffText1(diffs)962 assert.Equal(t, "jumps over the lazy", text1)963 delta := dmp.DiffToDelta(diffs)964 assert.Equal(t, "=4\t-1\t+ed\t=6\t-3\t+a\t=5\t+old dog", delta)965 // Convert delta string into a diff.966 deltaDiffs, err := dmp.DiffFromDelta(text1, delta)967 assert.Equal(t, diffs, deltaDiffs)968 // Test deltas with special characters.969 diffs = []Diff{970 Diff{DiffEqual, "\u0680 \x00 \t %"},971 Diff{DiffDelete, "\u0681 \x01 \n ^"},972 Diff{DiffInsert, "\u0682 \x02 \\ |"},973 }974 text1 = dmp.DiffText1(diffs)975 assert.Equal(t, "\u0680 \x00 \t %\u0681 \x01 \n ^", text1)976 // Lowercase, due to UrlEncode uses lower.977 delta = dmp.DiffToDelta(diffs)978 assert.Equal(t, "=7\t-7\t+%DA%82 %02 %5C %7C", delta)979 deltaDiffs, err = dmp.DiffFromDelta(text1, delta)980 assert.Equal(t, diffs, deltaDiffs)981 assert.Nil(t, err)982 // Verify pool of unchanged characters.983 diffs = []Diff{984 Diff{DiffInsert, "A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; / ? : @ & = + $ , # "},985 }986 delta = dmp.DiffToDelta(diffs)987 assert.Equal(t, "+A-Z a-z 0-9 - _ . ! ~ * ' ( ) ; / ? : @ & = + $ , # ", delta, "Unchanged characters.")988 // Convert delta string into a diff.989 deltaDiffs, err = dmp.DiffFromDelta("", delta)990 assert.Equal(t, diffs, deltaDiffs)991 assert.Nil(t, err)992}993func TestDiffXIndex(t *testing.T) {994 type TestCase struct {995 Name string996 Diffs []Diff997 Location int998 Expected int999 }1000 dmp := New()1001 for i, tc := range []TestCase{1002 {"Translation on equality", []Diff{{DiffDelete, "a"}, {DiffInsert, "1234"}, {DiffEqual, "xyz"}}, 2, 5},1003 {"Translation on deletion", []Diff{{DiffEqual, "a"}, {DiffDelete, "1234"}, {DiffEqual, "xyz"}}, 3, 1},1004 } {1005 actual := dmp.DiffXIndex(tc.Diffs, tc.Location)1006 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))1007 }1008}1009func TestDiffLevenshtein(t *testing.T) {1010 type TestCase struct {1011 Name string1012 Diffs []Diff1013 Expected int1014 }1015 dmp := New()1016 for i, tc := range []TestCase{1017 {"Levenshtein with trailing equality", []Diff{{DiffDelete, "абв"}, {DiffInsert, "1234"}, {DiffEqual, "эюя"}}, 4},1018 {"Levenshtein with leading equality", []Diff{{DiffEqual, "эюя"}, {DiffDelete, "абв"}, {DiffInsert, "1234"}}, 4},1019 {"Levenshtein with middle equality", []Diff{{DiffDelete, "абв"}, {DiffEqual, "эюя"}, {DiffInsert, "1234"}}, 7},1020 } {1021 actual := dmp.DiffLevenshtein(tc.Diffs)1022 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))1023 }1024}1025func TestDiffBisect(t *testing.T) {1026 type TestCase struct {1027 Name string1028 Time time.Time1029 Expected []Diff1030 }1031 dmp := New()1032 for i, tc := range []TestCase{1033 {1034 Name: "normal",1035 Time: time.Date(9999, time.December, 31, 23, 59, 59, 59, time.UTC),1036 Expected: []Diff{1037 {DiffDelete, "c"},1038 {DiffInsert, "m"},1039 {DiffEqual, "a"},1040 {DiffDelete, "t"},1041 {DiffInsert, "p"},1042 },1043 },1044 {1045 Name: "Negative deadlines count as having infinite time",1046 Time: time.Date(0001, time.January, 01, 00, 00, 00, 00, time.UTC),1047 Expected: []Diff{1048 {DiffDelete, "c"},1049 {DiffInsert, "m"},1050 {DiffEqual, "a"},1051 {DiffDelete, "t"},1052 {DiffInsert, "p"},1053 },1054 },1055 {1056 Name: "Timeout",1057 Time: time.Now().Add(time.Nanosecond),1058 Expected: []Diff{1059 {DiffDelete, "cat"},1060 {DiffInsert, "map"},1061 },1062 },1063 } {1064 actual := dmp.DiffBisect("cat", "map", tc.Time)1065 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %s", i, tc.Name))1066 }1067 // Test for invalid UTF-8 sequences1068 assert.Equal(t, []Diff{1069 Diff{DiffEqual, "��"},1070 }, dmp.DiffBisect("\xe0\xe5", "\xe0\xe5", time.Now().Add(time.Minute)))1071}1072func TestDiffMain(t *testing.T) {1073 type TestCase struct {1074 Text1 string1075 Text2 string1076 Expected []Diff1077 }1078 dmp := New()1079 // Perform a trivial diff.1080 for i, tc := range []TestCase{1081 {1082 "",1083 "",1084 nil,1085 },1086 {1087 "abc",1088 "abc",1089 []Diff{Diff{DiffEqual, "abc"}},1090 },1091 {1092 "abc",1093 "ab123c",1094 []Diff{Diff{DiffEqual, "ab"}, Diff{DiffInsert, "123"}, Diff{DiffEqual, "c"}},1095 },1096 {1097 "a123bc",1098 "abc",1099 []Diff{Diff{DiffEqual, "a"}, Diff{DiffDelete, "123"}, Diff{DiffEqual, "bc"}},1100 },1101 {1102 "abc",1103 "a123b456c",1104 []Diff{Diff{DiffEqual, "a"}, Diff{DiffInsert, "123"}, Diff{DiffEqual, "b"}, Diff{DiffInsert, "456"}, Diff{DiffEqual, "c"}},1105 },1106 {1107 "a123b456c",1108 "abc",1109 []Diff{Diff{DiffEqual, "a"}, Diff{DiffDelete, "123"}, Diff{DiffEqual, "b"}, Diff{DiffDelete, "456"}, Diff{DiffEqual, "c"}},1110 },1111 } {1112 actual := dmp.DiffMain(tc.Text1, tc.Text2, false)1113 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))1114 }1115 // Perform a real diff and switch off the timeout.1116 dmp.DiffTimeout = 01117 for i, tc := range []TestCase{1118 {1119 "a",1120 "b",1121 []Diff{Diff{DiffDelete, "a"}, Diff{DiffInsert, "b"}},1122 },1123 {1124 "Apples are a fruit.",1125 "Bananas are also fruit.",1126 []Diff{1127 Diff{DiffDelete, "Apple"},1128 Diff{DiffInsert, "Banana"},1129 Diff{DiffEqual, "s are a"},1130 Diff{DiffInsert, "lso"},1131 Diff{DiffEqual, " fruit."},1132 },1133 },1134 {1135 "ax\t",1136 "\u0680x\u0000",1137 []Diff{1138 Diff{DiffDelete, "a"},1139 Diff{DiffInsert, "\u0680"},1140 Diff{DiffEqual, "x"},1141 Diff{DiffDelete, "\t"},1142 Diff{DiffInsert, "\u0000"},1143 },1144 },1145 {1146 "1ayb2",1147 "abxab",1148 []Diff{1149 Diff{DiffDelete, "1"},1150 Diff{DiffEqual, "a"},1151 Diff{DiffDelete, "y"},1152 Diff{DiffEqual, "b"},1153 Diff{DiffDelete, "2"},1154 Diff{DiffInsert, "xab"},1155 },1156 },1157 {1158 "abcy",1159 "xaxcxabc",1160 []Diff{1161 Diff{DiffInsert, "xaxcx"},1162 Diff{DiffEqual, "abc"}, Diff{DiffDelete, "y"},1163 },1164 },1165 {1166 "ABCDa=bcd=efghijklmnopqrsEFGHIJKLMNOefg",1167 "a-bcd-efghijklmnopqrs",1168 []Diff{1169 Diff{DiffDelete, "ABCD"},1170 Diff{DiffEqual, "a"},1171 Diff{DiffDelete, "="},1172 Diff{DiffInsert, "-"},1173 Diff{DiffEqual, "bcd"},1174 Diff{DiffDelete, "="},1175 Diff{DiffInsert, "-"},1176 Diff{DiffEqual, "efghijklmnopqrs"},1177 Diff{DiffDelete, "EFGHIJKLMNOefg"},1178 },1179 },1180 {1181 "a [[Pennsylvania]] and [[New",1182 " and [[Pennsylvania]]",1183 []Diff{1184 Diff{DiffInsert, " "},1185 Diff{DiffEqual, "a"},1186 Diff{DiffInsert, "nd"},1187 Diff{DiffEqual, " [[Pennsylvania]]"},1188 Diff{DiffDelete, " and [[New"},1189 },1190 },1191 } {1192 actual := dmp.DiffMain(tc.Text1, tc.Text2, false)1193 assert.Equal(t, tc.Expected, actual, fmt.Sprintf("Test case #%d, %#v", i, tc))1194 }1195 // Test for invalid UTF-8 sequences1196 assert.Equal(t, []Diff{1197 Diff{DiffDelete, "��"},1198 }, dmp.DiffMain("\xe0\xe5", "", false))1199}1200func TestDiffMainWithTimeout(t *testing.T) {1201 dmp := New()1202 dmp.DiffTimeout = 200 * time.Millisecond1203 a := "`Twas brillig, and the slithy toves\nDid gyre and gimble in the wabe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe.\n"1204 b := "I am the very model of a modern major general,\nI've information vegetable, animal, and mineral,\nI know the kings of England, and I quote the fights historical,\nFrom Marathon to Waterloo, in order categorical.\n"1205 // Increase the text lengths by 1024 times to ensure a timeout.1206 for x := 0; x < 13; x++ {1207 a = a + a1208 b = b + b1209 }1210 startTime := time.Now()1211 dmp.DiffMain(a, b, true)1212 endTime := time.Now()1213 delta := endTime.Sub(startTime)1214 // Test that we took at least the timeout period.1215 assert.True(t, delta >= dmp.DiffTimeout, fmt.Sprintf("%v !>= %v", delta, dmp.DiffTimeout))1216 // Test that we didn't take forever (be very forgiving). Theoretically this test could fail very occasionally if the OS task swaps or locks up for a second at the wrong moment.1217 assert.True(t, delta < (dmp.DiffTimeout*100), fmt.Sprintf("%v !< %v", delta, dmp.DiffTimeout*100))1218}1219func TestDiffMainWithCheckLines(t *testing.T) {1220 type TestCase struct {1221 Text1 string1222 Text2 string1223 }1224 dmp := New()1225 dmp.DiffTimeout = 01226 // Test cases must be at least 100 chars long to pass the cutoff.1227 for i, tc := range []TestCase{1228 {1229 "1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n",1230 "abcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\nabcdefghij\n",1231 },1232 {1233 "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",1234 "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij",1235 },1236 {1237 "1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n1234567890\n",1238 "abcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n1234567890\n1234567890\n1234567890\nabcdefghij\n",1239 },1240 } {1241 resultWithoutCheckLines := dmp.DiffMain(tc.Text1, tc.Text2, false)1242 resultWithCheckLines := dmp.DiffMain(tc.Text1, tc.Text2, true)1243 // TODO this fails for the third test case, why?1244 if i != 2 {1245 assert.Equal(t, resultWithoutCheckLines, resultWithCheckLines, fmt.Sprintf("Test case #%d, %#v", i, tc))1246 }1247 assert.Equal(t, diffRebuildTexts(resultWithoutCheckLines), diffRebuildTexts(resultWithCheckLines), fmt.Sprintf("Test case #%d, %#v", i, tc))1248 }1249}1250func BenchmarkDiffMain(bench *testing.B) {1251 s1 := "`Twas brillig, and the slithy toves\nDid gyre and gimble in the wabe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe.\n"1252 s2 := "I am the very model of a modern major general,\nI've information vegetable, animal, and mineral,\nI know the kings of England, and I quote the fights historical,\nFrom Marathon to Waterloo, in order categorical.\n"1253 // Increase the text lengths by 1024 times to ensure a timeout.1254 for x := 0; x < 10; x++ {1255 s1 = s1 + s11256 s2 = s2 + s21257 }1258 dmp := New()1259 dmp.DiffTimeout = time.Second1260 bench.ResetTimer()1261 for i := 0; i < bench.N; i++ {1262 dmp.DiffMain(s1, s2, true)1263 }1264}1265func BenchmarkDiffMainLarge(b *testing.B) {1266 s1, s2 := speedtestTexts()1267 dmp := New()1268 b.ResetTimer()1269 for i := 0; i < b.N; i++ {1270 dmp.DiffMain(s1, s2, true)1271 }1272}1273func BenchmarkDiffMainRunesLargeLines(b *testing.B) {1274 s1, s2 := speedtestTexts()1275 dmp := New()1276 b.ResetTimer()1277 for i := 0; i < b.N; i++ {1278 text1, text2, linearray := dmp.DiffLinesToRunes(s1, s2)1279 diffs := dmp.DiffMainRunes(text1, text2, false)1280 diffs = dmp.DiffCharsToLines(diffs, linearray)1281 }1282}...

Full Screen

Full Screen

string.php

Source:string.php Github

copy

Full Screen

1<?php2/**3 * Parses unified or context diffs output from eg. the diff utility.4 *5 * Example:6 * <code>7 * $patch = file_get_contents('example.patch');8 * $diff = new Text_Diff('string', array($patch));9 * $renderer = new Text_Diff_Renderer_inline();10 * echo $renderer->render($diff);11 * </code>12 *13 * Copyright 2005 Örjan Persson <o@42mm.org>14 * Copyright 2005-2010 The Horde Project (http://www.horde.org/)15 *16 * See the enclosed file COPYING for license information (LGPL). If you did17 * not receive this file, see http://opensource.org/licenses/lgpl-license.php.18 *19 * @author Örjan Persson <o@42mm.org>20 * @package Text_Diff21 * @since 0.2.022 */23class Text_Diff_Engine_string {24 /**25 * Parses a unified or context diff.26 *27 * First param contains the whole diff and the second can be used to force28 * a specific diff type. If the second parameter is 'autodetect', the29 * diff will be examined to find out which type of diff this is.30 *31 * @param string $diff The diff content.32 * @param string $mode The diff mode of the content in $diff. One of33 * 'context', 'unified', or 'autodetect'.34 *35 * @return array List of all diff operations.36 */37 function diff($diff, $mode = 'autodetect')38 {39 // Detect line breaks.40 $lnbr = "\n";41 if (strpos($diff, "\r\n") !== false) {42 $lnbr = "\r\n";43 } elseif (strpos($diff, "\r") !== false) {44 $lnbr = "\r";45 }46 // Make sure we have a line break at the EOF.47 if (substr($diff, -strlen($lnbr)) != $lnbr) {48 $diff .= $lnbr;49 }50 if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') {51 return PEAR::raiseError('Type of diff is unsupported');52 }53 if ($mode == 'autodetect') {54 $context = strpos($diff, '***');55 $unified = strpos($diff, '---');56 if ($context === $unified) {57 return PEAR::raiseError('Type of diff could not be detected');58 } elseif ($context === false || $unified === false) {59 $mode = $context !== false ? 'context' : 'unified';60 } else {61 $mode = $context < $unified ? 'context' : 'unified';62 }63 }64 // Split by new line and remove the diff header, if there is one.65 $diff = explode($lnbr, $diff);66 if (($mode == 'context' && strpos($diff[0], '***') === 0) ||67 ($mode == 'unified' && strpos($diff[0], '---') === 0)) {68 array_shift($diff);69 array_shift($diff);70 }71 if ($mode == 'context') {72 return $this->parseContextDiff($diff);73 } else {74 return $this->parseUnifiedDiff($diff);75 }76 }77 /**78 * Parses an array containing the unified diff.79 *80 * @param array $diff Array of lines.81 *82 * @return array List of all diff operations.83 */84 function parseUnifiedDiff($diff)85 {86 $edits = array();87 $end = count($diff) - 1;88 for ($i = 0; $i < $end;) {89 $diff1 = array();90 switch (substr($diff[$i], 0, 1)) {91 case ' ':92 do {93 $diff1[] = substr($diff[$i], 1);94 } while (++$i < $end && substr($diff[$i], 0, 1) == ' ');95 $edits[] = new Text_Diff_Op_copy($diff1);96 break;97 case '+':98 // get all new lines99 do {100 $diff1[] = substr($diff[$i], 1);101 } while (++$i < $end && substr($diff[$i], 0, 1) == '+');102 $edits[] = new Text_Diff_Op_add($diff1);103 break;104 case '-':105 // get changed or removed lines106 $diff2 = array();107 do {108 $diff1[] = substr($diff[$i], 1);109 } while (++$i < $end && substr($diff[$i], 0, 1) == '-');110 while ($i < $end && substr($diff[$i], 0, 1) == '+') {111 $diff2[] = substr($diff[$i++], 1);112 }113 if (count($diff2) == 0) {114 $edits[] = new Text_Diff_Op_delete($diff1);115 } else {116 $edits[] = new Text_Diff_Op_change($diff1, $diff2);117 }118 break;119 default:120 $i++;121 break;122 }123 }124 return $edits;125 }126 /**127 * Parses an array containing the context diff.128 *129 * @param array $diff Array of lines.130 *131 * @return array List of all diff operations.132 */133 function parseContextDiff(&$diff)134 {135 $edits = array();136 $i = $max_i = $j = $max_j = 0;137 $end = count($diff) - 1;138 while ($i < $end && $j < $end) {139 while ($i >= $max_i && $j >= $max_j) {140 // Find the boundaries of the diff output of the two files141 for ($i = $j;142 $i < $end && substr($diff[$i], 0, 3) == '***';143 $i++);144 for ($max_i = $i;145 $max_i < $end && substr($diff[$max_i], 0, 3) != '---';146 $max_i++);147 for ($j = $max_i;148 $j < $end && substr($diff[$j], 0, 3) == '---';149 $j++);150 for ($max_j = $j;151 $max_j < $end && substr($diff[$max_j], 0, 3) != '***';152 $max_j++);153 }154 // find what hasn't been changed155 $array = array();156 while ($i < $max_i &&157 $j < $max_j &&158 strcmp($diff[$i], $diff[$j]) == 0) {159 $array[] = substr($diff[$i], 2);160 $i++;161 $j++;162 }163 while ($i < $max_i && ($max_j-$j) <= 1) {164 if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') {165 break;166 }167 $array[] = substr($diff[$i++], 2);168 }169 while ($j < $max_j && ($max_i-$i) <= 1) {170 if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') {171 break;172 }173 $array[] = substr($diff[$j++], 2);174 }175 if (count($array) > 0) {176 $edits[] = new Text_Diff_Op_copy($array);177 }178 if ($i < $max_i) {179 $diff1 = array();180 switch (substr($diff[$i], 0, 1)) {181 case '!':182 $diff2 = array();183 do {184 $diff1[] = substr($diff[$i], 2);185 if ($j < $max_j && substr($diff[$j], 0, 1) == '!') {186 $diff2[] = substr($diff[$j++], 2);187 }188 } while (++$i < $max_i && substr($diff[$i], 0, 1) == '!');189 $edits[] = new Text_Diff_Op_change($diff1, $diff2);190 break;191 case '+':192 do {193 $diff1[] = substr($diff[$i], 2);194 } while (++$i < $max_i && substr($diff[$i], 0, 1) == '+');195 $edits[] = new Text_Diff_Op_add($diff1);196 break;197 case '-':198 do {199 $diff1[] = substr($diff[$i], 2);200 } while (++$i < $max_i && substr($diff[$i], 0, 1) == '-');201 $edits[] = new Text_Diff_Op_delete($diff1);202 break;203 }204 }205 if ($j < $max_j) {206 $diff2 = array();207 switch (substr($diff[$j], 0, 1)) {208 case '+':209 do {210 $diff2[] = substr($diff[$j++], 2);211 } while ($j < $max_j && substr($diff[$j], 0, 1) == '+');212 $edits[] = new Text_Diff_Op_add($diff2);213 break;214 case '-':215 do {216 $diff2[] = substr($diff[$j++], 2);217 } while ($j < $max_j && substr($diff[$j], 0, 1) == '-');218 $edits[] = new Text_Diff_Op_delete($diff2);219 break;220 }221 }222 }223 return $edits;224 }225}...

Full Screen

Full Screen

diff

Using AI Code Generation

copy

Full Screen

1$diff = new \mageekguy\atoum\diff();2$diff = new \mageekguy\atoum\diff();3require_once __DIR__ . '/../../vendor/atoum/atoum/classes/diff.php';4require_once __DIR__ . '/../../vendor/autoload.php';5require_once __DIR__ . '/../../vendor/atoum/atoum/classes/diff.php';6$runner->addTestsFromDirectory(__DIR__ . '/../../tests/units');7$script->noCodeCoverageForNamespaces('mageekguy\atoum');8$script->noCodeCoverageForNamespaces('mageekguy\atoum\asserters');9$script->noCodeCoverageForNamespaces('mageekguy\atoum\exceptions');10$script->noCodeCoverageForNamespaces('mageekguy\atoum\report\fields');11$script->noCodeCoverageForNamespaces('mageekguy\atoum\report\writers');12$script->noCodeCoverageForNamespaces('mageekguy\atoum\reports');13$script->noCodeCoverageForNamespaces('mageekguy\atoum\stubs');14$script->noCodeCoverageForNamespaces('mageekguy\atoum\writers');15namespace tests\units;

Full Screen

Full Screen

diff

Using AI Code Generation

copy

Full Screen

1use atoum\diff\asText;2use atoum\diff\asText;3use atoum\diff\asText;4use atoum\diff\asText;5use atoum\diff\asText;6use atoum\diff\asText;7use atoum\diff\asText;8use atoum\diff\asText;9use atoum\diff\asText;10use atoum\diff\asText;11use atoum\diff\asText;12use atoum\diff\asText;13use atoum\diff\asText;14use atoum\diff\asText;15use atoum\diff\asText;16use atoum\diff\asText;17use atoum\diff\asText;18use atoum\diff\asText;19use atoum\diff\asText;20use atoum\diff\asText;

Full Screen

Full Screen

diff

Using AI Code Generation

copy

Full Screen

1$diff = new \mageekguy\atoum\tools\diffs\unified();2$diff->setReference($this->reference);3$diff->setData($this->data);4$diff->setTitle($this->title);5$diff->setReferenceTitle($this->referenceTitle);6$diff->setDataTitle($this->dataTitle);7$diff->setReferencePath($this->referencePath);8$diff->setDataPath($this->dataPath);9$diff->setOutputPath($this->outputPath);10$diff->setOutputPath($this->outputPath);11$diff->setIsHtml($this->isHtml);12$diff->setIsColored($this->isColored);13$diff->setIsInline($this->isInline);14$diff->setIsOnlyDifferences($this->isOnlyDifferenc

Full Screen

Full Screen

diff

Using AI Code Generation

copy

Full Screen

1require_once 'vendor/autoload.php';2use mageekguy\atoum\reports\realtime\cli;3use mageekguy\atoum\report\fields\runner\result\diff;4$cli = new cli();5$cli->addWriter($cli->getStdoutWriter());6$cli->addField(new diff());7$runner->addReport($cli);8require_once 'vendor/autoload.php';9use mageekguy\atoum\reports\realtime\cli;10use mageekguy\atoum\report\fields\runner\result\diff;11$cli = new cli();12$cli->addWriter($cli->getStdoutWriter());13$cli->addField(new diff());14$runner->addReport($cli);15require_once 'vendor/autoload.php';16use mageekguy\atoum\reports\realtime\cli;17use mageekguy\atoum\report\fields\runner\result\diff;18$cli = new cli();19$cli->addWriter($cli->getStdoutWriter());20$cli->addField(new diff());21$runner->addReport($cli);22require_once 'vendor/autoload.php';23use mageekguy\atoum\reports\realtime\cli;24use mageekguy\atoum\report\fields\runner\result\diff;25$cli = new cli();26$cli->addWriter($cli->getStdoutWriter());27$cli->addField(new diff());28$runner->addReport($cli);29require_once 'vendor/autoload.php';30use mageekguy\atoum\reports\realtime\cli;31use mageekguy\atoum\report\fields\runner\result\diff;32$cli = new cli();33$cli->addWriter($cli->getStdoutWriter());34$cli->addField(new diff());35$runner->addReport($cli);

Full Screen

Full Screen

diff

Using AI Code Generation

copy

Full Screen

1{2 public function isEqualTo($value, $failMessage = null)3 {4 $this->diff($value);5 return parent::isEqualTo($value, $failMessage);6 }7}8{9 public function isEqualTo($value, $failMessage = null)10 {11 $this->diff($value);12 return parent::isEqualTo($value, $failMessage);13 }14}15{16 public function isEqualTo($value, $failMessage = null)17 {18 $this->diff($value);19 return parent::isEqualTo($value, $failMessage);20 }21}22{23 public function isEqualTo($value, $failMessage = null)24 {25 $this->diff($value);26 return parent::isEqualTo($value, $failMessage);27 }28}29{30 public function isEqualTo($value, $failMessage = null)31 {32 $this->diff($value);33 return parent::isEqualTo($value, $failMessage);34 }35}36{37 public function isEqualTo($value, $failMessage = null)38 {39 $this->diff($value);40 return parent::isEqualTo($value, $failMessage);41 }42}43{44 public function isEqualTo($value, $failMessage = null)45 {46 $this->diff($value);47 return parent::isEqualTo($value, $failMessage);48 }49}

Full Screen

Full Screen

diff

Using AI Code Generation

copy

Full Screen

1require_once 'diff.php';2$diff = new diff;3$diff->setOldFile('oldfile.txt');4$diff->setNewFile('newfile.txt');5$diff->setOutputFormat('html');6$diff->setWordLevel(true);7$diff->setContextLines(2);8$diff->setTabSize(4);9$diff->setTrimWhitespace(true);10$diff->setIgnoreWhitespace(true);11$diff->setIgnoreWhitespaceChanges(true);12$diff->setIgnoreCase(true);13$diff->setIgnoreNumbers(true);14$diff->setIgnoreNewLines(true);15$diff->setIgnoreOldLines(true);16$diff->setIgnoreAllSpace(true);17$diff->setIgnoreEOL(true);18$diff->setIsCaseSensitive(false);19$diff->setIsNumeric(false);20$diff->setIsWhitespace(false);21$diff->setIsLineOriented(false);22$diff->setIsWordOriented(false);23$diff->setIsTextOriented(false);24$diff->setIsBinary(false);25$diff->setIsOldBinary(false);26$diff->setIsNewBinary(false);27$diff->setIsOldEmpty(false);28$diff->setIsNewEmpty(false);29$diff->setIsOldMissingNewline(false);30$diff->setIsNewMissingNewline(false);31$diff->setIsOldMissingNewlineAtEOF(false);32$diff->setIsNewMissingNewlineAtEOF(false);33$diff->setIsOldMissingFinalNewline(false);34$diff->setIsNewMissingFinalNewline(false);35$diff->setIsOldMissingFinalNewlineAtEOF(false);36$diff->setIsNewMissingFinalNewlineAtEOF(false);37$diff->setIsOldTrailingWhitespace(false);38$diff->setIsNewTrailingWhitespace(false);39$diff->setIsOldTrailingWhitespaceAtEOF(false);40$diff->setIsNewTrailingWhitespaceAtEOF(false);41$diff->setIsOldLeadingWhitespace(false);42$diff->setIsNewLeadingWhitespace(false);43$diff->setIsOldLeadingWhitespaceAtBOL(false);44$diff->setIsNewLeadingWhitespaceAtBOL(false);45$diff->setIsOldLeadingWhitespaceAtEOF(false);46$diff->setIsNewLeadingWhitespaceAtEOF(false);47$diff->setIsOldLeadingWhitespaceAtEOL(false);48$diff->setIsNewLeadingWhitespaceAtEOL(false);

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Atoum automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Run Selenium Automation Tests on LambdaTest Cloud Grid

Trigger Selenium automation tests on a cloud-based Grid of 3000+ real browsers and operating systems.

Test now for Free

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful