package handlers_test import ( "context" "encoding/json" "os" "path/filepath" "testing" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/yan1h/agent-coding-workflow/internal/acp/handlers" ) func TestFsRead_HappyPath(t *testing.T) { t.Parallel() tmp := t.TempDir() require.NoError(t, os.WriteFile(filepath.Join(tmp, "a.txt"), []byte("hello\n"), 0o644)) h := handlers.NewFsReadHandler() sess := handlers.SessionContext{SessionID: uuid.New(), CwdPath: tmp} params := mustJSON(t, map[string]any{"sessionId": "x", "path": filepath.Join(tmp, "a.txt")}) res := h.Handle(context.Background(), sess, params) require.Nil(t, res.Err) require.NotNil(t, res.OK) var out struct { Content string `json:"content"` } require.NoError(t, json.Unmarshal(res.OK, &out)) assert.Equal(t, "hello\n", out.Content) } func TestFsRead_PathOutsideWorktree(t *testing.T) { t.Parallel() tmp := t.TempDir() h := handlers.NewFsReadHandler() sess := handlers.SessionContext{CwdPath: tmp} outside := filepath.Join(filepath.VolumeName(tmp)+string(filepath.Separator), "etc", "passwd") params := mustJSON(t, map[string]any{"sessionId": "x", "path": outside}) res := h.Handle(context.Background(), sess, params) require.NotNil(t, res.Err) assert.Equal(t, -32001, res.Err.Code) } func TestFsRead_FileNotFound(t *testing.T) { t.Parallel() tmp := t.TempDir() h := handlers.NewFsReadHandler() sess := handlers.SessionContext{CwdPath: tmp} params := mustJSON(t, map[string]any{"sessionId": "x", "path": filepath.Join(tmp, "nope.txt")}) res := h.Handle(context.Background(), sess, params) require.NotNil(t, res.Err) assert.Equal(t, -32603, res.Err.Code) } func TestFsRead_LineLimit(t *testing.T) { t.Parallel() tmp := t.TempDir() require.NoError(t, os.WriteFile(filepath.Join(tmp, "f.txt"), []byte("L0\nL1\nL2\nL3\n"), 0o644)) h := handlers.NewFsReadHandler() sess := handlers.SessionContext{CwdPath: tmp} line := 1 limit := 2 params := mustJSON(t, map[string]any{ "sessionId": "x", "path": filepath.Join(tmp, "f.txt"), "line": line, "limit": limit, }) res := h.Handle(context.Background(), sess, params) require.Nil(t, res.Err) var out struct { Content string `json:"content"` } _ = json.Unmarshal(res.OK, &out) assert.Equal(t, "L1\nL2", out.Content) } func mustJSON(t *testing.T, v any) json.RawMessage { t.Helper() b, err := json.Marshal(v) require.NoError(t, err) return b }