package git import ( "os" "path/filepath" "testing" "git.membo.co.uk/dtomlinson/gitlocal/internal/testutil" ) func TestIsGitRepo(t *testing.T) { tests := []struct { name string setup func(t *testing.T) string expected bool }{ { name: "valid git repo", setup: func(t *testing.T) string { return testutil.CreateTempGitRepo(t) }, expected: true, }, { name: "not a git repo", setup: func(t *testing.T) string { return t.TempDir() }, expected: false, }, { name: "has .gitlocal but not .git", setup: func(t *testing.T) string { dir := t.TempDir() gitLocalDir := filepath.Join(dir, GitLocalDir) if err := os.Mkdir(gitLocalDir, 0755); err != nil { t.Fatalf("failed to create .gitlocal: %v", err) } return dir }, expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { path := tt.setup(t) result := IsGitRepo(path) if result != tt.expected { t.Errorf("expected %v, got %v", tt.expected, result) } }) } } func TestIsGitLocalRepo(t *testing.T) { tests := []struct { name string setup func(t *testing.T) string expected bool }{ { name: "has .gitlocal", setup: func(t *testing.T) string { dir := t.TempDir() gitLocalDir := filepath.Join(dir, GitLocalDir) if err := os.Mkdir(gitLocalDir, 0755); err != nil { t.Fatalf("failed to create .gitlocal: %v", err) } return dir }, expected: true, }, { name: "has .git but not .gitlocal", setup: func(t *testing.T) string { return testutil.CreateTempGitRepo(t) }, expected: false, }, { name: "has neither", setup: func(t *testing.T) string { return t.TempDir() }, expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { path := tt.setup(t) result := IsGitLocalRepo(path) if result != tt.expected { t.Errorf("expected %v, got %v", tt.expected, result) } }) } } func TestGetRemoteURL(t *testing.T) { tests := []struct { name string setup func(t *testing.T) string expected string }{ { name: "repo with remote", setup: func(t *testing.T) string { dir := testutil.CreateTempGitRepoWithRemote(t, "git@github.com:test/repo.git") return filepath.Join(dir, GitDir) }, expected: "git@github.com:test/repo.git", }, { name: "repo without remote", setup: func(t *testing.T) string { dir := testutil.CreateTempGitRepo(t) return filepath.Join(dir, GitDir) }, expected: "", }, { name: "invalid git dir", setup: func(t *testing.T) string { return "/nonexistent/.git" }, expected: "", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gitDir := tt.setup(t) result := GetRemoteURL(gitDir) if result != tt.expected { t.Errorf("expected %q, got %q", tt.expected, result) } }) } } func TestGetCurrentBranch(t *testing.T) { tests := []struct { name string setup func(t *testing.T) string expected string }{ { name: "default branch (master or main)", setup: func(t *testing.T) string { dir := testutil.CreateTempGitRepo(t) return filepath.Join(dir, GitDir) }, // Git might use master or main depending on config expected: "", // We'll check it's non-empty instead }, { name: "custom branch", setup: func(t *testing.T) string { dir := testutil.CreateTempGitRepoWithBranch(t, "develop") return filepath.Join(dir, GitDir) }, expected: "develop", }, { name: "invalid git dir", setup: func(t *testing.T) string { return "/nonexistent/.git" }, expected: "", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gitDir := tt.setup(t) result := GetCurrentBranch(gitDir) if tt.name == "default branch (master or main)" { // Just check it returned something if result == "" { t.Errorf("expected non-empty branch name, got empty string") } } else if result != tt.expected { t.Errorf("expected %q, got %q", tt.expected, result) } }) } } func TestConvert(t *testing.T) { tests := []struct { name string setup func(t *testing.T) string expectErr bool }{ { name: "valid git repo", setup: func(t *testing.T) string { return testutil.CreateTempGitRepo(t) }, expectErr: false, }, { name: "no .git directory", setup: func(t *testing.T) string { return t.TempDir() }, expectErr: true, }, { name: ".gitlocal already exists", setup: func(t *testing.T) string { dir := testutil.CreateTempGitRepo(t) gitLocalDir := filepath.Join(dir, GitLocalDir) if err := os.Mkdir(gitLocalDir, 0755); err != nil { t.Fatalf("failed to create .gitlocal: %v", err) } return dir }, expectErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { path := tt.setup(t) err := Convert(path) if tt.expectErr && err == nil { t.Errorf("expected error, got nil") } if !tt.expectErr && err != nil { t.Errorf("expected no error, got %v", err) } if !tt.expectErr { // Verify .git was renamed to .gitlocal gitPath := filepath.Join(path, GitDir) gitLocalPath := filepath.Join(path, GitLocalDir) if _, err := os.Stat(gitPath); !os.IsNotExist(err) { t.Errorf(".git directory still exists") } if _, err := os.Stat(gitLocalPath); os.IsNotExist(err) { t.Errorf(".gitlocal directory does not exist") } } }) } } func TestRevert(t *testing.T) { tests := []struct { name string setup func(t *testing.T) string expectErr bool }{ { name: "valid .gitlocal directory", setup: func(t *testing.T) string { dir := testutil.CreateTempGitRepo(t) // Convert to .gitlocal if err := Convert(dir); err != nil { t.Fatalf("failed to convert: %v", err) } return dir }, expectErr: false, }, { name: "no .gitlocal directory", setup: func(t *testing.T) string { return t.TempDir() }, expectErr: true, }, { name: ".git already exists", setup: func(t *testing.T) string { dir := testutil.CreateTempGitRepo(t) gitLocalDir := filepath.Join(dir, GitLocalDir) if err := os.Mkdir(gitLocalDir, 0755); err != nil { t.Fatalf("failed to create .gitlocal: %v", err) } return dir }, expectErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { path := tt.setup(t) err := Revert(path) if tt.expectErr && err == nil { t.Errorf("expected error, got nil") } if !tt.expectErr && err != nil { t.Errorf("expected no error, got %v", err) } if !tt.expectErr { // Verify .gitlocal was renamed to .git gitPath := filepath.Join(path, GitDir) gitLocalPath := filepath.Join(path, GitLocalDir) if _, err := os.Stat(gitLocalPath); !os.IsNotExist(err) { t.Errorf(".gitlocal directory still exists") } if _, err := os.Stat(gitPath); os.IsNotExist(err) { t.Errorf(".git directory does not exist") } } }) } } func TestConvertRevertRoundTrip(t *testing.T) { dir := testutil.CreateTempGitRepoWithRemote(t, "git@github.com:test/repo.git") // Initial state - should have .git if !IsGitRepo(dir) { t.Fatal("expected .git to exist initially") } // Convert if err := Convert(dir); err != nil { t.Fatalf("convert failed: %v", err) } // Should have .gitlocal, not .git if IsGitRepo(dir) { t.Error("expected .git to be gone after convert") } if !IsGitLocalRepo(dir) { t.Error("expected .gitlocal to exist after convert") } // Remote should still be accessible via .gitlocal gitLocalPath := filepath.Join(dir, GitLocalDir) remote := GetRemoteURL(gitLocalPath) if remote != "git@github.com:test/repo.git" { t.Errorf("expected remote to be preserved, got %q", remote) } // Revert if err := Revert(dir); err != nil { t.Fatalf("revert failed: %v", err) } // Should have .git again, not .gitlocal if !IsGitRepo(dir) { t.Error("expected .git to exist after revert") } if IsGitLocalRepo(dir) { t.Error("expected .gitlocal to be gone after revert") } // Remote should still be accessible gitPath := filepath.Join(dir, GitDir) remote = GetRemoteURL(gitPath) if remote != "git@github.com:test/repo.git" { t.Errorf("expected remote to be preserved after round trip, got %q", remote) } }