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.
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/lsp/diff"
14 "golang.org/x/tools/internal/lsp/diff"
15 "golang.org/x/tools/internal/span"
21 UnifiedPrefix = "--- " + FileA + "\n+++ " + FileB + "\n"
24 var TestCases = []struct {
25 Name, In, Out, Unified string
26 Edits, LineEdits []diff.TextEdit
40 Unified: UnifiedPrefix + `
45 Edits: []diff.TextEdit{{Span: newSpan(0, 5), NewText: "cheese"}},
46 LineEdits: []diff.TextEdit{{Span: newSpan(0, 6), NewText: "cheese\n"}},
51 Unified: UnifiedPrefix + `
56 Edits: []diff.TextEdit{{Span: newSpan(2, 2), NewText: "u"}},
57 LineEdits: []diff.TextEdit{{Span: newSpan(0, 5), NewText: "gourd\n"}},
62 Unified: UnifiedPrefix + `
67 Edits: []diff.TextEdit{{Span: newSpan(1, 2), NewText: ""}},
68 LineEdits: []diff.TextEdit{{Span: newSpan(0, 6), NewText: "goat\n"}},
73 Unified: UnifiedPrefix + `
78 Edits: []diff.TextEdit{{Span: newSpan(2, 3), NewText: "r"}},
79 LineEdits: []diff.TextEdit{{Span: newSpan(0, 5), NewText: "lord\n"}},
81 Name: "replace_partials",
84 Unified: UnifiedPrefix + `
89 Edits: []diff.TextEdit{
90 {Span: newSpan(1, 3), NewText: "u"},
91 {Span: newSpan(6, 7), NewText: "r"},
93 LineEdits: []diff.TextEdit{{Span: newSpan(0, 8), NewText: "bunker\n"}},
96 In: "1: one\n3: three\n",
97 Out: "1: one\n2: two\n3: three\n",
98 Unified: UnifiedPrefix + `
104 Edits: []diff.TextEdit{{Span: newSpan(7, 7), NewText: "2: two\n"}},
106 Name: "replace_no_newline",
109 Unified: UnifiedPrefix + `
112 \ No newline at end of file
114 \ No newline at end of file
116 Edits: []diff.TextEdit{{Span: newSpan(0, 1), NewText: "B"}},
121 Unified: UnifiedPrefix + `
124 \ No newline at end of file
126 \ No newline at end of file
128 Edits: []diff.TextEdit{{Span: newSpan(1, 1), NewText: "B"}},
129 LineEdits: []diff.TextEdit{{Span: newSpan(0, 1), NewText: "AB"}},
134 Unified: UnifiedPrefix + `
137 \ No newline at end of file
140 Edits: []diff.TextEdit{{Span: newSpan(1, 1), NewText: "\n"}},
141 LineEdits: []diff.TextEdit{{Span: newSpan(0, 1), NewText: "A\n"}},
143 Name: "delete_front",
144 In: "A\nB\nC\nA\nB\nB\nA\n",
145 Out: "C\nB\nA\nB\nA\nC\n",
146 Unified: UnifiedPrefix + `
158 Edits: []diff.TextEdit{
159 {Span: newSpan(0, 4), NewText: ""},
160 {Span: newSpan(6, 6), NewText: "B\n"},
161 {Span: newSpan(10, 12), NewText: ""},
162 {Span: newSpan(14, 14), NewText: "C\n"},
164 NoDiff: true, // diff algorithm produces different delete/insert pattern
167 Name: "replace_last_line",
170 Unified: UnifiedPrefix + `
177 Edits: []diff.TextEdit{{Span: newSpan(2, 3), NewText: "C\n"}},
178 LineEdits: []diff.TextEdit{{Span: newSpan(2, 4), NewText: "C\n\n"}},
181 Name: "multiple_replace",
182 In: "A\nB\nC\nD\nE\nF\nG\n",
183 Out: "A\nH\nI\nJ\nE\nF\nK\n",
184 Unified: UnifiedPrefix + `
198 Edits: []diff.TextEdit{
199 {Span: newSpan(2, 8), NewText: "H\nI\nJ\n"},
200 {Span: newSpan(12, 14), NewText: "K\n"},
202 NoDiff: true, // diff algorithm produces different delete/insert pattern
207 // expand all the spans to full versions
208 // we need them all to have their line number and column
209 for _, tc := range TestCases {
210 c := span.NewContentConverter("", []byte(tc.In))
211 for i := range tc.Edits {
212 tc.Edits[i].Span, _ = tc.Edits[i].Span.WithAll(c)
214 for i := range tc.LineEdits {
215 tc.LineEdits[i].Span, _ = tc.LineEdits[i].Span.WithAll(c)
220 func DiffTest(t *testing.T, compute diff.ComputeEdits) {
222 for _, test := range TestCases {
223 t.Run(test.Name, func(t *testing.T) {
225 edits, err := compute(span.URIFromPath("/"+test.Name), test.In, test.Out)
229 got := diff.ApplyEdits(test.In, edits)
230 unified := fmt.Sprint(diff.ToUnified(FileA, FileB, test.In, edits))
232 t.Errorf("got patched:\n%v\nfrom diff:\n%v\nexpected:\n%v", got, unified, test.Out)
234 if !test.NoDiff && unified != test.Unified {
235 t.Errorf("got diff:\n%v\nexpected:\n%v", unified, test.Unified)
241 func newSpan(start, end int) span.Span {
242 return span.New("", span.NewPoint(0, 0, start), span.NewPoint(0, 0, end))