package router import ( "context" "testing" "time" ) // The shape V-538 was filed for. Russian names the hour being entered, so // "половина восьмого" is 07:30 and never 08:30. Every case here is checked // against the hour a speaker means, not against the word in the sentence. func TestRewriteHalfPast(t *testing.T) { for _, tc := range []struct{ in, want string }{ {"напомни в половине восьмого", "напомни в 7:30"}, {"напомни в половине восьмого вечера", "напомни в 7:30 вечера"}, {"половина восьмого", "в 7:30"}, {"к половине девятого", "к 8:30"}, // The hour before one is twelve, not zero. {"в половине первого", "в 12:30"}, {"в половине двенадцатого", "в 11:30"}, // Contracted, and with no preposition of its own. {"разбуди полвосьмого", "разбуди в 7:30"}, {"разбуди пол-восьмого", "разбуди в 7:30"}, {"разбуди пол восьмого", "разбуди в 7:30"}, // Quarter-to counts the same way, from a cardinal. {"без четверти восемь", "в 7:45"}, {"позвони без двадцати восемь", "позвони в 7:40"}, {"без пяти час", "в 12:55"}, // Untouched: not a time. {"половина яблока", "половина яблока"}, {"без разницы восемь", "без разницы восемь"}, {"отметь последний пункт", "отметь последний пункт"}, {"напомни в 19:30", "напомни в 19:30"}, {"", ""}, } { if got := rewriteHalfPast(tc.in); got != tc.want { t.Errorf("rewriteHalfPast(%q) = %q, want %q", tc.in, got, tc.want) } } } // A guess in this shape is worse than a refusal, so the minutes a spoken clock // does not use are left for the parsers to fail on rather than invented. func TestQuarterToTakesOnlyClockMinutes(t *testing.T) { for _, in := range []string{"без семи восемь", "без тринадцати восемь"} { if got := rewriteHalfPast(in); got != in { t.Errorf("rewriteHalfPast(%q) = %q; those minutes are not a spoken clock", in, got) } } } // The rewrite is only useful if the parser under it reads the result. The stub // is the one that always answers, because the host path falls back to it // whenever python dateparser is missing. func TestStubParsesAHalfHour(t *testing.T) { now := time.Date(2026, 8, 5, 9, 0, 0, 0, time.Local) for _, tc := range []struct { utt string hour, min int }{ {"напомни выпить таблетку в половине восьмого вечера", 19, 30}, {"напомни в половине одиннадцатого", 10, 30}, {"разбуди полвосьмого", 7, 30}, {"позвони без четверти восемь", 7, 45}, } { got, ok, err := (StubDateTimeParser{}).Parse(context.Background(), tc.utt, now) if err != nil || !ok { t.Errorf("Parse(%q) = %v, %v, %v; want a time", tc.utt, got, ok, err) continue } if got.Hour() != tc.hour || got.Minute() != tc.min { t.Errorf("Parse(%q) = %02d:%02d, want %02d:%02d", tc.utt, got.Hour(), got.Minute(), tc.hour, tc.min) } } }