github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/internal/diff/lcs/old_test.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package lcs 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "log" 11 "math/rand" 12 "strings" 13 "testing" 14 ) 15 16 func TestAlgosOld(t *testing.T) { 17 for i, algo := range []func(*editGraph) lcs{forward, backward, twosided} { 18 t.Run(strings.Fields("forward backward twosided")[i], func(t *testing.T) { 19 for _, tx := range Btests { 20 lim := len(tx.a) + len(tx.b) 21 22 diffs, lcs := compute(stringSeqs{tx.a, tx.b}, algo, lim) 23 check(t, tx.a, lcs, tx.lcs) 24 checkDiffs(t, tx.a, diffs, tx.b) 25 26 diffs, lcs = compute(stringSeqs{tx.b, tx.a}, algo, lim) 27 check(t, tx.b, lcs, tx.lcs) 28 checkDiffs(t, tx.b, diffs, tx.a) 29 } 30 }) 31 } 32 } 33 34 func TestIntOld(t *testing.T) { 35 // need to avoid any characters in btests 36 lfill, rfill := "AAAAAAAAAAAA", "BBBBBBBBBBBB" 37 for _, tx := range Btests { 38 if len(tx.a) < 2 || len(tx.b) < 2 { 39 continue 40 } 41 left := tx.a + lfill 42 right := tx.b + rfill 43 lim := len(tx.a) + len(tx.b) 44 diffs, lcs := compute(stringSeqs{left, right}, twosided, lim) 45 check(t, left, lcs, tx.lcs) 46 checkDiffs(t, left, diffs, right) 47 diffs, lcs = compute(stringSeqs{right, left}, twosided, lim) 48 check(t, right, lcs, tx.lcs) 49 checkDiffs(t, right, diffs, left) 50 51 left = lfill + tx.a 52 right = rfill + tx.b 53 diffs, lcs = compute(stringSeqs{left, right}, twosided, lim) 54 check(t, left, lcs, tx.lcs) 55 checkDiffs(t, left, diffs, right) 56 diffs, lcs = compute(stringSeqs{right, left}, twosided, lim) 57 check(t, right, lcs, tx.lcs) 58 checkDiffs(t, right, diffs, left) 59 } 60 } 61 62 func TestSpecialOld(t *testing.T) { // exercises lcs.fix 63 a := "golang.org/x/tools/intern" 64 b := "github.com/google/safehtml/template\"\n\t\"golang.org/x/tools/intern" 65 diffs, lcs := compute(stringSeqs{a, b}, twosided, 4) 66 if !lcs.valid() { 67 t.Errorf("%d,%v", len(diffs), lcs) 68 } 69 } 70 71 func TestRegressionOld001(t *testing.T) { 72 a := "// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage diff_test\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"golang.org/x/tools/gopls/internal/lsp/diff\"\n\t\"golang.org/x/tools/internal/diff/difftest\"\n\t\"golang.org/x/tools/gopls/internal/span\"\n)\n" 73 74 b := "// Copyright 2019 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage diff_test\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/google/safehtml/template\"\n\t\"golang.org/x/tools/gopls/internal/lsp/diff\"\n\t\"golang.org/x/tools/internal/diff/difftest\"\n\t\"golang.org/x/tools/gopls/internal/span\"\n)\n" 75 for i := 1; i < len(b); i++ { 76 diffs, lcs := compute(stringSeqs{a, b}, twosided, i) // 14 from gopls 77 if !lcs.valid() { 78 t.Errorf("%d,%v", len(diffs), lcs) 79 } 80 checkDiffs(t, a, diffs, b) 81 } 82 } 83 84 func TestRegressionOld002(t *testing.T) { 85 a := "n\"\n)\n" 86 b := "n\"\n\t\"golang.org/x//nnal/stack\"\n)\n" 87 for i := 1; i <= len(b); i++ { 88 diffs, lcs := compute(stringSeqs{a, b}, twosided, i) 89 if !lcs.valid() { 90 t.Errorf("%d,%v", len(diffs), lcs) 91 } 92 checkDiffs(t, a, diffs, b) 93 } 94 } 95 96 func TestRegressionOld003(t *testing.T) { 97 a := "golang.org/x/hello v1.0.0\nrequire golang.org/x/unused v1" 98 b := "golang.org/x/hello v1" 99 for i := 1; i <= len(a); i++ { 100 diffs, lcs := compute(stringSeqs{a, b}, twosided, i) 101 if !lcs.valid() { 102 t.Errorf("%d,%v", len(diffs), lcs) 103 } 104 checkDiffs(t, a, diffs, b) 105 } 106 } 107 108 func TestRandOld(t *testing.T) { 109 rand.Seed(1) 110 for i := 0; i < 1000; i++ { 111 // TODO(adonovan): use ASCII and bytesSeqs here? The use of 112 // non-ASCII isn't relevant to the property exercised by the test. 113 a := []rune(randstr("abω", 16)) 114 b := []rune(randstr("abωc", 16)) 115 seq := runesSeqs{a, b} 116 117 const lim = 24 // large enough to get true lcs 118 _, forw := compute(seq, forward, lim) 119 _, back := compute(seq, backward, lim) 120 _, two := compute(seq, twosided, lim) 121 if lcslen(two) != lcslen(forw) || lcslen(forw) != lcslen(back) { 122 t.Logf("\n%v\n%v\n%v", forw, back, two) 123 t.Fatalf("%d forw:%d back:%d two:%d", i, lcslen(forw), lcslen(back), lcslen(two)) 124 } 125 if !two.valid() || !forw.valid() || !back.valid() { 126 t.Errorf("check failure") 127 } 128 } 129 } 130 131 // TestDiffAPI tests the public API functions (Diff{Bytes,Strings,Runes}) 132 // to ensure at least miminal parity of the three representations. 133 func TestDiffAPI(t *testing.T) { 134 for _, test := range []struct { 135 a, b string 136 wantStrings, wantBytes, wantRunes string 137 }{ 138 {"abcXdef", "abcxdef", "[{3 4 3 4}]", "[{3 4 3 4}]", "[{3 4 3 4}]"}, // ASCII 139 {"abcωdef", "abcΩdef", "[{3 5 3 5}]", "[{3 5 3 5}]", "[{3 4 3 4}]"}, // non-ASCII 140 } { 141 142 gotStrings := fmt.Sprint(DiffStrings(test.a, test.b)) 143 if gotStrings != test.wantStrings { 144 t.Errorf("DiffStrings(%q, %q) = %v, want %v", 145 test.a, test.b, gotStrings, test.wantStrings) 146 } 147 gotBytes := fmt.Sprint(DiffBytes([]byte(test.a), []byte(test.b))) 148 if gotBytes != test.wantBytes { 149 t.Errorf("DiffBytes(%q, %q) = %v, want %v", 150 test.a, test.b, gotBytes, test.wantBytes) 151 } 152 gotRunes := fmt.Sprint(DiffRunes([]rune(test.a), []rune(test.b))) 153 if gotRunes != test.wantRunes { 154 t.Errorf("DiffRunes(%q, %q) = %v, want %v", 155 test.a, test.b, gotRunes, test.wantRunes) 156 } 157 } 158 } 159 160 func BenchmarkTwoOld(b *testing.B) { 161 tests := genBench("abc", 96) 162 for i := 0; i < b.N; i++ { 163 for _, tt := range tests { 164 _, two := compute(stringSeqs{tt.before, tt.after}, twosided, 100) 165 if !two.valid() { 166 b.Error("check failed") 167 } 168 } 169 } 170 } 171 172 func BenchmarkForwOld(b *testing.B) { 173 tests := genBench("abc", 96) 174 for i := 0; i < b.N; i++ { 175 for _, tt := range tests { 176 _, two := compute(stringSeqs{tt.before, tt.after}, forward, 100) 177 if !two.valid() { 178 b.Error("check failed") 179 } 180 } 181 } 182 } 183 184 func genBench(set string, n int) []struct{ before, after string } { 185 // before and after for benchmarks. 24 strings of length n with 186 // before and after differing at least once, and about 5% 187 rand.Seed(3) 188 var ans []struct{ before, after string } 189 for i := 0; i < 24; i++ { 190 // maybe b should have an approximately known number of diffs 191 a := randstr(set, n) 192 cnt := 0 193 bb := make([]rune, 0, n) 194 for _, r := range a { 195 if rand.Float64() < .05 { 196 cnt++ 197 r = 'N' 198 } 199 bb = append(bb, r) 200 } 201 if cnt == 0 { 202 // avoid == shortcut 203 bb[n/2] = 'N' 204 } 205 ans = append(ans, struct{ before, after string }{a, string(bb)}) 206 } 207 return ans 208 } 209 210 // This benchmark represents a common case for a diff command: 211 // large file with a single relatively small diff in the middle. 212 // (It's not clear whether this is representative of gopls workloads 213 // or whether it is important to gopls diff performance.) 214 // 215 // TODO(adonovan) opt: it could be much faster. For example, 216 // comparing a file against itself is about 10x faster than with the 217 // small deletion in the middle. Strangely, comparing a file against 218 // itself minus the last byte is faster still; I don't know why. 219 // There is much low-hanging fruit here for further improvement. 220 func BenchmarkLargeFileSmallDiff(b *testing.B) { 221 data, err := ioutil.ReadFile("old.go") // large file 222 if err != nil { 223 log.Fatal(err) 224 } 225 226 n := len(data) 227 228 src := string(data) 229 dst := src[:n*49/100] + src[n*51/100:] // remove 2% from the middle 230 b.Run("string", func(b *testing.B) { 231 for i := 0; i < b.N; i++ { 232 compute(stringSeqs{src, dst}, twosided, len(src)+len(dst)) 233 } 234 }) 235 236 srcBytes := []byte(src) 237 dstBytes := []byte(dst) 238 b.Run("bytes", func(b *testing.B) { 239 for i := 0; i < b.N; i++ { 240 compute(bytesSeqs{srcBytes, dstBytes}, twosided, len(srcBytes)+len(dstBytes)) 241 } 242 }) 243 244 srcRunes := []rune(src) 245 dstRunes := []rune(dst) 246 b.Run("runes", func(b *testing.B) { 247 for i := 0; i < b.N; i++ { 248 compute(runesSeqs{srcRunes, dstRunes}, twosided, len(srcRunes)+len(dstRunes)) 249 } 250 }) 251 }