173 lines
5.2 KiB
Go
173 lines
5.2 KiB
Go
package gitcmd
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func buildFFRepo(t *testing.T) (repo *Repository, c2 string) {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
work := filepath.Join(dir, "work")
|
|
bare := filepath.Join(dir, "bare.git")
|
|
gitRun(t, "", nil, "init", "-q", "-b", "main", work)
|
|
writeFile(t, filepath.Join(work, "a.txt"), "a\n")
|
|
commitAs(t, work, "A", "a@x", "2024-03-01T00:00:00+00:00", "c1")
|
|
gitRun(t, work, nil, "branch", "feature")
|
|
gitRun(t, work, nil, "checkout", "-q", "feature")
|
|
writeFile(t, filepath.Join(work, "b.txt"), "b\n")
|
|
commitAs(t, work, "A", "a@x", "2024-03-02T00:00:00+00:00", "c2")
|
|
c2 = headSHA(t, work)
|
|
return cloneBareFromWork(t, work, bare), c2
|
|
}
|
|
|
|
func buildConflictRepo(t *testing.T) *Repository {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
work := filepath.Join(dir, "work")
|
|
bare := filepath.Join(dir, "bare.git")
|
|
gitRun(t, "", nil, "init", "-q", "-b", "main", work)
|
|
writeFile(t, filepath.Join(work, "f.txt"), "base\n")
|
|
commitAs(t, work, "A", "a@x", "2024-04-01T00:00:00+00:00", "c1")
|
|
gitRun(t, work, nil, "branch", "feature")
|
|
writeFile(t, filepath.Join(work, "f.txt"), "main\n")
|
|
commitAs(t, work, "A", "a@x", "2024-04-02T00:00:00+00:00", "c2main")
|
|
gitRun(t, work, nil, "checkout", "-q", "feature")
|
|
writeFile(t, filepath.Join(work, "f.txt"), "feature\n")
|
|
commitAs(t, work, "A", "a@x", "2024-04-03T00:00:00+00:00", "c3feat")
|
|
gitRun(t, work, nil, "checkout", "-q", "main")
|
|
return cloneBareFromWork(t, work, bare)
|
|
}
|
|
|
|
func TestMerge_Clean(t *testing.T) {
|
|
f := newMergeFixture(t)
|
|
res, err := f.repo.Merge("main", "feature", "merge feature", wAuthor, wAuthorEmail, false)
|
|
if err != nil {
|
|
t.Fatalf("Merge: %v", err)
|
|
}
|
|
if len(res.Conflicts) != 0 {
|
|
t.Errorf("conflicts = %v, want none", res.Conflicts)
|
|
}
|
|
if res.MergeCommit == nil {
|
|
t.Fatal("nil merge commit")
|
|
}
|
|
if res.FastForward {
|
|
t.Error("want real merge, got FF")
|
|
}
|
|
if len(res.MergeCommit.Parents) != 2 {
|
|
t.Errorf("parents = %v, want 2", res.MergeCommit.Parents)
|
|
}
|
|
tree, _ := f.repo.GetTree(res.MergeCommit.ID, "")
|
|
names := treeNames(tree)
|
|
for _, want := range []string{"a.txt", "b.txt", "c.txt"} {
|
|
if !containsStr(names, want) {
|
|
t.Errorf("merged tree missing %s; got %v", want, names)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMerge_FastForward(t *testing.T) {
|
|
repo, c2 := buildFFRepo(t)
|
|
res, err := repo.Merge("main", "feature", "ff", wAuthor, wAuthorEmail, false)
|
|
if err != nil {
|
|
t.Fatalf("Merge: %v", err)
|
|
}
|
|
if !res.FastForward {
|
|
t.Error("want FF")
|
|
}
|
|
if res.MergeCommit == nil || res.MergeCommit.ID != c2 {
|
|
t.Errorf("merge commit = %v, want %s", res.MergeCommit, c2)
|
|
}
|
|
tip, _ := repo.refSHA("refs/heads/main")
|
|
if tip != c2 {
|
|
t.Errorf("main tip = %s, want %s", tip, c2)
|
|
}
|
|
}
|
|
|
|
func TestMerge_Conflict(t *testing.T) {
|
|
repo := buildConflictRepo(t)
|
|
mainBefore, _ := repo.refSHA("refs/heads/main")
|
|
res, err := repo.Merge("main", "feature", "merge", wAuthor, wAuthorEmail, false)
|
|
if err != nil {
|
|
t.Fatalf("Merge: %v", err)
|
|
}
|
|
if res.MergeCommit != nil {
|
|
t.Error("want nil merge commit on conflict")
|
|
}
|
|
if len(res.Conflicts) == 0 {
|
|
t.Error("want conflicts")
|
|
} else if !containsStr(res.Conflicts, "f.txt") {
|
|
t.Errorf("conflicts = %v, want f.txt", res.Conflicts)
|
|
}
|
|
mainAfter, _ := repo.refSHA("refs/heads/main")
|
|
if mainAfter != mainBefore {
|
|
t.Errorf("main moved on conflict: %s -> %s", mainBefore, mainAfter)
|
|
}
|
|
}
|
|
|
|
func TestMergeViaTempRepo_Clean(t *testing.T) {
|
|
f := newMergeFixture(t)
|
|
res, err := f.repo.MergeViaTempRepo("main", "feature", "merge feature", wAuthor, wAuthorEmail, false)
|
|
if err != nil {
|
|
t.Fatalf("MergeViaTempRepo: %v", err)
|
|
}
|
|
if len(res.Conflicts) != 0 {
|
|
t.Errorf("conflicts = %v, want none", res.Conflicts)
|
|
}
|
|
if res.MergeCommit == nil {
|
|
t.Fatal("nil merge commit")
|
|
}
|
|
if res.FastForward {
|
|
t.Error("want real merge, got FF")
|
|
}
|
|
if len(res.MergeCommit.Parents) != 2 {
|
|
t.Errorf("parents = %v, want 2", res.MergeCommit.Parents)
|
|
}
|
|
tree, _ := f.repo.GetTree(res.MergeCommit.ID, "")
|
|
names := treeNames(tree)
|
|
for _, want := range []string{"a.txt", "b.txt", "c.txt"} {
|
|
if !containsStr(names, want) {
|
|
t.Errorf("merged tree missing %s; got %v", want, names)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMergeViaTempRepo_FastForward(t *testing.T) {
|
|
repo, c2 := buildFFRepo(t)
|
|
res, err := repo.MergeViaTempRepo("main", "feature", "ff", wAuthor, wAuthorEmail, false)
|
|
if err != nil {
|
|
t.Fatalf("MergeViaTempRepo: %v", err)
|
|
}
|
|
if !res.FastForward {
|
|
t.Error("want FF")
|
|
}
|
|
if res.MergeCommit == nil || res.MergeCommit.ID != c2 {
|
|
t.Errorf("merge commit = %v, want %s", res.MergeCommit, c2)
|
|
}
|
|
tip, _ := repo.refSHA("refs/heads/main")
|
|
if tip != c2 {
|
|
t.Errorf("main tip = %s, want %s", tip, c2)
|
|
}
|
|
}
|
|
|
|
func TestMergeViaTempRepo_Conflict(t *testing.T) {
|
|
repo := buildConflictRepo(t)
|
|
mainBefore, _ := repo.refSHA("refs/heads/main")
|
|
res, err := repo.MergeViaTempRepo("main", "feature", "merge", wAuthor, wAuthorEmail, false)
|
|
if err != nil {
|
|
t.Fatalf("MergeViaTempRepo: %v", err)
|
|
}
|
|
if res.MergeCommit != nil {
|
|
t.Error("want nil merge commit on conflict")
|
|
}
|
|
if len(res.Conflicts) == 0 {
|
|
t.Error("want conflicts")
|
|
} else if !containsStr(res.Conflicts, "f.txt") {
|
|
t.Errorf("conflicts = %v, want f.txt", res.Conflicts)
|
|
}
|
|
mainAfter, _ := repo.refSHA("refs/heads/main")
|
|
if mainAfter != mainBefore {
|
|
t.Errorf("main moved on conflict: %s -> %s", mainBefore, mainAfter)
|
|
}
|
|
}
|