diff --git a/Modules/Core/ComponentInterface/include/ComponentBase.h b/Modules/Core/ComponentInterface/include/ComponentBase.h index 1fb89f4a62dfb4a8e3925960819538c3e2140357..a84aef60d94f19902f13f0becf0ea9757c9bfac6 100644 --- a/Modules/Core/ComponentInterface/include/ComponentBase.h +++ b/Modules/Core/ComponentInterface/include/ComponentBase.h @@ -10,6 +10,7 @@ namespace elx class ComponentBase { public: virtual interfaceStatus ConnectFrom(const char *, ComponentBase*) = 0; + virtual int ConnectFrom(ComponentBase*) = 0; //protected: virtual ~ComponentBase() {}; }; diff --git a/Modules/Core/ComponentInterface/include/Interfaces.hxx b/Modules/Core/ComponentInterface/include/Interfaces.hxx index 0c26c023b8752f8ee282011ea8801e176212bb88..7b309ca0366759873cdc120024747b17faaaa702 100644 --- a/Modules/Core/ComponentInterface/include/Interfaces.hxx +++ b/Modules/Core/ComponentInterface/include/Interfaces.hxx @@ -44,6 +44,7 @@ class Accepting { public: interfaceStatus ConnectFromImpl(const char *, ComponentBase*) { return interfaceStatus::noaccepter; }; //no interface called interfacename ; + int ConnectFromImpl(ComponentBase*) { return 0; }; //Empty RestInterfaces does 0 successful connects ; }; template<typename FirstInterface, typename ... RestInterfaces> @@ -51,6 +52,7 @@ class Accepting<FirstInterface, RestInterfaces... > : public InterfaceAcceptor<F { public: interfaceStatus ConnectFromImpl(const char *, ComponentBase*); + int ConnectFromImpl(ComponentBase*); }; template<typename... Interfaces> @@ -63,6 +65,7 @@ class Implements : public AcceptingInterfaces, public ProvidingInterfaces, publi { public: virtual interfaceStatus ConnectFrom(const char *, ComponentBase*); + virtual int ConnectFrom(ComponentBase*); }; @@ -159,6 +162,11 @@ interfaceStatus Implements<AcceptingInterfaces, ProvidingInterfaces>::ConnectFro return AcceptingInterfaces::ConnectFromImpl(interfacename, other); } +template<typename AcceptingInterfaces, typename ProvidingInterfaces> +int Implements<AcceptingInterfaces, ProvidingInterfaces>::ConnectFrom(ComponentBase* other) +{ + return AcceptingInterfaces::ConnectFromImpl(other); +} template<typename FirstInterface, typename ... RestInterfaces> interfaceStatus Accepting<FirstInterface, RestInterfaces... >::ConnectFromImpl(const char * interfacename, ComponentBase* other) @@ -184,5 +192,16 @@ interfaceStatus Accepting<FirstInterface, RestInterfaces... >::ConnectFromImpl(c return Accepting< RestInterfaces ... >::ConnectFromImpl(interfacename, other); } +template<typename FirstInterface, typename ... RestInterfaces> +int Accepting<FirstInterface, RestInterfaces... >::ConnectFromImpl(ComponentBase* other) +{ + // static_cast always succeeds since we know via the template arguments of the component which InterfaceAcceptors its base classes are. + InterfaceAcceptor<FirstInterface>* acceptIF = static_cast<InterfaceAcceptor<FirstInterface>*> (this); + + // See if the other component has the right interface and try to connect them + // count the number of successes + return acceptIF->Connect(other) + Accepting< RestInterfaces ... >::ConnectFromImpl(other); +} + } // end namespace elx #endif // #define Interfaces_hxx \ No newline at end of file diff --git a/Testing/Unit/elxComponentInterfaceTest.cxx b/Testing/Unit/elxComponentInterfaceTest.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fac06b989e65ab6cce4af741708be87416a32283 --- /dev/null +++ b/Testing/Unit/elxComponentInterfaceTest.cxx @@ -0,0 +1,95 @@ +#include "SSDMetric3rdPartyComponent.h" +#include "GDOptimizer3rdPartyComponent.h" +#include "SSDMetric4thPartyComponent.h" +#include "GDOptimizer4thPartyComponent.h" + +#include "gtest/gtest.h" + +namespace elx { + +class InterfaceTest : public ::testing::Test { +public: + + virtual void SetUp() { + metric3p = new SSDMetric3rdPartyComponent(); + optimizer3p = new GDOptimizer3rdPartyComponent(); + + metric4p = new SSDMetric4thPartyComponent(); + optimizer4p = new GDOptimizer4thPartyComponent(); + } + + virtual void TearDown() { + delete metric3p; + delete optimizer3p; + delete metric4p; + delete optimizer4p; + } + // types as if returned by our component factory + ComponentBase* metric3p; + ComponentBase* optimizer3p; + ComponentBase* metric4p; + ComponentBase* optimizer4p; + +}; + +TEST_F( InterfaceTest, InterfaceNameTraits ) +{ + EXPECT_STREQ(InterfaceName<MetricValueInterface>::Get(), "MetricValueInterface"); + EXPECT_STREQ(InterfaceName<InterfaceAcceptor<MetricValueInterface> >::Get(), "MetricValueInterface"); +} + +TEST_F( InterfaceTest, DynamicCast ) +{ + int returnval; + //metric3p should have a MetricValueInterface + MetricValueInterface* valueIF = dynamic_cast<MetricValueInterface*> (metric3p); + ASSERT_NE(valueIF, nullptr); + EXPECT_NO_THROW(returnval = valueIF->GetValue()); + + //metric3p should have a MetricDerivativeInterface + MetricDerivativeInterface* derivativeIF = dynamic_cast<MetricDerivativeInterface*> (metric3p); + ASSERT_NE(derivativeIF, nullptr); + EXPECT_NO_THROW(returnval = derivativeIF->GetDerivative()); + + //optimizer3p should have a OptimizerUpdateInterface + OptimizerUpdateInterface* updateIF = dynamic_cast<OptimizerUpdateInterface*> (optimizer3p); + ASSERT_NE(updateIF, nullptr); + EXPECT_NO_THROW(returnval = updateIF->Update()); + + //optimizer3p should have a InterfaceAcceptor<MetricValueInterface> + InterfaceAcceptor<MetricValueInterface>* valueAcceptorIF = dynamic_cast<InterfaceAcceptor<MetricValueInterface>*> (optimizer3p); + ASSERT_NE(valueAcceptorIF, nullptr); + + //optimizer3p should have a InterfaceAcceptor<MetricDerivativeInterface> + InterfaceAcceptor<MetricDerivativeInterface>* derivativeAcceptorIF = dynamic_cast<InterfaceAcceptor<MetricDerivativeInterface>*> (optimizer3p); + ASSERT_NE(derivativeAcceptorIF, nullptr); + +} + +TEST_F( InterfaceTest, ComponentConnecting ) +{ + interfaceStatus IFstatus; + EXPECT_NO_THROW(IFstatus = optimizer3p->ConnectFrom("MetricValueInterface", metric3p)); + EXPECT_EQ(IFstatus, interfaceStatus::success); + + EXPECT_NO_THROW(IFstatus = optimizer3p->ConnectFrom("MetricValueInterface", metric4p)); + EXPECT_EQ(IFstatus, interfaceStatus::success); + + EXPECT_NO_THROW(IFstatus = optimizer4p->ConnectFrom("MetricValueInterface", metric3p)); + EXPECT_EQ(IFstatus, interfaceStatus::success); + + EXPECT_NO_THROW(IFstatus = optimizer4p->ConnectFrom("MetricValueInterface", metric4p)); + EXPECT_EQ(IFstatus, interfaceStatus::success); + + + EXPECT_NO_THROW(IFstatus = optimizer3p->ConnectFrom("MetricDerivativeInterface", metric3p)); + EXPECT_EQ(IFstatus, interfaceStatus::success); + + EXPECT_NO_THROW(IFstatus = optimizer3p->ConnectFrom("MetricDerivativeInterface", metric4p)); + EXPECT_EQ(IFstatus, interfaceStatus::noprovider); + + EXPECT_NO_THROW(IFstatus = optimizer4p->ConnectFrom("MetricDerivativeInterface", metric3p)); + EXPECT_EQ(IFstatus, interfaceStatus::noaccepter); + +} +} // namespace elx