summaryrefslogtreecommitdiff
path: root/internal/git/git_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/git/git_test.go')
-rw-r--r--internal/git/git_test.go200
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")
+ }
+}