boost/type_traits/type_traits_test.hpp
// (C) Copyright John Maddock 2000. // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt). // // See http://www.boost.org/libs/type_traits for most recent version including documentation. // common test code for type-traits tests // WARNING: contains code as well as declarations! #ifndef BOOST_TYPE_TRAITS_TEST_HPP #define BOOST_TYPE_TRAITS_TEST_HPP #include "boost/config.hpp" #include "boost/utility.hpp" #include "boost/type_traits/alignment_of.hpp" #include "boost/type_traits/type_with_alignment.hpp" #include "boost/type_traits/ice.hpp" #include <iostream> #include <typeinfo> // // define tests here unsigned failures = 0; unsigned test_count = 0; // // This must get defined within the test file. // All compilers have bugs, set this to the number of // regressions *expected* from a given compiler, // if there are no workarounds for the bugs, *and* // the regressions have been investigated. // extern unsigned int expected_failures; // // proc check_result() // Checks that there were no regressions: // int check_result(int argc, char** argv) { std::cout << test_count << " tests completed, " << failures << " failures found, " << expected_failures << " failures expected from this compiler." << std::endl; if((argc == 2) && (argv[1][0] == '-') && (argv[1][1] == 'a') && (argv[1][2] == 0)) { std::cout << "Press any key to continue..."; std::cin.get(); } return (failures == expected_failures) ? 0 : (failures != 0) ? static_cast<int>(failures) : -1; } // // this one is to verify that a constant is indeed a // constant-integral-expression: // // HP aCC cannot deal with missing names for template value parameters template <bool b> struct checker { static void check(bool, bool, const char*, bool){ ++test_count; } }; template <> struct checker<false> { static void check(bool o, bool n, const char* name, bool soft) { ++test_count; ++failures; // if this is a soft test, then failure is expected, // or may depend upon factors outside our control // (like compiler options)... if(soft)++expected_failures; std::cout << "checking value of " << name << "...failed" << std::endl; std::cout << "\tfound: " << n << " expected " << o << std::endl; } }; template <class T> struct typify{}; template <class T, class U> struct type_checker { static void check(const char* TT, const char*, const char* expression) { ++test_count; if(typeid(typify<T>) != typeid(typify<U>)) { ++failures; std::cout << "checking type of " << expression << "...failed" << std::endl; std::cout << " evaluating: type_checker<" << TT << "," << expression << ">" << std::endl; std::cout << " expected: type_checker<" << TT << "," << TT << ">" << std::endl; std::cout << " but got: " << typeid(type_checker<T,U>).name() << std::endl; } } }; #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template <class T> struct type_checker<T,T> { static void check(const char*, const char*, const char*) { ++test_count; } }; #endif #define value_test(v, x) checker<(v == x)>::check(v, x, #x, false); #define soft_value_test(v, x) checker<(v == x)>::check(v, x, #x, true); #define value_fail(v, x) \ ++test_count; \ ++failures; \ ++expected_failures;\ std::cout << "checking value of " << #x << "...failed" << std::endl; \ std::cout << " " #x " does not compile on this compiler" << std::endl; #define type_test(v, x) type_checker<v,x>::check(#v, #x, #x); #define type_test3(v, x, z) type_checker<v,x,z>::check(#v, #x "," #z, #x "," #z); #ifndef SHORT_TRANSFORM_TEST #define transform_check(name, from_suffix, to_suffix)\ type_test(bool to_suffix, name<bool from_suffix>::type);\ type_test(char to_suffix, name<char from_suffix>::type);\ type_test(wchar_t to_suffix, name<wchar_t from_suffix>::type);\ type_test(signed char to_suffix, name<signed char from_suffix>::type);\ type_test(unsigned char to_suffix, name<unsigned char from_suffix>::type);\ type_test(short to_suffix, name<short from_suffix>::type);\ type_test(unsigned short to_suffix, name<unsigned short from_suffix>::type);\ type_test(int to_suffix, name<int from_suffix>::type);\ type_test(unsigned int to_suffix, name<unsigned int from_suffix>::type);\ type_test(long to_suffix, name<long from_suffix>::type);\ type_test(unsigned long to_suffix, name<unsigned long from_suffix>::type);\ type_test(float to_suffix, name<float from_suffix>::type);\ type_test(long double to_suffix, name<long double from_suffix>::type);\ type_test(double to_suffix, name<double from_suffix>::type);\ type_test(UDT to_suffix, name<UDT from_suffix>::type);\ type_test(enum1 to_suffix, name<enum1 from_suffix>::type); #else #define transform_check(name, from_suffix, to_suffix)\ type_test(int to_suffix, name<int from_suffix>::type);\ type_test(UDT to_suffix, name<UDT from_suffix>::type);\ type_test(enum1 to_suffix, name<enum1 from_suffix>::type); #endif #define boost_dummy_macro_param template <class T> struct test_align { struct padded { char c; T t; }; static void do_it() { padded p; unsigned a = reinterpret_cast<char*>(&(p.t)) - reinterpret_cast<char*>(&p); ++test_count; // only fail if we do not have a multiple of the actual value: if((a > ::boost::alignment_of<T>::value) || (a % ::boost::alignment_of<T>::value)) { ++failures; std::cout << "checking value of " << typeid(boost::alignment_of<T>).name() << "...failed" << std::endl; std::cout << "\tfound: " << boost::alignment_of<T>::value << " expected " << a << std::endl; } // suppress warnings about unused variables: not_unused(p); not_unused(a); } template <class U> static void not_unused(U const&) {} }; #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template <class T> struct test_align<T&> { static void do_it() { // // we can't do the usual test because we can't take the address // of a reference, so check that the result is the same as for a // pointer type instead: unsigned a = boost::alignment_of<T*>::value; ++test_count; if(a != boost::alignment_of<T&>::value) { ++failures; std::cout << "checking value of " << typeid(boost::alignment_of<T&>).name() << "...failed" << std::endl; std::cout << "\tfound: " << boost::alignment_of<T&>::value << " expected " << a << std::endl; } } }; #endif #define align_test(T) test_align<T>::do_it() template<class T> struct test_type_with_align { typedef typename boost::type_with_alignment< (boost::alignment_of<T>::value)>::type align_t; static void do_it() { int align = boost::alignment_of<T>::value; int new_align = boost::alignment_of<align_t>::value; ++test_count; if (new_align % align != 0) { ++failures; std::cerr << "checking for an object with same alignment as " << typeid(T).name() << "...failed" << std::endl; std::cerr << "\tfound: " << typeid(align_t).name() << std::endl; } } }; #define type_with_align_test(T) test_type_with_align<T>::do_it() // // the following code allows us to test that a particular // template functions correctly when instanciated inside another template // (some bugs only show up in that situation). For each template // we declare one NESTED_DECL(classname) that sets up the template class // and multiple NESTED_TEST(classname, template-arg) declarations, to carry // the actual tests: template <bool b> struct nested_test { typedef nested_test type; bool run_time_value; const char* what; nested_test(bool b2, const char* w) : run_time_value(b2), what(w) { check(); } void check() { ++test_count; if(b != run_time_value) { ++failures; std::cerr << "Mismatch between runtime and compile time values in " << what << std::endl; } } }; #ifndef __SUNPRO_CC #define NESTED_DECL(what)\ template <class T> \ struct BOOST_TT_JOIN(nested_tester_,what){\ nested_test< (::boost::type_traits::ice_ne<0, ::boost::what<T>::value>::value)> tester;\ BOOST_TT_JOIN(nested_tester_,what)(const char* s) : tester(::boost::what<T>::value, s){}\ }; #define NESTED_TEST(what, with)\ {BOOST_TT_JOIN(nested_tester_,what)<with> check(#what "<" #with ">"); (void)check;} #else #define NESTED_DECL(what) #define NESTED_TEST(what, with) #endif #define BOOST_TT_JOIN( X, Y ) BOOST_DO_TT_JOIN( X, Y ) #define BOOST_DO_TT_JOIN( X, Y ) X##Y // // define some types to test with: // enum enum_UDT{ one, two, three }; struct UDT { UDT(){}; ~UDT(){}; UDT(const UDT&); UDT& operator=(const UDT&); int i; void f1(); int f2(); int f3(int); int f4(int, float); }; typedef void(*f1)(); typedef int(*f2)(int); typedef int(*f3)(int, bool); typedef void (UDT::*mf1)(); typedef int (UDT::*mf2)(); typedef int (UDT::*mf3)(int); typedef int (UDT::*mf4)(int, float); typedef int (UDT::*mp); typedef int (UDT::*cmf)(int) const; // cv-qualifiers applied to reference types should have no effect // declare these here for later use with is_reference and remove_reference: # ifdef BOOST_MSVC # pragma warning(push) # pragma warning(disable: 4181) # elif defined(__ICL) # pragma warning(push) # pragma warning(disable: 21) # endif // // This is intentional: // r_type and cr_type should be the same type // but some compilers wrongly apply cv-qualifiers // to reference types (this may generate a warning // on some compilers): // typedef int& r_type; typedef const r_type cr_type; # ifdef BOOST_MSVC # pragma warning(pop) # elif defined(__ICL) # pragma warning(pop) # pragma warning(disable: 985) // identifier truncated in debug information # endif struct POD_UDT { int x; }; struct empty_UDT { ~empty_UDT(){}; empty_UDT& operator=(const empty_UDT&){ return *this; } bool operator==(const empty_UDT&)const { return true; } }; struct empty_POD_UDT { empty_POD_UDT& operator=(const empty_POD_UDT&){ return *this; } bool operator==(const empty_POD_UDT&)const { return true; } }; union union_UDT { int x; double y; ~union_UDT(); }; union POD_union_UDT { int x; double y; }; union empty_union_UDT { ~empty_union_UDT(); }; union empty_POD_union_UDT{}; class Base { }; class Derived : public Base { }; class NonDerived { }; enum enum1 { one_,two_ }; enum enum2 { three_,four_ }; struct VB { virtual ~VB(){}; }; struct VD : VB { ~VD(){}; }; // // struct non_pointer: // used to verify that is_pointer does not return // true for class types that implement operator void*() // struct non_pointer { operator void*(){return this;} }; struct non_int_pointer { int i; operator int*(){return &i;} }; struct int_constructible { int_constructible(int); }; struct int_convertible { operator int(); }; // // struct non_empty: // used to verify that is_empty does not emit // spurious warnings or errors. // struct non_empty : private boost::noncopyable { int i; }; // // abstract base classes: struct test_abc1 { virtual void foo() = 0; virtual void foo2() = 0; }; struct test_abc2 { virtual void foo() = 0; virtual void foo2() = 0; }; struct incomplete_type; #endif // BOOST_TYPE_TRAITS_TEST_HPP