test_utils.hpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // ----------------------------------------------------------------------------
  2. // Copyright (C) 2002-2005 Marcin Kalicinski
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // For more information, see www.boost.org
  9. // ----------------------------------------------------------------------------
  10. #ifndef BOOST_PROPERTY_TREE_TEST_UTILS_INCLUDED
  11. #define BOOST_PROPERTY_TREE_TEST_UTILS_INCLUDED
  12. #define BOOST_PROPERTY_TREE_DEBUG // Enable ptree debugging
  13. #include <boost/property_tree/ptree.hpp>
  14. // Do not deprecate insecure CRT calls on VC8
  15. #if (defined(BOOST_MSVC) && (BOOST_MSVC >= 1400) && !defined(_CRT_SECURE_NO_DEPRECATE))
  16. # define _CRT_SECURE_NO_DEPRECATE
  17. #endif
  18. #include <boost/test/minimal.hpp>
  19. #include <boost/property_tree/detail/ptree_utils.hpp>
  20. #include <fstream>
  21. #include <cstring>
  22. #include <sstream>
  23. template<class Ptree>
  24. typename Ptree::size_type total_size(const Ptree &pt)
  25. {
  26. typename Ptree::size_type size = 1;
  27. for (typename Ptree::const_iterator it = pt.begin(); it != pt.end(); ++it)
  28. size += total_size(it->second);
  29. return size;
  30. }
  31. template<class Ptree>
  32. typename Ptree::size_type total_keys_size(const Ptree &pt)
  33. {
  34. typename Ptree::size_type size = 0;
  35. for (typename Ptree::const_iterator it = pt.begin(); it != pt.end(); ++it)
  36. {
  37. size += it->first.size();
  38. size += total_keys_size(it->second);
  39. }
  40. return size;
  41. }
  42. template<class Ptree>
  43. typename Ptree::size_type total_data_size(const Ptree &pt)
  44. {
  45. typename Ptree::size_type size = pt.data().size();
  46. for (typename Ptree::const_iterator it = pt.begin(); it != pt.end(); ++it)
  47. size += total_data_size(it->second);
  48. return size;
  49. }
  50. class test_file
  51. {
  52. public:
  53. test_file(const char *test_data, const char *filename)
  54. {
  55. if (test_data && filename)
  56. {
  57. name = filename;
  58. std::ofstream stream(name.c_str());
  59. using namespace std;
  60. stream.write(test_data, strlen(test_data));
  61. BOOST_CHECK(stream.good());
  62. }
  63. }
  64. ~test_file()
  65. {
  66. if (!name.empty())
  67. remove(name.c_str());
  68. }
  69. private:
  70. std::string name;
  71. };
  72. template<class Ptree>
  73. Ptree get_test_ptree()
  74. {
  75. using namespace boost::property_tree;
  76. typedef typename Ptree::key_type Str;
  77. Ptree pt;
  78. pt.put_value(detail::widen<Str>("data0"));
  79. pt.put(detail::widen<Str>("key1"), detail::widen<Str>("data1"));
  80. pt.put(detail::widen<Str>("key1.key"), detail::widen<Str>("data2"));
  81. pt.put(detail::widen<Str>("key2"), detail::widen<Str>("data3"));
  82. pt.put(detail::widen<Str>("key2.key"), detail::widen<Str>("data4"));
  83. return pt;
  84. }
  85. // Generic test for file parser
  86. template<class Ptree, class ReadFunc, class WriteFunc>
  87. void generic_parser_test(Ptree &pt,
  88. ReadFunc rf,
  89. WriteFunc wf,
  90. const char *test_data_1,
  91. const char *test_data_2,
  92. const char *filename_1,
  93. const char *filename_2,
  94. const char *filename_out)
  95. {
  96. using namespace boost::property_tree;
  97. // Create test files
  98. test_file file_1(test_data_1, filename_1);
  99. test_file file_2(test_data_2, filename_2);
  100. test_file file_out("", filename_out);
  101. rf(filename_1, pt); // Read file
  102. wf(filename_out, pt); // Write file
  103. Ptree pt2;
  104. rf(filename_out, pt2); // Read file again
  105. // Compare original with read
  106. BOOST_CHECK(pt == pt2);
  107. }
  108. // Generic test for file parser with expected success
  109. template<class Ptree, class ReadFunc, class WriteFunc>
  110. void generic_parser_test_ok(ReadFunc rf,
  111. WriteFunc wf,
  112. const char *test_data_1,
  113. const char *test_data_2,
  114. const char *filename_1,
  115. const char *filename_2,
  116. const char *filename_out,
  117. unsigned int total_size,
  118. unsigned int total_data_size,
  119. unsigned int total_keys_size)
  120. {
  121. using namespace boost::property_tree;
  122. std::cerr << "(progress) Starting generic parser test with test file \"" << filename_1 << "\"\n";
  123. // Make sure no instances exist
  124. //BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
  125. try
  126. {
  127. // Read file
  128. Ptree pt;
  129. generic_parser_test<Ptree, ReadFunc, WriteFunc>(pt, rf, wf,
  130. test_data_1, test_data_2,
  131. filename_1, filename_2, filename_out);
  132. // Determine total sizes
  133. typename Ptree::size_type actual_total_size = ::total_size(pt);
  134. typename Ptree::size_type actual_data_size = ::total_data_size(pt);
  135. typename Ptree::size_type actual_keys_size = ::total_keys_size(pt);
  136. if (actual_total_size != total_size ||
  137. actual_data_size != total_data_size ||
  138. actual_keys_size != total_keys_size)
  139. std::cerr << "Sizes: " << (unsigned)::total_size(pt) << ", " << (unsigned)::total_data_size(pt) << ", " << (unsigned)::total_keys_size(pt) << "\n";
  140. // Check total sizes
  141. BOOST_CHECK(actual_total_size == total_size);
  142. BOOST_CHECK(actual_data_size == total_data_size);
  143. BOOST_CHECK(actual_keys_size == total_keys_size);
  144. }
  145. catch (std::runtime_error &e)
  146. {
  147. BOOST_ERROR(e.what());
  148. }
  149. // Test for leaks
  150. //BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
  151. }
  152. // Generic test for file parser with expected error
  153. template<class Ptree, class ReadFunc, class WriteFunc, class Error>
  154. void generic_parser_test_error(ReadFunc rf,
  155. WriteFunc wf,
  156. const char *test_data_1,
  157. const char *test_data_2,
  158. const char *filename_1,
  159. const char *filename_2,
  160. const char *filename_out,
  161. unsigned long expected_error_line)
  162. {
  163. std::cerr << "(progress) Starting generic parser test with test file \"" << filename_1 << "\"\n";
  164. // Make sure no instances exist
  165. //BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
  166. {
  167. // Create ptree as a copy of test ptree (to test if read failure does not damage ptree)
  168. Ptree pt(get_test_ptree<Ptree>());
  169. try
  170. {
  171. generic_parser_test<Ptree, ReadFunc, WriteFunc>(pt, rf, wf,
  172. test_data_1, test_data_2,
  173. filename_1, filename_2, filename_out);
  174. BOOST_ERROR("No required exception thrown");
  175. }
  176. catch (Error &e)
  177. {
  178. BOOST_CHECK(e.line() == expected_error_line); // Test line number
  179. BOOST_CHECK(pt == get_test_ptree<Ptree>()); // Test if error damaged contents
  180. }
  181. catch (...)
  182. {
  183. BOOST_ERROR("Invalid exception type thrown");
  184. throw;
  185. }
  186. }
  187. // Test for leaks
  188. //BOOST_CHECK(Ptree::debug_get_instances_count() == 0);
  189. }
  190. template <typename Ch> std::basic_ostream<Ch>& errstream();
  191. template <> inline
  192. std::basic_ostream<char>& errstream() { return std::cerr; }
  193. #ifndef BOOST_NO_CWCHAR
  194. template <> inline
  195. std::basic_ostream<wchar_t>& errstream() { return std::wcerr; }
  196. #endif
  197. template <class Ptree, class ReadFunc, class WriteFunc>
  198. void check_exact_roundtrip(ReadFunc rf, WriteFunc wf, const char *test_data) {
  199. std::cerr << "(progress) Starting exact roundtrip test with test data:\n"
  200. << test_data << "\n-----\n";
  201. using namespace boost::property_tree;
  202. typedef typename Ptree::key_type::value_type Ch;
  203. typedef typename Ptree::key_type Str;
  204. Str native_test_data = detail::widen<Str>(test_data);
  205. std::basic_istringstream<Ch> in_stream(native_test_data);
  206. std::basic_ostringstream<Ch> out_stream;
  207. Ptree tree;
  208. rf(in_stream, tree);
  209. wf(out_stream, tree);
  210. std::cerr << "(progress) Roundtripped data:\n";
  211. errstream<Ch>() << out_stream.str();
  212. std::cerr << "\n-----\n";
  213. BOOST_CHECK(native_test_data == out_stream.str());
  214. }
  215. #endif