Files
go-telegram-bot/anthropic_test.go
T
2026-07-16 17:10:50 +02:00

144 lines
4.2 KiB
Go

package main
import (
"encoding/json"
"strings"
"testing"
"time"
"github.com/anthropics/anthropic-sdk-go"
)
func TestTimeContextFor(t *testing.T) {
cases := []struct {
hour int
expected string
}{
{3, "night"},
{5, "morning"},
{11, "morning"},
{12, "afternoon"},
{17, "afternoon"},
{18, "evening"},
{21, "evening"},
{22, "night"},
{23, "night"},
}
for _, tc := range cases {
ts := int(time.Date(2025, 5, 15, tc.hour, 0, 0, 0, time.Local).Unix())
if got := timeContextFor(ts); got != tc.expected {
t.Errorf("timeContextFor(hour=%d) = %q, want %q", tc.hour, got, tc.expected)
}
}
}
func TestBuildUserContext(t *testing.T) {
noon := int(time.Date(2025, 5, 15, 12, 0, 0, 0, time.Local).Unix())
got := buildUserContext("alice", "Alice", "Smith", true, "de", noon)
for _, want := range []string{"Alice Smith", "@alice", "Preferred language: de", "premium user", "afternoon"} {
if !strings.Contains(got, want) {
t.Errorf("buildUserContext premium: missing %q in:\n%s", want, got)
}
}
got = buildUserContext("", "", "", false, "", noon)
for _, want := range []string{"User: unknown (Telegram @unknown)", "Preferred language: en", "regular user"} {
if !strings.Contains(got, want) {
t.Errorf("buildUserContext fallback: missing %q in:\n%s", want, got)
}
}
got = buildUserContext("bob", "Bob", "", false, "en", noon)
if !strings.Contains(got, "User: Bob (Telegram @bob)") {
t.Errorf("buildUserContext firstname-only: got:\n%s", got)
}
}
func TestThinkingParamFromConfig(t *testing.T) {
cases := []struct {
name string
mode string
display string
ok bool
want map[string]any
}{
{"unset omits param", "", "", false, nil},
{"unknown value omits param", "bogus", "", false, nil},
{"adaptive no display", ThinkingModeAdaptive, "", true,
map[string]any{"type": "adaptive"}},
{"adaptive summarized", ThinkingModeAdaptive, ThinkingDisplaySummarized, true,
map[string]any{"type": "adaptive", "display": "summarized"}},
{"adaptive omitted", ThinkingModeAdaptive, ThinkingDisplayOmitted, true,
map[string]any{"type": "adaptive", "display": "omitted"}},
{"disabled", ThinkingModeDisabled, "", true,
map[string]any{"type": "disabled"}},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
union, ok := thinkingParamFromConfig(tc.mode, tc.display)
if ok != tc.ok {
t.Fatalf("ok = %v, want %v", ok, tc.ok)
}
if !tc.ok {
return
}
raw, err := json.Marshal(union)
if err != nil {
t.Fatalf("marshal: %v", err)
}
var got map[string]any
if err := json.Unmarshal(raw, &got); err != nil {
t.Fatalf("unmarshal %s: %v", raw, err)
}
if len(got) != len(tc.want) {
t.Fatalf("wire shape %s: got %d keys, want %d (%v)", raw, len(got), len(tc.want), tc.want)
}
for k, v := range tc.want {
if got[k] != v {
t.Errorf("wire shape %s: key %q = %v, want %v", raw, k, got[k], v)
}
}
})
}
}
func TestBackwardCompatibleParams(t *testing.T) {
params := anthropic.BetaMessageNewParams{
Model: "claude-test",
MaxTokens: defaultMaxTokens,
Messages: []anthropic.BetaMessageParam{
anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("hi")),
},
}
raw, err := json.Marshal(params)
if err != nil {
t.Fatalf("marshal: %v", err)
}
var got map[string]any
if err := json.Unmarshal(raw, &got); err != nil {
t.Fatalf("unmarshal: %v", err)
}
if _, present := got["thinking"]; present {
t.Errorf("zero Thinking union must omit the key; body: %s", raw)
}
if mt, ok := got["max_tokens"].(float64); !ok || int(mt) != defaultMaxTokens {
t.Errorf("max_tokens = %v, want %d; body: %s", got["max_tokens"], defaultMaxTokens, raw)
}
}
func TestEmptyStreamError(t *testing.T) {
err := emptyStreamError("max_tokens", 3900, 4000)
for _, want := range []string{"output budget exhausted", "3900", "4000"} {
if !strings.Contains(err.Error(), want) {
t.Errorf("max_tokens case: %q missing %q", err.Error(), want)
}
}
if got := emptyStreamError("end_turn", 0, 1000).Error(); got != "unexpected response format from Anthropic" {
t.Errorf("generic case = %q", got)
}
if got := emptyStreamError("", 0, 1000).Error(); got != "unexpected response format from Anthropic" {
t.Errorf("no-stop-reason case = %q", got)
}
}