Skip to content

Commit

Permalink
added ComponentStorage tests
Browse files Browse the repository at this point in the history
Signed-off-by: Ashton Larkin <[email protected]>
  • Loading branch information
adlarkin committed Jul 1, 2021
1 parent 023bc7f commit 40101a8
Show file tree
Hide file tree
Showing 3 changed files with 330 additions and 1 deletion.
5 changes: 4 additions & 1 deletion include/ignition/gazebo/detail/ComponentStorage.hh
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ enum class ComponentAdditionResult

/// \brief A class that stores all components that have been created. This class
/// also keeps track of the entity a component belongs to.
class IGNITION_GAZEBO_HIDDEN ComponentStorage
///
/// \note The symbols are visible so that unit tests can be written for this
/// class.
class IGNITION_GAZEBO_VISIBLE ComponentStorage
{
/// \brief Clear all of the entity and component data that has been tracked.
/// This "resets" the storage to its initial, empty state.
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ set (gtest_sources
Barrier_TEST.cc
Component_TEST.cc
ComponentFactory_TEST.cc
ComponentStorage_TEST.cc
Conversions_TEST.cc
EntityComponentManager_TEST.cc
EventManager_TEST.cc
Expand Down
325 changes: 325 additions & 0 deletions src/ComponentStorage_TEST.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
/*
* Copyright (C) 2021 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

#include <gtest/gtest.h>

#include <memory>
#include <utility>

#include "ignition/gazebo/Entity.hh"
#include "ignition/gazebo/Types.hh"
#include "ignition/gazebo/components/Component.hh"
#include "ignition/gazebo/components/Factory.hh"
#include "ignition/gazebo/components/LinearVelocity.hh"
#include "ignition/gazebo/components/Pose.hh"
#include "ignition/gazebo/detail/ComponentStorage.hh"

using namespace ignition;
using namespace gazebo;

// define components that are used across various test cases
const auto poseComp = components::Pose({0, 1, 2, 3, 4, 5});
const auto poseComp2 = components::Pose({1, 1, 1, 2, 2, 2});
const auto linVelComp = components::LinearVelocity({0, 1, 2});
const auto linVelComp2 = components::LinearVelocity({5, 5, 5});

// define entities that are used across various test cases
const Entity entity3 = 3;
const Entity entity4 = 4;

/////////////////////////////////////////////////
class ComponentStorageTest : public ::testing::Test
{
// Documentation inherited
protected: void SetUp() override
{
EXPECT_TRUE(this->storage.AddEntity(this->e1));
EXPECT_TRUE(this->storage.AddEntity(this->e2));
}

/// \brief Helper function for adding a component to the storage
/// \param[in] _entity The entity that owns _component
/// \param[in] _typeId The type ID of _component
/// \param[in] _component The component, which belongs to _entity
/// \return The result of the component addition
public: detail::ComponentAdditionResult AddComponent(const Entity _entity,
const ComponentTypeId _typeId,
const components::BaseComponent *_component)
{
auto compPtr = components::Factory::Instance()->New(
_typeId, _component);
return this->storage.AddComponent(_entity, std::move(compPtr));
}

/// \brief Helper function that uses ComponentStorage::ValidComponent to get
/// a component of a particular type that belongs to an entity.
/// \param[in] _entity The entity
/// \return A pointer to the component of the templated type. If no such
/// component exists, nullptr is returned
public: template<typename ComponentTypeT>
ComponentTypeT *Component(const Entity _entity)
{
auto baseComp = this->storage.ValidComponent(_entity,
ComponentTypeT::typeId);
return static_cast<ComponentTypeT *>(baseComp);
}

/// \brief Const version of the Component helper function
public: template<typename ComponentTypeT>
const ComponentTypeT *ConstComponent(const Entity _entity) const
{
auto baseComp = this->storage.ValidComponent(_entity,
ComponentTypeT::typeId);
return static_cast<const ComponentTypeT *>(baseComp);
}

public: detail::ComponentStorage storage;

public: const Entity e1{1};

public: const Entity e2{2};
};

/////////////////////////////////////////////////
TEST_F(ComponentStorageTest, AddEntity)
{
// Entities were already added to the storage in the test fixture's SetUp
// method. So, try to add entities that are already in the storage.
// This should fail
EXPECT_FALSE(this->storage.AddEntity(this->e1));
EXPECT_FALSE(this->storage.AddEntity(this->e2));

// Add entities that are not in the storage yet
EXPECT_TRUE(this->storage.AddEntity(5));
EXPECT_TRUE(this->storage.AddEntity(6));
}

/////////////////////////////////////////////////
TEST_F(ComponentStorageTest, RemoveEntity)
{
// Try to remove entities that aren't in the storage
EXPECT_FALSE(this->storage.RemoveEntity(3));
EXPECT_FALSE(this->storage.RemoveEntity(4));

// Remove entities that are in the storage
EXPECT_TRUE(this->storage.RemoveEntity(this->e1));
EXPECT_TRUE(this->storage.RemoveEntity(this->e2));

// Try to remove entities that have already been removed from the storage
EXPECT_FALSE(this->storage.RemoveEntity(this->e1));
EXPECT_FALSE(this->storage.RemoveEntity(this->e2));
}

/////////////////////////////////////////////////
TEST_F(ComponentStorageTest, AddComponent)
{
// Add components to entities in the storage
EXPECT_EQ(detail::ComponentAdditionResult::NEW_ADDITION,
this->AddComponent(this->e1, components::Pose::typeId, &poseComp));
EXPECT_EQ(detail::ComponentAdditionResult::NEW_ADDITION,
this->AddComponent(this->e2, components::LinearVelocity::typeId,
&linVelComp));

// Make sure the added components have the expected data
auto storagePoseComp = this->Component<components::Pose>(this->e1);
ASSERT_NE(nullptr, storagePoseComp);
EXPECT_EQ(poseComp.Data(), storagePoseComp->Data());
auto storageLinVelComp = this->Component<components::LinearVelocity>(
this->e2);
ASSERT_NE(nullptr, storageLinVelComp);
EXPECT_EQ(linVelComp.Data(), storageLinVelComp->Data());

// Try to add components to entities that aren't in the storage
// (to make sure these entities aren't in the storage, we can try to remove
// them from the storage. Since these entities are not in the storage, the
// remove call should fail)
EXPECT_FALSE(this->storage.RemoveEntity(entity3));
EXPECT_FALSE(this->storage.RemoveEntity(entity4));
EXPECT_EQ(detail::ComponentAdditionResult::FAILED_ADDITION,
this->AddComponent(entity3, components::Pose::typeId, &poseComp));
EXPECT_EQ(detail::ComponentAdditionResult::FAILED_ADDITION,
this->AddComponent(entity4, components::LinearVelocity::typeId,
&linVelComp));
EXPECT_EQ(nullptr, this->Component<components::Pose>(entity3));
EXPECT_EQ(nullptr, this->Component<components::LinearVelocity>(entity4));

// Add components to entities that already have a component of the same type
// (this has the same effect of modifying an existing component)
EXPECT_EQ(detail::ComponentAdditionResult::MODIFICATION,
this->AddComponent(this->e1, components::Pose::typeId, &poseComp2));
EXPECT_EQ(detail::ComponentAdditionResult::MODIFICATION,
this->AddComponent(this->e2, components::LinearVelocity::typeId,
&linVelComp2));

// We can't check if the modification actually took place since this requires
// functionality beyond the ComponentStorage API (see the comments in the
// ComponentStorage::AddComponent method definition for more details), but we
// can at least check that the components still exist after modification
ASSERT_NE(nullptr, this->Component<components::Pose>(this->e1));
ASSERT_NE(nullptr, this->Component<components::LinearVelocity>(this->e2));

// Remove components of a particular type and then re-add them
// (pose component)
EXPECT_TRUE(this->storage.RemoveComponent(this->e1,
components::Pose::typeId));
EXPECT_EQ(nullptr, this->Component<components::Pose>(this->e1));
EXPECT_EQ(detail::ComponentAdditionResult::RE_ADDITION,
this->AddComponent(this->e1, components::Pose::typeId, &poseComp));
storagePoseComp = this->Component<components::Pose>(this->e1);
ASSERT_NE(nullptr, storagePoseComp);
EXPECT_EQ(poseComp.Data(), storagePoseComp->Data());
// (linear velocity component)
EXPECT_TRUE(this->storage.RemoveComponent(this->e2,
components::LinearVelocity::typeId));
EXPECT_EQ(nullptr, this->Component<components::LinearVelocity>(this->e2));
EXPECT_EQ(detail::ComponentAdditionResult::RE_ADDITION,
this->AddComponent(this->e2, components::LinearVelocity::typeId,
&linVelComp));
storageLinVelComp = this->Component<components::LinearVelocity>(this->e2);
ASSERT_NE(nullptr, storageLinVelComp);
EXPECT_EQ(linVelComp.Data(), storageLinVelComp->Data());
}

/////////////////////////////////////////////////
TEST_F(ComponentStorageTest, RemoveComponent)
{
// Add components to entities
EXPECT_EQ(detail::ComponentAdditionResult::NEW_ADDITION,
this->AddComponent(this->e1, poseComp.TypeId(), &poseComp));
EXPECT_NE(nullptr, this->Component<components::Pose>(this->e1));
EXPECT_EQ(detail::ComponentAdditionResult::NEW_ADDITION,
this->AddComponent(this->e2, linVelComp.TypeId(), &linVelComp));
EXPECT_NE(nullptr, this->Component<components::LinearVelocity>(this->e2));

// Remove components that exist
EXPECT_TRUE(this->storage.RemoveComponent(this->e1,
components::Pose::typeId));
EXPECT_EQ(nullptr, this->Component<components::Pose>(this->e1));
EXPECT_TRUE(this->storage.RemoveComponent(this->e2,
components::LinearVelocity::typeId));
EXPECT_EQ(nullptr, this->Component<components::LinearVelocity>(this->e2));

// Try to remove components that don't exist
EXPECT_FALSE(this->storage.RemoveComponent(this->e1,
components::Pose::typeId));
EXPECT_EQ(nullptr, this->Component<components::Pose>(this->e1));
EXPECT_FALSE(this->storage.RemoveComponent(this->e2,
components::LinearVelocity::typeId));
EXPECT_EQ(nullptr, this->Component<components::LinearVelocity>(this->e2));

// Try to remove components from entities that don't exist
EXPECT_FALSE(this->storage.RemoveComponent(entity3,
components::Pose::typeId));
EXPECT_EQ(nullptr, this->Component<components::Pose>(entity3));
EXPECT_FALSE(this->storage.RemoveComponent(entity4,
components::LinearVelocity::typeId));
EXPECT_EQ(nullptr, this->Component<components::LinearVelocity>(entity4));
}

/////////////////////////////////////////////////
TEST_F(ComponentStorageTest, ValidComponent)
{
// Attach a component to an entity
EXPECT_EQ(detail::ComponentAdditionResult::NEW_ADDITION,
this->AddComponent(this->e1, poseComp.TypeId(), &poseComp));

// Get a component that is attached to an entity
auto derivedComp = this->Component<components::Pose>(this->e1);
ASSERT_NE(nullptr, derivedComp);
EXPECT_EQ(poseComp.Data(), derivedComp->Data());

// Test modifying the component that was retrieved
derivedComp->Data() = poseComp2.Data();
derivedComp = this->Component<components::Pose>(this->e1);
ASSERT_NE(nullptr, derivedComp);
EXPECT_EQ(poseComp2.Data(), derivedComp->Data());

// Try to get a component that does not exist
ASSERT_EQ(nullptr, this->Component<components::LinearVelocity>(this->e2));

// Remove a component and try to retrieve it
EXPECT_NE(nullptr, this->Component<components::Pose>(this->e1));
EXPECT_TRUE(this->storage.RemoveComponent(this->e1,
components::Pose::typeId));
ASSERT_EQ(nullptr, this->Component<components::Pose>(this->e1));
}

/////////////////////////////////////////////////
// Similar to the ValidComponent test, but this test covers the const version of
// the ComponentStorage::ValidComponent method (the ValidComponent test covered
// the non-const version of the ComponentStorage::ValidComponent)
TEST_F(ComponentStorageTest, ValidComponentConst)
{
// Attach a component to an entity
EXPECT_EQ(detail::ComponentAdditionResult::NEW_ADDITION,
this->AddComponent(this->e1, poseComp.TypeId(), &poseComp));

// Get a component that is attached to an entity
auto derivedComp = this->ConstComponent<components::Pose>(this->e1);
ASSERT_NE(nullptr, derivedComp);
EXPECT_EQ(poseComp.Data(), derivedComp->Data());

// Try to get a component that does not exist
ASSERT_EQ(nullptr,
this->ConstComponent<components::LinearVelocity>(this->e2));

// Remove a component and try to retrieve it
EXPECT_NE(nullptr, this->ConstComponent<components::Pose>(this->e1));
EXPECT_TRUE(this->storage.RemoveComponent(this->e1,
components::Pose::typeId));
ASSERT_EQ(nullptr, this->ConstComponent<components::Pose>(this->e1));
}

/////////////////////////////////////////////////
TEST_F(ComponentStorageTest, Reset)
{
// Add components to entities in the storage
EXPECT_EQ(detail::ComponentAdditionResult::NEW_ADDITION,
this->AddComponent(this->e1, poseComp.TypeId(), &poseComp));
EXPECT_EQ(detail::ComponentAdditionResult::NEW_ADDITION,
this->AddComponent(this->e2, linVelComp.TypeId(), &linVelComp));

// Make sure that the storage has entities and components
EXPECT_FALSE(this->storage.AddEntity(this->e1));
EXPECT_FALSE(this->storage.AddEntity(this->e2));
EXPECT_NE(nullptr, this->storage.ValidComponent(this->e1,
components::Pose::typeId));
EXPECT_NE(nullptr, this->storage.ValidComponent(this->e2,
components::LinearVelocity::typeId));

// Reset the storage
this->storage.Reset();

// Make sure the storage has no entities or components
EXPECT_FALSE(this->storage.RemoveEntity(this->e1));
EXPECT_EQ(nullptr, this->storage.ValidComponent(this->e1,
components::Pose::typeId));
EXPECT_FALSE(this->storage.RemoveEntity(this->e2));
EXPECT_EQ(nullptr, this->storage.ValidComponent(this->e2,
components::LinearVelocity::typeId));

// We should be able to re-add the entities that were removed
EXPECT_TRUE(this->storage.AddEntity(this->e1));
EXPECT_TRUE(this->storage.AddEntity(this->e2));

// The entities that were re-added shouldn't have any components associated
// with them since resetting the storage removed all components
EXPECT_EQ(nullptr, this->storage.ValidComponent(this->e1,
components::Pose::typeId));
EXPECT_EQ(nullptr, this->storage.ValidComponent(this->e2,
components::LinearVelocity::typeId));
}

0 comments on commit 40101a8

Please sign in to comment.