package main import ( "context" "strings" "testing" "github.com/kami/maven/internal/phraser" "github.com/kami/maven/internal/router" ) // gapPhraser — a phraser whose world model is configured and asleep, which is // the state the naming half exists for. type gapPhraser struct { *phraser.Stub worldCalls int } func (g *gapPhraser) PhraseWorld(context.Context, string, []string) (string, error) { g.worldCalls++ return "", phraser.ErrNoWorldModel } func worldTurn(utterance string) *queryTurn { return &queryTurn{dec: router.Decision{Intent: router.IntentQuery, Utterance: utterance}} } // A world question with the workstation asleep says so. The resident model is // not asked, because what it produces here is an invention with no signal that // it is one. func TestQueryGeneralNamesTheGap(t *testing.T) { g := &gapPhraser{Stub: phraser.NewStub()} h := &reactiveHandler{phraser: g} reply, ok := h.queryGeneral(context.Background(), worldTurn("почему небо голубое")) if !ok { t.Fatal("queryGeneral passed on the last source in the chain") } if reply != worldGap() { t.Fatalf("reply = %q, want the named gap", reply) } if g.worldCalls != 1 { t.Fatalf("PhraseWorld called %d times, want 1", g.worldCalls) } } // A phraser with no world seam at all — the Stub, and every box with no // `workstation` block — answers exactly as it did before this seam existed. func TestQueryGeneralWithoutAWorldModelIsUnchanged(t *testing.T) { h := &reactiveHandler{phraser: phraser.NewStub()} reply, ok := h.queryGeneral(context.Background(), worldTurn("почему небо голубое")) if !ok { t.Fatal("queryGeneral passed on the last source in the chain") } if !phraser.IsUnknownFallback(reply) { t.Fatalf("reply = %q, want the Stub's answer", reply) } } // The gap is spoken aloud by a Russian voice, so it is Russian, feminine and // informal. "не хочу" and "не могу" are her own verbs; there is no "вы" and no // English in it. func TestWorldGapIsInPersona(t *testing.T) { for _, bad := range []string{"вы", "ваш", "рад ", "дорогой", "милый"} { if strings.Contains(worldGap(), bad) { t.Errorf("the gap phrase contains %q: %s", bad, worldGap()) } } if strings.ContainsAny(worldGap(), "abcdefghijklmnopqrstuvwxyz") { t.Errorf("the gap phrase has Latin letters in it: %s", worldGap()) } } // The sources that hold a passage read it back rather than name a gap. He gets a // real quote instead of "не могу сейчас", and nothing is invented either way. func TestASourceWithAPassageReadsItBackInsteadOfNamingTheGap(t *testing.T) { g := &gapPhraser{Stub: phraser.NewStub()} h := &reactiveHandler{phraser: g} if got := h.phraseSource(context.Background(), "search", "почему небо голубое", []string{"Рэлеевское рассеяние."}); got != "" { t.Fatalf("phraseSource = %q, want \"\" so the caller's own floor reads the passage back", got) } if g.worldCalls != 1 { t.Fatalf("PhraseWorld called %d times, want 1", g.worldCalls) } }