// comment out to disable
#define ASSERT_USE_BOOST_STATIC_ASSERT
#define ASSERT_USE_BOOST_MPL_ASSERT
#define ASSERT_USE_BOOST_MPL_ASSERT_MSG
#define ASSERT_USE_KUODO_TYPES_ASSERT
#define ASSERT_USE_KUODO_TYPES_TYPE_ASSERT

// comment out to not assert
#define ASSERT_NAMESPACE
#define ASSERT_FUNCTION
#define ASSERT_CLASS
#define ASSERT_MEMBER_FUNCTION
#define ASSERT_DEEP

#include <iterator>
#include <list>
#include <vector>
#include "assert.hpp"

//BOOST_STATIC_ASSERT
#ifdef ASSERT_USE_BOOST_STATIC_ASSERT
  #include <boost/static_assert.hpp>
  #define ASSERT_BOOST_STATIC_ASSERT(a) BOOST_STATIC_ASSERT(a)
#else
  #define ASSERT_BOOST_STATIC_ASSERT(a) typedef void no_boost_static_assert
#endif

//BOOST_MPL_ASSERT
#ifdef ASSERT_USE_BOOST_MPL_ASSERT
  #include <boost/mpl/assert.hpp>
  #define ASSERT_BOOST_MPL_ASSERT(a) BOOST_MPL_ASSERT(a)
#else
  #define ASSERT_BOOST_MPL_ASSERT(a) typedef void no_boost_mpl_assert
#endif

//BOOST_MPL_ASSERT_MSG
#ifdef ASSERT_USE_BOOST_MPL_ASSERT_MSG
  #include <boost/mpl/assert.hpp>
  #define ASSERT_BOOST_MPL_ASSERT_MSG(a, b, c) BOOST_MPL_ASSERT_MSG(a, b, c)
#else
  #define ASSERT_BOOST_MPL_ASSERT_MSG(a, b, c) typedef void no_boost_mpl_assert_msg
#endif

namespace tests {

  //kuodo::types::assert
  #ifdef ASSERT_USE_KUODO_TYPES_ASSERT
    using kuodo::types::assert;
  #else
    template<int int_> struct assert {};
  #endif

  //kuodo::types::type_assert
  #ifdef ASSERT_USE_KUODO_TYPES_TYPE_ASSERT
    using kuodo::types::type_assert;
  #else
    template<typename type_> struct type_assert {};
  #endif

  using kuodo::types::assertion;

  template<bool value_> struct
   bool_value {
    static bool const value = value_;
    typedef bool value_type;
    typedef bool_value<value_> type;
    operator bool() const { return value_; }
    };
    template<bool value_>
     bool const bool_value<value_>::value;


  // namespace scope
  /////////////////////////////////////////////////////////////////////

  bool const namespace_assert_if =
    #ifdef ASSERT_NAMESPACE
    false;
    #else
    true;
    #endif

  template<typename type_> struct
   namespace_assert :
    assertion<namespace_assert_if>
      {};

  ASSERT_BOOST_STATIC_ASSERT(namespace_assert_if);
  ASSERT_BOOST_MPL_ASSERT((bool_value<namespace_assert_if>));
  ASSERT_BOOST_MPL_ASSERT_MSG(namespace_assert_if, NAMESPACE_ASSERT, (int));
  typedef assert<namespace_assert_if> assert_1;
  typedef type_assert<namespace_assert<int> > assert_2;
  
  
  // function scope
  /////////////////////////////////////////////////////////////////////

  template<typename type_> struct
   is_pointer :
    bool_value<false>
      {};
  template<typename type_> struct
   is_pointer<type_*> :
    bool_value<true>
      {};
      
  template<typename type_> struct
   not_pointer :
    assertion<is_pointer<type_>::value>
      {};

  template<typename type_>
   int function(type_ const&) {
    ASSERT_BOOST_STATIC_ASSERT(is_pointer<type_>::value);
    ASSERT_BOOST_MPL_ASSERT((is_pointer<type_>));
    ASSERT_BOOST_MPL_ASSERT_MSG((is_pointer<type_>::value), NOT_POINTER, (type_));
    typedef assert<is_pointer<type_>::value> assert_1;
    typedef type_assert<not_pointer<type_> > assert_2;
    return 0;
    }
    
  int use_function =
    #ifdef ASSERT_FUNCTION
    function(std::vector<int>());
    #else
    function(static_cast<void*>(0));
    #endif
  
  
  // class scope
  /////////////////////////////////////////////////////////////////////

  bool test_random_access(std::random_access_iterator_tag const*);
  bool (&test_random_access(void const*))[2];

  template<typename category_> struct
   is_random_access :
    bool_value< //use ::tests::test_random... or gcc 3.3
      sizeof(::tests::test_random_access(static_cast<category_*>(0))) == sizeof(true)
      > {};

  template<typename iterator_>
   class class_scope {
    typedef typename std::iterator_traits<iterator_>::iterator_category category_type;
    template<typename category_> struct
     not_random_access :
      assertion<is_random_access<category_>::value>
        {};
    ASSERT_BOOST_STATIC_ASSERT(is_random_access<category_type>::value);
    ASSERT_BOOST_MPL_ASSERT((is_random_access<category_type>));
    ASSERT_BOOST_MPL_ASSERT_MSG((is_random_access<category_type>::value), NOT_RANDOM_ACCESS, (iterator_, category_type));
    typedef assert<is_random_access<category_type>::value> assert_1;
    typedef type_assert<not_random_access<category_type> > assert_2;
    };
  
  #ifdef ASSERT_CLASS
  class_scope<std::list<int>::iterator> use_class_scope;
  #else
  class_scope<std::vector<int>::iterator> use_class_scope;
  #endif
  
  
  // class member function scope
  /////////////////////////////////////////////////////////////////////

  template<typename iterator_>
   class member_function {
    //typedef typename std::iterator_traits<iterator_>::iterator_category category_type;
    template<typename category_> struct
     not_random_access :
      assertion<is_random_access<category_>::value>
        {};
    public:
      int function() const {
        //with boost 1.33.0 and codewarrior 10 (mac):
        //BOOST_MPL_ASSERT_MSG on does not work if category_type is private to the class
        typedef typename std::iterator_traits<iterator_>::iterator_category category_type;
        ASSERT_BOOST_STATIC_ASSERT(is_random_access<category_type>::value);
        ASSERT_BOOST_MPL_ASSERT((is_random_access<category_type>));
        ASSERT_BOOST_MPL_ASSERT_MSG((is_random_access<category_type>::value), NOT_RANDOM_ACCESS, (iterator_, category_type));  
        typedef assert<is_random_access<category_type>::value> assert_1;  
        typedef type_assert<not_random_access<category_type> > assert_2;  
        return 0;
        }
    };

  int use_member_function =
    #ifdef ASSERT_MEMBER_FUNCTION
    member_function<std::list<int>::iterator>().function();
    #else
    member_function<std::vector<int>::iterator>().function();
    #endif

} //namespace tests

int main(int /*argc*/, char** /*argv*/) { return 0; }