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