00001 #ifndef CPPUT_INPUTTEST_H_INCLUDED
00002 # define CPPUT_INPUTTEST_H_INCLUDED
00003
00004 # include "forwards.h"
00005 # include <json/value.h>
00006 # include <cpptl/any.h>
00007 # include <cpptl/reflection.h>
00008
00009
00010 namespace CppUT {
00011
00012
00013
00014
00015
00016
00017
00018 class CPPUT_API TableDataSource
00019 {
00020 public:
00021 virtual ~TableDataSource()
00022 {
00023 }
00024
00025 virtual CppTL::Any getCellValue( int column, int row ) const = 0;
00026 virtual int rowCount() const = 0;
00027 virtual int columnCount() const = 0;
00028 };
00029
00030 class CPPUT_API JsonTableDataSource : public TableDataSource
00031 {
00032 public:
00033 JsonTableDataSource( const Json::Value &data )
00034 : data_( data )
00035 {
00036 }
00037
00038 public:
00039 virtual CppTL::Any getCellValue( int column, int row ) const
00040 {
00041 const Json::Value &value = data_[row][column];
00042 switch ( value.type() )
00043 {
00044 case Json::nullValue:
00045 return CppTL::Any();
00046 case Json::intValue:
00047 return CppTL::Any( value.asInt() );
00048 case Json::uintValue:
00049 return CppTL::Any( value.asUInt() );
00050 case Json::realValue:
00051 return CppTL::Any( value.asDouble() );
00052 case Json::stringValue:
00053 return CppTL::Any( value.asString() );
00054 case Json::booleanValue:
00055 return CppTL::Any( value.asBool() );
00056 default:
00057 return CppTL::Any();
00058 }
00059 }
00060
00061 virtual int rowCount() const
00062 {
00063 return data_.size();
00064 }
00065
00066 virtual int columnCount() const
00067 {
00068 int column = 0;
00069 return data_[column].size();
00070 }
00071 Json::Value data_;
00072 };
00073
00074
00075
00076 class CPPUT_API InputTest
00077 {
00078 public:
00079 virtual ~InputTest()
00080 {
00081 }
00082
00083 virtual void operator()( const TableDataSource &table ) = 0;
00084 };
00085
00086
00087
00088 template<class Functor>
00089 struct Bind234
00090 {
00091 typedef CPPTL_TYPENAME Functor::result_type result_type;
00092 typedef CPPTL_TYPENAME Functor::arg1_type arg1_type;
00093 typedef arg1_type first_argument_type;
00094 typedef CPPTL_TYPENAME Functor::arg2_type arg2_type;
00095 typedef CPPTL_TYPENAME Functor::arg3_type arg3_type;
00096 typedef CPPTL_TYPENAME Functor::arg4_type arg4_type;
00097 typedef CppTL::Functor1<arg1_type> functor_type;
00098 Bind234( const Functor &functor, arg2_type a2, arg3_type a3, arg4_type a4 )
00099 : functor_( functor ), a2_( a2 ), a3_( a3 ), a4_( a4 )
00100 {
00101 }
00102
00103 void operator()( const arg1_type &arg1 ) const
00104 {
00105 functor_( arg1, a2_, a3_, a4_ );
00106 }
00107
00108 private:
00109 Functor functor_;
00110 arg2_type a2_;
00111 arg3_type a3_;
00112 arg4_type a4_;
00113 };
00114
00115
00117 template<typename Functor, typename A2, typename A3, typename A4>
00118 CppTL::Functor1<CPPTL_TYPENAME Functor::arg1_type>
00119 bind234( const Functor &functor, A2 a2, A3 a3, A4 a4 )
00120 {
00121 return CppTL::fn1( Bind234<Functor>( functor, a2, a3, a4 ) );
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153 class CPPUT_API ColumnInputTest : public InputTest
00154 {
00155 public:
00156 ColumnInputTest()
00157 {
00158 this_ = CppTL::makeAny( this );
00159 }
00160
00161 virtual const CppTL::Class *getClass() const = 0;
00162
00163 virtual CppTL::Any getThis() = 0;
00164
00165 public:
00166 virtual void operator()( const TableDataSource &table )
00167 {
00168
00169
00170
00171 this_ = getThis();
00172 int rowCount = table.rowCount();
00173 int columnCount = table.columnCount();
00174 if ( rowCount < 1 || columnCount < 1)
00175 {
00176 CPPUT_CHECKING_FAIL( "Table row header is missing." );
00177 return;
00178 }
00179 const CppTL::Class *aClass = getClass();
00180 if ( !aClass )
00181 {
00182 CPPUT_CHECKING_FAIL( "Reflection class not found for input test." );
00183 return;
00184 }
00185 for ( int column = 0; column < columnCount; ++column )
00186 {
00187 CppTL::Any value = table.getCellValue( column, 0 );
00188 const std::string *headerName = ::get( &value, CppTL::Type<std::string>() );
00189 if ( headerName == 0 )
00190 {
00191 CPPUT_CHECKING_FAIL( "Can not convert header column to string." );
00192 return;
00193 }
00194 if ( headerName->empty() )
00195 continue;
00196 if ( headerName->at( headerName->length() - 1 ) == '?' )
00197 {
00198 CppTL::ConstString name( headerName->c_str(), headerName->c_str() + headerName->length() - 1 );
00199 CppTL::Functor0R<CppTL::Any> actual;
00200 const CppTL::Attribut *attribut = aClass->findAttribut( name );
00201 if ( attribut != 0 )
00202 {
00203 actual = CppTL::bindr( CppTL::memfn1r( this, &ColumnInputTest::actionGetAttribut ),
00204 CppTL::cref( *attribut ) );
00205 }
00206 else
00207 {
00208 const CppTL::Method *method = aClass->findMethod( name );
00209 if ( method == 0 )
00210 {
00211 CPPUT_CHECKING_FAIL( "No method or attribut found by reflection matching header name: " + name );
00212 return;
00213 }
00214 actual = CppTL::bindr( CppTL::memfn1r( this, &ColumnInputTest::actionGetResult ),
00215 CppTL::cref( *method ) );
00216 }
00217 Action action = bind234( CppTL::memfn4( this, &ColumnInputTest::actionCheckEquals ),
00218 column,
00219 CppTL::cref( table ),
00220 actual );
00221 checkActions_.push_back( action );
00222 }
00223 else
00224 {
00225 const CppTL::Attribut *attribut = aClass->findAttribut( headerName->c_str() );
00226 if ( attribut != 0 )
00227 {
00228 Action action = bind234( CppTL::memfn4( this, &ColumnInputTest::actionSetAttribut ),
00229 column,
00230 CppTL::cref( table ),
00231 CppTL::cref( *attribut ) );
00232 setAttributActions_.push_back( action );
00233 }
00234 else
00235 {
00236 const CppTL::Method *method = aClass->findMethod( headerName->c_str() );
00237 if ( method == 0 )
00238 {
00239 CPPUT_CHECKING_FAIL( "No method or attribut found by reflection matching header name: " + *headerName );
00240 return;
00241 }
00242 Action action = bind234( CppTL::memfn4( this, &ColumnInputTest::actionInvokeMethod ),
00243 column,
00244 CppTL::cref( table ),
00245 CppTL::cref( *method ) );
00246 checkActions_.push_back( action );
00247 }
00248 }
00249 }
00250 for ( int row = 1; row < rowCount; ++row )
00251 {
00252 processActions( setAttributActions_, row );
00253 processActions( invokeActions_, row );
00254 processActions( checkActions_, row );
00255 }
00256 }
00257
00258 private:
00259 typedef CppTL::Functor1<int> Action;
00260 typedef std::deque<Action> Actions;
00261
00262 private:
00263 void processActions( const Actions &actions, int row )
00264 {
00265 Actions::const_iterator it = actions.begin();
00266 Actions::const_iterator itEnd = actions.end();
00267 for ( ; it != itEnd; ++it )
00268 {
00269 const Action &action = *it;
00270 action( row );
00271 }
00272 }
00273
00274 void actionSetAttribut( int row,
00275 int column,
00276 const TableDataSource &table,
00277 const CppTL::Attribut &attribut )
00278 {
00279 attribut.set( this_, table.getCellValue( column, row ) );
00280 }
00281
00282 void actionInvokeMethod( int row,
00283 int column,
00284 const TableDataSource &table,
00285 const CppTL::Method &method )
00286 {
00287 CppTL::MethodParameters parameters;
00288 parameters.push_back( table.getCellValue( column, row ) );
00289 method.invoke( this_, parameters );
00290 }
00291
00292 void actionCheckEquals( int row,
00293 int column,
00294 const TableDataSource &table,
00295 CppTL::Functor0R<CppTL::Any> actual )
00296 {
00297 CppTL::Any actualValue = actual();
00298 CppTL::Any expectedValue = table.getCellValue( column, row );
00299 bool hasSameType = actualValue.hasSameType( expectedValue );
00300 CPPUT_CHECK( hasSameType, "Can not compare cell value: different type!" );
00301 if ( !hasSameType )
00302 return;
00303 typedef CppTL::Type<int> TypeInt;
00304 typedef CppTL::Type<double> TypeDouble;
00305 typedef CppTL::Type<std::string> TypeString;
00306 if ( actualValue.type() == CppTL::typeId( TypeInt() ) )
00307 {
00308 CPPUT_CHECK_EQUAL( any_cast( expectedValue, TypeInt() ),
00309 any_cast( actualValue, TypeInt() ) );
00310 }
00311 else if ( actualValue.type() == CppTL::typeId( TypeDouble() ) )
00312 {
00313 CPPUT_CHECK_EQUAL( any_cast( expectedValue, TypeDouble() ),
00314 any_cast( actualValue, TypeDouble() ) );
00315 }
00316 else if ( actualValue.type() == CppTL::typeId( TypeString() ) )
00317 {
00318 CPPUT_CHECK_EQUAL( any_cast( expectedValue, TypeString() ),
00319 any_cast( actualValue, TypeString() ) );
00320 }
00321 else
00322 {
00323 CPPUT_CHECKING_FAIL( "Unsupported type for equality test in cell value." );
00324 }
00325 }
00326
00327 CppTL::Any actionGetAttribut( const CppTL::Attribut &attribut )
00328 {
00329 return attribut.get( this_ );
00330 }
00331
00332 CppTL::Any actionGetResult( const CppTL::Method &method )
00333 {
00334 CppTL::MethodParameters parameters;
00335 return method.invoke( this_, parameters );
00336 }
00337
00338 private:
00339 CppTL::Any this_;
00340 Actions setAttributActions_;
00341 Actions invokeActions_;
00342 Actions checkActions_;
00343 };
00344
00345
00346 #define CPPUT_INPUT_FIXTURE_BEGIN( ClassType ) \
00347 public: \
00348 virtual CppTL::Any getThis() \
00349 { \
00350 return CppTL::makeAny( this ); \
00351 } \
00352 CPPTL_REFLECT_CLASS_BEGIN( ClassType ) \
00353
00354 #define CPPUT_INPUT_FIXTURE_END() \
00355 CPPTL_REFLECT_CLASS_END()
00356
00357 }
00358
00359
00360
00361 #endif // CPPUT_INPUTTEST_H_INCLUDED