From 6a5cad5700b0d0b6c16e05e6654f194183e129d8 Mon Sep 17 00:00:00 2001 From: Enmanuel Date: Sun, 8 Mar 2026 11:47:07 +0000 Subject: [PATCH] test: extraer resolveWorkDir y tests unitarios de aislamiento MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extraer la logica de resolucion de working_dir a una funcion resolveWorkDir() separada para hacerla testeable. Tres tests cubren: - WorkingDir vacio → crea tmpdir con prefijo claude-agent-* - WorkingDir configurado → crea el directorio y lo usa - WorkingDir ya existente → lo usa sin error Co-Authored-By: Claude Opus 4.6 --- shell/llm/claudecode.go | 42 ++++++++++++++++------------ shell/llm/claudecode_test.go | 53 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 18 deletions(-) diff --git a/shell/llm/claudecode.go b/shell/llm/claudecode.go index 95c7e87..50d8217 100644 --- a/shell/llm/claudecode.go +++ b/shell/llm/claudecode.go @@ -59,24 +59,7 @@ func NewClaudeCodeComplete(cfg config.ClaudeCodeCfg, log *slog.Logger) coretypes } // Resolve working directory once at init time. - workDir := cfg.WorkingDir - if workDir == "" { - tmp, err := os.MkdirTemp("", "claude-agent-*") - if err != nil { - log.Error("claude-code: failed to create temp working dir", "err", err) - // Fall through — cmd.Dir will remain empty (inherits CWD). - } else { - workDir = tmp - log.Warn("claude-code working_dir is empty, using temporary directory", - "dir", workDir, - ) - } - } else { - // Ensure configured directory exists. - if err := os.MkdirAll(workDir, 0o755); err != nil { - log.Error("claude-code: failed to create working dir", "dir", workDir, "err", err) - } - } + workDir := resolveWorkDir(cfg.WorkingDir, log) return func(ctx context.Context, req coretypes.CompletionRequest) (coretypes.CompletionResponse, error) { ctx, cancel := context.WithTimeout(ctx, timeout) @@ -141,6 +124,29 @@ func NewClaudeCodeComplete(cfg config.ClaudeCodeCfg, log *slog.Logger) coretypes } } +// resolveWorkDir determines the working directory for the claude subprocess. +// If configured is empty, it creates a temporary directory to avoid inheriting the launcher's CWD. +// If configured is non-empty, it ensures the directory exists. +func resolveWorkDir(configured string, log *slog.Logger) string { + if configured == "" { + tmp, err := os.MkdirTemp("", "claude-agent-*") + if err != nil { + log.Error("claude-code: failed to create temp working dir", "err", err) + return "" // Fall through — cmd.Dir will remain empty (inherits CWD). + } + log.Warn("claude-code working_dir is empty, using temporary directory", + "dir", tmp, + ) + return tmp + } + + // Ensure configured directory exists. + if err := os.MkdirAll(configured, 0o755); err != nil { + log.Error("claude-code: failed to create working dir", "dir", configured, "err", err) + } + return configured +} + // buildClaudeArgs constructs the CLI arguments for claude -p. func buildClaudeArgs(cfg config.ClaudeCodeCfg, req coretypes.CompletionRequest) []string { args := []string{"--print", "--output-format", "json"} diff --git a/shell/llm/claudecode_test.go b/shell/llm/claudecode_test.go index a8d414d..07c87d0 100644 --- a/shell/llm/claudecode_test.go +++ b/shell/llm/claudecode_test.go @@ -5,6 +5,9 @@ import ( "errors" "io" "log/slog" + "os" + "path/filepath" + "strings" "testing" "time" @@ -318,6 +321,56 @@ func TestFilterEnv_PrefixSafety(t *testing.T) { } } +// ── resolveWorkDir ────────────────────────────────────────────────────── + +func TestResolveWorkDir_EmptyCreatesTempDir(t *testing.T) { + dir := resolveWorkDir("", discardLog) + if dir == "" { + t.Fatal("expected a temp directory, got empty string") + } + defer os.RemoveAll(dir) + + if !strings.Contains(dir, "claude-agent-") { + t.Errorf("temp dir %q should contain 'claude-agent-' prefix", dir) + } + + info, err := os.Stat(dir) + if err != nil { + t.Fatalf("temp dir should exist: %v", err) + } + if !info.IsDir() { + t.Error("temp dir should be a directory") + } +} + +func TestResolveWorkDir_ConfiguredValueUsed(t *testing.T) { + want := filepath.Join(t.TempDir(), "custom-workdir") + + got := resolveWorkDir(want, discardLog) + + if got != want { + t.Errorf("got %q, want %q", got, want) + } + + info, err := os.Stat(got) + if err != nil { + t.Fatalf("configured dir should be created: %v", err) + } + if !info.IsDir() { + t.Error("configured dir should be a directory") + } +} + +func TestResolveWorkDir_ConfiguredAlreadyExists(t *testing.T) { + want := t.TempDir() // already exists + + got := resolveWorkDir(want, discardLog) + + if got != want { + t.Errorf("got %q, want %q", got, want) + } +} + // ── helpers ────────────────────────────────────────────────────────────── func contains(s, substr string) bool {