diff --git a/cmd/mavend/voicewire.go b/cmd/mavend/voicewire.go index f4fd334..4b07dd4 100644 --- a/cmd/mavend/voicewire.go +++ b/cmd/mavend/voicewire.go @@ -379,6 +379,7 @@ func buildRouter(emb router.Embedder, acts router.ActMatcher, threshold float64, // question and must keep reaching replySystem, while "что у меня сегодня" // is an agenda question and must not. grammars = append(grammars, router.AgendaQueryGrammars()...) + grammars = append(grammars, router.ListGrammars()...) grammars = append(grammars, router.ReminderGrammar()) return router.New(router.Config{ Grammars: grammars, diff --git a/internal/router/list_test.go b/internal/router/list_test.go new file mode 100644 index 0000000..5e0bb40 --- /dev/null +++ b/internal/router/list_test.go @@ -0,0 +1,89 @@ +package router + +import "testing" + +func TestParseListCaptureReadsListAndItem(t *testing.T) { + cases := []struct { + utterance string + list string + item string + }{ + {"добавь в список покупок молоко", "покупки", "молоко"}, + {"добавь в список молоко", "покупки", "молоко"}, + {"Добавь в покупки хлеб и яйца", "покупки", "хлеб и яйца"}, + {"запиши в список аптеки бинт", "аптека", "бинт"}, + {"добавь в список хозяйства лампочки.", "хозяйство", "лампочки"}, + {"add to the shopping list milk", "покупки", "milk"}, + } + for _, c := range cases { + got, ok := ParseListCapture(c.utterance) + if !ok { + t.Errorf("ParseListCapture(%q) did not claim it", c.utterance) + continue + } + if got.List != c.list || got.Item != c.item { + t.Errorf("ParseListCapture(%q) = %+v; want list %q item %q", c.utterance, got, c.list, c.item) + } + } +} + +// A marker with no item is not a capture, and an utterance that only mentions +// shopping is not one either. +func TestParseListCapturePasses(t *testing.T) { + for _, u := range []string{ + "добавь в список покупок", + "добавь в список", + "молоко закончилось", + "надо бы съездить в магазин", + "добавь в задачи купить молоко", + } { + if got, ok := ParseListCapture(u); ok { + t.Errorf("ParseListCapture(%q) claimed it as %+v", u, got) + } + } +} + +func TestParseListQueryNamesTheList(t *testing.T) { + cases := []struct{ utterance, list string }{ + {"что в списке покупок?", "покупки"}, + {"что в списке", "покупки"}, + {"что мне купить", "покупки"}, + {"покажи список аптеки", "аптека"}, + {"what's on the list", "покупки"}, + } + for _, c := range cases { + list, ok := ParseListQuery(c.utterance) + if !ok { + t.Errorf("ParseListQuery(%q) did not claim it", c.utterance) + continue + } + if list != c.list { + t.Errorf("ParseListQuery(%q) = %q; want %q", c.utterance, list, c.list) + } + } + if _, ok := ParseListQuery("какие у меня задачи"); ok { + t.Error("ParseListQuery claimed a task question") + } +} + +func TestParseListClearAndRemove(t *testing.T) { + if list, ok := ParseListClear("всё купил"); !ok || list != "покупки" { + t.Errorf("ParseListClear = %q, %v; want покупки, true", list, ok) + } + if list, ok := ParseListClear("очисти список аптеки"); !ok || list != "аптека" { + t.Errorf("ParseListClear = %q, %v; want аптека, true", list, ok) + } + if _, ok := ParseListClear("купил молоко"); ok { + t.Error("ParseListClear claimed a single item") + } + got, ok := ParseListRemove("вычеркни молоко") + if !ok || got.Item != "молоко" || got.List != "покупки" { + t.Errorf("ParseListRemove = %+v, %v; want молоко on покупки", got, ok) + } + if got, ok := ParseListRemove("убери из списка аптеки бинт"); !ok || got.Item != "бинт" || got.List != "аптека" { + t.Errorf("ParseListRemove = %+v, %v; want бинт on аптека", got, ok) + } + if _, ok := ParseListRemove("вычеркни"); ok { + t.Error("ParseListRemove claimed a marker with no item") + } +}