5232609719
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
74 lines
2.5 KiB
Go
74 lines
2.5 KiB
Go
package module
|
|
|
|
import (
|
|
"path/filepath"
|
|
"regexp"
|
|
"testing"
|
|
)
|
|
|
|
// TestAllManifestsLoadAndEventRegexesCompile is the repo-wide consistency
|
|
// gate for module manifests: every modules/<id>/module.yaml must LoadDir
|
|
// cleanly, and every declared events regex must compile under Go's RE2
|
|
// engine (AMPTemplates uses .NET (?<n>) syntax — these must have been
|
|
// converted to (?P<n>)) and carry at least one named capture group the
|
|
// agent's tracker actually reads (see agent/internal/state/tracker.go
|
|
// OnLogLine: name/player_name, id-family, msg/detail/reason).
|
|
func TestAllManifestsLoadAndEventRegexesCompile(t *testing.T) {
|
|
dir := filepath.Join("..", "..", "modules")
|
|
manifests, err := LoadDir(dir)
|
|
if err != nil {
|
|
t.Fatalf("LoadDir(%s): %v", dir, err)
|
|
}
|
|
if len(manifests) < 20 {
|
|
t.Fatalf("expected >=20 manifests, got %d — wrong dir?", len(manifests))
|
|
}
|
|
|
|
// Group names the tracker extracts (tracker.go firstGroup calls).
|
|
known := map[string]bool{
|
|
"name": true, "player_name": true,
|
|
"platform_id": true, "owner": true, "cross_id": true, "id": true, "player_id": true,
|
|
"msg": true, "detail": true, "reason": true,
|
|
}
|
|
validKinds := map[string]bool{"join": true, "leave": true, "chat": true, "death": true, "custom": true}
|
|
|
|
for _, m := range manifests {
|
|
m := m
|
|
t.Run(m.ID, func(t *testing.T) {
|
|
for evName, ev := range m.Events {
|
|
re, err := regexp.Compile(ev.Pattern)
|
|
if err != nil {
|
|
t.Errorf("event %q: pattern does not compile: %v", evName, err)
|
|
continue
|
|
}
|
|
if !validKinds[ev.Kind] {
|
|
t.Errorf("event %q: unknown kind %q", evName, ev.Kind)
|
|
}
|
|
// Every event must expose at least one group the tracker
|
|
// knows how to read, otherwise the event emits empty
|
|
// PlayerName/PlayerId/Detail and is a silently-useless knob.
|
|
got := false
|
|
for _, g := range re.SubexpNames() {
|
|
if known[g] {
|
|
got = true
|
|
}
|
|
}
|
|
if !got {
|
|
t.Errorf("event %q: no tracker-known named group (want one of name/id/msg families); groups=%v", evName, re.SubexpNames())
|
|
}
|
|
// join/leave should identify the player by name or id.
|
|
if ev.Kind == "join" || ev.Kind == "leave" {
|
|
hasIdent := false
|
|
for _, g := range re.SubexpNames() {
|
|
if g == "name" || g == "player_name" || g == "id" || g == "platform_id" || g == "player_id" || g == "owner" || g == "cross_id" {
|
|
hasIdent = true
|
|
}
|
|
}
|
|
if !hasIdent {
|
|
t.Errorf("event %q (kind %s): no player-identifying named group", evName, ev.Kind)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|