// 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-2019. // // 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 #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 #ifdef BOOST_HAS_INT128 void test_conversion_from_to_int128(); void test_conversion_from_to_uint128(); #endif void test_integral_conversions_on_min_max(); 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 #ifdef BOOST_HAS_INT128 suite->add(BOOST_TEST_CASE(&test_conversion_from_to_int128)); suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uint128)); #endif suite->add(BOOST_TEST_CASE(&test_integral_conversions_on_min_max)); 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 suppress 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 suppress 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 suppress 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(); // This is a part of test_conversion_from_integral_to_string('0') method, // but with BOOST_CHECK_EQUAL instead of BOOST_CHECK. It is required to see // what is produced by the to_str(t) method in situations when result // is different. BOOST_CHECK does not work with wchar_t. typedef std::numeric_limits limits; T t = (limits::min)(); BOOST_CHECK_EQUAL(lexical_cast(t), to_str(t)); test_conversion_from_integral_to_string('0'); test_conversion_from_string_to_integral('0'); #if !defined(BOOST_LCAST_NO_WCHAR_T) if (lexical_cast(t) != to_str(t)) { // Something went wrong, and now we are attempting to find and print the // difference. std::wstring wstr = to_str(t); std::string lcast_str = lexical_cast(t); std::string str; str.reserve(wstr.size()); for (std::size_t i = 0; i < wstr.size(); ++i) { str.push_back(static_cast(wstr[i])); } BOOST_CHECK_EQUAL(lcast_str.length(), lexical_cast(t).length()); BOOST_CHECK_EQUAL(to_str(t), str); BOOST_CHECK_EQUAL(lcast_str, str); } 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_minimal() { 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_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && !defined(_LIBCPP_VERSION) && !defined(BOOST_MSVC) 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_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && !defined(_LIBCPP_VERSION) && !defined(BOOST_MSVC) 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 = (sizeof(T) < 16 ? "160000000000000000000" : "1600000000000000000000000000000000000000"); std::string must_owerflow_negative_str = (sizeof(T) < 16 ? "-160000000000000000000" : "-1600000000000000000000000000000000000000"); 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'; } } template void test_conversion_from_to_integral() { test_conversion_from_to_integral_minimal(); 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 #ifdef BOOST_HAS_INT128 template struct test_if_specialized { static void test() {} }; template struct test_if_specialized { static void test() { test_conversion_from_to_integral_minimal(); } }; void test_conversion_from_to_int128() { test_if_specialized< std::numeric_limits::is_specialized, boost::int128_type >::test(); } void test_conversion_from_to_uint128() { test_if_specialized< std::numeric_limits::is_specialized, boost::uint128_type >::test(); } #endif template void test_integral_conversions_on_min_max_impl() { typedef SignedT signed_t; typedef BOOST_DEDUCED_TYPENAME boost::make_unsigned::type unsigned_t; typedef std::numeric_limits s_limits; typedef std::numeric_limits uns_limits; BOOST_CHECK_EQUAL(lexical_cast((uns_limits::max)()), (uns_limits::max)()); BOOST_CHECK_EQUAL(lexical_cast((uns_limits::min)()), (uns_limits::min)()); BOOST_CHECK_EQUAL(lexical_cast((s_limits::max)()), (s_limits::max)()); BOOST_CHECK_EQUAL(lexical_cast((uns_limits::min)()), static_cast((uns_limits::min)())); BOOST_CHECK_EQUAL(lexical_cast((s_limits::max)()), static_cast((s_limits::max)())); BOOST_CHECK_EQUAL(lexical_cast((s_limits::min)()), static_cast((s_limits::min)())); } void test_integral_conversions_on_min_max() { test_integral_conversions_on_min_max_impl(); test_integral_conversions_on_min_max_impl(); #ifdef _MSC_VER test_integral_conversions_on_min_max_impl(); #if defined(BOOST_HAS_LONG_LONG) test_integral_conversions_on_min_max_impl(); #elif defined(BOOST_HAS_MS_INT64) test_integral_conversions_on_min_max_impl<__int64>(); #endif #ifdef BOOST_HAS_INT128 test_integral_conversions_on_min_max_impl(); #endif #endif }