...

Source file src/golang.org/x/tools/internal/diff/difftest/difftest.go

Documentation: golang.org/x/tools/internal/diff/difftest

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package difftest supplies a set of tests that will operate on any
     6  // implementation of a diff algorithm as exposed by
     7  // "golang.org/x/tools/internal/diff"
     8  package difftest
     9  
    10  // There are two kinds of tests, semantic tests, and 'golden data' tests.
    11  // The semantic tests check that the computed diffs transform the input to
    12  // the output, and that 'patch' accepts the computed unified diffs.
    13  // The other tests just check that Edits and LineEdits haven't changed
    14  // unexpectedly. These fields may need to be changed when the diff algorithm
    15  // changes.
    16  
    17  import (
    18  	"testing"
    19  
    20  	"golang.org/x/tools/internal/diff"
    21  )
    22  
    23  const (
    24  	FileA         = "from"
    25  	FileB         = "to"
    26  	UnifiedPrefix = "--- " + FileA + "\n+++ " + FileB + "\n"
    27  )
    28  
    29  var TestCases = []struct {
    30  	Name, In, Out, Unified string
    31  	Edits, LineEdits       []diff.Edit // expectation (LineEdits=nil => already line-aligned)
    32  	NoDiff                 bool
    33  }{{
    34  	Name: "empty",
    35  	In:   "",
    36  	Out:  "",
    37  }, {
    38  	Name: "no_diff",
    39  	In:   "gargantuan\n",
    40  	Out:  "gargantuan\n",
    41  }, {
    42  	Name: "replace_all",
    43  	In:   "fruit\n",
    44  	Out:  "cheese\n",
    45  	Unified: UnifiedPrefix + `
    46  @@ -1 +1 @@
    47  -fruit
    48  +cheese
    49  `[1:],
    50  	Edits:     []diff.Edit{{Start: 0, End: 5, New: "cheese"}},
    51  	LineEdits: []diff.Edit{{Start: 0, End: 6, New: "cheese\n"}},
    52  }, {
    53  	Name: "insert_rune",
    54  	In:   "gord\n",
    55  	Out:  "gourd\n",
    56  	Unified: UnifiedPrefix + `
    57  @@ -1 +1 @@
    58  -gord
    59  +gourd
    60  `[1:],
    61  	Edits:     []diff.Edit{{Start: 2, End: 2, New: "u"}},
    62  	LineEdits: []diff.Edit{{Start: 0, End: 5, New: "gourd\n"}},
    63  }, {
    64  	Name: "delete_rune",
    65  	In:   "groat\n",
    66  	Out:  "goat\n",
    67  	Unified: UnifiedPrefix + `
    68  @@ -1 +1 @@
    69  -groat
    70  +goat
    71  `[1:],
    72  	Edits:     []diff.Edit{{Start: 1, End: 2, New: ""}},
    73  	LineEdits: []diff.Edit{{Start: 0, End: 6, New: "goat\n"}},
    74  }, {
    75  	Name: "replace_rune",
    76  	In:   "loud\n",
    77  	Out:  "lord\n",
    78  	Unified: UnifiedPrefix + `
    79  @@ -1 +1 @@
    80  -loud
    81  +lord
    82  `[1:],
    83  	Edits:     []diff.Edit{{Start: 2, End: 3, New: "r"}},
    84  	LineEdits: []diff.Edit{{Start: 0, End: 5, New: "lord\n"}},
    85  }, {
    86  	Name: "replace_partials",
    87  	In:   "blanket\n",
    88  	Out:  "bunker\n",
    89  	Unified: UnifiedPrefix + `
    90  @@ -1 +1 @@
    91  -blanket
    92  +bunker
    93  `[1:],
    94  	Edits: []diff.Edit{
    95  		{Start: 1, End: 3, New: "u"},
    96  		{Start: 6, End: 7, New: "r"},
    97  	},
    98  	LineEdits: []diff.Edit{{Start: 0, End: 8, New: "bunker\n"}},
    99  }, {
   100  	Name: "insert_line",
   101  	In:   "1: one\n3: three\n",
   102  	Out:  "1: one\n2: two\n3: three\n",
   103  	Unified: UnifiedPrefix + `
   104  @@ -1,2 +1,3 @@
   105   1: one
   106  +2: two
   107   3: three
   108  `[1:],
   109  	Edits: []diff.Edit{{Start: 7, End: 7, New: "2: two\n"}},
   110  }, {
   111  	Name: "replace_no_newline",
   112  	In:   "A",
   113  	Out:  "B",
   114  	Unified: UnifiedPrefix + `
   115  @@ -1 +1 @@
   116  -A
   117  \ No newline at end of file
   118  +B
   119  \ No newline at end of file
   120  `[1:],
   121  	Edits: []diff.Edit{{Start: 0, End: 1, New: "B"}},
   122  }, {
   123  	Name: "delete_empty",
   124  	In:   "meow",
   125  	Out:  "", // GNU diff -u special case: +0,0
   126  	Unified: UnifiedPrefix + `
   127  @@ -1 +0,0 @@
   128  -meow
   129  \ No newline at end of file
   130  `[1:],
   131  	Edits:     []diff.Edit{{Start: 0, End: 4, New: ""}},
   132  	LineEdits: []diff.Edit{{Start: 0, End: 4, New: ""}},
   133  }, {
   134  	Name: "append_empty",
   135  	In:   "", // GNU diff -u special case: -0,0
   136  	Out:  "AB\nC",
   137  	Unified: UnifiedPrefix + `
   138  @@ -0,0 +1,2 @@
   139  +AB
   140  +C
   141  \ No newline at end of file
   142  `[1:],
   143  	Edits:     []diff.Edit{{Start: 0, End: 0, New: "AB\nC"}},
   144  	LineEdits: []diff.Edit{{Start: 0, End: 0, New: "AB\nC"}},
   145  },
   146  	// TODO(adonovan): fix this test: GNU diff -u prints "+1,2", Unifies prints "+1,3".
   147  	// 	{
   148  	// 		Name: "add_start",
   149  	// 		In:   "A",
   150  	// 		Out:  "B\nCA",
   151  	// 		Unified: UnifiedPrefix + `
   152  	// @@ -1 +1,2 @@
   153  	// -A
   154  	// \ No newline at end of file
   155  	// +B
   156  	// +CA
   157  	// \ No newline at end of file
   158  	// `[1:],
   159  	// 		Edits:     []diff.TextEdit{{Span: newSpan(0, 0), NewText: "B\nC"}},
   160  	// 		LineEdits: []diff.TextEdit{{Span: newSpan(0, 0), NewText: "B\nC"}},
   161  	// 	},
   162  	{
   163  		Name: "add_end",
   164  		In:   "A",
   165  		Out:  "AB",
   166  		Unified: UnifiedPrefix + `
   167  @@ -1 +1 @@
   168  -A
   169  \ No newline at end of file
   170  +AB
   171  \ No newline at end of file
   172  `[1:],
   173  		Edits:     []diff.Edit{{Start: 1, End: 1, New: "B"}},
   174  		LineEdits: []diff.Edit{{Start: 0, End: 1, New: "AB"}},
   175  	}, {
   176  		Name: "add_empty",
   177  		In:   "",
   178  		Out:  "AB\nC",
   179  		Unified: UnifiedPrefix + `
   180  @@ -0,0 +1,2 @@
   181  +AB
   182  +C
   183  \ No newline at end of file
   184  `[1:],
   185  		Edits:     []diff.Edit{{Start: 0, End: 0, New: "AB\nC"}},
   186  		LineEdits: []diff.Edit{{Start: 0, End: 0, New: "AB\nC"}},
   187  	}, {
   188  		Name: "add_newline",
   189  		In:   "A",
   190  		Out:  "A\n",
   191  		Unified: UnifiedPrefix + `
   192  @@ -1 +1 @@
   193  -A
   194  \ No newline at end of file
   195  +A
   196  `[1:],
   197  		Edits:     []diff.Edit{{Start: 1, End: 1, New: "\n"}},
   198  		LineEdits: []diff.Edit{{Start: 0, End: 1, New: "A\n"}},
   199  	}, {
   200  		Name: "delete_front",
   201  		In:   "A\nB\nC\nA\nB\nB\nA\n",
   202  		Out:  "C\nB\nA\nB\nA\nC\n",
   203  		Unified: UnifiedPrefix + `
   204  @@ -1,7 +1,6 @@
   205  -A
   206  -B
   207   C
   208  +B
   209   A
   210   B
   211  -B
   212   A
   213  +C
   214  `[1:],
   215  		NoDiff: true, // unified diff is different but valid
   216  		Edits: []diff.Edit{
   217  			{Start: 0, End: 4, New: ""},
   218  			{Start: 6, End: 6, New: "B\n"},
   219  			{Start: 10, End: 12, New: ""},
   220  			{Start: 14, End: 14, New: "C\n"},
   221  		},
   222  		LineEdits: []diff.Edit{
   223  			{Start: 0, End: 4, New: ""},
   224  			{Start: 6, End: 6, New: "B\n"},
   225  			{Start: 10, End: 12, New: ""},
   226  			{Start: 14, End: 14, New: "C\n"},
   227  		},
   228  	}, {
   229  		Name: "replace_last_line",
   230  		In:   "A\nB\n",
   231  		Out:  "A\nC\n\n",
   232  		Unified: UnifiedPrefix + `
   233  @@ -1,2 +1,3 @@
   234   A
   235  -B
   236  +C
   237  +
   238  `[1:],
   239  		Edits:     []diff.Edit{{Start: 2, End: 3, New: "C\n"}},
   240  		LineEdits: []diff.Edit{{Start: 2, End: 4, New: "C\n\n"}},
   241  	},
   242  	{
   243  		Name: "multiple_replace",
   244  		In:   "A\nB\nC\nD\nE\nF\nG\n",
   245  		Out:  "A\nH\nI\nJ\nE\nF\nK\n",
   246  		Unified: UnifiedPrefix + `
   247  @@ -1,7 +1,7 @@
   248   A
   249  -B
   250  -C
   251  -D
   252  +H
   253  +I
   254  +J
   255   E
   256   F
   257  -G
   258  +K
   259  `[1:],
   260  		Edits: []diff.Edit{
   261  			{Start: 2, End: 8, New: "H\nI\nJ\n"},
   262  			{Start: 12, End: 14, New: "K\n"},
   263  		},
   264  		NoDiff: true, // diff algorithm produces different delete/insert pattern
   265  	},
   266  	{
   267  		Name:  "extra_newline",
   268  		In:    "\nA\n",
   269  		Out:   "A\n",
   270  		Edits: []diff.Edit{{Start: 0, End: 1, New: ""}},
   271  		Unified: UnifiedPrefix + `@@ -1,2 +1 @@
   272  -
   273   A
   274  `,
   275  	}, {
   276  		Name:      "unified_lines",
   277  		In:        "aaa\nccc\n",
   278  		Out:       "aaa\nbbb\nccc\n",
   279  		Edits:     []diff.Edit{{Start: 3, End: 3, New: "\nbbb"}},
   280  		LineEdits: []diff.Edit{{Start: 0, End: 4, New: "aaa\nbbb\n"}},
   281  		Unified:   UnifiedPrefix + "@@ -1,2 +1,3 @@\n aaa\n+bbb\n ccc\n",
   282  	}, {
   283  		Name: "60379",
   284  		In: `package a
   285  
   286  type S struct {
   287  s fmt.Stringer
   288  }
   289  `,
   290  		Out: `package a
   291  
   292  type S struct {
   293  	s fmt.Stringer
   294  }
   295  `,
   296  		Edits:     []diff.Edit{{Start: 27, End: 27, New: "\t"}},
   297  		LineEdits: []diff.Edit{{Start: 27, End: 42, New: "\ts fmt.Stringer\n"}},
   298  		Unified:   UnifiedPrefix + "@@ -1,5 +1,5 @@\n package a\n \n type S struct {\n-s fmt.Stringer\n+\ts fmt.Stringer\n }\n",
   299  	},
   300  }
   301  
   302  func DiffTest(t *testing.T, compute func(before, after string) []diff.Edit) {
   303  	for _, test := range TestCases {
   304  		t.Run(test.Name, func(t *testing.T) {
   305  			edits := compute(test.In, test.Out)
   306  			got, err := diff.Apply(test.In, edits)
   307  			if err != nil {
   308  				t.Fatalf("Apply failed: %v", err)
   309  			}
   310  			unified, err := diff.ToUnified(FileA, FileB, test.In, edits, diff.DefaultContextLines)
   311  			if err != nil {
   312  				t.Fatalf("ToUnified: %v", err)
   313  			}
   314  			if got != test.Out {
   315  				t.Errorf("Apply: got patched:\n%v\nfrom diff:\n%v\nexpected:\n%v",
   316  					got, unified, test.Out)
   317  			}
   318  			if !test.NoDiff && unified != test.Unified {
   319  				t.Errorf("Unified: got diff:\n%q\nexpected:\n%q diffs:%v",
   320  					unified, test.Unified, edits)
   321  			}
   322  		})
   323  	}
   324  }
   325  

View as plain text