diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-22 09:39:01 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-22 09:39:01 +0200 |
| commit | 66d824193dc63eeea5f59bc86238f5f6106ae02b (patch) | |
| tree | c79e5020ee638646abef2ed1975abc79883af7bb /internal/git/git_test.go | |
| parent | d3702993f2111e2e6e7c2702b12f10095b2b3519 (diff) | |
Implement git package (task 355)
Diffstat (limited to 'internal/git/git_test.go')
| -rw-r--r-- | internal/git/git_test.go | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/internal/git/git_test.go b/internal/git/git_test.go new file mode 100644 index 0000000..1fb531c --- /dev/null +++ b/internal/git/git_test.go @@ -0,0 +1,200 @@ +package git_test + +import ( + "context" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "codeberg.org/snonux/geheim/internal/git" +) + +// initRepo creates a temporary git repository with a minimal config so that +// git commit works without requiring the user's global identity to be set. +func initRepo(t *testing.T) string { + t.Helper() + dir := t.TempDir() + + for _, args := range [][]string{ + {"git", "init", dir}, + {"git", "-C", dir, "config", "user.email", "test@geheim.test"}, + {"git", "-C", dir, "config", "user.name", "Geheim Test"}, + } { + out, err := exec.Command(args[0], args[1:]...).CombinedOutput() + if err != nil { + t.Fatalf("setup %v: %v\n%s", args, err, out) + } + } + + return dir +} + +// writeFile creates a file with the given content inside dir. +func writeFile(t *testing.T, dir, name, content string) string { + t.Helper() + path := filepath.Join(dir, name) + if err := os.WriteFile(path, []byte(content), 0o600); err != nil { + t.Fatalf("writeFile %s: %v", path, err) + } + return path +} + +// gitOutput runs a raw git command in dir and returns trimmed stdout+stderr. +func gitOutput(t *testing.T, dir string, args ...string) string { + t.Helper() + args = append([]string{"-C", dir}, args...) + out, err := exec.Command("git", args...).CombinedOutput() + if err != nil { + t.Fatalf("git %v: %v\n%s", args, err, out) + } + return strings.TrimSpace(string(out)) +} + +// commitAll stages everything in dir and creates a commit so subsequent +// operations have a baseline history to work against. +func commitAll(t *testing.T, dir, msg string) { + t.Helper() + for _, args := range [][]string{ + {"git", "-C", dir, "add", "."}, + {"git", "-C", dir, "commit", "-m", msg}, + } { + out, err := exec.Command(args[0], args[1:]...).CombinedOutput() + if err != nil { + t.Fatalf("commitAll %v: %v\n%s", args, err, out) + } + } +} + +// TestAdd verifies that Add stages a file so git status reports it as a new file. +func TestAdd(t *testing.T) { + dir := initRepo(t) + g := git.New(dir) + ctx := context.Background() + + path := writeFile(t, dir, "secret.age", "encrypted data") + + if err := g.Add(ctx, path); err != nil { + t.Fatalf("Add: %v", err) + } + + status := gitOutput(t, dir, "status", "--short") + if !strings.Contains(status, "A secret.age") { + t.Errorf("expected 'A secret.age' in status, got: %q", status) + } +} + +// TestRemove verifies that Remove stages a file deletion (git rm) so the file +// disappears from the index after a committed baseline. +func TestRemove(t *testing.T) { + dir := initRepo(t) + g := git.New(dir) + ctx := context.Background() + + path := writeFile(t, dir, "secret.age", "encrypted data") + commitAll(t, dir, "initial commit") + + if err := g.Remove(ctx, path); err != nil { + t.Fatalf("Remove: %v", err) + } + + status := gitOutput(t, dir, "status", "--short") + if !strings.Contains(status, "D secret.age") { + t.Errorf("expected 'D secret.age' in status, got: %q", status) + } +} + +// TestCommit verifies that Commit records changes with the hardcoded message. +func TestCommit(t *testing.T) { + dir := initRepo(t) + g := git.New(dir) + ctx := context.Background() + + writeFile(t, dir, "secret.age", "encrypted data") + // Stage the file so there is something to commit. + if out, err := exec.Command("git", "-C", dir, "add", ".").CombinedOutput(); err != nil { + t.Fatalf("git add: %v\n%s", err, out) + } + + if err := g.Commit(ctx); err != nil { + t.Fatalf("Commit: %v", err) + } + + log := gitOutput(t, dir, "log", "--oneline", "-1") + const want = "Changing stuff, not telling what in commit history" + if !strings.Contains(log, want) { + t.Errorf("expected commit message %q in log, got: %q", want, log) + } +} + +// TestStatus verifies that Status runs without error on a clean repository. +func TestStatus(t *testing.T) { + dir := initRepo(t) + g := git.New(dir) + ctx := context.Background() + + if err := g.Status(ctx); err != nil { + t.Fatalf("Status: %v", err) + } +} + +// TestReset verifies that Reset discards uncommitted working-tree changes. +func TestReset(t *testing.T) { + dir := initRepo(t) + g := git.New(dir) + ctx := context.Background() + + path := writeFile(t, dir, "secret.age", "original") + commitAll(t, dir, "initial commit") + + // Overwrite the file so there is a dirty working tree. + if err := os.WriteFile(path, []byte("modified"), 0o600); err != nil { + t.Fatalf("overwrite: %v", err) + } + + if err := g.Reset(ctx); err != nil { + t.Fatalf("Reset: %v", err) + } + + got, err := os.ReadFile(path) + if err != nil { + t.Fatalf("ReadFile after Reset: %v", err) + } + if string(got) != "original" { + t.Errorf("expected file content 'original' after reset, got: %q", got) + } +} + +// TestAdd_nonexistent_file verifies that Add returns an error when the target +// file does not exist, because git add will fail. +func TestAdd_nonexistent_file(t *testing.T) { + dir := initRepo(t) + g := git.New(dir) + ctx := context.Background() + + err := g.Add(ctx, filepath.Join(dir, "does-not-exist.age")) + if err == nil { + t.Fatal("expected error when adding a nonexistent file, got nil") + } +} + +// TestCommit_nothing_to_commit verifies that Commit returns an error (exit 1 +// from git) when there is nothing staged, rather than panicking or crashing. +// Callers are expected to guard against this case, but the package must not hide +// the error entirely. +func TestCommit_nothing_to_commit(t *testing.T) { + dir := initRepo(t) + g := git.New(dir) + ctx := context.Background() + + // Create and commit a file so HEAD exists; index is now clean. + writeFile(t, dir, "secret.age", "data") + commitAll(t, dir, "initial commit") + + // Nothing staged — git commit should exit non-zero. + err := g.Commit(ctx) + if err == nil { + t.Fatal("expected error when committing with nothing to commit, got nil") + } +} |
