DarkflameServer/tests/dCommonTests/AMFDeserializeTests.cpp

439 lines
12 KiB
C++
Raw Normal View History

#include <fstream>
#include <memory>
#include <gtest/gtest.h>
#include "AMFDeserialize.h"
#include "Amf3.h"
#include "Game.h"
#include "Logger.h"
/**
* Helper method that all tests use to get their respective AMF.
*/
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> ReadFromBitStream(RakNet::BitStream& bitStream) {
AMFDeserialize deserializer;
return deserializer.Read(bitStream);
}
/**
* @brief Test reading an AMFUndefined value from a BitStream.
*/
TEST(dCommonTests, AMFDeserializeAMFUndefinedTest) {
CBITSTREAM;
2022-08-05 13:40:12 +00:00
bitStream.Write<uint8_t>(0x00);
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::Undefined);
}
/**
* @brief Test reading an AMFNull value from a BitStream.
*
*/
TEST(dCommonTests, AMFDeserializeAMFNullTest) {
CBITSTREAM;
2022-08-05 13:40:12 +00:00
bitStream.Write<uint8_t>(0x01);
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::Null);
}
/**
* @brief Test reading an AMFFalse value from a BitStream.
*/
TEST(dCommonTests, AMFDeserializeAMFFalseTest) {
CBITSTREAM;
2022-08-05 13:40:12 +00:00
bitStream.Write<uint8_t>(0x02);
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::False);
}
/**
* @brief Test reading an AMFTrue value from a BitStream.
*/
TEST(dCommonTests, AMFDeserializeAMFTrueTest) {
CBITSTREAM;
2022-08-05 13:40:12 +00:00
bitStream.Write<uint8_t>(0x03);
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::True);
}
/**
* @brief Test reading an AMFInteger value from a BitStream.
*/
TEST(dCommonTests, AMFDeserializeAMFIntegerTest) {
CBITSTREAM;
{
bitStream.Write<uint8_t>(0x04);
2022-08-05 13:40:12 +00:00
// 127 == 01111111
bitStream.Write<uint8_t>(127);
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::Integer);
2022-08-05 13:40:12 +00:00
// Check that the max value of a byte can be read correctly
ASSERT_EQ(static_cast<AMFIntValue*>(res.get())->GetValue(), 127);
}
bitStream.Reset();
{
bitStream.Write<uint8_t>(0x04);
bitStream.Write<uint32_t>(UINT32_MAX);
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::Integer);
// Check that we can read the maximum value correctly
ASSERT_EQ(static_cast<AMFIntValue*>(res.get())->GetValue(), 536870911);
}
bitStream.Reset();
{
bitStream.Write<uint8_t>(0x04);
// 131 == 10000011
bitStream.Write<uint8_t>(131);
// 255 == 11111111
bitStream.Write<uint8_t>(255);
// 127 == 01111111
bitStream.Write<uint8_t>(127);
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::Integer);
// Check that short max can be read correctly
ASSERT_EQ(static_cast<AMFIntValue*>(res.get())->GetValue(), UINT16_MAX);
}
bitStream.Reset();
{
bitStream.Write<uint8_t>(0x04);
// 255 == 11111111
bitStream.Write<uint8_t>(255);
// 127 == 01111111
bitStream.Write<uint8_t>(127);
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::Integer);
// Check that 2 byte max can be read correctly
ASSERT_EQ(static_cast<AMFIntValue*>(res.get())->GetValue(), 16383);
}
}
/**
* @brief Test reading an AMFDouble value from a BitStream.
*/
TEST(dCommonTests, AMFDeserializeAMFDoubleTest) {
CBITSTREAM;
2022-08-05 13:40:12 +00:00
bitStream.Write<uint8_t>(0x05);
bitStream.Write<double>(25346.4f);
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::Double);
ASSERT_EQ(static_cast<AMFDoubleValue*>(res.get())->GetValue(), 25346.4f);
}
/**
* @brief Test reading an AMFString value from a BitStream.
*/
TEST(dCommonTests, AMFDeserializeAMFStringTest) {
CBITSTREAM;
2022-08-05 13:40:12 +00:00
bitStream.Write<uint8_t>(0x06);
bitStream.Write<uint8_t>(0x0F);
std::string toWrite = "stateID";
for (auto e : toWrite) bitStream.Write<char>(e);
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::String);
ASSERT_EQ(static_cast<AMFStringValue*>(res.get())->GetValue(), "stateID");
}
/**
* @brief Test reading an AMFArray value from a BitStream.
*/
TEST(dCommonTests, AMFDeserializeAMFArrayTest) {
CBITSTREAM;
2022-08-05 13:40:12 +00:00
// Test empty AMFArray
bitStream.Write<uint8_t>(0x09);
bitStream.Write<uint8_t>(0x01);
bitStream.Write<uint8_t>(0x01);
{
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::Array);
ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetAssociative().size(), 0);
ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetDense().size(), 0);
}
bitStream.Reset();
// Test a key'd value and dense value
bitStream.Write<uint8_t>(0x09);
bitStream.Write<uint8_t>(0x03);
bitStream.Write<uint8_t>(0x15);
for (auto e : "BehaviorID") if (e != '\0') bitStream.Write<char>(e);
bitStream.Write<uint8_t>(0x06);
bitStream.Write<uint8_t>(0x0B);
for (auto e : "10447") if (e != '\0') bitStream.Write<char>(e);
bitStream.Write<uint8_t>(0x01);
bitStream.Write<uint8_t>(0x06);
bitStream.Write<uint8_t>(0x0B);
for (auto e : "10447") if (e != '\0') bitStream.Write<char>(e);
{
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) };
ASSERT_EQ(res->GetValueType(), eAmf::Array);
ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetAssociative().size(), 1);
ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetDense().size(), 1);
ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->Get<std::string>("BehaviorID")->GetValue(), "10447");
ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->Get<std::string>(0)->GetValue(), "10447");
}
}
/**
* @brief This test checks that if we recieve an unimplemented eAmf
* we correctly throw an error and can actch it.
feat: Make use of CMake presets to enable easy switching between debug and release configurations on all platforms (#1439) * Add MSVC optimization flags * test moving flags to json * Update CMakePresets.json * testing * trying more variations on the flags * third test * testing if these even have any effect * ditto * final(?) try for now * ONE MORE TIME * trying 'init' flags instead * export the compile commands so I can see if they're having any effect * move out g++ O2 flag * add Linux debug preset * update CMake presets * edit macos presets * try adding build types back to mac * macos refuses to work :( * try using compiler flags for mac instead * fix typo in windows preset * build reorganization and experimental clang support * temporarily remove macos build for testing purposes * updated cmake workflows * unexclude toolchain dir * update .gitignore * fix build directory issue * edit build script * update cmake configs * attempted docker fix * try zero-initializinng this struct to solve docker issue * try fixing macos build * one last MacOS try for the night * try disabling an apple-specific build rule * more fiddling with mac test builds * try and narrow down the macos build failure cause * try stripping out all the custom macos test logic again * I'm really just throwing everything to the wall and seeing what sticks * more macos tinkering * implib * try manual link directory specification * save me * aaaaaaaaa * paths paths paths * Revert "paths paths paths" This reverts commit 9a7d86aa6c59e73de27fbcda2111f7a1472008f4. * Revert "aaaaaaaaa" This reverts commit 338279c396e7c4a78174929a0aaf5205f2c026e6. * Revert "save me" This reverts commit bd73aa21a9cd1625f7cf567ab5b56bde46c0af0e. * Revert "try manual link directory specification" This reverts commit 0c2d40632ee5df9c241532d8bf62de9969e47f51. * Revert "implib" This reverts commit d41349d6edada6a041c64971730eed1c51af14c5. * Revert "more macos tinkering" This reverts commit 829ec35b57983ad4444d90ab780fff95a8b47608. * Revert "I'm really just throwing everything to the wall and seeing what sticks" This reverts commit 1a05b027fe822a94e5a6b70e6c744623d6a98e61. * Revert "try stripping out all the custom macos test logic again" This reverts commit cc15a26ce80ff9cfec5f1a94b0c00c42e1832c55. * Revert "try and narrow down the macos build failure cause" This reverts commit 5fd86833fa6e421860496c3626415ab70c93a795. * Revert "more fiddling with mac test builds" This reverts commit 0f843c02c90b2aa5f0c211e19c47b00798c295c8. * Revert "try disabling an apple-specific build rule" This reverts commit 45ec66e97605e3ea5b0a76f6eed0ec6f955c1675. * back to debug messages * see if this re-breaks mac * are these messages actually somehow fixing the issue? * was not actually fixed * add debug messages (again) * debug try 2 * change runtime output dir * rename gcc to gnu * expand cmake presets * fix preset * change defaults * altered cmake configuration scripts * disable /WX on MSVC * update github actions * update build presets * change gnu and clang build directories to enable consistent artifact generation * add RelWithDebInfo presets and move -Werror flag into presets.json * use DLU_CONFIG_DIR envvar * CMakePresets indentation * temp fix for MSVC debug builds
2024-11-18 01:03:54 +00:00
* Yes this leaks memory.
*/
TEST(dCommonTests, AMFDeserializeUnimplementedValuesTest) {
std::vector<eAmf> unimplementedValues = {
eAmf::XMLDoc,
eAmf::Date,
eAmf::Object,
eAmf::XML,
eAmf::ByteArray,
eAmf::VectorInt,
eAmf::VectorUInt,
eAmf::VectorDouble,
eAmf::VectorObject,
eAmf::Dictionary
2022-07-28 13:39:57 +00:00
};
// Run unimplemented tests to check that errors are thrown if
// unimplemented AMF values are attempted to be parsed.
std::ifstream fileStream;
fileStream.open("AMFBitStreamUnimplementedTest.bin", std::ios::binary);
// Read a test BitStream from a file
std::vector<char> baseBitStream;
char byte = 0;
while (fileStream.get(byte)) {
baseBitStream.push_back(byte);
}
fileStream.close();
for (auto value : unimplementedValues) {
RakNet::BitStream testBitStream;
for (auto element : baseBitStream) {
testBitStream.Write(element);
}
testBitStream.Write(value);
bool caughtException = false;
try {
ReadFromBitStream(testBitStream);
} catch (eAmf unimplementedValueType) {
caughtException = true;
}
ASSERT_EQ(caughtException, true);
}
}
/**
* @brief Test reading a packet capture from live from a BitStream
*/
TEST(dCommonTests, AMFDeserializeLivePacketTest) {
std::ifstream testFileStream;
testFileStream.open("AMFBitStreamTest.bin", std::ios::binary);
// Read a test BitStream from a file
RakNet::BitStream testBitStream;
char byte = 0;
while (testFileStream.get(byte)) {
testBitStream.Write<char>(byte);
}
testFileStream.close();
2024-02-27 07:29:51 +00:00
std::unique_ptr<AMFBaseValue> resultFromFn{ ReadFromBitStream(testBitStream) };
auto* result = static_cast<AMFArrayValue*>(resultFromFn.get());
// Test the outermost array
ASSERT_EQ(result->Get<std::string>("BehaviorID")->GetValue(), "10447");
ASSERT_EQ(result->Get<std::string>("objectID")->GetValue(), "288300744895913279");
// Test the execution state array
2024-02-27 07:29:51 +00:00
auto* executionState = result->GetArray("executionState");
ASSERT_NE(executionState, nullptr);
2024-02-27 07:29:51 +00:00
auto& strips = executionState->GetArray("strips")->GetDense();
ASSERT_EQ(strips.size(), 1);
auto* stripsPosition0 = dynamic_cast<AMFArrayValue*>(strips[0].get());
2024-02-27 07:29:51 +00:00
auto* actionIndex = stripsPosition0->Get<double>("actionIndex");
ASSERT_EQ(actionIndex->GetValue(), 0.0f);
2024-02-27 07:29:51 +00:00
auto* stripIdExecution = stripsPosition0->Get<double>("id");
ASSERT_EQ(stripIdExecution->GetValue(), 0.0f);
2024-02-27 07:29:51 +00:00
auto* stateIdExecution = executionState->Get<double>("stateID");
ASSERT_EQ(stateIdExecution->GetValue(), 0.0f);
2024-02-27 07:29:51 +00:00
auto& states = result->GetArray("states")->GetDense();
ASSERT_EQ(states.size(), 1);
auto* firstState = dynamic_cast<AMFArrayValue*>(states[0].get());
2024-02-27 07:29:51 +00:00
auto* stateID = firstState->Get<double>("id");
ASSERT_EQ(stateID->GetValue(), 0.0f);
2024-02-27 07:29:51 +00:00
auto& stripsInState = firstState->GetArray("strips")->GetDense();
ASSERT_EQ(stripsInState.size(), 1);
auto* firstStrip = dynamic_cast<AMFArrayValue*>(stripsInState[0].get());
2024-02-27 07:29:51 +00:00
auto& actionsInFirstStrip = firstStrip->GetArray("actions")->GetDense();
ASSERT_EQ(actionsInFirstStrip.size(), 3);
2024-02-27 07:29:51 +00:00
auto* actionID = firstStrip->Get<double>("id");
ASSERT_EQ(actionID->GetValue(), 0.0f);
2024-02-27 07:29:51 +00:00
auto* uiArray = firstStrip->GetArray("ui");
2024-02-27 07:29:51 +00:00
auto* xPos = uiArray->Get<double>("x");
auto* yPos = uiArray->Get<double>("y");
ASSERT_EQ(xPos->GetValue(), 103.0f);
ASSERT_EQ(yPos->GetValue(), 82.0f);
2024-02-27 07:29:51 +00:00
auto* stripId = firstStrip->Get<double>("id");
ASSERT_EQ(stripId->GetValue(), 0.0f);
auto* firstAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[0].get());
2024-02-27 07:29:51 +00:00
auto* firstType = firstAction->Get<std::string>("Type");
ASSERT_EQ(firstType->GetValue(), "OnInteract");
2024-02-27 07:29:51 +00:00
auto* firstCallback = firstAction->Get<std::string>("__callbackID__");
ASSERT_EQ(firstCallback->GetValue(), "");
auto* secondAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[1].get());
2024-02-27 07:29:51 +00:00
auto* secondType = secondAction->Get<std::string>("Type");
ASSERT_EQ(secondType->GetValue(), "FlyUp");
2024-02-27 07:29:51 +00:00
auto* secondCallback = secondAction->Get<std::string>("__callbackID__");
ASSERT_EQ(secondCallback->GetValue(), "");
2024-02-27 07:29:51 +00:00
auto* secondDistance = secondAction->Get<double>("Distance");
ASSERT_EQ(secondDistance->GetValue(), 25.0f);
auto* thirdAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[2].get());
2024-02-27 07:29:51 +00:00
auto* thirdType = thirdAction->Get<std::string>("Type");
ASSERT_EQ(thirdType->GetValue(), "FlyDown");
2024-02-27 07:29:51 +00:00
auto* thirdCallback = thirdAction->Get<std::string>("__callbackID__");
ASSERT_EQ(thirdCallback->GetValue(), "");
2024-02-27 07:29:51 +00:00
auto* thirdDistance = thirdAction->Get<double>("Distance");
ASSERT_EQ(thirdDistance->GetValue(), 25.0f);
}
TEST(dCommonTests, AMFBadConversionTest) {
std::ifstream testFileStream;
testFileStream.open("AMFBitStreamTest.bin", std::ios::binary);
// Read a test BitStream from a file
RakNet::BitStream testBitStream;
char byte = 0;
while (testFileStream.get(byte)) {
testBitStream.Write<char>(byte);
}
testFileStream.close();
std::unique_ptr<AMFBaseValue> resultFromFn(ReadFromBitStream(testBitStream));
auto result = static_cast<AMFArrayValue*>(resultFromFn.get());
// Actually a string value.
ASSERT_EQ(result->Get<double>("BehaviorID"), nullptr);
// Does not exist in the associative portion
feat: Make use of CMake presets to enable easy switching between debug and release configurations on all platforms (#1439) * Add MSVC optimization flags * test moving flags to json * Update CMakePresets.json * testing * trying more variations on the flags * third test * testing if these even have any effect * ditto * final(?) try for now * ONE MORE TIME * trying 'init' flags instead * export the compile commands so I can see if they're having any effect * move out g++ O2 flag * add Linux debug preset * update CMake presets * edit macos presets * try adding build types back to mac * macos refuses to work :( * try using compiler flags for mac instead * fix typo in windows preset * build reorganization and experimental clang support * temporarily remove macos build for testing purposes * updated cmake workflows * unexclude toolchain dir * update .gitignore * fix build directory issue * edit build script * update cmake configs * attempted docker fix * try zero-initializinng this struct to solve docker issue * try fixing macos build * one last MacOS try for the night * try disabling an apple-specific build rule * more fiddling with mac test builds * try and narrow down the macos build failure cause * try stripping out all the custom macos test logic again * I'm really just throwing everything to the wall and seeing what sticks * more macos tinkering * implib * try manual link directory specification * save me * aaaaaaaaa * paths paths paths * Revert "paths paths paths" This reverts commit 9a7d86aa6c59e73de27fbcda2111f7a1472008f4. * Revert "aaaaaaaaa" This reverts commit 338279c396e7c4a78174929a0aaf5205f2c026e6. * Revert "save me" This reverts commit bd73aa21a9cd1625f7cf567ab5b56bde46c0af0e. * Revert "try manual link directory specification" This reverts commit 0c2d40632ee5df9c241532d8bf62de9969e47f51. * Revert "implib" This reverts commit d41349d6edada6a041c64971730eed1c51af14c5. * Revert "more macos tinkering" This reverts commit 829ec35b57983ad4444d90ab780fff95a8b47608. * Revert "I'm really just throwing everything to the wall and seeing what sticks" This reverts commit 1a05b027fe822a94e5a6b70e6c744623d6a98e61. * Revert "try stripping out all the custom macos test logic again" This reverts commit cc15a26ce80ff9cfec5f1a94b0c00c42e1832c55. * Revert "try and narrow down the macos build failure cause" This reverts commit 5fd86833fa6e421860496c3626415ab70c93a795. * Revert "more fiddling with mac test builds" This reverts commit 0f843c02c90b2aa5f0c211e19c47b00798c295c8. * Revert "try disabling an apple-specific build rule" This reverts commit 45ec66e97605e3ea5b0a76f6eed0ec6f955c1675. * back to debug messages * see if this re-breaks mac * are these messages actually somehow fixing the issue? * was not actually fixed * add debug messages (again) * debug try 2 * change runtime output dir * rename gcc to gnu * expand cmake presets * fix preset * change defaults * altered cmake configuration scripts * disable /WX on MSVC * update github actions * update build presets * change gnu and clang build directories to enable consistent artifact generation * add RelWithDebInfo presets and move -Werror flag into presets.json * use DLU_CONFIG_DIR envvar * CMakePresets indentation * temp fix for MSVC debug builds
2024-11-18 01:03:54 +00:00
ASSERT_EQ(result->Get<std::nullptr_t>("DOES_NOT_EXIST"), nullptr);
result->Push(true);
// Exists and is correct type
ASSERT_NE(result->Get<bool>(0), nullptr);
// Value exists but is wrong typing
ASSERT_EQ(result->Get<std::string>(0), nullptr);
// Value is out of bounds
ASSERT_EQ(result->Get<bool>(1), nullptr);
}
/**
2022-07-28 13:39:57 +00:00
* Below is the AMF that is in the AMFBitStreamTest.bin file that we are reading in
* from a bitstream to test.
args: amf3!
{
"objectID": "288300744895913279",
"BehaviorID": "10447",
2022-07-28 13:39:57 +00:00
"executionState": amf3!
{
2022-07-28 13:39:57 +00:00
"strips": amf3!
[
2022-07-28 13:39:57 +00:00
amf3!
{
"actionIndex": 0.0,
"id": 0.0,
},
],
"stateID": 0.0,
},
"states": amf3!
[
amf3!
{
"id": 0.0,
"strips": amf3!
[
amf3!
{
"actions": amf3!
[
amf3!
{
"Type": "OnInteract",
"__callbackID__": "",
},
amf3!
{
"Distance": 25.0,
"Type": "FlyUp",
"__callbackID__": "",
},
amf3!
{
"Distance": 25.0,
"Type": "FlyDown",
"__callbackID__": "",
},
],
"id": 0.0,
"ui": amf3!
{
"x": 103.0,
"y": 82.0,
},
},
],
},
],
}
*/