Files
Erupe/network/binpacket/binpacket_test.go
Houmgaor 2a0e3e2c84 fix: re-enable CI lint job and fix ~65 lint errors (partial)
Re-enable the golangci-lint job in CI (disabled Oct 2025), update to
Go 1.25 and golangci-lint-action v7. Fix errcheck, gosimple S1009,
staticcheck SA4031 and SA2001 errors across 54 files. Remaining ~39
lint errors will be addressed in follow-up commits.
2026-02-17 17:59:00 +01:00

431 lines
9.7 KiB
Go

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()))
}
}