mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
test(capture): fixtures check client game messages, with a synthetic fixture
The fixture check now also reads every recorded client game message with the struct the server reads it with (GameMessageHandler::CreateReceived) and writes it again: it must read the whole message and give back the same bits. Game message fields are decoded with the server's structs in the fixture tests. A synthetic fixture, built in the test from the server's own structs (login, position update, a client game message), goes through the export steps (portable, anonymised, saved, read again) and passes the same checks; recorded fixtures stay in tests/fixtures-local and are never committed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "GameMessages.h"
|
||||
#include "GameMessageHandler.h"
|
||||
#include "ActivityMessages.h"
|
||||
#include "InventoryMessages.h"
|
||||
#include "ObjectMessages.h"
|
||||
@@ -94,4 +95,24 @@ namespace GameMessageDecoder {
|
||||
if (it == Decoders().end()) return std::nullopt;
|
||||
return it->second(payload);
|
||||
}
|
||||
|
||||
std::optional<bool> RoundTripReceived(MessageType::Game messageId, RakNet::BitStream& payload) {
|
||||
auto message = GameMessageHandler::CreateReceived(messageId);
|
||||
if (!message) return std::nullopt;
|
||||
const auto start = payload.GetReadOffset();
|
||||
if (!message->Deserialize(payload)) return std::nullopt;
|
||||
const auto read = payload.GetReadOffset() - start;
|
||||
// A whole byte or more left over: the struct stopped short of fields the message has
|
||||
if (payload.GetNumberOfUnreadBits() >= 8) return false;
|
||||
RakNet::BitStream written;
|
||||
message->Serialize(written);
|
||||
if (written.GetNumberOfBitsUsed() != read) return false;
|
||||
// The bits read, compared with the bits written
|
||||
payload.SetReadOffset(start);
|
||||
for (uint32_t bit = 0; bit < read; bit++) {
|
||||
bool original{}, again{};
|
||||
if (!payload.Read(original) || !written.Read(again) || original != again) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,13 @@ namespace GameMessageDecoder {
|
||||
// The message's fields, read from `payload` (the bits after the object ID and message ID), or nullopt when it has
|
||||
// no typed struct or doesn't read cleanly
|
||||
std::optional<nlohmann::json> Decode(MessageType::Game messageId, bool toServer, RakNet::BitStream& payload);
|
||||
|
||||
/**
|
||||
* Reads a message a client sent with the struct the server reads it with, and writes it again. nullopt when the
|
||||
* server has no typed struct for it or it doesn't read; otherwise whether it read the whole message (padding
|
||||
* after the last field aside) and the same bits came back. The capture fixture tests run it on every recorded client message.
|
||||
*/
|
||||
std::optional<bool> RoundTripReceived(MessageType::Game messageId, RakNet::BitStream& payload);
|
||||
}
|
||||
|
||||
#endif //!__GAMEMESSAGEDECODER__H__
|
||||
|
||||
@@ -269,3 +269,8 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
|
||||
|
||||
LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());
|
||||
}
|
||||
|
||||
std::unique_ptr<GameMessages::NetGameMsg> GameMessageHandler::CreateReceived(MessageType::Game messageID) {
|
||||
const auto handler = g_MessageHandlers.find(messageID);
|
||||
return handler == g_MessageHandlers.end() ? nullptr : handler->second();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
|
||||
namespace GameMessageHandler {
|
||||
void HandleMessage(RakNet::BitStream& inStream, const SystemAddress& sysAddr, LWOOBJID objectID, MessageType::Game messageID);
|
||||
|
||||
// A new, empty typed struct for a message a client sends, or nullptr when the server reads it inline (capture
|
||||
// fixtures read recorded messages with it)
|
||||
std::unique_ptr<GameMessages::NetGameMsg> CreateReceived(MessageType::Game messageID);
|
||||
};
|
||||
|
||||
#endif // GAMEMESSAGEHANDLER_H
|
||||
|
||||
Reference in New Issue
Block a user