go-process/program_test.go
Snider 75383c911d feat(ax-10): bring go-process to v0.8.0-alpha.1 + CLI test scaffold
- Migrate module path: dappco.re/go/core/process -> dappco.re/go/process
- Bump dappco.re/go/* deps to v0.8.0-alpha.1 in go.mod (any forge.lthn.ai/core/* paths migrated to canonical dappco.re/go/* form)
- Update Go source imports across 6 .go files

Co-Authored-By: Athena <athena@lthn.ai>
2026-04-24 23:43:57 +01:00

186 lines
4.2 KiB
Go

package process_test
import (
"context"
"errors"
"os/exec"
"path/filepath"
"testing"
"time"
process "dappco.re/go/process"
)
func testCtx(t *testing.T) context.Context {
t.Helper()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
t.Cleanup(cancel)
return ctx
}
func TestProgram_Find_KnownBinary(t *testing.T) {
p := &process.Program{Name: "echo"}
if err := p.Find(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if p.Path == "" {
t.Fatal("expected non-empty path")
}
}
func TestProgram_Find_UnknownBinary(t *testing.T) {
p := &process.Program{Name: "no-such-binary-xyzzy-42"}
err := p.Find()
if err == nil {
t.Fatal("expected error, got nil")
}
if !errors.Is(err, process.ErrProgramNotFound) {
t.Fatalf("expected ErrProgramNotFound, got %v", err)
}
}
func TestProgram_Find_UsesExistingPath(t *testing.T) {
path, err := exec.LookPath("echo")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
p := &process.Program{Path: path}
if err := p.Find(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if p.Path != path {
t.Fatalf("want %v, got %v", path, p.Path)
}
}
func TestProgram_Find_PrefersExistingPathOverName(t *testing.T) {
path, err := exec.LookPath("echo")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
p := &process.Program{
Name: "no-such-binary-xyzzy-42",
Path: path,
}
if err := p.Find(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if p.Path != path {
t.Fatalf("want %v, got %v", path, p.Path)
}
}
func TestProgram_Find_EmptyName(t *testing.T) {
p := &process.Program{}
if err := p.Find(); err == nil {
t.Fatal("expected error, got nil")
}
}
func TestProgram_Run_ReturnsOutput(t *testing.T) {
p := &process.Program{Name: "echo"}
if err := p.Find(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
out, err := p.Run(testCtx(t), "hello")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if out != "hello" {
t.Fatalf("want %q, got %q", "hello", out)
}
}
func TestProgram_Run_PreservesLeadingWhitespace(t *testing.T) {
p := &process.Program{Name: "sh"}
if err := p.Find(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
out, err := p.Run(testCtx(t), "-c", "printf ' hello \n'")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if out != " hello" {
t.Fatalf("want %q, got %q", " hello", out)
}
}
func TestProgram_Run_WithoutFind_FallsBackToName(t *testing.T) {
// Path is empty; RunDir should fall back to Name for OS PATH resolution.
p := &process.Program{Name: "echo"}
out, err := p.Run(testCtx(t), "fallback")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if out != "fallback" {
t.Fatalf("want %q, got %q", "fallback", out)
}
}
func TestProgram_RunDir_UsesDirectory(t *testing.T) {
p := &process.Program{Name: "pwd"}
if err := p.Find(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
dir := t.TempDir()
out, err := p.RunDir(testCtx(t), dir)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Resolve symlinks on both sides for portability (macOS uses /private/ prefix).
canonicalDir, err := filepath.EvalSymlinks(dir)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
canonicalOut, err := filepath.EvalSymlinks(out)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if canonicalDir != canonicalOut {
t.Fatalf("want %q, got %q", canonicalDir, canonicalOut)
}
}
func TestProgram_Run_FailingCommand(t *testing.T) {
p := &process.Program{Name: "false"}
if err := p.Find(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
_, err := p.Run(testCtx(t))
if err == nil {
t.Fatal("expected error, got nil")
}
}
func TestProgram_Run_NilContextRejected(t *testing.T) {
p := &process.Program{Name: "echo"}
_, err := p.Run(nil, "test")
if err == nil {
t.Fatal("expected error, got nil")
}
if !errors.Is(err, process.ErrProgramContextRequired) {
t.Fatalf("expected ErrProgramContextRequired, got %v", err)
}
}
func TestProgram_RunDir_EmptyNameRejected(t *testing.T) {
p := &process.Program{}
_, err := p.RunDir(testCtx(t), "", "test")
if err == nil {
t.Fatal("expected error, got nil")
}
if !errors.Is(err, process.ErrProgramNameRequired) {
t.Fatalf("expected ErrProgramNameRequired, got %v", err)
}
}