00001 #ifndef CPPUT_ASSERTENUM_H_INCLUDED
00002 # define CPPUT_ASSERTENUM_H_INCLUDED
00003
00004 # include <cpput/assertcommon.h>
00005 # include <cpptl/enumerator.h>
00006 # include <functional>
00007 # include <deque>
00008
00009
00010
00011 namespace CppUT
00012 {
00013 template<class AType
00014 ,class BType>
00015 struct DefaultComparator
00016 {
00017 DefaultComparator()
00018 {
00019 }
00020
00021 bool operator()( const AType &a, const BType &b ) const
00022 {
00023 return equalityTest( a, b );
00024 }
00025 };
00026
00027 template<class AType
00028 ,class BType>
00029 struct DeRefComparator
00030 {
00031 bool operator()( const AType *a, const BType *b ) const
00032 {
00033 return a == b ||
00034 ( !a && !b && *a == *b );
00035 }
00036 };
00037
00038 template<class AType
00039 ,class BType>
00040 struct RefComparator
00041 {
00042 bool operator()( AType a, BType b ) const
00043 {
00044 return equalityTest( a, b );
00045 }
00046 };
00047
00048 # ifndef CPPUT_NO_DEFAULT_ENUM_ITEM_STRINGIZE
00049 template<typename ItemType>
00050 std::string stringizeEnumItem( const ItemType &item )
00051 {
00052 return stringize( item );
00053 }
00054 # endif // CPPUT_NO_DEFAULT_ENUM_ITEM_STRINGIZE
00055
00056
00058 namespace Impl {
00059
00060 enum { noDifference = -1 };
00061
00062 template<class ExpectedEnumType
00063 ,class ActualEnumType
00064 ,class EqualityPredicate>
00065 unsigned int getSequenceDiffIndex( ExpectedEnumType expected,
00066 ActualEnumType actual,
00067 EqualityPredicate comparator )
00068 {
00069 unsigned int diffIndex = 0;
00070 while ( expected.is_open() )
00071 {
00072 if ( !actual.is_open() )
00073 return diffIndex;
00074 if ( !comparator(expected.current(), actual.current() ) )
00075 return diffIndex;
00076 expected.advance();
00077 actual.advance();
00078 ++diffIndex;
00079 }
00080 if ( actual.is_open() )
00081 return diffIndex;
00082 return (unsigned int)noDifference;
00083 }
00084
00085
00086 template<class ExpectedSetType
00087 ,class ActualSetType
00088 ,class MissingSeqType
00089 ,class ExtraneousSeqType
00090 ,class EqualityPredicate>
00091 void getSetDifference( ExpectedSetType expectedEnum,
00092 ActualSetType actualEnum,
00093 MissingSeqType &missing,
00094 ExtraneousSeqType &extraneous,
00095 EqualityPredicate predicate )
00096 {
00097 for ( ; actualEnum.is_open(); actualEnum.advance() )
00098 extraneous.push_back( actualEnum.current() );
00099
00100 for ( ; expectedEnum.is_open(); expectedEnum.advance() )
00101 {
00102 CPPTL_TYPENAME ExpectedSetType::value_type expectedItem = expectedEnum.current();
00103 bool found = false;
00104 CPPTL_TYPENAME ExtraneousSeqType::iterator it = extraneous.begin();
00105 for ( ; it != extraneous.end(); ++it )
00106 {
00107 const CPPTL_TYPENAME ExtraneousSeqType::value_type &actualItem = *it;
00108 if ( predicate( expectedItem, actualItem ) )
00109 {
00110 it = extraneous.erase( it );
00111 found = true;
00112 break;
00113 }
00114 }
00115
00116 if ( !found )
00117 missing.push_back( expectedItem );
00118 }
00119 }
00120
00121 }
00123
00124 template<class ExpectedEnumerator
00125 ,class ActualEnumerator
00126 ,class ExpectedStringizer
00127 ,class ActualStringizer
00128 ,class EqualityPredicate>
00129 CheckerResult checkCustomHeterogeneousSequenceEqual( const ExpectedEnumerator &expected,
00130 const ActualEnumerator &actual,
00131 ExpectedStringizer expectedStringizer,
00132 ActualStringizer actualStringizer,
00133 EqualityPredicate comparator,
00134 const Message &message )
00135 {
00136 CheckerResult result;
00137 unsigned int diffIndex = Impl::getSequenceDiffIndex( expected,
00138 actual,
00139 comparator );
00140 if ( diffIndex == Impl::noDifference )
00141 return result;
00142
00143 typedef CppTL::SliceEnumerator<ExpectedEnumerator> ExpectedEnumeratorSlice;
00144 ExpectedEnumeratorSlice common = CppTL::Enum::slice( expected, 0, diffIndex );
00145 ExpectedEnumeratorSlice expectedDiff = CppTL::Enum::slice( expected, diffIndex );
00146 typedef CppTL::SliceEnumerator<ActualEnumerator> ActualEnumeratorSlice;
00147 ActualEnumeratorSlice actualDiff = CppTL::Enum::slice( actual, diffIndex );
00148
00149 result.setFailed();
00150 result.message_ = message;
00151 result.message_.add( translate( "Sequences are not identical." ) );
00152 result.message_.add( translate( "Divergence position (0 based): " ) + stringize(diffIndex) );
00153 if ( common.is_open() )
00154 result.message_.add( translate( "Common:\n" ) + enumToStringCustom(common,
00155 expectedStringizer) );
00156 result.message_.add( translate( "Expected:\n" ) + enumToStringCustom(expectedDiff,
00157 expectedStringizer) );
00158 result.message_.add( translate( "Actual:\n" ) + enumToStringCustom(actualDiff,
00159 actualStringizer) );
00160 return result;
00161 }
00162
00163 template<class EnumeratorType
00164 ,class StringizerType
00165 ,class EqualityPredicate>
00166 CheckerResult checkCustomSequenceEqual( const EnumeratorType &expected,
00167 const EnumeratorType &actual,
00168 StringizerType stringizer,
00169 EqualityPredicate comparator,
00170 const Message &message )
00171 {
00172 return checkCustomHeterogeneousSequenceEqual( expected, actual,
00173 stringizer, stringizer,
00174 comparator, message );
00175 }
00176
00177 template<class EnumeratorType
00178 ,class StringizerType
00179 ,class EqualityPredicate>
00180 CheckerResult checkCustomStringSequenceEqual( const EnumeratorType &expected,
00181 const EnumeratorType &actual,
00182 StringizerType stringizer,
00183 const Message &message = Message() )
00184 {
00185 typedef CPPTL_TYPENAME EnumeratorType::value_type ValueType;
00186 DefaultComparator<ValueType,ValueType> comparator;
00187 return checkCustomHeterogeneousSequenceEqual( expected, actual,
00188 stringizer, stringizer,
00189 comparator, message );
00190 }
00191
00192 template<class ExpectedEnumerator
00193 ,class ActualEnumerator
00194 ,class EqualityPredicate>
00195 CheckerResult checkCustomEqualitySequenceEqual( const ExpectedEnumerator &expected,
00196 const ActualEnumerator &actual,
00197 EqualityPredicate comparator,
00198 const Message &message = Message() )
00199 {
00200 typedef DefaultStringizer<CPPTL_TYPENAME ExpectedEnumerator::value_type> ExpectedStringizer;
00201 typedef DefaultStringizer<CPPTL_TYPENAME ActualEnumerator::value_type> ActualStringizer;
00202 return checkCustomHeterogeneousSequenceEqual( expected, actual,
00203 ExpectedStringizer(), ActualStringizer(),
00204 comparator, message );
00205 }
00206
00207
00208 template<class ExpectedEnumeratorType
00209 ,class ActualEnumeratorType>
00210 CheckerResult checkSequenceEqual( const ExpectedEnumeratorType &expected,
00211 const ActualEnumeratorType &actual,
00212 const Message &message = Message() )
00213 {
00214 DefaultComparator<CPPTL_TYPENAME ExpectedEnumeratorType::value_type
00215 ,CPPTL_TYPENAME ActualEnumeratorType::value_type> comparator;
00216 return checkCustomEqualitySequenceEqual( expected, actual, comparator, message );
00217 }
00218
00219 template<class ExpectedEnumeratorType
00220 ,class ActualEnumeratorType
00221 ,class EqualityPredicate>
00222 CheckerResult checkCustomEqualityStlSequenceEqual( const ExpectedEnumeratorType &expected,
00223 const ActualEnumeratorType &actual,
00224 EqualityPredicate comparator,
00225 const Message &message = Message() )
00226 {
00227 return checkCustomEqualitySequenceEqual( CppTL::Enum::container( expected ),
00228 CppTL::Enum::container( actual ),
00229 comparator, message );
00230 }
00231
00232 template<class ExpectedEnumeratorType
00233 ,class ActualEnumeratorType>
00234 CheckerResult checkStlSequenceEqual( const ExpectedEnumeratorType &expected,
00235 const ActualEnumeratorType &actual,
00236 const Message &message = Message() )
00237 {
00238 return checkSequenceEqual( CppTL::Enum::container( expected ),
00239 CppTL::Enum::container( actual ),
00240 message );
00241 }
00242
00243 template<class ExpectedEnumerator
00244 ,class ActualEnumerator
00245 ,class ExpectedStringizer
00246 ,class ActualStringizer
00247 ,class EqualityPredicate>
00248 CheckerResult checkCustomHeterogeneousSetEqual( const ExpectedEnumerator &expected,
00249 const ActualEnumerator &actual,
00250 ExpectedStringizer expectedStringizer,
00251 ActualStringizer actualStringizer,
00252 EqualityPredicate predicate,
00253 const Message &message )
00254 {
00255 CheckerResult result;
00256 std::deque<CPPTL_TYPENAME ExpectedEnumerator::value_type> missing;
00257 std::deque<CPPTL_TYPENAME ActualEnumerator::value_type> extraneous;
00258 Impl::getSetDifference( expected, actual,
00259 missing, extraneous,
00260 predicate );
00261 if ( missing.empty() && extraneous.empty() )
00262 return result;
00263
00264 result.setFailed();
00265 result.message_ = message;
00266 result.message_.add( translate( "Sets do not contain the same items." ) );
00267 result.message_.add( translate( "Actual:\n" ) + enumToStringCustom(actual,actualStringizer) );
00268 if ( missing.size() > 0 )
00269 result.message_.add( translate( "Missing:\n" ) +
00270 enumToStringCustom( CppTL::Enum::container(missing),
00271 expectedStringizer ) );
00272 if ( extraneous.size() > 0 )
00273 result.message_.add( translate( "Extraneous:\n" ) +
00274 enumToStringCustom( CppTL::Enum::container(extraneous),
00275 actualStringizer ) );
00276 return result;
00277 }
00278
00279 template<class ExpectedEnumerator
00280 ,class ActualEnumerator
00281 ,class ItemStringizer
00282 ,class EqualityPredicate>
00283 CheckerResult checkCustomSetEqual( const ExpectedEnumerator &expected,
00284 const ActualEnumerator &actual,
00285 ItemStringizer itemStringizer,
00286 EqualityPredicate comparator,
00287 const Message &message = Message() )
00288 {
00289 return checkCustomHeterogeneousSetEqual( expected, actual,
00290 itemStringizer, itemStringizer,
00291 comparator, message );
00292 }
00293
00294 template<class ExpectedEnumerator
00295 ,class ActualEnumerator
00296 ,class ItemStringizer>
00297 CheckerResult checkCustomStringSetEqual( const ExpectedEnumerator &expected,
00298 const ActualEnumerator &actual,
00299 ItemStringizer itemStringizer,
00300 const Message &message = Message() )
00301 {
00302 DefaultComparator<CPPTL_TYPENAME ExpectedEnumerator::value_type
00303 ,CPPTL_TYPENAME ActualEnumerator::value_type> comparator;
00304 return checkCustomSetEqual( expected, actual, itemStringizer, comparator, message );
00305 }
00306
00307 template<class ExpectedEnumerator
00308 ,class ActualEnumerator
00309 ,class EqualityPredicate>
00310 CheckerResult checkCustomEqualitySetEqual( const ExpectedEnumerator &expected,
00311 const ActualEnumerator &actual,
00312 EqualityPredicate comparator,
00313 const Message &message = Message() )
00314 {
00315 typedef DefaultStringizer<CPPTL_TYPENAME ExpectedEnumerator::value_type> ExpectedStringizer;
00316 typedef DefaultStringizer<CPPTL_TYPENAME ActualEnumerator::value_type> ActualStringizer;
00317 return checkCustomHeterogeneousSetEqual( expected, actual,
00318 ExpectedStringizer(), ActualStringizer(),
00319 comparator, message );
00320 }
00321
00322 template<class ExpectedEnumerator
00323 ,class ActualEnumerator>
00324 CheckerResult checkSetEqual( const ExpectedEnumerator &expected,
00325 const ActualEnumerator &actual,
00326 const Message &message = Message() )
00327 {
00328 DefaultComparator<CPPTL_TYPENAME ExpectedEnumerator::value_type
00329 ,CPPTL_TYPENAME ActualEnumerator::value_type> comparator;
00330 return checkCustomEqualitySetEqual( expected, actual, comparator, message );
00331 }
00332
00333 template<class ExpectedStlSet
00334 ,class ActualStlSet>
00335 CheckerResult checkStlSetEqual( const ExpectedStlSet &expected,
00336 const ActualStlSet &actual,
00337 const Message &message = Message() )
00338 {
00339 return checkSetEqual( CppTL::Enum::container( expected ),
00340 CppTL::Enum::container( actual ),
00341 message );
00342 }
00343
00344 template<class ExpectedSetType
00345 ,class ActualSetType
00346 ,class EqualityPredicate>
00347 CheckerResult checkCustomEqualityStlSetEqual( const ExpectedSetType &expected,
00348 const ActualSetType &actual,
00349 EqualityPredicate predicate,
00350 const Message &message = Message() )
00351 {
00352 return checkSetEqual( CppTL::Enum::container( expected ),
00353 CppTL::Enum::container( actual ),
00354 predicate, message );
00355 }
00356
00357
00358 template<class EnumeratorType
00359 ,class ItemStringizerType>
00360 std::string enumToStringCustom( EnumeratorType enumerator,
00361 ItemStringizerType itemStringizer,
00362 const std::string &separator = "; ",
00363 const std::string &begin = "{ ",
00364 const std::string &end = " }" )
00365 {
00366 std::string str;
00367 for ( ; enumerator.is_open(); enumerator.advance() )
00368 {
00369 std::string item = itemStringizer( enumerator.current() );
00370 if ( !str.empty() )
00371 str += separator;
00372 str += item;
00373 }
00374 return begin + str + end;
00375 }
00376
00377
00378 template<class EnumType>
00379 std::string enumToString( const EnumType &enumerator,
00380 const std::string &separator = "; ",
00381 const std::string &begin = "{ ",
00382 const std::string &end = " }" )
00383 {
00384 return enumToStringCustom( enumerator,
00385 DefaultStringizer<CPPTL_TYPENAME EnumType::value_type>(),
00386 separator,
00387 begin,
00388 end );
00389 }
00390
00391 }
00392
00393
00397 # define CPPUT_ASSERT_SEQUENCE_EQUAL \
00398 CPPUT_BEGIN_ASSERTION_MACRO() \
00399 ::CppUT::checkSequenceEqual
00400
00404 # define CPPUT_ASSERT_SET_EQUAL \
00405 CPPUT_BEGIN_ASSERTION_MACRO() \
00406 ::CppUT::checkSetEqual
00407
00411 # define CPPUT_ASSERT_STL_SEQUENCE_EQUAL \
00412 CPPUT_BEGIN_ASSERTION_MACRO() \
00413 ::CppUT::checkStlSequenceEqual
00414
00418 # define CPPUT_ASSERT_STL_SET_EQUAL \
00419 CPPUT_BEGIN_ASSERTION_MACRO() \
00420 ::CppUT::checkStlSetEqual
00421
00422
00426 # define CPPUT_CHECK_SEQUENCE_EQUAL \
00427 CPPUT_BEGIN_CHECKING_MACRO() \
00428 ::CppUT::checkSequenceEqual
00429
00433 # define CPPUT_CHECK_SET_EQUAL \
00434 CPPUT_BEGIN_CHECKING_MACRO() \
00435 ::CppUT::checkSetEqual
00436
00437
00441 # define CPPUT_CHECK_STL_SEQUENCE_EQUAL \
00442 CPPUT_BEGIN_CHECKING_MACRO() \
00443 ::CppUT::checkStlSequenceEqual
00444
00448 # define CPPUT_CHECK_STL_SET_EQUAL \
00449 CPPUT_BEGIN_CHECKING_MACRO() \
00450 ::CppUT::checkStlSetEqual
00451
00452 #endif // CPPUT_ASSERTENUM_H_INCLUDED
00453