From 88244b57d49c658b70d7a367f837206f6b769611 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Tue, 3 Jul 2012 17:10:02 +0000 Subject: [PATCH] Split lexical_cast_test.cpp into two tests and reduce iterations count for integral types tests (now we must not exceed tests timeouts) [SVN r79246] --- lexical_cast_test.cpp | 477 +------------------ test/Jamfile.v2 | 1 + test/lexical_cast_integral_types_test.cpp | 539 ++++++++++++++++++++++ 3 files changed, 546 insertions(+), 471 deletions(-) create mode 100644 test/lexical_cast_integral_types_test.cpp diff --git a/lexical_cast_test.cpp b/lexical_cast_test.cpp index 844ee71..e7adc86 100644 --- a/lexical_cast_test.cpp +++ b/lexical_cast_test.cpp @@ -4,7 +4,7 @@ // // Copyright Terje Sletteb and Kevlin Henney, 2005. // Copyright Alexander Nasonov, 2006. -// Copyright Antony Polukhin, 2011. +// Copyright Antony Polukhin, 2011-2012. // // Distributed under the Boost // Software License, Version 1.0. (See accompanying file @@ -57,13 +57,6 @@ struct my_allocator : std::allocator { }; -// Test all 65536 values if true: -bool const lcast_test_small_integral_types_completely = false; - -// lcast_integral_test_counter: use when testing all values of an integral -// types is not possible. Max. portable value is 32767. -int const lcast_integral_test_counter=1000; - using namespace boost; void test_conversion_to_char(); @@ -80,18 +73,6 @@ void test_conversion_from_wstring(); void test_conversion_to_wstring(); void test_bad_lexical_cast(); void test_no_whitespace_stripping(); -void test_conversion_from_to_short(); -void test_conversion_from_to_ushort(); -void test_conversion_from_to_int(); -void test_conversion_from_to_uint(); -void test_conversion_from_to_long(); -void test_conversion_from_to_ulong(); -void test_conversion_from_to_intmax_t(); -void test_conversion_from_to_uintmax_t(); -#ifdef LCAST_TEST_LONGLONG -void test_conversion_from_to_longlong(); -void test_conversion_from_to_ulonglong(); -#endif #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION void test_traits(); void test_wtraits(); @@ -107,7 +88,6 @@ void test_char16_conversions(); void test_char32_conversions(); #endif - unit_test::test_suite *init_unit_test_suite(int, char *[]) { unit_test::test_suite *suite = @@ -128,18 +108,6 @@ unit_test::test_suite *init_unit_test_suite(int, char *[]) #endif suite->add(BOOST_TEST_CASE(test_bad_lexical_cast)); suite->add(BOOST_TEST_CASE(test_no_whitespace_stripping)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_short)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ushort)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_int)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uint)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulong)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_intmax_t)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uintmax_t)); -#ifdef LCAST_TEST_LONGLONG - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong)); - suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong)); -#endif #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION suite->add(BOOST_TEST_CASE(&test_traits)); suite->add(BOOST_TEST_CASE(&test_wtraits)); @@ -399,6 +367,7 @@ void test_conversion_to_wchar_t() BOOST_CHECK_THROW( lexical_cast(std::wstring(L"Test")), bad_lexical_cast); #endif + BOOST_CHECK(true); } void test_conversion_from_wstring() @@ -417,6 +386,7 @@ void test_conversion_from_wstring() BOOST_CHECK_THROW( lexical_cast(std::wstring(L"Test")), bad_lexical_cast); #endif + BOOST_CHECK(true); } void test_conversion_to_wstring() @@ -441,6 +411,7 @@ void test_conversion_to_wstring() BOOST_CHECK(L" " == lexical_cast(std::wstring(L" "))); BOOST_CHECK(L"" == lexical_cast(std::wstring(L""))); #endif + BOOST_CHECK(true); } void test_bad_lexical_cast() @@ -464,444 +435,6 @@ void test_no_whitespace_stripping() BOOST_CHECK_THROW(lexical_cast("123 "), bad_lexical_cast); } -// Replace "-,999" with "-999". -template -std::basic_string to_str_gcc_workaround(std::basic_string str) -{ - std::locale loc; - std::numpunct const& np = BOOST_USE_FACET(std::numpunct, loc); - std::ctype const& ct = BOOST_USE_FACET(std::ctype, loc); - - if(np.grouping().empty()) - return str; - - CharT prefix[3] = { ct.widen('-'), np.thousands_sep(), CharT() }; - - if(str.find(prefix) != 0) - return str; - - prefix[1] = CharT(); - str.replace(0, 2, prefix); - return str; -} - -template -std::basic_string to_str(T t) -{ - std::basic_ostringstream o; - o << t; - return to_str_gcc_workaround(o.str()); -} - -template -void test_conversion_from_integral_to_char(CharT zero) -{ - BOOST_CHECK(lexical_cast(static_cast(0)) == zero + 0); - BOOST_CHECK(lexical_cast(static_cast(1)) == zero + 1); - BOOST_CHECK(lexical_cast(static_cast(2)) == zero + 2); - BOOST_CHECK(lexical_cast(static_cast(3)) == zero + 3); - BOOST_CHECK(lexical_cast(static_cast(4)) == zero + 4); - BOOST_CHECK(lexical_cast(static_cast(5)) == zero + 5); - BOOST_CHECK(lexical_cast(static_cast(6)) == zero + 6); - BOOST_CHECK(lexical_cast(static_cast(7)) == zero + 7); - BOOST_CHECK(lexical_cast(static_cast(8)) == zero + 8); - BOOST_CHECK(lexical_cast(static_cast(9)) == zero + 9); - - BOOST_CHECK_THROW(lexical_cast(static_cast(10)), bad_lexical_cast); - - T t = (std::numeric_limits::max)(); - BOOST_CHECK_THROW(lexical_cast(t), bad_lexical_cast); -} - -template -void test_conversion_from_char_to_integral(CharT zero) -{ - BOOST_CHECK(lexical_cast( static_cast(zero + 0)) == static_cast(0) ); - BOOST_CHECK(lexical_cast( static_cast(zero + 1)) == static_cast(1) ); - BOOST_CHECK(lexical_cast( static_cast(zero + 2)) == static_cast(2) ); - BOOST_CHECK(lexical_cast( static_cast(zero + 3)) == static_cast(3) ); - BOOST_CHECK(lexical_cast( static_cast(zero + 4)) == static_cast(4) ); - BOOST_CHECK(lexical_cast( static_cast(zero + 5)) == static_cast(5) ); - BOOST_CHECK(lexical_cast( static_cast(zero + 6)) == static_cast(6) ); - BOOST_CHECK(lexical_cast( static_cast(zero + 7)) == static_cast(7) ); - BOOST_CHECK(lexical_cast( static_cast(zero + 8)) == static_cast(8) ); - BOOST_CHECK(lexical_cast( static_cast(zero + 9)) == static_cast(9) ); - - BOOST_CHECK_THROW(lexical_cast( static_cast(zero + 10)), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast( static_cast(zero - 1)), bad_lexical_cast); -} - -template -void test_conversion_from_integral_to_integral() -{ - T t = 0; - BOOST_CHECK(lexical_cast(t) == t); - - // Next two variables are used to supress warnings. - int st = 32767; unsigned int ut = st; - t = st; - BOOST_CHECK(lexical_cast(t) == st); - BOOST_CHECK(lexical_cast(t) == ut); - BOOST_CHECK(lexical_cast(t) == st); - BOOST_CHECK(lexical_cast(t) == ut); - BOOST_CHECK(lexical_cast(t) == st); - BOOST_CHECK(lexical_cast(t) == ut); - - t = (std::numeric_limits::max)(); - BOOST_CHECK(lexical_cast(t) == t); - - t = (std::numeric_limits::min)(); - BOOST_CHECK(lexical_cast(t) == t); -} - -template -void test_conversion_from_integral_to_string(CharT) -{ - typedef std::numeric_limits limits; - typedef std::basic_string string_type; - - T t; - - t = (limits::min)(); - BOOST_CHECK(lexical_cast(t) == to_str(t)); - - t = (limits::max)(); - BOOST_CHECK(lexical_cast(t) == to_str(t)); - - if(limits::digits <= 16 && lcast_test_small_integral_types_completely) - // min and max have already been tested. - for(t = 1 + (limits::min)(); t != (limits::max)(); ++t) - BOOST_CHECK(lexical_cast(t) == to_str(t)); - else - { - T const min_val = (limits::min)(); - T const max_val = (limits::max)(); - T const half_max_val = max_val / 2; - T const cnt = lcast_integral_test_counter; // to supress warnings - unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; - - unsigned int i; - - // Test values around min: - t = min_val; - for(i = 0; i < counter; ++i, ++t) - BOOST_CHECK(lexical_cast(t) == to_str(t)); - - // Test values around max: - t = max_val; - for(i = 0; i < counter; ++i, --t) - BOOST_CHECK(lexical_cast(t) == to_str(t)); - - // Test values around zero: - if(limits::is_signed) - for(t = static_cast(-counter); t < static_cast(counter); ++t) - BOOST_CHECK(lexical_cast(t) == to_str(t)); - - // Test values around 100, 1000, 10000, ... - T ten_power = 100; - for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) - { - // ten_power + 100 probably never overflows - for(t = ten_power - 100; t != ten_power + 100; ++t) - BOOST_CHECK(lexical_cast(t) == to_str(t)); - } - } -} - -template -void test_conversion_from_string_to_integral(CharT) -{ - typedef std::numeric_limits limits; - typedef std::basic_string string_type; - - string_type s; - string_type const zero = to_str(0); - string_type const nine = to_str(9); - T const min_val = (limits::min)(); - T const max_val = (limits::max)(); - - s = to_str(min_val); - BOOST_CHECK_EQUAL(lexical_cast(s), min_val); - if(limits::is_signed) - { - BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); - } - - s = to_str(max_val); - BOOST_CHECK_EQUAL(lexical_cast(s), max_val); - { - BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); - - s = to_str(max_val); - for (int i =1; i <=10; ++i) { - s[s.size()-1] += 1; - BOOST_CHECK_THROW(lexical_cast( s ), bad_lexical_cast); - } - - s = to_str(max_val); - std::locale loc; - typedef std::numpunct numpunct; - if ( BOOST_USE_FACET(numpunct, loc).grouping().empty() ) { - // Following tests work well for locale C - BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+s), max_val); - BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+to_str(0)+s), max_val); - BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+to_str(0)+to_str(0)+s), max_val); - } - - for (int i =1; i <=256; ++i) { - BOOST_CHECK_THROW(lexical_cast( to_str(i)+s ), bad_lexical_cast); - } - - typedef BOOST_DEDUCED_TYPENAME boost::integral_promotion::type promoted; - if ( !(boost::is_same::value) ) - { - promoted prom = max_val; - s = to_str(max_val); - for (int i =1; i <=256; ++i) { - BOOST_CHECK_THROW(lexical_cast( to_str(prom+i) ), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast( to_str(i)+s ), bad_lexical_cast); - } - } - } - - if(limits::digits <= 16 && lcast_test_small_integral_types_completely) - // min and max have already been tested. - for(T t = 1 + min_val; t != max_val; ++t) - BOOST_CHECK(lexical_cast(to_str(t)) == t); - else - { - T const half_max_val = max_val / 2; - T const cnt = lcast_integral_test_counter; // to supress warnings - unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; - - T t; - unsigned int i; - - // Test values around min: - t = min_val; - for(i = 0; i < counter; ++i, ++t) - BOOST_CHECK(lexical_cast(to_str(t)) == t); - - // Test values around max: - t = max_val; - for(i = 0; i < counter; ++i, --t) - BOOST_CHECK(lexical_cast(to_str(t)) == t); - - // Test values around zero: - if(limits::is_signed) - for(t = static_cast(-counter); t < static_cast(counter); ++t) - BOOST_CHECK(lexical_cast(to_str(t)) == t); - - // Test values around 100, 1000, 10000, ... - T ten_power = 100; - for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) - { - // ten_power + 100 probably never overflows - for(t = ten_power - 100; t != ten_power + 100; ++t) - BOOST_CHECK(lexical_cast(to_str(t)) == t); - } - } -} - -template -void test_conversion_from_to_integral_for_locale() -{ - std::locale current_locale; - typedef std::numpunct numpunct; - numpunct const& np = BOOST_USE_FACET(numpunct, current_locale); - if ( !np.grouping().empty() ) - { - BOOST_CHECK_THROW( - lexical_cast( std::string("100") + np.thousands_sep() + np.thousands_sep() + "0" ) - , bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast( std::string("100") + np.thousands_sep() ), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast( np.thousands_sep() + std::string("100") ), bad_lexical_cast); - - // Exception must not be thrown, when we are using no separators at all - BOOST_CHECK( lexical_cast("30000") == static_cast(30000) ); - } - - test_conversion_from_integral_to_integral(); - test_conversion_from_integral_to_string('0'); - test_conversion_from_string_to_integral('0'); -#if !defined(BOOST_LCAST_NO_WCHAR_T) - test_conversion_from_integral_to_string(L'0'); - test_conversion_from_string_to_integral(L'0'); -#endif -} - -struct restore_oldloc -{ - std::locale oldloc; - ~restore_oldloc() { std::locale::global(oldloc); } -}; - -template -void test_conversion_from_to_integral() -{ - char const zero = '0'; - signed char const szero = '0'; - unsigned char const uzero = '0'; - test_conversion_from_integral_to_char(zero); - test_conversion_from_char_to_integral(zero); - test_conversion_from_integral_to_char(szero); - test_conversion_from_char_to_integral(szero); - test_conversion_from_integral_to_char(uzero); - test_conversion_from_char_to_integral(uzero); -#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) - wchar_t const wzero = L'0'; - test_conversion_from_integral_to_char(wzero); - test_conversion_from_char_to_integral(wzero); -#endif -#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) - char16_t const u16zero = u'0'; - test_conversion_from_integral_to_char(u16zero); - test_conversion_from_char_to_integral(u16zero); -#endif -#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) - char32_t const u32zero = u'0'; - test_conversion_from_integral_to_char(u32zero); - test_conversion_from_char_to_integral(u32zero); -#endif - - BOOST_CHECK(lexical_cast("-1") == static_cast(-1)); - BOOST_CHECK(lexical_cast("-9") == static_cast(-9)); - BOOST_CHECK(lexical_cast(-1) == static_cast(-1)); - BOOST_CHECK(lexical_cast(-9) == static_cast(-9)); - - BOOST_CHECK_THROW(lexical_cast("-1.0"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("-9.0"), bad_lexical_cast); - BOOST_CHECK(lexical_cast(-1.0) == static_cast(-1)); - BOOST_CHECK(lexical_cast(-9.0) == static_cast(-9)); - - BOOST_CHECK(lexical_cast(static_cast(1)) == static_cast(1)); - BOOST_CHECK(lexical_cast(static_cast(9)) == static_cast(9)); - BOOST_CHECK_THROW(lexical_cast(1.1f), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(1.1), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(1.1L), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(1.0001f), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(1.0001), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(1.0001L), bad_lexical_cast); - - BOOST_CHECK(lexical_cast("+1") == static_cast(1) ); - BOOST_CHECK(lexical_cast("+9") == static_cast(9) ); - BOOST_CHECK(lexical_cast("+10") == static_cast(10) ); - BOOST_CHECK(lexical_cast("+90") == static_cast(90) ); - BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("--1"), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); - // test_conversion_from_to_integral_for_locale - - // Overflow test case from David W. Birdsall - std::string must_owerflow_str = "160000000000000000000"; - std::string must_owerflow_negative_str = "-160000000000000000000"; - for (int i = 0; i < 15; ++i) { - BOOST_CHECK_THROW(lexical_cast(must_owerflow_str), bad_lexical_cast); - BOOST_CHECK_THROW(lexical_cast(must_owerflow_negative_str), bad_lexical_cast); - - must_owerflow_str += '0'; - must_owerflow_negative_str += '0'; - } - - typedef std::numpunct numpunct; - - restore_oldloc guard; - std::locale const& oldloc = guard.oldloc; - - std::string grouping1 = BOOST_USE_FACET(numpunct, oldloc).grouping(); - std::string grouping2(grouping1); - - test_conversion_from_to_integral_for_locale(); - - try - { - std::locale newloc(""); - std::locale::global(newloc); - - grouping2 = BOOST_USE_FACET(numpunct, newloc).grouping(); - } - catch(std::exception const& ex) - { - std::string msg("Failed to set system locale: "); - msg += ex.what(); - BOOST_TEST_MESSAGE(msg); - } - - if(grouping1 != grouping2) - test_conversion_from_to_integral_for_locale(); - - if(grouping1.empty() && grouping2.empty()) - BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); -} - -void test_conversion_from_to_short() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_ushort() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_int() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_uint() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_long() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_ulong() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_intmax_t() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_uintmax_t() -{ - test_conversion_from_to_integral(); -} - -#if defined(BOOST_HAS_LONG_LONG) - -void test_conversion_from_to_longlong() -{ - test_conversion_from_to_integral(); -} - -void test_conversion_from_to_ulonglong() -{ - test_conversion_from_to_integral(); -} - -#elif defined(BOOST_HAS_MS_INT64) - -void test_conversion_from_to_longlong() -{ - test_conversion_from_to_integral<__int64>(); -} - -void test_conversion_from_to_ulonglong() -{ - test_conversion_from_to_integral(); -} - -#endif #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION void test_traits() @@ -960,6 +493,7 @@ void test_wallocator() #endif + void test_char_types_conversions() { const char c_arr[] = "Test array of chars"; @@ -1040,3 +574,4 @@ void test_char32_conversions() } #endif + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 474f689..f77a845 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -48,5 +48,6 @@ test-suite conversion ] [ run lexical_cast_iterator_range_test.cpp ] [ run lexical_cast_arrays_test.cpp ] + [ run lexical_cast_integral_types_test.cpp ] ; diff --git a/test/lexical_cast_integral_types_test.cpp b/test/lexical_cast_integral_types_test.cpp new file mode 100644 index 0000000..2cbdbf5 --- /dev/null +++ b/test/lexical_cast_integral_types_test.cpp @@ -0,0 +1,539 @@ +// Unit test for boost::lexical_cast. +// +// See http://www.boost.org for most recent version, including documentation. +// +// Copyright Terje Sletteb and Kevlin Henney, 2005. +// Copyright Alexander Nasonov, 2006. +// Copyright Antony Polukhin, 2011-2012. +// +// Distributed under 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). +// +// Note: The unit test no longer compile on MSVC 6, but lexical_cast itself works for it. + +// +// We need this #define before any #includes: otherwise msvc will emit warnings +// deep within std::string, resulting from our (perfectly legal) use of basic_string +// with a custom traits class: +// +#define _SCL_SECURE_NO_WARNINGS + +#include + +#if defined(__INTEL_COMPILER) +#pragma warning(disable: 193 383 488 981 1418 1419) +#elif defined(BOOST_MSVC) +#pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800) +#endif + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#if (defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64)) \ + && !(defined(BOOST_MSVC) && BOOST_MSVC < 1300) +#define LCAST_TEST_LONGLONG +#endif + +#if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) +#define BOOST_LCAST_NO_WCHAR_T +#endif + +// Test all 65536 values if true: +bool const lcast_test_small_integral_types_completely = false; + +// lcast_integral_test_counter: use when testing all values of an integral +// types is not possible. Max. portable value is 32767. +int const lcast_integral_test_counter=500; + +using namespace boost; + +void test_conversion_from_to_short(); +void test_conversion_from_to_ushort(); +void test_conversion_from_to_int(); +void test_conversion_from_to_uint(); +void test_conversion_from_to_long(); +void test_conversion_from_to_ulong(); +void test_conversion_from_to_intmax_t(); +void test_conversion_from_to_uintmax_t(); +#ifdef LCAST_TEST_LONGLONG +void test_conversion_from_to_longlong(); +void test_conversion_from_to_ulonglong(); +#endif + + +unit_test::test_suite *init_unit_test_suite(int, char *[]) +{ + unit_test::test_suite *suite = + BOOST_TEST_SUITE("lexical_cast unit test on integral types"); + + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_short)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ushort)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_int)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uint)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulong)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_intmax_t)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uintmax_t)); +#ifdef LCAST_TEST_LONGLONG + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong)); + suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong)); +#endif + + return suite; +} + +template +void test_conversion_from_integral_to_char(CharT zero) +{ + BOOST_CHECK(lexical_cast(static_cast(0)) == zero + 0); + BOOST_CHECK(lexical_cast(static_cast(1)) == zero + 1); + BOOST_CHECK(lexical_cast(static_cast(2)) == zero + 2); + BOOST_CHECK(lexical_cast(static_cast(3)) == zero + 3); + BOOST_CHECK(lexical_cast(static_cast(4)) == zero + 4); + BOOST_CHECK(lexical_cast(static_cast(5)) == zero + 5); + BOOST_CHECK(lexical_cast(static_cast(6)) == zero + 6); + BOOST_CHECK(lexical_cast(static_cast(7)) == zero + 7); + BOOST_CHECK(lexical_cast(static_cast(8)) == zero + 8); + BOOST_CHECK(lexical_cast(static_cast(9)) == zero + 9); + + BOOST_CHECK_THROW(lexical_cast(static_cast(10)), bad_lexical_cast); + + T t = (std::numeric_limits::max)(); + BOOST_CHECK_THROW(lexical_cast(t), bad_lexical_cast); +} + +template +void test_conversion_from_char_to_integral(CharT zero) +{ + BOOST_CHECK(lexical_cast( static_cast(zero + 0)) == static_cast(0) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 1)) == static_cast(1) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 2)) == static_cast(2) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 3)) == static_cast(3) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 4)) == static_cast(4) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 5)) == static_cast(5) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 6)) == static_cast(6) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 7)) == static_cast(7) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 8)) == static_cast(8) ); + BOOST_CHECK(lexical_cast( static_cast(zero + 9)) == static_cast(9) ); + + BOOST_CHECK_THROW(lexical_cast( static_cast(zero + 10)), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( static_cast(zero - 1)), bad_lexical_cast); +} + +template +void test_conversion_from_integral_to_integral() +{ + T t = 0; + BOOST_CHECK(lexical_cast(t) == t); + + // Next two variables are used to supress warnings. + int st = 32767; unsigned int ut = st; + t = st; + BOOST_CHECK(lexical_cast(t) == st); + BOOST_CHECK(lexical_cast(t) == ut); + BOOST_CHECK(lexical_cast(t) == st); + BOOST_CHECK(lexical_cast(t) == ut); + BOOST_CHECK(lexical_cast(t) == st); + BOOST_CHECK(lexical_cast(t) == ut); + + t = (std::numeric_limits::max)(); + BOOST_CHECK(lexical_cast(t) == t); + + t = (std::numeric_limits::min)(); + BOOST_CHECK(lexical_cast(t) == t); +} + + + + +// Replace "-,999" with "-999". +template +std::basic_string to_str_gcc_workaround(std::basic_string str) +{ + std::locale loc; + std::numpunct const& np = BOOST_USE_FACET(std::numpunct, loc); + std::ctype const& ct = BOOST_USE_FACET(std::ctype, loc); + + if(np.grouping().empty()) + return str; + + CharT prefix[3] = { ct.widen('-'), np.thousands_sep(), CharT() }; + + if(str.find(prefix) != 0) + return str; + + prefix[1] = CharT(); + str.replace(0, 2, prefix); + return str; +} + +template +std::basic_string to_str(T t) +{ + std::basic_ostringstream o; + o << t; + return to_str_gcc_workaround(o.str()); +} + + +template +void test_conversion_from_integral_to_string(CharT) +{ + typedef std::numeric_limits limits; + typedef std::basic_string string_type; + + T t; + + t = (limits::min)(); + BOOST_CHECK(lexical_cast(t) == to_str(t)); + + t = (limits::max)(); + BOOST_CHECK(lexical_cast(t) == to_str(t)); + + if(limits::digits <= 16 && lcast_test_small_integral_types_completely) + // min and max have already been tested. + for(t = 1 + (limits::min)(); t != (limits::max)(); ++t) + BOOST_CHECK(lexical_cast(t) == to_str(t)); + else + { + T const min_val = (limits::min)(); + T const max_val = (limits::max)(); + T const half_max_val = max_val / 2; + T const cnt = lcast_integral_test_counter; // to supress warnings + unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; + + unsigned int i; + + // Test values around min: + t = min_val; + for(i = 0; i < counter; ++i, ++t) + BOOST_CHECK(lexical_cast(t) == to_str(t)); + + // Test values around max: + t = max_val; + for(i = 0; i < counter; ++i, --t) + BOOST_CHECK(lexical_cast(t) == to_str(t)); + + // Test values around zero: + if(limits::is_signed) + for(t = static_cast(-counter); t < static_cast(counter); ++t) + BOOST_CHECK(lexical_cast(t) == to_str(t)); + + // Test values around 100, 1000, 10000, ... + T ten_power = 100; + for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) + { + // ten_power + 100 probably never overflows + for(t = ten_power - 100; t != ten_power + 100; ++t) + BOOST_CHECK(lexical_cast(t) == to_str(t)); + } + } +} + +template +void test_conversion_from_string_to_integral(CharT) +{ + typedef std::numeric_limits limits; + typedef std::basic_string string_type; + + string_type s; + string_type const zero = to_str(0); + string_type const nine = to_str(9); + T const min_val = (limits::min)(); + T const max_val = (limits::max)(); + + s = to_str(min_val); + BOOST_CHECK_EQUAL(lexical_cast(s), min_val); + if(limits::is_signed) + { + BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); + } + + s = to_str(max_val); + BOOST_CHECK_EQUAL(lexical_cast(s), max_val); + { + BOOST_CHECK_THROW(lexical_cast(s + zero), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(s + nine), bad_lexical_cast); + + s = to_str(max_val); + for (int i =1; i <=10; ++i) { + s[s.size()-1] += 1; + BOOST_CHECK_THROW(lexical_cast( s ), bad_lexical_cast); + } + + s = to_str(max_val); + std::locale loc; + typedef std::numpunct numpunct; + if ( BOOST_USE_FACET(numpunct, loc).grouping().empty() ) { + // Following tests work well for locale C + BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+s), max_val); + BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+to_str(0)+s), max_val); + BOOST_CHECK_EQUAL(lexical_cast(to_str(0)+to_str(0)+to_str(0)+s), max_val); + } + + for (int i =1; i <=256; ++i) { + BOOST_CHECK_THROW(lexical_cast( to_str(i)+s ), bad_lexical_cast); + } + + typedef BOOST_DEDUCED_TYPENAME boost::integral_promotion::type promoted; + if ( !(boost::is_same::value) ) + { + promoted prom = max_val; + s = to_str(max_val); + for (int i =1; i <=256; ++i) { + BOOST_CHECK_THROW(lexical_cast( to_str(prom+i) ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( to_str(i)+s ), bad_lexical_cast); + } + } + } + + if(limits::digits <= 16 && lcast_test_small_integral_types_completely) + // min and max have already been tested. + for(T t = 1 + min_val; t != max_val; ++t) + BOOST_CHECK(lexical_cast(to_str(t)) == t); + else + { + T const half_max_val = max_val / 2; + T const cnt = lcast_integral_test_counter; // to supress warnings + unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; + + T t; + unsigned int i; + + // Test values around min: + t = min_val; + for(i = 0; i < counter; ++i, ++t) + BOOST_CHECK(lexical_cast(to_str(t)) == t); + + // Test values around max: + t = max_val; + for(i = 0; i < counter; ++i, --t) + BOOST_CHECK(lexical_cast(to_str(t)) == t); + + // Test values around zero: + if(limits::is_signed) + for(t = static_cast(-counter); t < static_cast(counter); ++t) + BOOST_CHECK(lexical_cast(to_str(t)) == t); + + // Test values around 100, 1000, 10000, ... + T ten_power = 100; + for(int e = 2; e <= limits::digits10; ++e, ten_power *= 10) + { + // ten_power + 100 probably never overflows + for(t = ten_power - 100; t != ten_power + 100; ++t) + BOOST_CHECK(lexical_cast(to_str(t)) == t); + } + } +} + +template +void test_conversion_from_to_integral_for_locale() +{ + std::locale current_locale; + typedef std::numpunct numpunct; + numpunct const& np = BOOST_USE_FACET(numpunct, current_locale); + if ( !np.grouping().empty() ) + { + BOOST_CHECK_THROW( + lexical_cast( std::string("100") + np.thousands_sep() + np.thousands_sep() + "0" ) + , bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( std::string("100") + np.thousands_sep() ), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast( np.thousands_sep() + std::string("100") ), bad_lexical_cast); + + // Exception must not be thrown, when we are using no separators at all + BOOST_CHECK( lexical_cast("30000") == static_cast(30000) ); + } + + test_conversion_from_integral_to_integral(); + test_conversion_from_integral_to_string('0'); + test_conversion_from_string_to_integral('0'); +#if !defined(BOOST_LCAST_NO_WCHAR_T) + test_conversion_from_integral_to_string(L'0'); + test_conversion_from_string_to_integral(L'0'); +#endif +} + +struct restore_oldloc +{ + std::locale oldloc; + ~restore_oldloc() { std::locale::global(oldloc); } +}; + +template +void test_conversion_from_to_integral() +{ + char const zero = '0'; + signed char const szero = '0'; + unsigned char const uzero = '0'; + test_conversion_from_integral_to_char(zero); + test_conversion_from_char_to_integral(zero); + test_conversion_from_integral_to_char(szero); + test_conversion_from_char_to_integral(szero); + test_conversion_from_integral_to_char(uzero); + test_conversion_from_char_to_integral(uzero); +#if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) + wchar_t const wzero = L'0'; + test_conversion_from_integral_to_char(wzero); + test_conversion_from_char_to_integral(wzero); +#endif +#if !defined(BOOST_NO_CHAR16_T) && !defined(BOOST_NO_UNICODE_LITERALS) + char16_t const u16zero = u'0'; + test_conversion_from_integral_to_char(u16zero); + test_conversion_from_char_to_integral(u16zero); +#endif +#if !defined(BOOST_NO_CHAR32_T) && !defined(BOOST_NO_UNICODE_LITERALS) + char32_t const u32zero = u'0'; + test_conversion_from_integral_to_char(u32zero); + test_conversion_from_char_to_integral(u32zero); +#endif + + BOOST_CHECK(lexical_cast("-1") == static_cast(-1)); + BOOST_CHECK(lexical_cast("-9") == static_cast(-9)); + BOOST_CHECK(lexical_cast(-1) == static_cast(-1)); + BOOST_CHECK(lexical_cast(-9) == static_cast(-9)); + + BOOST_CHECK_THROW(lexical_cast("-1.0"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-9.0"), bad_lexical_cast); + BOOST_CHECK(lexical_cast(-1.0) == static_cast(-1)); + BOOST_CHECK(lexical_cast(-9.0) == static_cast(-9)); + + BOOST_CHECK(lexical_cast(static_cast(1)) == static_cast(1)); + BOOST_CHECK(lexical_cast(static_cast(9)) == static_cast(9)); + BOOST_CHECK_THROW(lexical_cast(1.1f), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.1), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.1L), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.0001f), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.0001), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(1.0001L), bad_lexical_cast); + + BOOST_CHECK(lexical_cast("+1") == static_cast(1) ); + BOOST_CHECK(lexical_cast("+9") == static_cast(9) ); + BOOST_CHECK(lexical_cast("+10") == static_cast(10) ); + BOOST_CHECK(lexical_cast("+90") == static_cast(90) ); + BOOST_CHECK_THROW(lexical_cast("++1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("-+9"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("--1"), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast("+-9"), bad_lexical_cast); + // test_conversion_from_to_integral_for_locale + + // Overflow test case from David W. Birdsall + std::string must_owerflow_str = "160000000000000000000"; + std::string must_owerflow_negative_str = "-160000000000000000000"; + for (int i = 0; i < 15; ++i) { + BOOST_CHECK_THROW(lexical_cast(must_owerflow_str), bad_lexical_cast); + BOOST_CHECK_THROW(lexical_cast(must_owerflow_negative_str), bad_lexical_cast); + + must_owerflow_str += '0'; + must_owerflow_negative_str += '0'; + } + + typedef std::numpunct numpunct; + + restore_oldloc guard; + std::locale const& oldloc = guard.oldloc; + + std::string grouping1 = BOOST_USE_FACET(numpunct, oldloc).grouping(); + std::string grouping2(grouping1); + + test_conversion_from_to_integral_for_locale(); + + try + { + std::locale newloc(""); + std::locale::global(newloc); + + grouping2 = BOOST_USE_FACET(numpunct, newloc).grouping(); + } + catch(std::exception const& ex) + { + std::string msg("Failed to set system locale: "); + msg += ex.what(); + BOOST_TEST_MESSAGE(msg); + } + + if(grouping1 != grouping2) + test_conversion_from_to_integral_for_locale(); + + if(grouping1.empty() && grouping2.empty()) + BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); +} + +void test_conversion_from_to_short() +{ + test_conversion_from_to_integral(); +} + +void test_conversion_from_to_ushort() +{ + test_conversion_from_to_integral(); +} + +void test_conversion_from_to_int() +{ + test_conversion_from_to_integral(); +} + +void test_conversion_from_to_uint() +{ + test_conversion_from_to_integral(); +} + +void test_conversion_from_to_long() +{ + test_conversion_from_to_integral(); +} + +void test_conversion_from_to_ulong() +{ + test_conversion_from_to_integral(); +} + +void test_conversion_from_to_intmax_t() +{ + test_conversion_from_to_integral(); +} + +void test_conversion_from_to_uintmax_t() +{ + test_conversion_from_to_integral(); +} + +#if defined(BOOST_HAS_LONG_LONG) + +void test_conversion_from_to_longlong() +{ + test_conversion_from_to_integral(); +} + +void test_conversion_from_to_ulonglong() +{ + test_conversion_from_to_integral(); +} + +#elif defined(BOOST_HAS_MS_INT64) + +void test_conversion_from_to_longlong() +{ + test_conversion_from_to_integral<__int64>(); +} + +void test_conversion_from_to_ulonglong() +{ + test_conversion_from_to_integral(); +} + +#endif + + + +