Files
aego/engine/registry_test.go
sanspie dae4bc19e1 Stage 1: engine core, platform, gpu, vfs
Foundation for the aego engine.

core/    errs, log, handle arena, mathx, clock, stats
platform SDL3 backend plus a headless one, input state, events
gpu      device abstraction with gl33 and null backends
vfs      scheme-based virtual filesystem with overlay mounts
engine   builder, module registry, phase-ordered system loop, jobs
demos    basic, resize, input, headless; sandbox driver

OpenGL bindings are generated into gpu/gl33/gl by tools/gen-gl.sh,
so the module has no external dependencies.
2026-09-18 20:51:54 +03:00

104 lines
3.0 KiB
Go

package engine
import (
"strings"
"testing"
"aego/core/errs"
)
type recorder struct {
id string
log *[]string
}
func (r recorder) Run(*Context) {
*r.log = append(*r.log, r.id)
}
func TestTopologicalOrder(t *testing.T) {
var seen []string
r := newRegistry()
s := r.Systems()
for _, d := range []SystemDesc{
{ID: "c", Phase: PhaseUpdate, After: []string{"b"}, System: recorder{id: "c", log: &seen}},
{ID: "a", Phase: PhaseUpdate, Before: []string{"b"}, System: recorder{id: "a", log: &seen}},
{ID: "b", Phase: PhaseUpdate, System: recorder{id: "b", log: &seen}},
{ID: "r", Phase: PhaseRender, System: recorder{id: "r", log: &seen}},
} {
if err := s.Register(d); err != nil {
t.Fatal(err)
}
}
if err := r.Freeze(); err != nil {
t.Fatal(err)
}
if got := strings.Join(s.Order(PhaseUpdate), ","); got != "a,b,c" {
t.Fatalf("update order = %s", got)
}
if got := strings.Join(s.Order(PhaseRender), ","); got != "r" {
t.Fatalf("render order = %s", got)
}
}
func TestRegistryErrors(t *testing.T) {
cases := []struct {
name string
descs []SystemDesc
code errs.Code
}{
{"cycle", []SystemDesc{
{ID: "a", Phase: PhaseUpdate, After: []string{"b"}, System: recorder{}},
{ID: "b", Phase: PhaseUpdate, After: []string{"a"}, System: recorder{}},
}, errs.EngineSystemCycle},
{"self", []SystemDesc{
{ID: "a", Phase: PhaseUpdate, After: []string{"a"}, System: recorder{}},
}, errs.EngineSystemCycle},
{"unknown", []SystemDesc{
{ID: "a", Phase: PhaseUpdate, Before: []string{"ghost"}, System: recorder{}},
}, errs.EngineSystemDep},
{"cross phase", []SystemDesc{
{ID: "a", Phase: PhaseUpdate, Before: []string{"b"}, System: recorder{}},
{ID: "b", Phase: PhaseRender, System: recorder{}},
}, errs.EngineSystemPhase},
}
for _, c := range cases {
r := newRegistry()
for _, d := range c.descs {
if err := r.Systems().Register(d); err != nil {
t.Fatalf("%s: register: %v", c.name, err)
}
}
err := r.Freeze()
if !errs.Has(err, c.code) {
t.Fatalf("%s: got %v, want %s", c.name, err, c.code)
}
}
}
func TestRegisterValidation(t *testing.T) {
r := newRegistry()
s := r.Systems()
if err := s.Register(SystemDesc{ID: "", Phase: PhaseUpdate, System: recorder{}}); !errs.Has(err, errs.EngineSystemBad) {
t.Fatalf("empty id: %v", err)
}
if err := s.Register(SystemDesc{ID: "a", Phase: PhaseUpdate}); !errs.Has(err, errs.EngineSystemBad) {
t.Fatalf("nil system: %v", err)
}
if err := s.Register(SystemDesc{ID: "a", Phase: Phase(200), System: recorder{}}); !errs.Has(err, errs.EngineSystemPhase) {
t.Fatalf("bad phase: %v", err)
}
if err := s.Register(SystemDesc{ID: "a", Phase: PhaseUpdate, System: recorder{}}); err != nil {
t.Fatal(err)
}
if err := s.Register(SystemDesc{ID: "a", Phase: PhaseInput, System: recorder{}}); !errs.Has(err, errs.EngineSystemDup) {
t.Fatalf("duplicate: %v", err)
}
if err := r.Freeze(); err != nil {
t.Fatal(err)
}
if err := s.Register(SystemDesc{ID: "b", Phase: PhaseUpdate, System: recorder{}}); !errs.Has(err, errs.EngineFrozen) {
t.Fatalf("frozen: %v", err)
}
}