4c95b200e4
The owner's wording from the PR 112 review, and the placeholder fixes under it.
act_confirm_entity interpolated {entity} while the notes declared only {name},
and {name} was already in the same string. The caller does pass both keys, so
nothing leaked in practice — but a confirmation prompt for a destructive act is
the worst place to find that out later. Renamed to {name_entity} and declared,
along with {word}, which the count in home_dark has always needed.
Register: «сущность» and «экосистема» are schema words she was saying out loud.
act_done_entity stops reporting in the passive and matches «готово.», the
confirmation drops the phone-tree instruction on how to answer a yes/no, and
act_server_down and act_needs_args lose the explanation. «угадывать не буду»
stays exactly as it was.
home_dark leads with the count, since that is the part he can act on, and stops
sharing its opener with home_empty — one means nothing came back and the other
means devices are unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XGTGCWX33aX8SMBSRz9VmS
87 lines
2.7 KiB
Go
87 lines
2.7 KiB
Go
package phraser
|
|
|
|
import (
|
|
"math/rand"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func loadTestActs(t *testing.T) *Acts {
|
|
t.Helper()
|
|
a, err := LoadActs(rand.NewSource(1))
|
|
if err != nil {
|
|
t.Fatalf("LoadActs: %v", err)
|
|
}
|
|
return a
|
|
}
|
|
|
|
// She talks about a lamp or a server, never about a row in a schema. «сущность»
|
|
// and «экосистема» are the same defect as saying a capability id out loud.
|
|
func TestNoActLineSaysASchemaWord(t *testing.T) {
|
|
a := loadTestActs(t)
|
|
for _, v := range a.Variants() {
|
|
for _, word := range []string{"сущност", "экосистем"} {
|
|
if strings.Contains(v, word) {
|
|
t.Errorf("variant %q says %q out loud", v, word)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Nexus, Praxis and Hexis fail independently, so "не отвечает" with no subject
|
|
// is not an answer he can act on.
|
|
func TestAServiceFailureNamesTheService(t *testing.T) {
|
|
a := loadTestActs(t)
|
|
for _, key := range []string{EcoDown, EcoDenied} {
|
|
got := a.Say(key, map[string]string{"name": "Praxis"})
|
|
if !strings.HasPrefix(got, "Praxis ") {
|
|
t.Errorf("%s = %q, want it to name the service", key, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
// A confirmation prompt for a destructive act is the worst place for an unfilled
|
|
// placeholder, so the two names it interpolates are distinct keys and both are
|
|
// declared.
|
|
func TestConfirmEntityFillsBothNames(t *testing.T) {
|
|
a := loadTestActs(t)
|
|
got := a.Say(ActConfirmEntity, map[string]string{
|
|
"name": "restart", "name_entity": "Muzick indexer",
|
|
})
|
|
if strings.ContainsAny(got, "{}") {
|
|
t.Fatalf("act_confirm_entity = %q, want no placeholder left", got)
|
|
}
|
|
if !strings.Contains(got, "restart") || !strings.Contains(got, "Muzick indexer") {
|
|
t.Fatalf("act_confirm_entity = %q, want both names", got)
|
|
}
|
|
}
|
|
|
|
// home_dark counts unreachable devices, and Russian inflects the noun after the
|
|
// number: the count goes in {count} and the noun comes from the helper.
|
|
func TestHomeDarkCountsWithTheHelper(t *testing.T) {
|
|
a := loadTestActs(t)
|
|
for n, want := range map[int]string{1: "1 устройство", 2: "2 устройства", 5: "5 устройств"} {
|
|
got := a.Say(HomeDark, map[string]string{"count": strconv.Itoa(n), "word": Devices(n)})
|
|
if !strings.Contains(got, want) {
|
|
t.Errorf("home_dark for %d = %q, want %q in it", n, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Four truths, four entries: a failure must not be able to report itself as a
|
|
// success, and an empty result must not read as a failure.
|
|
func TestActOutcomesStayDistinct(t *testing.T) {
|
|
a := loadTestActs(t)
|
|
seen := map[string]string{}
|
|
for _, key := range actKeys {
|
|
for _, v := range a.d.file.Entries[key].Variants {
|
|
if prev, dup := seen[v]; dup {
|
|
t.Errorf("%s and %s both say %q", prev, key, v)
|
|
}
|
|
seen[v] = key
|
|
}
|
|
}
|
|
}
|
|
|