170 lines
4.6 KiB
Go
170 lines
4.6 KiB
Go
package agent
|
|
|
|
import (
|
|
"log/slog"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestBuildGeminiArgsBaseline(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
args := buildGeminiArgs("write a haiku", ExecOptions{}, slog.Default())
|
|
expected := []string{
|
|
"-p", "write a haiku",
|
|
"--yolo",
|
|
"-o", "stream-json",
|
|
}
|
|
|
|
if len(args) != len(expected) {
|
|
t.Fatalf("expected %d args, got %d: %v", len(expected), len(args), args)
|
|
}
|
|
for i, want := range expected {
|
|
if args[i] != want {
|
|
t.Fatalf("expected args[%d] = %q, got %q", i, want, args[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuildGeminiArgsWithModel(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
args := buildGeminiArgs("hi", ExecOptions{Model: "gemini-2.5-pro"}, slog.Default())
|
|
|
|
var foundModel bool
|
|
for i, a := range args {
|
|
if a == "-m" {
|
|
if i+1 >= len(args) || args[i+1] != "gemini-2.5-pro" {
|
|
t.Fatalf("expected -m followed by gemini-2.5-pro, got %v", args)
|
|
}
|
|
foundModel = true
|
|
break
|
|
}
|
|
}
|
|
if !foundModel {
|
|
t.Fatalf("expected -m flag when Model is set, got args=%v", args)
|
|
}
|
|
}
|
|
|
|
func TestBuildGeminiArgsWithResume(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
args := buildGeminiArgs("hi", ExecOptions{ResumeSessionID: "3"}, slog.Default())
|
|
|
|
var foundResume bool
|
|
for i, a := range args {
|
|
if a == "-r" {
|
|
if i+1 >= len(args) || args[i+1] != "3" {
|
|
t.Fatalf("expected -r followed by session id, got %v", args)
|
|
}
|
|
foundResume = true
|
|
break
|
|
}
|
|
}
|
|
if !foundResume {
|
|
t.Fatalf("expected -r flag when ResumeSessionID is set, got args=%v", args)
|
|
}
|
|
}
|
|
|
|
func TestBuildGeminiArgsOmitsModelWhenEmpty(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
args := buildGeminiArgs("hi", ExecOptions{}, slog.Default())
|
|
for _, a := range args {
|
|
if a == "-m" {
|
|
t.Fatalf("expected no -m flag when Model is empty, got args=%v", args)
|
|
}
|
|
if a == "-r" {
|
|
t.Fatalf("expected no -r flag when ResumeSessionID is empty, got args=%v", args)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuildGeminiArgsPassesThroughCustomArgs(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
args := buildGeminiArgs("hi", ExecOptions{
|
|
CustomArgs: []string{"--sandbox"},
|
|
}, slog.Default())
|
|
|
|
if args[len(args)-1] != "--sandbox" {
|
|
t.Fatalf("expected --sandbox at end of args, got %v", args)
|
|
}
|
|
}
|
|
|
|
// envLookup returns the value of key in an env slice, or ("", false) if absent.
|
|
// When the key appears multiple times the last occurrence wins, mirroring how
|
|
// libc's getenv resolves duplicates on the daemon's supported platforms — the
|
|
// caller-supplied override therefore takes precedence over our default.
|
|
func envLookup(env []string, key string) (string, bool) {
|
|
prefix := key + "="
|
|
var value string
|
|
var found bool
|
|
for _, entry := range env {
|
|
if strings.HasPrefix(entry, prefix) {
|
|
value = strings.TrimPrefix(entry, prefix)
|
|
found = true
|
|
}
|
|
}
|
|
return value, found
|
|
}
|
|
|
|
func TestBuildGeminiEnvSetsTrustWorkspaceDefault(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
env := buildGeminiEnv(nil)
|
|
got, ok := envLookup(env, "GEMINI_CLI_TRUST_WORKSPACE")
|
|
if !ok {
|
|
t.Fatalf("expected GEMINI_CLI_TRUST_WORKSPACE to be set, got env=%v", env)
|
|
}
|
|
if got != "true" {
|
|
t.Fatalf("expected GEMINI_CLI_TRUST_WORKSPACE=true, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestBuildGeminiEnvRespectsExplicitOverride(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Users who deliberately set the value (e.g. to "false" to opt back into
|
|
// gemini's folder-trust gate, or to a future-proofed value) must win over
|
|
// our daemon default.
|
|
env := buildGeminiEnv(map[string]string{"GEMINI_CLI_TRUST_WORKSPACE": "false"})
|
|
got, ok := envLookup(env, "GEMINI_CLI_TRUST_WORKSPACE")
|
|
if !ok {
|
|
t.Fatalf("expected GEMINI_CLI_TRUST_WORKSPACE to be set, got env=%v", env)
|
|
}
|
|
if got != "false" {
|
|
t.Fatalf("expected caller's GEMINI_CLI_TRUST_WORKSPACE=false to win, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestBuildGeminiEnvPreservesOtherExtras(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
env := buildGeminiEnv(map[string]string{"GEMINI_API_KEY": "secret"})
|
|
if got, ok := envLookup(env, "GEMINI_API_KEY"); !ok || got != "secret" {
|
|
t.Fatalf("expected GEMINI_API_KEY=secret to pass through, got %q (ok=%v)", got, ok)
|
|
}
|
|
if got, ok := envLookup(env, "GEMINI_CLI_TRUST_WORKSPACE"); !ok || got != "true" {
|
|
t.Fatalf("expected default GEMINI_CLI_TRUST_WORKSPACE=true, got %q (ok=%v)", got, ok)
|
|
}
|
|
}
|
|
|
|
func TestBuildGeminiArgsFiltersBlockedCustomArgs(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
args := buildGeminiArgs("hi", ExecOptions{
|
|
CustomArgs: []string{"-o", "text", "--sandbox"},
|
|
}, slog.Default())
|
|
|
|
// -o text should be filtered, --sandbox should pass through
|
|
for i, a := range args {
|
|
if a == "-o" && i+1 < len(args) && args[i+1] == "text" {
|
|
t.Fatalf("blocked -o text should have been filtered: %v", args)
|
|
}
|
|
}
|
|
if args[len(args)-1] != "--sandbox" {
|
|
t.Fatalf("expected --sandbox to pass through, got %v", args)
|
|
}
|
|
}
|