mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-21 23:22:34 +01:00
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:
296
server/channelserver/handlers_distitem_test.go
Normal file
296
server/channelserver/handlers_distitem_test.go
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
package channelserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
cfg "erupe-ce/config"
|
||||||
|
"erupe-ce/network/mhfpacket"
|
||||||
|
)
|
||||||
|
|
||||||
|
// --- mockDistRepo ---
|
||||||
|
|
||||||
|
type mockDistRepo struct {
|
||||||
|
distributions []Distribution
|
||||||
|
listErr error
|
||||||
|
items map[uint32][]DistributionItem
|
||||||
|
itemsErr error
|
||||||
|
description string
|
||||||
|
descErr error
|
||||||
|
recordedDist uint32
|
||||||
|
recordedChar uint32
|
||||||
|
recordErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockDistRepo) List(_ uint32, _ uint8) ([]Distribution, error) {
|
||||||
|
return m.distributions, m.listErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockDistRepo) GetItems(distID uint32) ([]DistributionItem, error) {
|
||||||
|
if m.itemsErr != nil {
|
||||||
|
return nil, m.itemsErr
|
||||||
|
}
|
||||||
|
if m.items != nil {
|
||||||
|
return m.items[distID], nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockDistRepo) RecordAccepted(distID, charID uint32) error {
|
||||||
|
m.recordedDist = distID
|
||||||
|
m.recordedChar = charID
|
||||||
|
return m.recordErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockDistRepo) GetDescription(_ uint32) (string, error) {
|
||||||
|
return m.description, m.descErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfEnumerateDistItem_Empty(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.erupeConfig.RealClientMode = cfg.S6
|
||||||
|
server.distRepo = &mockDistRepo{}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfEnumerateDistItem{AckHandle: 100, DistType: 0}
|
||||||
|
handleMsgMhfEnumerateDistItem(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, errCode, ackData := parseAckBufData(t, p.data)
|
||||||
|
if errCode != 0 {
|
||||||
|
t.Errorf("ErrorCode = %d, want 0", errCode)
|
||||||
|
}
|
||||||
|
count := binary.BigEndian.Uint16(ackData[:2])
|
||||||
|
if count != 0 {
|
||||||
|
t.Errorf("dist count = %d, want 0", count)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfEnumerateDistItem_WithDistributions(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.erupeConfig.RealClientMode = cfg.S6
|
||||||
|
server.distRepo = &mockDistRepo{
|
||||||
|
distributions: []Distribution{
|
||||||
|
{
|
||||||
|
ID: 1,
|
||||||
|
Deadline: time.Unix(1000000, 0),
|
||||||
|
Rights: 0,
|
||||||
|
TimesAcceptable: 1,
|
||||||
|
TimesAccepted: 0,
|
||||||
|
MinHR: 1,
|
||||||
|
MaxHR: 999,
|
||||||
|
EventName: "Test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfEnumerateDistItem{AckHandle: 100, DistType: 0}
|
||||||
|
handleMsgMhfEnumerateDistItem(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, _, ackData := parseAckBufData(t, p.data)
|
||||||
|
count := binary.BigEndian.Uint16(ackData[:2])
|
||||||
|
if count != 1 {
|
||||||
|
t.Errorf("dist count = %d, want 1", count)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfApplyDistItem_Empty(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.erupeConfig.RealClientMode = cfg.S6
|
||||||
|
server.distRepo = &mockDistRepo{}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfApplyDistItem{
|
||||||
|
AckHandle: 100,
|
||||||
|
DistributionID: 42,
|
||||||
|
}
|
||||||
|
handleMsgMhfApplyDistItem(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, _, ackData := parseAckBufData(t, p.data)
|
||||||
|
// 4 (distID) + 2 (count=0) = 6
|
||||||
|
distID := binary.BigEndian.Uint32(ackData[:4])
|
||||||
|
if distID != 42 {
|
||||||
|
t.Errorf("distID = %d, want 42", distID)
|
||||||
|
}
|
||||||
|
itemCount := binary.BigEndian.Uint16(ackData[4:6])
|
||||||
|
if itemCount != 0 {
|
||||||
|
t.Errorf("item count = %d, want 0", itemCount)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfApplyDistItem_WithItems(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.erupeConfig.RealClientMode = cfg.S6
|
||||||
|
server.distRepo = &mockDistRepo{
|
||||||
|
items: map[uint32][]DistributionItem{
|
||||||
|
10: {
|
||||||
|
{ItemType: 1, ID: 100, ItemID: 200, Quantity: 5},
|
||||||
|
{ItemType: 2, ID: 101, ItemID: 300, Quantity: 3},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfApplyDistItem{
|
||||||
|
AckHandle: 100,
|
||||||
|
DistributionID: 10,
|
||||||
|
}
|
||||||
|
handleMsgMhfApplyDistItem(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, _, ackData := parseAckBufData(t, p.data)
|
||||||
|
itemCount := binary.BigEndian.Uint16(ackData[4:6])
|
||||||
|
if itemCount != 2 {
|
||||||
|
t.Errorf("item count = %d, want 2", itemCount)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfAcquireDistItem_ZeroID(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.distRepo = &mockDistRepo{}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfAcquireDistItem{
|
||||||
|
AckHandle: 100,
|
||||||
|
DistributionID: 0,
|
||||||
|
}
|
||||||
|
handleMsgMhfAcquireDistItem(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
if len(p.data) == 0 {
|
||||||
|
t.Fatal("Should respond")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfAcquireDistItem_RecordAccepted(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
distRepo := &mockDistRepo{
|
||||||
|
items: map[uint32][]DistributionItem{
|
||||||
|
5: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
server.distRepo = distRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
session.charID = 42
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfAcquireDistItem{
|
||||||
|
AckHandle: 100,
|
||||||
|
DistributionID: 5,
|
||||||
|
}
|
||||||
|
handleMsgMhfAcquireDistItem(session, pkt)
|
||||||
|
|
||||||
|
if distRepo.recordedDist != 5 {
|
||||||
|
t.Errorf("recorded dist ID = %d, want 5", distRepo.recordedDist)
|
||||||
|
}
|
||||||
|
if distRepo.recordedChar != 42 {
|
||||||
|
t.Errorf("recorded char ID = %d, want 42", distRepo.recordedChar)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
if len(p.data) == 0 {
|
||||||
|
t.Fatal("Should respond")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfAcquireDistItem_RecordError(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.distRepo = &mockDistRepo{
|
||||||
|
recordErr: errors.New("db error"),
|
||||||
|
}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfAcquireDistItem{
|
||||||
|
AckHandle: 100,
|
||||||
|
DistributionID: 5,
|
||||||
|
}
|
||||||
|
handleMsgMhfAcquireDistItem(session, pkt)
|
||||||
|
|
||||||
|
// Should still send success ack
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
if len(p.data) == 0 {
|
||||||
|
t.Fatal("Should respond")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfGetDistDescription_Success(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.distRepo = &mockDistRepo{description: "Test event description"}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfGetDistDescription{
|
||||||
|
AckHandle: 100,
|
||||||
|
DistributionID: 1,
|
||||||
|
}
|
||||||
|
handleMsgMhfGetDistDescription(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, errCode, ackData := parseAckBufData(t, p.data)
|
||||||
|
if errCode != 0 {
|
||||||
|
t.Errorf("ErrorCode = %d, want 0", errCode)
|
||||||
|
}
|
||||||
|
if len(ackData) == 0 {
|
||||||
|
t.Fatal("AckData should not be empty")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfGetDistDescription_Error(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.distRepo = &mockDistRepo{descErr: errors.New("not found")}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfGetDistDescription{
|
||||||
|
AckHandle: 100,
|
||||||
|
DistributionID: 999,
|
||||||
|
}
|
||||||
|
handleMsgMhfGetDistDescription(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, errCode, ackData := parseAckBufData(t, p.data)
|
||||||
|
if errCode != 0 {
|
||||||
|
t.Errorf("ErrorCode = %d, want 0 (still buf succeed)", errCode)
|
||||||
|
}
|
||||||
|
if len(ackData) != 4 {
|
||||||
|
t.Errorf("AckData len = %d, want 4 (fallback)", len(ackData))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
211
server/channelserver/handlers_helpers_test.go
Normal file
211
server/channelserver/handlers_helpers_test.go
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
package channelserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoadCharacterData_Success(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
charRepo.columns["test_col"] = []byte{0xAA, 0xBB, 0xCC}
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
loadCharacterData(session, 100, "test_col", nil)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case pkt := <-session.sendPackets:
|
||||||
|
if pkt.data == nil {
|
||||||
|
t.Fatal("Response packet should have data")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response packet queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadCharacterData_EmptyUsesDefault(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
defaultData := []byte{0x01, 0x02, 0x03}
|
||||||
|
loadCharacterData(session, 100, "missing_col", defaultData)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case pkt := <-session.sendPackets:
|
||||||
|
if pkt.data == nil {
|
||||||
|
t.Fatal("Response packet should have data")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response packet queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadCharacterData_Error(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
charRepo.loadColumnErr = errors.New("db error")
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
defaultData := []byte{0xFF}
|
||||||
|
loadCharacterData(session, 100, "test_col", defaultData)
|
||||||
|
|
||||||
|
// Should still send a response (with default data)
|
||||||
|
select {
|
||||||
|
case pkt := <-session.sendPackets:
|
||||||
|
if pkt.data == nil {
|
||||||
|
t.Fatal("Response packet should have data even on error")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response packet queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSaveCharacterData_Success(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
data := []byte{0x01, 0x02, 0x03}
|
||||||
|
saveCharacterData(session, 100, "test_col", data, 100)
|
||||||
|
|
||||||
|
// Should save and ack
|
||||||
|
if saved := charRepo.columns["test_col"]; saved == nil {
|
||||||
|
t.Error("Data should be saved to repo")
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case pkt := <-session.sendPackets:
|
||||||
|
if pkt.data == nil {
|
||||||
|
t.Fatal("Response packet should have data")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response packet queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSaveCharacterData_TooLarge(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
data := make([]byte, 200)
|
||||||
|
saveCharacterData(session, 100, "test_col", data, 50)
|
||||||
|
|
||||||
|
// Should fail with ack
|
||||||
|
if _, ok := charRepo.columns["test_col"]; ok {
|
||||||
|
t.Error("Data should NOT be saved when too large")
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case pkt := <-session.sendPackets:
|
||||||
|
if pkt.data == nil {
|
||||||
|
t.Fatal("Response packet should have data")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("Should queue a fail ack")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSaveCharacterData_SaveError(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
charRepo.saveErr = errors.New("save failed")
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
data := []byte{0x01}
|
||||||
|
saveCharacterData(session, 100, "test_col", data, 100)
|
||||||
|
|
||||||
|
// Should still queue a fail ack
|
||||||
|
select {
|
||||||
|
case pkt := <-session.sendPackets:
|
||||||
|
if pkt.data == nil {
|
||||||
|
t.Fatal("Response packet should have data")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("Should queue a fail ack on save error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSaveCharacterData_NoMaxSize(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
data := make([]byte, 5000)
|
||||||
|
saveCharacterData(session, 100, "test_col", data, 0)
|
||||||
|
|
||||||
|
// maxSize=0 means no limit
|
||||||
|
if saved := charRepo.columns["test_col"]; saved == nil {
|
||||||
|
t.Error("Data should be saved when maxSize is 0 (no limit)")
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-session.sendPackets:
|
||||||
|
default:
|
||||||
|
t.Fatal("Should queue success ack")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDoAckEarthSucceed(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.erupeConfig.EarthID = 42
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
doAckEarthSucceed(session, 100, nil)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case pkt := <-session.sendPackets:
|
||||||
|
if pkt.data == nil {
|
||||||
|
t.Fatal("Response should have data")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("Should queue a packet")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateRights(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
userRepo := &mockUserRepoGacha{}
|
||||||
|
userRepo.rights = 30
|
||||||
|
server.userRepo = userRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
updateRights(session)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case pkt := <-session.sendPackets:
|
||||||
|
if pkt.data == nil {
|
||||||
|
t.Fatal("Should queue MsgSysUpdateRight")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("updateRights should queue a packet")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateRights_Error(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
userRepo := &mockUserRepoGacha{rightsErr: errors.New("db error")}
|
||||||
|
server.userRepo = userRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
// Should not panic, falls back to rights=2
|
||||||
|
updateRights(session)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case pkt := <-session.sendPackets:
|
||||||
|
if pkt.data == nil {
|
||||||
|
t.Fatal("Should queue MsgSysUpdateRight even on error")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("updateRights should queue a packet even on error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
186
server/channelserver/handlers_kouryou_test.go
Normal file
186
server/channelserver/handlers_kouryou_test.go
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
package channelserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"erupe-ce/network/mhfpacket"
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseAckBufData extracts AckData from a serialized MsgSysAck buffer response.
|
||||||
|
// Wire format: opcode(2) + ackHandle(4) + isBuffer(1) + errorCode(1) + dataLen(2) + data(N)
|
||||||
|
func parseAckBufData(t *testing.T, raw []byte) (ackHandle uint32, errorCode uint8, ackData []byte) {
|
||||||
|
t.Helper()
|
||||||
|
if len(raw) < 10 {
|
||||||
|
t.Fatalf("raw packet too short: %d bytes", len(raw))
|
||||||
|
}
|
||||||
|
ackHandle = binary.BigEndian.Uint32(raw[2:6])
|
||||||
|
isBuffer := raw[6]
|
||||||
|
errorCode = raw[7]
|
||||||
|
if isBuffer == 0 {
|
||||||
|
t.Fatal("Expected buffer response, got simple ack")
|
||||||
|
}
|
||||||
|
dataLen := binary.BigEndian.Uint16(raw[8:10])
|
||||||
|
if int(dataLen) > len(raw)-10 {
|
||||||
|
t.Fatalf("data len %d exceeds remaining bytes %d", dataLen, len(raw)-10)
|
||||||
|
}
|
||||||
|
ackData = raw[10 : 10+dataLen]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfGetKouryouPoint(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
charRepo.ints["kouryou_point"] = 500
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfGetKouryouPoint{AckHandle: 100}
|
||||||
|
handleMsgMhfGetKouryouPoint(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, errCode, ackData := parseAckBufData(t, p.data)
|
||||||
|
if errCode != 0 {
|
||||||
|
t.Errorf("ErrorCode = %d, want 0", errCode)
|
||||||
|
}
|
||||||
|
if len(ackData) < 4 {
|
||||||
|
t.Fatal("AckData too short")
|
||||||
|
}
|
||||||
|
points := binary.BigEndian.Uint32(ackData[:4])
|
||||||
|
if points != 500 {
|
||||||
|
t.Errorf("points = %d, want 500", points)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfGetKouryouPoint_Error(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
charRepo.readErr = errors.New("db error")
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfGetKouryouPoint{AckHandle: 100}
|
||||||
|
handleMsgMhfGetKouryouPoint(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, _, ackData := parseAckBufData(t, p.data)
|
||||||
|
points := binary.BigEndian.Uint32(ackData[:4])
|
||||||
|
if points != 0 {
|
||||||
|
t.Errorf("points = %d, want 0 on error", points)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfAddKouryouPoint(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
charRepo.ints["kouryou_point"] = 100
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfAddKouryouPoint{
|
||||||
|
AckHandle: 200,
|
||||||
|
KouryouPoints: 50,
|
||||||
|
}
|
||||||
|
handleMsgMhfAddKouryouPoint(session, pkt)
|
||||||
|
|
||||||
|
if charRepo.ints["kouryou_point"] != 150 {
|
||||||
|
t.Errorf("kouryou_point = %d, want 150", charRepo.ints["kouryou_point"])
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, _, ackData := parseAckBufData(t, p.data)
|
||||||
|
points := binary.BigEndian.Uint32(ackData[:4])
|
||||||
|
if points != 150 {
|
||||||
|
t.Errorf("response points = %d, want 150", points)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfAddKouryouPoint_Error(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
charRepo.adjustErr = errors.New("db error")
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfAddKouryouPoint{
|
||||||
|
AckHandle: 200,
|
||||||
|
KouryouPoints: 50,
|
||||||
|
}
|
||||||
|
handleMsgMhfAddKouryouPoint(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, _, ackData := parseAckBufData(t, p.data)
|
||||||
|
points := binary.BigEndian.Uint32(ackData[:4])
|
||||||
|
if points != 0 {
|
||||||
|
t.Errorf("response points = %d, want 0 on error", points)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfExchangeKouryouPoint(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
charRepo.ints["kouryou_point"] = 10000
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfExchangeKouryouPoint{
|
||||||
|
AckHandle: 300,
|
||||||
|
KouryouPoints: 10000,
|
||||||
|
}
|
||||||
|
handleMsgMhfExchangeKouryouPoint(session, pkt)
|
||||||
|
|
||||||
|
if charRepo.ints["kouryou_point"] != 0 {
|
||||||
|
t.Errorf("kouryou_point = %d, want 0 after exchange", charRepo.ints["kouryou_point"])
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, _, ackData := parseAckBufData(t, p.data)
|
||||||
|
points := binary.BigEndian.Uint32(ackData[:4])
|
||||||
|
if points != 0 {
|
||||||
|
t.Errorf("response points = %d, want 0", points)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfExchangeKouryouPoint_Error(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
charRepo := newMockCharacterRepo()
|
||||||
|
charRepo.adjustErr = errors.New("db error")
|
||||||
|
server.charRepo = charRepo
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfExchangeKouryouPoint{
|
||||||
|
AckHandle: 300,
|
||||||
|
KouryouPoints: 5000,
|
||||||
|
}
|
||||||
|
handleMsgMhfExchangeKouryouPoint(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
if len(p.data) == 0 {
|
||||||
|
t.Fatal("Should still respond on error")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
177
server/channelserver/handlers_scenario_test.go
Normal file
177
server/channelserver/handlers_scenario_test.go
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
package channelserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"erupe-ce/network/mhfpacket"
|
||||||
|
)
|
||||||
|
|
||||||
|
// --- mockScenarioRepo ---
|
||||||
|
|
||||||
|
type mockScenarioRepo struct {
|
||||||
|
scenarios []Scenario
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockScenarioRepo) GetCounters() ([]Scenario, error) {
|
||||||
|
return m.scenarios, m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfInfoScenarioCounter_Empty(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.scenarioRepo = &mockScenarioRepo{}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfInfoScenarioCounter{AckHandle: 100}
|
||||||
|
handleMsgMhfInfoScenarioCounter(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, errCode, ackData := parseAckBufData(t, p.data)
|
||||||
|
if errCode != 0 {
|
||||||
|
t.Errorf("ErrorCode = %d, want 0", errCode)
|
||||||
|
}
|
||||||
|
if len(ackData) < 1 {
|
||||||
|
t.Fatal("AckData too short")
|
||||||
|
}
|
||||||
|
if ackData[0] != 0 {
|
||||||
|
t.Errorf("scenario count = %d, want 0", ackData[0])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfInfoScenarioCounter_WithScenarios(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.scenarioRepo = &mockScenarioRepo{
|
||||||
|
scenarios: []Scenario{
|
||||||
|
{MainID: 1000, CategoryID: 0},
|
||||||
|
{MainID: 2000, CategoryID: 3},
|
||||||
|
{MainID: 3000, CategoryID: 6},
|
||||||
|
{MainID: 4000, CategoryID: 7},
|
||||||
|
{MainID: 5000, CategoryID: 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfInfoScenarioCounter{AckHandle: 100}
|
||||||
|
handleMsgMhfInfoScenarioCounter(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, _, data := parseAckBufData(t, p.data)
|
||||||
|
if len(data) < 1 {
|
||||||
|
t.Fatal("AckData too short")
|
||||||
|
}
|
||||||
|
count := data[0]
|
||||||
|
if count != 5 {
|
||||||
|
t.Errorf("scenario count = %d, want 5", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each scenario: mainID(4) + exchange(1) + categoryID(1) = 6 bytes
|
||||||
|
expectedLen := 1 + 5*6
|
||||||
|
if len(data) != expectedLen {
|
||||||
|
t.Errorf("AckData len = %d, want %d", len(data), expectedLen)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify first scenario (categoryID=0, exchange=false)
|
||||||
|
mainID := binary.BigEndian.Uint32(data[1:5])
|
||||||
|
if mainID != 1000 {
|
||||||
|
t.Errorf("first mainID = %d, want 1000", mainID)
|
||||||
|
}
|
||||||
|
if data[5] != 0 {
|
||||||
|
t.Errorf("categoryID=0 should have exchange=false, got %d", data[5])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify second scenario (categoryID=3, exchange=true)
|
||||||
|
if data[5+6] != 1 {
|
||||||
|
t.Errorf("categoryID=3 should have exchange=true, got %d", data[5+6])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfInfoScenarioCounter_TrimTo128(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
scenarios := make([]Scenario, 200)
|
||||||
|
for i := range scenarios {
|
||||||
|
scenarios[i] = Scenario{MainID: uint32(i), CategoryID: 0}
|
||||||
|
}
|
||||||
|
server.scenarioRepo = &mockScenarioRepo{scenarios: scenarios}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfInfoScenarioCounter{AckHandle: 100}
|
||||||
|
handleMsgMhfInfoScenarioCounter(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, _, data := parseAckBufData(t, p.data)
|
||||||
|
if data[0] != 128 {
|
||||||
|
t.Errorf("scenario count = %d, want 128 (trimmed)", data[0])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfInfoScenarioCounter_DBError(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.scenarioRepo = &mockScenarioRepo{err: errors.New("db error")}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfInfoScenarioCounter{AckHandle: 100}
|
||||||
|
handleMsgMhfInfoScenarioCounter(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
if len(p.data) == 0 {
|
||||||
|
t.Fatal("Should still respond on error")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleMsgMhfInfoScenarioCounter_CategoryExchangeFlags(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
categoryID uint8
|
||||||
|
wantExch bool
|
||||||
|
}{
|
||||||
|
{"Basic", 0, false},
|
||||||
|
{"Veteran", 1, false},
|
||||||
|
{"Other (exchange)", 3, true},
|
||||||
|
{"Pallone (exchange)", 6, true},
|
||||||
|
{"Diva (exchange)", 7, true},
|
||||||
|
{"Unknown category 2", 2, false},
|
||||||
|
{"Unknown category 4", 4, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
server := createMockServer()
|
||||||
|
server.scenarioRepo = &mockScenarioRepo{
|
||||||
|
scenarios: []Scenario{{MainID: 1, CategoryID: tt.categoryID}},
|
||||||
|
}
|
||||||
|
session := createMockSession(1, server)
|
||||||
|
|
||||||
|
pkt := &mhfpacket.MsgMhfInfoScenarioCounter{AckHandle: 100}
|
||||||
|
handleMsgMhfInfoScenarioCounter(session, pkt)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case p := <-session.sendPackets:
|
||||||
|
_, _, data := parseAckBufData(t, p.data)
|
||||||
|
isExchange := data[5] != 0
|
||||||
|
if isExchange != tt.wantExch {
|
||||||
|
t.Errorf("exchange = %v, want %v for categoryID=%d", isExchange, tt.wantExch, tt.categoryID)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
t.Fatal("No response queued")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
228
server/channelserver/handlers_seibattle_test.go
Normal file
228
server/channelserver/handlers_seibattle_test.go
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user