package game import ( "log/slog" "testing" "time" "github.com/denisovdennis/autohero/internal/model" ) func TestHeroSocketDetachedKeepsMovement(t *testing.T) { e := NewEngine(100*time.Millisecond, make(chan model.CombatEvent, 8), slog.Default()) e.SetRoadGraph(testGraph()) h := &model.Hero{ ID: 1, State: model.StateWalking, HP: 10, MaxHP: 10, Level: 1, PositionX: 1, PositionY: 1, } hm := NewHeroMovement(h, testGraph(), time.Now()) e.mu.Lock() e.movements[1] = hm e.mu.Unlock() disconnectAt := time.Date(2026, 4, 1, 12, 0, 0, 0, time.UTC) e.HeroSocketDetached(1, true, disconnectAt) e.mu.RLock() _, ok := e.movements[1] e.mu.RUnlock() if !ok { t.Fatal("expected hero to remain resident in engine after last WS disconnect") } if h.WsDisconnectedAt == nil || !h.WsDisconnectedAt.Equal(disconnectAt) { t.Fatalf("expected WsDisconnectedAt on in-memory hero, got %v", h.WsDisconnectedAt) } } func TestMergeResidentHeroState(t *testing.T) { e := NewEngine(100*time.Millisecond, make(chan model.CombatEvent, 8), slog.Default()) e.SetRoadGraph(testGraph()) dst := &model.Hero{ID: 7, State: model.StateWalking, HP: 5, MaxHP: 10, Level: 2} if e.MergeResidentHeroState(dst) { t.Fatal("expected false when hero not resident") } h := &model.Hero{ ID: 7, State: model.StateWalking, HP: 9, MaxHP: 10, Level: 3, PositionX: 2, PositionY: 3, } hm := NewHeroMovement(h, testGraph(), time.Now()) e.mu.Lock() e.movements[7] = hm e.mu.Unlock() dst2 := &model.Hero{ID: 7, HP: 1, Level: 1} if !e.MergeResidentHeroState(dst2) { t.Fatal("expected true when resident") } if dst2.HP != 9 || dst2.Level != 3 { t.Fatalf("expected engine stats copied, got hp=%d level=%d", dst2.HP, dst2.Level) } }