package git import ( "fmt" "os" "os/exec" "path/filepath" "runtime" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestOutput(t *testing.T) { tests := []struct { name string exitCode int stdout string stderr string wantErr *GitError }{ { name: "successful command", stdout: "hello world", stderr: "", exitCode: 0, wantErr: nil, }, { name: "not a repo failure", stdout: "", stderr: "fatal: not a git repository (or any of the parent directories): .git", exitCode: 128, wantErr: &GitError{ ExitCode: 128, Stderr: "fatal: not a git repository (or any of the parent directories): .git", err: &exec.ExitError{}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cmd := Command{ &exec.Cmd{ Path: createMockExecutable(t, tt.stdout, tt.stderr, tt.exitCode), }, } out, err := cmd.Output() if tt.wantErr != nil { require.Error(t, err) var gitError *GitError require.ErrorAs(t, err, &gitError) assert.Equal(t, tt.wantErr.ExitCode, gitError.ExitCode) assert.Equal(t, tt.wantErr.Stderr, gitError.Stderr) assert.Equal(t, tt.wantErr.Error(), gitError.Error()) } else { require.NoError(t, err) } assert.Equal(t, tt.stdout, string(out)) }) } } func createMockExecutable(t *testing.T, stdout string, stderr string, exitCode int) string { tmpDir := t.TempDir() sourcePath := filepath.Join(tmpDir, "main.go") binaryPath := filepath.Join(tmpDir, "mockexec") if runtime.GOOS == "windows" { binaryPath += ".exe" } // Create Go source source := buildCommandSourceCode(exitCode, stdout, stderr) // Write source file if err := os.WriteFile(sourcePath, []byte(source), 0600); err != nil { t.Fatal(err) } // Compile cmd := exec.Command("go", "build", "-o", binaryPath, sourcePath) if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("failed to compile: %v\n%s", err, out) } return binaryPath } func buildCommandSourceCode(exitCode int, stdout, stderr string) string { return fmt.Sprintf(`package main import ( "fmt" "os" ) func main() { fmt.Printf(%q) fmt.Fprintf(os.Stderr, %q) os.Exit(%d) }`, stdout, stderr, exitCode) }