Files
Erupe/server/channelserver/sys_object_test.go
Houmgaor 48639942f6 style: run gofmt across entire codebase
330 non-vendor files had minor formatting inconsistencies
(comment alignment, whitespace). No logic changes.
2026-02-23 21:28:30 +01:00

322 lines
6.5 KiB
Go

package channelserver
import (
"sync"
"testing"
)
func TestObjectStruct(t *testing.T) {
obj := &Object{
id: 12345,
ownerCharID: 67890,
x: 100.5,
y: 50.25,
z: -10.0,
}
if obj.id != 12345 {
t.Errorf("Object id = %d, want 12345", obj.id)
}
if obj.ownerCharID != 67890 {
t.Errorf("Object ownerCharID = %d, want 67890", obj.ownerCharID)
}
if obj.x != 100.5 {
t.Errorf("Object x = %f, want 100.5", obj.x)
}
if obj.y != 50.25 {
t.Errorf("Object y = %f, want 50.25", obj.y)
}
if obj.z != -10.0 {
t.Errorf("Object z = %f, want -10.0", obj.z)
}
}
func TestObjectRWMutex(t *testing.T) {
obj := &Object{
id: 1,
ownerCharID: 100,
x: 0,
y: 0,
z: 0,
}
// Test read lock
obj.RLock()
_ = obj.x
obj.RUnlock()
// Test write lock
obj.Lock()
obj.x = 100.0
obj.Unlock()
if obj.x != 100.0 {
t.Errorf("Object x = %f, want 100.0 after write", obj.x)
}
}
func TestObjectConcurrentAccess(t *testing.T) {
obj := &Object{
id: 1,
ownerCharID: 100,
x: 0,
y: 0,
z: 0,
}
var wg sync.WaitGroup
// Concurrent writers
for i := 0; i < 10; i++ {
wg.Add(1)
go func(val float32) {
defer wg.Done()
for j := 0; j < 100; j++ {
obj.Lock()
obj.x = val
obj.y = val
obj.z = val
obj.Unlock()
}
}(float32(i))
}
// Concurrent readers
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 100; j++ {
obj.RLock()
_ = obj.x
_ = obj.y
_ = obj.z
obj.RUnlock()
}
}()
}
wg.Wait()
}
func TestStageBinaryKeyStruct(t *testing.T) {
key1 := stageBinaryKey{id0: 1, id1: 2}
key2 := stageBinaryKey{id0: 1, id1: 3}
key3 := stageBinaryKey{id0: 1, id1: 2}
// Different keys
if key1 == key2 {
t.Error("key1 and key2 should be different")
}
// Same keys
if key1 != key3 {
t.Error("key1 and key3 should be equal")
}
}
func TestStageBinaryKeyAsMapKey(t *testing.T) {
data := make(map[stageBinaryKey][]byte)
key1 := stageBinaryKey{id0: 0, id1: 0}
key2 := stageBinaryKey{id0: 0, id1: 1}
key3 := stageBinaryKey{id0: 1, id1: 0}
data[key1] = []byte{0x01}
data[key2] = []byte{0x02}
data[key3] = []byte{0x03}
if len(data) != 3 {
t.Errorf("Expected 3 entries, got %d", len(data))
}
if data[key1][0] != 0x01 {
t.Errorf("data[key1] = 0x%02X, want 0x01", data[key1][0])
}
if data[key2][0] != 0x02 {
t.Errorf("data[key2] = 0x%02X, want 0x02", data[key2][0])
}
if data[key3][0] != 0x03 {
t.Errorf("data[key3] = 0x%02X, want 0x03", data[key3][0])
}
}
func TestNewStageDefaults(t *testing.T) {
stage := NewStage("test_stage_001")
if stage.id != "test_stage_001" {
t.Errorf("stage.id = %s, want test_stage_001", stage.id)
}
if stage.maxPlayers != 127 {
t.Errorf("stage.maxPlayers = %d, want 127 (default)", stage.maxPlayers)
}
if stage.objectIndex != 0 {
t.Errorf("stage.objectIndex = %d, want 0", stage.objectIndex)
}
if stage.clients == nil {
t.Error("stage.clients should be initialized")
}
if stage.reservedClientSlots == nil {
t.Error("stage.reservedClientSlots should be initialized")
}
if stage.objects == nil {
t.Error("stage.objects should be initialized")
}
if stage.rawBinaryData == nil {
t.Error("stage.rawBinaryData should be initialized")
}
if stage.host != nil {
t.Error("stage.host should be nil initially")
}
if stage.password != "" {
t.Errorf("stage.password should be empty, got %s", stage.password)
}
}
func TestStageReservedClientSlots(t *testing.T) {
stage := NewStage("test")
// Reserve some slots
stage.reservedClientSlots[100] = true
stage.reservedClientSlots[200] = false // ready status doesn't matter for presence
stage.reservedClientSlots[300] = true
if len(stage.reservedClientSlots) != 3 {
t.Errorf("reservedClientSlots count = %d, want 3", len(stage.reservedClientSlots))
}
// Check ready status
if !stage.reservedClientSlots[100] {
t.Error("charID 100 should be ready")
}
if stage.reservedClientSlots[200] {
t.Error("charID 200 should not be ready")
}
}
func TestStageRawBinaryData(t *testing.T) {
stage := NewStage("test")
key := stageBinaryKey{id0: 5, id1: 10}
data := []byte{0xDE, 0xAD, 0xBE, 0xEF}
stage.rawBinaryData[key] = data
retrieved := stage.rawBinaryData[key]
if len(retrieved) != 4 {
t.Fatalf("retrieved data len = %d, want 4", len(retrieved))
}
if retrieved[0] != 0xDE || retrieved[3] != 0xEF {
t.Error("retrieved data doesn't match stored data")
}
}
func TestStageObjects(t *testing.T) {
stage := NewStage("test")
obj := &Object{
id: 1,
ownerCharID: 12345,
x: 100.0,
y: 200.0,
z: 300.0,
}
stage.objects[obj.id] = obj
if len(stage.objects) != 1 {
t.Errorf("objects count = %d, want 1", len(stage.objects))
}
retrieved := stage.objects[obj.id]
if retrieved.ownerCharID != 12345 {
t.Errorf("retrieved object ownerCharID = %d, want 12345", retrieved.ownerCharID)
}
}
func TestStageHost(t *testing.T) {
server := createMockServer()
stage := NewStage("test")
// Set host
host := createMockSession(100, server)
stage.host = host
if stage.host != host {
t.Error("stage host not set correctly")
}
if stage.host.charID != 100 {
t.Errorf("stage host charID = %d, want 100", stage.host.charID)
}
}
func TestStagePassword(t *testing.T) {
stage := NewStage("test")
// Set password
stage.password = "secret123"
if stage.password != "secret123" {
t.Errorf("stage password = %s, want secret123", stage.password)
}
}
func TestStageMaxPlayers(t *testing.T) {
stage := NewStage("test")
// Change max players
stage.maxPlayers = 16
if stage.maxPlayers != 16 {
t.Errorf("stage maxPlayers = %d, want 16", stage.maxPlayers)
}
}
func TestStageConcurrentClientAccess(t *testing.T) {
server := createMockServer()
stage := NewStage("test")
var wg sync.WaitGroup
// Concurrent client additions
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for j := 0; j < 10; j++ {
session := createMockSession(uint32(id*100+j), server)
stage.Lock()
stage.clients[session] = session.charID
stage.Unlock()
stage.Lock()
delete(stage.clients, session)
stage.Unlock()
}
}(i)
}
// Concurrent reads
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 50; j++ {
stage.RLock()
_ = len(stage.clients)
stage.RUnlock()
}
}()
}
wg.Wait()
}
func TestStageBroadcastMHF_EmptyStage(t *testing.T) {
stage := NewStage("test")
pkt := &mockPacket{opcode: 0x1234}
// Should not panic with empty stage
stage.BroadcastMHF(pkt, nil)
}