gui/pkg/lifecycle/service_test.go
Claude 18a455b460
Some checks failed
Security Scan / security (push) Failing after 25s
refactor: migrate entire gui to Core v0.8.0 API
- Import paths: forge.lthn.ai/core/go → dappco.re/go/core
- Import paths: forge.lthn.ai/core/go-log → dappco.re/go/core/log
- Import paths: forge.lthn.ai/core/go-io → dappco.re/go/core/io
- RegisterTask → c.Action("name", handler) across all 15 services
- QueryHandler signature: (any, bool, error) → core.Result
- PERFORM(task) → Action.Run(ctx, opts)
- QUERY returns single core.Result (not 3 values)
- All 17 packages build and test clean on v0.8.0-alpha.1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:14:19 +01:00

256 lines
6.2 KiB
Go

// pkg/lifecycle/service_test.go
package lifecycle
import (
"context"
"sync"
"testing"
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// --- Mock Platform ---
type mockPlatform struct {
mu sync.Mutex
handlers map[EventType][]func()
fileHandlers []func(string)
}
func newMockPlatform() *mockPlatform {
return &mockPlatform{
handlers: make(map[EventType][]func()),
}
}
func (m *mockPlatform) OnApplicationEvent(eventType EventType, handler func()) func() {
m.mu.Lock()
defer m.mu.Unlock()
m.handlers[eventType] = append(m.handlers[eventType], handler)
idx := len(m.handlers[eventType]) - 1
return func() {
m.mu.Lock()
defer m.mu.Unlock()
if idx < len(m.handlers[eventType]) {
m.handlers[eventType] = append(m.handlers[eventType][:idx], m.handlers[eventType][idx+1:]...)
}
}
}
func (m *mockPlatform) OnOpenedWithFile(handler func(string)) func() {
m.mu.Lock()
defer m.mu.Unlock()
m.fileHandlers = append(m.fileHandlers, handler)
idx := len(m.fileHandlers) - 1
return func() {
m.mu.Lock()
defer m.mu.Unlock()
if idx < len(m.fileHandlers) {
m.fileHandlers = append(m.fileHandlers[:idx], m.fileHandlers[idx+1:]...)
}
}
}
// simulateEvent fires all registered handlers for the given event type.
func (m *mockPlatform) simulateEvent(eventType EventType) {
m.mu.Lock()
handlers := make([]func(), len(m.handlers[eventType]))
copy(handlers, m.handlers[eventType])
m.mu.Unlock()
for _, h := range handlers {
h()
}
}
// simulateFileOpen fires all registered file-open handlers.
func (m *mockPlatform) simulateFileOpen(path string) {
m.mu.Lock()
handlers := make([]func(string), len(m.fileHandlers))
copy(handlers, m.fileHandlers)
m.mu.Unlock()
for _, h := range handlers {
h(path)
}
}
// handlerCount returns the number of registered handlers for event-based + file-based.
func (m *mockPlatform) handlerCount() int {
m.mu.Lock()
defer m.mu.Unlock()
count := len(m.fileHandlers)
for _, handlers := range m.handlers {
count += len(handlers)
}
return count
}
// --- Test helpers ---
func newTestLifecycleService(t *testing.T) (*Service, *core.Core, *mockPlatform) {
t.Helper()
mock := newMockPlatform()
c := core.New(
core.WithService(Register(mock)),
core.WithServiceLock(),
)
require.True(t, c.ServiceStartup(context.Background(), nil).OK)
svc := core.MustServiceFor[*Service](c, "lifecycle")
return svc, c, mock
}
// --- Tests ---
func TestRegister_Good(t *testing.T) {
svc, _, _ := newTestLifecycleService(t)
assert.NotNil(t, svc)
}
func TestApplicationStarted_Good(t *testing.T) {
_, c, mock := newTestLifecycleService(t)
var received bool
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
if _, ok := msg.(ActionApplicationStarted); ok {
received = true
}
return core.Result{OK: true}
})
mock.simulateEvent(EventApplicationStarted)
assert.True(t, received)
}
func TestDidBecomeActive_Good(t *testing.T) {
_, c, mock := newTestLifecycleService(t)
var received bool
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
if _, ok := msg.(ActionDidBecomeActive); ok {
received = true
}
return core.Result{OK: true}
})
mock.simulateEvent(EventDidBecomeActive)
assert.True(t, received)
}
func TestDidResignActive_Good(t *testing.T) {
_, c, mock := newTestLifecycleService(t)
var received bool
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
if _, ok := msg.(ActionDidResignActive); ok {
received = true
}
return core.Result{OK: true}
})
mock.simulateEvent(EventDidResignActive)
assert.True(t, received)
}
func TestWillTerminate_Good(t *testing.T) {
_, c, mock := newTestLifecycleService(t)
var received bool
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
if _, ok := msg.(ActionWillTerminate); ok {
received = true
}
return core.Result{OK: true}
})
mock.simulateEvent(EventWillTerminate)
assert.True(t, received)
}
func TestPowerStatusChanged_Good(t *testing.T) {
_, c, mock := newTestLifecycleService(t)
var received bool
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
if _, ok := msg.(ActionPowerStatusChanged); ok {
received = true
}
return core.Result{OK: true}
})
mock.simulateEvent(EventPowerStatusChanged)
assert.True(t, received)
}
func TestSystemSuspend_Good(t *testing.T) {
_, c, mock := newTestLifecycleService(t)
var received bool
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
if _, ok := msg.(ActionSystemSuspend); ok {
received = true
}
return core.Result{OK: true}
})
mock.simulateEvent(EventSystemSuspend)
assert.True(t, received)
}
func TestSystemResume_Good(t *testing.T) {
_, c, mock := newTestLifecycleService(t)
var received bool
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
if _, ok := msg.(ActionSystemResume); ok {
received = true
}
return core.Result{OK: true}
})
mock.simulateEvent(EventSystemResume)
assert.True(t, received)
}
func TestOpenedWithFile_Good(t *testing.T) {
_, c, mock := newTestLifecycleService(t)
var receivedPath string
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
if a, ok := msg.(ActionOpenedWithFile); ok {
receivedPath = a.Path
}
return core.Result{OK: true}
})
mock.simulateFileOpen("/Users/snider/Documents/test.txt")
assert.Equal(t, "/Users/snider/Documents/test.txt", receivedPath)
}
func TestOnShutdown_CancelsAll_Good(t *testing.T) {
svc, _, mock := newTestLifecycleService(t)
// Verify handlers were registered during OnStartup
assert.Greater(t, mock.handlerCount(), 0, "handlers should be registered after OnStartup")
// Shutdown should cancel all registrations
require.True(t, svc.OnShutdown(context.Background()).OK)
assert.Equal(t, 0, mock.handlerCount(), "all handlers should be cancelled after OnShutdown")
}
func TestRegister_Bad(t *testing.T) {
// No lifecycle service registered — actions are not received
c := core.New(core.WithServiceLock())
var received bool
c.RegisterAction(func(_ *core.Core, msg core.Message) core.Result {
if _, ok := msg.(ActionApplicationStarted); ok {
received = true
}
return core.Result{OK: true}
})
// No way to trigger events without the service
assert.False(t, received)
}