1
0
Protocol/packet_test.go
2025-09-02 20:25:42 -05:00

462 lines
13 KiB
Go

package eq2net
import (
"bytes"
"net"
"testing"
)
func TestEQPacket(t *testing.T) {
t.Run("NewEQPacket", func(t *testing.T) {
data := []byte{0x01, 0x02, 0x03, 0x04}
packet := NewEQPacket(0x1234, data)
if packet.Opcode != 0x1234 {
t.Errorf("Expected opcode 0x1234, got 0x%04x", packet.Opcode)
}
if !bytes.Equal(packet.Buffer, data) {
t.Errorf("Expected buffer %v, got %v", data, packet.Buffer)
}
if packet.Version != PROTOCOL_VERSION {
t.Errorf("Expected version %d, got %d", PROTOCOL_VERSION, packet.Version)
}
})
t.Run("ParsePacket", func(t *testing.T) {
// Test single-byte opcode
data1 := []byte{0x55, 0x01, 0x02, 0x03}
packet1, err := ParsePacket(data1)
if err != nil {
t.Fatalf("Failed to parse single-byte opcode: %v", err)
}
if packet1.Opcode != 0x55 {
t.Errorf("Expected opcode 0x55, got 0x%04x", packet1.Opcode)
}
if len(packet1.Buffer) != 3 {
t.Errorf("Expected buffer length 3, got %d", len(packet1.Buffer))
}
// Test two-byte opcode
data2 := []byte{0x12, 0x34, 0x01, 0x02, 0x03}
packet2, err := ParsePacket(data2)
if err != nil {
t.Fatalf("Failed to parse two-byte opcode: %v", err)
}
if packet2.Opcode != 0x1234 {
t.Errorf("Expected opcode 0x1234, got 0x%04x", packet2.Opcode)
}
if len(packet2.Buffer) != 3 {
t.Errorf("Expected buffer length 3, got %d", len(packet2.Buffer))
}
})
t.Run("Serialize", func(t *testing.T) {
// Test single-byte opcode serialization
packet1 := NewEQPacket(0x55, []byte{0x01, 0x02, 0x03})
serialized1 := packet1.Serialize()
expected1 := []byte{0x55, 0x01, 0x02, 0x03}
if !bytes.Equal(serialized1, expected1) {
t.Errorf("Expected serialized %v, got %v", expected1, serialized1)
}
// Test two-byte opcode serialization
packet2 := NewEQPacket(0x1234, []byte{0x01, 0x02, 0x03})
serialized2 := packet2.Serialize()
expected2 := []byte{0x12, 0x34, 0x01, 0x02, 0x03}
if !bytes.Equal(serialized2, expected2) {
t.Errorf("Expected serialized %v, got %v", expected2, serialized2)
}
})
t.Run("PreparePacket", func(t *testing.T) {
packet := NewEQPacket(0x1234, []byte{0x01, 0x02, 0x03})
packet.EmuOpcode = 0x5678
packet.OpcodeSize = 2
// Prepare packet for wire transmission
packet.PreparePacket(100)
if !packet.PacketPrepared {
t.Error("Expected packet to be marked as prepared")
}
// Should have headers and emulator opcode
// Format: 2 bytes sequence, 1 byte compression, then opcode
if len(packet.Buffer) < 5 {
t.Fatal("Buffer too small after preparation")
}
// Check that emulator opcode was added at correct position
// After 2-byte sequence and 1-byte compression flag
emuOpcode := uint16(packet.Buffer[4])<<8 | uint16(packet.Buffer[5])
if emuOpcode != 0x5678 {
t.Errorf("Expected emulator opcode 0x5678, got 0x%04x", emuOpcode)
}
})
t.Run("Clone", func(t *testing.T) {
original := NewEQPacket(0x1234, []byte{0x01, 0x02, 0x03})
original.SrcIP = net.ParseIP("192.168.1.1")
original.SrcPort = 9000
original.DstIP = net.ParseIP("192.168.1.2")
original.DstPort = 9001
original.EmuOpcode = 0x5678
original.OpcodeSize = 2
cloned := original.Clone()
// Verify clone has same values
if cloned.Opcode != original.Opcode {
t.Errorf("Cloned opcode mismatch: %v != %v", cloned.Opcode, original.Opcode)
}
if !bytes.Equal(cloned.Buffer, original.Buffer) {
t.Errorf("Cloned buffer mismatch: %v != %v", cloned.Buffer, original.Buffer)
}
if !cloned.SrcIP.Equal(original.SrcIP) {
t.Errorf("Cloned SrcIP mismatch: %v != %v", cloned.SrcIP, original.SrcIP)
}
if cloned.EmuOpcode != original.EmuOpcode {
t.Errorf("Cloned EmuOpcode mismatch: %v != %v", cloned.EmuOpcode, original.EmuOpcode)
}
// Verify it's a deep copy
original.Buffer[0] = 0xFF
if cloned.Buffer[0] == 0xFF {
t.Error("Clone shares buffer with original")
}
})
}
func TestProtocolPacket(t *testing.T) {
t.Run("NewProtocolPacket", func(t *testing.T) {
data := []byte{0x01, 0x02, 0x03}
packet := NewProtocolPacket(OP_Packet, data)
if packet.Opcode != OP_Packet {
t.Errorf("Expected opcode OP_Packet, got 0x%04x", packet.Opcode)
}
if !bytes.Equal(packet.Buffer, data) {
t.Errorf("Expected buffer %v, got %v", data, packet.Buffer)
}
})
t.Run("Compression", func(t *testing.T) {
// Test large packet compression (zlib)
largeData := make([]byte, 100)
for i := range largeData {
largeData[i] = byte(i % 256)
}
packet := NewProtocolPacket(OP_Packet, largeData)
originalLen := len(packet.Buffer)
// Compress
err := packet.Compress()
if err != nil {
t.Fatalf("Failed to compress: %v", err)
}
if !packet.Compressed {
t.Error("Packet should be marked as compressed")
}
if packet.Buffer[0] != 0x5a {
t.Errorf("Expected zlib compression flag 0x5a, got 0x%02x", packet.Buffer[0])
}
// Decompress
err = packet.Decompress()
if err != nil {
t.Fatalf("Failed to decompress: %v", err)
}
if packet.Compressed {
t.Error("Packet should not be marked as compressed after decompression")
}
if len(packet.Buffer) != originalLen {
t.Errorf("Decompressed size mismatch: expected %d, got %d", originalLen, len(packet.Buffer))
}
if !bytes.Equal(packet.Buffer, largeData) {
t.Error("Decompressed data does not match original")
}
})
t.Run("SimpleEncoding", func(t *testing.T) {
// Test small packet encoding
smallData := []byte{0x01, 0x02, 0x03}
packet := NewProtocolPacket(OP_Packet, smallData)
// Compress (should use simple encoding)
err := packet.Compress()
if err != nil {
t.Fatalf("Failed to compress: %v", err)
}
if !packet.Compressed {
t.Error("Packet should be marked as compressed")
}
if packet.Buffer[0] != 0xa5 {
t.Errorf("Expected simple encoding flag 0xa5, got 0x%02x", packet.Buffer[0])
}
// Decompress
err = packet.Decompress()
if err != nil {
t.Fatalf("Failed to decompress: %v", err)
}
if !bytes.Equal(packet.Buffer, smallData) {
t.Error("Decompressed data does not match original")
}
})
t.Run("Combine", func(t *testing.T) {
packet1 := NewProtocolPacket(OP_Packet, []byte{0x01, 0x02})
packet2 := NewProtocolPacket(OP_Ack, []byte{0x03, 0x04})
// Combine packets
success := packet1.Combine(packet2)
if !success {
t.Fatal("Failed to combine packets")
}
if packet1.Opcode != OP_Combined {
t.Errorf("Expected combined opcode, got 0x%04x", packet1.Opcode)
}
if len(packet1.SubPackets) != 2 {
t.Errorf("Expected 2 sub-packets, got %d", len(packet1.SubPackets))
}
})
t.Run("ExtractSubPackets", func(t *testing.T) {
// Create combined packet manually
packet1Data := []byte{0x00, 0x09, 0x01, 0x02} // OP_Packet with data
packet2Data := []byte{0x00, 0x15, 0x03, 0x04} // OP_Ack with data
combinedBuffer := []byte{
byte(len(packet1Data)), // Size of first packet
}
combinedBuffer = append(combinedBuffer, packet1Data...)
combinedBuffer = append(combinedBuffer, byte(len(packet2Data))) // Size of second packet
combinedBuffer = append(combinedBuffer, packet2Data...)
combined := NewProtocolPacket(OP_Combined, combinedBuffer)
// Extract sub-packets
subPackets, err := combined.ExtractSubPackets()
if err != nil {
t.Fatalf("Failed to extract sub-packets: %v", err)
}
if len(subPackets) != 2 {
t.Fatalf("Expected 2 sub-packets, got %d", len(subPackets))
}
if subPackets[0].Opcode != OP_Packet {
t.Errorf("Expected first packet opcode OP_Packet, got 0x%04x", subPackets[0].Opcode)
}
if subPackets[1].Opcode != OP_Ack {
t.Errorf("Expected second packet opcode OP_Ack, got 0x%04x", subPackets[1].Opcode)
}
})
}
func TestLoginPacket(t *testing.T) {
t.Run("NewLoginPacket", func(t *testing.T) {
data := []byte{0x01, 0x02, 0x03}
packet := NewLoginPacket(LOP_LoginRequestMsg, data)
if packet.LoginEmuOpcode != LOP_LoginRequestMsg {
t.Errorf("Expected opcode LOP_LoginRequestMsg, got %v", packet.LoginEmuOpcode)
}
if packet.OpcodeSize != 1 {
t.Errorf("Expected opcode size 1, got %d", packet.OpcodeSize)
}
if !bytes.Equal(packet.Buffer, data) {
t.Errorf("Expected buffer %v, got %v", data, packet.Buffer)
}
})
t.Run("ParseLoginPacket", func(t *testing.T) {
data := []byte{byte(LOP_LoginRequestMsg), 0x01, 0x02, 0x03}
packet, err := ParseLoginPacket(data)
if err != nil {
t.Fatalf("Failed to parse login packet: %v", err)
}
if packet.LoginEmuOpcode != LOP_LoginRequestMsg {
t.Errorf("Expected opcode LOP_LoginRequestMsg, got %v", packet.LoginEmuOpcode)
}
if len(packet.Buffer) != 3 {
t.Errorf("Expected buffer length 3, got %d", len(packet.Buffer))
}
})
t.Run("SerializeLogin", func(t *testing.T) {
packet := NewLoginPacket(LOP_WorldListMsg, []byte{0x01, 0x02})
serialized := packet.SerializeLogin()
expected := []byte{byte(LOP_WorldListMsg), 0x01, 0x02}
if !bytes.Equal(serialized, expected) {
t.Errorf("Expected serialized %v, got %v", expected, serialized)
}
})
t.Run("ConvertToProtocolPacket", func(t *testing.T) {
loginPacket := NewLoginPacket(LOP_LoginReplyMsg, []byte{0x01, 0x02})
loginPacket.SrcIP = net.ParseIP("192.168.1.1")
loginPacket.DstIP = net.ParseIP("192.168.1.2")
protoPacket := loginPacket.ConvertToProtocolPacket()
if protoPacket.Opcode != OP_Packet {
t.Errorf("Expected protocol opcode OP_Packet, got 0x%04x", protoPacket.Opcode)
}
// Should contain serialized login packet
expectedData := loginPacket.SerializeLogin()
if !bytes.Equal(protoPacket.Buffer, expectedData) {
t.Errorf("Protocol packet buffer mismatch")
}
// Should preserve network info
if !protoPacket.SrcIP.Equal(loginPacket.SrcIP) {
t.Errorf("Source IP not preserved")
}
})
}
func TestGamePacket(t *testing.T) {
t.Run("NewGamePacket", func(t *testing.T) {
data := []byte{0x01, 0x02, 0x03}
packet := NewGamePacket(GOP_LoginReplyMsg, data)
if packet.GameEmuOpcode != GOP_LoginReplyMsg {
t.Errorf("Expected opcode GOP_LoginReplyMsg, got %v", packet.GameEmuOpcode)
}
if packet.OpcodeSize != 2 {
t.Errorf("Expected opcode size 2, got %d", packet.OpcodeSize)
}
if !bytes.Equal(packet.Buffer, data) {
t.Errorf("Expected buffer %v, got %v", data, packet.Buffer)
}
})
t.Run("ParseGamePacket", func(t *testing.T) {
// Test normal 2-byte opcode
opcode := uint16(GOP_ZoneInfoMsg)
data1 := []byte{byte(opcode >> 8), byte(opcode), 0x01, 0x02}
packet1, err := ParseGamePacket(data1)
if err != nil {
t.Fatalf("Failed to parse game packet: %v", err)
}
if packet1.GameEmuOpcode != GOP_ZoneInfoMsg {
t.Errorf("Expected opcode GOP_ZoneInfoMsg, got %v", packet1.GameEmuOpcode)
}
// Test special encoding (low byte = 0x00)
data2 := []byte{0x00, 0x12, 0x00, 0x01, 0x02} // Extra 0x00 prefix
packet2, err := ParseGamePacket(data2)
if err != nil {
t.Fatalf("Failed to parse special encoded packet: %v", err)
}
if packet2.GameEmuOpcode != 0x1200 {
t.Errorf("Expected opcode 0x1200, got 0x%04x", packet2.GameEmuOpcode)
}
})
t.Run("SerializeGame", func(t *testing.T) {
// Test normal opcode
packet1 := NewGamePacket(GOP_MOTDMsg, []byte{0x01, 0x02})
serialized1 := packet1.SerializeGame()
opcode1 := uint16(GOP_MOTDMsg)
expected1 := []byte{byte(opcode1 >> 8), byte(opcode1), 0x01, 0x02}
if !bytes.Equal(serialized1, expected1) {
t.Errorf("Expected serialized %v, got %v", expected1, serialized1)
}
// Test special encoding (low byte = 0x00)
packet2 := NewGamePacket(0x1200, []byte{0x01, 0x02})
serialized2 := packet2.SerializeGame()
expected2 := []byte{0x00, 0x12, 0x00, 0x01, 0x02} // Extra 0x00 prefix
if !bytes.Equal(serialized2, expected2) {
t.Errorf("Expected special encoded %v, got %v", expected2, serialized2)
}
})
t.Run("CombineGamePackets", func(t *testing.T) {
packet1 := NewGamePacket(GOP_UpdateDataMsg, []byte{0x01})
packet2 := NewGamePacket(GOP_UpdateSpawnMsg, []byte{0x02})
packet3 := NewGamePacket(GOP_UpdateTimeMsg, []byte{0x03})
combined := CombineGamePackets([]*GamePacket{packet1, packet2, packet3})
if combined == nil {
t.Fatal("Failed to combine game packets")
}
if combined.Opcode != OP_AppCombined {
t.Errorf("Expected opcode OP_AppCombined, got 0x%04x", combined.Opcode)
}
// Verify buffer contains size-prefixed packets
if len(combined.Buffer) < 3 {
t.Error("Combined buffer too small")
}
})
}
func TestOpcodeNames(t *testing.T) {
t.Run("GetOpcodeName", func(t *testing.T) {
name := GetOpcodeName(OP_SessionRequest)
if name != "OP_SessionRequest" {
t.Errorf("Expected 'OP_SessionRequest', got '%s'", name)
}
unknownName := GetOpcodeName(0xFFFF)
if unknownName != "Unknown(65535)" {
t.Errorf("Expected 'Unknown(65535)', got '%s'", unknownName)
}
})
t.Run("GetLoginOpcodeName", func(t *testing.T) {
name := GetLoginOpcodeName(LOP_LoginRequestMsg)
if name != "LOP_LoginRequestMsg" {
t.Errorf("Expected 'LOP_LoginRequestMsg', got '%s'", name)
}
unknownName := GetLoginOpcodeName(0xFFFF)
if !bytes.Contains([]byte(unknownName), []byte("Unknown")) {
t.Errorf("Expected Unknown opcode name, got '%s'", unknownName)
}
})
t.Run("GetGameOpcodeName", func(t *testing.T) {
name := GetGameOpcodeName(GOP_ZoneInfoMsg)
if name != "GOP_ZoneInfoMsg" {
t.Errorf("Expected 'GOP_ZoneInfoMsg', got '%s'", name)
}
unknownName := GetGameOpcodeName(0xFFFF)
if !bytes.Contains([]byte(unknownName), []byte("Unknown")) {
t.Errorf("Expected Unknown opcode name, got '%s'", unknownName)
}
})
}