Complete architectural overhaul of pkg/core:
- All subsystem types renamed to idiomatic Go (no stutter)
- Core struct: App, Embed, Fs, Config, ErrPan, ErrLog, Cli, Service, Lock, Ipc, I18n
- Exports consolidated in core.go, contracts/options in contract.go
- Service() unified get/register: c.Service(), c.Service("name"), c.Service("name", svc)
- Lock() named mutex map: c.Lock("srv"), c.Lock("ipc")
- Error system: Err/ErrLog/ErrPan + Log/LogErr/LogPan (shared ErrSink interface)
- CoreCommand with optional description (i18n resolves from command path)
- Tests moved to tests/ directory (black-box package core_test)
- Removed: ServiceFor/MustServiceFor, global instance, Display/Workspace/Crypt interfaces
- New files: app.go, fs.go, ipc.go, lock.go, i18n.go, task.go, runtime.go, contract.go
Co-Authored-By: Virgil <virgil@lethean.io>
104 lines
2.4 KiB
Go
104 lines
2.4 KiB
Go
package core_test
|
|
|
|
import (
|
|
. "forge.lthn.ai/core/go/pkg/core"
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
// FuzzE exercises the E() error constructor with arbitrary input.
|
|
func FuzzE(f *testing.F) {
|
|
f.Add("svc.Method", "something broke", true)
|
|
f.Add("", "", false)
|
|
f.Add("a.b.c.d.e.f", "unicode: \u00e9\u00e8\u00ea", true)
|
|
|
|
f.Fuzz(func(t *testing.T, op, msg string, withErr bool) {
|
|
var underlying error
|
|
if withErr {
|
|
underlying = errors.New("wrapped")
|
|
}
|
|
|
|
e := E(op, msg, underlying)
|
|
if e == nil {
|
|
t.Fatal("E() returned nil")
|
|
}
|
|
|
|
s := e.Error()
|
|
if s == "" && (op != "" || msg != "") {
|
|
t.Fatal("Error() returned empty string for non-empty op/msg")
|
|
}
|
|
|
|
// Round-trip: Unwrap should return the underlying error
|
|
var coreErr *Err
|
|
if !errors.As(e, &coreErr) {
|
|
t.Fatal("errors.As failed for *Err")
|
|
}
|
|
if withErr && coreErr.Unwrap() == nil {
|
|
t.Fatal("Unwrap() returned nil with underlying error")
|
|
}
|
|
if !withErr && coreErr.Unwrap() != nil {
|
|
t.Fatal("Unwrap() returned non-nil without underlying error")
|
|
}
|
|
})
|
|
}
|
|
|
|
// FuzzServiceRegistration exercises service registration with arbitrary names.
|
|
func FuzzServiceRegistration(f *testing.F) {
|
|
f.Add("myservice")
|
|
f.Add("")
|
|
f.Add("a/b/c")
|
|
f.Add("service with spaces")
|
|
f.Add("service\x00null")
|
|
|
|
f.Fuzz(func(t *testing.T, name string) {
|
|
c, _ := New()
|
|
|
|
err := c.RegisterService(name, struct{}{})
|
|
if name == "" {
|
|
if err == nil {
|
|
t.Fatal("expected error for empty name")
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("unexpected error for name %q: %v", name, err)
|
|
}
|
|
|
|
// Retrieve should return the same service
|
|
got := c.Service(name)
|
|
if got == nil {
|
|
t.Fatalf("service %q not found after registration", name)
|
|
}
|
|
|
|
// Duplicate registration should fail
|
|
err = c.RegisterService(name, struct{}{})
|
|
if err == nil {
|
|
t.Fatalf("expected duplicate error for name %q", name)
|
|
}
|
|
})
|
|
}
|
|
|
|
// FuzzMessageDispatch exercises action dispatch with concurrent registrations.
|
|
func FuzzMessageDispatch(f *testing.F) {
|
|
f.Add("hello")
|
|
f.Add("")
|
|
f.Add("test\nmultiline")
|
|
|
|
f.Fuzz(func(t *testing.T, payload string) {
|
|
c, _ := New()
|
|
|
|
var received string
|
|
c.IPC().RegisterAction(func(_ *Core, msg Message) error {
|
|
received = msg.(string)
|
|
return nil
|
|
})
|
|
|
|
err := c.IPC().Action(payload)
|
|
if err != nil {
|
|
t.Fatalf("action dispatch failed: %v", err)
|
|
}
|
|
if received != payload {
|
|
t.Fatalf("got %q, want %q", received, payload)
|
|
}
|
|
})
|
|
}
|