1
2
3
4
5
6 package assert
7
8 import (
9 "bytes"
10 "fmt"
11 "math"
12 "reflect"
13 "strings"
14 "testing"
15 )
16
17 func assertAlmostEqual(t *testing.T, a, b float64, places int) {
18 if math.Abs(a-b) > math.Pow10(-places) {
19 t.Errorf("%.7f != %.7f", a, b)
20 }
21 }
22
23 func assertEqual(t *testing.T, a, b interface{}) {
24 if !reflect.DeepEqual(a, b) {
25 t.Errorf("%v != %v", a, b)
26 }
27 }
28
29 func splitChars(s string) []string {
30 chars := make([]string, 0, len(s))
31
32 for i := 0; i != len(s); i++ {
33 chars = append(chars, string(s[i]))
34 }
35 return chars
36 }
37
38 func TestSequenceMatcherRatio(t *testing.T) {
39 s := NewMatcher(splitChars("abcd"), splitChars("bcde"))
40 assertEqual(t, s.Ratio(), 0.75)
41 assertEqual(t, s.QuickRatio(), 0.75)
42 assertEqual(t, s.RealQuickRatio(), 1.0)
43 }
44
45 func TestGetOptCodes(t *testing.T) {
46 a := "qabxcd"
47 b := "abycdf"
48 s := NewMatcher(splitChars(a), splitChars(b))
49 w := &bytes.Buffer{}
50 for _, op := range s.GetOpCodes() {
51 fmt.Fprintf(w, "%s a[%d:%d], (%s) b[%d:%d] (%s)\n", string(op.Tag),
52 op.I1, op.I2, a[op.I1:op.I2], op.J1, op.J2, b[op.J1:op.J2])
53 }
54 result := w.String()
55 expected := `d a[0:1], (q) b[0:0] ()
56 e a[1:3], (ab) b[0:2] (ab)
57 r a[3:4], (x) b[2:3] (y)
58 e a[4:6], (cd) b[3:5] (cd)
59 i a[6:6], () b[5:6] (f)
60 `
61 if expected != result {
62 t.Errorf("unexpected op codes: \n%s", result)
63 }
64 }
65
66 func TestGroupedOpCodes(t *testing.T) {
67 a := []string{}
68 for i := 0; i != 39; i++ {
69 a = append(a, fmt.Sprintf("%02d", i))
70 }
71 b := []string{}
72 b = append(b, a[:8]...)
73 b = append(b, " i")
74 b = append(b, a[8:19]...)
75 b = append(b, " x")
76 b = append(b, a[20:22]...)
77 b = append(b, a[27:34]...)
78 b = append(b, " y")
79 b = append(b, a[35:]...)
80 s := NewMatcher(a, b)
81 w := &bytes.Buffer{}
82 for _, g := range s.GetGroupedOpCodes(-1) {
83 fmt.Fprintf(w, "group\n")
84 for _, op := range g {
85 fmt.Fprintf(w, " %s, %d, %d, %d, %d\n", string(op.Tag),
86 op.I1, op.I2, op.J1, op.J2)
87 }
88 }
89 result := w.String()
90 expected := `group
91 e, 5, 8, 5, 8
92 i, 8, 8, 8, 9
93 e, 8, 11, 9, 12
94 group
95 e, 16, 19, 17, 20
96 r, 19, 20, 20, 21
97 e, 20, 22, 21, 23
98 d, 22, 27, 23, 23
99 e, 27, 30, 23, 26
100 group
101 e, 31, 34, 27, 30
102 r, 34, 35, 30, 31
103 e, 35, 38, 31, 34
104 `
105 if expected != result {
106 t.Errorf("unexpected op codes: \n%s", result)
107 }
108 }
109
110 func rep(s string, count int) string {
111 return strings.Repeat(s, count)
112 }
113
114 func TestWithAsciiOneInsert(t *testing.T) {
115 sm := NewMatcher(splitChars(rep("b", 100)),
116 splitChars("a"+rep("b", 100)))
117 assertAlmostEqual(t, sm.Ratio(), 0.995, 3)
118 assertEqual(t, sm.GetOpCodes(),
119 []OpCode{{'i', 0, 0, 0, 1}, {'e', 0, 100, 1, 101}})
120 assertEqual(t, len(sm.bPopular), 0)
121
122 sm = NewMatcher(splitChars(rep("b", 100)),
123 splitChars(rep("b", 50)+"a"+rep("b", 50)))
124 assertAlmostEqual(t, sm.Ratio(), 0.995, 3)
125 assertEqual(t, sm.GetOpCodes(),
126 []OpCode{{'e', 0, 50, 0, 50}, {'i', 50, 50, 50, 51}, {'e', 50, 100, 51, 101}})
127 assertEqual(t, len(sm.bPopular), 0)
128 }
129
130 func TestWithAsciiOnDelete(t *testing.T) {
131 sm := NewMatcher(splitChars(rep("a", 40)+"c"+rep("b", 40)),
132 splitChars(rep("a", 40)+rep("b", 40)))
133 assertAlmostEqual(t, sm.Ratio(), 0.994, 3)
134 assertEqual(t, sm.GetOpCodes(),
135 []OpCode{{'e', 0, 40, 0, 40}, {'d', 40, 41, 40, 40}, {'e', 41, 81, 40, 80}})
136 }
137
138 func TestWithAsciiBJunk(t *testing.T) {
139 isJunk := func(s string) bool {
140 return s == " "
141 }
142 sm := NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
143 splitChars(rep("a", 44)+rep("b", 40)), true, isJunk)
144 assertEqual(t, sm.bJunk, map[string]struct{}{})
145
146 sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
147 splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk)
148 assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}})
149
150 isJunk = func(s string) bool {
151 return s == " " || s == "b"
152 }
153 sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
154 splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk)
155 assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}, "b": struct{}{}})
156 }
157
158 func TestSFBugsRatioForNullSeqn(t *testing.T) {
159 sm := NewMatcher(nil, nil)
160 assertEqual(t, sm.Ratio(), 1.0)
161 assertEqual(t, sm.QuickRatio(), 1.0)
162 assertEqual(t, sm.RealQuickRatio(), 1.0)
163 }
164
165 func TestSFBugsComparingEmptyLists(t *testing.T) {
166 groups := NewMatcher(nil, nil).GetGroupedOpCodes(-1)
167 assertEqual(t, len(groups), 0)
168 diff := UnifiedDiff{
169 FromFile: "Original",
170 ToFile: "Current",
171 Context: 3,
172 }
173 result, err := GetUnifiedDiffString(diff)
174 assertEqual(t, err, nil)
175 assertEqual(t, result, "")
176 }
177
178 func TestOutputFormatRangeFormatUnified(t *testing.T) {
179
180
181
182
183
184
185
186
187 fm := formatRangeUnified
188 assertEqual(t, fm(3, 3), "3,0")
189 assertEqual(t, fm(3, 4), "4")
190 assertEqual(t, fm(3, 5), "4,2")
191 assertEqual(t, fm(3, 6), "4,3")
192 assertEqual(t, fm(0, 0), "0,0")
193 }
194
195 func TestOutputFormatRangeFormatContext(t *testing.T) {
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211 fm := formatRangeContext
212 assertEqual(t, fm(3, 3), "3")
213 assertEqual(t, fm(3, 4), "4")
214 assertEqual(t, fm(3, 5), "4,5")
215 assertEqual(t, fm(3, 6), "4,6")
216 assertEqual(t, fm(0, 0), "0")
217 }
218
219 func TestOutputFormatTabDelimiter(t *testing.T) {
220 diff := UnifiedDiff{
221 A: splitChars("one"),
222 B: splitChars("two"),
223 FromFile: "Original",
224 FromDate: "2005-01-26 23:30:50",
225 ToFile: "Current",
226 ToDate: "2010-04-12 10:20:52",
227 Eol: "\n",
228 }
229 ud, err := GetUnifiedDiffString(diff)
230 assertEqual(t, err, nil)
231 assertEqual(t, SplitLines(ud)[:2], []string{
232 "--- Original\t2005-01-26 23:30:50\n",
233 "+++ Current\t2010-04-12 10:20:52\n",
234 })
235 cd, err := GetContextDiffString(ContextDiff(diff))
236 assertEqual(t, err, nil)
237 assertEqual(t, SplitLines(cd)[:2], []string{
238 "*** Original\t2005-01-26 23:30:50\n",
239 "--- Current\t2010-04-12 10:20:52\n",
240 })
241 }
242
243 func TestOutputFormatNoTrailingTabOnEmptyFiledate(t *testing.T) {
244 diff := UnifiedDiff{
245 A: splitChars("one"),
246 B: splitChars("two"),
247 FromFile: "Original",
248 ToFile: "Current",
249 Eol: "\n",
250 }
251 ud, err := GetUnifiedDiffString(diff)
252 assertEqual(t, err, nil)
253 assertEqual(t, SplitLines(ud)[:2], []string{"--- Original\n", "+++ Current\n"})
254
255 cd, err := GetContextDiffString(ContextDiff(diff))
256 assertEqual(t, err, nil)
257 assertEqual(t, SplitLines(cd)[:2], []string{"*** Original\n", "--- Current\n"})
258 }
259
260 func TestOmitFilenames(t *testing.T) {
261 diff := UnifiedDiff{
262 A: SplitLines("o\nn\ne\n"),
263 B: SplitLines("t\nw\no\n"),
264 Eol: "\n",
265 }
266 ud, err := GetUnifiedDiffString(diff)
267 assertEqual(t, err, nil)
268 assertEqual(t, SplitLines(ud), []string{
269 "@@ -0,0 +1,2 @@\n",
270 "+t\n",
271 "+w\n",
272 "@@ -2,2 +3,0 @@\n",
273 "-n\n",
274 "-e\n",
275 "\n",
276 })
277
278 cd, err := GetContextDiffString(ContextDiff(diff))
279 assertEqual(t, err, nil)
280 assertEqual(t, SplitLines(cd), []string{
281 "***************\n",
282 "*** 0 ****\n",
283 "--- 1,2 ----\n",
284 "+ t\n",
285 "+ w\n",
286 "***************\n",
287 "*** 2,3 ****\n",
288 "- n\n",
289 "- e\n",
290 "--- 3 ----\n",
291 "\n",
292 })
293 }
294
295 func TestSplitLines(t *testing.T) {
296 allTests := []struct {
297 input string
298 want []string
299 }{
300 {"foo", []string{"foo\n"}},
301 {"foo\nbar", []string{"foo\n", "bar\n"}},
302 {"foo\nbar\n", []string{"foo\n", "bar\n", "\n"}},
303 }
304 for _, test := range allTests {
305 assertEqual(t, SplitLines(test.input), test.want)
306 }
307 }
308
309 func benchmarkSplitLines(b *testing.B, count int) {
310 str := strings.Repeat("foo\n", count)
311
312 b.ResetTimer()
313
314 n := 0
315 for i := 0; i < b.N; i++ {
316 n += len(SplitLines(str))
317 }
318 }
319
320 func BenchmarkSplitLines100(b *testing.B) {
321 benchmarkSplitLines(b, 100)
322 }
323
324 func BenchmarkSplitLines10000(b *testing.B) {
325 benchmarkSplitLines(b, 10000)
326 }
327
View as plain text