1*88d15eacSSasha Smundak// Copyright 2017, The Go Authors. All rights reserved. 2*88d15eacSSasha Smundak// Use of this source code is governed by a BSD-style 3*88d15eacSSasha Smundak// license that can be found in the LICENSE file. 4*88d15eacSSasha Smundak 5*88d15eacSSasha Smundakpackage diff 6*88d15eacSSasha Smundak 7*88d15eacSSasha Smundakimport ( 8*88d15eacSSasha Smundak "fmt" 9*88d15eacSSasha Smundak "math/rand" 10*88d15eacSSasha Smundak "strings" 11*88d15eacSSasha Smundak "testing" 12*88d15eacSSasha Smundak "unicode" 13*88d15eacSSasha Smundak) 14*88d15eacSSasha Smundak 15*88d15eacSSasha Smundakfunc TestDifference(t *testing.T) { 16*88d15eacSSasha Smundak tests := []struct { 17*88d15eacSSasha Smundak // Before passing x and y to Difference, we strip all spaces so that 18*88d15eacSSasha Smundak // they can be used by the test author to indicate a missing symbol 19*88d15eacSSasha Smundak // in one of the lists. 20*88d15eacSSasha Smundak x, y string 21*88d15eacSSasha Smundak want string // '|' separated list of possible outputs 22*88d15eacSSasha Smundak }{{ 23*88d15eacSSasha Smundak x: "", 24*88d15eacSSasha Smundak y: "", 25*88d15eacSSasha Smundak want: "", 26*88d15eacSSasha Smundak }, { 27*88d15eacSSasha Smundak x: "#", 28*88d15eacSSasha Smundak y: "#", 29*88d15eacSSasha Smundak want: ".", 30*88d15eacSSasha Smundak }, { 31*88d15eacSSasha Smundak x: "##", 32*88d15eacSSasha Smundak y: "# ", 33*88d15eacSSasha Smundak want: ".X|X.", 34*88d15eacSSasha Smundak }, { 35*88d15eacSSasha Smundak x: "a#", 36*88d15eacSSasha Smundak y: "A ", 37*88d15eacSSasha Smundak want: "MX", 38*88d15eacSSasha Smundak }, { 39*88d15eacSSasha Smundak x: "#a", 40*88d15eacSSasha Smundak y: " A", 41*88d15eacSSasha Smundak want: "XM", 42*88d15eacSSasha Smundak }, { 43*88d15eacSSasha Smundak x: "# ", 44*88d15eacSSasha Smundak y: "##", 45*88d15eacSSasha Smundak want: ".Y|Y.", 46*88d15eacSSasha Smundak }, { 47*88d15eacSSasha Smundak x: " #", 48*88d15eacSSasha Smundak y: "@#", 49*88d15eacSSasha Smundak want: "Y.", 50*88d15eacSSasha Smundak }, { 51*88d15eacSSasha Smundak x: "@#", 52*88d15eacSSasha Smundak y: " #", 53*88d15eacSSasha Smundak want: "X.", 54*88d15eacSSasha Smundak }, { 55*88d15eacSSasha Smundak x: "##########0123456789", 56*88d15eacSSasha Smundak y: " 0123456789", 57*88d15eacSSasha Smundak want: "XXXXXXXXXX..........", 58*88d15eacSSasha Smundak }, { 59*88d15eacSSasha Smundak x: " 0123456789", 60*88d15eacSSasha Smundak y: "##########0123456789", 61*88d15eacSSasha Smundak want: "YYYYYYYYYY..........", 62*88d15eacSSasha Smundak }, { 63*88d15eacSSasha Smundak x: "#####0123456789#####", 64*88d15eacSSasha Smundak y: " 0123456789 ", 65*88d15eacSSasha Smundak want: "XXXXX..........XXXXX", 66*88d15eacSSasha Smundak }, { 67*88d15eacSSasha Smundak x: " 0123456789 ", 68*88d15eacSSasha Smundak y: "#####0123456789#####", 69*88d15eacSSasha Smundak want: "YYYYY..........YYYYY", 70*88d15eacSSasha Smundak }, { 71*88d15eacSSasha Smundak x: "01234##########56789", 72*88d15eacSSasha Smundak y: "01234 56789", 73*88d15eacSSasha Smundak want: ".....XXXXXXXXXX.....", 74*88d15eacSSasha Smundak }, { 75*88d15eacSSasha Smundak x: "01234 56789", 76*88d15eacSSasha Smundak y: "01234##########56789", 77*88d15eacSSasha Smundak want: ".....YYYYYYYYYY.....", 78*88d15eacSSasha Smundak }, { 79*88d15eacSSasha Smundak x: "0123456789##########", 80*88d15eacSSasha Smundak y: "0123456789 ", 81*88d15eacSSasha Smundak want: "..........XXXXXXXXXX", 82*88d15eacSSasha Smundak }, { 83*88d15eacSSasha Smundak x: "0123456789 ", 84*88d15eacSSasha Smundak y: "0123456789##########", 85*88d15eacSSasha Smundak want: "..........YYYYYYYYYY", 86*88d15eacSSasha Smundak }, { 87*88d15eacSSasha Smundak x: "abcdefghij0123456789", 88*88d15eacSSasha Smundak y: "ABCDEFGHIJ0123456789", 89*88d15eacSSasha Smundak want: "MMMMMMMMMM..........", 90*88d15eacSSasha Smundak }, { 91*88d15eacSSasha Smundak x: "ABCDEFGHIJ0123456789", 92*88d15eacSSasha Smundak y: "abcdefghij0123456789", 93*88d15eacSSasha Smundak want: "MMMMMMMMMM..........", 94*88d15eacSSasha Smundak }, { 95*88d15eacSSasha Smundak x: "01234abcdefghij56789", 96*88d15eacSSasha Smundak y: "01234ABCDEFGHIJ56789", 97*88d15eacSSasha Smundak want: ".....MMMMMMMMMM.....", 98*88d15eacSSasha Smundak }, { 99*88d15eacSSasha Smundak x: "01234ABCDEFGHIJ56789", 100*88d15eacSSasha Smundak y: "01234abcdefghij56789", 101*88d15eacSSasha Smundak want: ".....MMMMMMMMMM.....", 102*88d15eacSSasha Smundak }, { 103*88d15eacSSasha Smundak x: "0123456789abcdefghij", 104*88d15eacSSasha Smundak y: "0123456789ABCDEFGHIJ", 105*88d15eacSSasha Smundak want: "..........MMMMMMMMMM", 106*88d15eacSSasha Smundak }, { 107*88d15eacSSasha Smundak x: "0123456789ABCDEFGHIJ", 108*88d15eacSSasha Smundak y: "0123456789abcdefghij", 109*88d15eacSSasha Smundak want: "..........MMMMMMMMMM", 110*88d15eacSSasha Smundak }, { 111*88d15eacSSasha Smundak x: "ABCDEFGHIJ0123456789 ", 112*88d15eacSSasha Smundak y: " 0123456789abcdefghij", 113*88d15eacSSasha Smundak want: "XXXXXXXXXX..........YYYYYYYYYY", 114*88d15eacSSasha Smundak }, { 115*88d15eacSSasha Smundak x: " 0123456789abcdefghij", 116*88d15eacSSasha Smundak y: "ABCDEFGHIJ0123456789 ", 117*88d15eacSSasha Smundak want: "YYYYYYYYYY..........XXXXXXXXXX", 118*88d15eacSSasha Smundak }, { 119*88d15eacSSasha Smundak x: "ABCDE0123456789 FGHIJ", 120*88d15eacSSasha Smundak y: " 0123456789abcdefghij", 121*88d15eacSSasha Smundak want: "XXXXX..........YYYYYMMMMM", 122*88d15eacSSasha Smundak }, { 123*88d15eacSSasha Smundak x: " 0123456789abcdefghij", 124*88d15eacSSasha Smundak y: "ABCDE0123456789 FGHIJ", 125*88d15eacSSasha Smundak want: "YYYYY..........XXXXXMMMMM", 126*88d15eacSSasha Smundak }, { 127*88d15eacSSasha Smundak x: "ABCDE01234F G H I J 56789 ", 128*88d15eacSSasha Smundak y: " 01234 a b c d e56789fghij", 129*88d15eacSSasha Smundak want: "XXXXX.....XYXYXYXYXY.....YYYYY", 130*88d15eacSSasha Smundak }, { 131*88d15eacSSasha Smundak x: " 01234a b c d e 56789fghij", 132*88d15eacSSasha Smundak y: "ABCDE01234 F G H I J56789 ", 133*88d15eacSSasha Smundak want: "YYYYY.....XYXYXYXYXY.....XXXXX", 134*88d15eacSSasha Smundak }, { 135*88d15eacSSasha Smundak x: "FGHIJ01234ABCDE56789 ", 136*88d15eacSSasha Smundak y: " 01234abcde56789fghij", 137*88d15eacSSasha Smundak want: "XXXXX.....MMMMM.....YYYYY", 138*88d15eacSSasha Smundak }, { 139*88d15eacSSasha Smundak x: " 01234abcde56789fghij", 140*88d15eacSSasha Smundak y: "FGHIJ01234ABCDE56789 ", 141*88d15eacSSasha Smundak want: "YYYYY.....MMMMM.....XXXXX", 142*88d15eacSSasha Smundak }, { 143*88d15eacSSasha Smundak x: "ABCAB BA ", 144*88d15eacSSasha Smundak y: " C BABAC", 145*88d15eacSSasha Smundak want: "XX.X.Y..Y|XX.Y.X..Y", 146*88d15eacSSasha Smundak }, { 147*88d15eacSSasha Smundak x: "# #### ###", 148*88d15eacSSasha Smundak y: "#y####yy###", 149*88d15eacSSasha Smundak want: ".Y....YY...", 150*88d15eacSSasha Smundak }, { 151*88d15eacSSasha Smundak x: "# #### # ##x#x", 152*88d15eacSSasha Smundak y: "#y####y y## # ", 153*88d15eacSSasha Smundak want: ".Y....YXY..X.X", 154*88d15eacSSasha Smundak }, { 155*88d15eacSSasha Smundak x: "###z#z###### x #", 156*88d15eacSSasha Smundak y: "#y##Z#Z###### yy#", 157*88d15eacSSasha Smundak want: ".Y..M.M......XYY.", 158*88d15eacSSasha Smundak }, { 159*88d15eacSSasha Smundak x: "0 12z3x 456789 x x 0", 160*88d15eacSSasha Smundak y: "0y12Z3 y456789y y y0", 161*88d15eacSSasha Smundak want: ".Y..M.XY......YXYXY.|.Y..M.XY......XYXYY.", 162*88d15eacSSasha Smundak }, { 163*88d15eacSSasha Smundak x: "0 2 4 6 8 ..................abXXcdEXF.ghXi", 164*88d15eacSSasha Smundak y: " 1 3 5 7 9..................AB CDE F.GH I", 165*88d15eacSSasha Smundak want: "XYXYXYXYXY..................MMXXMM.X..MMXM", 166*88d15eacSSasha Smundak }, { 167*88d15eacSSasha Smundak x: "I HG.F EDC BA..................9 7 5 3 1 ", 168*88d15eacSSasha Smundak y: "iXhg.FXEdcXXba.................. 8 6 4 2 0", 169*88d15eacSSasha Smundak want: "MYMM..Y.MMYYMM..................XYXYXYXYXY", 170*88d15eacSSasha Smundak }, { 171*88d15eacSSasha Smundak x: "x1234", 172*88d15eacSSasha Smundak y: " 1234", 173*88d15eacSSasha Smundak want: "X....", 174*88d15eacSSasha Smundak }, { 175*88d15eacSSasha Smundak x: "x123x4", 176*88d15eacSSasha Smundak y: " 123 4", 177*88d15eacSSasha Smundak want: "X...X.", 178*88d15eacSSasha Smundak }, { 179*88d15eacSSasha Smundak x: "x1234x56", 180*88d15eacSSasha Smundak y: " 1234 ", 181*88d15eacSSasha Smundak want: "X....XXX", 182*88d15eacSSasha Smundak }, { 183*88d15eacSSasha Smundak x: "x1234xxx56", 184*88d15eacSSasha Smundak y: " 1234 56", 185*88d15eacSSasha Smundak want: "X....XXX..", 186*88d15eacSSasha Smundak }, { 187*88d15eacSSasha Smundak x: ".1234...ab", 188*88d15eacSSasha Smundak y: " 1234 AB", 189*88d15eacSSasha Smundak want: "X....XXXMM", 190*88d15eacSSasha Smundak }, { 191*88d15eacSSasha Smundak x: "x1234xxab.", 192*88d15eacSSasha Smundak y: " 1234 AB ", 193*88d15eacSSasha Smundak want: "X....XXMMX", 194*88d15eacSSasha Smundak }, { 195*88d15eacSSasha Smundak x: " 0123456789", 196*88d15eacSSasha Smundak y: "9012345678 ", 197*88d15eacSSasha Smundak want: "Y.........X", 198*88d15eacSSasha Smundak }, { 199*88d15eacSSasha Smundak x: " 0123456789", 200*88d15eacSSasha Smundak y: "8901234567 ", 201*88d15eacSSasha Smundak want: "YY........XX", 202*88d15eacSSasha Smundak }, { 203*88d15eacSSasha Smundak x: " 0123456789", 204*88d15eacSSasha Smundak y: "7890123456 ", 205*88d15eacSSasha Smundak want: "YYY.......XXX", 206*88d15eacSSasha Smundak }, { 207*88d15eacSSasha Smundak x: " 0123456789", 208*88d15eacSSasha Smundak y: "6789012345 ", 209*88d15eacSSasha Smundak want: "YYYY......XXXX", 210*88d15eacSSasha Smundak }, { 211*88d15eacSSasha Smundak x: "0123456789 ", 212*88d15eacSSasha Smundak y: " 5678901234", 213*88d15eacSSasha Smundak want: "XXXXX.....YYYYY|YYYYY.....XXXXX", 214*88d15eacSSasha Smundak }, { 215*88d15eacSSasha Smundak x: "0123456789 ", 216*88d15eacSSasha Smundak y: " 4567890123", 217*88d15eacSSasha Smundak want: "XXXX......YYYY", 218*88d15eacSSasha Smundak }, { 219*88d15eacSSasha Smundak x: "0123456789 ", 220*88d15eacSSasha Smundak y: " 3456789012", 221*88d15eacSSasha Smundak want: "XXX.......YYY", 222*88d15eacSSasha Smundak }, { 223*88d15eacSSasha Smundak x: "0123456789 ", 224*88d15eacSSasha Smundak y: " 2345678901", 225*88d15eacSSasha Smundak want: "XX........YY", 226*88d15eacSSasha Smundak }, { 227*88d15eacSSasha Smundak x: "0123456789 ", 228*88d15eacSSasha Smundak y: " 1234567890", 229*88d15eacSSasha Smundak want: "X.........Y", 230*88d15eacSSasha Smundak }, { 231*88d15eacSSasha Smundak x: "0 1 2 3 45 6 7 8 9 ", 232*88d15eacSSasha Smundak y: " 9 8 7 6 54 3 2 1 0", 233*88d15eacSSasha Smundak want: "XYXYXYXYX.YXYXYXYXY", 234*88d15eacSSasha Smundak }, { 235*88d15eacSSasha Smundak x: "0 1 2345678 9 ", 236*88d15eacSSasha Smundak y: " 6 72 5 819034", 237*88d15eacSSasha Smundak want: "XYXY.XX.XX.Y.YYY", 238*88d15eacSSasha Smundak }, { 239*88d15eacSSasha Smundak x: "F B Q M O I G T L N72X90 E 4S P 651HKRJU DA 83CVZW", 240*88d15eacSSasha Smundak y: " 5 W H XO10R9IV K ZLCTAJ8P3N SEQM4 7 2G6 UBD F ", 241*88d15eacSSasha Smundak want: "XYXYXYXY.YYYY.YXYXY.YYYYYYY.XXXXXY.YY.XYXYY.XXXXXX.Y.XYXXXXXX", 242*88d15eacSSasha Smundak }} 243*88d15eacSSasha Smundak 244*88d15eacSSasha Smundak for _, tt := range tests { 245*88d15eacSSasha Smundak t.Run("", func(t *testing.T) { 246*88d15eacSSasha Smundak x := strings.Replace(tt.x, " ", "", -1) 247*88d15eacSSasha Smundak y := strings.Replace(tt.y, " ", "", -1) 248*88d15eacSSasha Smundak es := testStrings(t, x, y) 249*88d15eacSSasha Smundak var want string 250*88d15eacSSasha Smundak got := es.String() 251*88d15eacSSasha Smundak for _, want = range strings.Split(tt.want, "|") { 252*88d15eacSSasha Smundak if got == want { 253*88d15eacSSasha Smundak return 254*88d15eacSSasha Smundak } 255*88d15eacSSasha Smundak } 256*88d15eacSSasha Smundak t.Errorf("Difference(%s, %s):\ngot %s\nwant %s", x, y, got, want) 257*88d15eacSSasha Smundak }) 258*88d15eacSSasha Smundak } 259*88d15eacSSasha Smundak} 260*88d15eacSSasha Smundak 261*88d15eacSSasha Smundakfunc TestDifferenceFuzz(t *testing.T) { 262*88d15eacSSasha Smundak tests := []struct{ px, py, pm float32 }{ 263*88d15eacSSasha Smundak {px: 0.0, py: 0.0, pm: 0.1}, 264*88d15eacSSasha Smundak {px: 0.0, py: 0.1, pm: 0.0}, 265*88d15eacSSasha Smundak {px: 0.1, py: 0.0, pm: 0.0}, 266*88d15eacSSasha Smundak {px: 0.0, py: 0.1, pm: 0.1}, 267*88d15eacSSasha Smundak {px: 0.1, py: 0.0, pm: 0.1}, 268*88d15eacSSasha Smundak {px: 0.2, py: 0.2, pm: 0.2}, 269*88d15eacSSasha Smundak {px: 0.3, py: 0.1, pm: 0.2}, 270*88d15eacSSasha Smundak {px: 0.1, py: 0.3, pm: 0.2}, 271*88d15eacSSasha Smundak {px: 0.2, py: 0.2, pm: 0.2}, 272*88d15eacSSasha Smundak {px: 0.3, py: 0.3, pm: 0.3}, 273*88d15eacSSasha Smundak {px: 0.1, py: 0.1, pm: 0.5}, 274*88d15eacSSasha Smundak {px: 0.4, py: 0.1, pm: 0.5}, 275*88d15eacSSasha Smundak {px: 0.3, py: 0.2, pm: 0.5}, 276*88d15eacSSasha Smundak {px: 0.2, py: 0.3, pm: 0.5}, 277*88d15eacSSasha Smundak {px: 0.1, py: 0.4, pm: 0.5}, 278*88d15eacSSasha Smundak } 279*88d15eacSSasha Smundak 280*88d15eacSSasha Smundak for i, tt := range tests { 281*88d15eacSSasha Smundak t.Run(fmt.Sprintf("P%d", i), func(t *testing.T) { 282*88d15eacSSasha Smundak // Sweep from 1B to 1KiB. 283*88d15eacSSasha Smundak for n := 1; n <= 1024; n <<= 1 { 284*88d15eacSSasha Smundak t.Run(fmt.Sprintf("N%d", n), func(t *testing.T) { 285*88d15eacSSasha Smundak for j := 0; j < 10; j++ { 286*88d15eacSSasha Smundak x, y := generateStrings(n, tt.px, tt.py, tt.pm, int64(j)) 287*88d15eacSSasha Smundak testStrings(t, x, y) 288*88d15eacSSasha Smundak } 289*88d15eacSSasha Smundak }) 290*88d15eacSSasha Smundak } 291*88d15eacSSasha Smundak }) 292*88d15eacSSasha Smundak } 293*88d15eacSSasha Smundak} 294*88d15eacSSasha Smundak 295*88d15eacSSasha Smundakfunc BenchmarkDifference(b *testing.B) { 296*88d15eacSSasha Smundak for n := 1 << 10; n <= 1<<20; n <<= 2 { 297*88d15eacSSasha Smundak b.Run(fmt.Sprintf("N%d", n), func(b *testing.B) { 298*88d15eacSSasha Smundak x, y := generateStrings(n, 0.05, 0.05, 0.10, 0) 299*88d15eacSSasha Smundak b.ReportAllocs() 300*88d15eacSSasha Smundak b.SetBytes(int64(len(x) + len(y))) 301*88d15eacSSasha Smundak for i := 0; i < b.N; i++ { 302*88d15eacSSasha Smundak Difference(len(x), len(y), func(ix, iy int) Result { 303*88d15eacSSasha Smundak return compareByte(x[ix], y[iy]) 304*88d15eacSSasha Smundak }) 305*88d15eacSSasha Smundak } 306*88d15eacSSasha Smundak }) 307*88d15eacSSasha Smundak } 308*88d15eacSSasha Smundak} 309*88d15eacSSasha Smundak 310*88d15eacSSasha Smundakfunc generateStrings(n int, px, py, pm float32, seed int64) (string, string) { 311*88d15eacSSasha Smundak if px+py+pm > 1.0 { 312*88d15eacSSasha Smundak panic("invalid probabilities") 313*88d15eacSSasha Smundak } 314*88d15eacSSasha Smundak py += px 315*88d15eacSSasha Smundak pm += py 316*88d15eacSSasha Smundak 317*88d15eacSSasha Smundak b := make([]byte, n) 318*88d15eacSSasha Smundak r := rand.New(rand.NewSource(seed)) 319*88d15eacSSasha Smundak r.Read(b) 320*88d15eacSSasha Smundak 321*88d15eacSSasha Smundak var x, y []byte 322*88d15eacSSasha Smundak for len(b) > 0 { 323*88d15eacSSasha Smundak switch p := r.Float32(); { 324*88d15eacSSasha Smundak case p < px: // UniqueX 325*88d15eacSSasha Smundak x = append(x, b[0]) 326*88d15eacSSasha Smundak case p < py: // UniqueY 327*88d15eacSSasha Smundak y = append(y, b[0]) 328*88d15eacSSasha Smundak case p < pm: // Modified 329*88d15eacSSasha Smundak x = append(x, 'A'+(b[0]%26)) 330*88d15eacSSasha Smundak y = append(y, 'a'+(b[0]%26)) 331*88d15eacSSasha Smundak default: // Identity 332*88d15eacSSasha Smundak x = append(x, b[0]) 333*88d15eacSSasha Smundak y = append(y, b[0]) 334*88d15eacSSasha Smundak } 335*88d15eacSSasha Smundak b = b[1:] 336*88d15eacSSasha Smundak } 337*88d15eacSSasha Smundak return string(x), string(y) 338*88d15eacSSasha Smundak} 339*88d15eacSSasha Smundak 340*88d15eacSSasha Smundakfunc testStrings(t *testing.T, x, y string) EditScript { 341*88d15eacSSasha Smundak es := Difference(len(x), len(y), func(ix, iy int) Result { 342*88d15eacSSasha Smundak return compareByte(x[ix], y[iy]) 343*88d15eacSSasha Smundak }) 344*88d15eacSSasha Smundak if es.LenX() != len(x) { 345*88d15eacSSasha Smundak t.Errorf("es.LenX = %d, want %d", es.LenX(), len(x)) 346*88d15eacSSasha Smundak } 347*88d15eacSSasha Smundak if es.LenY() != len(y) { 348*88d15eacSSasha Smundak t.Errorf("es.LenY = %d, want %d", es.LenY(), len(y)) 349*88d15eacSSasha Smundak } 350*88d15eacSSasha Smundak if !validateScript(x, y, es) { 351*88d15eacSSasha Smundak t.Errorf("invalid edit script: %v", es) 352*88d15eacSSasha Smundak } 353*88d15eacSSasha Smundak return es 354*88d15eacSSasha Smundak} 355*88d15eacSSasha Smundak 356*88d15eacSSasha Smundakfunc validateScript(x, y string, es EditScript) bool { 357*88d15eacSSasha Smundak var bx, by []byte 358*88d15eacSSasha Smundak for _, e := range es { 359*88d15eacSSasha Smundak switch e { 360*88d15eacSSasha Smundak case Identity: 361*88d15eacSSasha Smundak if !compareByte(x[len(bx)], y[len(by)]).Equal() { 362*88d15eacSSasha Smundak return false 363*88d15eacSSasha Smundak } 364*88d15eacSSasha Smundak bx = append(bx, x[len(bx)]) 365*88d15eacSSasha Smundak by = append(by, y[len(by)]) 366*88d15eacSSasha Smundak case UniqueX: 367*88d15eacSSasha Smundak bx = append(bx, x[len(bx)]) 368*88d15eacSSasha Smundak case UniqueY: 369*88d15eacSSasha Smundak by = append(by, y[len(by)]) 370*88d15eacSSasha Smundak case Modified: 371*88d15eacSSasha Smundak if !compareByte(x[len(bx)], y[len(by)]).Similar() { 372*88d15eacSSasha Smundak return false 373*88d15eacSSasha Smundak } 374*88d15eacSSasha Smundak bx = append(bx, x[len(bx)]) 375*88d15eacSSasha Smundak by = append(by, y[len(by)]) 376*88d15eacSSasha Smundak } 377*88d15eacSSasha Smundak } 378*88d15eacSSasha Smundak return string(bx) == x && string(by) == y 379*88d15eacSSasha Smundak} 380*88d15eacSSasha Smundak 381*88d15eacSSasha Smundak// compareByte returns a Result where the result is Equal if x == y, 382*88d15eacSSasha Smundak// similar if x and y differ only in casing, and different otherwise. 383*88d15eacSSasha Smundakfunc compareByte(x, y byte) (r Result) { 384*88d15eacSSasha Smundak switch { 385*88d15eacSSasha Smundak case x == y: 386*88d15eacSSasha Smundak return equalResult // Identity 387*88d15eacSSasha Smundak case unicode.ToUpper(rune(x)) == unicode.ToUpper(rune(y)): 388*88d15eacSSasha Smundak return similarResult // Modified 389*88d15eacSSasha Smundak default: 390*88d15eacSSasha Smundak return differentResult // UniqueX or UniqueY 391*88d15eacSSasha Smundak } 392*88d15eacSSasha Smundak} 393*88d15eacSSasha Smundak 394*88d15eacSSasha Smundakvar ( 395*88d15eacSSasha Smundak equalResult = Result{NumDiff: 0} 396*88d15eacSSasha Smundak similarResult = Result{NumDiff: 1} 397*88d15eacSSasha Smundak differentResult = Result{NumDiff: 2} 398*88d15eacSSasha Smundak) 399*88d15eacSSasha Smundak 400*88d15eacSSasha Smundakfunc TestResult(t *testing.T) { 401*88d15eacSSasha Smundak tests := []struct { 402*88d15eacSSasha Smundak result Result 403*88d15eacSSasha Smundak wantEqual bool 404*88d15eacSSasha Smundak wantSimilar bool 405*88d15eacSSasha Smundak }{ 406*88d15eacSSasha Smundak // equalResult is equal since NumDiff == 0, by definition of Equal method. 407*88d15eacSSasha Smundak {equalResult, true, true}, 408*88d15eacSSasha Smundak // similarResult is similar since it is a binary result where only one 409*88d15eacSSasha Smundak // element was compared (i.e., Either NumSame==1 or NumDiff==1). 410*88d15eacSSasha Smundak {similarResult, false, true}, 411*88d15eacSSasha Smundak // differentResult is different since there are enough differences that 412*88d15eacSSasha Smundak // it isn't even considered similar. 413*88d15eacSSasha Smundak {differentResult, false, false}, 414*88d15eacSSasha Smundak 415*88d15eacSSasha Smundak // Zero value is always equal. 416*88d15eacSSasha Smundak {Result{NumSame: 0, NumDiff: 0}, true, true}, 417*88d15eacSSasha Smundak 418*88d15eacSSasha Smundak // Binary comparisons (where NumSame+NumDiff == 1) are always similar. 419*88d15eacSSasha Smundak {Result{NumSame: 1, NumDiff: 0}, true, true}, 420*88d15eacSSasha Smundak {Result{NumSame: 0, NumDiff: 1}, false, true}, 421*88d15eacSSasha Smundak 422*88d15eacSSasha Smundak // More complex ratios. The exact ratio for similarity may change, 423*88d15eacSSasha Smundak // and may require updates to these test cases. 424*88d15eacSSasha Smundak {Result{NumSame: 1, NumDiff: 1}, false, true}, 425*88d15eacSSasha Smundak {Result{NumSame: 1, NumDiff: 2}, false, true}, 426*88d15eacSSasha Smundak {Result{NumSame: 1, NumDiff: 3}, false, false}, 427*88d15eacSSasha Smundak {Result{NumSame: 2, NumDiff: 1}, false, true}, 428*88d15eacSSasha Smundak {Result{NumSame: 2, NumDiff: 2}, false, true}, 429*88d15eacSSasha Smundak {Result{NumSame: 2, NumDiff: 3}, false, true}, 430*88d15eacSSasha Smundak {Result{NumSame: 3, NumDiff: 1}, false, true}, 431*88d15eacSSasha Smundak {Result{NumSame: 3, NumDiff: 2}, false, true}, 432*88d15eacSSasha Smundak {Result{NumSame: 3, NumDiff: 3}, false, true}, 433*88d15eacSSasha Smundak {Result{NumSame: 1000, NumDiff: 0}, true, true}, 434*88d15eacSSasha Smundak {Result{NumSame: 1000, NumDiff: 1}, false, true}, 435*88d15eacSSasha Smundak {Result{NumSame: 1000, NumDiff: 2}, false, true}, 436*88d15eacSSasha Smundak {Result{NumSame: 0, NumDiff: 1000}, false, false}, 437*88d15eacSSasha Smundak {Result{NumSame: 1, NumDiff: 1000}, false, false}, 438*88d15eacSSasha Smundak {Result{NumSame: 2, NumDiff: 1000}, false, false}, 439*88d15eacSSasha Smundak } 440*88d15eacSSasha Smundak 441*88d15eacSSasha Smundak for _, tt := range tests { 442*88d15eacSSasha Smundak if got := tt.result.Equal(); got != tt.wantEqual { 443*88d15eacSSasha Smundak t.Errorf("%#v.Equal() = %v, want %v", tt.result, got, tt.wantEqual) 444*88d15eacSSasha Smundak } 445*88d15eacSSasha Smundak if got := tt.result.Similar(); got != tt.wantSimilar { 446*88d15eacSSasha Smundak t.Errorf("%#v.Similar() = %v, want %v", tt.result, got, tt.wantSimilar) 447*88d15eacSSasha Smundak } 448*88d15eacSSasha Smundak } 449*88d15eacSSasha Smundak} 450