Compare commits

...

19 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
adbd9d78a6 Enhance MailInfo serialization test to verify all serialized fields completely
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 17:27:55 +00:00
copilot-swe-agent[bot]
89ea1ee831 Remove CDClient changes and revert unnecessary modifications to keep scope focused on network packet and mail tests
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 17:10:57 +00:00
copilot-swe-agent[bot]
177319438d Remove component tests and focus on network packet and mail bitstream tests
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 16:59:56 +00:00
copilot-swe-agent[bot]
74fb9428bb Fix component tests to work without database dependencies
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 08:40:34 +00:00
copilot-swe-agent[bot]
4d6debae84 Fix component tests to work without database dependencies
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 08:08:40 +00:00
copilot-swe-agent[bot]
48f8d0fe04 Fix test failures: initialize variables and remove useless assertions
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 07:31:45 +00:00
copilot-swe-agent[bot]
2b0791130f Improve CharacterComponent tests to follow proper variable testing pattern and address feedback on testing each component variable
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 06:53:34 +00:00
copilot-swe-agent[bot]
3c111735bc Remove consistency tests from all component tests as requested
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 06:49:35 +00:00
copilot-swe-agent[bot]
fc48f58425 Remove broken ChatPacketHandler tests that had compilation dependencies on dChatServer
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 06:31:47 +00:00
copilot-swe-agent[bot]
125c98570d Add additional component serialization tests for QuickBuildComponent, VendorComponent, and RenderComponent with comprehensive coverage
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 06:18:26 +00:00
copilot-swe-agent[bot]
de49b53366 Add initial comprehensive component serialization tests for CharacterComponent, InventoryComponent, ControllablePhysicsComponent, SkillComponent, and BuffComponent
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 06:11:52 +00:00
copilot-swe-agent[bot]
5a17e6cf23 Add comprehensive ChatPacketHandler bitstream tests for all handler methods
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 05:53:49 +00:00
copilot-swe-agent[bot]
b6764bbb10 Remove mail extended tests and add proper Mail.h tests to dGameTests
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 05:45:16 +00:00
copilot-swe-agent[bot]
e6204752aa Add comprehensive mail extended tests for MailInfo serialization edge cases and data integrity
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 05:29:24 +00:00
copilot-swe-agent[bot]
d376775731 Add comprehensive mail bitstream tests starting with MailInfo serialization
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 05:15:08 +00:00
copilot-swe-agent[bot]
c20260cd85 Split PacketTests.cpp into multiple files by packet type and fix missing newlines
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 04:57:44 +00:00
copilot-swe-agent[bot]
90f325f59c Complete comprehensive packet testing framework with 20 tests covering all major packet types and edge cases
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 04:44:51 +00:00
copilot-swe-agent[bot]
a82aeec50e Add comprehensive packet test framework with 14 tests covering packet serialization/deserialization
Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
2025-08-31 04:40:11 +00:00
copilot-swe-agent[bot]
065817b1ce Initial plan 2025-08-31 04:24:33 +00:00
13 changed files with 1390 additions and 4 deletions

View File

@@ -7,3 +7,4 @@ include(GoogleTest)
# Add the subdirectories
add_subdirectory(dCommonTests)
add_subdirectory(dGameTests)
add_subdirectory(dNetTests)

View File

@@ -1,5 +1,6 @@
set(DGAMETEST_SOURCES
"GameDependencies.cpp"
"MailTests.cpp"
)
add_subdirectory(dComponentsTests)

View File

@@ -0,0 +1,403 @@
#include "GameDependencies.h"
#include "Mail.h"
#include "MailInfo.h"
#include "BitStream.h"
#include "Entity.h"
#include "User.h"
#include "Character.h"
#include "dCommonVars.h"
#include "BitStreamUtils.h"
class MailTests : public GameDependenciesTest {
protected:
void SetUp() override {
SetUpDependencies();
}
void TearDown() override {
TearDownDependencies();
}
};
// Test SendRequest packet with MailInfo serialization
TEST_F(MailTests, SendRequestMailInfoSerialization) {
Mail::SendRequest sendRequest;
// Set up test mail info
sendRequest.mailInfo.senderUsername = "TestSender";
sendRequest.mailInfo.recipient = "TestRecipient";
sendRequest.mailInfo.subject = "Test Subject";
sendRequest.mailInfo.body = "Test mail body content";
sendRequest.mailInfo.id = 12345;
sendRequest.mailInfo.senderId = 678;
sendRequest.mailInfo.receiverId = 901;
sendRequest.mailInfo.timeSent = 1640995200;
sendRequest.mailInfo.wasRead = false;
sendRequest.mailInfo.languageCode = 1033;
sendRequest.mailInfo.itemID = 555;
sendRequest.mailInfo.itemCount = 10;
sendRequest.mailInfo.itemLOT = 1234;
sendRequest.mailInfo.itemSubkey = 999;
// Test that the mail info serializes to a non-empty bitstream
RakNet::BitStream mailInfoStream;
sendRequest.mailInfo.Serialize(mailInfoStream);
// Verify the stream contains data
ASSERT_GT(mailInfoStream.GetNumberOfBytesUsed(), 0);
// Verify all fields are serialized correctly by reading them back
mailInfoStream.ResetReadPointer();
// Read id (uint64_t)
uint64_t readId;
ASSERT_TRUE(mailInfoStream.Read(readId));
ASSERT_EQ(readId, 12345);
// Read subject (LUWString, 50 chars)
LUWString readSubject(50);
ASSERT_TRUE(mailInfoStream.Read(readSubject));
ASSERT_EQ(readSubject.GetAsString(), "Test Subject");
// Read body (LUWString, 400 chars)
LUWString readBody(400);
ASSERT_TRUE(mailInfoStream.Read(readBody));
ASSERT_EQ(readBody.GetAsString(), "Test mail body content");
// Read sender (LUWString, 32 chars)
LUWString readSender(32);
ASSERT_TRUE(mailInfoStream.Read(readSender));
ASSERT_EQ(readSender.GetAsString(), "TestSender");
// Read packing (uint32_t = 0)
uint32_t packing1;
ASSERT_TRUE(mailInfoStream.Read(packing1));
ASSERT_EQ(packing1, 0);
// Read attachedCurrency (uint64_t = 0)
uint64_t attachedCurrency;
ASSERT_TRUE(mailInfoStream.Read(attachedCurrency));
ASSERT_EQ(attachedCurrency, 0);
// Read itemID (LWOOBJID)
LWOOBJID readItemID;
ASSERT_TRUE(mailInfoStream.Read(readItemID));
ASSERT_EQ(readItemID, 555);
// Read itemLOT (LOT)
LOT readItemLOT;
ASSERT_TRUE(mailInfoStream.Read(readItemLOT));
ASSERT_EQ(readItemLOT, 1234);
// Read packing (uint32_t = 0)
uint32_t packing2;
ASSERT_TRUE(mailInfoStream.Read(packing2));
ASSERT_EQ(packing2, 0);
// Read itemSubkey (LWOOBJID)
LWOOBJID readItemSubkey;
ASSERT_TRUE(mailInfoStream.Read(readItemSubkey));
ASSERT_EQ(readItemSubkey, 999);
// Read itemCount (int16_t)
int16_t readItemCount;
ASSERT_TRUE(mailInfoStream.Read(readItemCount));
ASSERT_EQ(readItemCount, 10);
// Read subject type (uint8_t = 0)
uint8_t subjectType;
ASSERT_TRUE(mailInfoStream.Read(subjectType));
ASSERT_EQ(subjectType, 0);
// Read packing (uint8_t = 0)
uint8_t packing3;
ASSERT_TRUE(mailInfoStream.Read(packing3));
ASSERT_EQ(packing3, 0);
// Read packing (uint32_t = 0)
uint32_t packing4;
ASSERT_TRUE(mailInfoStream.Read(packing4));
ASSERT_EQ(packing4, 0);
// Read expiration date (uint64_t = timeSent)
uint64_t expirationDate;
ASSERT_TRUE(mailInfoStream.Read(expirationDate));
ASSERT_EQ(expirationDate, 1640995200);
// Read send date (uint64_t = timeSent)
uint64_t sendDate;
ASSERT_TRUE(mailInfoStream.Read(sendDate));
ASSERT_EQ(sendDate, 1640995200);
// Read wasRead (uint8_t)
uint8_t readWasRead;
ASSERT_TRUE(mailInfoStream.Read(readWasRead));
ASSERT_EQ(readWasRead, false);
// Read isLocalized (uint8_t = 0)
uint8_t isLocalized;
ASSERT_TRUE(mailInfoStream.Read(isLocalized));
ASSERT_EQ(isLocalized, 0);
// Read language code (uint16_t = 1033)
uint16_t readLanguageCode;
ASSERT_TRUE(mailInfoStream.Read(readLanguageCode));
ASSERT_EQ(readLanguageCode, 1033);
// Read final packing (uint32_t = 0)
uint32_t finalPacking;
ASSERT_TRUE(mailInfoStream.Read(finalPacking));
ASSERT_EQ(finalPacking, 0);
// Verify we've read all the data
ASSERT_EQ(mailInfoStream.GetNumberOfUnreadBits(), 0);
}
// Test SendResponse packet serialization
TEST_F(MailTests, SendResponseSerialization) {
Mail::SendResponse sendResponse;
sendResponse.status = Mail::eSendResponse::Success;
RakNet::BitStream outStream;
sendResponse.Serialize(outStream);
// Verify the stream contains data
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// Verify message ID and status are written
outStream.ResetReadPointer();
uint32_t messageID;
uint32_t status;
ASSERT_TRUE(outStream.Read(messageID));
ASSERT_TRUE(outStream.Read(status));
ASSERT_EQ(messageID, static_cast<uint32_t>(Mail::eMessageID::SendResponse));
ASSERT_EQ(status, static_cast<uint32_t>(Mail::eSendResponse::Success));
}
// Test NotificationResponse packet serialization
TEST_F(MailTests, NotificationResponseSerialization) {
Mail::NotificationResponse notificationResponse;
notificationResponse.status = Mail::eNotificationResponse::NewMail;
notificationResponse.auctionID = 12345;
notificationResponse.mailCount = 3;
RakNet::BitStream outStream;
notificationResponse.Serialize(outStream);
// Verify the stream contains data
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// Verify message ID and fields are written in the correct order
// Order: messageID, status, unused, unused, auctionID, unused, mailCount, packing
outStream.ResetReadPointer();
uint32_t messageID;
uint32_t status;
uint64_t unused1, unused2, auctionID, unused3;
uint32_t mailCount, packing;
ASSERT_TRUE(outStream.Read(messageID));
ASSERT_TRUE(outStream.Read(status));
ASSERT_TRUE(outStream.Read(unused1));
ASSERT_TRUE(outStream.Read(unused2));
ASSERT_TRUE(outStream.Read(auctionID));
ASSERT_TRUE(outStream.Read(unused3));
ASSERT_TRUE(outStream.Read(mailCount));
ASSERT_TRUE(outStream.Read(packing));
ASSERT_EQ(messageID, static_cast<uint32_t>(Mail::eMessageID::NotificationResponse));
ASSERT_EQ(status, static_cast<uint32_t>(Mail::eNotificationResponse::NewMail));
ASSERT_EQ(auctionID, 12345);
ASSERT_EQ(mailCount, 3);
}
// Test DataResponse packet serialization
TEST_F(MailTests, DataResponseSerialization) {
Mail::DataResponse dataResponse;
dataResponse.throttled = 0;
// Add some mail info
MailInfo mail1, mail2;
mail1.senderUsername = "Sender1";
mail1.recipient = "Recipient1";
mail1.subject = "Subject1";
mail1.body = "Body1";
mail1.id = 1;
mail1.senderId = 100;
mail1.receiverId = 200;
mail1.timeSent = 1640995200;
mail1.wasRead = false;
mail1.languageCode = 1033;
mail1.itemID = LWOOBJID_EMPTY;
mail1.itemCount = 0;
mail1.itemLOT = LOT_NULL;
mail1.itemSubkey = LWOOBJID_EMPTY;
mail2.senderUsername = "Sender2";
mail2.recipient = "Recipient2";
mail2.subject = "Subject2";
mail2.body = "Body2";
mail2.id = 2;
mail2.senderId = 300;
mail2.receiverId = 400;
mail2.timeSent = 1640995300;
mail2.wasRead = true;
mail2.languageCode = 1033;
mail2.itemID = 555;
mail2.itemCount = 10;
mail2.itemLOT = 1234;
mail2.itemSubkey = 999;
dataResponse.playerMail.push_back(mail1);
dataResponse.playerMail.push_back(mail2);
RakNet::BitStream outStream;
dataResponse.Serialize(outStream);
// Verify the stream contains data
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// Verify message ID, throttled, and mail count are written
outStream.ResetReadPointer();
uint32_t messageID;
uint32_t throttled;
uint16_t mailCount;
ASSERT_TRUE(outStream.Read(messageID));
ASSERT_TRUE(outStream.Read(throttled));
ASSERT_TRUE(outStream.Read(mailCount));
ASSERT_EQ(messageID, static_cast<uint32_t>(Mail::eMessageID::DataResponse));
ASSERT_EQ(throttled, 0);
ASSERT_EQ(mailCount, 2);
}
// Test AttachmentCollectRequest packet deserialization
TEST_F(MailTests, AttachmentCollectRequestDeserialize) {
// This test verifies the deserialization reads data in the correct order
RakNet::BitStream inStream;
uint32_t unknown = 123; // Unknown field that comes first
uint64_t mailID = 12345;
uint64_t playerID = 67890;
// The Deserialize method reads: unknown, mailID, playerID
inStream.Write(unknown);
inStream.Write(mailID);
inStream.Write(playerID);
inStream.ResetReadPointer();
Mail::AttachmentCollectRequest request;
ASSERT_TRUE(request.Deserialize(inStream));
ASSERT_EQ(request.mailID, mailID);
ASSERT_EQ(request.playerID, playerID);
}
// Test AttachmentCollectResponse packet serialization
TEST_F(MailTests, AttachmentCollectResponseSerialization) {
Mail::AttachmentCollectResponse response;
response.status = Mail::eAttachmentCollectResponse::Success;
response.mailID = 54321;
RakNet::BitStream outStream;
response.Serialize(outStream);
// Verify the stream contains data
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// Verify message ID, status, and mail ID are written
outStream.ResetReadPointer();
uint32_t messageID;
uint32_t status;
uint64_t mailID;
ASSERT_TRUE(outStream.Read(messageID));
ASSERT_TRUE(outStream.Read(status));
ASSERT_TRUE(outStream.Read(mailID));
ASSERT_EQ(messageID, static_cast<uint32_t>(Mail::eMessageID::AttachmentCollectResponse));
ASSERT_EQ(status, static_cast<uint32_t>(Mail::eAttachmentCollectResponse::Success));
ASSERT_EQ(mailID, 54321);
}
// Test DeleteRequest packet deserialization
TEST_F(MailTests, DeleteRequestDeserialize) {
// This test verifies the deserialization reads data in the correct order
RakNet::BitStream inStream;
int32_t unknown = 456; // Unknown field that comes first
uint64_t mailID = 98765;
uint64_t playerID = 11111;
// The Deserialize method reads: unknown, mailID, playerID
inStream.Write(unknown);
inStream.Write(mailID);
inStream.Write(playerID);
inStream.ResetReadPointer();
Mail::DeleteRequest request;
ASSERT_TRUE(request.Deserialize(inStream));
ASSERT_EQ(request.mailID, mailID);
ASSERT_EQ(request.playerID, playerID);
}
// Test DeleteResponse packet serialization
TEST_F(MailTests, DeleteResponseSerialization) {
Mail::DeleteResponse response;
response.status = Mail::eDeleteResponse::Success;
response.mailID = 13579;
RakNet::BitStream outStream;
response.Serialize(outStream);
// Verify the stream contains data
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// Verify message ID, status, and mail ID are written
outStream.ResetReadPointer();
uint32_t messageID;
uint32_t status;
uint64_t mailID;
ASSERT_TRUE(outStream.Read(messageID));
ASSERT_TRUE(outStream.Read(status));
ASSERT_TRUE(outStream.Read(mailID));
ASSERT_EQ(messageID, static_cast<uint32_t>(Mail::eMessageID::DeleteResponse));
ASSERT_EQ(status, static_cast<uint32_t>(Mail::eDeleteResponse::Success));
ASSERT_EQ(mailID, 13579);
}
// Test ReadRequest packet deserialization
TEST_F(MailTests, ReadRequestDeserialize) {
// This test verifies the deserialization reads data in the correct order
RakNet::BitStream inStream;
int32_t unknown = 789; // Unknown field that comes first
uint64_t mailID = 24680;
// The Deserialize method reads: unknown, mailID
inStream.Write(unknown);
inStream.Write(mailID);
inStream.ResetReadPointer();
Mail::ReadRequest request;
ASSERT_TRUE(request.Deserialize(inStream));
ASSERT_EQ(request.mailID, mailID);
}
// Test ReadResponse packet serialization
TEST_F(MailTests, ReadResponseSerialization) {
Mail::ReadResponse response;
response.mailID = 97531;
response.status = Mail::eReadResponse::Success;
RakNet::BitStream outStream;
response.Serialize(outStream);
// Verify the stream contains data
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// Verify message ID, status, and mail ID are written in correct order
outStream.ResetReadPointer();
uint32_t messageID;
uint32_t status;
uint64_t mailID;
ASSERT_TRUE(outStream.Read(messageID));
ASSERT_TRUE(outStream.Read(status));
ASSERT_TRUE(outStream.Read(mailID));
ASSERT_EQ(messageID, static_cast<uint32_t>(Mail::eMessageID::ReadResponse));
ASSERT_EQ(status, static_cast<uint32_t>(Mail::eReadResponse::Success));
ASSERT_EQ(mailID, 97531);
}

View File

@@ -1,8 +1,8 @@
set(DCOMPONENTS_TESTS
"DestroyableComponentTests.cpp"
"PetComponentTests.cpp"
"SimplePhysicsComponentTests.cpp"
"SavingTests.cpp"
"DestroyableComponentTests.cpp"
"PetComponentTests.cpp"
"SimplePhysicsComponentTests.cpp"
"SavingTests.cpp"
)
# Get the folder name and prepend it to the files above

View File

@@ -0,0 +1,28 @@
#include "TestCommon.h"
#include "AuthPackets.h"
#include "MessageType/Auth.h"
class AuthPacketTests : public PacketTestsBase {};
// ===== AuthPackets Tests =====
TEST_F(AuthPacketTests, AuthStampSerialization) {
Stamp testStamp(eStamps::PASSPORT_AUTH_START, 12345, 1609459200); // Jan 1, 2021 timestamp
RakNet::BitStream bitStream;
testStamp.Serialize(bitStream);
// Verify serialized data
eStamps readType;
uint32_t readValue;
uint64_t readTimestamp;
bitStream.Read(readType);
bitStream.Read(readValue);
bitStream.Read(readTimestamp);
ASSERT_EQ(readType, eStamps::PASSPORT_AUTH_START);
ASSERT_EQ(readValue, 12345u);
ASSERT_EQ(readTimestamp, 1609459200u);
ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 0);
}

View File

@@ -0,0 +1,26 @@
set(DNETTESTS_SOURCES
"TestCommon.cpp"
"AuthPacketTests.cpp"
"ChatPacketTests.cpp"
"WorldPacketTests.cpp"
"MasterPacketTests.cpp"
"PacketEdgeCaseTests.cpp"
"MailBitStreamTests.cpp"
)
# Set our executable
add_executable(dNetTests ${DNETTESTS_SOURCES})
# Needs to be in binary dir for ctest
if(APPLE)
add_custom_target(dNetTestsLink
${CMAKE_COMMAND} -E copy $<TARGET_FILE:MariaDB::ConnCpp> ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(dNetTests dNetTestsLink)
endif()
# Link needed libraries
target_link_libraries(dNetTests ${COMMON_LIBRARIES} GTest::gtest_main dNet)
# Discover the tests
gtest_discover_tests(dNetTests)

View File

@@ -0,0 +1,207 @@
#include "TestCommon.h"
#include "ChatPackets.h"
#include "ClientPackets.h"
#include "MessageType/Chat.h"
#include "MessageType/Client.h"
class ChatPacketTests : public PacketTestsBase {};
// ===== ChatPackets Tests =====
TEST_F(ChatPacketTests, ChatShowAllRequestSerialization) {
ShowAllRequest request;
request.requestor = 123456789;
request.displayZoneData = true;
request.displayIndividualPlayers = false;
RakNet::BitStream bitStream;
request.Serialize(bitStream);
VerifyHeader(&bitStream, ServiceType::CHAT, static_cast<uint32_t>(MessageType::Chat::SHOW_ALL));
LWOOBJID readRequestor;
bool readDisplayZoneData;
bool readDisplayIndividualPlayers;
bitStream.Read(readRequestor);
bitStream.Read(readDisplayZoneData);
bitStream.Read(readDisplayIndividualPlayers);
ASSERT_EQ(readRequestor, 123456789);
ASSERT_EQ(readDisplayZoneData, true);
ASSERT_EQ(readDisplayIndividualPlayers, false);
ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 0);
}
TEST_F(ChatPacketTests, ChatShowAllRequestRoundTrip) {
ShowAllRequest original;
original.requestor = 987654321;
original.displayZoneData = false;
original.displayIndividualPlayers = true;
RakNet::BitStream bitStream;
original.Serialize(bitStream);
// Skip header for deserialization
uint8_t rakNetPacketId{};
uint16_t serviceType{};
uint32_t packetId{};
uint8_t always0{};
bitStream.Read(rakNetPacketId);
bitStream.Read(serviceType);
bitStream.Read(packetId);
bitStream.Read(always0);
ShowAllRequest deserialized;
deserialized.Deserialize(bitStream);
ASSERT_EQ(deserialized.requestor, original.requestor);
ASSERT_EQ(deserialized.displayZoneData, original.displayZoneData);
ASSERT_EQ(deserialized.displayIndividualPlayers, original.displayIndividualPlayers);
}
TEST_F(ChatPacketTests, ChatFindPlayerRequestSerialization) {
FindPlayerRequest request;
request.requestor = 555555555;
request.playerName = LUWString(u"TestPlayer123");
RakNet::BitStream bitStream;
request.Serialize(bitStream);
VerifyHeader(&bitStream, ServiceType::CHAT, static_cast<uint32_t>(MessageType::Chat::WHO));
LWOOBJID readRequestor;
LUWString readPlayerName;
bitStream.Read(readRequestor);
bitStream.Read(readPlayerName);
ASSERT_EQ(readRequestor, 555555555);
ASSERT_EQ(readPlayerName.string, u"TestPlayer123");
ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 0);
}
TEST_F(ChatPacketTests, ChatFindPlayerRequestRoundTrip) {
FindPlayerRequest original;
original.requestor = 777777777;
original.playerName = LUWString(u"PlayerToFind");
RakNet::BitStream bitStream;
original.Serialize(bitStream);
// Skip header for deserialization
uint8_t rakNetPacketId{};
uint16_t serviceType{};
uint32_t packetId{};
uint8_t always0{};
bitStream.Read(rakNetPacketId);
bitStream.Read(serviceType);
bitStream.Read(packetId);
bitStream.Read(always0);
FindPlayerRequest deserialized;
deserialized.Deserialize(bitStream);
ASSERT_EQ(deserialized.requestor, original.requestor);
ASSERT_EQ(deserialized.playerName.string, original.playerName.string);
}
TEST_F(ChatPacketTests, ChatAnnouncementSerialization) {
ChatPackets::Announcement announcement;
announcement.title = "Test Title";
announcement.message = "Test announcement message";
// Call Send which will add header and serialize
announcement.Send(UNASSIGNED_SYSTEM_ADDRESS);
auto* bitStream = GetMostRecentBitStream();
VerifyHeader(bitStream, ServiceType::CHAT, static_cast<uint32_t>(MessageType::Chat::GM_ANNOUNCE));
// Read announcement data (size prefixed strings)
uint32_t titleSize;
bitStream->Read(titleSize);
ASSERT_EQ(titleSize, announcement.title.size());
std::string readTitle(titleSize, '\0');
bitStream->ReadBits(reinterpret_cast<unsigned char*>(readTitle.data()), BYTES_TO_BITS(titleSize), true);
uint32_t messageSize;
bitStream->Read(messageSize);
ASSERT_EQ(messageSize, announcement.message.size());
std::string readMessage(messageSize, '\0');
bitStream->ReadBits(reinterpret_cast<unsigned char*>(readMessage.data()), BYTES_TO_BITS(messageSize), true);
ASSERT_EQ(readTitle, "Test Title");
ASSERT_EQ(readMessage, "Test announcement message");
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
}
TEST_F(ChatPacketTests, ChatAchievementNotifySerialization) {
ChatPackets::AchievementNotify notify;
notify.targetPlayerName = LUWString(u"TargetPlayer");
notify.missionEmailID = 12345;
notify.earningPlayerID = 987654321;
notify.earnerName = LUWString(u"EarnerPlayer");
// Call Send which will add header and serialize
notify.Send(UNASSIGNED_SYSTEM_ADDRESS);
auto* bitStream = GetMostRecentBitStream();
VerifyHeader(bitStream, ServiceType::CHAT, static_cast<uint32_t>(MessageType::Chat::ACHIEVEMENT_NOTIFY));
// Read achievement data based on actual Serialize implementation
// Order: packing(13), earnerName, packing(15), missionEmailID, earningPlayerID, targetPlayerName
uint64_t packing1;
uint32_t packing2;
uint8_t packing3;
LUWString readEarnerName;
uint64_t packing4;
uint32_t packing5;
uint16_t packing6;
uint8_t packing7;
uint32_t readMissionEmailID;
LWOOBJID readEarningPlayerID;
LUWString readTargetPlayerName;
bitStream->Read(packing1);
bitStream->Read(packing2);
bitStream->Read(packing3);
bitStream->Read(readEarnerName);
bitStream->Read(packing4);
bitStream->Read(packing5);
bitStream->Read(packing6);
bitStream->Read(packing7);
bitStream->Read(readMissionEmailID);
bitStream->Read(readEarningPlayerID);
bitStream->Read(readTargetPlayerName);
ASSERT_EQ(readEarnerName.string, u"EarnerPlayer");
ASSERT_EQ(readMissionEmailID, 12345u);
ASSERT_EQ(readEarningPlayerID, 987654321);
ASSERT_EQ(readTargetPlayerName.string, u"TargetPlayer");
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
}
TEST_F(ChatPacketTests, ChatTeamInviteInitialResponseSerialization) {
ChatPackets::TeamInviteInitialResponse response;
response.inviteFailedToSend = true;
response.playerName = LUWString(u"InviteePlayer");
// Call Send which will add header and serialize
response.Send(UNASSIGNED_SYSTEM_ADDRESS);
auto* bitStream = GetMostRecentBitStream();
VerifyHeader(bitStream, ServiceType::CLIENT, static_cast<uint32_t>(MessageType::Client::TEAM_INVITE_INITIAL_RESPONSE));
// Read team invite response data
uint8_t readInviteFailedToSend; // Written as uint8_t in actual implementation
LUWString readPlayerName;
bitStream->Read(readInviteFailedToSend);
bitStream->Read(readPlayerName);
ASSERT_EQ(readInviteFailedToSend, static_cast<uint8_t>(true));
ASSERT_EQ(readPlayerName.string, u"InviteePlayer");
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
}

View File

@@ -0,0 +1,269 @@
#include "TestCommon.h"
#include "MailInfo.h"
#include "dCommonVars.h"
class MailBitStreamTests : public PacketTestsBase {
protected:
void SetUp() override {
PacketTestsBase::SetUp();
}
void TearDown() override {
PacketTestsBase::TearDown();
}
/**
* Helper to create a sample MailInfo for testing
*/
MailInfo CreateSampleMailInfo() {
MailInfo mailInfo;
mailInfo.senderUsername = "TestSender";
mailInfo.recipient = "TestRecipient";
mailInfo.subject = "Test Subject";
mailInfo.body = "Test body message";
mailInfo.id = 12345;
mailInfo.senderId = 67890;
mailInfo.receiverId = 11111;
mailInfo.timeSent = 1234567890;
mailInfo.wasRead = false;
mailInfo.languageCode = 1033;
mailInfo.itemID = LWOOBJID_EMPTY;
mailInfo.itemCount = 0;
mailInfo.itemLOT = LOT_NULL;
mailInfo.itemSubkey = LWOOBJID_EMPTY;
return mailInfo;
}
};
// Test basic MailInfo serialization
TEST_F(MailBitStreamTests, MailInfoBasicSerialization) {
MailInfo originalMail = CreateSampleMailInfo();
RakNet::BitStream outStream;
originalMail.Serialize(outStream);
// Verify the serialized data structure - basic sanity check
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// MailInfo serialization includes id, subject, body, sender, and various item data
// Let's verify the first field (id) is written correctly
outStream.ResetReadPointer();
uint64_t readId;
outStream.Read(readId);
ASSERT_EQ(readId, originalMail.id);
}
// Test MailInfo serialization with item attachment
TEST_F(MailBitStreamTests, MailInfoWithAttachmentSerialization) {
MailInfo originalMail = CreateSampleMailInfo();
originalMail.itemID = 999888777;
originalMail.itemCount = 5;
originalMail.itemLOT = 1234;
originalMail.itemSubkey = 555444333;
RakNet::BitStream outStream;
originalMail.Serialize(outStream);
// Verify the serialized data includes all our data
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// Reset and verify id
outStream.ResetReadPointer();
uint64_t readId;
outStream.Read(readId);
ASSERT_EQ(readId, originalMail.id);
}
// Test MailInfo serialization with different attachment scenarios
TEST_F(MailBitStreamTests, MailInfoVariousAttachmentScenarios) {
// Test with no attachment
{
MailInfo noAttachment = CreateSampleMailInfo();
noAttachment.itemID = LWOOBJID_EMPTY;
noAttachment.itemCount = 0;
noAttachment.itemLOT = LOT_NULL;
noAttachment.itemSubkey = LWOOBJID_EMPTY;
RakNet::BitStream outStream;
noAttachment.Serialize(outStream);
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
outStream.ResetReadPointer();
uint64_t readId;
outStream.Read(readId);
ASSERT_EQ(readId, noAttachment.id);
}
// Test with attachment
{
MailInfo withAttachment = CreateSampleMailInfo();
withAttachment.itemID = 123456789;
withAttachment.itemCount = 5;
withAttachment.itemLOT = 9876;
withAttachment.itemSubkey = 555666777;
RakNet::BitStream outStream;
withAttachment.Serialize(outStream);
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
outStream.ResetReadPointer();
uint64_t readId;
outStream.Read(readId);
ASSERT_EQ(readId, withAttachment.id);
}
}
// Test MailInfo serialization consistency
TEST_F(MailBitStreamTests, MailInfoSerializationConsistency) {
MailInfo originalMail = CreateSampleMailInfo();
originalMail.itemID = 111222333;
originalMail.itemCount = 7;
originalMail.itemLOT = 5678;
originalMail.itemSubkey = 444555666;
// Serialize the same mail multiple times
RakNet::BitStream stream1, stream2, stream3;
originalMail.Serialize(stream1);
originalMail.Serialize(stream2);
originalMail.Serialize(stream3);
// All streams should have the same number of bytes
ASSERT_EQ(stream1.GetNumberOfBytesUsed(), stream2.GetNumberOfBytesUsed());
ASSERT_EQ(stream2.GetNumberOfBytesUsed(), stream3.GetNumberOfBytesUsed());
// And the same data content
std::vector<uint8_t> data1(stream1.GetNumberOfBytesUsed());
std::vector<uint8_t> data2(stream2.GetNumberOfBytesUsed());
std::vector<uint8_t> data3(stream3.GetNumberOfBytesUsed());
memcpy(data1.data(), stream1.GetData(), stream1.GetNumberOfBytesUsed());
memcpy(data2.data(), stream2.GetData(), stream2.GetNumberOfBytesUsed());
memcpy(data3.data(), stream3.GetData(), stream3.GetNumberOfBytesUsed());
ASSERT_EQ(data1, data2);
ASSERT_EQ(data2, data3);
}
// Test MailInfo with Unicode characters
TEST_F(MailBitStreamTests, MailInfoUnicodeHandling) {
MailInfo originalMail = CreateSampleMailInfo();
originalMail.subject = "テストメール"; // "Test Mail" in Japanese
originalMail.body = "これはテストメッセージです。"; // "This is a test message" in Japanese
originalMail.senderUsername = "プレイヤー1"; // "Player 1" in Japanese
RakNet::BitStream outStream;
originalMail.Serialize(outStream);
// Verify data was written
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// Since we can't easily deserialize (it doesn't read all fields),
// we just verify that Unicode content can be serialized without errors
outStream.ResetReadPointer();
uint64_t readId;
outStream.Read(readId);
ASSERT_EQ(readId, originalMail.id);
}
// Test MailInfo edge cases with special values
TEST_F(MailBitStreamTests, MailInfoEdgeCases) {
MailInfo originalMail = CreateSampleMailInfo();
// Test with special/edge case values
originalMail.id = 0; // Zero ID
originalMail.itemID = LWOOBJID_EMPTY; // Special empty value
originalMail.itemCount = -1; // Negative count
originalMail.itemLOT = LOT_NULL; // Null LOT
originalMail.timeSent = 0; // Zero time
RakNet::BitStream outStream;
originalMail.Serialize(outStream);
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// Verify the ID field
outStream.ResetReadPointer();
uint64_t readId;
outStream.Read(readId);
ASSERT_EQ(readId, 0);
}
// Test MailInfo with very long strings that get truncated
TEST_F(MailBitStreamTests, MailInfoStringTruncation) {
MailInfo originalMail = CreateSampleMailInfo();
// Create strings longer than the allowed maximums
originalMail.subject = std::string(100, 'S'); // Longer than 50 char limit
originalMail.body = std::string(500, 'B'); // Longer than 400 char limit
originalMail.senderUsername = std::string(50, 'U'); // Longer than 32 char limit
RakNet::BitStream outStream;
originalMail.Serialize(outStream);
// Should still serialize successfully (LUWString handles truncation)
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
outStream.ResetReadPointer();
uint64_t readId;
outStream.Read(readId);
ASSERT_EQ(readId, originalMail.id);
}
// Test MailInfo data integrity across field types
TEST_F(MailBitStreamTests, MailInfoDataTypeIntegrity) {
MailInfo originalMail = CreateSampleMailInfo();
// Test with specific values to verify data types are handled correctly
originalMail.id = 0xFFFFFFFFFFFFFFFF; // Max uint64_t
originalMail.senderId = 0xFFFFFFFF; // Max uint32_t
originalMail.receiverId = 0xFFFFFFFF; // Max uint32_t
originalMail.timeSent = 0xFFFFFFFFFFFFFFFF; // Max uint64_t
originalMail.wasRead = true;
originalMail.languageCode = 0xFFFF; // Max uint16_t
originalMail.itemID = 0xFFFFFFFFFFFFFFFF; // Max LWOOBJID
originalMail.itemCount = 32767; // Max int16_t positive value
originalMail.itemSubkey = 0xFFFFFFFFFFFFFFFF; // Max LWOOBJID
RakNet::BitStream outStream;
originalMail.Serialize(outStream);
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
// Verify the first field (id)
outStream.ResetReadPointer();
uint64_t readId;
outStream.Read(readId);
ASSERT_EQ(readId, 0xFFFFFFFFFFFFFFFF);
}
// Test MailInfo with empty/minimal data
TEST_F(MailBitStreamTests, MailInfoMinimalData) {
MailInfo minimalMail;
// Set only required/essential fields
minimalMail.id = 1;
minimalMail.subject = "";
minimalMail.body = "";
minimalMail.senderUsername = "";
minimalMail.recipient = "";
minimalMail.senderId = 0;
minimalMail.receiverId = 0;
minimalMail.timeSent = 0;
minimalMail.wasRead = false;
minimalMail.languageCode = 0;
minimalMail.itemID = 0;
minimalMail.itemCount = 0;
minimalMail.itemLOT = 0;
minimalMail.itemSubkey = 0;
RakNet::BitStream outStream;
minimalMail.Serialize(outStream);
ASSERT_GT(outStream.GetNumberOfBytesUsed(), 0);
outStream.ResetReadPointer();
uint64_t readId;
outStream.Read(readId);
ASSERT_EQ(readId, 1);
}

View File

@@ -0,0 +1,69 @@
#include "TestCommon.h"
#include "MasterPackets.h"
#include "MessageType/Master.h"
class MasterPacketTests : public PacketTestsBase {};
// ===== MasterPackets Tests =====
// Note: These tests verify packet structure creation, but cannot easily test SendToMaster
// since it's not virtual. We can test the structure by calling the internal serialization.
TEST_F(MasterPacketTests, MasterPersistentIDResponseStructure) {
uint64_t testRequestID = 9876543210987654321ULL;
uint32_t testObjID = 555555;
MasterPackets::SendPersistentIDResponse(Game::server, UNASSIGNED_SYSTEM_ADDRESS, testRequestID, testObjID);
auto* bitStream = GetMostRecentBitStream();
VerifyHeader(bitStream, ServiceType::MASTER, static_cast<uint32_t>(MessageType::Master::REQUEST_PERSISTENT_ID_RESPONSE));
uint64_t readRequestID;
uint32_t readObjID;
bitStream->Read(readRequestID);
bitStream->Read(readObjID);
ASSERT_EQ(readRequestID, testRequestID);
ASSERT_EQ(readObjID, testObjID);
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
}
TEST_F(MasterPacketTests, MasterZoneTransferResponseStructure) {
uint64_t testRequestID = 1111111111111111111ULL;
bool testMythranShift = true;
uint32_t testZoneID = 1000;
uint32_t testZoneInstance = 5;
uint32_t testZoneClone = 10;
std::string testServerIP = "192.168.1.100";
uint32_t testServerPort = 2002;
MasterPackets::SendZoneTransferResponse(Game::server, UNASSIGNED_SYSTEM_ADDRESS, testRequestID, testMythranShift, testZoneID, testZoneInstance, testZoneClone, testServerIP, testServerPort);
auto* bitStream = GetMostRecentBitStream();
VerifyHeader(bitStream, ServiceType::MASTER, static_cast<uint32_t>(MessageType::Master::REQUEST_ZONE_TRANSFER_RESPONSE));
uint64_t readRequestID;
uint8_t readMythranShift;
uint32_t readZoneID;
uint32_t readZoneInstance;
uint32_t readZoneClone;
uint16_t readServerPort; // Note: written as uint16_t in actual implementation
LUString readServerIP(255); // Note: written as LUString with size 255
bitStream->Read(readRequestID);
bitStream->Read(readMythranShift);
bitStream->Read(readZoneID);
bitStream->Read(readZoneInstance);
bitStream->Read(readZoneClone);
bitStream->Read(readServerPort);
bitStream->Read(readServerIP);
ASSERT_EQ(readRequestID, testRequestID);
ASSERT_EQ(readMythranShift, static_cast<uint8_t>(testMythranShift));
ASSERT_EQ(readZoneID, testZoneID);
ASSERT_EQ(readZoneInstance, testZoneInstance);
ASSERT_EQ(readZoneClone, testZoneClone);
ASSERT_EQ(readServerPort, static_cast<uint16_t>(testServerPort));
ASSERT_EQ(readServerIP.string, testServerIP);
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
}

View File

@@ -0,0 +1,154 @@
#include "TestCommon.h"
#include "AuthPackets.h"
#include "ChatPackets.h"
#include "WorldPackets.h"
class PacketEdgeCaseTests : public PacketTestsBase {};
// ===== Edge Cases and Boundary Tests =====
TEST_F(PacketEdgeCaseTests, EmptyStringsHandling) {
FindPlayerRequest request;
request.requestor = 0;
request.playerName = LUWString(u"");
RakNet::BitStream bitStream;
request.Serialize(bitStream);
// Skip header
uint8_t rakNetPacketId{};
uint16_t serviceType{};
uint32_t packetId{};
uint8_t always0{};
bitStream.Read(rakNetPacketId);
bitStream.Read(serviceType);
bitStream.Read(packetId);
bitStream.Read(always0);
FindPlayerRequest deserialized;
deserialized.Deserialize(bitStream);
ASSERT_EQ(deserialized.requestor, 0);
ASSERT_EQ(deserialized.playerName.string, u"");
}
TEST_F(PacketEdgeCaseTests, MaxValueHandling) {
// Test with maximum values
ShowAllRequest request;
request.requestor = LWOOBJID_EMPTY; // Max LWOOBJID
request.displayZoneData = true;
request.displayIndividualPlayers = true;
RakNet::BitStream bitStream;
request.Serialize(bitStream);
// Skip header
uint8_t rakNetPacketId{};
uint16_t serviceType{};
uint32_t packetId{};
uint8_t always0{};
bitStream.Read(rakNetPacketId);
bitStream.Read(serviceType);
bitStream.Read(packetId);
bitStream.Read(always0);
ShowAllRequest deserialized;
deserialized.Deserialize(bitStream);
ASSERT_EQ(deserialized.requestor, LWOOBJID_EMPTY);
ASSERT_EQ(deserialized.displayZoneData, true);
ASSERT_EQ(deserialized.displayIndividualPlayers, true);
}
TEST_F(PacketEdgeCaseTests, LongPasswordHandling) {
// Test with a very long password for HTTPMonitorInfo (which has port field)
HTTPMonitorInfo info;
info.port = 65535; // Max port value
info.openWeb = true;
info.supportsSum = true;
info.supportsDetail = true;
info.supportsWho = true;
info.supportsObjects = true;
RakNet::BitStream bitStream;
info.Serialize(bitStream);
// Read serialized data
uint16_t readPort;
uint8_t readOpenWeb;
uint8_t readSupportsSum;
uint8_t readSupportsDetail;
uint8_t readSupportsWho;
uint8_t readSupportsObjects;
bitStream.Read(readPort);
bitStream.Read(readOpenWeb);
bitStream.Read(readSupportsSum);
bitStream.Read(readSupportsDetail);
bitStream.Read(readSupportsWho);
bitStream.Read(readSupportsObjects);
ASSERT_EQ(readPort, 65535);
ASSERT_EQ(readOpenWeb, 1);
ASSERT_EQ(readSupportsSum, 1);
ASSERT_EQ(readSupportsDetail, 1);
ASSERT_EQ(readSupportsWho, 1);
ASSERT_EQ(readSupportsObjects, 1);
ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 0);
}
TEST_F(PacketEdgeCaseTests, PacketDataConsistency) {
// Test that multiple calls produce identical results
Stamp stamp1(eStamps::PASSPORT_AUTH_START, 100, 2000000000);
Stamp stamp2(eStamps::PASSPORT_AUTH_START, 100, 2000000000);
RakNet::BitStream stream1, stream2;
stamp1.Serialize(stream1);
stamp2.Serialize(stream2);
// Should produce identical bit streams
ASSERT_EQ(stream1.GetNumberOfBitsUsed(), stream2.GetNumberOfBitsUsed());
// Read both streams and compare
eStamps type1, type2;
uint32_t value1, value2;
uint64_t timestamp1, timestamp2;
stream1.Read(type1);
stream1.Read(value1);
stream1.Read(timestamp1);
stream2.Read(type2);
stream2.Read(value2);
stream2.Read(timestamp2);
ASSERT_EQ(type1, type2);
ASSERT_EQ(value1, value2);
ASSERT_EQ(timestamp1, timestamp2);
}
TEST_F(PacketEdgeCaseTests, UnicodeStringHandling) {
// Test with various Unicode characters
FindPlayerRequest request;
request.requestor = 12345;
request.playerName = LUWString(u"テストプレイヤー123"); // Japanese characters
RakNet::BitStream bitStream;
request.Serialize(bitStream);
// Skip header
uint8_t rakNetPacketId{};
uint16_t serviceType{};
uint32_t packetId{};
uint8_t always0{};
bitStream.Read(rakNetPacketId);
bitStream.Read(serviceType);
bitStream.Read(packetId);
bitStream.Read(always0);
FindPlayerRequest deserialized;
deserialized.Deserialize(bitStream);
ASSERT_EQ(deserialized.requestor, request.requestor);
ASSERT_EQ(deserialized.playerName.string, request.playerName.string);
}

View File

@@ -0,0 +1,17 @@
#include "TestCommon.h"
// Define Game namespace globals needed for linking
namespace Game {
Logger* logger = nullptr;
dServer* server = nullptr;
dZoneManager* zoneManager = nullptr;
dChatFilter* chatFilter = nullptr;
dConfig* config = nullptr;
std::mt19937 randomEngine;
RakPeerInterface* chatServer = nullptr;
AssetManager* assetManager = nullptr;
SystemAddress chatSysAddr;
EntityManager* entityManager = nullptr;
std::string projectVersion;
signal_t lastSignal = 0;
}

View File

@@ -0,0 +1,101 @@
#pragma once
#include <gtest/gtest.h>
#include <memory>
#include "BitStream.h"
#include "dCommonVars.h"
#include "RakNetTypes.h"
#include "BitStreamUtils.h"
#include "ServiceType.h"
// Game dependencies for mocking
#include "Game.h"
#include "dServer.h"
// Forward declarations to minimize dependencies
class Logger;
class dConfig;
class AssetManager;
class dZoneManager;
class dChatFilter;
class EntityManager;
// Define Game namespace globals needed for linking
namespace Game {
extern Logger* logger;
extern dServer* server;
extern dZoneManager* zoneManager;
extern dChatFilter* chatFilter;
extern dConfig* config;
extern std::mt19937 randomEngine;
extern RakPeerInterface* chatServer;
extern AssetManager* assetManager;
extern SystemAddress chatSysAddr;
extern EntityManager* entityManager;
extern std::string projectVersion;
extern signal_t lastSignal;
}
// Simple mock server that captures bit streams for testing
class dServerMock : public dServer {
public:
dServerMock() {}
RakNet::BitStream* GetMostRecentBitStream() {
return this->m_MostRecentBitStream.get();
}
void Send(RakNet::BitStream& bitStream, const SystemAddress& sysAddr, bool broadcast) override {
this->m_MostRecentBitStream = std::make_unique<RakNet::BitStream>();
*this->m_MostRecentBitStream = bitStream;
}
private:
std::unique_ptr<RakNet::BitStream> m_MostRecentBitStream = nullptr;
};
class PacketTestsBase : public ::testing::Test {
protected:
void SetUp() override {
// Set up a minimal mock server for testing
Game::server = new dServerMock();
}
void TearDown() override {
if (Game::server) {
delete Game::server;
Game::server = nullptr;
}
}
/**
* Helper to get the most recent bit stream from the mock server
*/
RakNet::BitStream* GetMostRecentBitStream() {
auto* server = static_cast<dServerMock*>(Game::server);
return server->GetMostRecentBitStream();
}
/**
* Helper to verify packet header
*/
void VerifyHeader(RakNet::BitStream* bitStream, ServiceType expectedServiceType, uint32_t expectedPacketId) {
ASSERT_NE(bitStream, nullptr);
uint8_t rakNetPacketId{};
uint16_t serviceType{};
uint32_t packetId{};
uint8_t always0{};
bitStream->Read(rakNetPacketId);
bitStream->Read(serviceType);
bitStream->Read(packetId);
bitStream->Read(always0);
ASSERT_EQ(rakNetPacketId, 0x53); // ID_USER_PACKET_ENUM
ASSERT_EQ(serviceType, static_cast<uint16_t>(expectedServiceType));
ASSERT_EQ(packetId, expectedPacketId);
ASSERT_EQ(always0, 0x00);
}
};

View File

@@ -0,0 +1,110 @@
#include "TestCommon.h"
#include "WorldPackets.h"
#include "MessageType/Client.h"
#include "eRenameResponse.h"
class WorldPacketTests : public PacketTestsBase {};
// ===== WorldPackets Tests =====
TEST_F(WorldPacketTests, WorldHTTPMonitorInfoSerialization) {
HTTPMonitorInfo info;
info.port = 8080;
info.openWeb = true;
info.supportsSum = false;
info.supportsDetail = true;
info.supportsWho = false;
info.supportsObjects = true;
RakNet::BitStream bitStream;
info.Serialize(bitStream);
// Read serialized data
uint16_t readPort;
uint8_t readOpenWeb;
uint8_t readSupportsSum;
uint8_t readSupportsDetail;
uint8_t readSupportsWho;
uint8_t readSupportsObjects;
bitStream.Read(readPort);
bitStream.Read(readOpenWeb);
bitStream.Read(readSupportsSum);
bitStream.Read(readSupportsDetail);
bitStream.Read(readSupportsWho);
bitStream.Read(readSupportsObjects);
ASSERT_EQ(readPort, 8080);
ASSERT_EQ(readOpenWeb, 1);
ASSERT_EQ(readSupportsSum, 0);
ASSERT_EQ(readSupportsDetail, 1);
ASSERT_EQ(readSupportsWho, 0);
ASSERT_EQ(readSupportsObjects, 1);
ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 0);
}
TEST_F(WorldPacketTests, WorldCharacterDeleteResponse) {
bool testResponse = false;
WorldPackets::SendCharacterDeleteResponse(UNASSIGNED_SYSTEM_ADDRESS, testResponse);
auto* bitStream = GetMostRecentBitStream();
VerifyHeader(bitStream, ServiceType::CLIENT, static_cast<uint32_t>(MessageType::Client::DELETE_CHARACTER_RESPONSE));
uint8_t readResponse;
bitStream->Read(readResponse);
ASSERT_EQ(readResponse, static_cast<uint8_t>(testResponse));
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
}
TEST_F(WorldPacketTests, WorldCharacterRenameResponse) {
// Test with different enum values for character rename response
WorldPackets::SendCharacterRenameResponse(UNASSIGNED_SYSTEM_ADDRESS, eRenameResponse::NAME_IN_USE);
auto* bitStream = GetMostRecentBitStream();
VerifyHeader(bitStream, ServiceType::CLIENT, static_cast<uint32_t>(MessageType::Client::CHARACTER_RENAME_RESPONSE));
uint8_t readResponse;
bitStream->Read(readResponse);
ASSERT_EQ(readResponse, static_cast<uint8_t>(eRenameResponse::NAME_IN_USE));
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
}
TEST_F(WorldPacketTests, WorldTransferToWorld) {
std::string testServerIP = "10.0.0.1";
uint32_t testServerPort = 3000;
bool testMythranShift = false;
WorldPackets::SendTransferToWorld(UNASSIGNED_SYSTEM_ADDRESS, testServerIP, testServerPort, testMythranShift);
auto* bitStream = GetMostRecentBitStream();
VerifyHeader(bitStream, ServiceType::CLIENT, static_cast<uint32_t>(MessageType::Client::TRANSFER_TO_WORLD));
LUString readServerIP;
uint16_t readServerPort;
uint8_t readMythranShift;
bitStream->Read(readServerIP);
bitStream->Read(readServerPort);
bitStream->Read(readMythranShift);
ASSERT_EQ(readServerIP.string, testServerIP);
ASSERT_EQ(readServerPort, static_cast<uint16_t>(testServerPort));
ASSERT_EQ(readMythranShift, static_cast<uint8_t>(testMythranShift));
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
}
TEST_F(WorldPacketTests, WorldServerState) {
WorldPackets::SendServerState(UNASSIGNED_SYSTEM_ADDRESS);
auto* bitStream = GetMostRecentBitStream();
VerifyHeader(bitStream, ServiceType::CLIENT, static_cast<uint32_t>(MessageType::Client::SERVER_STATES));
uint8_t readState;
bitStream->Read(readState);
ASSERT_EQ(readState, 1); // Server is ready
ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0);
}