// ---------------------------------------------------------------------------- // Copyright (C) 2002-2005 Marcin Kalicinski // // 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) // // For more information, see www.boost.org // ---------------------------------------------------------------------------- #ifndef BOOST_PROPERTY_TREE_TEST_UTILS_INCLUDED #define BOOST_PROPERTY_TREE_TEST_UTILS_INCLUDED #define BOOST_PROPERTY_TREE_DEBUG // Enable ptree debugging #include // Do not deprecate insecure CRT calls on VC8 #if (defined(BOOST_MSVC) && (BOOST_MSVC >= 1400) && !defined(_CRT_SECURE_NO_DEPRECATE)) # define _CRT_SECURE_NO_DEPRECATE #endif #include #include #include #include #include template typename Ptree::size_type total_size(const Ptree &pt) { typename Ptree::size_type size = 1; for (typename Ptree::const_iterator it = pt.begin(); it != pt.end(); ++it) size += total_size(it->second); return size; } template typename Ptree::size_type total_keys_size(const Ptree &pt) { typename Ptree::size_type size = 0; for (typename Ptree::const_iterator it = pt.begin(); it != pt.end(); ++it) { size += it->first.size(); size += total_keys_size(it->second); } return size; } template typename Ptree::size_type total_data_size(const Ptree &pt) { typename Ptree::size_type size = pt.data().size(); for (typename Ptree::const_iterator it = pt.begin(); it != pt.end(); ++it) size += total_data_size(it->second); return size; } class test_file { public: test_file(const char *test_data, const char *filename) { if (test_data && filename) { name = filename; std::ofstream stream(name.c_str()); using namespace std; stream.write(test_data, strlen(test_data)); BOOST_CHECK(stream.good()); } } ~test_file() { if (!name.empty()) remove(name.c_str()); } private: std::string name; }; template Ptree get_test_ptree() { using namespace boost::property_tree; typedef typename Ptree::key_type Str; Ptree pt; pt.put_value(detail::widen("data0")); pt.put(detail::widen("key1"), detail::widen("data1")); pt.put(detail::widen("key1.key"), detail::widen("data2")); pt.put(detail::widen("key2"), detail::widen("data3")); pt.put(detail::widen("key2.key"), detail::widen("data4")); return pt; } // Generic test for file parser template void generic_parser_test(Ptree &pt, ReadFunc rf, WriteFunc wf, const char *test_data_1, const char *test_data_2, const char *filename_1, const char *filename_2, const char *filename_out) { using namespace boost::property_tree; // Create test files test_file file_1(test_data_1, filename_1); test_file file_2(test_data_2, filename_2); test_file file_out("", filename_out); rf(filename_1, pt); // Read file wf(filename_out, pt); // Write file Ptree pt2; rf(filename_out, pt2); // Read file again // Compare original with read BOOST_CHECK(pt == pt2); } // Generic test for file parser with expected success template void generic_parser_test_ok(ReadFunc rf, WriteFunc wf, const char *test_data_1, const char *test_data_2, const char *filename_1, const char *filename_2, const char *filename_out, unsigned int total_size, unsigned int total_data_size, unsigned int total_keys_size) { using namespace boost::property_tree; std::cerr << "(progress) Starting generic parser test with test file \"" << filename_1 << "\"\n"; // Make sure no instances exist //BOOST_CHECK(Ptree::debug_get_instances_count() == 0); try { // Read file Ptree pt; generic_parser_test(pt, rf, wf, test_data_1, test_data_2, filename_1, filename_2, filename_out); // Determine total sizes typename Ptree::size_type actual_total_size = ::total_size(pt); typename Ptree::size_type actual_data_size = ::total_data_size(pt); typename Ptree::size_type actual_keys_size = ::total_keys_size(pt); if (actual_total_size != total_size || actual_data_size != total_data_size || actual_keys_size != total_keys_size) std::cerr << "Sizes: " << (unsigned)::total_size(pt) << ", " << (unsigned)::total_data_size(pt) << ", " << (unsigned)::total_keys_size(pt) << "\n"; // Check total sizes BOOST_CHECK(actual_total_size == total_size); BOOST_CHECK(actual_data_size == total_data_size); BOOST_CHECK(actual_keys_size == total_keys_size); } catch (std::runtime_error &e) { BOOST_ERROR(e.what()); } // Test for leaks //BOOST_CHECK(Ptree::debug_get_instances_count() == 0); } // Generic test for file parser with expected error template void generic_parser_test_error(ReadFunc rf, WriteFunc wf, const char *test_data_1, const char *test_data_2, const char *filename_1, const char *filename_2, const char *filename_out, unsigned long expected_error_line) { std::cerr << "(progress) Starting generic parser test with test file \"" << filename_1 << "\"\n"; // Make sure no instances exist //BOOST_CHECK(Ptree::debug_get_instances_count() == 0); { // Create ptree as a copy of test ptree (to test if read failure does not damage ptree) Ptree pt(get_test_ptree()); try { generic_parser_test(pt, rf, wf, test_data_1, test_data_2, filename_1, filename_2, filename_out); BOOST_ERROR("No required exception thrown"); } catch (Error &e) { BOOST_CHECK(e.line() == expected_error_line); // Test line number BOOST_CHECK(pt == get_test_ptree()); // Test if error damaged contents } catch (...) { BOOST_ERROR("Invalid exception type thrown"); throw; } } // Test for leaks //BOOST_CHECK(Ptree::debug_get_instances_count() == 0); } template std::basic_ostream& errstream(); template <> inline std::basic_ostream& errstream() { return std::cerr; } #ifndef BOOST_NO_CWCHAR template <> inline std::basic_ostream& errstream() { return std::wcerr; } #endif template void check_exact_roundtrip(ReadFunc rf, WriteFunc wf, const char *test_data) { std::cerr << "(progress) Starting exact roundtrip test with test data:\n" << test_data << "\n-----\n"; using namespace boost::property_tree; typedef typename Ptree::key_type::value_type Ch; typedef typename Ptree::key_type Str; Str native_test_data = detail::widen(test_data); std::basic_istringstream in_stream(native_test_data); std::basic_ostringstream out_stream; Ptree tree; rf(in_stream, tree); wf(out_stream, tree); std::cerr << "(progress) Roundtripped data:\n"; errstream() << out_stream.str(); std::cerr << "\n-----\n"; BOOST_CHECK(native_test_data == out_stream.str()); } #endif