Files
Erupe/server/entranceserver/make_resp_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

264 lines
7.1 KiB
Go

package entranceserver
import (
"fmt"
"strings"
"testing"
"go.uber.org/zap"
cfg "erupe-ce/config"
)
// TestEncodeServerInfo_EmptyClanMemberLimits verifies the crash is FIXED when ClanMemberLimits is empty
// Previously panicked: runtime error: index out of range [-1]
// From erupe.log.1:659922
// After fix: Should handle empty array gracefully with default value (60)
func TestEncodeServerInfo_EmptyClanMemberLimits(t *testing.T) {
config := &cfg.Config{
RealClientMode: cfg.Z1,
Host: "127.0.0.1",
Entrance: cfg.Entrance{
Enabled: true,
Port: 53310,
Entries: []cfg.EntranceServerInfo{
{
Name: "TestServer",
Description: "Test",
IP: "127.0.0.1",
Type: 0,
Recommended: 0,
AllowedClientFlags: 0xFFFFFFFF,
Channels: []cfg.EntranceChannelInfo{
{
Port: 54001,
MaxPlayers: 100,
},
},
},
},
},
GameplayOptions: cfg.GameplayOptions{
ClanMemberLimits: [][]uint8{}, // Empty array - should now use default (60) instead of panicking
},
}
server := &Server{
logger: zap.NewNop(),
erupeConfig: config,
}
// Set up defer to catch ANY panic - we should NOT get array bounds panic anymore
defer func() {
if r := recover(); r != nil {
// If panic occurs, it should NOT be from array access
panicStr := fmt.Sprintf("%v", r)
if strings.Contains(panicStr, "index out of range") {
t.Errorf("Array bounds panic NOT fixed! Still getting: %v", r)
} else {
// Other panic is acceptable (network, DB, etc) - we only care about array bounds
t.Logf("Non-array-bounds panic (acceptable): %v", r)
}
}
}()
// This should NOT panic on array bounds anymore - should use default value 60
result := encodeServerInfo(config, server, true)
if len(result) > 0 {
t.Log("✅ encodeServerInfo handled empty ClanMemberLimits without array bounds panic")
}
}
// TestClanMemberLimitsBoundsChecking verifies bounds checking logic for ClanMemberLimits
// Tests the specific logic that was fixed without needing full database setup
func TestClanMemberLimitsBoundsChecking(t *testing.T) {
// Test the bounds checking logic directly
testCases := []struct {
name string
clanMemberLimits [][]uint8
expectedValue uint8
expectDefault bool
}{
{"empty array", [][]uint8{}, 60, true},
{"single row with 2 columns", [][]uint8{{1, 50}}, 50, false},
{"single row with 1 column", [][]uint8{{1}}, 60, true},
{"multiple rows, last has 2 columns", [][]uint8{{1, 10}, {2, 20}, {3, 60}}, 60, false},
{"multiple rows, last has 1 column", [][]uint8{{1, 10}, {2, 20}, {3}}, 60, true},
{"multiple rows with valid data", [][]uint8{{1, 10}, {2, 20}, {3, 30}, {4, 40}, {5, 50}}, 50, false},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Replicate the bounds checking logic from the fix
var maxClanMembers uint8 = 60
if len(tc.clanMemberLimits) > 0 {
lastRow := tc.clanMemberLimits[len(tc.clanMemberLimits)-1]
if len(lastRow) > 1 {
maxClanMembers = lastRow[1]
}
}
// Verify correct behavior
if maxClanMembers != tc.expectedValue {
t.Errorf("Expected value %d, got %d", tc.expectedValue, maxClanMembers)
}
if tc.expectDefault && maxClanMembers != 60 {
t.Errorf("Expected default value 60, got %d", maxClanMembers)
}
t.Logf("✅ %s: Safe bounds access, value = %d", tc.name, maxClanMembers)
})
}
}
// TestEncodeServerInfo_WithMockRepo tests encodeServerInfo with a mock server repo
func TestEncodeServerInfo_WithMockRepo(t *testing.T) {
config := &cfg.Config{
RealClientMode: cfg.Z1,
Host: "127.0.0.1",
Entrance: cfg.Entrance{
Enabled: true,
Port: 53310,
Entries: []cfg.EntranceServerInfo{
{
Name: "TestServer",
Description: "Test",
IP: "127.0.0.1",
Type: 0,
Recommended: 0,
AllowedClientFlags: 0xFFFFFFFF,
Channels: []cfg.EntranceChannelInfo{
{
Port: 54001,
MaxPlayers: 100,
},
},
},
},
},
GameplayOptions: cfg.GameplayOptions{
ClanMemberLimits: [][]uint8{{1, 60}},
},
}
server := &Server{
logger: zap.NewNop(),
erupeConfig: config,
serverRepo: &mockEntranceServerRepo{currentPlayers: 42},
}
result := encodeServerInfo(config, server, true)
if len(result) == 0 {
t.Error("encodeServerInfo returned empty result")
}
}
// TestMakeUsrResp_WithMockRepo tests makeUsrResp with a mock session repo
func TestMakeUsrResp_WithMockRepo(t *testing.T) {
config := &cfg.Config{
RealClientMode: cfg.Z1,
}
server := &Server{
logger: zap.NewNop(),
erupeConfig: config,
sessionRepo: &mockEntranceSessionRepo{serverID: 1234},
}
// Build a minimal USR request packet:
// 4 bytes ALL+ prefix, 1 byte 0x00, 2 bytes entry count, then 4 bytes per entry (char ID)
pkt := []byte{
'A', 'L', 'L', '+',
0x00,
0x00, 0x01, // 1 entry
0x00, 0x00, 0x00, 0x01, // char_id = 1
}
result := makeUsrResp(pkt, server)
if len(result) == 0 {
t.Error("makeUsrResp returned empty result")
}
}
// TestMakeUsrResp_NilSessionRepo tests makeUsrResp when sessionRepo is nil
func TestMakeUsrResp_NilSessionRepo(t *testing.T) {
config := &cfg.Config{
RealClientMode: cfg.Z1,
}
server := &Server{
logger: zap.NewNop(),
erupeConfig: config,
}
pkt := []byte{
'A', 'L', 'L', '+',
0x00,
0x00, 0x01,
0x00, 0x00, 0x00, 0x01,
}
result := makeUsrResp(pkt, server)
if len(result) == 0 {
t.Error("makeUsrResp returned empty result")
}
}
// TestEncodeServerInfo_MissingSecondColumnClanMemberLimits tests accessing [last][1] when [last] is too small
// Previously panicked: runtime error: index out of range [1]
// After fix: Should handle missing column gracefully with default value (60)
func TestEncodeServerInfo_MissingSecondColumnClanMemberLimits(t *testing.T) {
config := &cfg.Config{
RealClientMode: cfg.Z1,
Host: "127.0.0.1",
Entrance: cfg.Entrance{
Enabled: true,
Port: 53310,
Entries: []cfg.EntranceServerInfo{
{
Name: "TestServer",
Description: "Test",
IP: "127.0.0.1",
Type: 0,
Recommended: 0,
AllowedClientFlags: 0xFFFFFFFF,
Channels: []cfg.EntranceChannelInfo{
{
Port: 54001,
MaxPlayers: 100,
},
},
},
},
},
GameplayOptions: cfg.GameplayOptions{
ClanMemberLimits: [][]uint8{
{1}, // Only 1 element, code used to panic accessing [1]
},
},
}
server := &Server{
logger: zap.NewNop(),
erupeConfig: config,
}
defer func() {
if r := recover(); r != nil {
panicStr := fmt.Sprintf("%v", r)
if strings.Contains(panicStr, "index out of range") {
t.Errorf("Array bounds panic NOT fixed! Still getting: %v", r)
} else {
t.Logf("Non-array-bounds panic (acceptable): %v", r)
}
}
}()
// This should NOT panic on array bounds anymore - should use default value 60
result := encodeServerInfo(config, server, true)
if len(result) > 0 {
t.Log("✅ encodeServerInfo handled missing ClanMemberLimits column without array bounds panic")
}
}