Add MovingPlatformComponent and ModelComponent serialization tests

Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-08-31 19:23:28 +00:00
parent d19ba5ed59
commit f86024e06d
3 changed files with 490 additions and 0 deletions

View File

@@ -1,5 +1,7 @@
set(DCOMPONENTS_TESTS set(DCOMPONENTS_TESTS
"DestroyableComponentTests.cpp" "DestroyableComponentTests.cpp"
"ModelComponentTests.cpp"
"MovingPlatformComponentTests.cpp"
"PetComponentTests.cpp" "PetComponentTests.cpp"
"SimplePhysicsComponentTests.cpp" "SimplePhysicsComponentTests.cpp"
"SavingTests.cpp" "SavingTests.cpp"

View File

@@ -0,0 +1,265 @@
#include "GameDependencies.h"
#include <gtest/gtest.h>
#include "BitStream.h"
#include "ModelComponent.h"
#include "Entity.h"
#include "eReplicaComponentType.h"
#include "PetComponent.h"
class ModelTest : public GameDependenciesTest {
protected:
Entity* baseEntity;
ModelComponent* modelComponent;
CBITSTREAM
uint32_t flags = 0;
void SetUp() override {
SetUpDependencies();
baseEntity = new Entity(15, GameDependenciesTest::info);
modelComponent = baseEntity->AddComponent<ModelComponent>();
// Initialize some values to be not default
modelComponent->SetPosition(NiPoint3(10.0f, 20.0f, 30.0f));
modelComponent->SetRotation(NiQuaternion(4.0f, 1.0f, 2.0f, 3.0f)); // For x=1, y=2, z=3, w=4
modelComponent->AddInteract(); // Make it pickable
}
void TearDown() override {
delete baseEntity;
TearDownDependencies();
}
};
/**
* Test serialization of a ModelComponent for a non-pet entity
*/
TEST_F(ModelTest, ModelComponentSerializeNonPetTest) {
bitStream.Reset();
// Now we test a serialization for correctness.
modelComponent->Serialize(bitStream, false);
// Read back the serialized data
// ItemComponent serialization (since this is not a pet)
bool hasItemComponent;
bitStream.Read(hasItemComponent);
EXPECT_EQ(hasItemComponent, true);
LWOOBJID userModelID;
bitStream.Read(userModelID);
EXPECT_EQ(userModelID, baseEntity->GetObjectID()); // Should use entity ID when no user model ID
int extraInfo;
bitStream.Read(extraInfo);
EXPECT_EQ(extraInfo, 0);
bool hasExtraItemData;
bitStream.Read(hasExtraItemData);
EXPECT_EQ(hasExtraItemData, false);
// ModelComponent serialization
bool hasModelInfo;
bitStream.Read(hasModelInfo);
EXPECT_EQ(hasModelInfo, true);
bool isPickable;
bitStream.Read(isPickable);
EXPECT_EQ(isPickable, true); // We added an interact
uint32_t physicsType;
bitStream.Read(physicsType);
EXPECT_EQ(physicsType, 2);
NiPoint3 originalPosition;
bitStream.Read(originalPosition.x);
bitStream.Read(originalPosition.y);
bitStream.Read(originalPosition.z);
EXPECT_EQ(originalPosition, NiPoint3(10.0f, 20.0f, 30.0f));
NiQuaternion originalRotation;
bitStream.Read(originalRotation.x);
bitStream.Read(originalRotation.y);
bitStream.Read(originalRotation.z);
bitStream.Read(originalRotation.w);
EXPECT_EQ(originalRotation, NiQuaternion(4.0f, 1.0f, 2.0f, 3.0f)); // x=1, y=2, z=3, w=4
bool hasBehaviorInfo;
bitStream.Read(hasBehaviorInfo);
EXPECT_EQ(hasBehaviorInfo, true);
uint32_t numBehaviors;
bitStream.Read(numBehaviors);
EXPECT_EQ(numBehaviors, 0); // No behaviors added in test
bool isPaused;
bitStream.Read(isPaused);
EXPECT_EQ(isPaused, false);
}
/**
* Test serialization of a ModelComponent for a pet entity
*/
TEST_F(ModelTest, ModelComponentSerializePetTest) {
bitStream.Reset();
// Add a PetComponent to make this entity a pet
baseEntity->AddComponent<PetComponent>(1);
// Now we test a serialization for correctness.
modelComponent->Serialize(bitStream, false);
// Read back the serialized data
// Should NOT have ItemComponent serialization for pets
// ModelComponent serialization (should start immediately)
bool hasModelInfo;
bitStream.Read(hasModelInfo);
EXPECT_EQ(hasModelInfo, true);
bool isPickable;
bitStream.Read(isPickable);
EXPECT_EQ(isPickable, true); // We added an interact
uint32_t physicsType;
bitStream.Read(physicsType);
EXPECT_EQ(physicsType, 2);
NiPoint3 originalPosition;
bitStream.Read(originalPosition.x);
bitStream.Read(originalPosition.y);
bitStream.Read(originalPosition.z);
EXPECT_EQ(originalPosition, NiPoint3(10.0f, 20.0f, 30.0f));
NiQuaternion originalRotation;
bitStream.Read(originalRotation.x);
bitStream.Read(originalRotation.y);
bitStream.Read(originalRotation.z);
bitStream.Read(originalRotation.w);
EXPECT_EQ(originalRotation, NiQuaternion(4.0f, 1.0f, 2.0f, 3.0f)); // x=1, y=2, z=3, w=4
bool hasBehaviorInfo;
bitStream.Read(hasBehaviorInfo);
EXPECT_EQ(hasBehaviorInfo, true);
uint32_t numBehaviors;
bitStream.Read(numBehaviors);
EXPECT_EQ(numBehaviors, 0); // No behaviors added in test
bool isPaused;
bitStream.Read(isPaused);
EXPECT_EQ(isPaused, false);
}
/**
* Test serialization of a ModelComponent during initial update
*/
TEST_F(ModelTest, ModelComponentSerializeInitialUpdateTest) {
bitStream.Reset();
// Now we test a serialization for correctness with initial update.
modelComponent->Serialize(bitStream, true);
// Read back the serialized data
// ItemComponent serialization (since this is not a pet)
bool hasItemComponent;
bitStream.Read(hasItemComponent);
EXPECT_EQ(hasItemComponent, true);
LWOOBJID userModelID;
bitStream.Read(userModelID);
EXPECT_EQ(userModelID, baseEntity->GetObjectID());
int extraInfo;
bitStream.Read(extraInfo);
EXPECT_EQ(extraInfo, 0);
bool hasExtraItemData;
bitStream.Read(hasExtraItemData);
EXPECT_EQ(hasExtraItemData, false);
// ModelComponent serialization
bool hasModelInfo;
bitStream.Read(hasModelInfo);
EXPECT_EQ(hasModelInfo, true);
bool isPickable;
bitStream.Read(isPickable);
EXPECT_EQ(isPickable, true);
uint32_t physicsType;
bitStream.Read(physicsType);
EXPECT_EQ(physicsType, 2);
NiPoint3 originalPosition;
bitStream.Read(originalPosition.x);
bitStream.Read(originalPosition.y);
bitStream.Read(originalPosition.z);
EXPECT_EQ(originalPosition, NiPoint3(10.0f, 20.0f, 30.0f));
NiQuaternion originalRotation;
bitStream.Read(originalRotation.x);
bitStream.Read(originalRotation.y);
bitStream.Read(originalRotation.z);
bitStream.Read(originalRotation.w);
EXPECT_EQ(originalRotation, NiQuaternion(4.0f, 1.0f, 2.0f, 3.0f)); // x=1, y=2, z=3, w=4
bool hasBehaviorInfo;
bitStream.Read(hasBehaviorInfo);
EXPECT_EQ(hasBehaviorInfo, true);
uint32_t numBehaviors;
bitStream.Read(numBehaviors);
EXPECT_EQ(numBehaviors, 0);
bool isPaused;
bitStream.Read(isPaused);
EXPECT_EQ(isPaused, false);
// During initial update, should write an additional false for model editing info
bool hasModelEditingInfo;
bitStream.Read(hasModelEditingInfo);
EXPECT_EQ(hasModelEditingInfo, false);
}
/**
* Test ModelComponent getters and setters
*/
TEST_F(ModelTest, ModelComponentGettersSettersTest) {
// Test position
NiPoint3 testPosition(100.0f, 200.0f, 300.0f);
modelComponent->SetPosition(testPosition);
EXPECT_EQ(modelComponent->GetOriginalPosition(), testPosition);
// Test rotation
NiQuaternion testRotation(5.0f, 6.0f, 7.0f, 8.0f);
modelComponent->SetRotation(testRotation);
EXPECT_EQ(modelComponent->GetOriginalRotation(), testRotation);
// Test speed
modelComponent->SetSpeed(5.5f);
// Note: GetSpeed() method doesn't exist in the header, but we can verify the setter works
// Test interact
modelComponent->RemoveInteract(); // Remove the one we added in SetUp
// Test that isPickable becomes false when no interactions
bitStream.Reset();
modelComponent->Serialize(bitStream, false);
// Skip itemcomponent data
bool hasItemComponent;
bitStream.Read(hasItemComponent);
LWOOBJID userModelID;
bitStream.Read(userModelID);
int extraInfo;
bitStream.Read(extraInfo);
bool hasExtraItemData;
bitStream.Read(hasExtraItemData);
// Check model component
bool hasModelInfo;
bitStream.Read(hasModelInfo);
bool isPickable;
bitStream.Read(isPickable);
EXPECT_EQ(isPickable, false); // Should be false now
}

View File

@@ -0,0 +1,223 @@
#include "GameDependencies.h"
#include <gtest/gtest.h>
#include "BitStream.h"
#include "MovingPlatformComponent.h"
#include "Entity.h"
#include "eReplicaComponentType.h"
#include "eMovementPlatformState.h"
class MovingPlatformTest : public GameDependenciesTest {
protected:
Entity* baseEntity;
MovingPlatformComponent* movingPlatformComponent;
CBITSTREAM
uint32_t flags = 0;
void SetUp() override {
SetUpDependencies();
baseEntity = new Entity(15, GameDependenciesTest::info);
movingPlatformComponent = baseEntity->AddComponent<MovingPlatformComponent>("testPath");
// Initialize some values to be not default
movingPlatformComponent->SetSerialized(true);
// Set up the MoverSubComponent with some test values
auto* moverSubComponent = movingPlatformComponent->GetMoverSubComponent();
if (moverSubComponent) {
moverSubComponent->mState = eMovementPlatformState::Moving;
moverSubComponent->mDesiredWaypointIndex = 5;
moverSubComponent->mShouldStopAtDesiredWaypoint = true;
moverSubComponent->mInReverse = false;
moverSubComponent->mPercentBetweenPoints = 0.75f;
moverSubComponent->mPosition = NiPoint3(10.0f, 20.0f, 30.0f);
moverSubComponent->mCurrentWaypointIndex = 3;
moverSubComponent->mNextWaypointIndex = 4;
moverSubComponent->mIdleTimeElapsed = 2.5f;
}
}
void TearDown() override {
delete baseEntity;
TearDownDependencies();
}
};
/**
* Test serialization of a MovingPlatformComponent with m_Serialize = false
*/
TEST_F(MovingPlatformTest, MovingPlatformComponentSerializeDisabledTest) {
bitStream.Reset();
// Set m_Serialize to false to test the early return path
movingPlatformComponent->SetSerialized(false);
// Now we test a serialization for correctness.
movingPlatformComponent->Serialize(bitStream, false);
// Should only write two false booleans
ASSERT_EQ(bitStream.GetNumberOfBitsUsed(), 2);
bool firstFlag;
bool secondFlag;
bitStream.Read(firstFlag);
bitStream.Read(secondFlag);
EXPECT_EQ(firstFlag, false);
EXPECT_EQ(secondFlag, false);
}
/**
* Test serialization of a MovingPlatformComponent with enabled serialization but no path
*/
TEST_F(MovingPlatformTest, MovingPlatformComponentSerializeNoPathTest) {
bitStream.Reset();
// Create a component with no path to test the path logic
auto* entityNoPath = new Entity(16, GameDependenciesTest::info);
auto* componentNoPath = entityNoPath->AddComponent<MovingPlatformComponent>("");
componentNoPath->SetSerialized(true);
// Stop pathing to make hasPath false
componentNoPath->StopPathing();
componentNoPath->Serialize(bitStream, false);
// Should write: true (m_Serialize), false (hasPath), true (hasPlatform), mover type, then mover data
bool isEnabled;
bool hasPath;
bool hasPlatform;
bitStream.Read(isEnabled);
bitStream.Read(hasPath);
bitStream.Read(hasPlatform);
EXPECT_EQ(isEnabled, true);
EXPECT_EQ(hasPath, false);
EXPECT_EQ(hasPlatform, true);
// Should continue with platform serialization
eMoverSubComponentType moverType;
bitStream.Read(moverType);
EXPECT_EQ(moverType, eMoverSubComponentType::mover);
// Clean up
delete entityNoPath;
}
/**
* Test complete serialization of a MovingPlatformComponent with path
*/
TEST_F(MovingPlatformTest, MovingPlatformComponentSerializeFullTest) {
bitStream.Reset();
// Now we test a serialization for correctness.
movingPlatformComponent->Serialize(bitStream, false);
// Read back the serialized data
bool isEnabled;
bool hasPath;
bitStream.Read(isEnabled);
bitStream.Read(hasPath);
EXPECT_EQ(isEnabled, true);
EXPECT_EQ(hasPath, true);
if (hasPath) {
bool isOnRail;
bitStream.Read(isOnRail);
EXPECT_EQ(isOnRail, true);
uint16_t pathNameSize;
bitStream.Read(pathNameSize);
EXPECT_EQ(pathNameSize, 8); // "testPath" length
std::u16string pathName;
for (uint16_t i = 0; i < pathNameSize; i++) {
uint16_t character;
bitStream.Read(character);
pathName += character;
}
uint32_t startingPoint;
bitStream.Read(startingPoint);
EXPECT_EQ(startingPoint, 0);
bool reverse;
bitStream.Read(reverse);
EXPECT_EQ(reverse, false);
}
bool hasPlatform;
bitStream.Read(hasPlatform);
EXPECT_EQ(hasPlatform, true);
if (hasPlatform) {
eMoverSubComponentType moverType;
bitStream.Read(moverType);
EXPECT_EQ(moverType, eMoverSubComponentType::mover);
// Test MoverSubComponent serialization
bool moverHasData;
bitStream.Read(moverHasData);
EXPECT_EQ(moverHasData, true);
eMovementPlatformState state;
bitStream.Read(state);
EXPECT_EQ(state, eMovementPlatformState::Moving);
int32_t desiredWaypointIndex;
bitStream.Read(desiredWaypointIndex);
EXPECT_EQ(desiredWaypointIndex, 5);
bool shouldStopAtDesiredWaypoint;
bitStream.Read(shouldStopAtDesiredWaypoint);
EXPECT_EQ(shouldStopAtDesiredWaypoint, true);
bool inReverse;
bitStream.Read(inReverse);
EXPECT_EQ(inReverse, false);
float percentBetweenPoints;
bitStream.Read(percentBetweenPoints);
EXPECT_EQ(percentBetweenPoints, 0.75f);
float positionX, positionY, positionZ;
bitStream.Read(positionX);
bitStream.Read(positionY);
bitStream.Read(positionZ);
EXPECT_EQ(positionX, 10.0f);
EXPECT_EQ(positionY, 20.0f);
EXPECT_EQ(positionZ, 30.0f);
uint32_t currentWaypointIndex;
bitStream.Read(currentWaypointIndex);
EXPECT_EQ(currentWaypointIndex, 3);
uint32_t nextWaypointIndex;
bitStream.Read(nextWaypointIndex);
EXPECT_EQ(nextWaypointIndex, 4);
float idleTimeElapsed;
bitStream.Read(idleTimeElapsed);
EXPECT_EQ(idleTimeElapsed, 2.5f);
float moveTimeElapsed;
bitStream.Read(moveTimeElapsed);
EXPECT_EQ(moveTimeElapsed, 0.0f); // Always 0 in current implementation
}
}
/**
* Test MoverSubComponent initialization and basic functionality
*/
TEST_F(MovingPlatformTest, MoverSubComponentInitializationTest) {
auto* moverSubComponent = movingPlatformComponent->GetMoverSubComponent();
ASSERT_NE(moverSubComponent, nullptr);
// Test that we can access and modify the mover sub component
moverSubComponent->mState = eMovementPlatformState::Stopped;
EXPECT_EQ(moverSubComponent->mState, eMovementPlatformState::Stopped);
moverSubComponent->mDesiredWaypointIndex = 10;
EXPECT_EQ(moverSubComponent->mDesiredWaypointIndex, 10);
}