#ifndef __cxxtest__ValueTraits_h__ #define __cxxtest__ValueTraits_h__ // // ValueTraits are used by CxxTest to convert arbitrary // values used in TS_ASSERT_EQUALS() to a string representation. // // This header file contains value traits for builtin integral types. // To declare value traits for new types you should instantiate the class // ValueTraits. // #include #ifdef _CXXTEST_OLD_TEMPLATE_SYNTAX # define CXXTEST_TEMPLATE_INSTANTIATION #else // !_CXXTEST_OLD_TEMPLATE_SYNTAX # define CXXTEST_TEMPLATE_INSTANTIATION template<> #endif // _CXXTEST_OLD_TEMPLATE_SYNTAX namespace CxxTest { // // This is how we use the value traits // # define TS_AS_STRING(x) CxxTest::traits(x).asString() // // Char representation of a digit // char digitToChar( unsigned digit ); // // Convert byte value to hex digits // Returns pointer to internal buffer // const char *byteToHex( unsigned char byte ); // // Convert byte values to string // Returns one past the copied data // char *bytesToString( const unsigned char *bytes, unsigned numBytes, unsigned maxBytes, char *s ); // // Copy a string. // Returns one past the end of the destination string // Remember -- we can't use the standard library! // char *copyString( char *dst, const char *src ); // // Compare two strings. // Remember -- we can't use the standard library! // bool stringsEqual( const char *s1, const char *s2 ); // // Represent a character value as a string // Returns one past the end of the string // This will be the actual char if printable or '\xXXXX' otherwise // char *charToString( unsigned long c, char *s ); // // Prevent problems with negative (signed char)s // char *charToString( char c, char *s ); // // The default ValueTraits class dumps up to 8 bytes as hex values // template class ValueTraits { enum { MAX_BYTES = 8 }; char _asString[sizeof("{ ") + sizeof("XX ") * MAX_BYTES + sizeof("... }")]; public: ValueTraits( const T &t ) { bytesToString( (const unsigned char *)&t, sizeof(T), MAX_BYTES, _asString ); } const char *asString( void ) const { return _asString; } }; // // traits( T t ) // Creates an object of type ValueTraits // template inline ValueTraits traits( T t ) { return ValueTraits( t ); } // // You can duplicate the implementation of an existing ValueTraits // # define CXXTEST_COPY_TRAITS(CXXTEST_NEW_CLASS, CXXTEST_OLD_CLASS) \ CXXTEST_TEMPLATE_INSTANTIATION \ class ValueTraits< CXXTEST_NEW_CLASS > \ { \ ValueTraits< CXXTEST_OLD_CLASS > _old; \ public: \ ValueTraits( CXXTEST_NEW_CLASS n ) : _old( (CXXTEST_OLD_CLASS)n ) {} \ const char *asString( void ) const { return _old.asString(); } \ } // // Certain compilers need separate declarations for T and const T // # ifdef _CXXTEST_NO_COPY_CONST # define CXXTEST_COPY_CONST_TRAITS(CXXTEST_CLASS) # else // !_CXXTEST_NO_COPY_CONST # define CXXTEST_COPY_CONST_TRAITS(CXXTEST_CLASS) CXXTEST_COPY_TRAITS(CXXTEST_CLASS, const CXXTEST_CLASS) # endif // _CXXTEST_NO_COPY_CONST // // Avoid compiler warnings about unsigned types always >= 0 // template inline bool negative( N n ) { return n < 0; } template inline N abs( N n ) { return negative(n) ? -n : n; } # define CXXTEST_NON_NEGATIVE(Type) \ CXXTEST_TEMPLATE_INSTANTIATION \ inline bool negative( Type ) { return false; } \ CXXTEST_TEMPLATE_INSTANTIATION \ inline Type abs( Type value ) { return value; } CXXTEST_NON_NEGATIVE( bool ) CXXTEST_NON_NEGATIVE( unsigned char ) CXXTEST_NON_NEGATIVE( unsigned short int ) CXXTEST_NON_NEGATIVE( unsigned int ) CXXTEST_NON_NEGATIVE( unsigned long int ) # ifdef _CXXTEST_LONGLONG CXXTEST_NON_NEGATIVE( unsigned _CXXTEST_LONGLONG ) # endif // _CXXTEST_LONGLONG // // Represent (integral) number as a string // Returns one past the end of the string // Remember -- we can't use the standard library! // template char *numberToString( N n, char *s, N base = 10, unsigned skipDigits = 0, unsigned maxDigits = (unsigned)-1 ) { if ( negative(n) ) { *s++ = '-'; n = abs(n); } N digit = 1; while ( digit <= (n / base) ) digit *= base; N digitValue; for ( ; digit >= 1 && skipDigits; n -= digit * digitValue, digit /= base, -- skipDigits ) digitValue = (unsigned)(n / digit); for ( ; digit >= 1 && maxDigits; n -= digit * digitValue, digit /= base, -- maxDigits ) *s++ = digitToChar( (unsigned)(digitValue = (unsigned)(n / digit)) ); *s = '\0'; return s; } // // All the specific ValueTraits follow. // You can #define CXXTEST_USER_VALUE_TRAITS if you don't want them // #ifndef CXXTEST_USER_VALUE_TRAITS // // ValueTraits: const char * const & // This is used for printing strings, as in TS_FAIL( "Message" ) // CXXTEST_TEMPLATE_INSTANTIATION class ValueTraits { ValueTraits &operator=( const ValueTraits & ); const char *_asString; public: ValueTraits( const char * const &value ) : _asString( value ) {} ValueTraits( const ValueTraits &other ) : _asString( other._asString ) {} const char *asString( void ) const { return _asString; } }; CXXTEST_COPY_TRAITS( const char *, const char * const & ); CXXTEST_COPY_TRAITS( char *, const char * const & ); // // ValueTraits: bool // CXXTEST_TEMPLATE_INSTANTIATION class ValueTraits { bool _value; public: ValueTraits( const bool value ) : _value( value ) {} const char *asString( void ) const { return _value ? "true" : "false"; } }; CXXTEST_COPY_CONST_TRAITS( bool ); # ifdef _CXXTEST_LONGLONG // // ValueTraits: signed long long // CXXTEST_TEMPLATE_INSTANTIATION class ValueTraits { typedef _CXXTEST_LONGLONG T; char _asString[2 + 3 * sizeof(T)]; public: ValueTraits( T t ) { numberToString( t, _asString ); } const char *asString( void ) const { return _asString; } }; CXXTEST_COPY_CONST_TRAITS( signed _CXXTEST_LONGLONG ); // // ValueTraits: unsigned long long // CXXTEST_TEMPLATE_INSTANTIATION class ValueTraits { typedef unsigned _CXXTEST_LONGLONG T; char _asString[1 + 3 * sizeof(T)]; public: ValueTraits( T t ) { numberToString( t, _asString ); } const char *asString( void ) const { return _asString; } }; CXXTEST_COPY_CONST_TRAITS( unsigned _CXXTEST_LONGLONG ); # endif // _CXXTEST_LONGLONG // // ValueTraits: signed long // CXXTEST_TEMPLATE_INSTANTIATION class ValueTraits { typedef signed long int T; char _asString[2 + 3 * sizeof(T)]; public: ValueTraits( T t ) { numberToString( t, _asString ); } const char *asString( void ) const { return _asString; } }; CXXTEST_COPY_CONST_TRAITS( signed long int ); // // ValueTraits: unsigned long // CXXTEST_TEMPLATE_INSTANTIATION class ValueTraits { typedef unsigned long int T; char _asString[1 + 3 * sizeof(T)]; public: ValueTraits( T t ) { numberToString( t, _asString ); } const char *asString( void ) const { return _asString; } }; CXXTEST_COPY_CONST_TRAITS( unsigned long int ); // // All decimals are the same as the long version // CXXTEST_COPY_TRAITS( const signed int, const signed long int ); CXXTEST_COPY_TRAITS( const unsigned int, const unsigned long int ); CXXTEST_COPY_TRAITS( const signed short int, const signed long int ); CXXTEST_COPY_TRAITS( const unsigned short int, const unsigned long int ); CXXTEST_COPY_TRAITS( const unsigned char, const unsigned long int ); CXXTEST_COPY_CONST_TRAITS( signed int ); CXXTEST_COPY_CONST_TRAITS( unsigned int ); CXXTEST_COPY_CONST_TRAITS( signed short int ); CXXTEST_COPY_CONST_TRAITS( unsigned short int ); CXXTEST_COPY_CONST_TRAITS( unsigned char ); // // ValueTraits: char // Returns 'x' for printable chars, '\x??' for others // CXXTEST_TEMPLATE_INSTANTIATION class ValueTraits { char _asString[sizeof("'\\xXX'")]; public: ValueTraits( char c ) { copyString( charToString( c, copyString( _asString, "'" ) ), "'" ); } const char *asString( void ) const { return _asString; } }; CXXTEST_COPY_CONST_TRAITS( char ); // // ValueTraits: signed char // Same as char, some compilers need it // CXXTEST_COPY_TRAITS( const signed char, const char ); CXXTEST_COPY_CONST_TRAITS( signed char ); // // ValueTraits: double // CXXTEST_TEMPLATE_INSTANTIATION class ValueTraits { public: ValueTraits( double t ) { ( requiredDigitsOnLeft( t ) > MAX_DIGITS_ON_LEFT ) ? hugeNumber( t ) : normalNumber( t ); } const char *asString( void ) const { return _asString; } private: enum { MAX_DIGITS_ON_LEFT = 24, DIGITS_ON_RIGHT = 4, BASE = 10 }; char _asString[1 + MAX_DIGITS_ON_LEFT + 1 + DIGITS_ON_RIGHT + 1]; static unsigned requiredDigitsOnLeft( double t ); char *doNegative( double &t ); void hugeNumber( double t ); void normalNumber( double t ); char *doubleToString( double t, char *s, unsigned skip = 0, unsigned max = (unsigned)-1 ); }; CXXTEST_COPY_CONST_TRAITS( double ); // // ValueTraits: float // CXXTEST_COPY_TRAITS( const float, const double ); CXXTEST_COPY_CONST_TRAITS( float ); #endif // !CXXTEST_USER_VALUE_TRAITS }; #ifdef _CXXTEST_HAVE_STD # include #endif // _CXXTEST_HAVE_STD // // CXXTEST_ENUM_TRAITS // #define CXXTEST_ENUM_TRAITS( TYPE, VALUES ) \ namespace CxxTest \ { \ CXXTEST_TEMPLATE_INSTANTIATION \ class ValueTraits \ { \ TYPE _value; \ char _fallback[sizeof("(" #TYPE ")") + 3 * sizeof(TYPE)]; \ public: \ ValueTraits( TYPE value ) { \ _value = value; \ numberToString( _value, copyString( _fallback, "(" #TYPE ")" ) ); \ } \ const char *asString( void ) const \ { \ switch ( _value ) \ { \ VALUES \ default: return _fallback; \ } \ } \ }; \ } #define CXXTEST_ENUM_MEMBER( MEMBER ) \ case MEMBER: return #MEMBER; #endif // __cxxtest__ValueTraits_h__