this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add tests for ParseTextFragments

Covers that multiple fragments actually works and the unique error
contidions, but otherwise relies on the lower level tests for
correctness. Also update some comments and the README based on
observations from writing/debugging these tests.

+176 -13
+11 -8
README.md
··· 34 34 35 35 [apply.c]: https://github.com/git/git/blob/master/apply.c 36 36 37 - ## Known Issues and Differences From Git 37 + ## Differences From Git 38 38 39 - 1. Certain types of invalid input that I believe are accepted by `git apply` 40 - generate errors. These include: 39 + 1. Certain types of invalid input that are accepted by `git apply` generate 40 + errors. These include: 41 41 42 42 - Numbers immediately followed by non-numeric characters 43 43 - Trailing characters on a line after valid or expected content 44 44 45 - 2. The translation from C to Go may have introduced inconsistencies in the way 45 + 2. Errors for invalid input are generally more verbose and specific than those 46 + from `git apply`. 47 + 48 + 3. The translation from C to Go may have introduced inconsistencies in the way 46 49 Unicode file names are handled; these are bugs, so please report any issues 47 50 of this type. 48 51 49 - 3. When reading headers, there is no validation that OIDs present on an `index` 52 + 4. When reading headers, there is no validation that OIDs present on an `index` 50 53 line are shorter than or equal to the maximum hash length, as this requires 51 54 knowing if the repository used SHA1 or SHA256 hashes. 52 55 53 - 4. When reading "traditional" patches (those not produced by `git`), prefixes 54 - are not stripped from file names (`git apply` attempts to remove prefixes 55 - that match the current repository directory/prefix.) 56 + 5. When reading "traditional" patches (those not produced by `git`), prefixes 57 + are not stripped from file names; `git apply` attempts to remove prefixes 58 + that match the current repository directory/prefix.
+6 -1
gitdiff/parser.go
··· 134 134 } 135 135 136 136 if err := p.ParseTextChunk(frag); err != nil { 137 - return n, nil 137 + return n, err 138 138 } 139 139 140 140 f.Fragments = append(f.Fragments, frag) ··· 277 277 last.Line = strings.TrimSuffix(last.Line, "\n") 278 278 break 279 279 } 280 + // TODO(bkeyes): if this is because we hit the next header, it 281 + // would be helpful to return the miscounts line error. We could 282 + // either test for the common headers ("@@ -", "diff --git") or 283 + // assume any invalid op ends the fragment; git returns the same 284 + // generic error in all cases so either is compatible 280 285 return p.Errorf(0, "invalid line operation: %q", op) 281 286 } 282 287
+159 -4
gitdiff/parser_text_test.go
··· 1 1 package gitdiff 2 2 3 3 import ( 4 + "io" 4 5 "reflect" 5 6 "testing" 6 7 ) ··· 55 56 56 57 frag, err := p.ParseTextFragmentHeader() 57 58 if test.Err { 58 - if err == nil { 59 - t.Fatalf("expected error parsing header, but got nil") 59 + if err == nil || err == io.EOF { 60 + t.Fatalf("expected error parsing header, but got %v", err) 60 61 } 61 62 return 62 63 } ··· 152 153 TrailingContext: 1, 153 154 }, 154 155 }, 156 + "middleContext": { 157 + Input: ` context line 158 + -old line 1 159 + context line 160 + +new line 1 161 + context line 162 + `, 163 + Fragment: Fragment{ 164 + OldLines: 4, 165 + NewLines: 4, 166 + }, 167 + Output: &Fragment{ 168 + OldLines: 4, 169 + NewLines: 4, 170 + Lines: []FragmentLine{ 171 + {OpContext, "context line\n"}, 172 + {OpDelete, "old line 1\n"}, 173 + {OpContext, "context line\n"}, 174 + {OpAdd, "new line 1\n"}, 175 + {OpContext, "context line\n"}, 176 + }, 177 + LinesDeleted: 1, 178 + LinesAdded: 1, 179 + LeadingContext: 1, 180 + TrailingContext: 1, 181 + }, 182 + }, 155 183 "deleteFinalNewline": { 156 184 Input: ` context line 157 185 -old line 1 ··· 298 326 frag := test.Fragment 299 327 err := p.ParseTextChunk(&frag) 300 328 if test.Err { 301 - if err == nil { 302 - t.Fatalf("expected error parsing text chunk, but got nil") 329 + if err == nil || err == io.EOF { 330 + t.Fatalf("expected error parsing text chunk, but got %v", err) 303 331 } 304 332 return 305 333 } ··· 313 341 }) 314 342 } 315 343 } 344 + 345 + func TestParseTextFragments(t *testing.T) { 346 + tests := map[string]struct { 347 + Input string 348 + File File 349 + 350 + Fragments []*Fragment 351 + Err bool 352 + }{ 353 + "multipleChanges": { 354 + Input: `@@ -1,3 +1,2 @@ 355 + context line 356 + -old line 1 357 + context line 358 + @@ -8,3 +7,3 @@ 359 + context line 360 + -old line 2 361 + +new line 1 362 + context line 363 + @@ -15,3 +14,4 @@ 364 + context line 365 + -old line 3 366 + +new line 2 367 + +new line 3 368 + context line 369 + `, 370 + Fragments: []*Fragment{ 371 + { 372 + OldPosition: 1, 373 + OldLines: 3, 374 + NewPosition: 1, 375 + NewLines: 2, 376 + Lines: []FragmentLine{ 377 + {OpContext, "context line\n"}, 378 + {OpDelete, "old line 1\n"}, 379 + {OpContext, "context line\n"}, 380 + }, 381 + LinesDeleted: 1, 382 + LeadingContext: 1, 383 + TrailingContext: 1, 384 + }, 385 + { 386 + OldPosition: 8, 387 + OldLines: 3, 388 + NewPosition: 7, 389 + NewLines: 3, 390 + Lines: []FragmentLine{ 391 + {OpContext, "context line\n"}, 392 + {OpDelete, "old line 2\n"}, 393 + {OpAdd, "new line 1\n"}, 394 + {OpContext, "context line\n"}, 395 + }, 396 + LinesDeleted: 1, 397 + LinesAdded: 1, 398 + LeadingContext: 1, 399 + TrailingContext: 1, 400 + }, 401 + { 402 + OldPosition: 15, 403 + OldLines: 3, 404 + NewPosition: 14, 405 + NewLines: 4, 406 + Lines: []FragmentLine{ 407 + {OpContext, "context line\n"}, 408 + {OpDelete, "old line 3\n"}, 409 + {OpAdd, "new line 2\n"}, 410 + {OpAdd, "new line 3\n"}, 411 + {OpContext, "context line\n"}, 412 + }, 413 + LinesDeleted: 1, 414 + LinesAdded: 2, 415 + LeadingContext: 1, 416 + TrailingContext: 1, 417 + }, 418 + }, 419 + }, 420 + "badNewFile": { 421 + Input: `@@ -1 +1,2 @@ 422 + -old line 1 423 + +new line 1 424 + +new line 2 425 + `, 426 + File: File{ 427 + IsNew: true, 428 + }, 429 + Err: true, 430 + }, 431 + "badDeletedFile": { 432 + Input: `@@ -1,2 +1 @@ 433 + -old line 1 434 + context line 435 + `, 436 + File: File{ 437 + IsDelete: true, 438 + }, 439 + Err: true, 440 + }, 441 + } 442 + 443 + for name, test := range tests { 444 + t.Run(name, func(t *testing.T) { 445 + p := newTestParser(test.Input, true) 446 + 447 + file := test.File 448 + n, err := p.ParseTextFragments(&file) 449 + if test.Err { 450 + if err == nil || err == io.EOF { 451 + t.Fatalf("expected error parsing text fragments, but got %v", err) 452 + } 453 + return 454 + } 455 + if err != nil { 456 + t.Fatalf("error parsing text fragments: %v", err) 457 + } 458 + 459 + if len(test.Fragments) != n { 460 + t.Fatalf("incorrect number of added fragments: expected %d, actual %d", len(test.Fragments), n) 461 + } 462 + 463 + for i, frag := range test.Fragments { 464 + if !reflect.DeepEqual(frag, file.Fragments[i]) { 465 + t.Errorf("incorrect fragment at position %d\nexpected: %+v\nactual: %+v", i, frag, file.Fragments[i]) 466 + } 467 + } 468 + }) 469 + } 470 + }