github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/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 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: "append_empty", 124 In: "", // GNU diff -u special case: -0,0 125 Out: "AB\nC", 126 Unified: UnifiedPrefix + ` 127 @@ -0,0 +1,2 @@ 128 +AB 129 +C 130 \ No newline at end of file 131 `[1:], 132 Edits: []diff.Edit{{Start: 0, End: 0, New: "AB\nC"}}, 133 LineEdits: []diff.Edit{{Start: 0, End: 0, New: "AB\nC"}}, 134 }, 135 // TODO(adonovan): fix this test: GNU diff -u prints "+1,2", Unifies prints "+1,3". 136 // { 137 // Name: "add_start", 138 // In: "A", 139 // Out: "B\nCA", 140 // Unified: UnifiedPrefix + ` 141 // @@ -1 +1,2 @@ 142 // -A 143 // \ No newline at end of file 144 // +B 145 // +CA 146 // \ No newline at end of file 147 // `[1:], 148 // Edits: []diff.TextEdit{{Span: newSpan(0, 0), NewText: "B\nC"}}, 149 // LineEdits: []diff.TextEdit{{Span: newSpan(0, 0), NewText: "B\nC"}}, 150 // }, 151 { 152 Name: "add_end", 153 In: "A", 154 Out: "AB", 155 Unified: UnifiedPrefix + ` 156 @@ -1 +1 @@ 157 -A 158 \ No newline at end of file 159 +AB 160 \ No newline at end of file 161 `[1:], 162 Edits: []diff.Edit{{Start: 1, End: 1, New: "B"}}, 163 LineEdits: []diff.Edit{{Start: 0, End: 1, New: "AB"}}, 164 }, { 165 Name: "add_empty", 166 In: "", 167 Out: "AB\nC", 168 Unified: UnifiedPrefix + ` 169 @@ -0,0 +1,2 @@ 170 +AB 171 +C 172 \ No newline at end of file 173 `[1:], 174 Edits: []diff.Edit{{Start: 0, End: 0, New: "AB\nC"}}, 175 LineEdits: []diff.Edit{{Start: 0, End: 0, New: "AB\nC"}}, 176 }, { 177 Name: "add_newline", 178 In: "A", 179 Out: "A\n", 180 Unified: UnifiedPrefix + ` 181 @@ -1 +1 @@ 182 -A 183 \ No newline at end of file 184 +A 185 `[1:], 186 Edits: []diff.Edit{{Start: 1, End: 1, New: "\n"}}, 187 LineEdits: []diff.Edit{{Start: 0, End: 1, New: "A\n"}}, 188 }, { 189 Name: "delete_front", 190 In: "A\nB\nC\nA\nB\nB\nA\n", 191 Out: "C\nB\nA\nB\nA\nC\n", 192 Unified: UnifiedPrefix + ` 193 @@ -1,7 +1,6 @@ 194 -A 195 -B 196 C 197 +B 198 A 199 B 200 -B 201 A 202 +C 203 `[1:], 204 NoDiff: true, // unified diff is different but valid 205 Edits: []diff.Edit{ 206 {Start: 0, End: 4, New: ""}, 207 {Start: 6, End: 6, New: "B\n"}, 208 {Start: 10, End: 12, New: ""}, 209 {Start: 14, End: 14, New: "C\n"}, 210 }, 211 LineEdits: []diff.Edit{ 212 {Start: 0, End: 6, New: "C\n"}, 213 {Start: 6, End: 8, New: "B\nA\n"}, 214 {Start: 10, End: 14, New: "A\n"}, 215 {Start: 14, End: 14, New: "C\n"}, 216 }, 217 }, { 218 Name: "replace_last_line", 219 In: "A\nB\n", 220 Out: "A\nC\n\n", 221 Unified: UnifiedPrefix + ` 222 @@ -1,2 +1,3 @@ 223 A 224 -B 225 +C 226 + 227 `[1:], 228 Edits: []diff.Edit{{Start: 2, End: 3, New: "C\n"}}, 229 LineEdits: []diff.Edit{{Start: 2, End: 4, New: "C\n\n"}}, 230 }, 231 { 232 Name: "multiple_replace", 233 In: "A\nB\nC\nD\nE\nF\nG\n", 234 Out: "A\nH\nI\nJ\nE\nF\nK\n", 235 Unified: UnifiedPrefix + ` 236 @@ -1,7 +1,7 @@ 237 A 238 -B 239 -C 240 -D 241 +H 242 +I 243 +J 244 E 245 F 246 -G 247 +K 248 `[1:], 249 Edits: []diff.Edit{ 250 {Start: 2, End: 8, New: "H\nI\nJ\n"}, 251 {Start: 12, End: 14, New: "K\n"}, 252 }, 253 NoDiff: true, // diff algorithm produces different delete/insert pattern 254 }, 255 { 256 Name: "extra_newline", 257 In: "\nA\n", 258 Out: "A\n", 259 Edits: []diff.Edit{{Start: 0, End: 1, New: ""}}, 260 Unified: UnifiedPrefix + `@@ -1,2 +1 @@ 261 - 262 A 263 `, 264 }, 265 } 266 267 func DiffTest(t *testing.T, compute func(before, after string) []diff.Edit) { 268 for _, test := range TestCases { 269 t.Run(test.Name, func(t *testing.T) { 270 edits := compute(test.In, test.Out) 271 got, err := diff.Apply(test.In, edits) 272 if err != nil { 273 t.Fatalf("Apply failed: %v", err) 274 } 275 unified, err := diff.ToUnified(FileA, FileB, test.In, edits) 276 if err != nil { 277 t.Fatalf("ToUnified: %v", err) 278 } 279 if got != test.Out { 280 t.Errorf("Apply: got patched:\n%v\nfrom diff:\n%v\nexpected:\n%v", 281 got, unified, test.Out) 282 } 283 if !test.NoDiff && unified != test.Unified { 284 t.Errorf("Unified: got diff:\n%q\nexpected:\n%q diffs:%v", 285 unified, test.Unified, edits) 286 } 287 }) 288 } 289 }