#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/test/minimal.hpp>
#include <RCF/Idl.hpp>
#include <RCF/RcfServer.hpp>
#include <RCF/ObjectFactoryService.hpp>
#include <RCF/test/TransportFactories.hpp>
#include <RCF/test/ThreadGroup.hpp>
#include <RCF/util/CommandLine.hpp>
#include <RCF/util/PortNumbers.hpp>
namespace A {
RCF_BEGIN( Calculator, "Calculator" )
RCF_METHOD_R2(double, add, double, double)
RCF_METHOD_R2(double, sub, double, double)
RCF_METHOD_R2(double, mul, double, double)
RCF_METHOD_R2(double, div, double, double)
RCF_METHOD_V3(void, add, double, double, double&)
RCF_METHOD_V3(void, sub, double, double, double&)
RCF_METHOD_V3(void, mul, double, double, double&)
RCF_METHOD_V3(void, div, double, double, double&)
RCF_METHOD_V1(void, M_in, double)
RCF_METHOD_V1(void, M_plus, double)
RCF_METHOD_R0(double, RcM)
RCF_METHOD_V1(void, RcM, double&)
RCF_END( Calculator )
RCF_BEGIN( X, "X" )
RCF_METHOD_R0(int, f0)
RCF_METHOD_R1(int, f1, int)
RCF_METHOD_R2(int, f2, int, int)
RCF_METHOD_R3(int, f3, int, int, int)
RCF_METHOD_R4(int, f4, int, int, int, int)
RCF_METHOD_R5(int, f5, int, int, int, int, int)
RCF_METHOD_V0(void, f6)
RCF_METHOD_V1(void, f7, int)
RCF_METHOD_V2(void, f8, int, int)
RCF_METHOD_V3(void, f9, int, int, int)
RCF_METHOD_V4(void, f10, int, int, int, int)
RCF_METHOD_V5(void, f11, int, int, int, int, int)
RCF_END( X )
RCF_BEGIN(Y, "Y")
RCF_METHOD_R1(boost::int16_t, increment, const boost::int16_t &)
RCF_METHOD_R1(boost::int32_t, increment, const boost::int32_t &)
RCF_METHOD_R1(boost::int64_t, increment, const boost::int64_t &)
RCF_METHOD_R1(boost::uint16_t, increment, const boost::uint16_t &)
RCF_METHOD_R1(boost::uint32_t, increment, const boost::uint32_t &)
RCF_METHOD_R1(boost::uint64_t, increment, const boost::uint64_t &)
RCF_END(Y)
} //namespace A
namespace A {
namespace B {
class CalculatorDivideByZeroException : public std::exception {
public:
CalculatorDivideByZeroException(std::string msg) : msg_(msg) {}
~CalculatorDivideByZeroException() throw() {}
const char *what() const throw() { return msg_.c_str(); }
private:
std::string msg_;
};
class Calculator {
public:
Calculator() : M_(0) {}
double add(double x, double y) { return x+y; }
double sub(double x, double y) { return x-y; }
double mul(double x, double y) { return x*y; }
double div(double x, double y) { if (y==0) throw CalculatorDivideByZeroException("Divide by zero"); return x/y; }
void add(double x, double y, double &z) { z = x+y; }
void sub(double x, double y, double &z) { z = x-y; }
void mul(double x, double y, double &z) { z = x*y; }
void div(double x, double y, double &z) { if (y==0) throw int(5); z = x/y; }
void M_in(double x) { M_ = x; }
void M_plus(double x) { M_ += x; }
double RcM() { return M_; }
void RcM(double &x) { x = M_; }
private:
Calculator(const Calculator &);
Calculator &operator=(const Calculator &);
double M_;
};
class X {
public:
int f0() { return 1; }
int f1(int) { return 1; }
int f2(int, int) { return 1; }
int f3(int, int, int) { return 1; }
int f4(int, int, int, int) { return 1; }
int f5(int, int, int, int, int) { return 1; }
void f6() {}
void f7(int) {}
void f8(int, int) {}
void f9(int, int, int) {}
void f10(int, int, int, int) {}
void f11(int, int, int, int, int) {}
};
class Y
{
public:
boost::int16_t increment(const boost::int16_t &n) { return n+1; }
boost::int32_t increment(const boost::int32_t &n) { return n+1; }
boost::int64_t increment(const boost::int64_t &n) { return n+1; }
boost::uint16_t increment(const boost::uint16_t &n) { return n+1; }
boost::uint32_t increment(const boost::uint32_t &n) { return n+1; }
boost::uint64_t increment(const boost::uint64_t &n) { return n+1; }
};
} // namespace B
} // namespace A
inline bool fuzzy_eq(double d1, double d2, float tolerance = .1)
{
return (d1-d2)*(d1-d2) < tolerance;
}
void testCalculatorClient(const RCF::I_ClientTransport &clientTransport)
{
using namespace A;
RcfClient<Calculator> calc1(clientTransport.clone());
bool ok = RCF::createRemoteObject<Calculator>(calc1);
BOOST_CHECK(ok);
RcfClient<Calculator> calc2 = calc1;
RcfClient<Calculator> calc3;
calc3 = calc1;
RcfClient<Calculator> calc4(calc3);
double ret = 0;
double x = 0;
double y = 0;
x = 1.5;
y = 2.5;
ret = calc1.add(x,y); BOOST_CHECK( fuzzy_eq(ret, x+y) );
ret = calc1.sub(x,y); BOOST_CHECK( fuzzy_eq(ret, x-y) );
ret = calc1.mul(x,y); BOOST_CHECK( fuzzy_eq(ret, x*y) );
ret = calc1.div(x,y); BOOST_CHECK( fuzzy_eq(ret, x/y) );
x = 1.5;
y = 2.5;
ret = calc2.add(x,y); BOOST_CHECK( fuzzy_eq(ret, x+y) );
ret = calc2.sub(x,y); BOOST_CHECK( fuzzy_eq(ret, x-y) );
ret = calc2.mul(x,y); BOOST_CHECK( fuzzy_eq(ret, x*y) );
ret = calc2.div(x,y); BOOST_CHECK( fuzzy_eq(ret, x/y) );
x = 1.5;
y = 2.5;
ret = calc3.add(x,y); BOOST_CHECK( fuzzy_eq(ret, x+y) );
ret = calc3.sub(x,y); BOOST_CHECK( fuzzy_eq(ret, x-y) );
ret = calc3.mul(x,y); BOOST_CHECK( fuzzy_eq(ret, x*y) );
ret = calc3.div(x,y); BOOST_CHECK( fuzzy_eq(ret, x/y) );
x = 1.5;
y = 2.5;
ret = calc4.add(x,y); BOOST_CHECK( fuzzy_eq(ret, x+y) );
ret = calc4.sub(x,y); BOOST_CHECK( fuzzy_eq(ret, x-y) );
ret = calc4.mul(x,y); BOOST_CHECK( fuzzy_eq(ret, x*y) );
ret = calc4.div(x,y); BOOST_CHECK( fuzzy_eq(ret, x/y) );
x = 3.14;
y = -2.718;
calc4.add(x,y, ret); BOOST_CHECK( fuzzy_eq(ret, x+y) );
calc4.sub(x,y, ret); BOOST_CHECK( fuzzy_eq(ret, x-y) );
calc4.mul(x,y, ret); BOOST_CHECK( fuzzy_eq(ret, x*y) );
calc4.div(x,y, ret); BOOST_CHECK( fuzzy_eq(ret, x/y) );
x = 1;
y = 2;
ret = 1;
ret = calc1.RcM(); BOOST_CHECK( fuzzy_eq(ret, 0) );
calc2.M_in(x);
calc3.M_plus(y);
calc4.RcM(ret); BOOST_CHECK( fuzzy_eq(ret, x+y) );
calc1.M_in(0);
ret = calc2.RcM(); BOOST_CHECK( fuzzy_eq(ret, 0) );
{
RcfClient<X> x(clientTransport.clone());
x.f0();
x.f1(1);
x.f2(1,1);
x.f3(1,1,1);
x.f4(1,1,1,1);
x.f5(1,1,1,1,1);
x.f6();
x.f7(1);
x.f8(1,1);
x.f9(1,1,1);
x.f10(1,1,1,1);
x.f11(1,1,1,1,1);
}
x = 1;
y = 1;
ret = 0;
ret = calc4.add(1,1); BOOST_CHECK( fuzzy_eq(ret, 2) );
ret = calc4.add(1,1); BOOST_CHECK( fuzzy_eq(ret, 2) );
ret = 0;
//calc4.setOneway(true);
ret = calc4.add(RCF::Oneway, 1,1); BOOST_CHECK( fuzzy_eq(ret, 0) );
ret = calc4.add(RCF::Oneway, 1,1); BOOST_CHECK( fuzzy_eq(ret, 0) );
ret = calc4.add(RCF::Oneway, 1,1); BOOST_CHECK( fuzzy_eq(ret, 0) );
ret = 0;
//calc4.setOneway(false);
ret = calc4.add(1,1); BOOST_CHECK( fuzzy_eq(ret, 2) );
ret = calc4.add(1,1); BOOST_CHECK( fuzzy_eq(ret, 2) );
// Test propagation of remote std::exception derived exeptions
x = 1;
y = 0;
try
{
ret = calc1.div(x,y);
BOOST_CHECK(1==0);
}
catch(const RCF::RemoteException &e)
{
RCF_TRACE("RCF::RemoteException caught")(e);
BOOST_CHECK(1==1);
}
/*
#ifndef __BORLANDC__ // Scopeguard bug with Borland C++... causes theses tests to crash
// Test propagation of remote non-std::exception derived exeptions
x = 1;
y = 0;
ret = 0;
try
{
calc.div(x,y, ret);
BOOST_CHECK(1==0);
}
catch(const RCF::RemoteException &e)
{
RCF_TRACE("RCF::RemoteException caught")(e);
BOOST_CHECK(1==1);
}
// check that the server is still alive....
x = 1;
y = 1;
ret = 0;
ret = calc.div(x,y);
BOOST_CHECK( fuzzy_eq(ret, 1) );
{
RcfClient<Calculator> mycalc(ip, port);
x = 1;
y = 1;
ret = 0;
ret = mycalc.div(x,y);
BOOST_CHECK( fuzzy_eq(ret, 1) );
}
#endif //! __BORLANDC__
*/
}
void testCalculatorClientReps(const RCF::I_ClientTransport &clientTransport, int nReps)
{
try
{
for (int i=0; i<nReps; ++i)
{
testCalculatorClient(clientTransport);
}
}
catch(...)
{
BOOST_CHECK(1==0);
}
}
int test_main(int argc, char **argv)
{
util::CommandLine::getSingleton().parse(argc, argv);
for (unsigned int i=0; i<RCF::getTransportFactories().size(); ++i)
{
RCF::TransportFactoryPtr transportFactoryPtr = RCF::getTransportFactories()[i];
std::pair<RCF::ServerTransportPtr, RCF::ClientTransportAutoPtrPtr> transports = transportFactoryPtr->createTransports();
RCF::ServerTransportPtr serverTransportPtr( transports.first );
RCF::ClientTransportAutoPtr clientTransportAutoPtr( *transports.second );
RCF::writeTransportTypes(std::cout, *serverTransportPtr, *clientTransportAutoPtr);
RCF::RcfServer server(serverTransportPtr);
unsigned int numberOfTokens = 50;
unsigned int objectTimeoutS = 60;
RCF::ObjectFactoryServicePtr objectFactoryServicePtr( new RCF::ObjectFactoryService(numberOfTokens, objectTimeoutS) );
objectFactoryServicePtr->bind<A::Calculator, A::B::Calculator>();
objectFactoryServicePtr->bind<A::X, A::B::X>();
server.addService( RCF::ServicePtr(objectFactoryServicePtr) );
A::B::Calculator calculator;
server.bind<A::Calculator>(calculator);
A::B::X x;
server.bind<A::X>(x);
A::B::Y y;
server.bind<A::Y>(y);
server.start();
int nReps = 2;
int nThreads = 5;
ThreadGroup clients;
for (int i=0; i<nThreads; ++i)
{
clients.push_back( ThreadPtr(new Thread(
boost::bind(&testCalculatorClientReps, boost::ref(*clientTransportAutoPtr), nReps))));
}
joinThreadGroup(clients);
boost::int16_t i16 = 1;
boost::int32_t i32 = 2;
boost::int64_t i64 = 3;
boost::uint16_t ui16 = 4;
boost::uint32_t ui32 = 5;
boost::uint64_t ui64 = 6;
A::Y::RcfClient client( clientTransportAutoPtr->clone());
BOOST_CHECK(client.increment(i16) == i16+1);
BOOST_CHECK(client.increment(i32) == i32+1);
BOOST_CHECK(client.increment(i64) == i64+1);
BOOST_CHECK(client.increment(ui16) == ui16+1);
BOOST_CHECK(client.increment(ui32) == ui32+1);
BOOST_CHECK(client.increment(ui64) == ui64+1);
server.stop();
}
return boost::exit_success;
}