253 lines
8.3 KiB
C++
253 lines
8.3 KiB
C++
// ----------------------------------------------------------------------------
|
|
// 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 <boost/property_tree/ptree.hpp>
|
|
|
|
// 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 <boost/test/minimal.hpp>
|
|
#include <boost/property_tree/detail/ptree_utils.hpp>
|
|
#include <fstream>
|
|
#include <cstring>
|
|
#include <sstream>
|
|
|
|
template<class Ptree>
|
|
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<class Ptree>
|
|
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<class Ptree>
|
|
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<class Ptree>
|
|
Ptree get_test_ptree()
|
|
{
|
|
using namespace boost::property_tree;
|
|
typedef typename Ptree::key_type Str;
|
|
Ptree pt;
|
|
pt.put_value(detail::widen<Str>("data0"));
|
|
pt.put(detail::widen<Str>("key1"), detail::widen<Str>("data1"));
|
|
pt.put(detail::widen<Str>("key1.key"), detail::widen<Str>("data2"));
|
|
pt.put(detail::widen<Str>("key2"), detail::widen<Str>("data3"));
|
|
pt.put(detail::widen<Str>("key2.key"), detail::widen<Str>("data4"));
|
|
return pt;
|
|
}
|
|
|
|
// Generic test for file parser
|
|
template<class Ptree, class ReadFunc, class WriteFunc>
|
|
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<class Ptree, class ReadFunc, class WriteFunc>
|
|
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<Ptree, ReadFunc, WriteFunc>(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<class Ptree, class ReadFunc, class WriteFunc, class Error>
|
|
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<Ptree>());
|
|
try
|
|
{
|
|
generic_parser_test<Ptree, ReadFunc, WriteFunc>(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<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 <typename Ch> std::basic_ostream<Ch>& errstream();
|
|
template <> inline
|
|
std::basic_ostream<char>& errstream() { return std::cerr; }
|
|
#ifndef BOOST_NO_CWCHAR
|
|
template <> inline
|
|
std::basic_ostream<wchar_t>& errstream() { return std::wcerr; }
|
|
#endif
|
|
|
|
template <class Ptree, class ReadFunc, class WriteFunc>
|
|
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<Str>(test_data);
|
|
|
|
std::basic_istringstream<Ch> in_stream(native_test_data);
|
|
std::basic_ostringstream<Ch> out_stream;
|
|
Ptree tree;
|
|
rf(in_stream, tree);
|
|
wf(out_stream, tree);
|
|
std::cerr << "(progress) Roundtripped data:\n";
|
|
errstream<Ch>() << out_stream.str();
|
|
std::cerr << "\n-----\n";
|
|
BOOST_CHECK(native_test_data == out_stream.str());
|
|
}
|
|
|
|
#endif
|