From 10d5ebf231bdc37293235a6fc2bdf94fd25d0c56 Mon Sep 17 00:00:00 2001 From: Sami Hiltunen Date: Fri, 23 Oct 2020 14:17:38 +0200 Subject: apply: Add bindings for git_apply_to_tree (#657) Adds bindings to the git_apply_to_tree function that allows applying a diff directly to a tree. --- diff_test.go | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) (limited to 'diff_test.go') diff --git a/diff_test.go b/diff_test.go index e440206..e2f810b 100644 --- a/diff_test.go +++ b/diff_test.go @@ -5,6 +5,7 @@ import ( "fmt" "io/ioutil" "path" + "reflect" "strings" "testing" ) @@ -463,6 +464,141 @@ func TestApplyDiffAddfile(t *testing.T) { }) } +func TestApplyToTree(t *testing.T) { + repo := createTestRepo(t) + defer cleanupTestRepo(t, repo) + + seedTestRepo(t, repo) + + commitA, treeA := addAndGetTree(t, repo, "file", "a") + defer commitA.Free() + defer treeA.Free() + commitB, treeB := addAndGetTree(t, repo, "file", "b") + defer commitB.Free() + defer treeB.Free() + commitC, treeC := addAndGetTree(t, repo, "file", "c") + defer commitC.Free() + defer treeC.Free() + + diffAB, err := repo.DiffTreeToTree(treeA, treeB, nil) + checkFatal(t, err) + + diffAC, err := repo.DiffTreeToTree(treeA, treeC, nil) + checkFatal(t, err) + + for _, tc := range []struct { + name string + tree *Tree + diff *Diff + applyHunkCallback ApplyHunkCallback + applyDeltaCallback ApplyDeltaCallback + error error + expectedDiff *Diff + }{ + { + name: "applying patch produces the same diff", + tree: treeA, + diff: diffAB, + expectedDiff: diffAB, + }, + { + name: "applying a conflicting patch errors", + tree: treeB, + diff: diffAC, + error: &GitError{ + Message: "hunk at line 1 did not apply", + Code: ErrApplyFail, + Class: ErrClassPatch, + }, + }, + { + name: "callbacks succeeding apply the diff", + tree: treeA, + diff: diffAB, + applyHunkCallback: func(*DiffHunk) (bool, error) { return true, nil }, + applyDeltaCallback: func(*DiffDelta) (bool, error) { return true, nil }, + expectedDiff: diffAB, + }, + { + name: "hunk callback returning false does not apply", + tree: treeA, + diff: diffAB, + applyHunkCallback: func(*DiffHunk) (bool, error) { return false, nil }, + }, + { + name: "hunk callback erroring fails the call", + tree: treeA, + diff: diffAB, + applyHunkCallback: func(*DiffHunk) (bool, error) { return true, errors.New("message dropped") }, + error: &GitError{ + Code: ErrGeneric, + Class: ErrClassInvalid, + }, + }, + { + name: "delta callback returning false does not apply", + tree: treeA, + diff: diffAB, + applyDeltaCallback: func(*DiffDelta) (bool, error) { return false, nil }, + }, + { + name: "delta callback erroring fails the call", + tree: treeA, + diff: diffAB, + applyDeltaCallback: func(*DiffDelta) (bool, error) { return true, errors.New("message dropped") }, + error: &GitError{ + Code: ErrGeneric, + Class: ErrClassInvalid, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + opts, err := DefaultApplyOptions() + checkFatal(t, err) + + opts.ApplyHunkCallback = tc.applyHunkCallback + opts.ApplyDeltaCallback = tc.applyDeltaCallback + + index, err := repo.ApplyToTree(tc.diff, tc.tree, opts) + if tc.error != nil { + if !reflect.DeepEqual(err, tc.error) { + t.Fatalf("expected error %q but got %q", tc.error, err) + } + + return + } + checkFatal(t, err) + + patchedTreeOID, err := index.WriteTreeTo(repo) + checkFatal(t, err) + + patchedTree, err := repo.LookupTree(patchedTreeOID) + checkFatal(t, err) + + patchedDiff, err := repo.DiffTreeToTree(tc.tree, patchedTree, nil) + checkFatal(t, err) + + appliedRaw, err := patchedDiff.ToBuf(DiffFormatPatch) + checkFatal(t, err) + + if tc.expectedDiff == nil { + if len(appliedRaw) > 0 { + t.Fatalf("expected no diff but got: %s", appliedRaw) + } + + return + } + + expectedDiff, err := tc.expectedDiff.ToBuf(DiffFormatPatch) + checkFatal(t, err) + + if string(expectedDiff) != string(appliedRaw) { + t.Fatalf("diffs do not match:\nexpected: %s\n\nactual: %s", expectedDiff, appliedRaw) + } + }) + } +} + // checkSecondFileStaged checks that there is a single file called "file2" uncommitted in the repo func checkSecondFileStaged(t *testing.T, repo *Repository) { opts := StatusOptions{ -- cgit v1.2.3