package main import ( "strings" "testing" "time" ) // TestTimeContextFor verifies the time-of-day bucketing used for greetings. func TestTimeContextFor(t *testing.T) { cases := []struct { hour int expected string }{ {3, "night"}, // hours < 5 {5, "morning"}, // 5 <= h < 12 {11, "morning"}, // {12, "afternoon"}, // 12 <= h < 18 {17, "afternoon"}, // {18, "evening"}, // 18 <= h < 22 {21, "evening"}, // {22, "night"}, // h >= 22 {23, "night"}, // } for _, tc := range cases { // Build the timestamp in the host's local zone so timeContextFor (which // reads local time) observes exactly tc.hour regardless of the test // machine's timezone. 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) } } } // TestBuildUserContext verifies the per-turn context block reflects the user's // details and applies the documented fallbacks. func TestBuildUserContext(t *testing.T) { noon := int(time.Date(2025, 5, 15, 12, 0, 0, 0, time.Local).Unix()) // Fully-populated premium user. 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) } } // Missing name/username/language fall back; non-premium reads "regular user". 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) } } // First name only (no last name) must not leave a trailing space in the name. got = buildUserContext("bob", "Bob", "", false, "en", noon) if !strings.Contains(got, "User: Bob (Telegram @bob)") { t.Errorf("buildUserContext firstname-only: got:\n%s", got) } }