Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 60 additions & 30 deletions Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include <Terrain/MockTerrain.h>

using ::testing::_;
using ::testing::AtLeast;
using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::Return;
Expand All @@ -29,8 +28,6 @@ class TerrainHeightGradientListComponentTest : public ::testing::Test
protected:
AZ::ComponentApplication m_app;

AZStd::unique_ptr<AZ::Entity> m_entity;

void SetUp() override
{
AZ::ComponentApplication::Descriptor appDesc;
Expand All @@ -46,47 +43,76 @@ class TerrainHeightGradientListComponentTest : public ::testing::Test
m_app.Destroy();
}

void CreateEntity()
AZStd::unique_ptr<AZ::Entity> CreateEntity()
{
m_entity = AZStd::make_unique<AZ::Entity>();
ASSERT_TRUE(m_entity);
auto entity = AZStd::make_unique<AZ::Entity>();

// Create the required box component.
UnitTest::MockAxisAlignedBoxShapeComponent* boxComponent = m_entity->CreateComponent<UnitTest::MockAxisAlignedBoxShapeComponent>();
m_app.RegisterComponentDescriptor(boxComponent->CreateDescriptor());
entity->Init();

return entity;
}

Terrain::TerrainHeightGradientListComponent* AddHeightGradientListToEntity(AZ::Entity* entity)
{
// Create the TerrainHeightGradientListComponent with an entity in its configuration.
Terrain::TerrainHeightGradientListConfig config;
config.m_gradientEntities.push_back(m_entity->GetId());
config.m_gradientEntities.push_back(entity->GetId());

Terrain::TerrainHeightGradientListComponent* heightGradientListComponent = m_entity->CreateComponent<Terrain::TerrainHeightGradientListComponent>(config);
auto heightGradientListComponent = entity->CreateComponent<Terrain::TerrainHeightGradientListComponent>(config);
m_app.RegisterComponentDescriptor(heightGradientListComponent->CreateDescriptor());

return heightGradientListComponent;
}

void AddRequiredComponetsToEntity(AZ::Entity* entity)
{
// Create the required box component.
UnitTest::MockAxisAlignedBoxShapeComponent* boxComponent = entity->CreateComponent<UnitTest::MockAxisAlignedBoxShapeComponent>();
m_app.RegisterComponentDescriptor(boxComponent->CreateDescriptor());

// Create a MockTerrainLayerSpawnerComponent to provide the required TerrainAreaService.
UnitTest::MockTerrainLayerSpawnerComponent* layerSpawner = m_entity->CreateComponent<UnitTest::MockTerrainLayerSpawnerComponent>();
UnitTest::MockTerrainLayerSpawnerComponent* layerSpawner = entity->CreateComponent<UnitTest::MockTerrainLayerSpawnerComponent>();
m_app.RegisterComponentDescriptor(layerSpawner->CreateDescriptor());

m_entity->Init();
}
};

TEST_F(TerrainHeightGradientListComponentTest, MissingRequiredComponentsActivateFailure)
{
auto entity = CreateEntity();

AddHeightGradientListToEntity(entity.get());

const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails();
EXPECT_FALSE(sortOutcome.IsSuccess());

entity.reset();
}

TEST_F(TerrainHeightGradientListComponentTest, ActivateEntityActivateSuccess)
{
// Check that the entity activates.
CreateEntity();
auto entity = CreateEntity();

m_entity->Activate();
EXPECT_EQ(m_entity->GetState(), AZ::Entity::State::Active);
AddHeightGradientListToEntity(entity.get());

m_entity.reset();
AddRequiredComponetsToEntity(entity.get());

entity->Activate();
EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);

entity.reset();
}

TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientRefreshesTerrainSystem)
{
// Check that the HeightGradientListComponent informs the TerrainSystem when the composition changes.
CreateEntity();
auto entity = CreateEntity();

AddHeightGradientListToEntity(entity.get());

m_entity->Activate();
AddRequiredComponetsToEntity(entity.get());

entity->Activate();

NiceMock<UnitTest::MockTerrainSystemService> terrainSystem;

Expand All @@ -95,32 +121,36 @@ TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientRefreshesTer
// and once when the HeightGradientListComponent gets the OnCompositionChanged directly through the DependencyNotificationBus.
EXPECT_CALL(terrainSystem, RefreshArea(_)).Times(2);

LmbrCentral::DependencyNotificationBus::Event(m_entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
LmbrCentral::DependencyNotificationBus::Event(entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);

// Stop the EXPECT_CALL check now, as OnCompositionChanged will get called twice again during the reset.
Mock::VerifyAndClearExpectations(&terrainSystem);

m_entity.reset();
entity.reset();
}

TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientListReturnsHeights)
{
// Check that the HeightGradientListComponent returns expected height values.
CreateEntity();
auto entity = CreateEntity();

AddHeightGradientListToEntity(entity.get());

AddRequiredComponetsToEntity(entity.get());

NiceMock<UnitTest::MockTerrainAreaHeightRequests> heightfieldRequestBus(m_entity->GetId());
NiceMock<UnitTest::MockTerrainAreaHeightRequests> heightfieldRequestBus(entity->GetId());

m_entity->Activate();
entity->Activate();

const float mockGradientValue = 0.25f;
NiceMock<UnitTest::MockGradientRequests> gradientRequests(m_entity->GetId());
NiceMock<UnitTest::MockGradientRequests> gradientRequests(entity->GetId());
ON_CALL(gradientRequests, GetValue).WillByDefault(Return(mockGradientValue));

// Setup a mock to provide the encompassing Aabb to the HeightGradientListComponent.
const float min = 0.0f;
const float max = 1000.0f;
const AZ::Aabb aabb = AZ::Aabb::CreateFromMinMax(AZ::Vector3(min), AZ::Vector3(max));
NiceMock<UnitTest::MockShapeComponentRequests> mockShapeRequests(m_entity->GetId());
NiceMock<UnitTest::MockShapeComponentRequests> mockShapeRequests(entity->GetId());
ON_CALL(mockShapeRequests, GetEncompassingAabb).WillByDefault(Return(aabb));

const float worldMax = 10000.0f;
Expand All @@ -130,17 +160,17 @@ TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientListReturnsH
ON_CALL(mockterrainDataRequests, GetTerrainAabb).WillByDefault(Return(worldAabb));

// Ensure the cached values in the HeightGradientListComponent are up to date.
LmbrCentral::DependencyNotificationBus::Event(m_entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
LmbrCentral::DependencyNotificationBus::Event(entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);

const AZ::Vector3 inPosition = AZ::Vector3::CreateZero();
AZ::Vector3 outPosition = AZ::Vector3::CreateZero();
bool terrainExists = false;
Terrain::TerrainAreaHeightRequestBus::Event(m_entity->GetId(), &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, terrainExists);
Terrain::TerrainAreaHeightRequestBus::Event(entity->GetId(), &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, terrainExists);

const float height = outPosition.GetZ();

EXPECT_NEAR(height, mockGradientValue * max, 0.01f);

m_entity.reset();
entity.reset();
}

103 changes: 52 additions & 51 deletions Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
#include <GradientSignal/Ebuses/MockGradientRequestBus.h>

using ::testing::NiceMock;
using ::testing::AtLeast;
using ::testing::_;
using ::testing::Return;

namespace UnitTest
Expand All @@ -22,10 +20,6 @@ namespace UnitTest
protected:
AZ::ComponentApplication m_app;

AZStd::unique_ptr<AZ::Entity> m_entity;
UnitTest::MockTerrainLayerSpawnerComponent* m_layerSpawnerComponent = nullptr;
AZStd::unique_ptr<AZ::Entity> m_gradientEntity1, m_gradientEntity2;

const AZStd::string surfaceTag1 = "testtag1";
const AZStd::string surfaceTag2 = "testtag2";

Expand All @@ -37,82 +31,85 @@ namespace UnitTest
appDesc.m_stackRecordLevels = 20;

m_app.Create(appDesc);

CreateEntities();
}

void TearDown() override
{
m_gradientEntity2.reset();
m_gradientEntity1.reset();
m_entity.reset();

m_app.Destroy();
}

void CreateEntities()
AZStd::unique_ptr<AZ::Entity> CreateEntity()
{
m_entity = AZStd::make_unique<AZ::Entity>();
ASSERT_TRUE(m_entity);

m_entity->Init();

m_gradientEntity1 = AZStd::make_unique<AZ::Entity>();
ASSERT_TRUE(m_gradientEntity1);

m_gradientEntity1->Init();
auto entity = AZStd::make_unique<AZ::Entity>();
entity->Init();
return entity;
}

m_gradientEntity2 = AZStd::make_unique<AZ::Entity>();
ASSERT_TRUE(m_gradientEntity2);
UnitTest::MockTerrainLayerSpawnerComponent* AddRequiredComponentsToEntity(AZ::Entity* entity)
{
auto layerSpawnerComponent = entity->CreateComponent<UnitTest::MockTerrainLayerSpawnerComponent>();
m_app.RegisterComponentDescriptor(layerSpawnerComponent->CreateDescriptor());

m_gradientEntity2->Init();
return layerSpawnerComponent;
}

void AddSurfaceGradientListToEntities()
{
m_layerSpawnerComponent = m_entity->CreateComponent<UnitTest::MockTerrainLayerSpawnerComponent>();
m_app.RegisterComponentDescriptor(m_layerSpawnerComponent->CreateDescriptor());
};

Terrain::TerrainSurfaceGradientListConfig config;
TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientMissingRequirementsActivateFails)
{
auto entity = CreateEntity();

Terrain::TerrainSurfaceGradientMapping mapping1;
mapping1.m_gradientEntityId = m_gradientEntity1->GetId();
mapping1.m_surfaceTag = SurfaceData::SurfaceTag(surfaceTag1);
config.m_gradientSurfaceMappings.emplace_back(mapping1);
auto terrainSurfaceGradientListComponent = entity->CreateComponent<Terrain::TerrainSurfaceGradientListComponent>();
m_app.RegisterComponentDescriptor(terrainSurfaceGradientListComponent->CreateDescriptor());

Terrain::TerrainSurfaceGradientMapping mapping2;
mapping2.m_gradientEntityId = m_gradientEntity2->GetId();
mapping2.m_surfaceTag = SurfaceData::SurfaceTag(surfaceTag2);
config.m_gradientSurfaceMappings.emplace_back(mapping2);
const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails();
EXPECT_FALSE(sortOutcome.IsSuccess());

Terrain::TerrainSurfaceGradientListComponent* terrainSurfaceGradientListComponent =
m_entity->CreateComponent<Terrain::TerrainSurfaceGradientListComponent>(
Terrain::TerrainSurfaceGradientListComponent(config));
m_app.RegisterComponentDescriptor(terrainSurfaceGradientListComponent->CreateDescriptor());
}
};
entity.reset();
}

TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientReturnsSurfaceWeightsInOrder)
{
auto entity = CreateEntity();

AddRequiredComponentsToEntity(entity.get());

// When there is more that one surface/weight defined and added to the component, they should all
// be returned in descending weight order.
AddSurfaceGradientListToEntities();

m_entity->Activate();
m_gradientEntity1->Activate();
m_gradientEntity2->Activate();
auto gradientEntity1 = CreateEntity();
auto gradientEntity2 = CreateEntity();

Terrain::TerrainSurfaceGradientListConfig config;

Terrain::TerrainSurfaceGradientMapping mapping1;
mapping1.m_gradientEntityId = gradientEntity1->GetId();
mapping1.m_surfaceTag = SurfaceData::SurfaceTag(surfaceTag1);
config.m_gradientSurfaceMappings.emplace_back(mapping1);

Terrain::TerrainSurfaceGradientMapping mapping2;
mapping2.m_gradientEntityId = gradientEntity2->GetId();
mapping2.m_surfaceTag = SurfaceData::SurfaceTag(surfaceTag2);
config.m_gradientSurfaceMappings.emplace_back(mapping2);

auto terrainSurfaceGradientListComponent = entity->CreateComponent<Terrain::TerrainSurfaceGradientListComponent>(config);
m_app.RegisterComponentDescriptor(terrainSurfaceGradientListComponent->CreateDescriptor());

entity->Activate();
gradientEntity1->Activate();
gradientEntity2->Activate();

const float gradient1Value = 0.3f;
NiceMock<UnitTest::MockGradientRequests> mockGradientRequests1(m_gradientEntity1->GetId());
NiceMock<UnitTest::MockGradientRequests> mockGradientRequests1(gradientEntity1->GetId());
ON_CALL(mockGradientRequests1, GetValue).WillByDefault(Return(gradient1Value));

const float gradient2Value = 1.0f;
NiceMock<UnitTest::MockGradientRequests> mockGradientRequests2(m_gradientEntity2->GetId());
NiceMock<UnitTest::MockGradientRequests> mockGradientRequests2(gradientEntity2->GetId());
ON_CALL(mockGradientRequests2, GetValue).WillByDefault(Return(gradient2Value));

AzFramework::SurfaceData::OrderedSurfaceTagWeightSet weightSet;
Terrain::TerrainAreaSurfaceRequestBus::Event(
m_entity->GetId(), &Terrain::TerrainAreaSurfaceRequestBus::Events::GetSurfaceWeights, AZ::Vector3::CreateZero(), weightSet);
entity->GetId(), &Terrain::TerrainAreaSurfaceRequestBus::Events::GetSurfaceWeights, AZ::Vector3::CreateZero(), weightSet);

AZ::Crc32 expectedCrcList[] = { AZ::Crc32(surfaceTag2), AZ::Crc32(surfaceTag1) };
const float expectedWeightList[] = { gradient2Value, gradient1Value };
Expand All @@ -124,6 +121,10 @@ namespace UnitTest
EXPECT_NEAR(surfaceWeight.m_weight, expectedWeightList[index], 0.01f);
index++;
}

gradientEntity2.reset();
gradientEntity1.reset();
entity.reset();
}
} // namespace UnitTest

Expand Down