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  }