// 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-2025. // // 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 #include #include #include #include #include #include // std::transform #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 #ifndef BOOST_TEST_CLOSE_FRACTION // Naiive, but works for tests in this file #define BOOST_TEST_CLOSE_FRACTION(x, y, eps) BOOST_TEST(x - y + eps <= eps * 2) #endif template struct my_traits : std::char_traits { }; template struct my_allocator : std::allocator { typedef std::allocator base_t; my_allocator(){} template my_allocator(const my_allocator& v) : base_t(v) {} template struct rebind { typedef my_allocator other; }; }; using namespace boost; void test_conversion_to_char() { BOOST_TEST_EQ('A', lexical_cast('A')); BOOST_TEST_EQ(' ', lexical_cast(' ')); BOOST_TEST_EQ('1', lexical_cast(1)); BOOST_TEST_EQ('0', lexical_cast(0)); BOOST_TEST_THROWS(lexical_cast(123), bad_lexical_cast); BOOST_TEST_EQ('1', lexical_cast(1.0)); BOOST_TEST_EQ('1', lexical_cast(true)); BOOST_TEST_EQ('0', lexical_cast(false)); BOOST_TEST_EQ('A', lexical_cast("A")); BOOST_TEST_EQ(' ', lexical_cast(" ")); BOOST_TEST_THROWS(lexical_cast(""), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("Test"), bad_lexical_cast); BOOST_TEST_EQ('A', lexical_cast(std::string("A"))); BOOST_TEST_EQ(' ', lexical_cast(std::string(" "))); BOOST_TEST_THROWS( lexical_cast(std::string("")), bad_lexical_cast); BOOST_TEST_THROWS( lexical_cast(std::string("Test")), bad_lexical_cast); } void test_conversion_to_int() { BOOST_TEST_EQ(1, lexical_cast('1')); BOOST_TEST_EQ(0, lexical_cast('0')); BOOST_TEST_THROWS(lexical_cast('A'), bad_lexical_cast); BOOST_TEST_EQ(1, lexical_cast(1)); BOOST_TEST_EQ(1, lexical_cast(1.0)); BOOST_TEST_EQ( (std::numeric_limits::max)(), lexical_cast((std::numeric_limits::max)())); BOOST_TEST_EQ( (std::numeric_limits::min)(), lexical_cast((std::numeric_limits::min)())); BOOST_TEST_THROWS(lexical_cast(1.23), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast(1e20), bad_lexical_cast); BOOST_TEST_EQ(1, lexical_cast(true)); BOOST_TEST_EQ(0, lexical_cast(false)); BOOST_TEST_EQ(123, lexical_cast("123")); BOOST_TEST_THROWS( lexical_cast(" 123"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast(""), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("Test"), bad_lexical_cast); BOOST_TEST_EQ(123, lexical_cast("123")); BOOST_TEST_EQ(123, lexical_cast(std::string("123"))); BOOST_TEST_THROWS( lexical_cast(std::string(" 123")), bad_lexical_cast); BOOST_TEST_THROWS( lexical_cast(std::string("")), bad_lexical_cast); BOOST_TEST_THROWS( lexical_cast(std::string("Test")), bad_lexical_cast); } void test_conversion_with_nonconst_char() { std::vector buffer; buffer.push_back('1'); buffer.push_back('\0'); BOOST_TEST_EQ(boost::lexical_cast(&buffer[0]), 1); std::vector buffer2; buffer2.push_back('1'); buffer2.push_back('\0'); BOOST_TEST_EQ(boost::lexical_cast(&buffer2[0]), 1); std::vector buffer3; buffer3.push_back('1'); buffer3.push_back('\0'); BOOST_TEST_EQ(boost::lexical_cast(&buffer3[0]), 1); #ifndef BOOST_LCAST_NO_WCHAR_T std::vector buffer4; buffer4.push_back(L'1'); buffer4.push_back(L'\0'); BOOST_TEST_EQ(boost::lexical_cast(&buffer4[0]), 1); #endif } void test_conversion_to_double() { BOOST_TEST_CLOSE_FRACTION(1.0, lexical_cast('1'), (std::numeric_limits::epsilon())); BOOST_TEST_THROWS(lexical_cast('A'), bad_lexical_cast); BOOST_TEST_CLOSE_FRACTION(1.0, lexical_cast(1), (std::numeric_limits::epsilon())); BOOST_TEST_CLOSE_FRACTION(1.23, lexical_cast(1.23), (std::numeric_limits::epsilon())); BOOST_TEST_CLOSE_FRACTION(1.234567890, lexical_cast(1.234567890), std::numeric_limits::epsilon()); BOOST_TEST_CLOSE_FRACTION(1.234567890, lexical_cast("1.234567890"), std::numeric_limits::epsilon()); BOOST_TEST_CLOSE_FRACTION(1.0, lexical_cast(true), (std::numeric_limits::epsilon())); BOOST_TEST_CLOSE_FRACTION(0.0, lexical_cast(false), (std::numeric_limits::epsilon())); BOOST_TEST_CLOSE_FRACTION(1.23, lexical_cast("1.23"), (std::numeric_limits::epsilon())); BOOST_TEST_THROWS(lexical_cast(""), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("Test"), bad_lexical_cast); BOOST_TEST_CLOSE_FRACTION(1.23, lexical_cast(std::string("1.23")), (std::numeric_limits::epsilon())); BOOST_TEST_THROWS( lexical_cast(std::string("")), bad_lexical_cast); BOOST_TEST_THROWS( lexical_cast(std::string("Test")), bad_lexical_cast); } void test_conversion_to_bool() { BOOST_TEST_EQ(true, lexical_cast('1')); BOOST_TEST_EQ(false, lexical_cast('0')); BOOST_TEST_THROWS(lexical_cast('A'), bad_lexical_cast); BOOST_TEST_EQ(true, lexical_cast(1)); BOOST_TEST_EQ(false, lexical_cast(0)); BOOST_TEST_THROWS(lexical_cast(123), bad_lexical_cast); BOOST_TEST_EQ(true, lexical_cast(1.0)); BOOST_TEST_THROWS(lexical_cast(-123), bad_lexical_cast); BOOST_TEST_EQ(false, lexical_cast(0.0)); BOOST_TEST_THROWS(lexical_cast(1234), bad_lexical_cast); #if !defined(_CRAYC) // Looks like a bug in CRAY compiler (throws bad_lexical_cast) // TODO: localize the bug and report it to developers. BOOST_TEST_EQ(true, lexical_cast(true)); BOOST_TEST_EQ(false, lexical_cast(false)); #endif BOOST_TEST_EQ(true, lexical_cast("1")); BOOST_TEST_EQ(false, lexical_cast("0")); BOOST_TEST_THROWS(lexical_cast(""), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("Test"), bad_lexical_cast); BOOST_TEST_EQ(true, lexical_cast("1")); BOOST_TEST_EQ(false, lexical_cast("0")); BOOST_TEST_EQ(true, lexical_cast(std::string("1"))); BOOST_TEST_EQ(false, lexical_cast(std::string("0"))); BOOST_TEST_THROWS(lexical_cast(1.0001L), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast(2), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast(2u), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast(-1), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast(-2), bad_lexical_cast); BOOST_TEST_THROWS( lexical_cast(std::string("")), bad_lexical_cast); BOOST_TEST_THROWS( lexical_cast(std::string("Test")), bad_lexical_cast); BOOST_TEST(lexical_cast("+1") == true); BOOST_TEST(lexical_cast("+0") == false); BOOST_TEST(lexical_cast("-0") == false); BOOST_TEST_THROWS(lexical_cast("--0"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("-+-0"), bad_lexical_cast); BOOST_TEST(lexical_cast("0") == false); BOOST_TEST(lexical_cast("1") == true); BOOST_TEST(lexical_cast("00") == false); BOOST_TEST(lexical_cast("00000000000") == false); BOOST_TEST(lexical_cast("000000000001") == true); BOOST_TEST(lexical_cast("+00") == false ); BOOST_TEST(lexical_cast("-00") == false ); BOOST_TEST(lexical_cast("+00000000001") == true ); BOOST_TEST_THROWS(lexical_cast("020"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("00200"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("-00200"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("+00200"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("000000000002"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("-1"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("-0000000001"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("00000000011"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("001001"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("-00000000010"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("-000000000100"), bad_lexical_cast); } void test_conversion_to_string() { char buf[] = "hello"; char* str = buf; BOOST_TEST_EQ(str, lexical_cast(str)); BOOST_TEST_EQ("A", lexical_cast('A')); BOOST_TEST_EQ(" ", lexical_cast(' ')); BOOST_TEST_EQ("123", lexical_cast(123)); BOOST_TEST_EQ("1.23", lexical_cast(1.23)); BOOST_TEST_EQ("1.111111111", lexical_cast(1.111111111)); BOOST_TEST_EQ("1", lexical_cast(true)); BOOST_TEST_EQ("0", lexical_cast(false)); BOOST_TEST_EQ("Test", lexical_cast("Test")); BOOST_TEST_EQ(" ", lexical_cast(" ")); BOOST_TEST_EQ("", lexical_cast("")); BOOST_TEST_EQ("Test", lexical_cast(std::string("Test"))); BOOST_TEST_EQ(" ", lexical_cast(std::string(" "))); BOOST_TEST_EQ("", lexical_cast(std::string(""))); } void test_conversion_from_to_wchar_t_alias() { BOOST_TEST_EQ(123u, lexical_cast("123")); BOOST_TEST_EQ(123u, lexical_cast("123")); BOOST_TEST_EQ(123u, lexical_cast("123")); BOOST_TEST_EQ(std::string("123"), lexical_cast(static_cast(123))); BOOST_TEST_EQ(std::string("123"), lexical_cast(123u)); BOOST_TEST_EQ(std::string("123"), lexical_cast(123ul)); } void test_conversion_from_wchar_t() { #ifndef BOOST_LCAST_NO_WCHAR_T #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) BOOST_TEST_EQ(1, lexical_cast(L'1')); BOOST_TEST_THROWS(lexical_cast(L'A'), bad_lexical_cast); #endif BOOST_TEST_EQ(123, lexical_cast(L"123")); BOOST_TEST_THROWS(lexical_cast(L""), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast(L"Test"), bad_lexical_cast); #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) BOOST_TEST_EQ(1.0, lexical_cast(L'1')); BOOST_TEST_THROWS(lexical_cast(L'A'), bad_lexical_cast); #endif BOOST_TEST_EQ(1.23, lexical_cast(L"1.23")); BOOST_TEST_THROWS(lexical_cast(L""), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast(L"Test"), bad_lexical_cast); #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) BOOST_TEST_EQ(true, lexical_cast(L'1')); BOOST_TEST_EQ(false, lexical_cast(L'0')); BOOST_TEST_THROWS(lexical_cast(L'A'), bad_lexical_cast); #endif BOOST_TEST_EQ(true, lexical_cast(L"1")); BOOST_TEST_EQ(false, lexical_cast(L"0")); BOOST_TEST_THROWS(lexical_cast(L""), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast(L"Test"), bad_lexical_cast); #endif } void test_conversion_to_wchar_t() { #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) BOOST_TEST(L'1' == lexical_cast(1)); BOOST_TEST(L'0' == lexical_cast(0)); BOOST_TEST(L'1' == lexical_cast('1')); BOOST_TEST(L'0' == lexical_cast('0')); BOOST_TEST_THROWS(lexical_cast(123), bad_lexical_cast); BOOST_TEST(L'1' == lexical_cast(1.0)); BOOST_TEST(L'0' == lexical_cast(0.0)); BOOST_TEST(L'1' == lexical_cast(true)); BOOST_TEST(L'0' == lexical_cast(false)); BOOST_TEST(L'A' == lexical_cast(L'A')); BOOST_TEST(L' ' == lexical_cast(L' ')); BOOST_TEST(L'A' == lexical_cast(L"A")); BOOST_TEST(L' ' == lexical_cast(L" ")); BOOST_TEST_THROWS(lexical_cast(L""), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast(L"Test"), bad_lexical_cast); BOOST_TEST(L'A' == lexical_cast(std::wstring(L"A"))); BOOST_TEST(L' ' == lexical_cast(std::wstring(L" "))); BOOST_TEST_THROWS( lexical_cast(std::wstring(L"")), bad_lexical_cast); BOOST_TEST_THROWS( lexical_cast(std::wstring(L"Test")), bad_lexical_cast); #endif BOOST_TEST(true); } void test_conversion_from_wstring() { #ifndef BOOST_LCAST_NO_WCHAR_T BOOST_TEST_EQ(123, lexical_cast(std::wstring(L"123"))); BOOST_TEST_THROWS( lexical_cast(std::wstring(L"")), bad_lexical_cast); BOOST_TEST_THROWS( lexical_cast(std::wstring(L"Test")), bad_lexical_cast); BOOST_TEST_EQ(true, lexical_cast(std::wstring(L"1"))); BOOST_TEST_EQ(false, lexical_cast(std::wstring(L"0"))); BOOST_TEST_THROWS( lexical_cast(std::wstring(L"")), bad_lexical_cast); BOOST_TEST_THROWS( lexical_cast(std::wstring(L"Test")), bad_lexical_cast); #endif BOOST_TEST(true); } void test_conversion_to_wstring() { #ifndef BOOST_LCAST_NO_WCHAR_T wchar_t buf[] = L"hello"; wchar_t* str = buf; BOOST_TEST(str == lexical_cast(str)); BOOST_TEST(L"123" == lexical_cast(123)); BOOST_TEST(L"1.23" == lexical_cast(1.23)); BOOST_TEST(L"1" == lexical_cast(true)); BOOST_TEST(L"0" == lexical_cast(false)); #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) BOOST_TEST(L"A" == lexical_cast(L'A')); BOOST_TEST(L" " == lexical_cast(L' ')); BOOST_TEST(L"A" == lexical_cast('A')); #endif BOOST_TEST(L"Test" == lexical_cast(L"Test")); BOOST_TEST(L" " == lexical_cast(L" ")); BOOST_TEST(L"" == lexical_cast(L"")); BOOST_TEST(L"Test" == lexical_cast(std::wstring(L"Test"))); BOOST_TEST(L" " == lexical_cast(std::wstring(L" "))); BOOST_TEST(L"" == lexical_cast(std::wstring(L""))); #endif BOOST_TEST(true); } void test_bad_lexical_cast() { try { lexical_cast(std::string("Test")); BOOST_TEST(false); // Exception expected } catch(const bad_lexical_cast &e) { BOOST_TEST(e.source_type() == typeid(std::string)); BOOST_TEST(e.target_type() == typeid(int)); } } void test_no_whitespace_stripping() { BOOST_TEST_THROWS(lexical_cast(" 123"), bad_lexical_cast); BOOST_TEST_THROWS(lexical_cast("123 "), bad_lexical_cast); } void test_traits() { typedef std::basic_string > my_string; my_string const s("s"); BOOST_TEST(boost::lexical_cast(s) == s[0]); BOOST_TEST(boost::lexical_cast(s) == s); BOOST_TEST(boost::lexical_cast(-1) == "-1"); BOOST_TEST(boost::lexical_cast(my_string("42")) == 42); BOOST_TEST(boost::lexical_cast(my_string("1.0")) == 1.0); } void test_wtraits() { typedef std::basic_string > my_string; my_string const s(L"s"); BOOST_TEST(boost::lexical_cast(s) == s[0]); BOOST_TEST(boost::lexical_cast(s) == s); BOOST_TEST(boost::lexical_cast(-1) == L"-1"); BOOST_TEST(boost::lexical_cast(my_string(L"42")) == 42); BOOST_TEST(boost::lexical_cast(my_string(L"1.0")) == 1.0); } void test_allocator() { // Following test cause compilation error on MSVC2012: // (Reason: cannot convert from 'std::_Wrap_alloc<_Alloc>' to 'const my_allocator') // // MSVC developer is notified about this issue #if !defined(_MSC_VER) || (_MSC_VER < 1700) typedef std::basic_string< char , std::char_traits , my_allocator > my_string; my_string s("s"); BOOST_TEST(boost::lexical_cast(s) == s[0]); BOOST_TEST(boost::lexical_cast(s) == "s"); BOOST_TEST(boost::lexical_cast(s) == s); BOOST_TEST(boost::lexical_cast(1) == "1"); BOOST_TEST(boost::lexical_cast("s") == s); BOOST_TEST(boost::lexical_cast(std::string("s")) == s); #endif } void test_wallocator() { // Following test cause compilation error on MSVC2012: // (Reason: cannot convert from 'std::_Wrap_alloc<_Alloc>' to 'const my_allocator') // // MSVC developer is notified about this issue #if !defined(_MSC_VER) || (_MSC_VER < 1700) typedef std::basic_string< wchar_t , std::char_traits , my_allocator > my_string; my_string s(L"s"); BOOST_TEST(boost::lexical_cast(s) == s[0]); BOOST_TEST(boost::lexical_cast(s) == L"s"); BOOST_TEST(boost::lexical_cast(s) == s); BOOST_TEST(boost::lexical_cast(1) == L"1"); BOOST_TEST(boost::lexical_cast(L"s") == s); BOOST_TEST(boost::lexical_cast(std::wstring(L"s")) == s); #endif } void test_char_types_conversions() { const char c_arr[] = "Test array of chars"; const unsigned char uc_arr[] = "Test array of chars"; const signed char sc_arr[] = "Test array of chars"; BOOST_TEST(boost::lexical_cast(c_arr) == std::string(c_arr)); BOOST_TEST(boost::lexical_cast(uc_arr) == std::string(c_arr)); BOOST_TEST(boost::lexical_cast(sc_arr) == std::string(c_arr)); BOOST_TEST(boost::lexical_cast(c_arr[0]) == c_arr[0]); BOOST_TEST(boost::lexical_cast(uc_arr[0]) == c_arr[0]); BOOST_TEST(boost::lexical_cast(sc_arr[0]) == c_arr[0]); BOOST_TEST(boost::lexical_cast(c_arr[0]) == uc_arr[0]); BOOST_TEST(boost::lexical_cast(uc_arr[0]) == uc_arr[0]); BOOST_TEST(boost::lexical_cast(sc_arr[0]) == uc_arr[0]); BOOST_TEST(boost::lexical_cast(c_arr[0]) == sc_arr[0]); BOOST_TEST(boost::lexical_cast(uc_arr[0]) == sc_arr[0]); BOOST_TEST(boost::lexical_cast(sc_arr[0]) == sc_arr[0]); #ifndef BOOST_LCAST_NO_WCHAR_T const wchar_t wc_arr[]=L"Test array of chars"; BOOST_TEST(boost::lexical_cast(wc_arr) == std::wstring(wc_arr)); BOOST_TEST(boost::lexical_cast(wc_arr[0]) == wc_arr[0]); #endif } struct foo_operators_test { foo_operators_test() : f(2) {} int f; }; template OStream& operator<<(OStream& ostr, const foo_operators_test& foo) { ostr << foo.f; return ostr; } template IStream& operator>>(IStream& istr, foo_operators_test& foo) { istr >> foo.f; return istr; } void operators_overload_test() { foo_operators_test foo; BOOST_TEST_EQ(boost::lexical_cast(foo), "2"); BOOST_TEST_EQ((boost::lexical_cast("2")).f, 2); // Must compile (void)boost::lexical_cast(foo); } void test_char16_conversions() { // There's no std::ctype in Xcode_15.0.1 #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && !defined(__APPLE__) BOOST_TEST(u"100" == lexical_cast(u"100")); BOOST_TEST(u"1" == lexical_cast(u'1')); #endif } void test_char32_conversions() { // There's no std::ctype in Xcode_15.0.1 #if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && !defined(__APPLE__) BOOST_TEST(U"100" == lexical_cast(U"100")); BOOST_TEST(U"1" == lexical_cast(U'1')); #endif } void test_getting_pointer_to_function() { // Just checking that &lexical_cast is not ambiguous typedef char char_arr[4]; typedef int(*f1)(const char_arr&); f1 p1 = &boost::lexical_cast; BOOST_TEST(p1); typedef int(*f2)(const std::string&); f2 p2 = &boost::lexical_cast; BOOST_TEST(p2); typedef std::string(*f3)(const int&); f3 p3 = &boost::lexical_cast; BOOST_TEST(p3); std::vector values; std::vector ret; std::transform(values.begin(), values.end(), ret.begin(), boost::lexical_cast); } int main() { test_conversion_to_char(); test_conversion_to_int(); test_conversion_to_double(); test_conversion_to_bool(); test_conversion_from_to_wchar_t_alias(); test_conversion_to_string(); test_conversion_with_nonconst_char(); #ifndef BOOST_LCAST_NO_WCHAR_T test_conversion_from_wchar_t(); test_conversion_to_wchar_t(); test_conversion_from_wstring(); test_conversion_to_wstring(); #endif test_bad_lexical_cast(); test_no_whitespace_stripping(); test_traits(); test_wtraits(); test_allocator(); test_wallocator(); test_char_types_conversions(); operators_overload_test(); test_char16_conversions(); test_char32_conversions(); test_getting_pointer_to_function(); return boost::report_errors(); }