|
5 | 5 | "fmt"
|
6 | 6 | "io/ioutil"
|
7 | 7 | "path"
|
| 8 | + "reflect" |
8 | 9 | "strings"
|
9 | 10 | "testing"
|
10 | 11 | )
|
@@ -463,6 +464,141 @@ func TestApplyDiffAddfile(t *testing.T) {
|
463 | 464 | })
|
464 | 465 | }
|
465 | 466 |
|
| 467 | +func TestApplyToTree(t *testing.T) { |
| 468 | + repo := createTestRepo(t) |
| 469 | + defer cleanupTestRepo(t, repo) |
| 470 | + |
| 471 | + seedTestRepo(t, repo) |
| 472 | + |
| 473 | + commitA, treeA := addAndGetTree(t, repo, "file", "a") |
| 474 | + defer commitA.Free() |
| 475 | + defer treeA.Free() |
| 476 | + commitB, treeB := addAndGetTree(t, repo, "file", "b") |
| 477 | + defer commitB.Free() |
| 478 | + defer treeB.Free() |
| 479 | + commitC, treeC := addAndGetTree(t, repo, "file", "c") |
| 480 | + defer commitC.Free() |
| 481 | + defer treeC.Free() |
| 482 | + |
| 483 | + diffAB, err := repo.DiffTreeToTree(treeA, treeB, nil) |
| 484 | + checkFatal(t, err) |
| 485 | + |
| 486 | + diffAC, err := repo.DiffTreeToTree(treeA, treeC, nil) |
| 487 | + checkFatal(t, err) |
| 488 | + |
| 489 | + for _, tc := range []struct { |
| 490 | + name string |
| 491 | + tree *Tree |
| 492 | + diff *Diff |
| 493 | + applyHunkCallback ApplyHunkCallback |
| 494 | + applyDeltaCallback ApplyDeltaCallback |
| 495 | + error error |
| 496 | + expectedDiff *Diff |
| 497 | + }{ |
| 498 | + { |
| 499 | + name: "applying patch produces the same diff", |
| 500 | + tree: treeA, |
| 501 | + diff: diffAB, |
| 502 | + expectedDiff: diffAB, |
| 503 | + }, |
| 504 | + { |
| 505 | + name: "applying a conflicting patch errors", |
| 506 | + tree: treeB, |
| 507 | + diff: diffAC, |
| 508 | + error: &GitError{ |
| 509 | + Message: "hunk at line 1 did not apply", |
| 510 | + Code: ErrApplyFail, |
| 511 | + Class: ErrClassPatch, |
| 512 | + }, |
| 513 | + }, |
| 514 | + { |
| 515 | + name: "callbacks succeeding apply the diff", |
| 516 | + tree: treeA, |
| 517 | + diff: diffAB, |
| 518 | + applyHunkCallback: func(*DiffHunk) (bool, error) { return true, nil }, |
| 519 | + applyDeltaCallback: func(*DiffDelta) (bool, error) { return true, nil }, |
| 520 | + expectedDiff: diffAB, |
| 521 | + }, |
| 522 | + { |
| 523 | + name: "hunk callback returning false does not apply", |
| 524 | + tree: treeA, |
| 525 | + diff: diffAB, |
| 526 | + applyHunkCallback: func(*DiffHunk) (bool, error) { return false, nil }, |
| 527 | + }, |
| 528 | + { |
| 529 | + name: "hunk callback erroring fails the call", |
| 530 | + tree: treeA, |
| 531 | + diff: diffAB, |
| 532 | + applyHunkCallback: func(*DiffHunk) (bool, error) { return true, errors.New("message dropped") }, |
| 533 | + error: &GitError{ |
| 534 | + Code: ErrGeneric, |
| 535 | + Class: ErrClassInvalid, |
| 536 | + }, |
| 537 | + }, |
| 538 | + { |
| 539 | + name: "delta callback returning false does not apply", |
| 540 | + tree: treeA, |
| 541 | + diff: diffAB, |
| 542 | + applyDeltaCallback: func(*DiffDelta) (bool, error) { return false, nil }, |
| 543 | + }, |
| 544 | + { |
| 545 | + name: "delta callback erroring fails the call", |
| 546 | + tree: treeA, |
| 547 | + diff: diffAB, |
| 548 | + applyDeltaCallback: func(*DiffDelta) (bool, error) { return true, errors.New("message dropped") }, |
| 549 | + error: &GitError{ |
| 550 | + Code: ErrGeneric, |
| 551 | + Class: ErrClassInvalid, |
| 552 | + }, |
| 553 | + }, |
| 554 | + } { |
| 555 | + t.Run(tc.name, func(t *testing.T) { |
| 556 | + opts, err := DefaultApplyOptions() |
| 557 | + checkFatal(t, err) |
| 558 | + |
| 559 | + opts.ApplyHunkCallback = tc.applyHunkCallback |
| 560 | + opts.ApplyDeltaCallback = tc.applyDeltaCallback |
| 561 | + |
| 562 | + index, err := repo.ApplyToTree(tc.diff, tc.tree, opts) |
| 563 | + if tc.error != nil { |
| 564 | + if !reflect.DeepEqual(err, tc.error) { |
| 565 | + t.Fatalf("expected error %q but got %q", tc.error, err) |
| 566 | + } |
| 567 | + |
| 568 | + return |
| 569 | + } |
| 570 | + checkFatal(t, err) |
| 571 | + |
| 572 | + patchedTreeOID, err := index.WriteTreeTo(repo) |
| 573 | + checkFatal(t, err) |
| 574 | + |
| 575 | + patchedTree, err := repo.LookupTree(patchedTreeOID) |
| 576 | + checkFatal(t, err) |
| 577 | + |
| 578 | + patchedDiff, err := repo.DiffTreeToTree(tc.tree, patchedTree, nil) |
| 579 | + checkFatal(t, err) |
| 580 | + |
| 581 | + appliedRaw, err := patchedDiff.ToBuf(DiffFormatPatch) |
| 582 | + checkFatal(t, err) |
| 583 | + |
| 584 | + if tc.expectedDiff == nil { |
| 585 | + if len(appliedRaw) > 0 { |
| 586 | + t.Fatalf("expected no diff but got: %s", appliedRaw) |
| 587 | + } |
| 588 | + |
| 589 | + return |
| 590 | + } |
| 591 | + |
| 592 | + expectedDiff, err := tc.expectedDiff.ToBuf(DiffFormatPatch) |
| 593 | + checkFatal(t, err) |
| 594 | + |
| 595 | + if string(expectedDiff) != string(appliedRaw) { |
| 596 | + t.Fatalf("diffs do not match:\nexpected: %s\n\nactual: %s", expectedDiff, appliedRaw) |
| 597 | + } |
| 598 | + }) |
| 599 | + } |
| 600 | +} |
| 601 | + |
466 | 602 | // checkSecondFileStaged checks that there is a single file called "file2" uncommitted in the repo
|
467 | 603 | func checkSecondFileStaged(t *testing.T, repo *Repository) {
|
468 | 604 | opts := StatusOptions{
|
|
0 commit comments