This is intended to be used for intra-module communication. Modules can specify service that are then implemented by other modules. This way we can use features from for example part in Core without relying on the Part module explicitly. Base does provide Service definition - which is basically an abstract class with pure virtual methods. This service then can be implemented in other modules and accessed in runtime via ServiceProvider class that stores all implementations. ServiceProvider does store multiple implementations so in theory it is possible to use it to provide granular implementations. For example, part can provide CenterOfMass service that provides center of mass for part features, mesh can implement another one for meshes and then we can iterate over all implementations and find one that can provide center of
111 lines
2.6 KiB
C++
111 lines
2.6 KiB
C++
#include <gtest/gtest.h>
|
|
#include <Base/ServiceProvider.h>
|
|
|
|
class SimpleService
|
|
{
|
|
public:
|
|
virtual ~SimpleService() = default;
|
|
virtual std::string foo() = 0;
|
|
|
|
SimpleService() = default;
|
|
|
|
SimpleService(const SimpleService& other) = delete;
|
|
SimpleService(SimpleService&& other) noexcept = delete;
|
|
SimpleService& operator=(const SimpleService& other) = delete;
|
|
SimpleService& operator=(SimpleService&& other) noexcept = delete;
|
|
};
|
|
|
|
class FirstServiceImplementation final: public SimpleService
|
|
{
|
|
public:
|
|
std::string foo() override
|
|
{
|
|
return "first";
|
|
}
|
|
};
|
|
|
|
class SecondServiceImplementation final: public SimpleService
|
|
{
|
|
public:
|
|
std::string foo() override
|
|
{
|
|
return "second";
|
|
}
|
|
};
|
|
|
|
TEST(ServiceProvider, provideEmptyImplementation)
|
|
{
|
|
// Arrange
|
|
Base::ServiceProvider serviceProvider;
|
|
|
|
// Act
|
|
auto implementation = serviceProvider.provide<SimpleService>();
|
|
|
|
// Assert
|
|
EXPECT_EQ(implementation, nullptr);
|
|
}
|
|
|
|
TEST(ServiceProvider, provideEmptyImplementationList)
|
|
{
|
|
// Arrange
|
|
Base::ServiceProvider serviceProvider;
|
|
|
|
// Act
|
|
const auto implementations = serviceProvider.all<SimpleService>();
|
|
|
|
// Assert
|
|
EXPECT_EQ(implementations.size(), 0);
|
|
}
|
|
|
|
TEST(ServiceProvider, provideImplementation)
|
|
{
|
|
// Arrange
|
|
Base::ServiceProvider serviceProvider;
|
|
|
|
serviceProvider.implement<SimpleService>(new FirstServiceImplementation);
|
|
|
|
// Act
|
|
auto implementation = serviceProvider.provide<SimpleService>();
|
|
|
|
// Assert
|
|
EXPECT_NE(implementation, nullptr);
|
|
EXPECT_EQ(implementation->foo(), "first");
|
|
}
|
|
|
|
TEST(ServiceProvider, provideLatestImplementation)
|
|
{
|
|
// Arrange
|
|
Base::ServiceProvider serviceProvider;
|
|
|
|
serviceProvider.implement<SimpleService>(new FirstServiceImplementation);
|
|
serviceProvider.implement<SimpleService>(new SecondServiceImplementation);
|
|
|
|
// Act
|
|
auto implementation = serviceProvider.provide<SimpleService>();
|
|
|
|
// Assert
|
|
EXPECT_NE(implementation, nullptr);
|
|
EXPECT_EQ(implementation->foo(), "second");
|
|
}
|
|
|
|
TEST(ServiceProvider, provideAllImplementations)
|
|
{
|
|
// Arrange
|
|
Base::ServiceProvider serviceProvider;
|
|
|
|
serviceProvider.implement<SimpleService>(new FirstServiceImplementation);
|
|
serviceProvider.implement<SimpleService>(new SecondServiceImplementation);
|
|
|
|
// Act
|
|
auto implementations = serviceProvider.all<SimpleService>();
|
|
auto it = implementations.begin();
|
|
|
|
// Assert
|
|
// Implementations should be available in order from the most recent one
|
|
EXPECT_EQ((*it)->foo(), "second");
|
|
++it;
|
|
EXPECT_EQ((*it)->foo(), "first");
|
|
++it;
|
|
EXPECT_EQ(it, implementations.end());
|
|
}
|