xref: /aosp_15_r20/external/go-cmp/cmp/internal/diff/diff_test.go (revision 88d15eac089d7f20c739ff1001d56b91872b21a1)
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