diff options
Diffstat (limited to 'cxxtest/ValueTraits.h')
-rw-r--r-- | cxxtest/ValueTraits.h | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/cxxtest/ValueTraits.h b/cxxtest/ValueTraits.h new file mode 100644 index 0000000..71145ad --- /dev/null +++ b/cxxtest/ValueTraits.h @@ -0,0 +1,377 @@ +#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<YourClass>. +// + +#include <cxxtest/Flags.h> + +#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 T> + 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<T> + // + template <class T> + inline ValueTraits<T> traits( T t ) + { + return ValueTraits<T>( 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<class N> inline bool negative( N n ) { return n < 0; } + template<class N> inline N abs( N n ) { return negative(n) ? -n : n; } + +# define CXXTEST_NON_NEGATIVE(Type) \ + CXXTEST_TEMPLATE_INSTANTIATION \ + inline bool negative<Type>( Type ) { return false; } \ + CXXTEST_TEMPLATE_INSTANTIATION \ + inline Type abs<Type>( 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<class N> + 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<const char * const &> + { + 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<const bool> + { + 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<const signed _CXXTEST_LONGLONG> + { + typedef _CXXTEST_LONGLONG T; + char _asString[2 + 3 * sizeof(T)]; + public: + ValueTraits( T t ) { numberToString<T>( 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<const unsigned _CXXTEST_LONGLONG> + { + typedef unsigned _CXXTEST_LONGLONG T; + char _asString[1 + 3 * sizeof(T)]; + public: + ValueTraits( T t ) { numberToString<T>( 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<const signed long int> + { + typedef signed long int T; + char _asString[2 + 3 * sizeof(T)]; + public: + ValueTraits( T t ) { numberToString<T>( t, _asString ); } + const char *asString( void ) const { return _asString; } + }; + + CXXTEST_COPY_CONST_TRAITS( signed long int ); + + // + // ValueTraits: unsigned long + // + CXXTEST_TEMPLATE_INSTANTIATION + class ValueTraits<const unsigned long int> + { + typedef unsigned long int T; + char _asString[1 + 3 * sizeof(T)]; + public: + ValueTraits( T t ) { numberToString<T>( 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<const char> + { + 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<const double> + { + 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 <cxxtest/StdValueTraits.h> +#endif // _CXXTEST_HAVE_STD + +// +// CXXTEST_ENUM_TRAITS +// +#define CXXTEST_ENUM_TRAITS( TYPE, VALUES ) \ + namespace CxxTest \ + { \ + CXXTEST_TEMPLATE_INSTANTIATION \ + class ValueTraits<TYPE> \ + { \ + TYPE _value; \ + char _fallback[sizeof("(" #TYPE ")") + 3 * sizeof(TYPE)]; \ + public: \ + ValueTraits( TYPE value ) { \ + _value = value; \ + numberToString<unsigned long int>( _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__ |