package tools import ( "context" "encoding/json" "errors" "os" "path/filepath" "strings" "testing" "[[.SDKModule]]/pluginsdk" ) // fakeHost answers host.files.* for files inside dir, like Cletus does for // the folder the user opened. func fakeHost(dir string, canWrite bool) *pluginsdk.Host { return pluginsdk.NewTestHost(func(method string, params json.RawMessage) (any, error) { var p struct{ Path string } _ = json.Unmarshal(params, &p) path := p.Path if !filepath.IsAbs(path) { path = filepath.Join(dir, path) } switch method { case "host.files.resolve": if _, err := os.Stat(path); err != nil { return nil, errors.New(p.Path + " does not exist") } return path, nil case "host.files.can_write": return canWrite, nil } return nil, errors.New("unexpected host call " + method) }) } func run(t *testing.T, tool pluginsdk.Tool, h *pluginsdk.Host, args string, edit bool) pluginsdk.ToolResult { t.Helper() return tool.Run(context.Background(), h, pluginsdk.ToolCall{Args: json.RawMessage(args), EditMode: edit}) } func TestCountLines(t *testing.T) { dir := t.TempDir() if err := os.WriteFile(filepath.Join(dir, "a.txt"), []byte("one\ntwo\nthree"), 0o644); err != nil { t.Fatal(err) } got := run(t, countLines, fakeHost(dir, false), `{"path":"a.txt"}`, false) if got.Error != "" || !strings.Contains(got.Text, "3 lines") { t.Fatalf("got %+v", got) } if got := run(t, countLines, fakeHost(dir, false), `{"path":"missing.txt"}`, false); got.Error == "" { t.Fatal("a missing file should fail") } } func TestSaveSummaryNeedsEdits(t *testing.T) { dir := t.TempDir() if err := os.WriteFile(filepath.Join(dir, "a.txt"), []byte("one\n"), 0o644); err != nil { t.Fatal(err) } if got := run(t, saveSummary, fakeHost(dir, false), `{"path":"a.txt"}`, false); got.Error == "" { t.Fatal("saving without edits allowed should fail") } got := run(t, saveSummary, fakeHost(dir, true), `{"path":"a.txt"}`, true) if got.Error != "" { t.Fatalf("got %+v", got) } data, err := os.ReadFile(filepath.Join(dir, "a.txt.summary.txt")) if err != nil || string(data) != "1 lines\n" { t.Fatalf("summary = %q, %v", data, err) } }