golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/internal/diff/difftest/difftest.go (about) 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 }