149 lines
3.7 KiB
Go
149 lines
3.7 KiB
Go
package git_test
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"superwork-tui/internal/git"
|
|
)
|
|
|
|
// initTestRepo creates a temporary git repo with one commit on the default branch.
|
|
func initTestRepo(t *testing.T) string {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
run := func(args ...string) {
|
|
t.Helper()
|
|
cmd := exec.Command("git", args...)
|
|
cmd.Dir = dir
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("git %v: %v\n%s", args, err, out)
|
|
}
|
|
}
|
|
run("init")
|
|
run("config", "user.email", "test@test.com")
|
|
run("config", "user.name", "test")
|
|
f := filepath.Join(dir, "file.txt")
|
|
if err := os.WriteFile(f, []byte("hello"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
run("add", ".")
|
|
run("commit", "-m", "init")
|
|
return dir
|
|
}
|
|
|
|
func TestHasChanges_Clean(t *testing.T) {
|
|
dir := initTestRepo(t)
|
|
has, err := git.HasChanges(context.Background(), dir)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if has {
|
|
t.Error("expected no changes on clean repo")
|
|
}
|
|
}
|
|
|
|
func TestHasChanges_Dirty(t *testing.T) {
|
|
dir := initTestRepo(t)
|
|
f := filepath.Join(dir, "new.txt")
|
|
if err := os.WriteFile(f, []byte("dirty"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
has, err := git.HasChanges(context.Background(), dir)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if !has {
|
|
t.Error("expected changes with untracked file")
|
|
}
|
|
}
|
|
|
|
func TestMergePreview_Clean(t *testing.T) {
|
|
dir := initTestRepo(t)
|
|
run := func(args ...string) {
|
|
t.Helper()
|
|
cmd := exec.Command("git", args...)
|
|
cmd.Dir = dir
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("git %v: %v\n%s", args, err, out)
|
|
}
|
|
}
|
|
// Create a branch with a non-conflicting new file.
|
|
run("checkout", "-b", "feature")
|
|
f := filepath.Join(dir, "feature.txt")
|
|
if err := os.WriteFile(f, []byte("feature"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
run("add", ".")
|
|
run("commit", "-m", "feature commit")
|
|
// Return to the original branch via checkout -.
|
|
run("checkout", "-")
|
|
|
|
result, err := git.MergePreview(context.Background(), git.MergePreviewOpts{
|
|
WorkspaceRoot: dir,
|
|
Branch: "feature",
|
|
})
|
|
// A fast-forward-prevented merge that succeeds may leave MERGE_HEAD; abort to clean up.
|
|
defer func() {
|
|
cmd := exec.Command("git", "-C", dir, "merge", "--abort")
|
|
_ = cmd.Run()
|
|
}()
|
|
|
|
if err != nil {
|
|
t.Fatalf("expected clean merge, got error: %v (output: %s)", err, result.Output)
|
|
}
|
|
if !result.Clean {
|
|
t.Errorf("expected Clean=true, got false; conflicts: %v", result.Conflicts)
|
|
}
|
|
}
|
|
|
|
func TestMergePreview_Conflict(t *testing.T) {
|
|
dir := initTestRepo(t)
|
|
run := func(args ...string) {
|
|
t.Helper()
|
|
cmd := exec.Command("git", args...)
|
|
cmd.Dir = dir
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("git %v: %v\n%s", args, err, out)
|
|
}
|
|
}
|
|
// Create a branch that modifies file.txt.
|
|
run("checkout", "-b", "conflict-branch")
|
|
f := filepath.Join(dir, "file.txt")
|
|
if err := os.WriteFile(f, []byte("branch change"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
run("add", ".")
|
|
run("commit", "-m", "branch change")
|
|
|
|
// Return to original branch and make a conflicting change to the same file.
|
|
run("checkout", "-")
|
|
if err := os.WriteFile(f, []byte("main change"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
run("add", ".")
|
|
run("commit", "-m", "main change")
|
|
|
|
result, _ := git.MergePreview(context.Background(), git.MergePreviewOpts{
|
|
WorkspaceRoot: dir,
|
|
Branch: "conflict-branch",
|
|
})
|
|
// Abort the in-progress merge to leave repo clean for test teardown.
|
|
defer func() {
|
|
cmd := exec.Command("git", "-C", dir, "merge", "--abort")
|
|
_ = cmd.Run()
|
|
}()
|
|
|
|
if result.Clean {
|
|
t.Error("expected Clean=false for conflicting merge")
|
|
}
|
|
if len(result.Conflicts) == 0 {
|
|
t.Errorf("expected at least one conflict entry, got none; output: %s", result.Output)
|
|
}
|
|
}
|