util_formatting_ostream.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*
  2. * Copyright Andrey Semashev 2007 - 2015.
  3. * Distributed under the Boost Software License, Version 1.0.
  4. * (See accompanying file LICENSE_1_0.txt or copy at
  5. * http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. /*!
  8. * \file util_formatting_ostream.cpp
  9. * \author Andrey Semashev
  10. * \date 26.05.2013
  11. *
  12. * \brief This header contains tests for the formatting output stream wrapper.
  13. */
  14. #define BOOST_TEST_MODULE util_formatting_ostream
  15. #include <locale>
  16. #include <string>
  17. #include <iomanip>
  18. #include <sstream>
  19. #include <iostream>
  20. #include <algorithm>
  21. #include <boost/config.hpp>
  22. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  23. #include <string_view>
  24. #endif
  25. #include <boost/test/unit_test.hpp>
  26. #include <boost/utility/string_view.hpp>
  27. #include <boost/log/utility/formatting_ostream.hpp>
  28. #include "char_definitions.hpp"
  29. #if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
  30. #define BOOST_UTF8_DECL
  31. #define BOOST_UTF8_BEGIN_NAMESPACE namespace {
  32. #define BOOST_UTF8_END_NAMESPACE }
  33. #include <boost/detail/utf8_codecvt_facet.hpp>
  34. #include <boost/detail/utf8_codecvt_facet.ipp>
  35. #endif // defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
  36. namespace logging = boost::log;
  37. namespace {
  38. struct unreferencable_data
  39. {
  40. unsigned int m : 2;
  41. unsigned int n : 6;
  42. enum my_enum
  43. {
  44. one = 1,
  45. two = 2
  46. };
  47. // The following static constants don't have definitions, so they can only be used in constant expressions.
  48. // Trying to bind a reference to these members will result in linking errors.
  49. static const int x = 7;
  50. static const my_enum y = one;
  51. unreferencable_data()
  52. {
  53. m = 1;
  54. n = 5;
  55. }
  56. };
  57. template< typename CharT >
  58. struct test_impl
  59. {
  60. typedef CharT char_type;
  61. typedef test_data< char_type > strings;
  62. typedef std::basic_string< char_type > string_type;
  63. typedef std::basic_ostringstream< char_type > ostream_type;
  64. typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
  65. template< typename StringT >
  66. static void width_formatting()
  67. {
  68. // Check that widening works
  69. {
  70. string_type str_fmt;
  71. formatting_ostream_type strm_fmt(str_fmt);
  72. strm_fmt << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
  73. strm_fmt.flush();
  74. ostream_type strm_correct;
  75. strm_correct << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
  76. BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
  77. }
  78. // Check that the string is not truncated
  79. {
  80. string_type str_fmt;
  81. formatting_ostream_type strm_fmt(str_fmt);
  82. strm_fmt << strings::abc() << std::setw(1) << (StringT)strings::abcd() << strings::ABC();
  83. strm_fmt.flush();
  84. ostream_type strm_correct;
  85. strm_correct << strings::abc() << std::setw(1) << (StringT)strings::abcd() << strings::ABC();
  86. BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
  87. }
  88. }
  89. template< typename StringT >
  90. static void fill_formatting()
  91. {
  92. string_type str_fmt;
  93. formatting_ostream_type strm_fmt(str_fmt);
  94. strm_fmt << strings::abc() << std::setfill(static_cast< char_type >('x')) << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
  95. strm_fmt.flush();
  96. ostream_type strm_correct;
  97. strm_correct << strings::abc() << std::setfill(static_cast< char_type >('x')) << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
  98. BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
  99. }
  100. template< typename StringT >
  101. static void alignment()
  102. {
  103. // Left alignment
  104. {
  105. string_type str_fmt;
  106. formatting_ostream_type strm_fmt(str_fmt);
  107. strm_fmt << strings::abc() << std::setw(8) << std::left << (StringT)strings::abcd() << strings::ABC();
  108. strm_fmt.flush();
  109. ostream_type strm_correct;
  110. strm_correct << strings::abc() << std::setw(8) << std::left << (StringT)strings::abcd() << strings::ABC();
  111. BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
  112. }
  113. // Right alignment
  114. {
  115. string_type str_fmt;
  116. formatting_ostream_type strm_fmt(str_fmt);
  117. strm_fmt << strings::abc() << std::setw(8) << std::right << (StringT)strings::abcd() << strings::ABC();
  118. strm_fmt.flush();
  119. ostream_type strm_correct;
  120. strm_correct << strings::abc() << std::setw(8) << std::right << (StringT)strings::abcd() << strings::ABC();
  121. BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
  122. }
  123. }
  124. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  125. template< typename StringT >
  126. static void rvalue_stream()
  127. {
  128. string_type str_fmt;
  129. formatting_ostream_type(str_fmt) << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC() << std::flush;
  130. ostream_type strm_correct;
  131. strm_correct << strings::abc() << std::setw(8) << (StringT)strings::abcd() << strings::ABC();
  132. BOOST_CHECK(equal_strings(str_fmt, strm_correct.str()));
  133. }
  134. #endif
  135. static void output_unreferencable_data()
  136. {
  137. unreferencable_data data;
  138. {
  139. string_type str_fmt;
  140. formatting_ostream_type strm_fmt(str_fmt);
  141. strm_fmt << data.m << static_cast< char_type >(' ') << data.n << static_cast< char_type >(' ') << unreferencable_data::x << static_cast< char_type >(' ') << unreferencable_data::y;
  142. strm_fmt.flush();
  143. ostream_type strm_correct;
  144. strm_correct << static_cast< unsigned int >(data.m) << static_cast< char_type >(' ') << static_cast< unsigned int >(data.n) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::x) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::y);
  145. BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
  146. }
  147. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  148. {
  149. string_type str_fmt;
  150. formatting_ostream_type(str_fmt) << data.m << static_cast< char_type >(' ') << data.n << static_cast< char_type >(' ') << unreferencable_data::x << static_cast< char_type >(' ') << unreferencable_data::y << std::flush;
  151. ostream_type strm_correct;
  152. strm_correct << static_cast< unsigned int >(data.m) << static_cast< char_type >(' ') << static_cast< unsigned int >(data.n) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::x) << static_cast< char_type >(' ') << static_cast< int >(unreferencable_data::y);
  153. BOOST_CHECK(equal_strings(str_fmt, strm_correct.str()));
  154. }
  155. #endif
  156. }
  157. };
  158. } // namespace
  159. // Test support for width formatting
  160. BOOST_AUTO_TEST_CASE_TEMPLATE(width_formatting, CharT, char_types)
  161. {
  162. typedef test_impl< CharT > test;
  163. test::BOOST_NESTED_TEMPLATE width_formatting< const CharT* >();
  164. test::BOOST_NESTED_TEMPLATE width_formatting< typename test::string_type >();
  165. test::BOOST_NESTED_TEMPLATE width_formatting< boost::basic_string_view< CharT > >();
  166. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  167. test::BOOST_NESTED_TEMPLATE width_formatting< std::basic_string_view< CharT > >();
  168. #endif
  169. }
  170. // Test support for filler character setup
  171. BOOST_AUTO_TEST_CASE_TEMPLATE(fill_formatting, CharT, char_types)
  172. {
  173. typedef test_impl< CharT > test;
  174. test::BOOST_NESTED_TEMPLATE fill_formatting< const CharT* >();
  175. test::BOOST_NESTED_TEMPLATE fill_formatting< typename test::string_type >();
  176. test::BOOST_NESTED_TEMPLATE fill_formatting< boost::basic_string_view< CharT > >();
  177. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  178. test::BOOST_NESTED_TEMPLATE fill_formatting< std::basic_string_view< CharT > >();
  179. #endif
  180. }
  181. // Test support for text alignment
  182. BOOST_AUTO_TEST_CASE_TEMPLATE(alignment, CharT, char_types)
  183. {
  184. typedef test_impl< CharT > test;
  185. test::BOOST_NESTED_TEMPLATE alignment< const CharT* >();
  186. test::BOOST_NESTED_TEMPLATE alignment< typename test::string_type >();
  187. test::BOOST_NESTED_TEMPLATE alignment< boost::basic_string_view< CharT > >();
  188. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  189. test::BOOST_NESTED_TEMPLATE alignment< std::basic_string_view< CharT > >();
  190. #endif
  191. }
  192. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  193. // Test support for rvalue stream objects
  194. BOOST_AUTO_TEST_CASE_TEMPLATE(rvalue_stream, CharT, char_types)
  195. {
  196. typedef test_impl< CharT > test;
  197. test::BOOST_NESTED_TEMPLATE rvalue_stream< const CharT* >();
  198. test::BOOST_NESTED_TEMPLATE rvalue_stream< typename test::string_type >();
  199. test::BOOST_NESTED_TEMPLATE rvalue_stream< boost::basic_string_view< CharT > >();
  200. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  201. test::BOOST_NESTED_TEMPLATE rvalue_stream< std::basic_string_view< CharT > >();
  202. #endif
  203. }
  204. #endif
  205. // Test output of data to which a reference cannot be bound
  206. BOOST_AUTO_TEST_CASE_TEMPLATE(output_unreferencable_data, CharT, char_types)
  207. {
  208. typedef test_impl< CharT > test;
  209. test::output_unreferencable_data();
  210. }
  211. namespace my_namespace {
  212. class A {};
  213. template< typename CharT, typename TraitsT >
  214. inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, A const&)
  215. {
  216. strm << "A";
  217. return strm;
  218. }
  219. class B {};
  220. template< typename CharT, typename TraitsT >
  221. inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B&)
  222. {
  223. strm << "B";
  224. return strm;
  225. }
  226. template< typename CharT, typename TraitsT >
  227. inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B*)
  228. {
  229. strm << "B*";
  230. return strm;
  231. }
  232. template< typename CharT, typename TraitsT >
  233. inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, const B*)
  234. {
  235. strm << "const B*";
  236. return strm;
  237. }
  238. class C {};
  239. template< typename CharT, typename TraitsT >
  240. inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, C const&)
  241. {
  242. strm << "C";
  243. return strm;
  244. }
  245. enum E { eee };
  246. template< typename CharT, typename TraitsT >
  247. inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, E)
  248. {
  249. strm << "E";
  250. return strm;
  251. }
  252. } // namespace my_namespace
  253. // Test operator forwarding
  254. BOOST_AUTO_TEST_CASE_TEMPLATE(operator_forwarding, CharT, char_types)
  255. {
  256. typedef CharT char_type;
  257. typedef std::basic_string< char_type > string_type;
  258. typedef std::basic_ostringstream< char_type > ostream_type;
  259. typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
  260. string_type str_fmt;
  261. formatting_ostream_type strm_fmt(str_fmt);
  262. const my_namespace::A a = my_namespace::A(); // const lvalue
  263. my_namespace::B b; // lvalue
  264. strm_fmt << a << b << my_namespace::C(); // rvalue
  265. strm_fmt << my_namespace::eee;
  266. strm_fmt << &b << (my_namespace::B const*)&b;
  267. strm_fmt.flush();
  268. ostream_type strm_correct;
  269. strm_correct << a << b << my_namespace::C() << my_namespace::eee << &b << (my_namespace::B const*)&b;
  270. BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
  271. }
  272. namespace my_namespace2 {
  273. class A {};
  274. template< typename CharT, typename TraitsT, typename AllocatorT >
  275. inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, A const&)
  276. {
  277. strm << "A";
  278. return strm;
  279. }
  280. class B {};
  281. template< typename CharT, typename TraitsT, typename AllocatorT >
  282. inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, B&)
  283. {
  284. strm << "B";
  285. return strm;
  286. }
  287. class C {};
  288. template< typename CharT, typename TraitsT, typename AllocatorT >
  289. inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, C const&)
  290. {
  291. strm << "C";
  292. return strm;
  293. }
  294. class D {};
  295. template< typename CharT, typename TraitsT, typename AllocatorT >
  296. inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm,
  297. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  298. D&&
  299. #else
  300. D const&
  301. #endif
  302. )
  303. {
  304. strm << "D";
  305. return strm;
  306. }
  307. enum E { eee };
  308. template< typename CharT, typename TraitsT, typename AllocatorT >
  309. inline logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (logging::basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, E)
  310. {
  311. strm << "E";
  312. return strm;
  313. }
  314. } // namespace my_namespace2
  315. // Test operator overriding
  316. BOOST_AUTO_TEST_CASE_TEMPLATE(operator_overriding, CharT, char_types)
  317. {
  318. typedef CharT char_type;
  319. typedef std::basic_string< char_type > string_type;
  320. typedef std::basic_ostringstream< char_type > ostream_type;
  321. typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type;
  322. string_type str_fmt;
  323. formatting_ostream_type strm_fmt(str_fmt);
  324. const my_namespace2::A a = my_namespace2::A(); // const lvalue
  325. my_namespace2::B b; // lvalue
  326. strm_fmt << a << b << my_namespace2::C() << my_namespace2::D(); // rvalue
  327. strm_fmt << my_namespace2::eee;
  328. strm_fmt.flush();
  329. ostream_type strm_correct;
  330. strm_correct << "ABCDE";
  331. BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str()));
  332. }
  333. #if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T)
  334. namespace {
  335. const char narrow_chars[] = "\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!";
  336. const wchar_t wide_chars[] = { 0x041f, 0x0440, 0x0438, 0x0432, 0x0435, 0x0442, L',', L' ', 0x043c, 0x0438, 0x0440, L'!', 0 };
  337. template< typename StringT >
  338. void test_narrowing_code_conversion()
  339. {
  340. std::locale loc(std::locale::classic(), new utf8_codecvt_facet());
  341. // Test rvalues
  342. {
  343. std::string str_fmt;
  344. logging::formatting_ostream strm_fmt(str_fmt);
  345. strm_fmt.imbue(loc);
  346. strm_fmt << (StringT)wide_chars;
  347. strm_fmt.flush();
  348. BOOST_CHECK(equal_strings(str_fmt, std::string(narrow_chars)));
  349. }
  350. // Test lvalues
  351. {
  352. std::string str_fmt;
  353. logging::formatting_ostream strm_fmt(str_fmt);
  354. strm_fmt.imbue(loc);
  355. StringT wstr = StringT(wide_chars);
  356. strm_fmt << wstr;
  357. strm_fmt.flush();
  358. BOOST_CHECK(equal_strings(str_fmt, std::string(narrow_chars)));
  359. }
  360. // Test const lvalues
  361. {
  362. std::string str_fmt;
  363. logging::formatting_ostream strm_fmt(str_fmt);
  364. strm_fmt.imbue(loc);
  365. const StringT wstr = StringT(wide_chars);
  366. strm_fmt << wstr;
  367. strm_fmt.flush();
  368. BOOST_CHECK(equal_strings(str_fmt, std::string(narrow_chars)));
  369. }
  370. }
  371. template< typename StringT >
  372. void test_widening_code_conversion()
  373. {
  374. std::locale loc(std::locale::classic(), new utf8_codecvt_facet());
  375. // Test rvalues
  376. {
  377. std::wstring str_fmt;
  378. logging::wformatting_ostream strm_fmt(str_fmt);
  379. strm_fmt.imbue(loc);
  380. strm_fmt << (StringT)narrow_chars;
  381. strm_fmt.flush();
  382. BOOST_CHECK(equal_strings(str_fmt, std::wstring(wide_chars)));
  383. }
  384. // Test lvalues
  385. {
  386. std::wstring str_fmt;
  387. logging::wformatting_ostream strm_fmt(str_fmt);
  388. strm_fmt.imbue(loc);
  389. StringT str = StringT(narrow_chars);
  390. strm_fmt << str;
  391. strm_fmt.flush();
  392. BOOST_CHECK(equal_strings(str_fmt, std::wstring(wide_chars)));
  393. }
  394. // Test const lvalues
  395. {
  396. std::wstring str_fmt;
  397. logging::wformatting_ostream strm_fmt(str_fmt);
  398. strm_fmt.imbue(loc);
  399. const StringT str = StringT(narrow_chars);
  400. strm_fmt << str;
  401. strm_fmt.flush();
  402. BOOST_CHECK(equal_strings(str_fmt, std::wstring(wide_chars)));
  403. }
  404. }
  405. } // namespace
  406. // Test character code conversion
  407. BOOST_AUTO_TEST_CASE(character_code_conversion)
  408. {
  409. test_narrowing_code_conversion< const wchar_t* >();
  410. test_widening_code_conversion< const char* >();
  411. test_narrowing_code_conversion< std::wstring >();
  412. test_widening_code_conversion< std::string >();
  413. test_narrowing_code_conversion< boost::wstring_view >();
  414. test_widening_code_conversion< boost::string_view >();
  415. #if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
  416. test_narrowing_code_conversion< std::wstring_view >();
  417. test_widening_code_conversion< std::string_view >();
  418. #endif
  419. }
  420. #endif