Home | History | Annotate | Download | only in unit
      1 /* boost limits_test.cpp   test your <limits> file for important
      2  *
      3  * Copyright Jens Maurer 2000
      4  * Permission to use, copy, modify, sell, and distribute this software
      5  * is hereby granted without fee provided that the above copyright notice
      6  * appears in all copies and that both that copyright notice and this
      7  * permission notice appear in supporting documentation,
      8  *
      9  * Jens Maurer makes no representations about the suitability of this
     10  * software for any purpose. It is provided "as is" without express or
     11  * implied warranty.
     12  *
     13  */
     14 
     15 #include <limits>
     16 //#include <sstream>
     17 
     18 #include "cppunit/cppunit_proxy.h"
     19 
     20 #if !defined (STLPORT) || defined(_STLP_USE_NAMESPACES)
     21 using namespace std;
     22 #endif
     23 
     24 //
     25 // TestCase class
     26 //
     27 class LimitTest : public CPPUNIT_NS::TestCase
     28 {
     29   CPPUNIT_TEST_SUITE(LimitTest);
     30 #  if defined (__BORLANDC__)
     31   /* Ignore FPU exceptions, set FPU precision to 64 bits */
     32   unsigned int _float_control_word = _control87(0, 0);
     33   _control87(PC_64|MCW_EM|IC_AFFINE, MCW_PC|MCW_EM|MCW_IC);
     34 #  endif
     35   CPPUNIT_TEST(test);
     36   CPPUNIT_TEST(qnan_test);
     37 #  if defined (__BORLANDC__)
     38   /* Reset floating point control word */
     39   _clear87();
     40   _control87(_float_control_word, MCW_PC|MCW_EM|MCW_IC);
     41 #  endif
     42   CPPUNIT_TEST_SUITE_END();
     43 
     44 protected:
     45   void test();
     46   void qnan_test();
     47 };
     48 
     49 CPPUNIT_TEST_SUITE_REGISTRATION(LimitTest);
     50 
     51 #if defined (STLPORT) && defined (_STLP_STATIC_CONST_INIT_BUG)
     52 #  define CHECK_COND(X) if (!(X))  { CPPUNIT_MESSAGE(#X); return false; }
     53 #else
     54 //This version force to have external linkage on static constant which might
     55 //reveal that _STLP_NO_STATIC_CONST_DEFINITION should be commented.
     56 bool check_cond(const bool& cond) { return cond; }
     57 #  define CHECK_COND(X) if (!check_cond(X)) { CPPUNIT_MESSAGE(#X); return false; }
     58 #endif
     59 
     60 bool valid_sign_info(bool, bool)
     61 { return true; }
     62 
     63 template <class _Tp>
     64 bool valid_sign_info(bool limit_is_signed, const _Tp &) {
     65   return (limit_is_signed && _Tp(-1) < 0) ||
     66          (!limit_is_signed && _Tp(-1) > 0);
     67 }
     68 
     69 template <class _Tp>
     70 bool test_integral_limits_base(const _Tp &, bool unknown_sign = true, bool is_signed = true) {
     71   typedef numeric_limits<_Tp> lim;
     72 
     73   CHECK_COND(lim::is_specialized);
     74   CHECK_COND(lim::is_exact);
     75   CHECK_COND(lim::is_integer);
     76   CHECK_COND(!lim::is_iec559);
     77   CHECK_COND(lim::min() < lim::max());
     78   CHECK_COND((unknown_sign && ((lim::is_signed && (lim::min() != 0)) || (!lim::is_signed && (lim::min() == 0)))) ||
     79              (!unknown_sign && ((lim::is_signed && is_signed) || (!lim::is_signed && !is_signed))));
     80 
     81   if (unknown_sign) {
     82     CHECK_COND(valid_sign_info(lim::is_signed, _Tp()));
     83   }
     84   return true;
     85 }
     86 
     87 template <class _Tp>
     88 bool test_integral_limits(const _Tp &val, bool unknown_sign = true, bool is_signed = true) {
     89   if (!test_integral_limits_base(val, unknown_sign, is_signed))
     90     return false;
     91 
     92   typedef numeric_limits<_Tp> lim;
     93 
     94   CHECK_COND(lim::is_modulo);
     95 
     96   if (lim::is_bounded ||
     97      (!lim::is_bounded && !lim::is_signed)) {
     98     _Tp tmp = lim::min();
     99     CHECK_COND( --tmp > lim::min() );
    100   }
    101 
    102   if (lim::is_bounded) {
    103     _Tp tmp = lim::max();
    104     CHECK_COND( ++tmp < lim::max() );
    105   }
    106 
    107   return true;
    108 }
    109 
    110 template <class _Tp>
    111 bool test_signed_integral_limits(const _Tp &__val) {
    112   return test_integral_limits(__val, false, true);
    113 }
    114 template <class _Tp>
    115 bool test_unsigned_integral_limits(const _Tp &__val) {
    116   return test_integral_limits(__val, false, false);
    117 }
    118 
    119 template <class _Tp>
    120 bool test_float_values(_Tp lhs, _Tp rhs)
    121 { return lhs == rhs; }
    122 
    123 template <class _Tp>
    124 bool test_float_limits(const _Tp &) {
    125   typedef numeric_limits<_Tp> lim;
    126   CHECK_COND(lim::is_specialized);
    127   CHECK_COND(!lim::is_modulo);
    128   CHECK_COND(!lim::is_integer);
    129   CHECK_COND(lim::is_signed);
    130 
    131   CHECK_COND(lim::max() > 1000);
    132   CHECK_COND(lim::min() > 0);
    133   CHECK_COND(lim::min() < 0.001);
    134   CHECK_COND(lim::epsilon() > 0);
    135 
    136   if (lim::is_iec559) {
    137     CHECK_COND(lim::has_infinity);
    138     CHECK_COND(lim::has_quiet_NaN);
    139     CHECK_COND(lim::has_signaling_NaN);
    140     CHECK_COND(lim::has_denorm == denorm_present);
    141   }
    142 
    143   if (lim::has_denorm == denorm_absent) {
    144     CHECK_COND(lim::denorm_min() == lim::min());
    145     _Tp tmp = lim::min();
    146     tmp /= 2;
    147     if (tmp > 0 && tmp < lim::min()) {
    148       // has_denorm could be denorm_present
    149       CPPUNIT_MESSAGE("It looks like your compiler/platform supports denormalized floating point representation.");
    150     }
    151   }
    152   else if (lim::has_denorm == denorm_present) {
    153     CHECK_COND(lim::denorm_min() > 0);
    154     CHECK_COND(lim::denorm_min() < lim::min());
    155 
    156     _Tp tmp = lim::min();
    157     while (tmp != 0) {
    158       _Tp old_tmp = tmp;
    159       tmp /= 2;
    160       CHECK_COND(tmp < old_tmp);
    161       CHECK_COND(tmp >= lim::denorm_min() || tmp == (_Tp)0);
    162       //ostringstream str;
    163       //str << "denorm_min = " << lim::denorm_min() << ", tmp = " << tmp;
    164       //CPPUNIT_MESSAGE(str.str().c_str());
    165     }
    166   }
    167 
    168   if (lim::has_infinity) {
    169     const _Tp infinity = lim::infinity();
    170     /* Make sure those values are not 0 or similar nonsense.
    171      * Infinity must compare as if larger than the maximum representable value. */
    172 
    173     _Tp val = lim::max();
    174     val *= 2;
    175 
    176     /* We use test_float_values because without it some compilers (gcc) perform weird
    177      * optimization on the test giving unexpected result. */
    178     CHECK_COND(test_float_values(val, infinity));
    179 
    180     /*
    181     ostringstream str;
    182     str << "lim::max() = " << lim::max() << ", val = " << val << ", infinity = " << infinity;
    183     CPPUNIT_MESSAGE( str.str().c_str() );
    184     str.str(string());
    185     str << "sizeof(_Tp) = " << sizeof(_Tp);
    186     CPPUNIT_MESSAGE( str.str().c_str() );
    187     if (sizeof(_Tp) == 4) {
    188       str.str(string());
    189       str << "val in hexa: " << showbase << hex << *((const unsigned int*)&val);
    190       str << ", infinity in hexa: " << showbase << hex << *((const unsigned int*)&infinity);
    191     }
    192 #if defined (_STLP_LONG_LONG)
    193     else if (sizeof(_Tp) == sizeof(_STLP_LONG_LONG)) {
    194       str.str(string());
    195       str << "val in hexa: " << showbase << hex << *((const unsigned _STLP_LONG_LONG*)&val);
    196       str << ", infinity in hexa: " << showbase << hex << *((const unsigned _STLP_LONG_LONG*)&infinity);
    197     }
    198 #endif
    199     else {
    200       str.str(string());
    201       str << "val: ";
    202       for (int i = 0; i != sizeof(_Tp) /  sizeof(unsigned short); ++i) {
    203         if (i != 0) str << ' ';
    204         str << showbase << hex << setw(4) << setfill('0') << *((const unsigned short*)&val + i);
    205       }
    206       str << ", infinity: ";
    207       for (int i = 0; i != sizeof(_Tp) /  sizeof(unsigned short); ++i) {
    208         if (i != 0) str << ' ';
    209         str << showbase << hex << setw(4) << setfill('0') << *((const unsigned short*)&infinity + i);
    210       }
    211     }
    212     CPPUNIT_MESSAGE( str.str().c_str() );
    213     str.str(string());
    214     str << dec;
    215     str << "lim::digits = " << lim::digits << ", lim::digits10 = " << lim::digits10 << endl;
    216     str << "lim::min_exponent = " << lim::min_exponent << ", lim::min_exponent10 = " << lim::min_exponent10 << endl;
    217     str << "lim::max_exponent = " << lim::max_exponent << ", lim::max_exponent10 = " << lim::max_exponent10 << endl;
    218     CPPUNIT_MESSAGE( str.str().c_str() );
    219     */
    220 
    221     CHECK_COND(infinity == infinity);
    222     CHECK_COND(infinity > lim::max());
    223     CHECK_COND(-infinity < -lim::max());
    224   }
    225 
    226   return true;
    227 }
    228 
    229 //float generate_nan(float f) {
    230 //  return 0.0f / f;
    231 //}
    232 template <class _Tp>
    233 bool test_qnan(const _Tp &) {
    234   typedef numeric_limits<_Tp> lim;
    235   if (lim::has_quiet_NaN) {
    236     const _Tp qnan = lim::quiet_NaN();
    237 
    238     //if (sizeof(_Tp) == 4) {
    239     //  ostringstream str;
    240     //  str << "qnan " << qnan << ", in hexa: " << showbase << hex << *((unsigned int*)&qnan);
    241     //  CPPUNIT_MESSAGE( str.str().c_str() );
    242     //  str.str("");
    243     //  float val = generate_nan(0.0f);
    244     //  str << "val " << val << ", in hexa: " << showbase << hex << *((unsigned int*)&val);
    245     //  CPPUNIT_MESSAGE( str.str().c_str() );
    246     //  str.str("");
    247     //  val = -qnan;
    248     //  str << "-qnan " << val << ", in hexa: " << showbase << hex << *((unsigned int*)&val);
    249     //  CPPUNIT_MESSAGE( str.str().c_str() );
    250     //}
    251     /* NaNs shall always compare "false" when compared for equality
    252     * If one of these fail, your compiler may be optimizing incorrectly,
    253     * or the STLport is incorrectly configured.
    254     */
    255     CHECK_COND(! (qnan == 42));
    256     CHECK_COND(! (qnan == qnan));
    257     CHECK_COND(qnan != 42);
    258     CHECK_COND(qnan != qnan);
    259 
    260     /* The following tests may cause arithmetic traps.
    261     * CHECK_COND(! (qnan < 42));
    262     * CHECK_COND(! (qnan > 42));
    263     * CHECK_COND(! (qnan <= 42));
    264     * CHECK_COND(! (qnan >= 42));
    265     */
    266   }
    267   return true;
    268 }
    269 
    270 
    271 class ArbitraryType
    272 {};
    273 
    274 void LimitTest::test() {
    275   CPPUNIT_CHECK(test_integral_limits_base(bool()));
    276   CPPUNIT_CHECK(test_integral_limits(char()));
    277   typedef signed char signed_char;
    278   CPPUNIT_CHECK(test_signed_integral_limits(signed_char()));
    279   typedef unsigned char unsigned_char;
    280   CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_char()));
    281 #  if defined (_STLP_HAS_WCHAR_T) && !defined (_STLP_WCHAR_T_IS_USHORT)
    282   CPPUNIT_CHECK(test_integral_limits(wchar_t()));
    283 #  endif
    284   CPPUNIT_CHECK(test_signed_integral_limits(short()));
    285   typedef unsigned short unsigned_short;
    286   CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_short()));
    287   CPPUNIT_CHECK(test_signed_integral_limits(int()));
    288   typedef unsigned int unsigned_int;
    289   CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_int()));
    290   CPPUNIT_CHECK(test_signed_integral_limits(long()));
    291   typedef unsigned long unsigned_long;
    292   CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_long()));
    293 #  if defined (_STLP_LONG_LONG)
    294   typedef _STLP_LONG_LONG long_long;
    295   CPPUNIT_CHECK(test_signed_integral_limits(long_long()));
    296   typedef unsigned _STLP_LONG_LONG unsigned_long_long;
    297   CPPUNIT_CHECK(test_unsigned_integral_limits(unsigned_long_long()));
    298 #endif
    299 
    300   CPPUNIT_CHECK(test_float_limits(float()));
    301   CPPUNIT_CHECK(test_float_limits(double()));
    302 #  if !defined ( _STLP_NO_LONG_DOUBLE )
    303   typedef long double long_double;
    304   CPPUNIT_CHECK(test_float_limits(long_double()));
    305 #  endif
    306 
    307   CPPUNIT_ASSERT( !numeric_limits<ArbitraryType>::is_specialized );
    308 }
    309 
    310 void LimitTest::qnan_test() {
    311   CPPUNIT_CHECK(test_qnan(float()));
    312   CPPUNIT_CHECK(test_qnan(double()));
    313 #  if !defined ( _STLP_NO_LONG_DOUBLE )
    314   typedef long double long_double;
    315   CPPUNIT_CHECK(test_qnan(long_double()));
    316 #  endif
    317 }
    318