github.com/mistwind/reviewdog@v0.0.0-20230322024206-9cfa11856d58/diff/parse_test.go (about) 1 package diff 2 3 import ( 4 "bufio" 5 "encoding/json" 6 "io" 7 "os" 8 "path/filepath" 9 "reflect" 10 "strings" 11 "testing" 12 ) 13 14 //go:generate go run testdata/gen.go 15 16 const longLine = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Convallis tellus id interdum velit laoreet. Porttitor rhoncus dolor purus non enim praesent. Phasellus egestas tellus rutrum tellus pellentesque. Fringilla urna porttitor rhoncus dolor purus non enim praesent. Proin fermentum leo vel orci porta non pulvinar neque laoreet. Imperdiet nulla malesuada pellentesque elit eget gravida cum. Sit amet nulla facilities morbi tempus iaculis urna id volutpat. Et molestie ac feugiat sed lectus vestibulum mattis. Tortor at auctor urna nunc id cursus metus. Nisl tincidunt eget nullam non nisi est. Tortor at auctor urna nunc id cursus metus. Ornare massa eget egestas purus viverra accumsan. Venenatis urna cursus eget nunc scelerisque viverra mauris in. Platea dictumst vestibulum rhoncus est pellentesque elit. Auctor neque vitae tempus quam pellentesque nec. Vivamus arcu felis bibendum ut tristique et egestas quis. At in tellus integer feugiat scelerisque varius morbi. Imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque. Ac turpis egestas integer eget aliquet nibh praesent tristique. Senectus et netus et malesuada fames ac turpis egestas. Odio eu feugiat pretium nibh ipsum consequat nisl vel. Elit eget gravida cum sociis natoque penatibus et. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. Tincidunt arcu non sodales neque sodales ut etiam sit. Fringilla phasellus faucibus scelerisque eleifend donec pretium vulputate. Urna cursus eget nunc scelerisque viverra mauris in aliquam. Fames ac turpis egestas sed. Vivamus arcu felis bibendum ut tristique et egestas quis ipsum. Turpis tincidunt id aliquet risus feugiat in ante metus dictum. Leo a diam sollicitudin tempor id eu. Consectetur adipiscing elit ut aliquam. Facilities nullam vehicula ipsum a arcu. Dignissim suspendisse in est ante in nibh mauris cursus. Faucibus interdum posuere lorem ipsum dolor sit amet consectetur. Neque convallis a cras semper. Pellentesque habitant morbi tristique senectus. Arcu non sodales neque sodales ut etiam. Pretium quam vulputate dignissim suspendisse in. Id velit ut tortor pretium viverra suspendisse potenti. Venenatis urna cursus eget nunc scelerisque. Vestibulum lorem sed risus ultricies tristique. Faucibus purus in massa tempor. Tellus elementum sagittis vitae et. Ut tortor pretium viverra suspendisse potenti nullam ac. Non arcu risus quis varius. Magna ac placerat vestibulum lectus mauris ultrices eros in. Venenatis lectus magna fringilla urna porttitor. Ultrices gravida dictum fusce ut. Hac habitasse platea dictumst quisque sagittis purus sit. Dictum at tempor commodo ullamcorper a lacus. Mi bibendum neque egestas congue quisque. Lobortis elementum nibh tellus molestie nunc non. Dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique. Pulvinar sapien et ligula ullamcorper malesuada proin libero nunc. Vel elit scelerisque mauris pellentesque pulvinar pellentesque. Eget nulla facilities etiam dignissim diam quis enim. Convallis posuere morbi leo urna molestie. Pellentesque adipiscing commodo elit at imperdiet dui. Mattis pellentesque id nibh tortor id aliquet. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit lectus. Enim lobortis scelerisque fermentum dui faucibus in ornare quam. Maecenas pharetra convallis posuere morbi leo. Dolor morbi non arcu risus quis. Sit amet purus gravida quis. Quis varius quam quisque id diam vel quam elementum. Tortor condimentum lacinia quis vel eros donec. Gravida neque convallis a cras semper auctor neque vitae tempus. Odio eu feugiat pretium nibh ipsum consequat nisl vel pretium. Urna et pharetra pharetra massa massa ultricies mi. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Convallis tellus id interdum velit laoreet. Porttitor rhoncus dolor purus non enim praesent. Phasellus egestas tellus rutrum tellus pellentesque. Fringilla urna porttitor rhoncus dolor purus non enim praesent. Proin fermentum leo vel orci porta non pulvinar neque laoreet. Imperdiet nulla malesuada pellentesque elit eget gravida cum. Sit amet nulla facilities morbi tempus iaculis urna id volutpat. Et molestie ac feugiat sed lectus vestibulum mattis. Tortor at auctor urna nunc id cursus metus. Nisl tincidunt eget nullam non nisi est. Tortor at auctor urna nunc id cursus metus. Ornare massa eget egestas purus viverra accumsan. Venenatis urna cursus eget nunc scelerisque viverra mauris in. Platea dictumst vestibulum rhoncus est pellentesque elit. Auctor neque vitae tempus quam pellentesque nec. Vivamus arcu felis bibendum ut tristique et egestas quis. At in tellus integer feugiat scelerisque varius morbi. Imperdiet nulla malesuada pellentesque elit eget gravida cum sociis natoque. Ac turpis egestas integer eget aliquet nibh praesent tristique. Senectus et netus et malesuada fames ac turpis egestas. Odio eu feugiat pretium nibh ipsum consequat nisl vel. Elit eget gravida cum sociis natoque penatibus et. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. Tincidunt arcu non sodales neque sodales ut etiam sit. Fringilla phasellus faucibus scelerisque eleifend donec pretium vulputate. Urna cursus eget nunc scelerisque viverra mauris in aliquam. Fames ac turpis egestas sed. Vivamus arcu felis bibendum ut tristique et egestas quis ipsum. Turpis tincidunt id aliquet risus feugiat in ante metus dictum. Leo a diam sollicitudin tempor id eu. Consectetur adipiscing elit ut aliquam. Facilities nullam vehicula ipsum a arcu. Dignissim suspendisse in est ante in nibh mauris cursus. Faucibus interdum posuere lorem ipsum dolor sit amet consectetur. Neque convallis a cras semper. Pellentesque habitant morbi tristique senectus. Arcu non sodales neque sodales ut etiam. Pretium quam vulputate dignissim suspendisse in. Id velit ut tortor pretium viverra suspendisse potenti. Venenatis urna cursus eget nunc scelerisque. Vestibulum lorem sed risus ultricies tristique. Faucibus purus in massa tempor. Tellus elementum sagittis vitae et. Ut tortor pretium viverra suspendisse potenti nullam ac. Non arcu risus quis varius. Magna ac placerat vestibulum lectus mauris ultrices eros in. Venenatis lectus magna fringilla urna porttitor. Ultrices gravida dictum fusce ut. Hac habitasse platea dictumst quisque sagittis purus sit. Dictum at tempor commodo ullamcorper a lacus. Mi bibendum neque egestas congue quisque. Lobortis elementum nibh tellus molestie nunc non. Dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique. Pulvinar sapien et ligula ullamcorper malesuada proin libero nunc. Vel elit scelerisque mauris pellentesque pulvinar pellentesque. Eget nulla facilities etiam dignissim diam quis enim. Convallis posuere morbi leo urna molestie. Pellentesque adipiscing commodo elit at imperdiet dui. Mattis pellentesque id nibh tortor id aliquet. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit lectus. Enim lobortis scelerisque fermentum dui faucibus in ornare quam. Maecenas pharetra convallis posuere morbi leo. Dolor morbi non arcu risus quis. Sit amet purus gravida quis. Quis varius quam quisque id diam vel quam elementum. Tortor condimentum lacinia quis vel eros donec. Gravida neque convallis a cras semper auctor neque vitae tempus. Odio eu feugiat pretium nibh ipsum consequat nisl vel pretium. Urna et pharetra pharetra massa massa ultricies mi.` 17 18 func TestParseMultiFile(t *testing.T) { 19 files, err := filepath.Glob("testdata/*.diff") 20 if err != nil { 21 t.Fatal(err) 22 } 23 for _, fname := range files { 24 t.Log(fname) 25 f, err := os.Open(fname) 26 if err != nil { 27 t.Fatal(err) 28 } 29 difffiles, err := ParseMultiFile(f) 30 if err != nil { 31 t.Errorf("%v: %v", fname, err) 32 } 33 34 wantfile, err := os.Open(fname + ".json") 35 if err != nil { 36 t.Fatal(err) 37 } 38 dec := json.NewDecoder(wantfile) 39 var want []*FileDiff 40 if err := dec.Decode(&want); err != nil { 41 t.Fatal(err) 42 } 43 if !reflect.DeepEqual(difffiles, want) { 44 l := len(difffiles) 45 if len(want) > l { 46 l = len(want) 47 } 48 for i := 0; i < l; i++ { 49 var a, b *FileDiff 50 if i < len(want) { 51 a = want[i] 52 } 53 if i < len(difffiles) { 54 b = difffiles[i] 55 } 56 t.Errorf("want %#v, got %#v", a, b) 57 } 58 } 59 60 wantfile.Close() 61 f.Close() 62 } 63 } 64 65 func TestParseMultiFile_sample(t *testing.T) { 66 content := `--- sample.old.txt 2016-10-13 05:09:35.820791185 +0900 67 +++ sample.new.txt 2016-10-13 05:15:26.839245048 +0900 68 @@ -1,3 +1,4 @@ 69 unchanged, contextual line 70 -deleted line 71 +added line 72 +added line 73 unchanged, contextual line 74 --- nonewline.old.txt 2016-10-13 15:34:14.931778318 +0900 75 +++ nonewline.new.txt 2016-10-13 15:34:14.868444672 +0900 76 @@ -1,4 +1,4 @@ 77 " vim: nofixeol noendofline 78 No newline at end of both the old and new file 79 -a 80 -a 81 \ No newline at end of file 82 +b 83 +b 84 \ No newline at end of file 85 ` 86 87 got, err := ParseMultiFile(strings.NewReader(content)) 88 if err != nil { 89 t.Fatal(err) 90 } 91 want := []*FileDiff{ 92 { 93 PathOld: "sample.old.txt", 94 PathNew: "sample.new.txt", 95 TimeOld: "2016-10-13 05:09:35.820791185 +0900", 96 TimeNew: "2016-10-13 05:15:26.839245048 +0900", 97 Hunks: []*Hunk{ 98 { 99 StartLineOld: 1, LineLengthOld: 3, StartLineNew: 1, LineLengthNew: 4, 100 Lines: []*Line{ 101 {Type: 0, Content: "unchanged, contextual line", LnumDiff: 1, LnumOld: 1, LnumNew: 1}, 102 {Type: 2, Content: "deleted line", LnumDiff: 2, LnumOld: 2, LnumNew: 0}, 103 {Type: 1, Content: "added line", LnumDiff: 3, LnumOld: 0, LnumNew: 2}, 104 {Type: 1, Content: "added line", LnumDiff: 4, LnumOld: 0, LnumNew: 3}, 105 {Type: 0, Content: "unchanged, contextual line", LnumDiff: 5, LnumOld: 3, LnumNew: 4}, 106 }, 107 }, 108 }, 109 }, 110 { 111 PathOld: "nonewline.old.txt", 112 PathNew: "nonewline.new.txt", 113 TimeOld: "2016-10-13 15:34:14.931778318 +0900", 114 TimeNew: "2016-10-13 15:34:14.868444672 +0900", 115 Hunks: []*Hunk{ 116 { 117 StartLineOld: 1, LineLengthOld: 4, StartLineNew: 1, LineLengthNew: 4, 118 Lines: []*Line{ 119 {Type: 0, Content: "\" vim: nofixeol noendofline", LnumDiff: 1, LnumOld: 1, LnumNew: 1}, 120 {Type: 0, Content: "No newline at end of both the old and new file", LnumDiff: 2, LnumOld: 2, LnumNew: 2}, 121 {Type: 2, Content: "a", LnumDiff: 3, LnumOld: 3, LnumNew: 0}, 122 {Type: 2, Content: "a", LnumDiff: 4, LnumOld: 4, LnumNew: 0}, 123 {Type: 1, Content: "b", LnumDiff: 5, LnumOld: 0, LnumNew: 3}, 124 {Type: 1, Content: "b", LnumDiff: 6, LnumOld: 0, LnumNew: 4}, 125 }, 126 }, 127 }, 128 }, 129 } 130 if !reflect.DeepEqual(got, want) { 131 t.Errorf("error. in:\n%v", content) 132 for _, fd := range got { 133 t.Logf("FileDiff: %#v\n", fd) 134 for _, h := range fd.Hunks { 135 t.Logf(" Hunk%#v\n", h) 136 for _, l := range h.Lines { 137 t.Logf(" Line%#v\n", l) 138 } 139 } 140 } 141 } 142 } 143 144 func TestFileParser_Parse(t *testing.T) { 145 tests := []struct { 146 in string 147 want *FileDiff 148 }{ 149 { 150 in: "", 151 want: nil, 152 }, 153 { 154 in: `diff --git a/empty.txt b/empty.txtq 155 deleted file mode 100644 156 index e69de29..0000000 157 `, 158 want: &FileDiff{ 159 Extended: []string{ 160 "diff --git a/empty.txt b/empty.txtq", 161 "deleted file mode 100644", 162 "index e69de29..0000000", 163 }, 164 }, 165 }, 166 { 167 in: `--- sample.old.txt 2016-10-13 05:09:35.820791185 +0900 168 +++ sample.new.txt 2016-10-13 05:15:26.839245048 +0900 169 @@ -1,3 +1,4 @@ 170 unchanged, contextual line 171 -deleted line 172 +added line 173 +added line 174 unchanged, contextual line 175 `, 176 want: &FileDiff{ 177 PathOld: "sample.old.txt", 178 PathNew: "sample.new.txt", 179 TimeOld: "2016-10-13 05:09:35.820791185 +0900", 180 TimeNew: "2016-10-13 05:15:26.839245048 +0900", 181 Hunks: []*Hunk{ 182 { 183 StartLineOld: 1, LineLengthOld: 3, StartLineNew: 1, LineLengthNew: 4, 184 Lines: []*Line{ 185 {Type: 0, Content: "unchanged, contextual line", LnumDiff: 1, LnumOld: 1, LnumNew: 1}, 186 {Type: 2, Content: "deleted line", LnumDiff: 2, LnumOld: 2, LnumNew: 0}, 187 {Type: 1, Content: "added line", LnumDiff: 3, LnumOld: 0, LnumNew: 2}, 188 {Type: 1, Content: "added line", LnumDiff: 4, LnumOld: 0, LnumNew: 3}, 189 {Type: 0, Content: "unchanged, contextual line", LnumDiff: 5, LnumOld: 3, LnumNew: 4}, 190 }, 191 }, 192 }, 193 }, 194 }, 195 { 196 in: `--- sample.old.txt 2016-10-13 05:09:35.820791185 +0900 197 +++ sample.new.txt 2016-10-13 05:15:26.839245048 +0900 198 @@ -1,1 +1,1 @@ 199 unchanged, contextual line 200 @@ -2,1 +2,1 @@ 201 unchanged, contextual line 202 `, 203 want: &FileDiff{ 204 PathOld: "sample.old.txt", 205 PathNew: "sample.new.txt", 206 TimeOld: "2016-10-13 05:09:35.820791185 +0900", 207 TimeNew: "2016-10-13 05:15:26.839245048 +0900", 208 Hunks: []*Hunk{ 209 { 210 StartLineOld: 1, LineLengthOld: 1, StartLineNew: 1, LineLengthNew: 1, 211 Lines: []*Line{ 212 {Type: 0, Content: "unchanged, contextual line", LnumDiff: 1, LnumOld: 1, LnumNew: 1}, 213 }, 214 }, 215 { 216 StartLineOld: 2, LineLengthOld: 1, StartLineNew: 2, LineLengthNew: 1, 217 Lines: []*Line{ 218 {Type: 0, Content: "unchanged, contextual line", LnumDiff: 3, LnumOld: 2, LnumNew: 2}, 219 }, 220 }, 221 }, 222 }, 223 }, 224 } 225 for _, tt := range tests { 226 p := &fileParser{r: bufio.NewReader(strings.NewReader(tt.in))} 227 got, err := p.Parse() 228 if err != nil { 229 t.Errorf("got error %v for in:\n %v", err, tt.in) 230 } 231 if !reflect.DeepEqual(got, tt.want) { 232 t.Errorf("fileParser.Parse() = %#v, want %#v\nin: %v", got, tt.want, tt.in) 233 t.Log("got:") 234 for _, h := range got.Hunks { 235 for _, l := range h.Lines { 236 t.Logf("%#v", l) 237 } 238 } 239 t.Log("want:") 240 for _, h := range tt.want.Hunks { 241 for _, l := range h.Lines { 242 t.Logf("%#v", l) 243 } 244 } 245 } 246 } 247 } 248 249 func TestParseFileHeader(t *testing.T) { 250 tests := []struct { 251 in string 252 filename string 253 timestamp string 254 }{ 255 { 256 in: "--- sample.old.txt 2016-10-13 05:09:35.820791185 +0900", 257 filename: "sample.old.txt", 258 timestamp: "2016-10-13 05:09:35.820791185 +0900", 259 }, 260 { 261 in: "+++ sample.old.txt", 262 filename: "sample.old.txt", 263 timestamp: "", 264 }, 265 } 266 for _, tt := range tests { 267 gotf, gott := parseFileHeader(tt.in) 268 if gotf != tt.filename || gott != tt.timestamp { 269 t.Errorf("parseFileHeader(%v) = (%v, %v), want (%v, %v)", tt.in, gotf, gott, tt.filename, tt.timestamp) 270 } 271 } 272 } 273 274 func TestParseExtendedHeader(t *testing.T) { 275 tests := []struct { 276 in string 277 want []string 278 }{ 279 { 280 in: `diff --git a/sample.txt b/sample.txt 281 index a949a96..769bdae 100644 282 --- a/sample.old.txt 283 +++ b/sample.new.txt 284 @@ -1,3 +1,4 @@ 285 `, 286 want: []string{"diff --git a/sample.txt b/sample.txt", "index a949a96..769bdae 100644"}, 287 }, 288 { 289 in: `diff --git a/sample.txt b/sample.txt 290 deleted file mode 100644 291 index e69de29..0000000 292 `, 293 want: []string{"diff --git a/sample.txt b/sample.txt", "deleted file mode 100644", "index e69de29..0000000"}, 294 }, 295 { 296 in: `diff --git a/sample.txt b/sample.txt 297 new file mode 100644 298 index 0000000..e69de29 299 diff --git a/sample2.txt b/sample2.txt 300 new file mode 100644 301 index 0000000..ee946eb 302 `, 303 want: []string{"diff --git a/sample.txt b/sample.txt", "new file mode 100644", "index 0000000..e69de29"}, 304 }, 305 { 306 in: `--- a/sample.old.txt 307 +++ b/sample.new.txt 308 @@ -1,3 +1,4 @@ 309 `, 310 want: nil, 311 }, 312 } 313 for _, tt := range tests { 314 got := parseExtendedHeader(bufio.NewReader(strings.NewReader(tt.in))) 315 if !reflect.DeepEqual(got, tt.want) { 316 t.Errorf("in:\n%v\ngot:\n%v\nwant:\n%v", tt.in, strings.Join(got, "\n"), strings.Join(tt.want, "\n")) 317 } 318 } 319 } 320 321 func TestHunkParser_Parse(t *testing.T) { 322 tests := []struct { 323 in string 324 lnumdiff int 325 want *Hunk 326 }{ 327 { 328 in: `@@ -1,3 +1,4 @@ optional section heading 329 unchanged, contextual line 330 -deleted line 331 +added line 332 +added line 333 unchanged, contextual line 334 `, 335 want: &Hunk{ 336 StartLineOld: 1, LineLengthOld: 3, StartLineNew: 1, LineLengthNew: 4, 337 Section: "optional section heading", 338 Lines: []*Line{ 339 {Type: 0, Content: "unchanged, contextual line", LnumDiff: 1, LnumOld: 1, LnumNew: 1}, 340 {Type: 2, Content: "deleted line", LnumDiff: 2, LnumOld: 2, LnumNew: 0}, 341 {Type: 1, Content: "added line", LnumDiff: 3, LnumOld: 0, LnumNew: 2}, 342 {Type: 1, Content: "added line", LnumDiff: 4, LnumOld: 0, LnumNew: 3}, 343 {Type: 0, Content: "unchanged, contextual line", LnumDiff: 5, LnumOld: 3, LnumNew: 4}, 344 }, 345 }, 346 }, 347 { 348 in: `@@ -1,3 +1,4 @@ 349 unchanged, contextual line 350 -deleted line 351 +added line 352 +added line 353 unchanged, contextual line 354 @@ -1,3 +1,4 @@ 355 `, 356 lnumdiff: 14, 357 want: &Hunk{ 358 StartLineOld: 1, LineLengthOld: 3, StartLineNew: 1, LineLengthNew: 4, 359 Section: "", 360 Lines: []*Line{ 361 {Type: 0, Content: "unchanged, contextual line", LnumDiff: 15, LnumOld: 1, LnumNew: 1}, 362 {Type: 2, Content: "deleted line", LnumDiff: 16, LnumOld: 2, LnumNew: 0}, 363 {Type: 1, Content: "added line", LnumDiff: 17, LnumOld: 0, LnumNew: 2}, 364 {Type: 1, Content: "added line", LnumDiff: 18, LnumOld: 0, LnumNew: 3}, 365 {Type: 0, Content: "unchanged, contextual line", LnumDiff: 19, LnumOld: 3, LnumNew: 4}, 366 }, 367 }, 368 }, 369 } 370 for _, tt := range tests { 371 got, err := (&hunkParser{r: bufio.NewReader(strings.NewReader(tt.in)), lnumdiff: tt.lnumdiff}).Parse() 372 if err != nil { 373 t.Errorf("hunkParser.Parse(%v) got an unexpected err %v", tt.in, err) 374 } 375 if !reflect.DeepEqual(got, tt.want) { 376 t.Errorf("hunkParser.Parse(%v) = \n%#v\n, want \n%#v", tt.in, got, tt.want) 377 t.Logf("got lines:") 378 for _, l := range got.Lines { 379 t.Logf("%#v", l) 380 } 381 t.Logf("want lines:") 382 for _, l := range tt.want.Lines { 383 t.Logf("%#v", l) 384 } 385 } 386 } 387 } 388 389 func TestParseHunkRange(t *testing.T) { 390 tests := []struct { 391 in string 392 want *hunkrange 393 }{ 394 { 395 in: "@@ -1,3 +1,4 @@", 396 want: &hunkrange{lold: 1, sold: 3, lnew: 1, snew: 4}, 397 }, 398 { 399 in: "@@ -1 +1 @@", 400 want: &hunkrange{lold: 1, sold: 1, lnew: 1, snew: 1}, 401 }, 402 { 403 in: "@@ -1,3 +1,4 @@ optional section", 404 want: &hunkrange{lold: 1, sold: 3, lnew: 1, snew: 4, section: "optional section"}, 405 }, 406 } 407 for _, tt := range tests { 408 got, err := parseHunkRange(tt.in) 409 if err != nil { 410 t.Errorf("parseHunkRange(%v) got an unexpected err %v", tt.in, err) 411 } 412 if !reflect.DeepEqual(got, tt.want) { 413 t.Errorf("parseHunkRange(%v) = %#v, want %#v", tt.in, got, tt.want) 414 } 415 } 416 } 417 418 func TestParseLS(t *testing.T) { 419 tests := []struct { 420 in string 421 l int 422 s int 423 }{ 424 {in: "1,3", l: 1, s: 3}, 425 {in: "14", l: 14, s: 1}, 426 } 427 for _, tt := range tests { 428 gotl, gots, err := parseLS(tt.in) 429 if err != nil { 430 t.Errorf("parseLS(%v) got an unexpected err %v", tt.in, err) 431 } 432 if gotl != tt.l || gots != tt.s { 433 t.Errorf("parseLS(%v) = (%v, %v, _), want (%v, %v, _)", tt.in, gotl, gots, tt.l, tt.s) 434 } 435 } 436 } 437 438 func TestReadline(t *testing.T) { 439 tests := []struct { 440 in string 441 out []string 442 }{ 443 { 444 in: `line1 445 line2 446 line3`, 447 out: []string{"line1", "line2", "line3"}, 448 }, 449 { 450 in: longLine + ` 451 line2 452 line3`, 453 out: []string{longLine, "line2", "line3"}, 454 }, 455 } 456 for _, tt := range tests { 457 r := bufio.NewReader(strings.NewReader(tt.in)) 458 for _, exp := range tt.out { 459 got, err := readline(r) 460 if err != nil { 461 t.Error(err) 462 } 463 if got != exp { 464 t.Errorf("got:\n%v\n\nwant:\n%v", got, exp) 465 } 466 } 467 { 468 if _, err := readline(r); err != io.EOF { 469 t.Errorf("got err %v, want io.EOF", err) 470 } 471 } 472 } 473 } 474 475 func TestUnquoteCStyle(t *testing.T) { 476 tests := []struct { 477 in string 478 out string 479 }{ 480 {in: `no need to unquote`, out: `no need to unquote`}, 481 {in: `"C-escapes \a\b\t\n\v\f\r\"\\"`, out: "C-escapes \a\b\t\n\v\f\r\"\\"}, 482 483 // from https://github.com/git/git/blob/041f5ea1cf987a4068ef5f39ba0a09be85952064/t/t3902-quoted.sh#L48-L76 484 {in: `Name`, out: `Name`}, 485 {in: `"Name and a\nLF"`, out: "Name and a\nLF"}, 486 {in: `"Name and an\tHT"`, out: "Name and an\tHT"}, 487 {in: `"Name\""`, out: `Name"`}, 488 {in: `With SP in it`, out: `With SP in it`}, 489 {in: `"\346\277\261\351\207\216\t\347\264\224"`, out: "濱野\t純"}, 490 {in: `"\346\277\261\351\207\216\n\347\264\224"`, out: "濱野\n純"}, 491 {in: `"\346\277\261\351\207\216 \347\264\224"`, out: `濱野 純`}, 492 {in: `"\346\277\261\351\207\216\"\347\264\224"`, out: "濱野\"純"}, 493 {in: `"\346\277\261\351\207\216/file"`, out: `濱野/file`}, 494 {in: `"\346\277\261\351\207\216\347\264\224"`, out: `濱野純`}, 495 496 // Edge cases of ill-formed diff file name. 497 {in: `\347\264\224`, out: `\347\264\224`}, // no need to unquote 498 {in: `"\34a"`, out: "34a"}, 499 {in: `"\14"`, out: `14`}, 500 } 501 502 for _, tt := range tests { 503 if got := unquoteCStyle(tt.in); got != tt.out { 504 t.Errorf("unquoteCStyle(%q) = %q, want %q", tt.in, got, tt.out) 505 } 506 } 507 }