package main import ( "encoding/json" "net/http" "path/filepath" "testing" "github.com/stretchr/testify/require" ) func TestImageShowUsesStoredImageForTelegramAndTerminal(t *testing.T) { picture := imageTestPNG(t, 5, 4) store := &ImageStore{dir: filepath.Join(t.TempDir(), imageDirName)} name, err := store.Save(picture) require.NoError(t, err) telegram := newTelegramFake(t) bot, logs := telegramStartTestBot(t, telegram) box := &Toolbox{imageShow: &ImageShow{ store: store, bot: bot, }} args, err := json.Marshal(ToolImageShowArguments{ Image: name, Caption: "A red point.", }) require.NoError(t, err) output := box.run(t.Context(), "image_show", string(args)) require.Equal(t, imageText([]string{name}, "A red point.")+"\n"+filepath.Join(store.dir, name), output) calls := telegram.Calls() require.Len(t, calls, 1) require.Equal(t, "sendPhoto", calls[0].method) require.Equal(t, "4242", calls[0].params["chat_id"]) require.Equal(t, "A red point.", calls[0].params["caption"]) require.Equal(t, name, calls[0].params["photo_name"]) require.Equal(t, picture, calls[0].params["photo"]) require.Empty(t, logs.String()) } func TestImageShowRefusesUnknownNamesBeforeSending(t *testing.T) { telegram := newTelegramFake(t) bot, _ := telegramStartTestBot(t, telegram) show := &ImageShow{ store: &ImageStore{dir: t.TempDir()}, bot: bot, } for _, name := range []string{"../image.png", "unknown", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.png"} { _, err := show.Show(t.Context(), name, "Do not send this.") require.Error(t, err) } require.Empty(t, telegram.Calls()) box := &Toolbox{} require.Equal(t, `error: unknown tool "image_show"`, box.run(t.Context(), "image_show", `{"image":"unknown","caption":""}`)) } func TestImageShowFallsBackOnlyWhenTelegramRefusesPhoto(t *testing.T) { testCases := []struct { name string status int methods []string failure bool }{ { name: "refused photo sends document", status: http.StatusBadRequest, methods: []string{"sendPhoto", "sendDocument"}, }, { name: "uncertain server error does not send twice", status: http.StatusBadGateway, methods: []string{"sendPhoto"}, failure: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { telegram := newTelegramFake(t) telegram.fail = func(call TelegramFakeCall) (int, string) { if call.method == "sendPhoto" { return tc.status, "photo refused" } return 0, "" } store := &ImageStore{dir: t.TempDir()} picture := imageTestPNG(t, 3, 3) name, err := store.Save(picture) require.NoError(t, err) bot, _ := telegramStartTestBot(t, telegram) show := &ImageShow{ store: store, bot: bot, } _, err = show.Show(t.Context(), name, "Caption") if tc.failure { require.Error(t, err) } else { require.NoError(t, err) } var methods []string for _, call := range telegram.Calls() { methods = append(methods, call.method) if call.method == "sendDocument" { require.Equal(t, picture, call.params["document"]) require.Equal(t, name, call.params["document_name"]) require.Equal(t, "Caption", call.params["caption"]) } } require.Equal(t, tc.methods, methods) }) } } func TestAgentShowsImageInTerminalWithoutTelegram(t *testing.T) { server := newModelFake(t) test := newTestTurnLoop(t, server) name, err := test.agent.Images().Save(imageTestPNG(t, 2, 2)) require.NoError(t, err) output := test.loop.tools.run(t.Context(), "image_show", `{"image":"`+name+`","caption":"Here it is."}`) require.Equal(t, imageText([]string{name}, "Here it is.")+"\n"+filepath.Join(test.agent.Images().dir, name), output) require.Contains(t, terminalEventText(Event{ Kind: "echo", Text: output, }), filepath.Join(test.agent.Images().dir, name)) }