mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 07:32:32 +01:00
test: backport remaining test files from v9.2.x-stable
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.
This commit is contained in:
430
network/binpacket/binpacket_test.go
Normal file
430
network/binpacket/binpacket_test.go
Normal file
@@ -0,0 +1,430 @@
|
||||
package binpacket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
)
|
||||
|
||||
func TestMsgBinTargetedOpcode(t *testing.T) {
|
||||
m := &MsgBinTargeted{}
|
||||
if m.Opcode() != network.MSG_SYS_CAST_BINARY {
|
||||
t.Errorf("MsgBinTargeted.Opcode() = %v, want MSG_SYS_CAST_BINARY", m.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinTargetedParseEmpty(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(0) // TargetCount = 0
|
||||
|
||||
bf.Seek(0, 0)
|
||||
|
||||
m := &MsgBinTargeted{}
|
||||
err := m.Parse(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if m.TargetCount != 0 {
|
||||
t.Errorf("TargetCount = %d, want 0", m.TargetCount)
|
||||
}
|
||||
if len(m.TargetCharIDs) != 0 {
|
||||
t.Errorf("TargetCharIDs len = %d, want 0", len(m.TargetCharIDs))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinTargetedParseSingleTarget(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(1) // TargetCount = 1
|
||||
bf.WriteUint32(0x12345678) // TargetCharID
|
||||
bf.WriteBytes([]byte{0xDE, 0xAD, 0xBE, 0xEF})
|
||||
|
||||
bf.Seek(0, 0)
|
||||
|
||||
m := &MsgBinTargeted{}
|
||||
err := m.Parse(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if m.TargetCount != 1 {
|
||||
t.Errorf("TargetCount = %d, want 1", m.TargetCount)
|
||||
}
|
||||
if len(m.TargetCharIDs) != 1 {
|
||||
t.Errorf("TargetCharIDs len = %d, want 1", len(m.TargetCharIDs))
|
||||
}
|
||||
if m.TargetCharIDs[0] != 0x12345678 {
|
||||
t.Errorf("TargetCharIDs[0] = %x, want 0x12345678", m.TargetCharIDs[0])
|
||||
}
|
||||
if !bytes.Equal(m.RawDataPayload, []byte{0xDE, 0xAD, 0xBE, 0xEF}) {
|
||||
t.Errorf("RawDataPayload = %v, want [0xDE, 0xAD, 0xBE, 0xEF]", m.RawDataPayload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinTargetedParseMultipleTargets(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(3) // TargetCount = 3
|
||||
bf.WriteUint32(100)
|
||||
bf.WriteUint32(200)
|
||||
bf.WriteUint32(300)
|
||||
bf.WriteBytes([]byte{0x01, 0x02, 0x03})
|
||||
|
||||
bf.Seek(0, 0)
|
||||
|
||||
m := &MsgBinTargeted{}
|
||||
err := m.Parse(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if m.TargetCount != 3 {
|
||||
t.Errorf("TargetCount = %d, want 3", m.TargetCount)
|
||||
}
|
||||
if len(m.TargetCharIDs) != 3 {
|
||||
t.Errorf("TargetCharIDs len = %d, want 3", len(m.TargetCharIDs))
|
||||
}
|
||||
if m.TargetCharIDs[0] != 100 || m.TargetCharIDs[1] != 200 || m.TargetCharIDs[2] != 300 {
|
||||
t.Errorf("TargetCharIDs = %v, want [100, 200, 300]", m.TargetCharIDs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinTargetedBuild(t *testing.T) {
|
||||
m := &MsgBinTargeted{
|
||||
TargetCount: 2,
|
||||
TargetCharIDs: []uint32{0x11111111, 0x22222222},
|
||||
RawDataPayload: []byte{0xAA, 0xBB},
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := m.Build(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
expected := []byte{
|
||||
0x00, 0x02, // TargetCount
|
||||
0x11, 0x11, 0x11, 0x11, // TargetCharIDs[0]
|
||||
0x22, 0x22, 0x22, 0x22, // TargetCharIDs[1]
|
||||
0xAA, 0xBB, // RawDataPayload
|
||||
}
|
||||
|
||||
if !bytes.Equal(bf.Data(), expected) {
|
||||
t.Errorf("Build() = %v, want %v", bf.Data(), expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinTargetedRoundTrip(t *testing.T) {
|
||||
original := &MsgBinTargeted{
|
||||
TargetCount: 3,
|
||||
TargetCharIDs: []uint32{1000, 2000, 3000},
|
||||
RawDataPayload: []byte{0x01, 0x02, 0x03, 0x04, 0x05},
|
||||
}
|
||||
|
||||
// Build
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Parse
|
||||
bf.Seek(0, 0)
|
||||
parsed := &MsgBinTargeted{}
|
||||
err = parsed.Parse(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
// Compare
|
||||
if parsed.TargetCount != original.TargetCount {
|
||||
t.Errorf("TargetCount = %d, want %d", parsed.TargetCount, original.TargetCount)
|
||||
}
|
||||
if len(parsed.TargetCharIDs) != len(original.TargetCharIDs) {
|
||||
t.Errorf("TargetCharIDs len = %d, want %d", len(parsed.TargetCharIDs), len(original.TargetCharIDs))
|
||||
}
|
||||
for i := range original.TargetCharIDs {
|
||||
if parsed.TargetCharIDs[i] != original.TargetCharIDs[i] {
|
||||
t.Errorf("TargetCharIDs[%d] = %d, want %d", i, parsed.TargetCharIDs[i], original.TargetCharIDs[i])
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(parsed.RawDataPayload, original.RawDataPayload) {
|
||||
t.Errorf("RawDataPayload = %v, want %v", parsed.RawDataPayload, original.RawDataPayload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinMailNotifyOpcode(t *testing.T) {
|
||||
m := MsgBinMailNotify{}
|
||||
if m.Opcode() != network.MSG_SYS_CASTED_BINARY {
|
||||
t.Errorf("MsgBinMailNotify.Opcode() = %v, want MSG_SYS_CASTED_BINARY", m.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinMailNotifyBuild(t *testing.T) {
|
||||
m := MsgBinMailNotify{
|
||||
SenderName: "TestPlayer",
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := m.Build(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
data := bf.Data()
|
||||
|
||||
// First byte should be 0x01 (Unk)
|
||||
if data[0] != 0x01 {
|
||||
t.Errorf("First byte = %x, want 0x01", data[0])
|
||||
}
|
||||
|
||||
// Total length should be 1 (Unk) + 21 (padded name) = 22
|
||||
if len(data) != 22 {
|
||||
t.Errorf("Data len = %d, want 22", len(data))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinMailNotifyBuildEmptyName(t *testing.T) {
|
||||
m := MsgBinMailNotify{
|
||||
SenderName: "",
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := m.Build(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
if len(bf.Data()) != 22 {
|
||||
t.Errorf("Data len = %d, want 22", len(bf.Data()))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinChatOpcode(t *testing.T) {
|
||||
m := &MsgBinChat{}
|
||||
if m.Opcode() != network.MSG_SYS_CAST_BINARY {
|
||||
t.Errorf("MsgBinChat.Opcode() = %v, want MSG_SYS_CAST_BINARY", m.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinChatTypes(t *testing.T) {
|
||||
tests := []struct {
|
||||
chatType ChatType
|
||||
value uint8
|
||||
}{
|
||||
{ChatTypeStage, 1},
|
||||
{ChatTypeGuild, 2},
|
||||
{ChatTypeAlliance, 3},
|
||||
{ChatTypeParty, 4},
|
||||
{ChatTypeWhisper, 5},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
if uint8(tt.chatType) != tt.value {
|
||||
t.Errorf("ChatType %v = %d, want %d", tt.chatType, uint8(tt.chatType), tt.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinChatBuildParse(t *testing.T) {
|
||||
original := &MsgBinChat{
|
||||
Unk0: 0x00,
|
||||
Type: ChatTypeStage,
|
||||
Flags: 0x0000,
|
||||
Message: "Hello",
|
||||
SenderName: "Player",
|
||||
}
|
||||
|
||||
// Build
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Parse
|
||||
bf.Seek(0, 0)
|
||||
parsed := &MsgBinChat{}
|
||||
err = parsed.Parse(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
// Compare
|
||||
if parsed.Unk0 != original.Unk0 {
|
||||
t.Errorf("Unk0 = %d, want %d", parsed.Unk0, original.Unk0)
|
||||
}
|
||||
if parsed.Type != original.Type {
|
||||
t.Errorf("Type = %d, want %d", parsed.Type, original.Type)
|
||||
}
|
||||
if parsed.Flags != original.Flags {
|
||||
t.Errorf("Flags = %d, want %d", parsed.Flags, original.Flags)
|
||||
}
|
||||
if parsed.Message != original.Message {
|
||||
t.Errorf("Message = %q, want %q", parsed.Message, original.Message)
|
||||
}
|
||||
if parsed.SenderName != original.SenderName {
|
||||
t.Errorf("SenderName = %q, want %q", parsed.SenderName, original.SenderName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinChatBuildParseJapanese(t *testing.T) {
|
||||
original := &MsgBinChat{
|
||||
Unk0: 0x00,
|
||||
Type: ChatTypeGuild,
|
||||
Flags: 0x0001,
|
||||
Message: "こんにちは",
|
||||
SenderName: "テスト",
|
||||
}
|
||||
|
||||
// Build
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Parse
|
||||
bf.Seek(0, 0)
|
||||
parsed := &MsgBinChat{}
|
||||
err = parsed.Parse(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if parsed.Message != original.Message {
|
||||
t.Errorf("Message = %q, want %q", parsed.Message, original.Message)
|
||||
}
|
||||
if parsed.SenderName != original.SenderName {
|
||||
t.Errorf("SenderName = %q, want %q", parsed.SenderName, original.SenderName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinChatBuildParseEmpty(t *testing.T) {
|
||||
original := &MsgBinChat{
|
||||
Unk0: 0x00,
|
||||
Type: ChatTypeParty,
|
||||
Flags: 0x0000,
|
||||
Message: "",
|
||||
SenderName: "",
|
||||
}
|
||||
|
||||
// Build
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Parse
|
||||
bf.Seek(0, 0)
|
||||
parsed := &MsgBinChat{}
|
||||
err = parsed.Parse(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if parsed.Message != "" {
|
||||
t.Errorf("Message = %q, want empty", parsed.Message)
|
||||
}
|
||||
if parsed.SenderName != "" {
|
||||
t.Errorf("SenderName = %q, want empty", parsed.SenderName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinChatBuildFormat(t *testing.T) {
|
||||
m := &MsgBinChat{
|
||||
Unk0: 0x12,
|
||||
Type: ChatTypeWhisper,
|
||||
Flags: 0x3456,
|
||||
Message: "Hi",
|
||||
SenderName: "A",
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := m.Build(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
data := bf.Data()
|
||||
|
||||
// Verify header structure
|
||||
if data[0] != 0x12 {
|
||||
t.Errorf("Unk0 = %x, want 0x12", data[0])
|
||||
}
|
||||
if data[1] != uint8(ChatTypeWhisper) {
|
||||
t.Errorf("Type = %x, want %x", data[1], uint8(ChatTypeWhisper))
|
||||
}
|
||||
// Flags at bytes 2-3 (big endian)
|
||||
if data[2] != 0x34 || data[3] != 0x56 {
|
||||
t.Errorf("Flags = %x%x, want 3456", data[2], data[3])
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinChatAllTypes(t *testing.T) {
|
||||
types := []ChatType{
|
||||
ChatTypeStage,
|
||||
ChatTypeGuild,
|
||||
ChatTypeAlliance,
|
||||
ChatTypeParty,
|
||||
ChatTypeWhisper,
|
||||
}
|
||||
|
||||
for _, chatType := range types {
|
||||
t.Run("", func(t *testing.T) {
|
||||
original := &MsgBinChat{
|
||||
Type: chatType,
|
||||
Message: "Test",
|
||||
SenderName: "Player",
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
bf.Seek(0, 0)
|
||||
parsed := &MsgBinChat{}
|
||||
err = parsed.Parse(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if parsed.Type != chatType {
|
||||
t.Errorf("Type = %d, want %d", parsed.Type, chatType)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgBinMailNotifyParsePanics(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Error("Parse() should panic with 'implement me'")
|
||||
}
|
||||
}()
|
||||
|
||||
m := MsgBinMailNotify{}
|
||||
bf := byteframe.NewByteFrame()
|
||||
_ = m.Parse(bf)
|
||||
}
|
||||
|
||||
func TestMsgBinMailNotifyBuildLongName(t *testing.T) {
|
||||
m := MsgBinMailNotify{
|
||||
SenderName: "ThisIsAVeryLongPlayerNameThatExceeds21Characters",
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := m.Build(bf)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Data should still be 22 bytes (1 + 21)
|
||||
if len(bf.Data()) != 22 {
|
||||
t.Errorf("Data len = %d, want 22", len(bf.Data()))
|
||||
}
|
||||
}
|
||||
828
network/mhfpacket/mhfpacket_test.go
Normal file
828
network/mhfpacket/mhfpacket_test.go
Normal file
@@ -0,0 +1,828 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
func TestMHFPacketInterface(t *testing.T) {
|
||||
// Verify that packets implement the MHFPacket interface
|
||||
var _ MHFPacket = &MsgSysPing{}
|
||||
var _ MHFPacket = &MsgSysTime{}
|
||||
var _ MHFPacket = &MsgSysNop{}
|
||||
var _ MHFPacket = &MsgSysEnd{}
|
||||
var _ MHFPacket = &MsgSysLogin{}
|
||||
var _ MHFPacket = &MsgSysLogout{}
|
||||
}
|
||||
|
||||
func TestFromOpcodeReturnsCorrectType(t *testing.T) {
|
||||
tests := []struct {
|
||||
opcode network.PacketID
|
||||
wantType string
|
||||
}{
|
||||
{network.MSG_HEAD, "*mhfpacket.MsgHead"},
|
||||
{network.MSG_SYS_PING, "*mhfpacket.MsgSysPing"},
|
||||
{network.MSG_SYS_TIME, "*mhfpacket.MsgSysTime"},
|
||||
{network.MSG_SYS_NOP, "*mhfpacket.MsgSysNop"},
|
||||
{network.MSG_SYS_END, "*mhfpacket.MsgSysEnd"},
|
||||
{network.MSG_SYS_ACK, "*mhfpacket.MsgSysAck"},
|
||||
{network.MSG_SYS_LOGIN, "*mhfpacket.MsgSysLogin"},
|
||||
{network.MSG_SYS_LOGOUT, "*mhfpacket.MsgSysLogout"},
|
||||
{network.MSG_SYS_CREATE_STAGE, "*mhfpacket.MsgSysCreateStage"},
|
||||
{network.MSG_SYS_ENTER_STAGE, "*mhfpacket.MsgSysEnterStage"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(tt.opcode)
|
||||
if pkt == nil {
|
||||
t.Errorf("FromOpcode(%s) returned nil", tt.opcode)
|
||||
return
|
||||
}
|
||||
if pkt.Opcode() != tt.opcode {
|
||||
t.Errorf("Opcode() = %s, want %s", pkt.Opcode(), tt.opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromOpcodeUnknown(t *testing.T) {
|
||||
// Test with an invalid opcode
|
||||
pkt := FromOpcode(network.PacketID(0xFFFF))
|
||||
if pkt != nil {
|
||||
t.Error("FromOpcode(0xFFFF) should return nil for unknown opcode")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysPingRoundTrip(t *testing.T) {
|
||||
original := &MsgSysPing{
|
||||
AckHandle: 0x12345678,
|
||||
}
|
||||
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
// Build
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Parse
|
||||
bf.Seek(0, io.SeekStart)
|
||||
parsed := &MsgSysPing{}
|
||||
err = parsed.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
// Compare
|
||||
if parsed.AckHandle != original.AckHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", parsed.AckHandle, original.AckHandle)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysTimeRoundTrip(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
getRemoteTime bool
|
||||
timestamp uint32
|
||||
}{
|
||||
{"no remote time", false, 1577105879},
|
||||
{"with remote time", true, 1609459200},
|
||||
{"zero timestamp", false, 0},
|
||||
{"max timestamp", true, 0xFFFFFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
original := &MsgSysTime{
|
||||
GetRemoteTime: tt.getRemoteTime,
|
||||
Timestamp: tt.timestamp,
|
||||
}
|
||||
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
// Build
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Parse
|
||||
bf.Seek(0, io.SeekStart)
|
||||
parsed := &MsgSysTime{}
|
||||
err = parsed.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
// Compare
|
||||
if parsed.GetRemoteTime != original.GetRemoteTime {
|
||||
t.Errorf("GetRemoteTime = %v, want %v", parsed.GetRemoteTime, original.GetRemoteTime)
|
||||
}
|
||||
if parsed.Timestamp != original.Timestamp {
|
||||
t.Errorf("Timestamp = %d, want %d", parsed.Timestamp, original.Timestamp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysPingOpcode(t *testing.T) {
|
||||
pkt := &MsgSysPing{}
|
||||
if pkt.Opcode() != network.MSG_SYS_PING {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_PING", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysTimeOpcode(t *testing.T) {
|
||||
pkt := &MsgSysTime{}
|
||||
if pkt.Opcode() != network.MSG_SYS_TIME {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_TIME", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromOpcodeSystemPackets(t *testing.T) {
|
||||
// Test all system packet opcodes return non-nil
|
||||
systemOpcodes := []network.PacketID{
|
||||
network.MSG_SYS_reserve01,
|
||||
network.MSG_SYS_reserve02,
|
||||
network.MSG_SYS_reserve03,
|
||||
network.MSG_SYS_reserve04,
|
||||
network.MSG_SYS_reserve05,
|
||||
network.MSG_SYS_reserve06,
|
||||
network.MSG_SYS_reserve07,
|
||||
network.MSG_SYS_ADD_OBJECT,
|
||||
network.MSG_SYS_DEL_OBJECT,
|
||||
network.MSG_SYS_DISP_OBJECT,
|
||||
network.MSG_SYS_HIDE_OBJECT,
|
||||
network.MSG_SYS_END,
|
||||
network.MSG_SYS_NOP,
|
||||
network.MSG_SYS_ACK,
|
||||
network.MSG_SYS_LOGIN,
|
||||
network.MSG_SYS_LOGOUT,
|
||||
network.MSG_SYS_SET_STATUS,
|
||||
network.MSG_SYS_PING,
|
||||
network.MSG_SYS_TIME,
|
||||
}
|
||||
|
||||
for _, opcode := range systemOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Errorf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromOpcodeStagePackets(t *testing.T) {
|
||||
stageOpcodes := []network.PacketID{
|
||||
network.MSG_SYS_CREATE_STAGE,
|
||||
network.MSG_SYS_STAGE_DESTRUCT,
|
||||
network.MSG_SYS_ENTER_STAGE,
|
||||
network.MSG_SYS_BACK_STAGE,
|
||||
network.MSG_SYS_MOVE_STAGE,
|
||||
network.MSG_SYS_LEAVE_STAGE,
|
||||
network.MSG_SYS_LOCK_STAGE,
|
||||
network.MSG_SYS_UNLOCK_STAGE,
|
||||
network.MSG_SYS_RESERVE_STAGE,
|
||||
network.MSG_SYS_UNRESERVE_STAGE,
|
||||
network.MSG_SYS_SET_STAGE_PASS,
|
||||
}
|
||||
|
||||
for _, opcode := range stageOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Errorf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpcodeMatches(t *testing.T) {
|
||||
// Verify that packets return the same opcode they were created from
|
||||
tests := []network.PacketID{
|
||||
network.MSG_HEAD,
|
||||
network.MSG_SYS_PING,
|
||||
network.MSG_SYS_TIME,
|
||||
network.MSG_SYS_END,
|
||||
network.MSG_SYS_NOP,
|
||||
network.MSG_SYS_ACK,
|
||||
network.MSG_SYS_LOGIN,
|
||||
network.MSG_SYS_CREATE_STAGE,
|
||||
}
|
||||
|
||||
for _, opcode := range tests {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Skip("opcode not implemented")
|
||||
}
|
||||
if pkt.Opcode() != opcode {
|
||||
t.Errorf("Opcode() = %s, want %s", pkt.Opcode(), opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParserInterface(t *testing.T) {
|
||||
// Verify Parser interface works
|
||||
var p Parser = &MsgSysPing{}
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(123)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
err := p.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Errorf("Parse() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderInterface(t *testing.T) {
|
||||
// Verify Builder interface works
|
||||
var b Builder = &MsgSysPing{AckHandle: 456}
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
err := b.Build(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Errorf("Build() error = %v", err)
|
||||
}
|
||||
if len(bf.Data()) == 0 {
|
||||
t.Error("Build() should write data")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpcoderInterface(t *testing.T) {
|
||||
// Verify Opcoder interface works
|
||||
var o Opcoder = &MsgSysPing{}
|
||||
opcode := o.Opcode()
|
||||
|
||||
if opcode != network.MSG_SYS_PING {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_PING", opcode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientContextNilSafe(t *testing.T) {
|
||||
// Some packets may need to handle nil ClientContext
|
||||
pkt := &MsgSysPing{AckHandle: 123}
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
// This should not panic even with nil context (implementation dependent)
|
||||
// Note: The actual behavior depends on implementation
|
||||
err := pkt.Build(bf, nil)
|
||||
if err != nil {
|
||||
// Error is acceptable if nil context is not supported
|
||||
t.Logf("Build() with nil context returned error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysPingBuildFormat(t *testing.T) {
|
||||
pkt := &MsgSysPing{AckHandle: 0x12345678}
|
||||
bf := byteframe.NewByteFrame()
|
||||
pkt.Build(bf, &clientctx.ClientContext{})
|
||||
|
||||
data := bf.Data()
|
||||
if len(data) != 4 {
|
||||
t.Errorf("Build() data len = %d, want 4", len(data))
|
||||
}
|
||||
|
||||
// Verify big-endian format (default)
|
||||
if data[0] != 0x12 || data[1] != 0x34 || data[2] != 0x56 || data[3] != 0x78 {
|
||||
t.Errorf("Build() data = %x, want 12345678", data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysTimeBuildFormat(t *testing.T) {
|
||||
pkt := &MsgSysTime{
|
||||
GetRemoteTime: true,
|
||||
Timestamp: 0xDEADBEEF,
|
||||
}
|
||||
bf := byteframe.NewByteFrame()
|
||||
pkt.Build(bf, &clientctx.ClientContext{})
|
||||
|
||||
data := bf.Data()
|
||||
if len(data) != 5 {
|
||||
t.Errorf("Build() data len = %d, want 5 (1 bool + 4 uint32)", len(data))
|
||||
}
|
||||
|
||||
// First byte is bool (1 = true)
|
||||
if data[0] != 1 {
|
||||
t.Errorf("GetRemoteTime byte = %d, want 1", data[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysNop(t *testing.T) {
|
||||
pkt := FromOpcode(network.MSG_SYS_NOP)
|
||||
if pkt == nil {
|
||||
t.Fatal("FromOpcode(MSG_SYS_NOP) returned nil")
|
||||
}
|
||||
if pkt.Opcode() != network.MSG_SYS_NOP {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_NOP", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysEnd(t *testing.T) {
|
||||
pkt := FromOpcode(network.MSG_SYS_END)
|
||||
if pkt == nil {
|
||||
t.Fatal("FromOpcode(MSG_SYS_END) returned nil")
|
||||
}
|
||||
if pkt.Opcode() != network.MSG_SYS_END {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_END", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgHead(t *testing.T) {
|
||||
pkt := FromOpcode(network.MSG_HEAD)
|
||||
if pkt == nil {
|
||||
t.Fatal("FromOpcode(MSG_HEAD) returned nil")
|
||||
}
|
||||
if pkt.Opcode() != network.MSG_HEAD {
|
||||
t.Errorf("Opcode() = %s, want MSG_HEAD", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysAck(t *testing.T) {
|
||||
pkt := FromOpcode(network.MSG_SYS_ACK)
|
||||
if pkt == nil {
|
||||
t.Fatal("FromOpcode(MSG_SYS_ACK) returned nil")
|
||||
}
|
||||
if pkt.Opcode() != network.MSG_SYS_ACK {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ACK", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBinaryPackets(t *testing.T) {
|
||||
binaryOpcodes := []network.PacketID{
|
||||
network.MSG_SYS_CAST_BINARY,
|
||||
network.MSG_SYS_CASTED_BINARY,
|
||||
network.MSG_SYS_SET_STAGE_BINARY,
|
||||
network.MSG_SYS_GET_STAGE_BINARY,
|
||||
network.MSG_SYS_WAIT_STAGE_BINARY,
|
||||
}
|
||||
|
||||
for _, opcode := range binaryOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Errorf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnumeratePackets(t *testing.T) {
|
||||
enumOpcodes := []network.PacketID{
|
||||
network.MSG_SYS_ENUMERATE_CLIENT,
|
||||
network.MSG_SYS_ENUMERATE_STAGE,
|
||||
}
|
||||
|
||||
for _, opcode := range enumOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Errorf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSemaphorePackets(t *testing.T) {
|
||||
semaOpcodes := []network.PacketID{
|
||||
network.MSG_SYS_CREATE_ACQUIRE_SEMAPHORE,
|
||||
network.MSG_SYS_ACQUIRE_SEMAPHORE,
|
||||
network.MSG_SYS_RELEASE_SEMAPHORE,
|
||||
network.MSG_SYS_CHECK_SEMAPHORE,
|
||||
}
|
||||
|
||||
for _, opcode := range semaOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Errorf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestObjectPackets(t *testing.T) {
|
||||
objOpcodes := []network.PacketID{
|
||||
network.MSG_SYS_ADD_OBJECT,
|
||||
network.MSG_SYS_DEL_OBJECT,
|
||||
network.MSG_SYS_DISP_OBJECT,
|
||||
network.MSG_SYS_HIDE_OBJECT,
|
||||
}
|
||||
|
||||
for _, opcode := range objOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Errorf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogPackets(t *testing.T) {
|
||||
logOpcodes := []network.PacketID{
|
||||
network.MSG_SYS_TERMINAL_LOG,
|
||||
network.MSG_SYS_ISSUE_LOGKEY,
|
||||
network.MSG_SYS_RECORD_LOG,
|
||||
}
|
||||
|
||||
for _, opcode := range logOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Errorf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMHFSaveLoad(t *testing.T) {
|
||||
saveLoadOpcodes := []network.PacketID{
|
||||
network.MSG_MHF_SAVEDATA,
|
||||
network.MSG_MHF_LOADDATA,
|
||||
}
|
||||
|
||||
for _, opcode := range saveLoadOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Errorf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysCreateStageParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
wantHandle uint32
|
||||
wantUnk0 uint8
|
||||
wantPlayers uint8
|
||||
wantStageID string
|
||||
}{
|
||||
{
|
||||
name: "simple stage",
|
||||
data: append([]byte{0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x05}, append([]byte("test"), 0x00)...),
|
||||
wantHandle: 1,
|
||||
wantUnk0: 2,
|
||||
wantPlayers: 4,
|
||||
wantStageID: "test",
|
||||
},
|
||||
{
|
||||
name: "empty stage ID",
|
||||
data: []byte{0x12, 0x34, 0x56, 0x78, 0x01, 0x02, 0x00},
|
||||
wantHandle: 0x12345678,
|
||||
wantUnk0: 1,
|
||||
wantPlayers: 2,
|
||||
wantStageID: "",
|
||||
},
|
||||
{
|
||||
name: "with null terminator",
|
||||
data: append([]byte{0x00, 0x00, 0x00, 0x0A, 0x01, 0x01, 0x08}, append([]byte("stage01"), 0x00)...),
|
||||
wantHandle: 10,
|
||||
wantUnk0: 1,
|
||||
wantPlayers: 1,
|
||||
wantStageID: "stage01",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteBytes(tt.data)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysCreateStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.wantHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.wantHandle)
|
||||
}
|
||||
if pkt.Unk0 != tt.wantUnk0 {
|
||||
t.Errorf("Unk0 = %d, want %d", pkt.Unk0, tt.wantUnk0)
|
||||
}
|
||||
if pkt.PlayerCount != tt.wantPlayers {
|
||||
t.Errorf("PlayerCount = %d, want %d", pkt.PlayerCount, tt.wantPlayers)
|
||||
}
|
||||
if pkt.StageID != tt.wantStageID {
|
||||
t.Errorf("StageID = %q, want %q", pkt.StageID, tt.wantStageID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysEnterStageParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
wantHandle uint32
|
||||
wantUnk bool
|
||||
wantStageID string
|
||||
}{
|
||||
{
|
||||
name: "enter mezeporta",
|
||||
data: append([]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x0F}, append([]byte("sl1Ns200p0a0u0"), 0x00)...),
|
||||
wantHandle: 1,
|
||||
wantUnk: false,
|
||||
wantStageID: "sl1Ns200p0a0u0",
|
||||
},
|
||||
{
|
||||
name: "with unk bool set",
|
||||
data: append([]byte{0xAB, 0xCD, 0xEF, 0x12, 0x01, 0x05}, append([]byte("room1"), 0x00)...),
|
||||
wantHandle: 0xABCDEF12,
|
||||
wantUnk: true,
|
||||
wantStageID: "room1",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteBytes(tt.data)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysEnterStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.wantHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.wantHandle)
|
||||
}
|
||||
if pkt.Unk != tt.wantUnk {
|
||||
t.Errorf("Unk = %v, want %v", pkt.Unk, tt.wantUnk)
|
||||
}
|
||||
if pkt.StageID != tt.wantStageID {
|
||||
t.Errorf("StageID = %q, want %q", pkt.StageID, tt.wantStageID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysMoveStageParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
wantHandle uint32
|
||||
wantUnkBool uint8
|
||||
wantStageID string
|
||||
}{
|
||||
{
|
||||
name: "move to quest stage",
|
||||
data: append([]byte{0x00, 0x00, 0x12, 0x34, 0x00, 0x06}, []byte("quest1")...),
|
||||
wantHandle: 0x1234,
|
||||
wantUnkBool: 0,
|
||||
wantStageID: "quest1",
|
||||
},
|
||||
{
|
||||
name: "with null in string",
|
||||
data: append([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x08}, append([]byte("stage"), []byte{0x00, 0x00, 0x00}...)...),
|
||||
wantHandle: 0xFFFFFFFF,
|
||||
wantUnkBool: 1,
|
||||
wantStageID: "stage",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteBytes(tt.data)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysMoveStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.wantHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.wantHandle)
|
||||
}
|
||||
if pkt.UnkBool != tt.wantUnkBool {
|
||||
t.Errorf("UnkBool = %d, want %d", pkt.UnkBool, tt.wantUnkBool)
|
||||
}
|
||||
if pkt.StageID != tt.wantStageID {
|
||||
t.Errorf("StageID = %q, want %q", pkt.StageID, tt.wantStageID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysLockStageParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
wantHandle uint32
|
||||
wantStageID string
|
||||
}{
|
||||
{
|
||||
name: "lock stage",
|
||||
data: append([]byte{0x00, 0x00, 0x00, 0x05, 0x01, 0x01, 0x06}, append([]byte("room01"), 0x00)...),
|
||||
wantHandle: 5,
|
||||
wantStageID: "room01",
|
||||
},
|
||||
{
|
||||
name: "different unk values",
|
||||
data: append([]byte{0x12, 0x34, 0x56, 0x78, 0x02, 0x03, 0x04}, append([]byte("test"), 0x00)...),
|
||||
wantHandle: 0x12345678,
|
||||
wantStageID: "test",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteBytes(tt.data)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysLockStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.wantHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.wantHandle)
|
||||
}
|
||||
if pkt.StageID != tt.wantStageID {
|
||||
t.Errorf("StageID = %q, want %q", pkt.StageID, tt.wantStageID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysUnlockStageRoundTrip(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
unk0 uint16
|
||||
}{
|
||||
{"zero value", 0},
|
||||
{"typical value", 1},
|
||||
{"max value", 0xFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
// Build (returns NOT IMPLEMENTED)
|
||||
original := &MsgSysUnlockStage{}
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf, ctx)
|
||||
if err == nil {
|
||||
t.Fatal("Build() expected NOT IMPLEMENTED error")
|
||||
}
|
||||
|
||||
// Parse should consume a uint16 without error
|
||||
bf = byteframe.NewByteFrame()
|
||||
bf.WriteUint16(tt.unk0)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
parsed := &MsgSysUnlockStage{}
|
||||
err = parsed.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysBackStageParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
wantHandle uint32
|
||||
}{
|
||||
{"simple handle", []byte{0x00, 0x00, 0x00, 0x01}, 1},
|
||||
{"large handle", []byte{0xDE, 0xAD, 0xBE, 0xEF}, 0xDEADBEEF},
|
||||
{"zero handle", []byte{0x00, 0x00, 0x00, 0x00}, 0},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteBytes(tt.data)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysBackStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.wantHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.wantHandle)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysLogoutParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
wantUnk0 uint8
|
||||
}{
|
||||
{"typical logout", []byte{0x01}, 1},
|
||||
{"zero value", []byte{0x00}, 0},
|
||||
{"max value", []byte{0xFF}, 255},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteBytes(tt.data)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysLogout{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.Unk0 != tt.wantUnk0 {
|
||||
t.Errorf("Unk0 = %d, want %d", pkt.Unk0, tt.wantUnk0)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysLoginParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ackHandle uint32
|
||||
charID0 uint32
|
||||
loginTokenNumber uint32
|
||||
hardcodedZero0 uint16
|
||||
requestVersion uint16
|
||||
charID1 uint32
|
||||
hardcodedZero1 uint16
|
||||
tokenStrLen uint16
|
||||
tokenString string
|
||||
}{
|
||||
{
|
||||
name: "typical login",
|
||||
ackHandle: 1,
|
||||
charID0: 12345,
|
||||
loginTokenNumber: 67890,
|
||||
hardcodedZero0: 0,
|
||||
requestVersion: 1,
|
||||
charID1: 12345,
|
||||
hardcodedZero1: 0,
|
||||
tokenStrLen: 0x11,
|
||||
tokenString: "abc123token",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ackHandle)
|
||||
bf.WriteUint32(tt.charID0)
|
||||
bf.WriteUint32(tt.loginTokenNumber)
|
||||
bf.WriteUint16(tt.hardcodedZero0)
|
||||
bf.WriteUint16(tt.requestVersion)
|
||||
bf.WriteUint32(tt.charID1)
|
||||
bf.WriteUint16(tt.hardcodedZero1)
|
||||
bf.WriteUint16(tt.tokenStrLen)
|
||||
bf.WriteBytes(append([]byte(tt.tokenString), 0x00)) // null terminated
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysLogin{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ackHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle)
|
||||
}
|
||||
if pkt.CharID0 != tt.charID0 {
|
||||
t.Errorf("CharID0 = %d, want %d", pkt.CharID0, tt.charID0)
|
||||
}
|
||||
if pkt.LoginTokenNumber != tt.loginTokenNumber {
|
||||
t.Errorf("LoginTokenNumber = %d, want %d", pkt.LoginTokenNumber, tt.loginTokenNumber)
|
||||
}
|
||||
if pkt.RequestVersion != tt.requestVersion {
|
||||
t.Errorf("RequestVersion = %d, want %d", pkt.RequestVersion, tt.requestVersion)
|
||||
}
|
||||
if pkt.LoginTokenString != tt.tokenString {
|
||||
t.Errorf("LoginTokenString = %q, want %q", pkt.LoginTokenString, tt.tokenString)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
2229
network/mhfpacket/msg_batch_parse_test.go
Normal file
2229
network/mhfpacket/msg_batch_parse_test.go
Normal file
File diff suppressed because it is too large
Load Diff
1413
network/mhfpacket/msg_build_test.go
Normal file
1413
network/mhfpacket/msg_build_test.go
Normal file
File diff suppressed because it is too large
Load Diff
1150
network/mhfpacket/msg_comprehensive_test.go
Normal file
1150
network/mhfpacket/msg_comprehensive_test.go
Normal file
File diff suppressed because it is too large
Load Diff
180
network/mhfpacket/msg_mhf_acquire_cafe_item_test.go
Normal file
180
network/mhfpacket/msg_mhf_acquire_cafe_item_test.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
_config "erupe-ce/config"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Initialize ErupeConfig for tests that access it
|
||||
_config.ErupeConfig = &_config.Config{
|
||||
RealClientMode: _config.ZZ, // Default to ZZ for tests
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfAcquireCafeItemOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfAcquireCafeItem{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ACQUIRE_CAFE_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ACQUIRE_CAFE_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfAcquireCafeItemParse(t *testing.T) {
|
||||
// Test basic parsing with current implementation (always reads uint32 for PointCost)
|
||||
// Current code: m.PointCost = bf.ReadUint32() (no client mode check)
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x12345678) // AckHandle
|
||||
bf.WriteUint16(1) // ItemType
|
||||
bf.WriteUint16(100) // ItemID
|
||||
bf.WriteUint16(5) // Quant
|
||||
bf.WriteUint32(1000) // PointCost (uint32)
|
||||
bf.WriteUint16(0) // Unk0
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAcquireCafeItem{}
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
err := pkt.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x12345678 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x12345678", pkt.AckHandle)
|
||||
}
|
||||
if pkt.ItemType != 1 {
|
||||
t.Errorf("ItemType = %d, want 1", pkt.ItemType)
|
||||
}
|
||||
if pkt.ItemID != 100 {
|
||||
t.Errorf("ItemID = %d, want 100", pkt.ItemID)
|
||||
}
|
||||
if pkt.Quant != 5 {
|
||||
t.Errorf("Quant = %d, want 5", pkt.Quant)
|
||||
}
|
||||
if pkt.PointCost != 1000 {
|
||||
t.Errorf("PointCost = %d, want 1000", pkt.PointCost)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfAcquireCafeItemParseUint32PointCost documents the current behavior.
|
||||
//
|
||||
// CURRENT BEHAVIOR: Always reads PointCost as uint32.
|
||||
//
|
||||
// EXPECTED BEHAVIOR AFTER FIX (commit 3d0114c):
|
||||
// - G6+: Read PointCost as uint32
|
||||
// - G1-G5.2: Read PointCost as uint16
|
||||
//
|
||||
// This test verifies current uint32 parsing works correctly.
|
||||
// After the fix is applied, this test should still pass for G6+ clients.
|
||||
func TestMsgMhfAcquireCafeItemParseUint32PointCost(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pointCost uint32
|
||||
wantCost uint32
|
||||
}{
|
||||
{"small cost", 100, 100},
|
||||
{"medium cost", 5000, 5000},
|
||||
{"large cost exceeding uint16", 70000, 70000},
|
||||
{"max uint32", 0xFFFFFFFF, 0xFFFFFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xAAAABBBB) // AckHandle
|
||||
bf.WriteUint16(1) // ItemType
|
||||
bf.WriteUint16(200) // ItemID
|
||||
bf.WriteUint16(10) // Quant
|
||||
bf.WriteUint32(tt.pointCost)
|
||||
bf.WriteUint16(0) // Unk0
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAcquireCafeItem{}
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
err := pkt.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.PointCost != tt.wantCost {
|
||||
t.Errorf("PointCost = %d, want %d", pkt.PointCost, tt.wantCost)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfAcquireCafeItemParseFieldOrder verifies the exact field order in parsing.
|
||||
// This is important because the fix changes when PointCost is read (uint16 vs uint32).
|
||||
func TestMsgMhfAcquireCafeItemParseFieldOrder(t *testing.T) {
|
||||
// Build a packet with known values
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x11223344) // AckHandle (offset 0-3)
|
||||
bf.WriteUint16(0x5566) // ItemType (offset 4-5)
|
||||
bf.WriteUint16(0x7788) // ItemID (offset 6-7)
|
||||
bf.WriteUint16(0x99AA) // Quant (offset 8-9)
|
||||
bf.WriteUint32(0xBBCCDDEE) // PointCost (offset 10-13)
|
||||
bf.WriteUint16(0xFF00) // Unk0 (offset 14-15)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAcquireCafeItem{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x11223344 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x11223344", pkt.AckHandle)
|
||||
}
|
||||
if pkt.ItemType != 0x5566 {
|
||||
t.Errorf("ItemType = 0x%X, want 0x5566", pkt.ItemType)
|
||||
}
|
||||
if pkt.ItemID != 0x7788 {
|
||||
t.Errorf("ItemID = 0x%X, want 0x7788", pkt.ItemID)
|
||||
}
|
||||
if pkt.Quant != 0x99AA {
|
||||
t.Errorf("Quant = 0x%X, want 0x99AA", pkt.Quant)
|
||||
}
|
||||
if pkt.PointCost != 0xBBCCDDEE {
|
||||
t.Errorf("PointCost = 0x%X, want 0xBBCCDDEE", pkt.PointCost)
|
||||
}
|
||||
if pkt.Unk0 != 0xFF00 {
|
||||
t.Errorf("Unk0 = 0x%X, want 0xFF00", pkt.Unk0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfAcquireCafeItemBuildNotImplemented(t *testing.T) {
|
||||
pkt := &MsgMhfAcquireCafeItem{
|
||||
AckHandle: 123,
|
||||
ItemType: 1,
|
||||
ItemID: 100,
|
||||
Quant: 5,
|
||||
PointCost: 1000,
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
err := pkt.Build(bf, ctx)
|
||||
if err == nil {
|
||||
t.Error("Build() should return error (NOT IMPLEMENTED)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfAcquireCafeItemFromOpcode(t *testing.T) {
|
||||
pkt := FromOpcode(network.MSG_MHF_ACQUIRE_CAFE_ITEM)
|
||||
if pkt == nil {
|
||||
t.Fatal("FromOpcode(MSG_MHF_ACQUIRE_CAFE_ITEM) returned nil")
|
||||
}
|
||||
if pkt.Opcode() != network.MSG_MHF_ACQUIRE_CAFE_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ACQUIRE_CAFE_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
263
network/mhfpacket/msg_mhf_acquire_test.go
Normal file
263
network/mhfpacket/msg_mhf_acquire_test.go
Normal file
@@ -0,0 +1,263 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
func TestAcquirePacketOpcodes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pkt MHFPacket
|
||||
expect network.PacketID
|
||||
}{
|
||||
{"MsgMhfAcquireGuildTresure", &MsgMhfAcquireGuildTresure{}, network.MSG_MHF_ACQUIRE_GUILD_TRESURE},
|
||||
{"MsgMhfAcquireTitle", &MsgMhfAcquireTitle{}, network.MSG_MHF_ACQUIRE_TITLE},
|
||||
{"MsgMhfAcquireDistItem", &MsgMhfAcquireDistItem{}, network.MSG_MHF_ACQUIRE_DIST_ITEM},
|
||||
{"MsgMhfAcquireMonthlyItem", &MsgMhfAcquireMonthlyItem{}, network.MSG_MHF_ACQUIRE_MONTHLY_ITEM},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.pkt.Opcode(); got != tt.expect {
|
||||
t.Errorf("Opcode() = %v, want %v", got, tt.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfAcquireGuildTresureParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ackHandle uint32
|
||||
huntID uint32
|
||||
unk bool
|
||||
}{
|
||||
{"basic acquisition", 1, 12345, false},
|
||||
{"large hunt ID", 0xABCDEF12, 0xFFFFFFFF, true},
|
||||
{"zero values", 0, 0, false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ackHandle)
|
||||
bf.WriteUint32(tt.huntID)
|
||||
bf.WriteBool(tt.unk)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAcquireGuildTresure{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ackHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle)
|
||||
}
|
||||
if pkt.HuntID != tt.huntID {
|
||||
t.Errorf("HuntID = %d, want %d", pkt.HuntID, tt.huntID)
|
||||
}
|
||||
if pkt.Unk != tt.unk {
|
||||
t.Errorf("Unk = %v, want %v", pkt.Unk, tt.unk)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfAcquireTitleParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ackHandle uint32
|
||||
titleIDs []uint16
|
||||
}{
|
||||
{"acquire title 1", 1, []uint16{1}},
|
||||
{"acquire titles 100 200", 0x12345678, []uint16{100, 200}},
|
||||
{"no titles", 0xFFFFFFFF, []uint16{}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ackHandle)
|
||||
bf.WriteUint16(uint16(len(tt.titleIDs))) // count
|
||||
bf.WriteUint16(0) // zeroed
|
||||
for _, id := range tt.titleIDs {
|
||||
bf.WriteUint16(id)
|
||||
}
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAcquireTitle{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ackHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle)
|
||||
}
|
||||
if len(pkt.TitleIDs) != len(tt.titleIDs) {
|
||||
t.Errorf("TitleIDs len = %d, want %d", len(pkt.TitleIDs), len(tt.titleIDs))
|
||||
}
|
||||
for i, id := range tt.titleIDs {
|
||||
if i < len(pkt.TitleIDs) && pkt.TitleIDs[i] != id {
|
||||
t.Errorf("TitleIDs[%d] = %d, want %d", i, pkt.TitleIDs[i], id)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfAcquireDistItemParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ackHandle uint32
|
||||
distributionType uint8
|
||||
distributionID uint32
|
||||
}{
|
||||
{"type 0", 1, 0, 12345},
|
||||
{"type 1", 0xABCD, 1, 67890},
|
||||
{"max values", 0xFFFFFFFF, 0xFF, 0xFFFFFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ackHandle)
|
||||
bf.WriteUint8(tt.distributionType)
|
||||
bf.WriteUint32(tt.distributionID)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAcquireDistItem{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ackHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle)
|
||||
}
|
||||
if pkt.DistributionType != tt.distributionType {
|
||||
t.Errorf("DistributionType = %d, want %d", pkt.DistributionType, tt.distributionType)
|
||||
}
|
||||
if pkt.DistributionID != tt.distributionID {
|
||||
t.Errorf("DistributionID = %d, want %d", pkt.DistributionID, tt.distributionID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfAcquireMonthlyItemParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ackHandle uint32
|
||||
unk0 uint8
|
||||
unk1 uint8
|
||||
unk2 uint16
|
||||
unk3 uint32
|
||||
}{
|
||||
{"basic", 1, 0, 0, 0, 0},
|
||||
{"with values", 100, 10, 20, 30, 40},
|
||||
{"max values", 0xFFFFFFFF, 0xFF, 0xFF, 0xFFFF, 0xFFFFFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ackHandle)
|
||||
bf.WriteUint8(tt.unk0)
|
||||
bf.WriteUint8(tt.unk1)
|
||||
bf.WriteUint16(tt.unk2)
|
||||
bf.WriteUint32(tt.unk3)
|
||||
bf.WriteUint32(0) // Zeroed (consumed by Parse)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAcquireMonthlyItem{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ackHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle)
|
||||
}
|
||||
if pkt.Unk0 != tt.unk0 {
|
||||
t.Errorf("Unk0 = %d, want %d", pkt.Unk0, tt.unk0)
|
||||
}
|
||||
if pkt.Unk1 != tt.unk1 {
|
||||
t.Errorf("Unk1 = %d, want %d", pkt.Unk1, tt.unk1)
|
||||
}
|
||||
if pkt.Unk2 != tt.unk2 {
|
||||
t.Errorf("Unk2 = %d, want %d", pkt.Unk2, tt.unk2)
|
||||
}
|
||||
if pkt.Unk3 != tt.unk3 {
|
||||
t.Errorf("Unk3 = %d, want %d", pkt.Unk3, tt.unk3)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcquirePacketsFromOpcode(t *testing.T) {
|
||||
acquireOpcodes := []network.PacketID{
|
||||
network.MSG_MHF_ACQUIRE_GUILD_TRESURE,
|
||||
network.MSG_MHF_ACQUIRE_TITLE,
|
||||
network.MSG_MHF_ACQUIRE_DIST_ITEM,
|
||||
network.MSG_MHF_ACQUIRE_MONTHLY_ITEM,
|
||||
}
|
||||
|
||||
for _, opcode := range acquireOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Fatalf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
if pkt.Opcode() != opcode {
|
||||
t.Errorf("Opcode() = %s, want %s", pkt.Opcode(), opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcquirePacketEdgeCases(t *testing.T) {
|
||||
t.Run("guild tresure with max hunt ID", func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1)
|
||||
bf.WriteUint32(0xFFFFFFFF)
|
||||
bf.WriteBool(true)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAcquireGuildTresure{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.HuntID != 0xFFFFFFFF {
|
||||
t.Errorf("HuntID = %d, want %d", pkt.HuntID, 0xFFFFFFFF)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("dist item with all types", func(t *testing.T) {
|
||||
for i := uint8(0); i < 5; i++ {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1)
|
||||
bf.WriteUint8(i)
|
||||
bf.WriteUint32(12345)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAcquireDistItem{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v for type %d", err, i)
|
||||
}
|
||||
|
||||
if pkt.DistributionType != i {
|
||||
t.Errorf("DistributionType = %d, want %d", pkt.DistributionType, i)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
364
network/mhfpacket/msg_mhf_guacot_test.go
Normal file
364
network/mhfpacket/msg_mhf_guacot_test.go
Normal file
@@ -0,0 +1,364 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
)
|
||||
|
||||
func TestMsgMhfUpdateGuacotOpcode_Guacot(t *testing.T) {
|
||||
pkt := &MsgMhfUpdateGuacot{}
|
||||
if pkt.Opcode() != network.MSG_MHF_UPDATE_GUACOT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_UPDATE_GUACOT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfEnumerateGuacotOpcode_Guacot(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateGuacot{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_GUACOT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_GUACOT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfUpdateGuacotParse_SingleEntry(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xAABBCCDD) // AckHandle
|
||||
bf.WriteUint16(1) // EntryCount
|
||||
bf.WriteUint16(0) // Zeroed
|
||||
|
||||
// Goocoo entry
|
||||
bf.WriteUint32(2) // Index
|
||||
for i := 0; i < 22; i++ {
|
||||
bf.WriteInt16(int16(i + 1)) // Data1
|
||||
}
|
||||
bf.WriteUint32(100) // Data2[0]
|
||||
bf.WriteUint32(200) // Data2[1]
|
||||
bf.WriteUint8(5) // Name length
|
||||
bf.WriteBytes([]byte("Porky"))
|
||||
|
||||
pkt := &MsgMhfUpdateGuacot{}
|
||||
bf.Seek(0, 0)
|
||||
err := pkt.Parse(bf, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error: %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xAABBCCDD {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xAABBCCDD", pkt.AckHandle)
|
||||
}
|
||||
if pkt.EntryCount != 1 {
|
||||
t.Errorf("EntryCount = %d, want 1", pkt.EntryCount)
|
||||
}
|
||||
if len(pkt.Goocoos) != 1 {
|
||||
t.Fatalf("len(Goocoos) = %d, want 1", len(pkt.Goocoos))
|
||||
}
|
||||
|
||||
g := pkt.Goocoos[0]
|
||||
if g.Index != 2 {
|
||||
t.Errorf("Index = %d, want 2", g.Index)
|
||||
}
|
||||
if len(g.Data1) != 22 {
|
||||
t.Fatalf("len(Data1) = %d, want 22", len(g.Data1))
|
||||
}
|
||||
for i := 0; i < 22; i++ {
|
||||
if g.Data1[i] != int16(i+1) {
|
||||
t.Errorf("Data1[%d] = %d, want %d", i, g.Data1[i], i+1)
|
||||
}
|
||||
}
|
||||
if len(g.Data2) != 2 {
|
||||
t.Fatalf("len(Data2) = %d, want 2", len(g.Data2))
|
||||
}
|
||||
if g.Data2[0] != 100 {
|
||||
t.Errorf("Data2[0] = %d, want 100", g.Data2[0])
|
||||
}
|
||||
if g.Data2[1] != 200 {
|
||||
t.Errorf("Data2[1] = %d, want 200", g.Data2[1])
|
||||
}
|
||||
if string(g.Name) != "Porky" {
|
||||
t.Errorf("Name = %q, want %q", string(g.Name), "Porky")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfUpdateGuacotParse_MultipleEntries(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1) // AckHandle
|
||||
bf.WriteUint16(3) // EntryCount
|
||||
bf.WriteUint16(0) // Zeroed
|
||||
|
||||
for idx := uint32(0); idx < 3; idx++ {
|
||||
bf.WriteUint32(idx) // Index
|
||||
for i := 0; i < 22; i++ {
|
||||
bf.WriteInt16(int16(idx*100 + uint32(i)))
|
||||
}
|
||||
bf.WriteUint32(idx * 10) // Data2[0]
|
||||
bf.WriteUint32(idx * 20) // Data2[1]
|
||||
name := []byte("Pog")
|
||||
bf.WriteUint8(uint8(len(name)))
|
||||
bf.WriteBytes(name)
|
||||
}
|
||||
|
||||
pkt := &MsgMhfUpdateGuacot{}
|
||||
bf.Seek(0, 0)
|
||||
err := pkt.Parse(bf, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error: %v", err)
|
||||
}
|
||||
|
||||
if len(pkt.Goocoos) != 3 {
|
||||
t.Fatalf("len(Goocoos) = %d, want 3", len(pkt.Goocoos))
|
||||
}
|
||||
for idx := uint32(0); idx < 3; idx++ {
|
||||
g := pkt.Goocoos[idx]
|
||||
if g.Index != idx {
|
||||
t.Errorf("Goocoos[%d].Index = %d, want %d", idx, g.Index, idx)
|
||||
}
|
||||
if g.Data1[0] != int16(idx*100) {
|
||||
t.Errorf("Goocoos[%d].Data1[0] = %d, want %d", idx, g.Data1[0], idx*100)
|
||||
}
|
||||
if g.Data2[0] != idx*10 {
|
||||
t.Errorf("Goocoos[%d].Data2[0] = %d, want %d", idx, g.Data2[0], idx*10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfUpdateGuacotParse_ZeroEntries(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(42) // AckHandle
|
||||
bf.WriteUint16(0) // EntryCount
|
||||
bf.WriteUint16(0) // Zeroed
|
||||
|
||||
pkt := &MsgMhfUpdateGuacot{}
|
||||
bf.Seek(0, 0)
|
||||
err := pkt.Parse(bf, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error: %v", err)
|
||||
}
|
||||
|
||||
if pkt.EntryCount != 0 {
|
||||
t.Errorf("EntryCount = %d, want 0", pkt.EntryCount)
|
||||
}
|
||||
if len(pkt.Goocoos) != 0 {
|
||||
t.Errorf("len(Goocoos) = %d, want 0", len(pkt.Goocoos))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfUpdateGuacotParse_DeletionEntry(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1) // AckHandle
|
||||
bf.WriteUint16(1) // EntryCount
|
||||
bf.WriteUint16(0) // Zeroed
|
||||
|
||||
bf.WriteUint32(0) // Index
|
||||
// Data1[0] = 0 signals deletion
|
||||
bf.WriteInt16(0)
|
||||
for i := 1; i < 22; i++ {
|
||||
bf.WriteInt16(0)
|
||||
}
|
||||
bf.WriteUint32(0) // Data2[0]
|
||||
bf.WriteUint32(0) // Data2[1]
|
||||
bf.WriteUint8(0) // Empty name
|
||||
|
||||
pkt := &MsgMhfUpdateGuacot{}
|
||||
bf.Seek(0, 0)
|
||||
err := pkt.Parse(bf, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error: %v", err)
|
||||
}
|
||||
|
||||
g := pkt.Goocoos[0]
|
||||
if g.Data1[0] != 0 {
|
||||
t.Errorf("Data1[0] = %d, want 0 (deletion marker)", g.Data1[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfUpdateGuacotParse_EmptyName(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1) // AckHandle
|
||||
bf.WriteUint16(1) // EntryCount
|
||||
bf.WriteUint16(0) // Zeroed
|
||||
|
||||
bf.WriteUint32(0) // Index
|
||||
for i := 0; i < 22; i++ {
|
||||
bf.WriteInt16(1)
|
||||
}
|
||||
bf.WriteUint32(0) // Data2[0]
|
||||
bf.WriteUint32(0) // Data2[1]
|
||||
bf.WriteUint8(0) // Empty name
|
||||
|
||||
pkt := &MsgMhfUpdateGuacot{}
|
||||
bf.Seek(0, 0)
|
||||
err := pkt.Parse(bf, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error: %v", err)
|
||||
}
|
||||
|
||||
if len(pkt.Goocoos[0].Name) != 0 {
|
||||
t.Errorf("Name length = %d, want 0", len(pkt.Goocoos[0].Name))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfEnumerateGuacotParse(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x12345678) // AckHandle
|
||||
bf.WriteUint32(0) // Unk0
|
||||
bf.WriteUint16(0) // Zeroed
|
||||
|
||||
pkt := &MsgMhfEnumerateGuacot{}
|
||||
bf.Seek(0, 0)
|
||||
err := pkt.Parse(bf, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error: %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x12345678 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x12345678", pkt.AckHandle)
|
||||
}
|
||||
if pkt.Unk0 != 0 {
|
||||
t.Errorf("Unk0 = %d, want 0", pkt.Unk0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfUpdateGuacotBuild_NotImplemented(t *testing.T) {
|
||||
pkt := &MsgMhfUpdateGuacot{}
|
||||
err := pkt.Build(byteframe.NewByteFrame(), nil)
|
||||
if err == nil {
|
||||
t.Error("Build() should return error (not implemented)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgMhfEnumerateGuacotBuild_NotImplemented(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateGuacot{}
|
||||
err := pkt.Build(byteframe.NewByteFrame(), nil)
|
||||
if err == nil {
|
||||
t.Error("Build() should return error (not implemented)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoocooStruct_Data1Size(t *testing.T) {
|
||||
// Verify 22 int16 entries = 44 bytes of outfit/appearance data
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1) // AckHandle
|
||||
bf.WriteUint16(1) // EntryCount
|
||||
bf.WriteUint16(0) // Zeroed
|
||||
|
||||
bf.WriteUint32(0) // Index
|
||||
for i := 0; i < 22; i++ {
|
||||
bf.WriteInt16(int16(i * 3))
|
||||
}
|
||||
bf.WriteUint32(0xDEAD) // Data2[0]
|
||||
bf.WriteUint32(0xBEEF) // Data2[1]
|
||||
bf.WriteUint8(0) // No name
|
||||
|
||||
pkt := &MsgMhfUpdateGuacot{}
|
||||
bf.Seek(0, 0)
|
||||
_ = pkt.Parse(bf, nil)
|
||||
|
||||
g := pkt.Goocoos[0]
|
||||
|
||||
// Verify all 22 data slots are correctly read
|
||||
for i := 0; i < 22; i++ {
|
||||
expected := int16(i * 3)
|
||||
if g.Data1[i] != expected {
|
||||
t.Errorf("Data1[%d] = %d, want %d", i, g.Data1[i], expected)
|
||||
}
|
||||
}
|
||||
|
||||
if g.Data2[0] != 0xDEAD {
|
||||
t.Errorf("Data2[0] = 0x%X, want 0xDEAD", g.Data2[0])
|
||||
}
|
||||
if g.Data2[1] != 0xBEEF {
|
||||
t.Errorf("Data2[1] = 0x%X, want 0xBEEF", g.Data2[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoocooSerialization_Roundtrip(t *testing.T) {
|
||||
// Simulate what handleMsgMhfUpdateGuacot does when saving to DB
|
||||
goocoo := Goocoo{
|
||||
Index: 1,
|
||||
Data1: make([]int16, 22),
|
||||
Data2: []uint32{0x1234, 0x5678},
|
||||
Name: []byte("MyPoogie"),
|
||||
}
|
||||
goocoo.Data1[0] = 5 // outfit type (non-zero = exists)
|
||||
goocoo.Data1[1] = 100 // some appearance data
|
||||
goocoo.Data1[21] = -50 // test negative int16
|
||||
|
||||
// Serialize (matches handler logic)
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(goocoo.Index)
|
||||
for i := range goocoo.Data1 {
|
||||
bf.WriteInt16(goocoo.Data1[i])
|
||||
}
|
||||
for i := range goocoo.Data2 {
|
||||
bf.WriteUint32(goocoo.Data2[i])
|
||||
}
|
||||
bf.WriteUint8(uint8(len(goocoo.Name)))
|
||||
bf.WriteBytes(goocoo.Name)
|
||||
|
||||
// Deserialize and verify
|
||||
data := bf.Data()
|
||||
rbf := byteframe.NewByteFrameFromBytes(data)
|
||||
|
||||
index := rbf.ReadUint32()
|
||||
if index != 1 {
|
||||
t.Errorf("index = %d, want 1", index)
|
||||
}
|
||||
|
||||
data1_0 := rbf.ReadInt16()
|
||||
if data1_0 != 5 {
|
||||
t.Errorf("data1[0] = %d, want 5", data1_0)
|
||||
}
|
||||
data1_1 := rbf.ReadInt16()
|
||||
if data1_1 != 100 {
|
||||
t.Errorf("data1[1] = %d, want 100", data1_1)
|
||||
}
|
||||
// Skip to data1[21]
|
||||
for i := 2; i < 21; i++ {
|
||||
rbf.ReadInt16()
|
||||
}
|
||||
data1_21 := rbf.ReadInt16()
|
||||
if data1_21 != -50 {
|
||||
t.Errorf("data1[21] = %d, want -50", data1_21)
|
||||
}
|
||||
|
||||
d2_0 := rbf.ReadUint32()
|
||||
if d2_0 != 0x1234 {
|
||||
t.Errorf("data2[0] = 0x%X, want 0x1234", d2_0)
|
||||
}
|
||||
d2_1 := rbf.ReadUint32()
|
||||
if d2_1 != 0x5678 {
|
||||
t.Errorf("data2[1] = 0x%X, want 0x5678", d2_1)
|
||||
}
|
||||
|
||||
nameLen := rbf.ReadUint8()
|
||||
if nameLen != 8 {
|
||||
t.Errorf("nameLen = %d, want 8", nameLen)
|
||||
}
|
||||
name := rbf.ReadBytes(uint(nameLen))
|
||||
if string(name) != "MyPoogie" {
|
||||
t.Errorf("name = %q, want %q", string(name), "MyPoogie")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoocooEntrySize(t *testing.T) {
|
||||
// Each goocoo entry in the packet should be:
|
||||
// 4 (index) + 22*2 (data1) + 2*4 (data2) + 1 (name len) + N (name)
|
||||
// = 4 + 44 + 8 + 1 + N = 57 + N bytes
|
||||
name := []byte("Test")
|
||||
expectedSize := 4 + 44 + 8 + 1 + len(name)
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0) // index
|
||||
for i := 0; i < 22; i++ {
|
||||
bf.WriteInt16(0)
|
||||
}
|
||||
bf.WriteUint32(0) // data2[0]
|
||||
bf.WriteUint32(0) // data2[1]
|
||||
bf.WriteUint8(uint8(len(name))) // name len
|
||||
bf.WriteBytes(name)
|
||||
|
||||
if len(bf.Data()) != expectedSize {
|
||||
t.Errorf("entry size = %d bytes, want %d bytes (57 + %d name)", len(bf.Data()), expectedSize, len(name))
|
||||
}
|
||||
}
|
||||
537
network/mhfpacket/msg_mhf_packets_test.go
Normal file
537
network/mhfpacket/msg_mhf_packets_test.go
Normal file
@@ -0,0 +1,537 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
// TestMsgMhfSavedataParse tests parsing MsgMhfSavedata
|
||||
func TestMsgMhfSavedataParse(t *testing.T) {
|
||||
pkt := FromOpcode(network.MSG_MHF_SAVEDATA)
|
||||
if pkt == nil {
|
||||
t.Fatal("FromOpcode(MSG_MHF_SAVEDATA) returned nil")
|
||||
}
|
||||
if pkt.Opcode() != network.MSG_MHF_SAVEDATA {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_SAVEDATA", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfLoaddataParse tests parsing MsgMhfLoaddata
|
||||
func TestMsgMhfLoaddataParse(t *testing.T) {
|
||||
pkt := FromOpcode(network.MSG_MHF_LOADDATA)
|
||||
if pkt == nil {
|
||||
t.Fatal("FromOpcode(MSG_MHF_LOADDATA) returned nil")
|
||||
}
|
||||
if pkt.Opcode() != network.MSG_MHF_LOADDATA {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_LOADDATA", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfListMemberOpcode tests MsgMhfListMember Opcode
|
||||
func TestMsgMhfListMemberOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfListMember{}
|
||||
if pkt.Opcode() != network.MSG_MHF_LIST_MEMBER {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_LIST_MEMBER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfOprMemberOpcode tests MsgMhfOprMember Opcode
|
||||
func TestMsgMhfOprMemberOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfOprMember{}
|
||||
if pkt.Opcode() != network.MSG_MHF_OPR_MEMBER {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_OPR_MEMBER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumerateDistItemOpcode tests MsgMhfEnumerateDistItem Opcode
|
||||
func TestMsgMhfEnumerateDistItemOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateDistItem{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_DIST_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_DIST_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfApplyDistItemOpcode tests MsgMhfApplyDistItem Opcode
|
||||
func TestMsgMhfApplyDistItemOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfApplyDistItem{}
|
||||
if pkt.Opcode() != network.MSG_MHF_APPLY_DIST_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_APPLY_DIST_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfAcquireDistItemOpcode tests MsgMhfAcquireDistItem Opcode
|
||||
func TestMsgMhfAcquireDistItemOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfAcquireDistItem{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ACQUIRE_DIST_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ACQUIRE_DIST_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfGetDistDescriptionOpcode tests MsgMhfGetDistDescription Opcode
|
||||
func TestMsgMhfGetDistDescriptionOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfGetDistDescription{}
|
||||
if pkt.Opcode() != network.MSG_MHF_GET_DIST_DESCRIPTION {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_GET_DIST_DESCRIPTION", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfSendMailOpcode tests MsgMhfSendMail Opcode
|
||||
func TestMsgMhfSendMailOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfSendMail{}
|
||||
if pkt.Opcode() != network.MSG_MHF_SEND_MAIL {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_SEND_MAIL", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfReadMailOpcode tests MsgMhfReadMail Opcode
|
||||
func TestMsgMhfReadMailOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfReadMail{}
|
||||
if pkt.Opcode() != network.MSG_MHF_READ_MAIL {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_READ_MAIL", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfListMailOpcode tests MsgMhfListMail Opcode
|
||||
func TestMsgMhfListMailOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfListMail{}
|
||||
if pkt.Opcode() != network.MSG_MHF_LIST_MAIL {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_LIST_MAIL", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfOprtMailOpcode tests MsgMhfOprtMail Opcode
|
||||
func TestMsgMhfOprtMailOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfOprtMail{}
|
||||
if pkt.Opcode() != network.MSG_MHF_OPRT_MAIL {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_OPRT_MAIL", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfLoadFavoriteQuestOpcode tests MsgMhfLoadFavoriteQuest Opcode
|
||||
func TestMsgMhfLoadFavoriteQuestOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfLoadFavoriteQuest{}
|
||||
if pkt.Opcode() != network.MSG_MHF_LOAD_FAVORITE_QUEST {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_LOAD_FAVORITE_QUEST", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfSaveFavoriteQuestOpcode tests MsgMhfSaveFavoriteQuest Opcode
|
||||
func TestMsgMhfSaveFavoriteQuestOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfSaveFavoriteQuest{}
|
||||
if pkt.Opcode() != network.MSG_MHF_SAVE_FAVORITE_QUEST {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_SAVE_FAVORITE_QUEST", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfRegisterEventOpcode tests MsgMhfRegisterEvent Opcode
|
||||
func TestMsgMhfRegisterEventOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfRegisterEvent{}
|
||||
if pkt.Opcode() != network.MSG_MHF_REGISTER_EVENT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_REGISTER_EVENT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfReleaseEventOpcode tests MsgMhfReleaseEvent Opcode
|
||||
func TestMsgMhfReleaseEventOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfReleaseEvent{}
|
||||
if pkt.Opcode() != network.MSG_MHF_RELEASE_EVENT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_RELEASE_EVENT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfTransitMessageOpcode tests MsgMhfTransitMessage Opcode
|
||||
func TestMsgMhfTransitMessageOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfTransitMessage{}
|
||||
if pkt.Opcode() != network.MSG_MHF_TRANSIT_MESSAGE {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_TRANSIT_MESSAGE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfPresentBoxOpcode tests MsgMhfPresentBox Opcode
|
||||
func TestMsgMhfPresentBoxOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfPresentBox{}
|
||||
if pkt.Opcode() != network.MSG_MHF_PRESENT_BOX {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_PRESENT_BOX", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfServerCommandOpcode tests MsgMhfServerCommand Opcode
|
||||
func TestMsgMhfServerCommandOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfServerCommand{}
|
||||
if pkt.Opcode() != network.MSG_MHF_SERVER_COMMAND {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_SERVER_COMMAND", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfShutClientOpcode tests MsgMhfShutClient Opcode
|
||||
func TestMsgMhfShutClientOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfShutClient{}
|
||||
if pkt.Opcode() != network.MSG_MHF_SHUT_CLIENT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_SHUT_CLIENT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfAnnounceOpcode tests MsgMhfAnnounce Opcode
|
||||
func TestMsgMhfAnnounceOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfAnnounce{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ANNOUNCE {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ANNOUNCE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfSetLoginwindowOpcode tests MsgMhfSetLoginwindow Opcode
|
||||
func TestMsgMhfSetLoginwindowOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfSetLoginwindow{}
|
||||
if pkt.Opcode() != network.MSG_MHF_SET_LOGINWINDOW {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_SET_LOGINWINDOW", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfGetCaUniqueIDOpcode tests MsgMhfGetCaUniqueID Opcode
|
||||
func TestMsgMhfGetCaUniqueIDOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfGetCaUniqueID{}
|
||||
if pkt.Opcode() != network.MSG_MHF_GET_CA_UNIQUE_ID {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_GET_CA_UNIQUE_ID", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfSetCaAchievementOpcode tests MsgMhfSetCaAchievement Opcode
|
||||
func TestMsgMhfSetCaAchievementOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfSetCaAchievement{}
|
||||
if pkt.Opcode() != network.MSG_MHF_SET_CA_ACHIEVEMENT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_SET_CA_ACHIEVEMENT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfCaravanMyScoreOpcode tests MsgMhfCaravanMyScore Opcode
|
||||
func TestMsgMhfCaravanMyScoreOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfCaravanMyScore{}
|
||||
if pkt.Opcode() != network.MSG_MHF_CARAVAN_MY_SCORE {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_CARAVAN_MY_SCORE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfCaravanRankingOpcode tests MsgMhfCaravanRanking Opcode
|
||||
func TestMsgMhfCaravanRankingOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfCaravanRanking{}
|
||||
if pkt.Opcode() != network.MSG_MHF_CARAVAN_RANKING {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_CARAVAN_RANKING", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfCaravanMyRankOpcode tests MsgMhfCaravanMyRank Opcode
|
||||
func TestMsgMhfCaravanMyRankOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfCaravanMyRank{}
|
||||
if pkt.Opcode() != network.MSG_MHF_CARAVAN_MY_RANK {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_CARAVAN_MY_RANK", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumerateQuestOpcode tests MsgMhfEnumerateQuest Opcode
|
||||
func TestMsgMhfEnumerateQuestOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateQuest{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_QUEST {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_QUEST", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumerateEventOpcode tests MsgMhfEnumerateEvent Opcode
|
||||
func TestMsgMhfEnumerateEventOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateEvent{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_EVENT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_EVENT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumeratePriceOpcode tests MsgMhfEnumeratePrice Opcode
|
||||
func TestMsgMhfEnumeratePriceOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumeratePrice{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_PRICE {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_PRICE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumerateRankingOpcode tests MsgMhfEnumerateRanking Opcode
|
||||
func TestMsgMhfEnumerateRankingOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateRanking{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_RANKING {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_RANKING", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumerateOrderOpcode tests MsgMhfEnumerateOrder Opcode
|
||||
func TestMsgMhfEnumerateOrderOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateOrder{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_ORDER {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_ORDER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumerateShopOpcode tests MsgMhfEnumerateShop Opcode
|
||||
func TestMsgMhfEnumerateShopOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateShop{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_SHOP {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_SHOP", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfGetExtraInfoOpcode tests MsgMhfGetExtraInfo Opcode
|
||||
func TestMsgMhfGetExtraInfoOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfGetExtraInfo{}
|
||||
if pkt.Opcode() != network.MSG_MHF_GET_EXTRA_INFO {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_GET_EXTRA_INFO", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumerateItemOpcode tests MsgMhfEnumerateItem Opcode
|
||||
func TestMsgMhfEnumerateItemOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateItem{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfAcquireItemOpcode tests MsgMhfAcquireItem Opcode
|
||||
func TestMsgMhfAcquireItemOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfAcquireItem{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ACQUIRE_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ACQUIRE_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfTransferItemOpcode tests MsgMhfTransferItem Opcode
|
||||
func TestMsgMhfTransferItemOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfTransferItem{}
|
||||
if pkt.Opcode() != network.MSG_MHF_TRANSFER_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_TRANSFER_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEntryRookieGuildOpcode tests MsgMhfEntryRookieGuild Opcode
|
||||
func TestMsgMhfEntryRookieGuildOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEntryRookieGuild{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENTRY_ROOKIE_GUILD {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENTRY_ROOKIE_GUILD", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgCaExchangeItemOpcode tests MsgCaExchangeItem Opcode
|
||||
func TestMsgCaExchangeItemOpcode(t *testing.T) {
|
||||
pkt := &MsgCaExchangeItem{}
|
||||
if pkt.Opcode() != network.MSG_CA_EXCHANGE_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_CA_EXCHANGE_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumerateCampaignOpcode tests MsgMhfEnumerateCampaign Opcode
|
||||
func TestMsgMhfEnumerateCampaignOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateCampaign{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_CAMPAIGN {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_CAMPAIGN", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfStateCampaignOpcode tests MsgMhfStateCampaign Opcode
|
||||
func TestMsgMhfStateCampaignOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfStateCampaign{}
|
||||
if pkt.Opcode() != network.MSG_MHF_STATE_CAMPAIGN {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_STATE_CAMPAIGN", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfApplyCampaignOpcode tests MsgMhfApplyCampaign Opcode
|
||||
func TestMsgMhfApplyCampaignOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfApplyCampaign{}
|
||||
if pkt.Opcode() != network.MSG_MHF_APPLY_CAMPAIGN {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_APPLY_CAMPAIGN", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfCreateJointOpcode tests MsgMhfCreateJoint Opcode
|
||||
func TestMsgMhfCreateJointOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfCreateJoint{}
|
||||
if pkt.Opcode() != network.MSG_MHF_CREATE_JOINT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_CREATE_JOINT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfOperateJointOpcode tests MsgMhfOperateJoint Opcode
|
||||
func TestMsgMhfOperateJointOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfOperateJoint{}
|
||||
if pkt.Opcode() != network.MSG_MHF_OPERATE_JOINT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_OPERATE_JOINT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfInfoJointOpcode tests MsgMhfInfoJoint Opcode
|
||||
func TestMsgMhfInfoJointOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfInfoJoint{}
|
||||
if pkt.Opcode() != network.MSG_MHF_INFO_JOINT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_INFO_JOINT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfGetCogInfoOpcode tests MsgMhfGetCogInfo Opcode
|
||||
func TestMsgMhfGetCogInfoOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfGetCogInfo{}
|
||||
if pkt.Opcode() != network.MSG_MHF_GET_COG_INFO {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_GET_COG_INFO", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfCheckMonthlyItemOpcode tests MsgMhfCheckMonthlyItem Opcode
|
||||
func TestMsgMhfCheckMonthlyItemOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfCheckMonthlyItem{}
|
||||
if pkt.Opcode() != network.MSG_MHF_CHECK_MONTHLY_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_CHECK_MONTHLY_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfAcquireMonthlyItemOpcode tests MsgMhfAcquireMonthlyItem Opcode
|
||||
func TestMsgMhfAcquireMonthlyItemOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfAcquireMonthlyItem{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ACQUIRE_MONTHLY_ITEM {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ACQUIRE_MONTHLY_ITEM", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfCheckWeeklyStampOpcode tests MsgMhfCheckWeeklyStamp Opcode
|
||||
func TestMsgMhfCheckWeeklyStampOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfCheckWeeklyStamp{}
|
||||
if pkt.Opcode() != network.MSG_MHF_CHECK_WEEKLY_STAMP {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_CHECK_WEEKLY_STAMP", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfExchangeWeeklyStampOpcode tests MsgMhfExchangeWeeklyStamp Opcode
|
||||
func TestMsgMhfExchangeWeeklyStampOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfExchangeWeeklyStamp{}
|
||||
if pkt.Opcode() != network.MSG_MHF_EXCHANGE_WEEKLY_STAMP {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_EXCHANGE_WEEKLY_STAMP", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfCreateMercenaryOpcode tests MsgMhfCreateMercenary Opcode
|
||||
func TestMsgMhfCreateMercenaryOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfCreateMercenary{}
|
||||
if pkt.Opcode() != network.MSG_MHF_CREATE_MERCENARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_CREATE_MERCENARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumerateMercenaryLogOpcode tests MsgMhfEnumerateMercenaryLog Opcode
|
||||
func TestMsgMhfEnumerateMercenaryLogOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateMercenaryLog{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_MERCENARY_LOG {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_MERCENARY_LOG", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnumerateGuacotOpcode tests MsgMhfEnumerateGuacot Opcode
|
||||
func TestMsgMhfEnumerateGuacotOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnumerateGuacot{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENUMERATE_GUACOT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENUMERATE_GUACOT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfUpdateGuacotOpcode tests MsgMhfUpdateGuacot Opcode
|
||||
func TestMsgMhfUpdateGuacotOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfUpdateGuacot{}
|
||||
if pkt.Opcode() != network.MSG_MHF_UPDATE_GUACOT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_UPDATE_GUACOT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfEnterTournamentQuestOpcode tests MsgMhfEnterTournamentQuest Opcode
|
||||
func TestMsgMhfEnterTournamentQuestOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfEnterTournamentQuest{}
|
||||
if pkt.Opcode() != network.MSG_MHF_ENTER_TOURNAMENT_QUEST {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_ENTER_TOURNAMENT_QUEST", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfResetAchievementOpcode tests MsgMhfResetAchievement Opcode
|
||||
func TestMsgMhfResetAchievementOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfResetAchievement{}
|
||||
if pkt.Opcode() != network.MSG_MHF_RESET_ACHIEVEMENT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_RESET_ACHIEVEMENT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfPaymentAchievementOpcode tests MsgMhfPaymentAchievement Opcode
|
||||
func TestMsgMhfPaymentAchievementOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfPaymentAchievement{}
|
||||
if pkt.Opcode() != network.MSG_MHF_PAYMENT_ACHIEVEMENT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_PAYMENT_ACHIEVEMENT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfDisplayedAchievementOpcode tests MsgMhfDisplayedAchievement Opcode
|
||||
func TestMsgMhfDisplayedAchievementOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfDisplayedAchievement{}
|
||||
if pkt.Opcode() != network.MSG_MHF_DISPLAYED_ACHIEVEMENT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_DISPLAYED_ACHIEVEMENT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfGetBbsSnsStatusOpcode tests MsgMhfGetBbsSnsStatus Opcode
|
||||
func TestMsgMhfGetBbsSnsStatusOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfGetBbsSnsStatus{}
|
||||
if pkt.Opcode() != network.MSG_MHF_GET_BBS_SNS_STATUS {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_GET_BBS_SNS_STATUS", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfApplyBbsArticleOpcode tests MsgMhfApplyBbsArticle Opcode
|
||||
func TestMsgMhfApplyBbsArticleOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfApplyBbsArticle{}
|
||||
if pkt.Opcode() != network.MSG_MHF_APPLY_BBS_ARTICLE {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_APPLY_BBS_ARTICLE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfGetEtcPointsOpcode tests MsgMhfGetEtcPoints Opcode
|
||||
func TestMsgMhfGetEtcPointsOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfGetEtcPoints{}
|
||||
if pkt.Opcode() != network.MSG_MHF_GET_ETC_POINTS {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_GET_ETC_POINTS", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfUpdateEtcPointOpcode tests MsgMhfUpdateEtcPoint Opcode
|
||||
func TestMsgMhfUpdateEtcPointOpcode(t *testing.T) {
|
||||
pkt := &MsgMhfUpdateEtcPoint{}
|
||||
if pkt.Opcode() != network.MSG_MHF_UPDATE_ETC_POINT {
|
||||
t.Errorf("Opcode() = %s, want MSG_MHF_UPDATE_ETC_POINT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestAchievementPacketParse tests simple achievement packet parsing
|
||||
func TestAchievementPacketParse(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint8(5) // AchievementID
|
||||
bf.WriteUint16(100) // Unk1
|
||||
bf.WriteUint16(200) // Unk2
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAddAchievement{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AchievementID != 5 {
|
||||
t.Errorf("AchievementID = %d, want 5", pkt.AchievementID)
|
||||
}
|
||||
if pkt.Unk1 != 100 {
|
||||
t.Errorf("Unk1 = %d, want 100", pkt.Unk1)
|
||||
}
|
||||
if pkt.Unk2 != 200 {
|
||||
t.Errorf("Unk2 = %d, want 200", pkt.Unk2)
|
||||
}
|
||||
}
|
||||
301
network/mhfpacket/msg_opcode_coverage_test.go
Normal file
301
network/mhfpacket/msg_opcode_coverage_test.go
Normal file
@@ -0,0 +1,301 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
// callBuildSafe calls Build on the packet, recovering from panics.
|
||||
// Returns the error from Build, or nil if it panicked (panic is acceptable
|
||||
// for "Not implemented" stubs).
|
||||
func callBuildSafe(pkt MHFPacket, bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) (err error, panicked bool) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
panicked = true
|
||||
}
|
||||
}()
|
||||
err = pkt.Build(bf, ctx)
|
||||
return err, false
|
||||
}
|
||||
|
||||
// callParseSafe calls Parse on the packet, recovering from panics.
|
||||
func callParseSafe(pkt MHFPacket, bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) (err error, panicked bool) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
panicked = true
|
||||
}
|
||||
}()
|
||||
err = pkt.Parse(bf, ctx)
|
||||
return err, false
|
||||
}
|
||||
|
||||
// TestBuildCoverage_NotImplemented exercises Build() on packet types whose Build
|
||||
// method is not yet covered. These stubs either return errors.New("NOT IMPLEMENTED")
|
||||
// or panic("Not implemented"). Both are acceptable outcomes that indicate the
|
||||
// method was reached.
|
||||
func TestBuildCoverage_NotImplemented(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pkt MHFPacket
|
||||
}{
|
||||
// msg_ca_exchange_item.go
|
||||
{"MsgCaExchangeItem", &MsgCaExchangeItem{}},
|
||||
// msg_head.go
|
||||
{"MsgHead", &MsgHead{}},
|
||||
// msg_mhf_acquire_cafe_item.go
|
||||
{"MsgMhfAcquireCafeItem", &MsgMhfAcquireCafeItem{}},
|
||||
// msg_mhf_acquire_monthly_item.go
|
||||
{"MsgMhfAcquireMonthlyItem", &MsgMhfAcquireMonthlyItem{}},
|
||||
// msg_mhf_acquire_ud_item.go
|
||||
{"MsgMhfAcquireUdItem", &MsgMhfAcquireUdItem{}},
|
||||
// msg_mhf_announce.go
|
||||
{"MsgMhfAnnounce", &MsgMhfAnnounce{}},
|
||||
// msg_mhf_check_monthly_item.go
|
||||
{"MsgMhfCheckMonthlyItem", &MsgMhfCheckMonthlyItem{}},
|
||||
// msg_mhf_check_weekly_stamp.go
|
||||
{"MsgMhfCheckWeeklyStamp", &MsgMhfCheckWeeklyStamp{}},
|
||||
// msg_mhf_enumerate_festa_member.go
|
||||
{"MsgMhfEnumerateFestaMember", &MsgMhfEnumerateFestaMember{}},
|
||||
// msg_mhf_enumerate_inv_guild.go
|
||||
{"MsgMhfEnumerateInvGuild", &MsgMhfEnumerateInvGuild{}},
|
||||
// msg_mhf_enumerate_item.go
|
||||
{"MsgMhfEnumerateItem", &MsgMhfEnumerateItem{}},
|
||||
// msg_mhf_enumerate_order.go
|
||||
{"MsgMhfEnumerateOrder", &MsgMhfEnumerateOrder{}},
|
||||
// msg_mhf_enumerate_quest.go
|
||||
{"MsgMhfEnumerateQuest", &MsgMhfEnumerateQuest{}},
|
||||
// msg_mhf_enumerate_ranking.go
|
||||
{"MsgMhfEnumerateRanking", &MsgMhfEnumerateRanking{}},
|
||||
// msg_mhf_enumerate_shop.go
|
||||
{"MsgMhfEnumerateShop", &MsgMhfEnumerateShop{}},
|
||||
// msg_mhf_enumerate_warehouse.go
|
||||
{"MsgMhfEnumerateWarehouse", &MsgMhfEnumerateWarehouse{}},
|
||||
// msg_mhf_exchange_fpoint_2_item.go
|
||||
{"MsgMhfExchangeFpoint2Item", &MsgMhfExchangeFpoint2Item{}},
|
||||
// msg_mhf_exchange_item_2_fpoint.go
|
||||
{"MsgMhfExchangeItem2Fpoint", &MsgMhfExchangeItem2Fpoint{}},
|
||||
// msg_mhf_exchange_weekly_stamp.go
|
||||
{"MsgMhfExchangeWeeklyStamp", &MsgMhfExchangeWeeklyStamp{}},
|
||||
// msg_mhf_generate_ud_guild_map.go
|
||||
{"MsgMhfGenerateUdGuildMap", &MsgMhfGenerateUdGuildMap{}},
|
||||
// msg_mhf_get_boost_time.go
|
||||
{"MsgMhfGetBoostTime", &MsgMhfGetBoostTime{}},
|
||||
// msg_mhf_get_boost_time_limit.go
|
||||
{"MsgMhfGetBoostTimeLimit", &MsgMhfGetBoostTimeLimit{}},
|
||||
// msg_mhf_get_cafe_duration.go
|
||||
{"MsgMhfGetCafeDuration", &MsgMhfGetCafeDuration{}},
|
||||
// msg_mhf_get_cafe_duration_bonus_info.go
|
||||
{"MsgMhfGetCafeDurationBonusInfo", &MsgMhfGetCafeDurationBonusInfo{}},
|
||||
// msg_mhf_get_cog_info.go
|
||||
{"MsgMhfGetCogInfo", &MsgMhfGetCogInfo{}},
|
||||
// msg_mhf_get_gacha_point.go
|
||||
{"MsgMhfGetGachaPoint", &MsgMhfGetGachaPoint{}},
|
||||
// msg_mhf_get_gem_info.go
|
||||
{"MsgMhfGetGemInfo", &MsgMhfGetGemInfo{}},
|
||||
// msg_mhf_get_kiju_info.go
|
||||
{"MsgMhfGetKijuInfo", &MsgMhfGetKijuInfo{}},
|
||||
// msg_mhf_get_myhouse_info.go
|
||||
{"MsgMhfGetMyhouseInfo", &MsgMhfGetMyhouseInfo{}},
|
||||
// msg_mhf_get_notice.go
|
||||
{"MsgMhfGetNotice", &MsgMhfGetNotice{}},
|
||||
// msg_mhf_get_tower_info.go
|
||||
{"MsgMhfGetTowerInfo", &MsgMhfGetTowerInfo{}},
|
||||
// msg_mhf_get_ud_info.go
|
||||
{"MsgMhfGetUdInfo", &MsgMhfGetUdInfo{}},
|
||||
// msg_mhf_get_ud_schedule.go
|
||||
{"MsgMhfGetUdSchedule", &MsgMhfGetUdSchedule{}},
|
||||
// msg_mhf_get_weekly_schedule.go
|
||||
{"MsgMhfGetWeeklySchedule", &MsgMhfGetWeeklySchedule{}},
|
||||
// msg_mhf_guild_huntdata.go
|
||||
{"MsgMhfGuildHuntdata", &MsgMhfGuildHuntdata{}},
|
||||
// msg_mhf_info_joint.go
|
||||
{"MsgMhfInfoJoint", &MsgMhfInfoJoint{}},
|
||||
// msg_mhf_load_deco_myset.go
|
||||
{"MsgMhfLoadDecoMyset", &MsgMhfLoadDecoMyset{}},
|
||||
// msg_mhf_load_guild_adventure.go
|
||||
{"MsgMhfLoadGuildAdventure", &MsgMhfLoadGuildAdventure{}},
|
||||
// msg_mhf_load_guild_cooking.go
|
||||
{"MsgMhfLoadGuildCooking", &MsgMhfLoadGuildCooking{}},
|
||||
// msg_mhf_load_hunter_navi.go
|
||||
{"MsgMhfLoadHunterNavi", &MsgMhfLoadHunterNavi{}},
|
||||
// msg_mhf_load_otomo_airou.go
|
||||
{"MsgMhfLoadOtomoAirou", &MsgMhfLoadOtomoAirou{}},
|
||||
// msg_mhf_load_partner.go
|
||||
{"MsgMhfLoadPartner", &MsgMhfLoadPartner{}},
|
||||
// msg_mhf_load_plate_box.go
|
||||
{"MsgMhfLoadPlateBox", &MsgMhfLoadPlateBox{}},
|
||||
// msg_mhf_load_plate_data.go
|
||||
{"MsgMhfLoadPlateData", &MsgMhfLoadPlateData{}},
|
||||
// msg_mhf_post_notice.go
|
||||
{"MsgMhfPostNotice", &MsgMhfPostNotice{}},
|
||||
// msg_mhf_post_tower_info.go
|
||||
{"MsgMhfPostTowerInfo", &MsgMhfPostTowerInfo{}},
|
||||
// msg_mhf_reserve10f.go
|
||||
{"MsgMhfReserve10F", &MsgMhfReserve10F{}},
|
||||
// msg_mhf_server_command.go
|
||||
{"MsgMhfServerCommand", &MsgMhfServerCommand{}},
|
||||
// msg_mhf_set_loginwindow.go
|
||||
{"MsgMhfSetLoginwindow", &MsgMhfSetLoginwindow{}},
|
||||
// msg_mhf_shut_client.go
|
||||
{"MsgMhfShutClient", &MsgMhfShutClient{}},
|
||||
// msg_mhf_stampcard_stamp.go
|
||||
{"MsgMhfStampcardStamp", &MsgMhfStampcardStamp{}},
|
||||
// msg_sys_add_object.go
|
||||
{"MsgSysAddObject", &MsgSysAddObject{}},
|
||||
// msg_sys_back_stage.go
|
||||
{"MsgSysBackStage", &MsgSysBackStage{}},
|
||||
// msg_sys_cast_binary.go
|
||||
{"MsgSysCastBinary", &MsgSysCastBinary{}},
|
||||
// msg_sys_create_semaphore.go
|
||||
{"MsgSysCreateSemaphore", &MsgSysCreateSemaphore{}},
|
||||
// msg_sys_create_stage.go
|
||||
{"MsgSysCreateStage", &MsgSysCreateStage{}},
|
||||
// msg_sys_del_object.go
|
||||
{"MsgSysDelObject", &MsgSysDelObject{}},
|
||||
// msg_sys_disp_object.go
|
||||
{"MsgSysDispObject", &MsgSysDispObject{}},
|
||||
// msg_sys_echo.go
|
||||
{"MsgSysEcho", &MsgSysEcho{}},
|
||||
// msg_sys_enter_stage.go
|
||||
{"MsgSysEnterStage", &MsgSysEnterStage{}},
|
||||
// msg_sys_enumerate_client.go
|
||||
{"MsgSysEnumerateClient", &MsgSysEnumerateClient{}},
|
||||
// msg_sys_extend_threshold.go
|
||||
{"MsgSysExtendThreshold", &MsgSysExtendThreshold{}},
|
||||
// msg_sys_get_stage_binary.go
|
||||
{"MsgSysGetStageBinary", &MsgSysGetStageBinary{}},
|
||||
// msg_sys_hide_object.go
|
||||
{"MsgSysHideObject", &MsgSysHideObject{}},
|
||||
// msg_sys_leave_stage.go
|
||||
{"MsgSysLeaveStage", &MsgSysLeaveStage{}},
|
||||
// msg_sys_lock_stage.go
|
||||
{"MsgSysLockStage", &MsgSysLockStage{}},
|
||||
// msg_sys_login.go
|
||||
{"MsgSysLogin", &MsgSysLogin{}},
|
||||
// msg_sys_move_stage.go
|
||||
{"MsgSysMoveStage", &MsgSysMoveStage{}},
|
||||
// msg_sys_set_stage_binary.go
|
||||
{"MsgSysSetStageBinary", &MsgSysSetStageBinary{}},
|
||||
// msg_sys_set_stage_pass.go
|
||||
{"MsgSysSetStagePass", &MsgSysSetStagePass{}},
|
||||
// msg_sys_set_status.go
|
||||
{"MsgSysSetStatus", &MsgSysSetStatus{}},
|
||||
// msg_sys_wait_stage_binary.go
|
||||
{"MsgSysWaitStageBinary", &MsgSysWaitStageBinary{}},
|
||||
|
||||
// Reserve files - sys reserves
|
||||
{"MsgSysReserve01", &MsgSysReserve01{}},
|
||||
{"MsgSysReserve02", &MsgSysReserve02{}},
|
||||
{"MsgSysReserve03", &MsgSysReserve03{}},
|
||||
{"MsgSysReserve04", &MsgSysReserve04{}},
|
||||
{"MsgSysReserve05", &MsgSysReserve05{}},
|
||||
{"MsgSysReserve06", &MsgSysReserve06{}},
|
||||
{"MsgSysReserve07", &MsgSysReserve07{}},
|
||||
{"MsgSysReserve0C", &MsgSysReserve0C{}},
|
||||
{"MsgSysReserve0D", &MsgSysReserve0D{}},
|
||||
{"MsgSysReserve0E", &MsgSysReserve0E{}},
|
||||
{"MsgSysReserve4A", &MsgSysReserve4A{}},
|
||||
{"MsgSysReserve4B", &MsgSysReserve4B{}},
|
||||
{"MsgSysReserve4C", &MsgSysReserve4C{}},
|
||||
{"MsgSysReserve4D", &MsgSysReserve4D{}},
|
||||
{"MsgSysReserve4E", &MsgSysReserve4E{}},
|
||||
{"MsgSysReserve4F", &MsgSysReserve4F{}},
|
||||
{"MsgSysReserve55", &MsgSysReserve55{}},
|
||||
{"MsgSysReserve56", &MsgSysReserve56{}},
|
||||
{"MsgSysReserve57", &MsgSysReserve57{}},
|
||||
{"MsgSysReserve5C", &MsgSysReserve5C{}},
|
||||
{"MsgSysReserve5E", &MsgSysReserve5E{}},
|
||||
{"MsgSysReserve5F", &MsgSysReserve5F{}},
|
||||
{"MsgSysReserve71", &MsgSysReserve71{}},
|
||||
{"MsgSysReserve72", &MsgSysReserve72{}},
|
||||
{"MsgSysReserve73", &MsgSysReserve73{}},
|
||||
{"MsgSysReserve74", &MsgSysReserve74{}},
|
||||
{"MsgSysReserve75", &MsgSysReserve75{}},
|
||||
{"MsgSysReserve76", &MsgSysReserve76{}},
|
||||
{"MsgSysReserve77", &MsgSysReserve77{}},
|
||||
{"MsgSysReserve78", &MsgSysReserve78{}},
|
||||
{"MsgSysReserve79", &MsgSysReserve79{}},
|
||||
{"MsgSysReserve7A", &MsgSysReserve7A{}},
|
||||
{"MsgSysReserve7B", &MsgSysReserve7B{}},
|
||||
{"MsgSysReserve7C", &MsgSysReserve7C{}},
|
||||
{"MsgSysReserve7E", &MsgSysReserve7E{}},
|
||||
{"MsgSysReserve180", &MsgSysReserve180{}},
|
||||
{"MsgSysReserve188", &MsgSysReserve188{}},
|
||||
{"MsgSysReserve18B", &MsgSysReserve18B{}},
|
||||
{"MsgSysReserve18E", &MsgSysReserve18E{}},
|
||||
{"MsgSysReserve18F", &MsgSysReserve18F{}},
|
||||
{"MsgSysReserve192", &MsgSysReserve192{}},
|
||||
{"MsgSysReserve193", &MsgSysReserve193{}},
|
||||
{"MsgSysReserve194", &MsgSysReserve194{}},
|
||||
{"MsgSysReserve19B", &MsgSysReserve19B{}},
|
||||
{"MsgSysReserve19E", &MsgSysReserve19E{}},
|
||||
{"MsgSysReserve19F", &MsgSysReserve19F{}},
|
||||
{"MsgSysReserve1A4", &MsgSysReserve1A4{}},
|
||||
{"MsgSysReserve1A6", &MsgSysReserve1A6{}},
|
||||
{"MsgSysReserve1A7", &MsgSysReserve1A7{}},
|
||||
{"MsgSysReserve1A8", &MsgSysReserve1A8{}},
|
||||
{"MsgSysReserve1A9", &MsgSysReserve1A9{}},
|
||||
{"MsgSysReserve1AA", &MsgSysReserve1AA{}},
|
||||
{"MsgSysReserve1AB", &MsgSysReserve1AB{}},
|
||||
{"MsgSysReserve1AC", &MsgSysReserve1AC{}},
|
||||
{"MsgSysReserve1AD", &MsgSysReserve1AD{}},
|
||||
{"MsgSysReserve1AE", &MsgSysReserve1AE{}},
|
||||
{"MsgSysReserve1AF", &MsgSysReserve1AF{}},
|
||||
}
|
||||
|
||||
ctx := &clientctx.ClientContext{}
|
||||
bf := byteframe.NewByteFrame()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err, panicked := callBuildSafe(tt.pkt, bf, ctx)
|
||||
if panicked {
|
||||
// Build panicked with "Not implemented" - this is acceptable
|
||||
// and still exercises the code path for coverage.
|
||||
return
|
||||
}
|
||||
if err == nil {
|
||||
// Build succeeded (some packets may have implemented Build)
|
||||
return
|
||||
}
|
||||
// Build returned an error, which is expected for NOT IMPLEMENTED stubs
|
||||
if err.Error() != "NOT IMPLEMENTED" {
|
||||
t.Errorf("Build() returned unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseCoverage_NotImplemented exercises Parse() on packet types whose Parse
|
||||
// method returns "NOT IMPLEMENTED" and is not yet covered by existing tests.
|
||||
func TestParseCoverage_NotImplemented(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pkt MHFPacket
|
||||
}{
|
||||
// msg_mhf_acquire_tournament.go - Parse returns NOT IMPLEMENTED
|
||||
{"MsgMhfAcquireTournament", &MsgMhfAcquireTournament{}},
|
||||
// msg_mhf_entry_tournament.go - Parse returns NOT IMPLEMENTED
|
||||
{"MsgMhfEntryTournament", &MsgMhfEntryTournament{}},
|
||||
// msg_mhf_update_guild.go - Parse returns NOT IMPLEMENTED
|
||||
{"MsgMhfUpdateGuild", &MsgMhfUpdateGuild{}},
|
||||
}
|
||||
|
||||
ctx := &clientctx.ClientContext{}
|
||||
bf := byteframe.NewByteFrame()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err, panicked := callParseSafe(tt.pkt, bf, ctx)
|
||||
if panicked {
|
||||
return
|
||||
}
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if err.Error() != "NOT IMPLEMENTED" {
|
||||
t.Errorf("Parse() returned unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
880
network/mhfpacket/msg_parse_large_test.go
Normal file
880
network/mhfpacket/msg_parse_large_test.go
Normal file
@@ -0,0 +1,880 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
// TestParseLargeMsgSysUpdateRightBuild tests Build for MsgSysUpdateRight (no Parse implementation).
|
||||
func TestParseLargeMsgSysUpdateRightBuild(t *testing.T) {
|
||||
ctx := &clientctx.ClientContext{}
|
||||
original := &MsgSysUpdateRight{
|
||||
ClientRespAckHandle: 0x12345678,
|
||||
Bitfield: 0xDEADBEEF,
|
||||
Rights: nil,
|
||||
UnkSize: 0,
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
if err := original.Build(bf, ctx); err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Verify binary output manually:
|
||||
// uint32 ClientRespAckHandle + uint32 Bitfield + uint16 Rights count(0) + uint16 padding(0) + ps.Uint16 empty string(uint16(1) + 0x00)
|
||||
data := bf.Data()
|
||||
if len(data) < 12 {
|
||||
t.Fatalf("Build() wrote %d bytes, want at least 12", len(data))
|
||||
}
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
if bf.ReadUint32() != 0x12345678 {
|
||||
t.Error("ClientRespAckHandle mismatch")
|
||||
}
|
||||
if bf.ReadUint32() != 0xDEADBEEF {
|
||||
t.Error("Bitfield mismatch")
|
||||
}
|
||||
if bf.ReadUint16() != 0 {
|
||||
t.Error("Rights count should be 0")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfOperateWarehouse tests Parse for MsgMhfOperateWarehouse.
|
||||
func TestParseLargeMsgMhfOperateWarehouse(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xAABBCCDD) // AckHandle
|
||||
bf.WriteUint8(1) // Operation
|
||||
bf.WriteUint8(0) // BoxType = item
|
||||
bf.WriteUint8(2) // BoxIndex
|
||||
bf.WriteUint8(8) // lenName (unused but read)
|
||||
bf.WriteUint16(0) // Unk
|
||||
bf.WriteBytes([]byte("TestBox"))
|
||||
bf.WriteUint8(0) // null terminator
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfOperateWarehouse{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xAABBCCDD {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xAABBCCDD", pkt.AckHandle)
|
||||
}
|
||||
if pkt.Operation != 1 {
|
||||
t.Errorf("Operation = %d, want 1", pkt.Operation)
|
||||
}
|
||||
if pkt.BoxType != 0 {
|
||||
t.Errorf("BoxType = %d, want 0", pkt.BoxType)
|
||||
}
|
||||
if pkt.BoxIndex != 2 {
|
||||
t.Errorf("BoxIndex = %d, want 2", pkt.BoxIndex)
|
||||
}
|
||||
if pkt.Name != "TestBox" {
|
||||
t.Errorf("Name = %q, want %q", pkt.Name, "TestBox")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfOperateWarehouseEquip tests Parse for MsgMhfOperateWarehouse with equip box type.
|
||||
func TestParseLargeMsgMhfOperateWarehouseEquip(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(42) // AckHandle
|
||||
bf.WriteUint8(2) // Operation
|
||||
bf.WriteUint8(1) // BoxType = equip
|
||||
bf.WriteUint8(0) // BoxIndex
|
||||
bf.WriteUint8(5) // lenName
|
||||
bf.WriteUint16(0) // Unk
|
||||
bf.WriteBytes([]byte("Arms"))
|
||||
bf.WriteUint8(0) // null terminator
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfOperateWarehouse{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.BoxType != 1 {
|
||||
t.Errorf("BoxType = %d, want 1", pkt.BoxType)
|
||||
}
|
||||
if pkt.Name != "Arms" {
|
||||
t.Errorf("Name = %q, want %q", pkt.Name, "Arms")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfLoadHouse tests Parse for MsgMhfLoadHouse.
|
||||
func TestParseLargeMsgMhfLoadHouse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ackHandle uint32
|
||||
charID uint32
|
||||
destination uint8
|
||||
checkPass bool
|
||||
password string
|
||||
}{
|
||||
{"with password", 0xAABBCCDD, 12345, 1, true, "pass123"},
|
||||
{"no password", 0x11111111, 0, 0, false, ""},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ackHandle)
|
||||
bf.WriteUint32(tt.charID)
|
||||
bf.WriteUint8(tt.destination)
|
||||
bf.WriteBool(tt.checkPass)
|
||||
bf.WriteUint16(0) // Unk (hardcoded 0)
|
||||
bf.WriteUint8(uint8(len(tt.password) + 1)) // Password length
|
||||
bf.WriteBytes([]byte(tt.password))
|
||||
bf.WriteUint8(0) // null terminator
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfLoadHouse{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ackHandle {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ackHandle)
|
||||
}
|
||||
if pkt.CharID != tt.charID {
|
||||
t.Errorf("CharID = %d, want %d", pkt.CharID, tt.charID)
|
||||
}
|
||||
if pkt.Destination != tt.destination {
|
||||
t.Errorf("Destination = %d, want %d", pkt.Destination, tt.destination)
|
||||
}
|
||||
if pkt.CheckPass != tt.checkPass {
|
||||
t.Errorf("CheckPass = %v, want %v", pkt.CheckPass, tt.checkPass)
|
||||
}
|
||||
if pkt.Password != tt.password {
|
||||
t.Errorf("Password = %q, want %q", pkt.Password, tt.password)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfSendMail tests Parse for MsgMhfSendMail.
|
||||
func TestParseLargeMsgMhfSendMail(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x12345678) // AckHandle
|
||||
bf.WriteUint32(99999) // RecipientID
|
||||
bf.WriteUint16(6) // SubjectLength
|
||||
bf.WriteUint16(12) // BodyLength
|
||||
bf.WriteUint32(5) // Quantity
|
||||
bf.WriteUint16(1001) // ItemID
|
||||
bf.WriteBytes([]byte("Hello"))
|
||||
bf.WriteUint8(0) // null terminator for Subject
|
||||
bf.WriteBytes([]byte("Hello World"))
|
||||
bf.WriteUint8(0) // null terminator for Body
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfSendMail{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x12345678 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x12345678", pkt.AckHandle)
|
||||
}
|
||||
if pkt.RecipientID != 99999 {
|
||||
t.Errorf("RecipientID = %d, want 99999", pkt.RecipientID)
|
||||
}
|
||||
if pkt.SubjectLength != 6 {
|
||||
t.Errorf("SubjectLength = %d, want 6", pkt.SubjectLength)
|
||||
}
|
||||
if pkt.BodyLength != 12 {
|
||||
t.Errorf("BodyLength = %d, want 12", pkt.BodyLength)
|
||||
}
|
||||
if pkt.Quantity != 5 {
|
||||
t.Errorf("Quantity = %d, want 5", pkt.Quantity)
|
||||
}
|
||||
if pkt.ItemID != 1001 {
|
||||
t.Errorf("ItemID = %d, want 1001", pkt.ItemID)
|
||||
}
|
||||
if pkt.Subject != "Hello" {
|
||||
t.Errorf("Subject = %q, want %q", pkt.Subject, "Hello")
|
||||
}
|
||||
if pkt.Body != "Hello World" {
|
||||
t.Errorf("Body = %q, want %q", pkt.Body, "Hello World")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfApplyBbsArticle tests Parse for MsgMhfApplyBbsArticle.
|
||||
func TestParseLargeMsgMhfApplyBbsArticle(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xCAFEBABE) // AckHandle
|
||||
bf.WriteUint32(42) // Unk0
|
||||
|
||||
// Unk1: 16 bytes
|
||||
unk1 := make([]byte, 16)
|
||||
for i := range unk1 {
|
||||
unk1[i] = byte(i + 1)
|
||||
}
|
||||
bf.WriteBytes(unk1)
|
||||
|
||||
// Name: 32 bytes (padded with nulls) - uses bfutil.UpToNull
|
||||
nameBytes := make([]byte, 32)
|
||||
copy(nameBytes, "Hunter")
|
||||
bf.WriteBytes(nameBytes)
|
||||
|
||||
// Title: 128 bytes (padded with nulls)
|
||||
titleBytes := make([]byte, 128)
|
||||
copy(titleBytes, "My Post Title")
|
||||
bf.WriteBytes(titleBytes)
|
||||
|
||||
// Description: 256 bytes (padded with nulls)
|
||||
descBytes := make([]byte, 256)
|
||||
copy(descBytes, "This is a description")
|
||||
bf.WriteBytes(descBytes)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfApplyBbsArticle{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xCAFEBABE {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xCAFEBABE", pkt.AckHandle)
|
||||
}
|
||||
if pkt.Unk0 != 42 {
|
||||
t.Errorf("Unk0 = %d, want 42", pkt.Unk0)
|
||||
}
|
||||
if !bytes.Equal(pkt.Unk1, unk1) {
|
||||
t.Error("Unk1 mismatch")
|
||||
}
|
||||
if pkt.Name != "Hunter" {
|
||||
t.Errorf("Name = %q, want %q", pkt.Name, "Hunter")
|
||||
}
|
||||
if pkt.Title != "My Post Title" {
|
||||
t.Errorf("Title = %q, want %q", pkt.Title, "My Post Title")
|
||||
}
|
||||
if pkt.Description != "This is a description" {
|
||||
t.Errorf("Description = %q, want %q", pkt.Description, "This is a description")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfChargeFesta tests Parse for MsgMhfChargeFesta.
|
||||
func TestParseLargeMsgMhfChargeFesta(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x11223344) // AckHandle
|
||||
bf.WriteUint32(100) // FestaID
|
||||
bf.WriteUint32(200) // GuildID
|
||||
bf.WriteUint16(3) // soul count
|
||||
bf.WriteUint16(10) // soul value 1
|
||||
bf.WriteUint16(20) // soul value 2
|
||||
bf.WriteUint16(30) // soul value 3
|
||||
bf.WriteUint8(0) // Unk
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfChargeFesta{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x11223344 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x11223344", pkt.AckHandle)
|
||||
}
|
||||
if pkt.FestaID != 100 {
|
||||
t.Errorf("FestaID = %d, want 100", pkt.FestaID)
|
||||
}
|
||||
if pkt.GuildID != 200 {
|
||||
t.Errorf("GuildID = %d, want 200", pkt.GuildID)
|
||||
}
|
||||
if len(pkt.Souls) != 3 {
|
||||
t.Fatalf("Souls len = %d, want 3", len(pkt.Souls))
|
||||
}
|
||||
expectedSouls := []uint16{10, 20, 30}
|
||||
for i, v := range expectedSouls {
|
||||
if pkt.Souls[i] != v {
|
||||
t.Errorf("Souls[%d] = %d, want %d", i, pkt.Souls[i], v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfChargeFestaZeroSouls tests Parse for MsgMhfChargeFesta with zero soul entries.
|
||||
func TestParseLargeMsgMhfChargeFestaZeroSouls(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1) // AckHandle
|
||||
bf.WriteUint32(0) // FestaID
|
||||
bf.WriteUint32(0) // GuildID
|
||||
bf.WriteUint16(0) // soul count = 0
|
||||
bf.WriteUint8(0) // Unk
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfChargeFesta{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if len(pkt.Souls) != 0 {
|
||||
t.Errorf("Souls len = %d, want 0", len(pkt.Souls))
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfOperateJoint tests Parse for MsgMhfOperateJoint.
|
||||
// Parse reads: uint32 AckHandle, uint32 AllianceID, uint32 GuildID, uint8 Action,
|
||||
// uint8 dataLen, 4 bytes Data1, dataLen bytes Data2.
|
||||
func TestParseLargeMsgMhfOperateJoint(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x12345678) // AckHandle
|
||||
bf.WriteUint32(100) // AllianceID
|
||||
bf.WriteUint32(200) // GuildID
|
||||
bf.WriteUint8(0x01) // Action = OPERATE_JOINT_DISBAND
|
||||
bf.WriteUint8(3) // dataLen = 3
|
||||
bf.WriteBytes([]byte{0xAA, 0xBB, 0xCC, 0xDD}) // Data1 (always 4 bytes)
|
||||
bf.WriteBytes([]byte{0x01, 0x02, 0x03}) // Data2 (dataLen bytes)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfOperateJoint{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x12345678 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x12345678", pkt.AckHandle)
|
||||
}
|
||||
if pkt.AllianceID != 100 {
|
||||
t.Errorf("AllianceID = %d, want 100", pkt.AllianceID)
|
||||
}
|
||||
if pkt.GuildID != 200 {
|
||||
t.Errorf("GuildID = %d, want 200", pkt.GuildID)
|
||||
}
|
||||
if pkt.Action != OPERATE_JOINT_DISBAND {
|
||||
t.Errorf("Action = %d, want %d", pkt.Action, OPERATE_JOINT_DISBAND)
|
||||
}
|
||||
if pkt.Data1 == nil {
|
||||
t.Fatal("Data1 is nil")
|
||||
}
|
||||
if pkt.Data2 == nil {
|
||||
t.Fatal("Data2 is nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfOperationInvGuild tests Parse for MsgMhfOperationInvGuild.
|
||||
func TestParseLargeMsgMhfOperationInvGuild(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xAABBCCDD) // AckHandle
|
||||
bf.WriteUint8(1) // Operation
|
||||
bf.WriteUint8(5) // ActiveHours
|
||||
bf.WriteUint8(7) // DaysActive
|
||||
bf.WriteUint8(3) // PlayStyle
|
||||
bf.WriteUint8(2) // GuildRequest
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfOperationInvGuild{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xAABBCCDD {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xAABBCCDD", pkt.AckHandle)
|
||||
}
|
||||
if pkt.Operation != 1 {
|
||||
t.Errorf("Operation = %d, want 1", pkt.Operation)
|
||||
}
|
||||
if pkt.ActiveHours != 5 {
|
||||
t.Errorf("ActiveHours = %d, want 5", pkt.ActiveHours)
|
||||
}
|
||||
if pkt.DaysActive != 7 {
|
||||
t.Errorf("DaysActive = %d, want 7", pkt.DaysActive)
|
||||
}
|
||||
if pkt.PlayStyle != 3 {
|
||||
t.Errorf("PlayStyle = %d, want 3", pkt.PlayStyle)
|
||||
}
|
||||
if pkt.GuildRequest != 2 {
|
||||
t.Errorf("GuildRequest = %d, want 2", pkt.GuildRequest)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfSaveMercenary tests Parse for MsgMhfSaveMercenary.
|
||||
func TestParseLargeMsgMhfSaveMercenary(t *testing.T) {
|
||||
mercData := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xCAFEBABE) // AckHandle
|
||||
bf.WriteUint32(0) // lenData (skipped)
|
||||
bf.WriteUint32(5000) // GCP
|
||||
bf.WriteUint32(42) // PactMercID
|
||||
bf.WriteUint32(uint32(len(mercData))) // dataSize
|
||||
bf.WriteUint32(0) // Merc index (skipped)
|
||||
bf.WriteBytes(mercData)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfSaveMercenary{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xCAFEBABE {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xCAFEBABE", pkt.AckHandle)
|
||||
}
|
||||
if pkt.GCP != 5000 {
|
||||
t.Errorf("GCP = %d, want 5000", pkt.GCP)
|
||||
}
|
||||
if pkt.PactMercID != 42 {
|
||||
t.Errorf("PactMercID = %d, want 42", pkt.PactMercID)
|
||||
}
|
||||
if !bytes.Equal(pkt.MercData, mercData) {
|
||||
t.Errorf("MercData = %v, want %v", pkt.MercData, mercData)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfUpdateHouse tests Parse for MsgMhfUpdateHouse.
|
||||
func TestParseLargeMsgMhfUpdateHouse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
state uint8
|
||||
password string
|
||||
}{
|
||||
{"with password", 1, "secret"},
|
||||
{"empty password", 0, ""},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x12345678) // AckHandle
|
||||
bf.WriteUint8(tt.state) // State
|
||||
bf.WriteUint8(1) // Unk1
|
||||
bf.WriteUint16(0) // Unk2
|
||||
bf.WriteUint8(uint8(len(tt.password) + 1)) // Password length
|
||||
bf.WriteBytes([]byte(tt.password))
|
||||
bf.WriteUint8(0) // null terminator
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfUpdateHouse{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x12345678 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x12345678", pkt.AckHandle)
|
||||
}
|
||||
if pkt.State != tt.state {
|
||||
t.Errorf("State = %d, want %d", pkt.State, tt.state)
|
||||
}
|
||||
if pkt.Unk1 != 1 {
|
||||
t.Errorf("Unk1 = %d, want 1", pkt.Unk1)
|
||||
}
|
||||
if pkt.Password != tt.password {
|
||||
t.Errorf("Password = %q, want %q", pkt.Password, tt.password)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgSysCreateAcquireSemaphore tests Parse for MsgSysCreateAcquireSemaphore.
|
||||
func TestParseLargeMsgSysCreateAcquireSemaphore(t *testing.T) {
|
||||
semID := "stage_001"
|
||||
semBytes := make([]byte, len(semID)+1) // include space for null if needed
|
||||
copy(semBytes, semID)
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xDEADBEEF) // AckHandle
|
||||
bf.WriteUint16(100) // Unk0
|
||||
bf.WriteUint8(4) // PlayerCount
|
||||
bf.WriteUint8(uint8(len(semBytes))) // SemaphoreIDLength
|
||||
bf.WriteBytes(semBytes)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysCreateAcquireSemaphore{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xDEADBEEF {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xDEADBEEF", pkt.AckHandle)
|
||||
}
|
||||
if pkt.Unk0 != 100 {
|
||||
t.Errorf("Unk0 = %d, want 100", pkt.Unk0)
|
||||
}
|
||||
if pkt.PlayerCount != 4 {
|
||||
t.Errorf("PlayerCount = %d, want 4", pkt.PlayerCount)
|
||||
}
|
||||
if pkt.SemaphoreID != semID {
|
||||
t.Errorf("SemaphoreID = %q, want %q", pkt.SemaphoreID, semID)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfOperateGuild tests Parse for MsgMhfOperateGuild.
|
||||
func TestParseLargeMsgMhfOperateGuild(t *testing.T) {
|
||||
dataPayload := []byte{0x10, 0x20, 0x30, 0x40, 0x50}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xAABBCCDD) // AckHandle
|
||||
bf.WriteUint32(999) // GuildID
|
||||
bf.WriteUint8(0x09) // Action = OperateGuildUpdateComment
|
||||
bf.WriteUint8(uint8(len(dataPayload))) // dataLen
|
||||
bf.WriteBytes([]byte{0x01, 0x02, 0x03, 0x04}) // Data1 (always 4 bytes)
|
||||
bf.WriteBytes(dataPayload) // Data2 (dataLen bytes)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfOperateGuild{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xAABBCCDD {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xAABBCCDD", pkt.AckHandle)
|
||||
}
|
||||
if pkt.GuildID != 999 {
|
||||
t.Errorf("GuildID = %d, want 999", pkt.GuildID)
|
||||
}
|
||||
if pkt.Action != OperateGuildUpdateComment {
|
||||
t.Errorf("Action = %d, want %d", pkt.Action, OperateGuildUpdateComment)
|
||||
}
|
||||
if pkt.Data1 == nil {
|
||||
t.Fatal("Data1 is nil")
|
||||
}
|
||||
if pkt.Data2 == nil {
|
||||
t.Fatal("Data2 is nil")
|
||||
}
|
||||
data2Bytes := pkt.Data2.Data()
|
||||
if !bytes.Equal(data2Bytes, dataPayload) {
|
||||
t.Errorf("Data2 = %v, want %v", data2Bytes, dataPayload)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfReadBeatLevel tests Parse for MsgMhfReadBeatLevel.
|
||||
func TestParseLargeMsgMhfReadBeatLevel(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x12345678) // AckHandle
|
||||
bf.WriteUint32(1) // Unk0
|
||||
bf.WriteUint32(4) // ValidIDCount
|
||||
|
||||
// Write 16 uint32 IDs
|
||||
ids := [16]uint32{0x74, 0x6B, 0x02, 0x24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
for _, id := range ids {
|
||||
bf.WriteUint32(id)
|
||||
}
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfReadBeatLevel{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x12345678 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x12345678", pkt.AckHandle)
|
||||
}
|
||||
if pkt.Unk0 != 1 {
|
||||
t.Errorf("Unk0 = %d, want 1", pkt.Unk0)
|
||||
}
|
||||
if pkt.ValidIDCount != 4 {
|
||||
t.Errorf("ValidIDCount = %d, want 4", pkt.ValidIDCount)
|
||||
}
|
||||
for i, id := range ids {
|
||||
if pkt.IDs[i] != id {
|
||||
t.Errorf("IDs[%d] = 0x%X, want 0x%X", i, pkt.IDs[i], id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgSysCreateObject tests Parse for MsgSysCreateObject.
|
||||
func TestParseLargeMsgSysCreateObject(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ackHandle uint32
|
||||
x, y, z float32
|
||||
unk0 uint32
|
||||
}{
|
||||
{"origin", 1, 0.0, 0.0, 0.0, 0},
|
||||
{"typical", 0x12345678, 1.5, 2.5, 3.5, 42},
|
||||
{"negative coords", 0xFFFFFFFF, -100.25, 200.75, -300.125, 0xDEADBEEF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ackHandle)
|
||||
bf.WriteFloat32(tt.x)
|
||||
bf.WriteFloat32(tt.y)
|
||||
bf.WriteFloat32(tt.z)
|
||||
bf.WriteUint32(tt.unk0)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysCreateObject{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ackHandle {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ackHandle)
|
||||
}
|
||||
if pkt.X != tt.x {
|
||||
t.Errorf("X = %f, want %f", pkt.X, tt.x)
|
||||
}
|
||||
if pkt.Y != tt.y {
|
||||
t.Errorf("Y = %f, want %f", pkt.Y, tt.y)
|
||||
}
|
||||
if pkt.Z != tt.z {
|
||||
t.Errorf("Z = %f, want %f", pkt.Z, tt.z)
|
||||
}
|
||||
if pkt.Unk0 != tt.unk0 {
|
||||
t.Errorf("Unk0 = %d, want %d", pkt.Unk0, tt.unk0)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgSysLockGlobalSema tests Parse for MsgSysLockGlobalSema.
|
||||
func TestParseLargeMsgSysLockGlobalSema(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xDEADBEEF) // AckHandle
|
||||
bf.WriteUint16(8) // UserIDLength
|
||||
bf.WriteUint16(11) // ServerChannelIDLength
|
||||
bf.WriteBytes([]byte("user123"))
|
||||
bf.WriteUint8(0) // null terminator
|
||||
bf.WriteBytes([]byte("channel_01"))
|
||||
bf.WriteUint8(0) // null terminator
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysLockGlobalSema{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xDEADBEEF {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xDEADBEEF", pkt.AckHandle)
|
||||
}
|
||||
if pkt.UserIDLength != 8 {
|
||||
t.Errorf("UserIDLength = %d, want 8", pkt.UserIDLength)
|
||||
}
|
||||
if pkt.ServerChannelIDLength != 11 {
|
||||
t.Errorf("ServerChannelIDLength = %d, want 11", pkt.ServerChannelIDLength)
|
||||
}
|
||||
if pkt.UserIDString != "user123" {
|
||||
t.Errorf("UserIDString = %q, want %q", pkt.UserIDString, "user123")
|
||||
}
|
||||
if pkt.ServerChannelIDString != "channel_01" {
|
||||
t.Errorf("ServerChannelIDString = %q, want %q", pkt.ServerChannelIDString, "channel_01")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfCreateJoint tests Parse for MsgMhfCreateJoint.
|
||||
func TestParseLargeMsgMhfCreateJoint(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xCAFEBABE) // AckHandle
|
||||
bf.WriteUint32(500) // GuildID
|
||||
bf.WriteUint32(15) // len (unused)
|
||||
bf.WriteBytes([]byte("Alliance01"))
|
||||
bf.WriteUint8(0) // null terminator
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfCreateJoint{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xCAFEBABE {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xCAFEBABE", pkt.AckHandle)
|
||||
}
|
||||
if pkt.GuildID != 500 {
|
||||
t.Errorf("GuildID = %d, want 500", pkt.GuildID)
|
||||
}
|
||||
if pkt.Name != "Alliance01" {
|
||||
t.Errorf("Name = %q, want %q", pkt.Name, "Alliance01")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfGetUdTacticsRemainingPoint tests Parse for MsgMhfGetUdTacticsRemainingPoint.
|
||||
func TestParseLargeMsgMhfGetUdTacticsRemainingPoint(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x12345678) // AckHandle
|
||||
bf.WriteUint32(100) // Unk0
|
||||
bf.WriteUint32(200) // Unk1
|
||||
bf.WriteUint32(300) // Unk2
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfGetUdTacticsRemainingPoint{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x12345678 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x12345678", pkt.AckHandle)
|
||||
}
|
||||
if pkt.Unk0 != 100 {
|
||||
t.Errorf("Unk0 = %d, want 100", pkt.Unk0)
|
||||
}
|
||||
if pkt.Unk1 != 200 {
|
||||
t.Errorf("Unk1 = %d, want 200", pkt.Unk1)
|
||||
}
|
||||
if pkt.Unk2 != 300 {
|
||||
t.Errorf("Unk2 = %d, want 300", pkt.Unk2)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfPostCafeDurationBonusReceived tests Parse for MsgMhfPostCafeDurationBonusReceived.
|
||||
func TestParseLargeMsgMhfPostCafeDurationBonusReceived(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xAABBCCDD) // AckHandle
|
||||
bf.WriteUint32(3) // count
|
||||
bf.WriteUint32(1001) // CafeBonusID[0]
|
||||
bf.WriteUint32(1002) // CafeBonusID[1]
|
||||
bf.WriteUint32(1003) // CafeBonusID[2]
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfPostCafeDurationBonusReceived{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xAABBCCDD {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xAABBCCDD", pkt.AckHandle)
|
||||
}
|
||||
if len(pkt.CafeBonusID) != 3 {
|
||||
t.Fatalf("CafeBonusID len = %d, want 3", len(pkt.CafeBonusID))
|
||||
}
|
||||
expected := []uint32{1001, 1002, 1003}
|
||||
for i, v := range expected {
|
||||
if pkt.CafeBonusID[i] != v {
|
||||
t.Errorf("CafeBonusID[%d] = %d, want %d", i, pkt.CafeBonusID[i], v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfPostCafeDurationBonusReceivedEmpty tests Parse with zero IDs.
|
||||
func TestParseLargeMsgMhfPostCafeDurationBonusReceivedEmpty(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1) // AckHandle
|
||||
bf.WriteUint32(0) // count = 0
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfPostCafeDurationBonusReceived{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
if len(pkt.CafeBonusID) != 0 {
|
||||
t.Errorf("CafeBonusID len = %d, want 0", len(pkt.CafeBonusID))
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfRegistGuildAdventureDiva tests Parse for MsgMhfRegistGuildAdventureDiva.
|
||||
func TestParseLargeMsgMhfRegistGuildAdventureDiva(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x12345678) // AckHandle
|
||||
bf.WriteUint32(5) // Destination
|
||||
bf.WriteUint32(1000) // Charge
|
||||
bf.WriteUint32(42) // CharID (skipped)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfRegistGuildAdventureDiva{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x12345678 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x12345678", pkt.AckHandle)
|
||||
}
|
||||
if pkt.Destination != 5 {
|
||||
t.Errorf("Destination = %d, want 5", pkt.Destination)
|
||||
}
|
||||
if pkt.Charge != 1000 {
|
||||
t.Errorf("Charge = %d, want 1000", pkt.Charge)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfStateFestaG tests Parse for MsgMhfStateFestaG.
|
||||
func TestParseLargeMsgMhfStateFestaG(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xDEADBEEF) // AckHandle
|
||||
bf.WriteUint32(100) // FestaID
|
||||
bf.WriteUint32(200) // GuildID
|
||||
bf.WriteUint16(0) // Hardcoded 0
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfStateFestaG{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xDEADBEEF {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xDEADBEEF", pkt.AckHandle)
|
||||
}
|
||||
if pkt.FestaID != 100 {
|
||||
t.Errorf("FestaID = %d, want 100", pkt.FestaID)
|
||||
}
|
||||
if pkt.GuildID != 200 {
|
||||
t.Errorf("GuildID = %d, want 200", pkt.GuildID)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgMhfStateFestaU tests Parse for MsgMhfStateFestaU.
|
||||
func TestParseLargeMsgMhfStateFestaU(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xCAFEBABE) // AckHandle
|
||||
bf.WriteUint32(300) // FestaID
|
||||
bf.WriteUint32(400) // GuildID
|
||||
bf.WriteUint16(0) // Hardcoded 0
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfStateFestaU{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xCAFEBABE {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xCAFEBABE", pkt.AckHandle)
|
||||
}
|
||||
if pkt.FestaID != 300 {
|
||||
t.Errorf("FestaID = %d, want 300", pkt.FestaID)
|
||||
}
|
||||
if pkt.GuildID != 400 {
|
||||
t.Errorf("GuildID = %d, want 400", pkt.GuildID)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgSysEnumerateStage tests Parse for MsgSysEnumerateStage.
|
||||
func TestParseLargeMsgSysEnumerateStage(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x11223344) // AckHandle
|
||||
bf.WriteUint8(1) // Unk0
|
||||
bf.WriteUint8(0) // skipped byte
|
||||
bf.WriteBytes([]byte("quest_"))
|
||||
bf.WriteUint8(0) // null terminator
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysEnumerateStage{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x11223344 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x11223344", pkt.AckHandle)
|
||||
}
|
||||
if pkt.StagePrefix != "quest_" {
|
||||
t.Errorf("StagePrefix = %q, want %q", pkt.StagePrefix, "quest_")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseLargeMsgSysReserveStage tests Parse for MsgSysReserveStage.
|
||||
func TestParseLargeMsgSysReserveStage(t *testing.T) {
|
||||
stageID := "stage_42"
|
||||
stageBytes := make([]byte, len(stageID)+1) // padded with null at end
|
||||
copy(stageBytes, stageID)
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0xAABBCCDD) // AckHandle
|
||||
bf.WriteUint8(0x11) // Ready
|
||||
bf.WriteUint8(uint8(len(stageBytes))) // stageIDLength
|
||||
bf.WriteBytes(stageBytes)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysReserveStage{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0xAABBCCDD {
|
||||
t.Errorf("AckHandle = 0x%X, want 0xAABBCCDD", pkt.AckHandle)
|
||||
}
|
||||
if pkt.Ready != 0x11 {
|
||||
t.Errorf("Ready = 0x%X, want 0x11", pkt.Ready)
|
||||
}
|
||||
if pkt.StageID != stageID {
|
||||
t.Errorf("StageID = %q, want %q", pkt.StageID, stageID)
|
||||
}
|
||||
}
|
||||
776
network/mhfpacket/msg_parse_medium_test.go
Normal file
776
network/mhfpacket/msg_parse_medium_test.go
Normal file
@@ -0,0 +1,776 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
// --- 5-stmt packets (medium complexity) ---
|
||||
|
||||
// TestParseMediumVoteFesta verifies Parse for MsgMhfVoteFesta.
|
||||
// Fields: AckHandle(u32), FestaID(u32), GuildID(u32), TrialID(u32)
|
||||
func TestParseMediumVoteFesta(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ack uint32
|
||||
festaID uint32
|
||||
guildID uint32
|
||||
trialID uint32
|
||||
}{
|
||||
{"typical", 0x11223344, 1, 500, 42},
|
||||
{"zero", 0, 0, 0, 0},
|
||||
{"max", 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ack)
|
||||
bf.WriteUint32(tt.festaID)
|
||||
bf.WriteUint32(tt.guildID)
|
||||
bf.WriteUint32(tt.trialID)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgMhfVoteFesta{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack)
|
||||
}
|
||||
if pkt.FestaID != tt.festaID {
|
||||
t.Errorf("FestaID = %d, want %d", pkt.FestaID, tt.festaID)
|
||||
}
|
||||
if pkt.GuildID != tt.guildID {
|
||||
t.Errorf("GuildID = %d, want %d", pkt.GuildID, tt.guildID)
|
||||
}
|
||||
if pkt.TrialID != tt.trialID {
|
||||
t.Errorf("TrialID = %d, want %d", pkt.TrialID, tt.trialID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseMediumAcquireSemaphore verifies Parse for MsgSysAcquireSemaphore.
|
||||
// Fields: AckHandle(u32), SemaphoreIDLength(u8), SemaphoreID(string via bfutil.UpToNull)
|
||||
func TestParseMediumAcquireSemaphore(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ack uint32
|
||||
semaphoreID string
|
||||
}{
|
||||
{"typical", 0xAABBCCDD, "quest_semaphore"},
|
||||
{"short", 1, "s"},
|
||||
{"empty", 0, ""},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ack)
|
||||
// SemaphoreIDLength includes the null terminator in the read
|
||||
idBytes := []byte(tt.semaphoreID)
|
||||
idBytes = append(idBytes, 0x00) // null terminator
|
||||
bf.WriteUint8(uint8(len(idBytes)))
|
||||
bf.WriteBytes(idBytes)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgSysAcquireSemaphore{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack)
|
||||
}
|
||||
if pkt.SemaphoreID != tt.semaphoreID {
|
||||
t.Errorf("SemaphoreID = %q, want %q", pkt.SemaphoreID, tt.semaphoreID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseMediumCheckSemaphore verifies Parse for MsgSysCheckSemaphore.
|
||||
// Fields: AckHandle(u32), semaphoreIDLength(u8), SemaphoreID(string via bfutil.UpToNull)
|
||||
func TestParseMediumCheckSemaphore(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ack uint32
|
||||
semaphoreID string
|
||||
}{
|
||||
{"typical", 0x12345678, "global_semaphore"},
|
||||
{"short id", 42, "x"},
|
||||
{"empty id", 0, ""},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ack)
|
||||
idBytes := []byte(tt.semaphoreID)
|
||||
idBytes = append(idBytes, 0x00)
|
||||
bf.WriteUint8(uint8(len(idBytes)))
|
||||
bf.WriteBytes(idBytes)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgSysCheckSemaphore{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack)
|
||||
}
|
||||
if pkt.SemaphoreID != tt.semaphoreID {
|
||||
t.Errorf("SemaphoreID = %q, want %q", pkt.SemaphoreID, tt.semaphoreID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseMediumGetUserBinary verifies Parse for MsgSysGetUserBinary.
|
||||
// Fields: AckHandle(u32), CharID(u32), BinaryType(u8)
|
||||
func TestParseMediumGetUserBinary(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ack uint32
|
||||
charID uint32
|
||||
binaryType uint8
|
||||
}{
|
||||
{"typical", 0xDEADBEEF, 12345, 1},
|
||||
{"zero", 0, 0, 0},
|
||||
{"max", 0xFFFFFFFF, 0xFFFFFFFF, 255},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ack)
|
||||
bf.WriteUint32(tt.charID)
|
||||
bf.WriteUint8(tt.binaryType)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgSysGetUserBinary{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack)
|
||||
}
|
||||
if pkt.CharID != tt.charID {
|
||||
t.Errorf("CharID = %d, want %d", pkt.CharID, tt.charID)
|
||||
}
|
||||
if pkt.BinaryType != tt.binaryType {
|
||||
t.Errorf("BinaryType = %d, want %d", pkt.BinaryType, tt.binaryType)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseMediumSetObjectBinary verifies Parse for MsgSysSetObjectBinary.
|
||||
// Fields: ObjID(u32), DataSize(u16), RawDataPayload([]byte of DataSize)
|
||||
func TestParseMediumSetObjectBinary(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
objID uint32
|
||||
payload []byte
|
||||
}{
|
||||
{"typical", 42, []byte{0x01, 0x02, 0x03, 0x04}},
|
||||
{"empty", 0, []byte{}},
|
||||
{"large", 0xCAFEBABE, []byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.objID)
|
||||
bf.WriteUint16(uint16(len(tt.payload)))
|
||||
bf.WriteBytes(tt.payload)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgSysSetObjectBinary{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.ObjID != tt.objID {
|
||||
t.Errorf("ObjID = %d, want %d", pkt.ObjID, tt.objID)
|
||||
}
|
||||
if pkt.DataSize != uint16(len(tt.payload)) {
|
||||
t.Errorf("DataSize = %d, want %d", pkt.DataSize, len(tt.payload))
|
||||
}
|
||||
if !bytes.Equal(pkt.RawDataPayload, tt.payload) {
|
||||
t.Errorf("RawDataPayload = %v, want %v", pkt.RawDataPayload, tt.payload)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseMediumSetUserBinary verifies Parse for MsgSysSetUserBinary.
|
||||
// Fields: BinaryType(u8), DataSize(u16), RawDataPayload([]byte of DataSize)
|
||||
func TestParseMediumSetUserBinary(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
binaryType uint8
|
||||
payload []byte
|
||||
}{
|
||||
{"typical", 1, []byte{0xDE, 0xAD, 0xBE, 0xEF}},
|
||||
{"empty", 0, []byte{}},
|
||||
{"max type", 255, []byte{0x01}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint8(tt.binaryType)
|
||||
bf.WriteUint16(uint16(len(tt.payload)))
|
||||
bf.WriteBytes(tt.payload)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgSysSetUserBinary{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.BinaryType != tt.binaryType {
|
||||
t.Errorf("BinaryType = %d, want %d", pkt.BinaryType, tt.binaryType)
|
||||
}
|
||||
if pkt.DataSize != uint16(len(tt.payload)) {
|
||||
t.Errorf("DataSize = %d, want %d", pkt.DataSize, len(tt.payload))
|
||||
}
|
||||
if !bytes.Equal(pkt.RawDataPayload, tt.payload) {
|
||||
t.Errorf("RawDataPayload = %v, want %v", pkt.RawDataPayload, tt.payload)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// --- 4-stmt packets ---
|
||||
|
||||
// TestParseMediumGetUdRanking verifies Parse for MsgMhfGetUdRanking.
|
||||
// Fields: AckHandle(u32), Unk0(u8)
|
||||
func TestParseMediumGetUdRanking(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ack uint32
|
||||
unk0 uint8
|
||||
}{
|
||||
{"typical", 0x11223344, 5},
|
||||
{"zero", 0, 0},
|
||||
{"max", 0xFFFFFFFF, 255},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ack)
|
||||
bf.WriteUint8(tt.unk0)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgMhfGetUdRanking{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack)
|
||||
}
|
||||
if pkt.Unk0 != tt.unk0 {
|
||||
t.Errorf("Unk0 = %d, want %d", pkt.Unk0, tt.unk0)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseMediumGetUdTacticsRanking verifies Parse for MsgMhfGetUdTacticsRanking.
|
||||
// Fields: AckHandle(u32), GuildID(u32)
|
||||
func TestParseMediumGetUdTacticsRanking(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ack uint32
|
||||
guildID uint32
|
||||
}{
|
||||
{"typical", 0xAABBCCDD, 500},
|
||||
{"zero", 0, 0},
|
||||
{"max", 0xFFFFFFFF, 0xFFFFFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ack)
|
||||
bf.WriteUint32(tt.guildID)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgMhfGetUdTacticsRanking{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack)
|
||||
}
|
||||
if pkt.GuildID != tt.guildID {
|
||||
t.Errorf("GuildID = %d, want %d", pkt.GuildID, tt.guildID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseMediumRegistGuildTresure verifies Parse for MsgMhfRegistGuildTresure.
|
||||
// Fields: AckHandle(u32), DataLen(u16), Data([]byte), trailing u32 (discarded)
|
||||
func TestParseMediumRegistGuildTresure(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ack uint32
|
||||
data []byte
|
||||
}{
|
||||
{"typical", 0x12345678, []byte{0x01, 0x02, 0x03}},
|
||||
{"empty data", 1, []byte{}},
|
||||
{"larger data", 0xDEADBEEF, []byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ack)
|
||||
bf.WriteUint16(uint16(len(tt.data)))
|
||||
bf.WriteBytes(tt.data)
|
||||
bf.WriteUint32(0) // trailing uint32 that is read and discarded
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgMhfRegistGuildTresure{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack)
|
||||
}
|
||||
if !bytes.Equal(pkt.Data, tt.data) {
|
||||
t.Errorf("Data = %v, want %v", pkt.Data, tt.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseMediumUpdateMyhouseInfo verifies Parse for MsgMhfUpdateMyhouseInfo.
|
||||
// Fields: AckHandle(u32), Unk0([]byte of 0x16A bytes)
|
||||
func TestParseMediumUpdateMyhouseInfo(t *testing.T) {
|
||||
t.Run("typical", func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
ack := uint32(0xCAFEBABE)
|
||||
bf.WriteUint32(ack)
|
||||
|
||||
// 0x16A = 362 bytes
|
||||
payload := make([]byte, 0x16A)
|
||||
for i := range payload {
|
||||
payload[i] = byte(i % 256)
|
||||
}
|
||||
bf.WriteBytes(payload)
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgMhfUpdateMyhouseInfo{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
if len(pkt.Data) != 0x16A {
|
||||
t.Errorf("Unk0 length = %d, want %d", len(pkt.Data), 0x16A)
|
||||
}
|
||||
if !bytes.Equal(pkt.Data, payload) {
|
||||
t.Error("Unk0 content mismatch")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("zero values", func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteBytes(make([]byte, 0x16A))
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
pkt := &MsgMhfUpdateMyhouseInfo{}
|
||||
if err := pkt.Parse(bf, nil); err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0", pkt.AckHandle)
|
||||
}
|
||||
if len(pkt.Data) != 0x16A {
|
||||
t.Errorf("Unk0 length = %d, want %d", len(pkt.Data), 0x16A)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// --- 3-stmt packets (AckHandle-only Parse) ---
|
||||
|
||||
// TestParseMediumAckHandleOnlyBatch tests Parse for all 3-stmt packets that only
|
||||
// read a single AckHandle uint32. These are verified to parse correctly and
|
||||
// return the expected AckHandle value.
|
||||
func TestParseMediumAckHandleOnlyBatch(t *testing.T) {
|
||||
packets := []struct {
|
||||
name string
|
||||
pkt MHFPacket
|
||||
// getAck extracts the AckHandle from the parsed packet
|
||||
getAck func() uint32
|
||||
}{
|
||||
{
|
||||
"MsgMhfGetUdBonusQuestInfo",
|
||||
&MsgMhfGetUdBonusQuestInfo{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdDailyPresentList",
|
||||
&MsgMhfGetUdDailyPresentList{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdGuildMapInfo",
|
||||
&MsgMhfGetUdGuildMapInfo{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdMonsterPoint",
|
||||
&MsgMhfGetUdMonsterPoint{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdMyRanking",
|
||||
&MsgMhfGetUdMyRanking{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdNormaPresentList",
|
||||
&MsgMhfGetUdNormaPresentList{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdRankingRewardList",
|
||||
&MsgMhfGetUdRankingRewardList{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdSelectedColorInfo",
|
||||
&MsgMhfGetUdSelectedColorInfo{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdShopCoin",
|
||||
&MsgMhfGetUdShopCoin{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdTacticsBonusQuest",
|
||||
&MsgMhfGetUdTacticsBonusQuest{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdTacticsFirstQuestBonus",
|
||||
&MsgMhfGetUdTacticsFirstQuestBonus{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdTacticsFollower",
|
||||
&MsgMhfGetUdTacticsFollower{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdTacticsLog",
|
||||
&MsgMhfGetUdTacticsLog{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdTacticsPoint",
|
||||
&MsgMhfGetUdTacticsPoint{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfGetUdTacticsRewardList",
|
||||
&MsgMhfGetUdTacticsRewardList{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgMhfReceiveCafeDurationBonus",
|
||||
&MsgMhfReceiveCafeDurationBonus{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgSysDeleteSemaphore",
|
||||
&MsgSysDeleteSemaphore{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"MsgSysReleaseSemaphore",
|
||||
&MsgSysReleaseSemaphore{},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
ctx := &clientctx.ClientContext{}
|
||||
ackValues := []uint32{0x12345678, 0, 0xFFFFFFFF, 0xDEADBEEF}
|
||||
|
||||
for _, tc := range packets {
|
||||
for _, ackVal := range ackValues {
|
||||
t.Run(tc.name+"/ack_"+ackHex(ackVal), func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(ackVal)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
err := tc.pkt.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseMediumAckHandleOnlyVerifyValues tests each 3-stmt AckHandle-only
|
||||
// packet individually, verifying that the AckHandle field is correctly populated.
|
||||
func TestParseMediumAckHandleOnlyVerifyValues(t *testing.T) {
|
||||
ctx := &clientctx.ClientContext{}
|
||||
ack := uint32(0xCAFEBABE)
|
||||
|
||||
makeFrame := func() *byteframe.ByteFrame {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(ack)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
return bf
|
||||
}
|
||||
|
||||
t.Run("MsgMhfGetUdBonusQuestInfo", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdBonusQuestInfo{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdDailyPresentList", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdDailyPresentList{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdGuildMapInfo", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdGuildMapInfo{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdMonsterPoint", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdMonsterPoint{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdMyRanking", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdMyRanking{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdNormaPresentList", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdNormaPresentList{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdRankingRewardList", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdRankingRewardList{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdSelectedColorInfo", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdSelectedColorInfo{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdShopCoin", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdShopCoin{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdTacticsBonusQuest", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdTacticsBonusQuest{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdTacticsFirstQuestBonus", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdTacticsFirstQuestBonus{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdTacticsFollower", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdTacticsFollower{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdTacticsLog", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdTacticsLog{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdTacticsPoint", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdTacticsPoint{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfGetUdTacticsRewardList", func(t *testing.T) {
|
||||
pkt := &MsgMhfGetUdTacticsRewardList{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgMhfReceiveCafeDurationBonus", func(t *testing.T) {
|
||||
pkt := &MsgMhfReceiveCafeDurationBonus{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgSysDeleteSemaphore", func(t *testing.T) {
|
||||
pkt := &MsgSysDeleteSemaphore{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.SemaphoreID != ack {
|
||||
t.Errorf("SemaphoreID = 0x%X, want 0x%X", pkt.SemaphoreID, ack)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MsgSysReleaseSemaphore", func(t *testing.T) {
|
||||
pkt := &MsgSysReleaseSemaphore{}
|
||||
if err := pkt.Parse(makeFrame(), ctx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pkt.AckHandle != ack {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestParseMediumDeleteUser verifies that MsgSysDeleteUser.Parse returns
|
||||
// NOT IMPLEMENTED error (Parse is not implemented, only Build is).
|
||||
func TestParseMediumDeleteUser(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(12345)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysDeleteUser{}
|
||||
err := pkt.Parse(bf, nil)
|
||||
if err == nil {
|
||||
t.Fatal("Parse() should return error for NOT IMPLEMENTED")
|
||||
}
|
||||
if err.Error() != "NOT IMPLEMENTED" {
|
||||
t.Errorf("Parse() error = %q, want %q", err.Error(), "NOT IMPLEMENTED")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseMediumInsertUser verifies that MsgSysInsertUser.Parse returns
|
||||
// NOT IMPLEMENTED error (Parse is not implemented, only Build is).
|
||||
func TestParseMediumInsertUser(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(12345)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysInsertUser{}
|
||||
err := pkt.Parse(bf, nil)
|
||||
if err == nil {
|
||||
t.Fatal("Parse() should return error for NOT IMPLEMENTED")
|
||||
}
|
||||
if err.Error() != "NOT IMPLEMENTED" {
|
||||
t.Errorf("Parse() error = %q, want %q", err.Error(), "NOT IMPLEMENTED")
|
||||
}
|
||||
}
|
||||
|
||||
// ackHex returns a hex string for a uint32 ack value, used for test naming.
|
||||
func ackHex(v uint32) string {
|
||||
const hex = "0123456789ABCDEF"
|
||||
buf := make([]byte, 8)
|
||||
for i := 7; i >= 0; i-- {
|
||||
buf[i] = hex[v&0xF]
|
||||
v >>= 4
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
216
network/mhfpacket/msg_parse_small_test.go
Normal file
216
network/mhfpacket/msg_parse_small_test.go
Normal file
@@ -0,0 +1,216 @@
|
||||
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")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
218
network/mhfpacket/msg_parse_test.go
Normal file
218
network/mhfpacket/msg_parse_test.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
// TestMsgMhfGetAchievementParse tests MsgMhfGetAchievement parsing
|
||||
func TestMsgMhfGetAchievementDetailedParse(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(0x12345678) // AckHandle
|
||||
bf.WriteUint32(54321) // CharID
|
||||
bf.WriteUint32(99999) // Unk1
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfGetAchievement{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != 0x12345678 {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x12345678", pkt.AckHandle)
|
||||
}
|
||||
if pkt.CharID != 54321 {
|
||||
t.Errorf("CharID = %d, want 54321", pkt.CharID)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgMhfAddAchievementDetailedParse tests MsgMhfAddAchievement parsing
|
||||
func TestMsgMhfAddAchievementDetailedParse(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint8(42) // AchievementID
|
||||
bf.WriteUint16(12345) // Unk1
|
||||
bf.WriteUint16(0xFFFF) // Unk2 - max value
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgMhfAddAchievement{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AchievementID != 42 {
|
||||
t.Errorf("AchievementID = %d, want 42", pkt.AchievementID)
|
||||
}
|
||||
if pkt.Unk1 != 12345 {
|
||||
t.Errorf("Unk1 = %d, want 12345", pkt.Unk1)
|
||||
}
|
||||
if pkt.Unk2 != 0xFFFF {
|
||||
t.Errorf("Unk2 = %d, want 65535", pkt.Unk2)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCastBinaryDetailedParse tests MsgSysCastBinary parsing with various payloads
|
||||
func TestMsgSysCastBinaryDetailedParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
unk uint32
|
||||
broadcastType uint8
|
||||
messageType uint8
|
||||
payload []byte
|
||||
}{
|
||||
{"empty payload", 0, 1, 2, []byte{}},
|
||||
{"typical payload", 0x006400C8, 0x10, 0x20, []byte{0x01, 0x02, 0x03}},
|
||||
{"chat message", 0, 0x01, 0x01, []byte("Hello, World!")},
|
||||
{"binary data", 0xFFFFFFFF, 0xFF, 0xFF, []byte{0xDE, 0xAD, 0xBE, 0xEF}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.unk)
|
||||
bf.WriteUint8(tt.broadcastType)
|
||||
bf.WriteUint8(tt.messageType)
|
||||
bf.WriteUint16(uint16(len(tt.payload)))
|
||||
bf.WriteBytes(tt.payload)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysCastBinary{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.Unk != tt.unk {
|
||||
t.Errorf("Unk = %d, want %d", pkt.Unk, tt.unk)
|
||||
}
|
||||
if pkt.BroadcastType != tt.broadcastType {
|
||||
t.Errorf("BroadcastType = %d, want %d", pkt.BroadcastType, tt.broadcastType)
|
||||
}
|
||||
if pkt.MessageType != tt.messageType {
|
||||
t.Errorf("MessageType = %d, want %d", pkt.MessageType, tt.messageType)
|
||||
}
|
||||
if len(pkt.RawDataPayload) != len(tt.payload) {
|
||||
t.Errorf("RawDataPayload len = %d, want %d", len(pkt.RawDataPayload), len(tt.payload))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysLogoutParse tests MsgSysLogout parsing
|
||||
func TestMsgSysLogoutDetailedParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
unk0 uint8
|
||||
}{
|
||||
{0},
|
||||
{1},
|
||||
{100},
|
||||
{255},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint8(tt.unk0)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysLogout{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.Unk0 != tt.unk0 {
|
||||
t.Errorf("Unk0 = %d, want %d", pkt.Unk0, tt.unk0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysBackStageParse tests MsgSysBackStage parsing
|
||||
func TestMsgSysBackStageDetailedParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
ackHandle uint32
|
||||
}{
|
||||
{0},
|
||||
{1},
|
||||
{0x12345678},
|
||||
{0xFFFFFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ackHandle)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysBackStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ackHandle {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ackHandle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysPingParse tests MsgSysPing parsing
|
||||
func TestMsgSysPingDetailedParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
ackHandle uint32
|
||||
}{
|
||||
{0},
|
||||
{0xABCDEF12},
|
||||
{0xFFFFFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ackHandle)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysPing{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ackHandle {
|
||||
t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ackHandle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysTimeParse tests MsgSysTime parsing
|
||||
func TestMsgSysTimeDetailedParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
getRemoteTime bool
|
||||
timestamp uint32
|
||||
}{
|
||||
{false, 0},
|
||||
{true, 1577836800}, // 2020-01-01 00:00:00
|
||||
{false, 0xFFFFFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteBool(tt.getRemoteTime)
|
||||
bf.WriteUint32(tt.timestamp)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysTime{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.GetRemoteTime != tt.getRemoteTime {
|
||||
t.Errorf("GetRemoteTime = %v, want %v", pkt.GetRemoteTime, tt.getRemoteTime)
|
||||
}
|
||||
if pkt.Timestamp != tt.timestamp {
|
||||
t.Errorf("Timestamp = %d, want %d", pkt.Timestamp, tt.timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
310
network/mhfpacket/msg_sys_core_test.go
Normal file
310
network/mhfpacket/msg_sys_core_test.go
Normal file
@@ -0,0 +1,310 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
func TestMsgSysAckRoundTrip(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ackHandle uint32
|
||||
isBufferResponse bool
|
||||
errorCode uint8
|
||||
ackData []byte
|
||||
}{
|
||||
{
|
||||
name: "simple non-buffer response",
|
||||
ackHandle: 1,
|
||||
isBufferResponse: false,
|
||||
errorCode: 0,
|
||||
ackData: []byte{0x00, 0x00, 0x00, 0x00},
|
||||
},
|
||||
{
|
||||
name: "buffer response with small data",
|
||||
ackHandle: 0x12345678,
|
||||
isBufferResponse: true,
|
||||
errorCode: 0,
|
||||
ackData: []byte{0x01, 0x02, 0x03, 0x04, 0x05},
|
||||
},
|
||||
{
|
||||
name: "error response",
|
||||
ackHandle: 100,
|
||||
isBufferResponse: false,
|
||||
errorCode: 1,
|
||||
ackData: []byte{0xDE, 0xAD, 0xBE, 0xEF},
|
||||
},
|
||||
{
|
||||
name: "empty buffer response",
|
||||
ackHandle: 999,
|
||||
isBufferResponse: true,
|
||||
errorCode: 0,
|
||||
ackData: []byte{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
original := &MsgSysAck{
|
||||
AckHandle: tt.ackHandle,
|
||||
IsBufferResponse: tt.isBufferResponse,
|
||||
ErrorCode: tt.errorCode,
|
||||
AckData: tt.ackData,
|
||||
}
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
// Build
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Parse
|
||||
bf.Seek(0, io.SeekStart)
|
||||
parsed := &MsgSysAck{}
|
||||
err = parsed.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
// Compare
|
||||
if parsed.AckHandle != original.AckHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", parsed.AckHandle, original.AckHandle)
|
||||
}
|
||||
if parsed.IsBufferResponse != original.IsBufferResponse {
|
||||
t.Errorf("IsBufferResponse = %v, want %v", parsed.IsBufferResponse, original.IsBufferResponse)
|
||||
}
|
||||
if parsed.ErrorCode != original.ErrorCode {
|
||||
t.Errorf("ErrorCode = %d, want %d", parsed.ErrorCode, original.ErrorCode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysAckLargePayload(t *testing.T) {
|
||||
// Test with payload larger than 0xFFFF to trigger extended size field
|
||||
largeData := make([]byte, 0x10000) // 65536 bytes
|
||||
for i := range largeData {
|
||||
largeData[i] = byte(i % 256)
|
||||
}
|
||||
|
||||
original := &MsgSysAck{
|
||||
AckHandle: 1,
|
||||
IsBufferResponse: true,
|
||||
ErrorCode: 0,
|
||||
AckData: largeData,
|
||||
}
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
// Build
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Parse
|
||||
bf.Seek(0, io.SeekStart)
|
||||
parsed := &MsgSysAck{}
|
||||
err = parsed.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if len(parsed.AckData) != len(largeData) {
|
||||
t.Errorf("AckData len = %d, want %d", len(parsed.AckData), len(largeData))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysAckOpcode(t *testing.T) {
|
||||
pkt := &MsgSysAck{}
|
||||
if pkt.Opcode() != network.MSG_SYS_ACK {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ACK", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysNopRoundTrip(t *testing.T) {
|
||||
original := &MsgSysNop{}
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
// Build
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Should write no data
|
||||
if len(bf.Data()) != 0 {
|
||||
t.Errorf("MsgSysNop.Build() wrote %d bytes, want 0", len(bf.Data()))
|
||||
}
|
||||
|
||||
// Parse (from empty buffer)
|
||||
parsed := &MsgSysNop{}
|
||||
err = parsed.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysNopOpcode(t *testing.T) {
|
||||
pkt := &MsgSysNop{}
|
||||
if pkt.Opcode() != network.MSG_SYS_NOP {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_NOP", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysEndRoundTrip(t *testing.T) {
|
||||
original := &MsgSysEnd{}
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
// Build
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
// Should write no data
|
||||
if len(bf.Data()) != 0 {
|
||||
t.Errorf("MsgSysEnd.Build() wrote %d bytes, want 0", len(bf.Data()))
|
||||
}
|
||||
|
||||
// Parse (from empty buffer)
|
||||
parsed := &MsgSysEnd{}
|
||||
err = parsed.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysEndOpcode(t *testing.T) {
|
||||
pkt := &MsgSysEnd{}
|
||||
if pkt.Opcode() != network.MSG_SYS_END {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_END", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysAckNonBufferResponse(t *testing.T) {
|
||||
// Non-buffer response should always read/write 4 bytes of data
|
||||
original := &MsgSysAck{
|
||||
AckHandle: 1,
|
||||
IsBufferResponse: false,
|
||||
ErrorCode: 0,
|
||||
AckData: []byte{0xAA, 0xBB, 0xCC, 0xDD},
|
||||
}
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
parsed := &MsgSysAck{}
|
||||
err = parsed.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
// Non-buffer response should have exactly 4 bytes of data
|
||||
if len(parsed.AckData) != 4 {
|
||||
t.Errorf("Non-buffer AckData len = %d, want 4", len(parsed.AckData))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysAckNonBufferShortData(t *testing.T) {
|
||||
// Non-buffer response with short data should pad to 4 bytes
|
||||
original := &MsgSysAck{
|
||||
AckHandle: 1,
|
||||
IsBufferResponse: false,
|
||||
ErrorCode: 0,
|
||||
AckData: []byte{0x01}, // Only 1 byte
|
||||
}
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
err := original.Build(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
bf.Seek(0, io.SeekStart)
|
||||
parsed := &MsgSysAck{}
|
||||
err = parsed.Parse(bf, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
// Should still read 4 bytes
|
||||
if len(parsed.AckData) != 4 {
|
||||
t.Errorf("AckData len = %d, want 4", len(parsed.AckData))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysAckBuildFormat(t *testing.T) {
|
||||
pkt := &MsgSysAck{
|
||||
AckHandle: 0x12345678,
|
||||
IsBufferResponse: true,
|
||||
ErrorCode: 0x55,
|
||||
AckData: []byte{0xAA, 0xBB},
|
||||
}
|
||||
ctx := &clientctx.ClientContext{}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
pkt.Build(bf, ctx)
|
||||
|
||||
data := bf.Data()
|
||||
|
||||
// Check AckHandle (big-endian)
|
||||
if data[0] != 0x12 || data[1] != 0x34 || data[2] != 0x56 || data[3] != 0x78 {
|
||||
t.Errorf("AckHandle bytes = %X, want 12345678", data[:4])
|
||||
}
|
||||
|
||||
// Check IsBufferResponse (1 = true)
|
||||
if data[4] != 1 {
|
||||
t.Errorf("IsBufferResponse byte = %d, want 1", data[4])
|
||||
}
|
||||
|
||||
// Check ErrorCode
|
||||
if data[5] != 0x55 {
|
||||
t.Errorf("ErrorCode byte = %X, want 55", data[5])
|
||||
}
|
||||
|
||||
// Check payload size (2 bytes, big-endian)
|
||||
if data[6] != 0x00 || data[7] != 0x02 {
|
||||
t.Errorf("PayloadSize bytes = %X %X, want 00 02", data[6], data[7])
|
||||
}
|
||||
|
||||
// Check actual data
|
||||
if data[8] != 0xAA || data[9] != 0xBB {
|
||||
t.Errorf("AckData bytes = %X %X, want AA BB", data[8], data[9])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCorePacketsFromOpcode(t *testing.T) {
|
||||
coreOpcodes := []network.PacketID{
|
||||
network.MSG_SYS_NOP,
|
||||
network.MSG_SYS_END,
|
||||
network.MSG_SYS_ACK,
|
||||
network.MSG_SYS_PING,
|
||||
}
|
||||
|
||||
for _, opcode := range coreOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Fatalf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
if pkt.Opcode() != opcode {
|
||||
t.Errorf("Opcode() = %s, want %s", pkt.Opcode(), opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
592
network/mhfpacket/msg_sys_packets_test.go
Normal file
592
network/mhfpacket/msg_sys_packets_test.go
Normal file
@@ -0,0 +1,592 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
// TestMsgSysCastBinaryParse tests parsing MsgSysCastBinary
|
||||
func TestMsgSysCastBinaryParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
unk uint32
|
||||
broadcastType uint8
|
||||
messageType uint8
|
||||
payload []byte
|
||||
}{
|
||||
{"empty payload", 0, 1, 2, []byte{}},
|
||||
{"small payload", 0x006400C8, 3, 4, []byte{0xAA, 0xBB, 0xCC}},
|
||||
{"large payload", 0xFFFFFFFF, 0xFF, 0xFF, make([]byte, 100)},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.unk)
|
||||
bf.WriteUint8(tt.broadcastType)
|
||||
bf.WriteUint8(tt.messageType)
|
||||
bf.WriteUint16(uint16(len(tt.payload)))
|
||||
bf.WriteBytes(tt.payload)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysCastBinary{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.Unk != tt.unk {
|
||||
t.Errorf("Unk = %d, want %d", pkt.Unk, tt.unk)
|
||||
}
|
||||
if pkt.BroadcastType != tt.broadcastType {
|
||||
t.Errorf("BroadcastType = %d, want %d", pkt.BroadcastType, tt.broadcastType)
|
||||
}
|
||||
if pkt.MessageType != tt.messageType {
|
||||
t.Errorf("MessageType = %d, want %d", pkt.MessageType, tt.messageType)
|
||||
}
|
||||
if len(pkt.RawDataPayload) != len(tt.payload) {
|
||||
t.Errorf("RawDataPayload len = %d, want %d", len(pkt.RawDataPayload), len(tt.payload))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCastBinaryOpcode tests Opcode method
|
||||
func TestMsgSysCastBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCastBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_CAST_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_CAST_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCreateSemaphoreOpcode tests Opcode method
|
||||
func TestMsgSysCreateSemaphoreOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCreateSemaphore{}
|
||||
if pkt.Opcode() != network.MSG_SYS_CREATE_SEMAPHORE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_CREATE_SEMAPHORE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCastedBinaryOpcode tests Opcode method
|
||||
func TestMsgSysCastedBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCastedBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_CASTED_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_CASTED_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysSetStageBinaryOpcode tests Opcode method
|
||||
func TestMsgSysSetStageBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysSetStageBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_SET_STAGE_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_SET_STAGE_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysGetStageBinaryOpcode tests Opcode method
|
||||
func TestMsgSysGetStageBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysGetStageBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_GET_STAGE_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_GET_STAGE_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysWaitStageBinaryOpcode tests Opcode method
|
||||
func TestMsgSysWaitStageBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysWaitStageBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_WAIT_STAGE_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_WAIT_STAGE_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysEnumerateClientOpcode tests Opcode method
|
||||
func TestMsgSysEnumerateClientOpcode(t *testing.T) {
|
||||
pkt := &MsgSysEnumerateClient{}
|
||||
if pkt.Opcode() != network.MSG_SYS_ENUMERATE_CLIENT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ENUMERATE_CLIENT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysEnumerateStageOpcode tests Opcode method
|
||||
func TestMsgSysEnumerateStageOpcode(t *testing.T) {
|
||||
pkt := &MsgSysEnumerateStage{}
|
||||
if pkt.Opcode() != network.MSG_SYS_ENUMERATE_STAGE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ENUMERATE_STAGE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCreateMutexOpcode tests Opcode method
|
||||
func TestMsgSysCreateMutexOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCreateMutex{}
|
||||
if pkt.Opcode() != network.MSG_SYS_CREATE_MUTEX {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_CREATE_MUTEX", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCreateOpenMutexOpcode tests Opcode method
|
||||
func TestMsgSysCreateOpenMutexOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCreateOpenMutex{}
|
||||
if pkt.Opcode() != network.MSG_SYS_CREATE_OPEN_MUTEX {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_CREATE_OPEN_MUTEX", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysDeleteMutexOpcode tests Opcode method
|
||||
func TestMsgSysDeleteMutexOpcode(t *testing.T) {
|
||||
pkt := &MsgSysDeleteMutex{}
|
||||
if pkt.Opcode() != network.MSG_SYS_DELETE_MUTEX {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_DELETE_MUTEX", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysOpenMutexOpcode tests Opcode method
|
||||
func TestMsgSysOpenMutexOpcode(t *testing.T) {
|
||||
pkt := &MsgSysOpenMutex{}
|
||||
if pkt.Opcode() != network.MSG_SYS_OPEN_MUTEX {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_OPEN_MUTEX", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCloseMutexOpcode tests Opcode method
|
||||
func TestMsgSysCloseMutexOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCloseMutex{}
|
||||
if pkt.Opcode() != network.MSG_SYS_CLOSE_MUTEX {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_CLOSE_MUTEX", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysDeleteSemaphoreOpcode tests Opcode method
|
||||
func TestMsgSysDeleteSemaphoreOpcode(t *testing.T) {
|
||||
pkt := &MsgSysDeleteSemaphore{}
|
||||
if pkt.Opcode() != network.MSG_SYS_DELETE_SEMAPHORE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_DELETE_SEMAPHORE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysAcquireSemaphoreOpcode tests Opcode method
|
||||
func TestMsgSysAcquireSemaphoreOpcode(t *testing.T) {
|
||||
pkt := &MsgSysAcquireSemaphore{}
|
||||
if pkt.Opcode() != network.MSG_SYS_ACQUIRE_SEMAPHORE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ACQUIRE_SEMAPHORE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysReleaseSemaphoreOpcode tests Opcode method
|
||||
func TestMsgSysReleaseSemaphoreOpcode(t *testing.T) {
|
||||
pkt := &MsgSysReleaseSemaphore{}
|
||||
if pkt.Opcode() != network.MSG_SYS_RELEASE_SEMAPHORE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_RELEASE_SEMAPHORE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCheckSemaphoreOpcode tests Opcode method
|
||||
func TestMsgSysCheckSemaphoreOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCheckSemaphore{}
|
||||
if pkt.Opcode() != network.MSG_SYS_CHECK_SEMAPHORE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_CHECK_SEMAPHORE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCreateAcquireSemaphoreOpcode tests Opcode method
|
||||
func TestMsgSysCreateAcquireSemaphoreOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCreateAcquireSemaphore{}
|
||||
if pkt.Opcode() != network.MSG_SYS_CREATE_ACQUIRE_SEMAPHORE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_CREATE_ACQUIRE_SEMAPHORE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysOperateRegisterOpcode tests Opcode method
|
||||
func TestMsgSysOperateRegisterOpcode(t *testing.T) {
|
||||
pkt := &MsgSysOperateRegister{}
|
||||
if pkt.Opcode() != network.MSG_SYS_OPERATE_REGISTER {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_OPERATE_REGISTER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysLoadRegisterOpcode tests Opcode method
|
||||
func TestMsgSysLoadRegisterOpcode(t *testing.T) {
|
||||
pkt := &MsgSysLoadRegister{}
|
||||
if pkt.Opcode() != network.MSG_SYS_LOAD_REGISTER {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_LOAD_REGISTER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysNotifyRegisterOpcode tests Opcode method
|
||||
func TestMsgSysNotifyRegisterOpcode(t *testing.T) {
|
||||
pkt := &MsgSysNotifyRegister{}
|
||||
if pkt.Opcode() != network.MSG_SYS_NOTIFY_REGISTER {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_NOTIFY_REGISTER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCreateObjectOpcode tests Opcode method
|
||||
func TestMsgSysCreateObjectOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCreateObject{}
|
||||
if pkt.Opcode() != network.MSG_SYS_CREATE_OBJECT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_CREATE_OBJECT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysDeleteObjectOpcode tests Opcode method
|
||||
func TestMsgSysDeleteObjectOpcode(t *testing.T) {
|
||||
pkt := &MsgSysDeleteObject{}
|
||||
if pkt.Opcode() != network.MSG_SYS_DELETE_OBJECT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_DELETE_OBJECT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysPositionObjectOpcode tests Opcode method
|
||||
func TestMsgSysPositionObjectOpcode(t *testing.T) {
|
||||
pkt := &MsgSysPositionObject{}
|
||||
if pkt.Opcode() != network.MSG_SYS_POSITION_OBJECT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_POSITION_OBJECT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysRotateObjectOpcode tests Opcode method
|
||||
func TestMsgSysRotateObjectOpcode(t *testing.T) {
|
||||
pkt := &MsgSysRotateObject{}
|
||||
if pkt.Opcode() != network.MSG_SYS_ROTATE_OBJECT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ROTATE_OBJECT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysDuplicateObjectOpcode tests Opcode method
|
||||
func TestMsgSysDuplicateObjectOpcode(t *testing.T) {
|
||||
pkt := &MsgSysDuplicateObject{}
|
||||
if pkt.Opcode() != network.MSG_SYS_DUPLICATE_OBJECT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_DUPLICATE_OBJECT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysSetObjectBinaryOpcode tests Opcode method
|
||||
func TestMsgSysSetObjectBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysSetObjectBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_SET_OBJECT_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_SET_OBJECT_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysGetObjectBinaryOpcode tests Opcode method
|
||||
func TestMsgSysGetObjectBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysGetObjectBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_GET_OBJECT_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_GET_OBJECT_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysGetObjectOwnerOpcode tests Opcode method
|
||||
func TestMsgSysGetObjectOwnerOpcode(t *testing.T) {
|
||||
pkt := &MsgSysGetObjectOwner{}
|
||||
if pkt.Opcode() != network.MSG_SYS_GET_OBJECT_OWNER {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_GET_OBJECT_OWNER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysUpdateObjectBinaryOpcode tests Opcode method
|
||||
func TestMsgSysUpdateObjectBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysUpdateObjectBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_UPDATE_OBJECT_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_UPDATE_OBJECT_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCleanupObjectOpcode tests Opcode method
|
||||
func TestMsgSysCleanupObjectOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCleanupObject{}
|
||||
if pkt.Opcode() != network.MSG_SYS_CLEANUP_OBJECT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_CLEANUP_OBJECT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysInsertUserOpcode tests Opcode method
|
||||
func TestMsgSysInsertUserOpcode(t *testing.T) {
|
||||
pkt := &MsgSysInsertUser{}
|
||||
if pkt.Opcode() != network.MSG_SYS_INSERT_USER {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_INSERT_USER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysDeleteUserOpcode tests Opcode method
|
||||
func TestMsgSysDeleteUserOpcode(t *testing.T) {
|
||||
pkt := &MsgSysDeleteUser{}
|
||||
if pkt.Opcode() != network.MSG_SYS_DELETE_USER {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_DELETE_USER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysSetUserBinaryOpcode tests Opcode method
|
||||
func TestMsgSysSetUserBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysSetUserBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_SET_USER_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_SET_USER_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysGetUserBinaryOpcode tests Opcode method
|
||||
func TestMsgSysGetUserBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysGetUserBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_GET_USER_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_GET_USER_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysNotifyUserBinaryOpcode tests Opcode method
|
||||
func TestMsgSysNotifyUserBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysNotifyUserBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_NOTIFY_USER_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_NOTIFY_USER_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysUpdateRightOpcode tests Opcode method
|
||||
func TestMsgSysUpdateRightOpcode(t *testing.T) {
|
||||
pkt := &MsgSysUpdateRight{}
|
||||
if pkt.Opcode() != network.MSG_SYS_UPDATE_RIGHT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_UPDATE_RIGHT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysAuthQueryOpcode tests Opcode method
|
||||
func TestMsgSysAuthQueryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysAuthQuery{}
|
||||
if pkt.Opcode() != network.MSG_SYS_AUTH_QUERY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_AUTH_QUERY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysAuthDataOpcode tests Opcode method
|
||||
func TestMsgSysAuthDataOpcode(t *testing.T) {
|
||||
pkt := &MsgSysAuthData{}
|
||||
if pkt.Opcode() != network.MSG_SYS_AUTH_DATA {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_AUTH_DATA", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysAuthTerminalOpcode tests Opcode method
|
||||
func TestMsgSysAuthTerminalOpcode(t *testing.T) {
|
||||
pkt := &MsgSysAuthTerminal{}
|
||||
if pkt.Opcode() != network.MSG_SYS_AUTH_TERMINAL {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_AUTH_TERMINAL", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysRightsReloadOpcode tests Opcode method
|
||||
func TestMsgSysRightsReloadOpcode(t *testing.T) {
|
||||
pkt := &MsgSysRightsReload{}
|
||||
if pkt.Opcode() != network.MSG_SYS_RIGHTS_RELOAD {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_RIGHTS_RELOAD", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysTerminalLogOpcode tests Opcode method
|
||||
func TestMsgSysTerminalLogOpcode(t *testing.T) {
|
||||
pkt := &MsgSysTerminalLog{}
|
||||
if pkt.Opcode() != network.MSG_SYS_TERMINAL_LOG {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_TERMINAL_LOG", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysIssueLogkeyOpcode tests Opcode method
|
||||
func TestMsgSysIssueLogkeyOpcode(t *testing.T) {
|
||||
pkt := &MsgSysIssueLogkey{}
|
||||
if pkt.Opcode() != network.MSG_SYS_ISSUE_LOGKEY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ISSUE_LOGKEY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysRecordLogOpcode tests Opcode method
|
||||
func TestMsgSysRecordLogOpcode(t *testing.T) {
|
||||
pkt := &MsgSysRecordLog{}
|
||||
if pkt.Opcode() != network.MSG_SYS_RECORD_LOG {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_RECORD_LOG", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysEchoOpcode tests Opcode method
|
||||
func TestMsgSysEchoOpcode(t *testing.T) {
|
||||
pkt := &MsgSysEcho{}
|
||||
if pkt.Opcode() != network.MSG_SYS_ECHO {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ECHO", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysGetFileOpcode tests Opcode method
|
||||
func TestMsgSysGetFileOpcode(t *testing.T) {
|
||||
pkt := &MsgSysGetFile{}
|
||||
if pkt.Opcode() != network.MSG_SYS_GET_FILE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_GET_FILE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysHideClientOpcode tests Opcode method
|
||||
func TestMsgSysHideClientOpcode(t *testing.T) {
|
||||
pkt := &MsgSysHideClient{}
|
||||
if pkt.Opcode() != network.MSG_SYS_HIDE_CLIENT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_HIDE_CLIENT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysSetStatusOpcode tests Opcode method
|
||||
func TestMsgSysSetStatusOpcode(t *testing.T) {
|
||||
pkt := &MsgSysSetStatus{}
|
||||
if pkt.Opcode() != network.MSG_SYS_SET_STATUS {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_SET_STATUS", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysStageDestructOpcode tests Opcode method
|
||||
func TestMsgSysStageDestructOpcode(t *testing.T) {
|
||||
pkt := &MsgSysStageDestruct{}
|
||||
if pkt.Opcode() != network.MSG_SYS_STAGE_DESTRUCT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_STAGE_DESTRUCT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysLeaveStageOpcode tests Opcode method
|
||||
func TestMsgSysLeaveStageOpcode(t *testing.T) {
|
||||
pkt := &MsgSysLeaveStage{}
|
||||
if pkt.Opcode() != network.MSG_SYS_LEAVE_STAGE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_LEAVE_STAGE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysReserveStageOpcode tests Opcode method
|
||||
func TestMsgSysReserveStageOpcode(t *testing.T) {
|
||||
pkt := &MsgSysReserveStage{}
|
||||
if pkt.Opcode() != network.MSG_SYS_RESERVE_STAGE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_RESERVE_STAGE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysUnreserveStageOpcode tests Opcode method
|
||||
func TestMsgSysUnreserveStageOpcode(t *testing.T) {
|
||||
pkt := &MsgSysUnreserveStage{}
|
||||
if pkt.Opcode() != network.MSG_SYS_UNRESERVE_STAGE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_UNRESERVE_STAGE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysSetStagePassOpcode tests Opcode method
|
||||
func TestMsgSysSetStagePassOpcode(t *testing.T) {
|
||||
pkt := &MsgSysSetStagePass{}
|
||||
if pkt.Opcode() != network.MSG_SYS_SET_STAGE_PASS {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_SET_STAGE_PASS", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysLockGlobalSemaOpcode tests Opcode method
|
||||
func TestMsgSysLockGlobalSemaOpcode(t *testing.T) {
|
||||
pkt := &MsgSysLockGlobalSema{}
|
||||
if pkt.Opcode() != network.MSG_SYS_LOCK_GLOBAL_SEMA {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_LOCK_GLOBAL_SEMA", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysUnlockGlobalSemaOpcode tests Opcode method
|
||||
func TestMsgSysUnlockGlobalSemaOpcode(t *testing.T) {
|
||||
pkt := &MsgSysUnlockGlobalSema{}
|
||||
if pkt.Opcode() != network.MSG_SYS_UNLOCK_GLOBAL_SEMA {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_UNLOCK_GLOBAL_SEMA", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysTransBinaryOpcode tests Opcode method
|
||||
func TestMsgSysTransBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysTransBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_TRANS_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_TRANS_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysCollectBinaryOpcode tests Opcode method
|
||||
func TestMsgSysCollectBinaryOpcode(t *testing.T) {
|
||||
pkt := &MsgSysCollectBinary{}
|
||||
if pkt.Opcode() != network.MSG_SYS_COLLECT_BINARY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_COLLECT_BINARY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysGetStateOpcode tests Opcode method
|
||||
func TestMsgSysGetStateOpcode(t *testing.T) {
|
||||
pkt := &MsgSysGetState{}
|
||||
if pkt.Opcode() != network.MSG_SYS_GET_STATE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_GET_STATE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysSerializeOpcode tests Opcode method
|
||||
func TestMsgSysSerializeOpcode(t *testing.T) {
|
||||
pkt := &MsgSysSerialize{}
|
||||
if pkt.Opcode() != network.MSG_SYS_SERIALIZE {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_SERIALIZE", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysEnumlobbyOpcode tests Opcode method
|
||||
func TestMsgSysEnumlobbyOpcode(t *testing.T) {
|
||||
pkt := &MsgSysEnumlobby{}
|
||||
if pkt.Opcode() != network.MSG_SYS_ENUMLOBBY {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ENUMLOBBY", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysEnumuserOpcode tests Opcode method
|
||||
func TestMsgSysEnumuserOpcode(t *testing.T) {
|
||||
pkt := &MsgSysEnumuser{}
|
||||
if pkt.Opcode() != network.MSG_SYS_ENUMUSER {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ENUMUSER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysInfokyserverOpcode tests Opcode method
|
||||
func TestMsgSysInfokyserverOpcode(t *testing.T) {
|
||||
pkt := &MsgSysInfokyserver{}
|
||||
if pkt.Opcode() != network.MSG_SYS_INFOKYSERVER {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_INFOKYSERVER", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysExtendThresholdOpcode tests Opcode method
|
||||
func TestMsgSysExtendThresholdOpcode(t *testing.T) {
|
||||
pkt := &MsgSysExtendThreshold{}
|
||||
if pkt.Opcode() != network.MSG_SYS_EXTEND_THRESHOLD {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_EXTEND_THRESHOLD", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysAddObjectOpcode tests Opcode method
|
||||
func TestMsgSysAddObjectOpcode(t *testing.T) {
|
||||
pkt := &MsgSysAddObject{}
|
||||
if pkt.Opcode() != network.MSG_SYS_ADD_OBJECT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_ADD_OBJECT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysDelObjectOpcode tests Opcode method
|
||||
func TestMsgSysDelObjectOpcode(t *testing.T) {
|
||||
pkt := &MsgSysDelObject{}
|
||||
if pkt.Opcode() != network.MSG_SYS_DEL_OBJECT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_DEL_OBJECT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysDispObjectOpcode tests Opcode method
|
||||
func TestMsgSysDispObjectOpcode(t *testing.T) {
|
||||
pkt := &MsgSysDispObject{}
|
||||
if pkt.Opcode() != network.MSG_SYS_DISP_OBJECT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_DISP_OBJECT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsgSysHideObjectOpcode tests Opcode method
|
||||
func TestMsgSysHideObjectOpcode(t *testing.T) {
|
||||
pkt := &MsgSysHideObject{}
|
||||
if pkt.Opcode() != network.MSG_SYS_HIDE_OBJECT {
|
||||
t.Errorf("Opcode() = %s, want MSG_SYS_HIDE_OBJECT", pkt.Opcode())
|
||||
}
|
||||
}
|
||||
332
network/mhfpacket/msg_sys_stage_test.go
Normal file
332
network/mhfpacket/msg_sys_stage_test.go
Normal file
@@ -0,0 +1,332 @@
|
||||
package mhfpacket
|
||||
|
||||
import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
func TestStagePacketOpcodes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pkt MHFPacket
|
||||
expect network.PacketID
|
||||
}{
|
||||
{"MsgSysCreateStage", &MsgSysCreateStage{}, network.MSG_SYS_CREATE_STAGE},
|
||||
{"MsgSysEnterStage", &MsgSysEnterStage{}, network.MSG_SYS_ENTER_STAGE},
|
||||
{"MsgSysMoveStage", &MsgSysMoveStage{}, network.MSG_SYS_MOVE_STAGE},
|
||||
{"MsgSysBackStage", &MsgSysBackStage{}, network.MSG_SYS_BACK_STAGE},
|
||||
{"MsgSysLockStage", &MsgSysLockStage{}, network.MSG_SYS_LOCK_STAGE},
|
||||
{"MsgSysUnlockStage", &MsgSysUnlockStage{}, network.MSG_SYS_UNLOCK_STAGE},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.pkt.Opcode(); got != tt.expect {
|
||||
t.Errorf("Opcode() = %v, want %v", got, tt.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysCreateStageFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ackHandle uint32
|
||||
unk0 uint8
|
||||
playerCount uint8
|
||||
stageID string
|
||||
}{
|
||||
{"empty stage", 1, 1, 4, ""},
|
||||
{"mezeporta", 0x12345678, 2, 8, "sl1Ns200p0a0u0"},
|
||||
{"quest room", 100, 1, 4, "q1234"},
|
||||
{"max players", 0xFFFFFFFF, 2, 16, "max_stage"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.ackHandle)
|
||||
bf.WriteUint8(tt.unk0)
|
||||
bf.WriteUint8(tt.playerCount)
|
||||
stageIDBytes := []byte(tt.stageID)
|
||||
bf.WriteUint8(uint8(len(stageIDBytes)))
|
||||
bf.WriteBytes(append(stageIDBytes, 0x00))
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysCreateStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.ackHandle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle)
|
||||
}
|
||||
if pkt.Unk0 != tt.unk0 {
|
||||
t.Errorf("Unk0 = %d, want %d", pkt.Unk0, tt.unk0)
|
||||
}
|
||||
if pkt.PlayerCount != tt.playerCount {
|
||||
t.Errorf("PlayerCount = %d, want %d", pkt.PlayerCount, tt.playerCount)
|
||||
}
|
||||
if pkt.StageID != tt.stageID {
|
||||
t.Errorf("StageID = %q, want %q", pkt.StageID, tt.stageID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysEnterStageFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handle uint32
|
||||
unk bool
|
||||
stageID string
|
||||
}{
|
||||
{"enter town", 1, false, "town01"},
|
||||
{"force enter", 2, true, "quest_stage"},
|
||||
{"rasta bar", 999, false, "sl1Ns211p0a0u0"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.handle)
|
||||
bf.WriteBool(tt.unk)
|
||||
stageIDBytes := []byte(tt.stageID)
|
||||
bf.WriteUint8(uint8(len(stageIDBytes)))
|
||||
bf.WriteBytes(append(stageIDBytes, 0x00))
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysEnterStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.handle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.handle)
|
||||
}
|
||||
if pkt.Unk != tt.unk {
|
||||
t.Errorf("Unk = %v, want %v", pkt.Unk, tt.unk)
|
||||
}
|
||||
if pkt.StageID != tt.stageID {
|
||||
t.Errorf("StageID = %q, want %q", pkt.StageID, tt.stageID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysMoveStageFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handle uint32
|
||||
unkBool uint8
|
||||
stageID string
|
||||
}{
|
||||
{"move to area", 1, 0, "area01"},
|
||||
{"move to quest", 0xABCD, 1, "quest12345"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.handle)
|
||||
bf.WriteUint8(tt.unkBool)
|
||||
stageIDBytes := []byte(tt.stageID)
|
||||
bf.WriteUint8(uint8(len(stageIDBytes)))
|
||||
bf.WriteBytes(stageIDBytes)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysMoveStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.handle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.handle)
|
||||
}
|
||||
if pkt.UnkBool != tt.unkBool {
|
||||
t.Errorf("UnkBool = %d, want %d", pkt.UnkBool, tt.unkBool)
|
||||
}
|
||||
if pkt.StageID != tt.stageID {
|
||||
t.Errorf("StageID = %q, want %q", pkt.StageID, tt.stageID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysLockStageFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handle uint32
|
||||
unk0 uint8
|
||||
unk1 uint8
|
||||
stageID string
|
||||
}{
|
||||
{"lock room", 1, 1, 1, "room01"},
|
||||
{"private party", 0x1234, 1, 1, "party_stage"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.handle)
|
||||
bf.WriteUint8(tt.unk0)
|
||||
bf.WriteUint8(tt.unk1)
|
||||
stageIDBytes := []byte(tt.stageID)
|
||||
bf.WriteUint8(uint8(len(stageIDBytes)))
|
||||
bf.WriteBytes(append(stageIDBytes, 0x00))
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysLockStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.handle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.handle)
|
||||
}
|
||||
// Unk0 and Unk1 are read but discarded by Parse, so we only verify
|
||||
// that Parse consumed the bytes without error
|
||||
if pkt.StageID != tt.stageID {
|
||||
t.Errorf("StageID = %q, want %q", pkt.StageID, tt.stageID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysUnlockStageFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
unk0 uint16
|
||||
}{
|
||||
{"zero", 0},
|
||||
{"typical", 1},
|
||||
{"max", 0xFFFF},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(tt.unk0)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysUnlockStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
// MsgSysUnlockStage is an empty struct; Parse reads and discards a uint16.
|
||||
// We just verify Parse doesn't error.
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMsgSysBackStageFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
handle uint32
|
||||
}{
|
||||
{"small handle", 1},
|
||||
{"large handle", 0xDEADBEEF},
|
||||
{"zero", 0},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(tt.handle)
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysBackStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.AckHandle != tt.handle {
|
||||
t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.handle)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStageIDEdgeCases(t *testing.T) {
|
||||
t.Run("long stage ID", func(t *testing.T) {
|
||||
// Stage ID with max length (255 bytes)
|
||||
longID := make([]byte, 200)
|
||||
for i := range longID {
|
||||
longID[i] = 'a' + byte(i%26)
|
||||
}
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1)
|
||||
bf.WriteUint8(1)
|
||||
bf.WriteUint8(4)
|
||||
bf.WriteUint8(uint8(len(longID)))
|
||||
bf.WriteBytes(append(longID, 0x00))
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysCreateStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
if pkt.StageID != string(longID) {
|
||||
t.Errorf("StageID length = %d, want %d", len(pkt.StageID), len(longID))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("stage ID with null terminator", func(t *testing.T) {
|
||||
// String terminated with null byte
|
||||
stageID := "test\x00extra"
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(1)
|
||||
bf.WriteUint8(0)
|
||||
bf.WriteUint8(uint8(len(stageID)))
|
||||
bf.WriteBytes([]byte(stageID))
|
||||
bf.Seek(0, io.SeekStart)
|
||||
|
||||
pkt := &MsgSysEnterStage{}
|
||||
err := pkt.Parse(bf, &clientctx.ClientContext{})
|
||||
if err != nil {
|
||||
t.Fatalf("Parse() error = %v", err)
|
||||
}
|
||||
|
||||
// Should truncate at null
|
||||
if pkt.StageID != "test" {
|
||||
t.Errorf("StageID = %q, want %q (should truncate at null)", pkt.StageID, "test")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestStagePacketFromOpcode(t *testing.T) {
|
||||
stageOpcodes := []network.PacketID{
|
||||
network.MSG_SYS_CREATE_STAGE,
|
||||
network.MSG_SYS_ENTER_STAGE,
|
||||
network.MSG_SYS_BACK_STAGE,
|
||||
network.MSG_SYS_MOVE_STAGE,
|
||||
network.MSG_SYS_LOCK_STAGE,
|
||||
network.MSG_SYS_UNLOCK_STAGE,
|
||||
}
|
||||
|
||||
for _, opcode := range stageOpcodes {
|
||||
t.Run(opcode.String(), func(t *testing.T) {
|
||||
pkt := FromOpcode(opcode)
|
||||
if pkt == nil {
|
||||
t.Fatalf("FromOpcode(%s) returned nil", opcode)
|
||||
}
|
||||
if pkt.Opcode() != opcode {
|
||||
t.Errorf("Opcode() = %s, want %s", pkt.Opcode(), opcode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
211
network/packetid_test.go
Normal file
211
network/packetid_test.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPacketIDType(t *testing.T) {
|
||||
// PacketID is based on uint16
|
||||
var p PacketID = 0xFFFF
|
||||
if uint16(p) != 0xFFFF {
|
||||
t.Errorf("PacketID max value = %d, want %d", uint16(p), 0xFFFF)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketIDConstants(t *testing.T) {
|
||||
// Test critical packet IDs are correct
|
||||
tests := []struct {
|
||||
name string
|
||||
id PacketID
|
||||
expect uint16
|
||||
}{
|
||||
{"MSG_HEAD", MSG_HEAD, 0},
|
||||
{"MSG_SYS_END", MSG_SYS_END, 0x10},
|
||||
{"MSG_SYS_NOP", MSG_SYS_NOP, 0x11},
|
||||
{"MSG_SYS_ACK", MSG_SYS_ACK, 0x12},
|
||||
{"MSG_SYS_LOGIN", MSG_SYS_LOGIN, 0x14},
|
||||
{"MSG_SYS_LOGOUT", MSG_SYS_LOGOUT, 0x15},
|
||||
{"MSG_SYS_PING", MSG_SYS_PING, 0x17},
|
||||
{"MSG_SYS_TIME", MSG_SYS_TIME, 0x1A},
|
||||
{"MSG_SYS_CREATE_STAGE", MSG_SYS_CREATE_STAGE, 0x20},
|
||||
{"MSG_SYS_ENTER_STAGE", MSG_SYS_ENTER_STAGE, 0x22},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if uint16(tt.id) != tt.expect {
|
||||
t.Errorf("%s = 0x%X, want 0x%X", tt.name, uint16(tt.id), tt.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketIDString(t *testing.T) {
|
||||
// Test that String() method works for known packet IDs
|
||||
tests := []struct {
|
||||
id PacketID
|
||||
contains string
|
||||
}{
|
||||
{MSG_HEAD, "MSG_HEAD"},
|
||||
{MSG_SYS_PING, "MSG_SYS_PING"},
|
||||
{MSG_SYS_END, "MSG_SYS_END"},
|
||||
{MSG_SYS_NOP, "MSG_SYS_NOP"},
|
||||
{MSG_SYS_ACK, "MSG_SYS_ACK"},
|
||||
{MSG_SYS_LOGIN, "MSG_SYS_LOGIN"},
|
||||
{MSG_SYS_LOGOUT, "MSG_SYS_LOGOUT"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.contains, func(t *testing.T) {
|
||||
got := tt.id.String()
|
||||
if got != tt.contains {
|
||||
t.Errorf("String() = %q, want %q", got, tt.contains)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketIDUnknown(t *testing.T) {
|
||||
// Unknown packet ID should still have a valid string representation
|
||||
unknown := PacketID(0xFFFF)
|
||||
str := unknown.String()
|
||||
if str == "" {
|
||||
t.Error("String() for unknown PacketID should not be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketIDZero(t *testing.T) {
|
||||
// MSG_HEAD should be 0
|
||||
if MSG_HEAD != 0 {
|
||||
t.Errorf("MSG_HEAD = %d, want 0", MSG_HEAD)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemPacketIDRange(t *testing.T) {
|
||||
// System packets should be in a specific range
|
||||
systemPackets := []PacketID{
|
||||
MSG_SYS_reserve01,
|
||||
MSG_SYS_reserve02,
|
||||
MSG_SYS_reserve03,
|
||||
MSG_SYS_ADD_OBJECT,
|
||||
MSG_SYS_DEL_OBJECT,
|
||||
MSG_SYS_END,
|
||||
MSG_SYS_NOP,
|
||||
MSG_SYS_ACK,
|
||||
MSG_SYS_LOGIN,
|
||||
MSG_SYS_LOGOUT,
|
||||
MSG_SYS_PING,
|
||||
MSG_SYS_TIME,
|
||||
}
|
||||
|
||||
for _, pkt := range systemPackets {
|
||||
// System packets should have IDs > 0 (MSG_HEAD is 0)
|
||||
if pkt < MSG_SYS_reserve01 {
|
||||
t.Errorf("System packet %s has ID %d, should be >= MSG_SYS_reserve01", pkt, pkt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMHFPacketIDRange(t *testing.T) {
|
||||
// MHF packets start at MSG_MHF_SAVEDATA (0x60)
|
||||
mhfPackets := []PacketID{
|
||||
MSG_MHF_SAVEDATA,
|
||||
MSG_MHF_LOADDATA,
|
||||
MSG_MHF_ENUMERATE_QUEST,
|
||||
MSG_MHF_ACQUIRE_TITLE,
|
||||
MSG_MHF_ACQUIRE_DIST_ITEM,
|
||||
MSG_MHF_ACQUIRE_MONTHLY_ITEM,
|
||||
}
|
||||
|
||||
for _, pkt := range mhfPackets {
|
||||
// MHF packets should be >= MSG_MHF_SAVEDATA
|
||||
if pkt < MSG_MHF_SAVEDATA {
|
||||
t.Errorf("MHF packet %s has ID %d, should be >= MSG_MHF_SAVEDATA (%d)", pkt, pkt, MSG_MHF_SAVEDATA)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStagePacketIDsSequential(t *testing.T) {
|
||||
// Stage-related packets should be sequential
|
||||
stagePackets := []PacketID{
|
||||
MSG_SYS_CREATE_STAGE,
|
||||
MSG_SYS_STAGE_DESTRUCT,
|
||||
MSG_SYS_ENTER_STAGE,
|
||||
MSG_SYS_BACK_STAGE,
|
||||
MSG_SYS_MOVE_STAGE,
|
||||
MSG_SYS_LEAVE_STAGE,
|
||||
MSG_SYS_LOCK_STAGE,
|
||||
MSG_SYS_UNLOCK_STAGE,
|
||||
}
|
||||
|
||||
for i := 1; i < len(stagePackets); i++ {
|
||||
if stagePackets[i] != stagePackets[i-1]+1 {
|
||||
t.Errorf("Stage packets not sequential: %s (%d) should follow %s (%d)",
|
||||
stagePackets[i], stagePackets[i], stagePackets[i-1], stagePackets[i-1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketIDUniqueness(t *testing.T) {
|
||||
// Sample of important packet IDs should be unique
|
||||
packets := []PacketID{
|
||||
MSG_HEAD,
|
||||
MSG_SYS_END,
|
||||
MSG_SYS_NOP,
|
||||
MSG_SYS_ACK,
|
||||
MSG_SYS_LOGIN,
|
||||
MSG_SYS_LOGOUT,
|
||||
MSG_SYS_PING,
|
||||
MSG_SYS_TIME,
|
||||
MSG_SYS_CREATE_STAGE,
|
||||
MSG_SYS_ENTER_STAGE,
|
||||
MSG_MHF_SAVEDATA,
|
||||
MSG_MHF_LOADDATA,
|
||||
}
|
||||
|
||||
seen := make(map[PacketID]bool)
|
||||
for _, pkt := range packets {
|
||||
if seen[pkt] {
|
||||
t.Errorf("Duplicate PacketID: %s (%d)", pkt, pkt)
|
||||
}
|
||||
seen[pkt] = true
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcquirePacketIDs(t *testing.T) {
|
||||
// Verify acquire-related packet IDs exist and are correct type
|
||||
acquirePackets := []PacketID{
|
||||
MSG_MHF_ACQUIRE_DIST_ITEM,
|
||||
MSG_MHF_ACQUIRE_TITLE,
|
||||
MSG_MHF_ACQUIRE_ITEM,
|
||||
MSG_MHF_ACQUIRE_MONTHLY_ITEM,
|
||||
MSG_MHF_ACQUIRE_CAFE_ITEM,
|
||||
MSG_MHF_ACQUIRE_GUILD_TRESURE,
|
||||
}
|
||||
|
||||
for _, pkt := range acquirePackets {
|
||||
str := pkt.String()
|
||||
if str == "" {
|
||||
t.Errorf("PacketID %d should have a string representation", pkt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGuildPacketIDs(t *testing.T) {
|
||||
// Verify guild-related packet IDs
|
||||
guildPackets := []PacketID{
|
||||
MSG_MHF_CREATE_GUILD,
|
||||
MSG_MHF_OPERATE_GUILD,
|
||||
MSG_MHF_OPERATE_GUILD_MEMBER,
|
||||
MSG_MHF_INFO_GUILD,
|
||||
MSG_MHF_ENUMERATE_GUILD,
|
||||
MSG_MHF_UPDATE_GUILD,
|
||||
}
|
||||
|
||||
for _, pkt := range guildPackets {
|
||||
// All guild packets should be MHF packets
|
||||
if pkt < MSG_MHF_SAVEDATA {
|
||||
t.Errorf("Guild packet %s should be an MHF packet (>= 0x60)", pkt)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user