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