mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
Import 18 network packet test files and 5 server infrastructure test files, adapted for main branch APIs: fix config import alias (_config), remove non-existent DevMode field, use global handlerTable instead of per-server handlers map, and correct validateToken mock expectations to include both token and tokenID arguments. Adds go-sqlmock dependency for database mocking in signserver tests.
217 lines
6.5 KiB
Go
217 lines
6.5 KiB
Go
package mhfpacket
|
|
|
|
import (
|
|
"io"
|
|
"testing"
|
|
|
|
"erupe-ce/common/byteframe"
|
|
"erupe-ce/network/clientctx"
|
|
)
|
|
|
|
// TestParseSmallNotImplemented tests Parse for packets whose Parse method returns
|
|
// "NOT IMPLEMENTED". We verify that Parse returns a non-nil error and does not panic.
|
|
func TestParseSmallNotImplemented(t *testing.T) {
|
|
packets := []struct {
|
|
name string
|
|
pkt MHFPacket
|
|
}{
|
|
// MHF packets - NOT IMPLEMENTED
|
|
{"MsgMhfAcceptReadReward", &MsgMhfAcceptReadReward{}},
|
|
{"MsgMhfAddRewardSongCount", &MsgMhfAddRewardSongCount{}},
|
|
{"MsgMhfDebugPostValue", &MsgMhfDebugPostValue{}},
|
|
{"MsgMhfEnterTournamentQuest", &MsgMhfEnterTournamentQuest{}},
|
|
{"MsgMhfGetCaAchievementHist", &MsgMhfGetCaAchievementHist{}},
|
|
{"MsgMhfGetCaUniqueID", &MsgMhfGetCaUniqueID{}},
|
|
{"MsgMhfGetDailyMissionMaster", &MsgMhfGetDailyMissionMaster{}},
|
|
{"MsgMhfGetDailyMissionPersonal", &MsgMhfGetDailyMissionPersonal{}},
|
|
{"MsgMhfGetExtraInfo", &MsgMhfGetExtraInfo{}},
|
|
{"MsgMhfGetRestrictionEvent", &MsgMhfGetRestrictionEvent{}},
|
|
{"MsgMhfKickExportForce", &MsgMhfKickExportForce{}},
|
|
{"MsgMhfPaymentAchievement", &MsgMhfPaymentAchievement{}},
|
|
{"MsgMhfPostRyoudama", &MsgMhfPostRyoudama{}},
|
|
{"MsgMhfRegistSpabiTime", &MsgMhfRegistSpabiTime{}},
|
|
{"MsgMhfResetAchievement", &MsgMhfResetAchievement{}},
|
|
{"MsgMhfResetTitle", &MsgMhfResetTitle{}},
|
|
{"MsgMhfSetCaAchievement", &MsgMhfSetCaAchievement{}},
|
|
{"MsgMhfSetDailyMissionPersonal", &MsgMhfSetDailyMissionPersonal{}},
|
|
{"MsgMhfSetUdTacticsFollower", &MsgMhfSetUdTacticsFollower{}},
|
|
{"MsgMhfStampcardPrize", &MsgMhfStampcardPrize{}},
|
|
{"MsgMhfUpdateForceGuildRank", &MsgMhfUpdateForceGuildRank{}},
|
|
{"MsgMhfUseUdShopCoin", &MsgMhfUseUdShopCoin{}},
|
|
|
|
// SYS packets - NOT IMPLEMENTED
|
|
{"MsgSysAuthData", &MsgSysAuthData{}},
|
|
{"MsgSysAuthQuery", &MsgSysAuthQuery{}},
|
|
{"MsgSysAuthTerminal", &MsgSysAuthTerminal{}},
|
|
{"MsgSysCloseMutex", &MsgSysCloseMutex{}},
|
|
{"MsgSysCollectBinary", &MsgSysCollectBinary{}},
|
|
{"MsgSysCreateMutex", &MsgSysCreateMutex{}},
|
|
{"MsgSysCreateOpenMutex", &MsgSysCreateOpenMutex{}},
|
|
{"MsgSysDeleteMutex", &MsgSysDeleteMutex{}},
|
|
{"MsgSysEnumlobby", &MsgSysEnumlobby{}},
|
|
{"MsgSysEnumuser", &MsgSysEnumuser{}},
|
|
{"MsgSysGetObjectBinary", &MsgSysGetObjectBinary{}},
|
|
{"MsgSysGetState", &MsgSysGetState{}},
|
|
{"MsgSysInfokyserver", &MsgSysInfokyserver{}},
|
|
{"MsgSysOpenMutex", &MsgSysOpenMutex{}},
|
|
{"MsgSysRotateObject", &MsgSysRotateObject{}},
|
|
{"MsgSysSerialize", &MsgSysSerialize{}},
|
|
{"MsgSysTransBinary", &MsgSysTransBinary{}},
|
|
}
|
|
|
|
ctx := &clientctx.ClientContext{}
|
|
for _, tc := range packets {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
bf := byteframe.NewByteFrame()
|
|
// Write some padding bytes so Parse has data available if it tries to read.
|
|
bf.WriteUint32(0)
|
|
bf.Seek(0, io.SeekStart)
|
|
|
|
err := tc.pkt.Parse(bf, ctx)
|
|
if err == nil {
|
|
t.Fatalf("Parse() expected error for NOT IMPLEMENTED packet, got nil")
|
|
}
|
|
if err.Error() != "NOT IMPLEMENTED" {
|
|
t.Fatalf("Parse() error = %q, want %q", err.Error(), "NOT IMPLEMENTED")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestParseSmallNoData tests Parse for packets with no fields that return nil.
|
|
func TestParseSmallNoData(t *testing.T) {
|
|
packets := []struct {
|
|
name string
|
|
pkt MHFPacket
|
|
}{
|
|
{"MsgSysCleanupObject", &MsgSysCleanupObject{}},
|
|
{"MsgSysUnreserveStage", &MsgSysUnreserveStage{}},
|
|
}
|
|
|
|
ctx := &clientctx.ClientContext{}
|
|
for _, tc := range packets {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
bf := byteframe.NewByteFrame()
|
|
err := tc.pkt.Parse(bf, ctx)
|
|
if err != nil {
|
|
t.Fatalf("Parse() error = %v, want nil", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestParseSmallLogout tests Parse for MsgSysLogout which reads a single uint8 field.
|
|
func TestParseSmallLogout(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
unk0 uint8
|
|
}{
|
|
{"hardcoded 1", 1},
|
|
{"zero", 0},
|
|
{"max", 255},
|
|
}
|
|
|
|
ctx := &clientctx.ClientContext{}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
bf := byteframe.NewByteFrame()
|
|
bf.WriteUint8(tt.unk0)
|
|
bf.Seek(0, io.SeekStart)
|
|
|
|
pkt := &MsgSysLogout{}
|
|
err := pkt.Parse(bf, ctx)
|
|
if err != nil {
|
|
t.Fatalf("Parse() error = %v", err)
|
|
}
|
|
if pkt.Unk0 != tt.unk0 {
|
|
t.Errorf("Unk0 = %d, want %d", pkt.Unk0, tt.unk0)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestParseSmallEnumerateHouse tests Parse for MsgMhfEnumerateHouse which reads
|
|
// AckHandle, CharID, Method, Unk, lenName, and optional Name.
|
|
func TestParseSmallEnumerateHouse(t *testing.T) {
|
|
ctx := &clientctx.ClientContext{}
|
|
|
|
t.Run("no name", func(t *testing.T) {
|
|
bf := byteframe.NewByteFrame()
|
|
bf.WriteUint32(0x11223344) // AckHandle
|
|
bf.WriteUint32(0xDEADBEEF) // CharID
|
|
bf.WriteUint8(2) // Method
|
|
bf.WriteUint16(100) // Unk
|
|
bf.WriteUint8(0) // lenName = 0 (no name)
|
|
bf.Seek(0, io.SeekStart)
|
|
|
|
pkt := &MsgMhfEnumerateHouse{}
|
|
err := pkt.Parse(bf, ctx)
|
|
if err != nil {
|
|
t.Fatalf("Parse() error = %v", err)
|
|
}
|
|
if pkt.AckHandle != 0x11223344 {
|
|
t.Errorf("AckHandle = 0x%X, want 0x11223344", pkt.AckHandle)
|
|
}
|
|
if pkt.CharID != 0xDEADBEEF {
|
|
t.Errorf("CharID = 0x%X, want 0xDEADBEEF", pkt.CharID)
|
|
}
|
|
if pkt.Method != 2 {
|
|
t.Errorf("Method = %d, want 2", pkt.Method)
|
|
}
|
|
if pkt.Name != "" {
|
|
t.Errorf("Name = %q, want empty", pkt.Name)
|
|
}
|
|
})
|
|
|
|
t.Run("with name", func(t *testing.T) {
|
|
bf := byteframe.NewByteFrame()
|
|
bf.WriteUint32(1) // AckHandle
|
|
bf.WriteUint32(42) // CharID
|
|
bf.WriteUint8(1) // Method
|
|
bf.WriteUint16(200) // Unk
|
|
// The name is SJIS null-terminated bytes. Use ASCII-compatible bytes.
|
|
nameBytes := []byte("Test\x00")
|
|
bf.WriteUint8(uint8(len(nameBytes))) // lenName > 0
|
|
bf.WriteBytes(nameBytes) // null-terminated name
|
|
bf.Seek(0, io.SeekStart)
|
|
|
|
pkt := &MsgMhfEnumerateHouse{}
|
|
err := pkt.Parse(bf, ctx)
|
|
if err != nil {
|
|
t.Fatalf("Parse() error = %v", err)
|
|
}
|
|
if pkt.AckHandle != 1 {
|
|
t.Errorf("AckHandle = %d, want 1", pkt.AckHandle)
|
|
}
|
|
if pkt.CharID != 42 {
|
|
t.Errorf("CharID = %d, want 42", pkt.CharID)
|
|
}
|
|
if pkt.Method != 1 {
|
|
t.Errorf("Method = %d, want 1", pkt.Method)
|
|
}
|
|
if pkt.Name != "Test" {
|
|
t.Errorf("Name = %q, want %q", pkt.Name, "Test")
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestParseSmallNotImplementedDoesNotPanic ensures that calling Parse on NOT IMPLEMENTED
|
|
// packets with a nil ClientContext does not cause a nil pointer dereference panic.
|
|
func TestParseSmallNotImplementedDoesNotPanic(t *testing.T) {
|
|
packets := []MHFPacket{
|
|
&MsgMhfAcceptReadReward{},
|
|
&MsgSysAuthData{},
|
|
&MsgSysSerialize{},
|
|
}
|
|
|
|
for _, pkt := range packets {
|
|
t.Run("nil_ctx", func(t *testing.T) {
|
|
bf := byteframe.NewByteFrame()
|
|
err := pkt.Parse(bf, nil)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
})
|
|
}
|
|
}
|