package clock import ( "context" "encoding/json" "strings" "testing" "time" "gitea.stevedudenhoeffer.com/steve/majordomo/llm" ) func fixed() time.Time { return time.Date(2026, 6, 10, 15, 30, 0, 0, time.UTC) } func callTool(t *testing.T, name, args string) llm.ToolResult { t.Helper() sk := New(WithClock(fixed)) tool, ok := sk.Tools().Get(name) if !ok { t.Fatalf("tool %q missing", name) } return llm.ExecuteTool(context.Background(), tool, llm.ToolCall{ ID: "c1", Name: name, Arguments: json.RawMessage(args), }) } func TestTimeNowUTC(t *testing.T) { res := callTool(t, "time_now", `{}`) if res.IsError { t.Fatalf("result = %+v", res) } var out map[string]string if err := json.Unmarshal([]byte(res.Content), &out); err != nil { t.Fatalf("decode: %v", err) } if out["rfc3339"] != "2026-06-10T15:30:00Z" || out["weekday"] != "Wednesday" { t.Errorf("out = %v", out) } } func TestTimeNowZoned(t *testing.T) { res := callTool(t, "time_now", `{"timezone":"America/New_York"}`) if res.IsError { t.Fatalf("result = %+v", res) } if !strings.Contains(res.Content, "2026-06-10T11:30:00-04:00") { t.Errorf("content = %s", res.Content) } } func TestTimeNowBadZone(t *testing.T) { res := callTool(t, "time_now", `{"timezone":"Mars/Olympus"}`) if !res.IsError { t.Errorf("result = %+v, want error", res) } } func TestTimeConvert(t *testing.T) { res := callTool(t, "time_convert", `{"time":"2026-06-10T15:30:00Z","timezone":"Europe/Berlin"}`) if res.IsError { t.Fatalf("result = %+v", res) } if !strings.Contains(res.Content, "2026-06-10T17:30:00+02:00") { t.Errorf("content = %s", res.Content) } } func TestInstructionsMentionTools(t *testing.T) { sk := New() if !strings.Contains(sk.Instructions(), "time_now") { t.Errorf("instructions = %q", sk.Instructions()) } }