package router import ( "testing" "time" ) func TestCalendarEventFormatter(t *testing.T) { f := CalendarEventFormatter{} date := time.Date(2026, 7, 6, 0, 0, 0, 0, time.UTC) // Empty if got := f.Format(nil, date); got != "на 06.07.2026 ничего нет." { t.Errorf("empty: got %q", got) } // One event if got := f.Format([]string{"Standup @ 10:00-10:30"}, date); got != "на 06.07.2026: Standup @ 10:00-10:30" { t.Errorf("one: got %q", got) } // Multiple events if got := f.Format([]string{"Standup @ 10:00-10:30", "Lunch @ 12:00-13:00"}, date); got != "на 06.07.2026: Standup @ 10:00-10:30; Lunch @ 12:00-13:00" { t.Errorf("multiple: got %q", got) } } func TestCalendarEventFormatterHedgesUncertainEntries(t *testing.T) { f := CalendarEventFormatter{} date := time.Date(2026, 7, 6, 0, 0, 0, 0, time.UTC) // An event relayed off a phone notification is not a calendar read, and she // says so instead of reciting a guess as fact. got := f.FormatEntries([]CalendarEntry{ {Text: "Standup @ 10:00-10:30"}, {Text: "Планёрка @ 14:00-14:30", Uncertain: true}, }, date) want := "на 06.07.2026: Standup @ 10:00-10:30; похоже, Планёрка @ 14:00-14:30" if got != want { t.Errorf("got %q\nwant %q", got, want) } // Format is FormatEntries with everything certain. if got := f.FormatEntries(nil, date); got != "на 06.07.2026 ничего нет." { t.Errorf("empty: got %q", got) } } func TestIsDayPlanQuery(t *testing.T) { yes := []string{ "какие планы на сегодня?", "что у меня по плану", "расскажи план", "мой распорядок на сегодня", "расписание?", "что дальше?", "what's next", "what is my plan today", } for _, s := range yes { if !IsDayPlanQuery(s) { t.Errorf("IsDayPlanQuery(%q) = false, want true", s) } } no := []string{ // The calendar listing owns these. "что у меня сегодня?", "какие планы на завтра?", "план на послезавтра", "что было вчера", // "планёрка" is a meeting, not a request for the plan. "когда планёрка?", "запиши планёрку на 14:00", "какая погода?", "", } for _, s := range no { if IsDayPlanQuery(s) { t.Errorf("IsDayPlanQuery(%q) = true, want false", s) } } } // The plan is built for the clock's own day. A weekday, a week or a weekend // carries no сегодня-family token, so the plan used to claim the utterance and // recite today under today's date. Refusing is the right answer until the plan // can build a day that is not the clock's own. func TestIsDayPlanQueryRefusesOtherSpans(t *testing.T) { for _, s := range []string{ "какие планы на понедельник?", "планы на пятницу", "какие планы на неделю?", "планы на выходные", "какие планы на месяц?", "what are my plans for friday?", "my plan for the week", } { if IsDayPlanQuery(s) { t.Errorf("IsDayPlanQuery(%q) = true, want false", s) } } } // The rest-of-day test tokenizes like IsDayPlanQuery does. The substring form // it replaced fired on any word containing "next" or "дальше". func TestIsRestOfDayQuery(t *testing.T) { for _, s := range []string{"что дальше?", "и что потом, дальше?", "what's next", "NEXT"} { if !IsRestOfDayQuery(s) { t.Errorf("IsRestOfDayQuery(%q) = false, want true", s) } } for _, s := range []string{"какие планы на сегодня?", "проверь nextcloud", "дальшесъезд", ""} { if IsRestOfDayQuery(s) { t.Errorf("IsRestOfDayQuery(%q) = true, want false", s) } } }