test(channelserver): add unit tests for helpers, kouryou, scenario, seibattle, and distitem handlers

Cover previously untested handler files with mock-based unit tests:
- handlers_helpers: load/save character data, ack helpers, updateRights
- handlers_kouryou: get/add/exchange points with success and error paths
- handlers_scenario: scenario counter serialization, 128-entry trim, category exchange flags
- handlers_seibattle: all type codes, Earth response format, data size validation
- handlers_distitem: enumerate/apply/acquire distributions, description retrieval
This commit is contained in:
Houmgaor
2026-02-22 18:55:31 +01:00
parent bcb5086dbb
commit 6c0269d21f
5 changed files with 1098 additions and 0 deletions

View File

@@ -0,0 +1,228 @@
package channelserver
import (
"encoding/binary"
"testing"
"erupe-ce/network/mhfpacket"
)
func TestHandleMsgMhfGetSeibattle_AllTypes(t *testing.T) {
tests := []struct {
name string
pktType uint8
}{
{"Timetable", 1},
{"KeyScore", 3},
{"Career", 4},
{"Opponent", 5},
{"ConventionResult", 6},
{"CharScore", 7},
{"CurResult", 8},
{"UnknownType", 99},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server := createMockServer()
server.erupeConfig.EarthID = 1
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetSeibattle{
AckHandle: 100,
Type: tt.pktType,
}
handleMsgMhfGetSeibattle(session, pkt)
select {
case p := <-session.sendPackets:
_, errCode, ackData := parseAckBufData(t, p.data)
if errCode != 0 {
t.Errorf("ErrorCode = %d, want 0", errCode)
}
// Earth header: EarthID(4) + 0(4) + 0(4) + count(4) = 16 bytes minimum
if len(ackData) < 16 {
t.Errorf("AckData too short: %d bytes", len(ackData))
}
earthID := binary.BigEndian.Uint32(ackData[:4])
if earthID != 1 {
t.Errorf("EarthID = %d, want 1", earthID)
}
default:
t.Fatal("No response queued")
}
})
}
}
func TestHandleMsgMhfGetSeibattle_TimetableEntryCount(t *testing.T) {
server := createMockServer()
server.erupeConfig.EarthID = 1
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetSeibattle{
AckHandle: 100,
Type: 1, // Timetable
}
handleMsgMhfGetSeibattle(session, pkt)
select {
case p := <-session.sendPackets:
_, _, ackData := parseAckBufData(t, p.data)
count := binary.BigEndian.Uint32(ackData[12:16])
if count != 3 {
t.Errorf("timetable count = %d, want 3", count)
}
default:
t.Fatal("No response queued")
}
}
func TestHandleMsgMhfGetBreakSeibatuLevelReward_DataSize(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetBreakSeibatuLevelReward{AckHandle: 100}
handleMsgMhfGetBreakSeibatuLevelReward(session, pkt)
select {
case p := <-session.sendPackets:
_, _, ackData := parseAckBufData(t, p.data)
// 4 × int32 = 16 bytes
if len(ackData) != 16 {
t.Errorf("AckData len = %d, want 16", len(ackData))
}
default:
t.Fatal("No response queued")
}
}
func TestHandleMsgMhfGetWeeklySeibatuRankingReward_EarthFormat(t *testing.T) {
server := createMockServer()
server.erupeConfig.EarthID = 42
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetWeeklySeibatuRankingReward{AckHandle: 100}
handleMsgMhfGetWeeklySeibatuRankingReward(session, pkt)
select {
case p := <-session.sendPackets:
_, _, ackData := parseAckBufData(t, p.data)
earthID := binary.BigEndian.Uint32(ackData[:4])
if earthID != 42 {
t.Errorf("EarthID = %d, want 42", earthID)
}
count := binary.BigEndian.Uint32(ackData[12:16])
if count != 1 {
t.Errorf("reward count = %d, want 1", count)
}
default:
t.Fatal("No response queued")
}
}
func TestHandleMsgMhfGetFixedSeibatuRankingTable_DataSize(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetFixedSeibatuRankingTable{AckHandle: 100}
handleMsgMhfGetFixedSeibatuRankingTable(session, pkt)
select {
case p := <-session.sendPackets:
_, _, ackData := parseAckBufData(t, p.data)
// 4 + 4 + 32 = 40 bytes
if len(ackData) != 40 {
t.Errorf("AckData len = %d, want 40", len(ackData))
}
default:
t.Fatal("No response queued")
}
}
func TestHandleMsgMhfReadBeatLevel_VerifyIDEcho(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfReadBeatLevel{
AckHandle: 100,
ValidIDCount: 2,
IDs: [16]uint32{0x74, 0x6B},
}
handleMsgMhfReadBeatLevel(session, pkt)
select {
case p := <-session.sendPackets:
_, _, ackData := parseAckBufData(t, p.data)
// 2 entries × (4+4+4+4) = 32 bytes
if len(ackData) != 32 {
t.Errorf("AckData len = %d, want 32", len(ackData))
}
firstID := binary.BigEndian.Uint32(ackData[:4])
if firstID != 0x74 {
t.Errorf("first ID = 0x%x, want 0x74", firstID)
}
secondID := binary.BigEndian.Uint32(ackData[16:20])
if secondID != 0x6B {
t.Errorf("second ID = 0x%x, want 0x6B", secondID)
}
default:
t.Fatal("No response queued")
}
}
func TestHandleMsgMhfReadBeatLevelAllRanking_DataSize(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfReadBeatLevelAllRanking{AckHandle: 100}
handleMsgMhfReadBeatLevelAllRanking(session, pkt)
select {
case p := <-session.sendPackets:
_, _, ackData := parseAckBufData(t, p.data)
// 4+4+4 + 100*(4+4+32) = 4012 bytes
expectedLen := 12 + 100*40
if len(ackData) != expectedLen {
t.Errorf("AckData len = %d, want %d", len(ackData), expectedLen)
}
default:
t.Fatal("No response queued")
}
}
func TestHandleMsgMhfReadBeatLevelMyRanking_EmptyResponse(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfReadBeatLevelMyRanking{AckHandle: 100}
handleMsgMhfReadBeatLevelMyRanking(session, pkt)
select {
case p := <-session.sendPackets:
_, _, ackData := parseAckBufData(t, p.data)
if len(ackData) != 0 {
t.Errorf("AckData len = %d, want 0", len(ackData))
}
default:
t.Fatal("No response queued")
}
}
func TestHandleMsgMhfReadLastWeekBeatRanking_DataSize(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfReadLastWeekBeatRanking{AckHandle: 100}
handleMsgMhfReadLastWeekBeatRanking(session, pkt)
select {
case p := <-session.sendPackets:
_, _, ackData := parseAckBufData(t, p.data)
if len(ackData) != 16 {
t.Errorf("AckData len = %d, want 16", len(ackData))
}
default:
t.Fatal("No response queued")
}
}