// ----------------------------------------------------------------------------
// Copyright (C) 2002-2006 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
// ----------------------------------------------------------------------------

// Intentionally no include guards (to be included more than once)

#if !defined(CHTYPE) || !defined(T) || !defined(PTREE) || !defined(NOCASE) || !defined(WIDECHAR)
#   error No character type specified
#endif

void test_debug(PTREE *)
{
#if 0
    // Check count
    BOOST_TEST(PTREE::debug_get_instances_count() == 0);

    {

        // Create ptrees
        PTREE pt1, pt2;
        BOOST_TEST(PTREE::debug_get_instances_count() == 2);

        // Create PTREE
        PTREE *pt3 = new PTREE;
        BOOST_TEST(PTREE::debug_get_instances_count() == 3);

        // Insert
        pt1.push_back(std::make_pair(T("key"), *pt3));
        BOOST_TEST(PTREE::debug_get_instances_count() == 4);

        // Insert
        pt2.push_back(std::make_pair(T("key"), *pt3));
        BOOST_TEST(PTREE::debug_get_instances_count() == 5);

        // Clear
        pt1.clear();
        BOOST_TEST(PTREE::debug_get_instances_count() == 4);

        // Clear
        pt2.clear();
        BOOST_TEST(PTREE::debug_get_instances_count() == 3);

        // Delete
        delete pt3;
        BOOST_TEST(PTREE::debug_get_instances_count() == 2);

    }

    // Check count
    BOOST_TEST(PTREE::debug_get_instances_count() == 0);
#endif
}

void test_constructor_destructor_assignment(PTREE *)
{

    {

        // Test constructor from string
        PTREE pt1(T("data"));
        BOOST_TEST(pt1.data() == T("data"));
        //BOOST_TEST(PTREE::debug_get_instances_count() == 1);

        // Do insertions
        PTREE &tmp1 = pt1.put(T("key1"), T("data1"));
        PTREE &tmp2 = pt1.put(T("key2"), T("data2"));
        tmp1.put(T("key3"), T("data3"));
        tmp2.put(T("key4"), T("data4"));
        //BOOST_TEST(PTREE::debug_get_instances_count() == 5);

        // Make a copy using copy constructor
        PTREE *pt2 = new PTREE(pt1);
        BOOST_TEST(*pt2 == pt1);
        //BOOST_TEST(PTREE::debug_get_instances_count() == 10);

        // Make a copy using = operator
        PTREE *pt3 = new PTREE;
        *pt3 = *pt2;
        BOOST_TEST(*pt3 == *pt2);
        //BOOST_TEST(PTREE::debug_get_instances_count() == 15);

        // Test self assignment
        pt1 = pt1;
        BOOST_TEST(pt1 == *pt2);
        BOOST_TEST(pt1 == *pt3);
        //BOOST_TEST(PTREE::debug_get_instances_count() == 15);

        // Destroy
        delete pt2;
        //BOOST_TEST(PTREE::debug_get_instances_count() == 10);

        // Destroy
        delete pt3;
        //BOOST_TEST(PTREE::debug_get_instances_count() == 5);

    }

    // Check count
    //BOOST_TEST(PTREE::debug_get_instances_count() == 0);

}

void test_insertion(PTREE *)
{

    // Do insertions
    PTREE pt;
    PTREE tmp1(T("data1"));
    PTREE tmp2(T("data2"));
    PTREE tmp3(T("data3"));
    PTREE tmp4(T("data4"));
    PTREE::iterator it1 = pt.insert(pt.end(), std::make_pair(T("key1"), tmp1));
    PTREE::iterator it2 = pt.insert(it1, std::make_pair(T("key2"), tmp2));
    PTREE::iterator it3 = it1->second.push_back(std::make_pair(T("key3"), tmp3));
    PTREE::iterator it4 = it1->second.push_front(std::make_pair(T("key4"), tmp4));
    it2->second.insert(it2->second.end(), it1->second.begin(), it1->second.end());

    // Check instance count
    //BOOST_TEST(PTREE::debug_get_instances_count() == 11);

    // Check contents
    BOOST_TEST(pt.get(T("key1"), T("")) == T("data1"));
    BOOST_TEST(pt.get(T("key2"), T("")) == T("data2"));
    BOOST_TEST(pt.get(T("key1.key3"), T("")) == T("data3"));
    BOOST_TEST(pt.get(T("key1.key4"), T("")) == T("data4"));
    BOOST_TEST(pt.get(T("key2.key3"), T("")) == T("data3"));
    BOOST_TEST(pt.get(T("key2.key4"), T("")) == T("data4"));

    // Check sequence
    PTREE::iterator it = it2;
    ++it; BOOST_TEST(it == it1);
    ++it; BOOST_TEST(it == pt.end());
    it = it4; 
    ++it; BOOST_TEST(it == it3);
    ++it; BOOST_TEST(it == it1->second.end());

}

void test_erasing(PTREE *)
{
    
    // Do insertions
    PTREE pt;
    PTREE tmp1(T("data1"));
    PTREE tmp2(T("data2"));
    PTREE tmp3(T("data3"));
    PTREE tmp4(T("data4"));
    PTREE::iterator it1 = pt.insert(pt.end(), std::make_pair(T("key1"), tmp1));
    PTREE::iterator it2 = pt.insert(it1, std::make_pair(T("key2"), tmp2));
    it1->second.push_back(std::make_pair(T("key"), tmp3));
    it1->second.push_front(std::make_pair(T("key"), tmp4));
    it2->second.insert(it2->second.end(), it1->second.begin(), it1->second.end());

    // Check instance count
    //BOOST_TEST(PTREE::debug_get_instances_count() == 11);

    // Test range erase
    PTREE::iterator it = it1->second.erase(it1->second.begin(), it1->second.end());
    BOOST_TEST(it == it1->second.end());
    //BOOST_TEST(PTREE::debug_get_instances_count() == 9);

    // Test single erase
    PTREE::size_type n = pt.erase(T("key1"));
    BOOST_TEST(n == 1);
    //BOOST_TEST(PTREE::debug_get_instances_count() == 8);

    // Test multiple erase
    n = it2->second.erase(T("key"));
    BOOST_TEST(n == 2);
    //BOOST_TEST(PTREE::debug_get_instances_count() == 6);

    // Test one more erase
    n = pt.erase(T("key2"));
    BOOST_TEST(n == 1);
    //BOOST_TEST(PTREE::debug_get_instances_count() == 5);

}

void test_clear(PTREE *)
{

    // Do insertions
    PTREE pt(T("data"));
    pt.push_back(std::make_pair(T("key"), PTREE(T("data"))));

    // Check instance count
    //BOOST_TEST(PTREE::debug_get_instances_count() == 2);

    // Test clear
    pt.clear();
    BOOST_TEST(pt.empty());
    BOOST_TEST(pt.data().empty());
    //BOOST_TEST(PTREE::debug_get_instances_count() == 1);

}

void test_pushpop(PTREE *)
{

    // Do insertions
    PTREE pt;
    PTREE tmp1(T("data1"));
    PTREE tmp2(T("data2"));
    PTREE tmp3(T("data3"));
    PTREE tmp4(T("data4"));
    pt.push_back(std::make_pair(T("key3"), tmp3));
    pt.push_front(std::make_pair(T("key2"), tmp2));
    pt.push_back(std::make_pair(T("key4"), tmp4));
    pt.push_front(std::make_pair(T("key1"), tmp1));

    // Check instance count
    //BOOST_TEST(PTREE::debug_get_instances_count() == 9);

    // Check sequence
    PTREE::iterator it = pt.begin();
    BOOST_TEST(it->first == T("key1")); ++it;
    BOOST_TEST(it->first == T("key2")); ++it;
    BOOST_TEST(it->first == T("key3")); ++it;
    BOOST_TEST(it->first == T("key4")); ++it;
    BOOST_TEST(it == pt.end());

    // Test pops
    pt.pop_back();
    //BOOST_TEST(PTREE::debug_get_instances_count() == 8);
    BOOST_TEST(pt.front().second.data() == T("data1"));
    BOOST_TEST(pt.back().second.data() == T("data3"));
    pt.pop_front();
    //BOOST_TEST(PTREE::debug_get_instances_count() == 7);
    BOOST_TEST(pt.front().second.data() == T("data2"));
    BOOST_TEST(pt.back().second.data() == T("data3"));
    pt.pop_back();
    //BOOST_TEST(PTREE::debug_get_instances_count() == 6);
    BOOST_TEST(pt.front().second.data() == T("data2"));
    BOOST_TEST(pt.back().second.data() == T("data2"));
    pt.pop_front();
    //BOOST_TEST(PTREE::debug_get_instances_count() == 5);
    BOOST_TEST(pt.empty());

}

void test_container_iteration(PTREE *)
{
    
    // Do insertions
    PTREE pt;
    pt.put(T("key3"), T(""));
    pt.put(T("key1"), T(""));
    pt.put(T("key4"), T(""));
    pt.put(T("key2"), T(""));

    // iterator
    {
        PTREE::iterator it = pt.begin();
        BOOST_TEST(it->first == T("key3")); ++it;
        BOOST_TEST(it->first == T("key1")); ++it;
        BOOST_TEST(it->first == T("key4")); ++it;
        BOOST_TEST(it->first == T("key2")); ++it;
        BOOST_TEST(it == pt.end());
    }

    // const_iterator
    {
        PTREE::const_iterator it = pt.begin();
        BOOST_TEST(it->first == T("key3")); ++it;
        BOOST_TEST(it->first == T("key1")); ++it;
        BOOST_TEST(it->first == T("key4")); ++it;
        BOOST_TEST(it->first == T("key2")); ++it;
        BOOST_TEST(it == pt.end());
    }

    // reverse_iterator
    {
        PTREE::reverse_iterator it = pt.rbegin();
        BOOST_TEST(it->first == T("key2")); ++it;
        BOOST_TEST(it->first == T("key4")); ++it;
        BOOST_TEST(it->first == T("key1")); ++it;
        BOOST_TEST(it->first == T("key3")); ++it;
        BOOST_TEST(it == pt.rend());
    }

    // const_reverse_iterator
    {
        PTREE::const_reverse_iterator it = pt.rbegin();
        BOOST_TEST(it->first == T("key2")); ++it;
        BOOST_TEST(it->first == T("key4")); ++it;
        BOOST_TEST(it->first == T("key1")); ++it;
        BOOST_TEST(it->first == T("key3")); ++it;
        BOOST_TEST(it == PTREE::const_reverse_iterator(pt.rend()));
    }

}

void test_swap(PTREE *)
{
    
    PTREE pt1, pt2;

    // Do insertions
    pt1.put(T("key1"), T(""));
    pt1.put(T("key2"), T(""));
    pt1.put(T("key1.key3"), T(""));
    pt1.put(T("key1.key4"), T(""));

    // Check counts
    //BOOST_TEST(PTREE::debug_get_instances_count() == 6);
    BOOST_TEST(pt1.size() == 2);
    BOOST_TEST(pt1.get_child(T("key1")).size() == 2);
    BOOST_TEST(pt2.size() == 0);

    // Swap using member function
    pt1.swap(pt2);
    
    // Check counts
    //BOOST_TEST(PTREE::debug_get_instances_count() == 6);
    BOOST_TEST(pt2.size() == 2);
    BOOST_TEST(pt2.get_child(T("key1")).size() == 2);
    BOOST_TEST(pt1.size() == 0);

    // Swap using free function
    swap(pt1, pt2);

    // Check counts
    //BOOST_TEST(PTREE::debug_get_instances_count() == 6);
    BOOST_TEST(pt1.size() == 2);
    BOOST_TEST(pt1.get_child(T("key1")).size() == 2);
    BOOST_TEST(pt2.size() == 0);

    // Swap using std algorithm
    std::swap(pt1, pt2);

    // Check counts
    //BOOST_TEST(PTREE::debug_get_instances_count() == 6);
    BOOST_TEST(pt2.size() == 2);
    BOOST_TEST(pt2.get_child(T("key1")).size() == 2);
    BOOST_TEST(pt1.size() == 0);

}

void test_sort_reverse(PTREE *)
{
    
    PTREE pt;

    // Do insertions
    pt.put(T("key2"), T("data2"));
    pt.put(T("key1"), T("data1"));
    pt.put(T("key4"), T("data4"));
    pt.put(T("key3"), T("data3"));
    pt.put(T("key3.key1"), T(""));
    pt.put(T("key4.key2"), T(""));

    // Reverse
    pt.reverse();

    // Check sequence
    {
        PTREE::iterator it = pt.begin();
        BOOST_TEST(it->first == T("key3")); ++it;
        BOOST_TEST(it->first == T("key4")); ++it;
        BOOST_TEST(it->first == T("key1")); ++it;
        BOOST_TEST(it->first == T("key2")); ++it;
        BOOST_TEST(it == pt.end());
    }
    // Check sequence using find to check if index is ok
    {
        PTREE::iterator it = pt.begin();
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key3")))); ++it;
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key4")))); ++it;
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key1")))); ++it;
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key2")))); ++it;
        BOOST_TEST(it == pt.end());
    }

    // Sort
    pt.sort(SortPred<PTREE>());

    // Check sequence
    {
        PTREE::iterator it = pt.begin();
        BOOST_TEST(it->first == T("key1")); ++it;
        BOOST_TEST(it->first == T("key2")); ++it;
        BOOST_TEST(it->first == T("key3")); ++it;
        BOOST_TEST(it->first == T("key4")); ++it;
        BOOST_TEST(it == pt.end());
    }
    // Check sequence (using find to check if index is ok)
    {
        PTREE::iterator it = pt.begin();
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key1")))); ++it;
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key2")))); ++it;
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key3")))); ++it;
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key4")))); ++it;
        BOOST_TEST(it == pt.end());
    }
    
    // Sort reverse
    pt.sort(SortPredRev<PTREE>());

    // Check sequence
    {
        PTREE::iterator it = pt.begin();
        BOOST_TEST(it->first == T("key4")); ++it;
        BOOST_TEST(it->first == T("key3")); ++it;
        BOOST_TEST(it->first == T("key2")); ++it;
        BOOST_TEST(it->first == T("key1")); ++it;
        BOOST_TEST(it == pt.end());
    }
    // Check sequence (using find to check if index is ok)
    {
        PTREE::iterator it = pt.begin();
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key4")))); ++it;
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key3")))); ++it;
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key2")))); ++it;
        BOOST_TEST(it == pt.to_iterator(pt.find(T("key1")))); ++it;
        BOOST_TEST(it == pt.end());
    }

}

void test_case(PTREE *)
{
    
    // Do insertions
    PTREE pt;
    pt.put(T("key1"), T("data1"));
    pt.put(T("KEY2"), T("data2"));
    pt.put(T("kEy1.keY3"), T("data3"));
    pt.put(T("KEY1.key4"), T("data4"));

    // Check findings depending on traits type
#if (NOCASE == 0)
    //BOOST_TEST(PTREE::debug_get_instances_count() == 7);
    BOOST_TEST(pt.get(T("key1"), T("")) == T("data1"));
    BOOST_TEST(pt.get(T("key2"), T("")) == T(""));
    BOOST_TEST(pt.get(T("key1.key3"), T("")) == T(""));
    BOOST_TEST(pt.get(T("KEY1.key4"), T("")) == T("data4"));
#else
    //BOOST_TEST(PTREE::debug_get_instances_count() == 5);
    BOOST_TEST(pt.get(T("key1"), T("1")) == pt.get(T("KEY1"), T("2")));
    BOOST_TEST(pt.get(T("key2"), T("1")) == pt.get(T("KEY2"), T("2")));
    BOOST_TEST(pt.get(T("key1.key3"), T("1")) == pt.get(T("KEY1.KEY3"), T("2")));
    BOOST_TEST(pt.get(T("key1.key4"), T("1")) == pt.get(T("KEY1.KEY4"), T("2")));
#endif

    // Do more insertions
    pt.push_back(PTREE::value_type(T("key1"), PTREE()));
    pt.push_back(PTREE::value_type(T("key1"), PTREE()));

    // Test counts
#if (NOCASE == 0)
    BOOST_TEST(pt.count(T("key1")) == 3);
    BOOST_TEST(pt.count(T("KEY1")) == 1);
    BOOST_TEST(pt.count(T("key2")) == 0);
    BOOST_TEST(pt.count(T("KEY2")) == 1);
    BOOST_TEST(pt.count(T("key3")) == 0);
    BOOST_TEST(pt.count(T("KEY3")) == 0);
#else
    BOOST_TEST(pt.count(T("key1")) == 3);
    BOOST_TEST(pt.count(T("KEY1")) == 3);
    BOOST_TEST(pt.count(T("key2")) == 1);
    BOOST_TEST(pt.count(T("KEY2")) == 1);
    BOOST_TEST(pt.count(T("key3")) == 0);
    BOOST_TEST(pt.count(T("KEY3")) == 0);
#endif

}

void test_comparison(PTREE *)
{

    // Prepare original
    PTREE pt_orig(T("data"));
    pt_orig.put(T("key1"), T("data1"));
    pt_orig.put(T("key1.key3"), T("data2"));
    pt_orig.put(T("key1.key4"), T("data3"));
    pt_orig.put(T("key2"), T("data4"));

    // Test originals
    {
        PTREE pt1(pt_orig);
        PTREE pt2(pt_orig);
        BOOST_TEST(pt1 == pt2);
        BOOST_TEST(pt2 == pt1);
        BOOST_TEST(!(pt1 != pt2));
        BOOST_TEST(!(pt2 != pt1));
    }

    // Test originals with modified case
#if (NOCASE != 0)
    {
        PTREE pt1(pt_orig);
        PTREE pt2(pt_orig);
        pt1.pop_back();
        pt1.put(T("KEY2"), T("data4"));
        BOOST_TEST(pt1 == pt2);
        BOOST_TEST(pt2 == pt1);
        BOOST_TEST(!(pt1 != pt2));
        BOOST_TEST(!(pt2 != pt1));
    }
#endif

    // Test modified copies (both modified the same way)
    {
        PTREE pt1(pt_orig);
        PTREE pt2(pt_orig);
        pt1.put(T("key1.key5"), T("."));
        pt2.put(T("key1.key5"), T("."));
        BOOST_TEST(pt1 == pt2);
        BOOST_TEST(pt2 == pt1);
        BOOST_TEST(!(pt1 != pt2));
        BOOST_TEST(!(pt2 != pt1));
    }

    // Test modified copies (modified root data)
    {
        PTREE pt1(pt_orig);
        PTREE pt2(pt_orig);
        pt1.data() = T("a");
        pt2.data() = T("b");
        BOOST_TEST(!(pt1 == pt2));
        BOOST_TEST(!(pt2 == pt1));
        BOOST_TEST(pt1 != pt2);
        BOOST_TEST(pt2 != pt1);
    }

    // Test modified copies (added subkeys with different data)
    {
        PTREE pt1(pt_orig);
        PTREE pt2(pt_orig);
        pt1.put(T("key1.key5"), T("a"));
        pt2.put(T("key1.key5"), T("b"));
        BOOST_TEST(!(pt1 == pt2));
        BOOST_TEST(!(pt2 == pt1));
        BOOST_TEST(pt1 != pt2);
        BOOST_TEST(pt2 != pt1);
    }

    // Test modified copies (added subkeys with different keys)
    {
        PTREE pt1(pt_orig);
        PTREE pt2(pt_orig);
        pt1.put(T("key1.key5"), T(""));
        pt2.put(T("key1.key6"), T(""));
        BOOST_TEST(!(pt1 == pt2));
        BOOST_TEST(!(pt2 == pt1));
        BOOST_TEST(pt1 != pt2);
        BOOST_TEST(pt2 != pt1);
    }

    // Test modified copies (added subkey to only one copy)
    {
        PTREE pt1(pt_orig);
        PTREE pt2(pt_orig);
        pt1.put(T("key1.key5"), T(""));
        BOOST_TEST(!(pt1 == pt2));
        BOOST_TEST(!(pt2 == pt1));
        BOOST_TEST(pt1 != pt2);
        BOOST_TEST(pt2 != pt1);
    }

}

void test_front_back(PTREE *)
{
    
    // Do insertions
    PTREE pt;
    pt.put(T("key1"), T(""));
    pt.put(T("key2"), T(""));

    // Check front and back
    BOOST_TEST(pt.front().first == T("key1"));
    BOOST_TEST(pt.back().first == T("key2"));

}

void test_get_put(PTREE *)
{
    
    typedef std::basic_string<CHTYPE> str_t;

    // Temporary storage
    str_t tmp_string;
    boost::optional<int> opt_int;
    boost::optional<long> opt_long;
    boost::optional<double> opt_double;
    boost::optional<float> opt_float;
    boost::optional<str_t> opt_string;
    boost::optional<CHTYPE> opt_char;
    boost::optional<bool> opt_bool;
    
    // Do insertions via put
    PTREE pt;
    PTREE &pt1 = pt.put(T("k1"), 1);
    PTREE &pt2 = pt.put(T("k2.k"), 2.5);
    PTREE &pt3 = pt.put(T("k3.k.k"), T("ala ma kota"));
    PTREE &pt4 = pt.put(T("k4.k.k.k"), CHTYPE('c'));
    PTREE &pt5 = pt.put(T("k5.k.k.k.f"), false);
    PTREE &pt6 = pt.put(T("k5.k.k.k.t"), true);

    // Check instances count
    //BOOST_TEST(PTREE::debug_get_instances_count() == 17);

    // Check if const char * version returns std::string
    BOOST_TEST(typeid(pt.get_value(T(""))) == typeid(str_t));
    
    // Do extractions via get (throwing version)
    BOOST_TEST(pt.get<int>(T("k1")) == 1);
    BOOST_TEST(pt.get<long>(T("k1")) == 1);
    BOOST_TEST(pt.get<double>(T("k2.k")) == 2.5);
    BOOST_TEST(pt.get<float>(T("k2.k")) == 2.5f);
    BOOST_TEST(pt.get<str_t>(T("k3.k.k")) == str_t(T("ala ma kota")));
    BOOST_TEST(pt.get<CHTYPE>(T("k4.k.k.k")) == CHTYPE('c'));
    BOOST_TEST(pt.get<bool>(T("k5.k.k.k.f")) == false);
    BOOST_TEST(pt.get<bool>(T("k5.k.k.k.t")) == true);

    // Do extractions via get (default value version)
    BOOST_TEST(pt.get(T("k1"), 0) == 1);
    BOOST_TEST(pt.get(T("k1"), 0L) == 1);
    BOOST_TEST(pt.get(T("k2.k"), 0.0) == 2.5);
    BOOST_TEST(pt.get(T("k2.k"), 0.0f) == 2.5f);
    BOOST_TEST(pt.get(T("k3.k.k"), str_t()) == str_t(T("ala ma kota")));
    BOOST_TEST(pt.get(T("k3.k.k"), T("")) == T("ala ma kota"));
    BOOST_TEST(pt.get(T("k4.k.k.k"), CHTYPE('\0')) == CHTYPE('c'));
    BOOST_TEST(pt.get(T("k5.k.k.k.f"), true) == false);
    BOOST_TEST(pt.get(T("k5.k.k.k.t"), false) == true);

    // Do extractions via get (optional version)
    opt_int = pt.get_optional<int>(T("k1"));
    BOOST_TEST(opt_int && *opt_int == 1);
    opt_long = pt.get_optional<long>(T("k1"));
    BOOST_TEST(opt_long && *opt_long == 1);
    opt_double = pt.get_optional<double>(T("k2.k"));
    BOOST_TEST(opt_double && *opt_double == 2.5);
    opt_float = pt.get_optional<float>(T("k2.k"));
    BOOST_TEST(opt_float && *opt_float == 2.5f);
    opt_string = pt.get_optional<str_t>(T("k3.k.k"));
    BOOST_TEST(opt_string && *opt_string == str_t(T("ala ma kota")));
    opt_char = pt.get_optional<CHTYPE>(T("k4.k.k.k"));
    BOOST_TEST(opt_char && *opt_char == CHTYPE('c'));
    opt_bool = pt.get_optional<bool>(T("k5.k.k.k.f"));
    BOOST_TEST(opt_bool && *opt_bool == false);
    opt_bool = pt.get_optional<bool>(T("k5.k.k.k.t"));
    BOOST_TEST(opt_bool && *opt_bool == true);

    // Do insertions via put_value
    pt1.put_value(short(1));
    pt2.put_value(2.5f);
    pt3.put_value(str_t(T("ala ma kota")));
    pt4.put_value(CHTYPE('c'));
    pt5.put_value(false);
    pt6.put_value(true);

    // Do extractions via get_value (throwing version)
    BOOST_TEST(pt1.get_value<int>() == 1);
    BOOST_TEST(pt1.get_value<long>() == 1);
    BOOST_TEST(pt2.get_value<double>() == 2.5);
    BOOST_TEST(pt2.get_value<float>() == 2.5f);
    BOOST_TEST(pt3.get_value<str_t>() == str_t(T("ala ma kota")));
    BOOST_TEST(pt4.get_value<CHTYPE>() == CHTYPE('c'));
    BOOST_TEST(pt5.get_value<bool>() == false);
    BOOST_TEST(pt6.get_value<bool>() == true);

    // Do extractions via get_value (default value version)
    BOOST_TEST(pt1.get_value(0) == 1);
    BOOST_TEST(pt1.get_value(0L) == 1);
    BOOST_TEST(pt2.get_value(0.0) == 2.5);
    BOOST_TEST(pt2.get_value(0.0f) == 2.5f);
    BOOST_TEST(pt3.get_value(str_t()) == str_t(T("ala ma kota")));
    BOOST_TEST(pt3.get_value(T("")) == T("ala ma kota"));
    BOOST_TEST(pt4.get_value(CHTYPE('\0')) == CHTYPE('c'));
    BOOST_TEST(pt5.get_value(true) == false);
    BOOST_TEST(pt6.get_value(false) == true);

    // Do extractions via get_value (optional version)
    opt_int = pt1.get_value_optional<int>();
    BOOST_TEST(opt_int && *opt_int == 1);
    opt_long = pt1.get_value_optional<long>();
    BOOST_TEST(opt_long && *opt_long == 1);
    opt_double = pt2.get_value_optional<double>();
    BOOST_TEST(opt_double && *opt_double == 2.5);
    opt_float = pt2.get_value_optional<float>();
    BOOST_TEST(opt_float && *opt_float == 2.5f);
    opt_string = pt3.get_value_optional<str_t>();
    BOOST_TEST(opt_string && *opt_string == str_t(T("ala ma kota")));
    opt_char = pt4.get_value_optional<CHTYPE>();
    BOOST_TEST(opt_char && *opt_char == CHTYPE('c'));
    opt_bool = pt5.get_value_optional<bool>();
    BOOST_TEST(opt_bool && *opt_bool == false);
    opt_bool = pt6.get_value_optional<bool>();
    BOOST_TEST(opt_bool && *opt_bool == true);

    // Do incorrect extractions (throwing version)
    try
    {
        pt.get<int>(T("k2.k.bogus.path"));
        BOOST_ERROR("No required exception thrown");
    }
    catch (boost::property_tree::ptree_bad_path &) { }
    catch (...)
    {
        BOOST_ERROR("Wrong exception type thrown");
    }
    try
    {
        pt.get<int>(T("k2.k"));
        BOOST_ERROR("No required exception thrown");
    }
    catch (boost::property_tree::ptree_bad_data &) { }
    catch (...)
    {
        BOOST_ERROR("Wrong exception type thrown");
    }

    // Do incorrect extractions (default value version)
    BOOST_TEST(pt.get(T("k2.k"), -7) == -7);
    BOOST_TEST(pt.get(T("k3.k.k"), -7) == -7);
    BOOST_TEST(pt.get(T("k4.k.k.k"), -7) == -7);

    // Do incorrect extractions (optional version)
    BOOST_TEST(!pt.get_optional<int>(T("k2.k")));
    BOOST_TEST(!pt.get_optional<int>(T("k3.k.k")));
    BOOST_TEST(!pt.get_optional<int>(T("k4.k.k.k")));

    // Test multiple puts with the same key
    {
        PTREE pt;
        pt.put(T("key"), 1);
        BOOST_TEST(pt.get<int>(T("key")) == 1);
        BOOST_TEST(pt.size() == 1);
        pt.put(T("key"), 2);
        BOOST_TEST(pt.get<int>(T("key")) == 2);
        BOOST_TEST(pt.size() == 1);
        pt.put(T("key.key.key"), 1);
        PTREE &child = pt.get_child(T("key.key"));
        BOOST_TEST(pt.get<int>(T("key.key.key")) == 1);
        BOOST_TEST(child.size() == 1);
        BOOST_TEST(child.count(T("key")) == 1);
        pt.put(T("key.key.key"), 2);
        BOOST_TEST(pt.get<int>(T("key.key.key")) == 2);
        BOOST_TEST(child.size() == 1);
        BOOST_TEST(child.count(T("key")) == 1);
    }

    // Test multiple puts with the same key
    {
        PTREE pt;
        pt.put(T("key"), 1);
        BOOST_TEST(pt.get<int>(T("key")) == 1);
        BOOST_TEST(pt.size() == 1);
        pt.put(T("key"), 2);
        BOOST_TEST(pt.get<int>(T("key")) == 2);
        BOOST_TEST(pt.size() == 1);
        pt.put(T("key.key.key"), 1);
        PTREE &child = pt.get_child(T("key.key"));
        BOOST_TEST(child.size() == 1);
        BOOST_TEST(child.count(T("key")) == 1);
        pt.add(T("key.key.key"), 2);
        BOOST_TEST(child.size() == 2);
        BOOST_TEST(child.count(T("key")) == 2);
    }

    // Test that put does not destroy children
    {
        PTREE pt;
        pt.put(T("key1"), 1);
        pt.put(T("key1.key2"), 2);
        BOOST_TEST(pt.get<int>(T("key1"), 0) == 1);
        BOOST_TEST(pt.get<int>(T("key1.key2"), 0) == 2);
        pt.put(T("key1"), 2);
        BOOST_TEST(pt.get<int>(T("key1"), 0) == 2);
        BOOST_TEST(pt.get<int>(T("key1.key2"), 0) == 2);
    }

    // Test that get of single character that is whitespace works
    {
        PTREE pt;
        pt.put_value(T(' '));
        CHTYPE ch = pt.get_value<CHTYPE>();
        BOOST_TEST(ch == T(' '));
    }

    // Test that get of non-char value with trailing and leading whitespace works
    {
        PTREE pt;
        pt.put_value(T(" \t\n99 \t\n"));
        BOOST_TEST(pt.get_value<int>(0) == 99);
    }

}
                                    
void test_get_child_put_child(PTREE *)
{
    PTREE pt(T("ala ma kota"));

    // Do insertions via put_child
    PTREE pt1, pt2, pt3;
    pt1.put_child(T("k1"), PTREE());
    pt1.put_child(T("k2.k"), PTREE());
    pt2.put_child(T("k1"), pt);
    pt2.put_child(T("k2.k"), pt);

    // Const references to test const versions of methods
    const PTREE &cpt1 = pt1, &cpt2 = pt2;

    // Do correct extractions via get_child (throwing version)
    BOOST_TEST(pt1.get_child(T("k1")).empty());
    BOOST_TEST(pt1.get_child(T("k2.k")).empty());
    BOOST_TEST(pt2.get_child(T("k1")) == pt);
    BOOST_TEST(pt2.get_child(T("k2.k")) == pt);
    BOOST_TEST(cpt1.get_child(T("k1")).empty());
    BOOST_TEST(cpt1.get_child(T("k2.k")).empty());
    BOOST_TEST(cpt2.get_child(T("k1")) == pt);
    BOOST_TEST(cpt2.get_child(T("k2.k")) == pt);

    // Do correct extractions via get_child (default value version)
    BOOST_TEST(pt1.get_child(T("k1"), PTREE(T("def"))) != PTREE(T("def")));
    BOOST_TEST(pt1.get_child(T("k2.k"), PTREE(T("def"))) != PTREE(T("def")));
    BOOST_TEST(pt2.get_child(T("k1"), PTREE(T("def"))) == pt);
    BOOST_TEST(pt2.get_child(T("k2.k"), PTREE(T("def"))) == pt);
    BOOST_TEST(cpt1.get_child(T("k1"), PTREE(T("def"))) != PTREE(T("def")));
    BOOST_TEST(cpt1.get_child(T("k2.k"), PTREE(T("def"))) != PTREE(T("def")));
    BOOST_TEST(cpt2.get_child(T("k1"), PTREE(T("def"))) == pt);
    BOOST_TEST(cpt2.get_child(T("k2.k"), PTREE(T("def"))) == pt);

    // Do correct extractions via get_child (optional version)
    boost::optional<PTREE &> opt;
    boost::optional<const PTREE &> copt;
    opt = pt1.get_child_optional(T("k1"));
    BOOST_TEST(opt);
    opt = pt1.get_child_optional(T("k2.k"));
    BOOST_TEST(opt);
    opt = pt2.get_child_optional(T("k1"));
    BOOST_TEST(opt && *opt == pt);
    opt = pt2.get_child_optional(T("k2.k"));
    BOOST_TEST(opt && *opt == pt);
    copt = cpt1.get_child_optional(T("k1"));
    BOOST_TEST(copt);
    copt = cpt1.get_child_optional(T("k2.k"));
    BOOST_TEST(copt);
    copt = cpt2.get_child_optional(T("k1"));
    BOOST_TEST(copt && *copt == pt);
    copt = cpt2.get_child_optional(T("k2.k"));
    BOOST_TEST(copt && *copt == pt);

    // Do incorrect extractions via get_child (throwing version)
    try
    {
        pt.get_child(T("k2.k.bogus.path"));
        BOOST_ERROR("No required exception thrown");
    }
    catch (boost::property_tree::ptree_bad_path &) { }
    catch (...)
    {
        BOOST_ERROR("Wrong exception type thrown");
    }

    // Do incorrect extractions via get_child (default value version)
    BOOST_TEST(&pt.get_child(T("k2.k.bogus.path"), pt3) == &pt3);

    // Do incorrect extractions via get_child (optional version)
    BOOST_TEST(!pt.get_child_optional(T("k2.k.bogus.path")));

    // Test multiple puts with the same key
    {
        PTREE pt, tmp1(T("data1")), tmp2(T("data2"));
        pt.put_child(T("key"), tmp1);
        BOOST_TEST(pt.get_child(T("key")) == tmp1);
        BOOST_TEST(pt.size() == 1);
        pt.put_child(T("key"), tmp2);
        BOOST_TEST(pt.get_child(T("key")) == tmp2);
        BOOST_TEST(pt.size() == 1);
        pt.put_child(T("key.key.key"), tmp1);
        PTREE &child = pt.get_child(T("key.key"));
        BOOST_TEST(child.size() == 1);
        pt.put_child(T("key.key.key"), tmp2);
        BOOST_TEST(child.size() == 1);
    }

    // Test multiple adds with the same key
    {
        PTREE pt, tmp1(T("data1")), tmp2(T("data2"));
        pt.add_child(T("key"), tmp1);
        BOOST_TEST(pt.size() == 1);
        pt.add_child(T("key"), tmp2);
        BOOST_TEST(pt.size() == 2);
        BOOST_TEST(pt.count(T("key")) == 2);
        pt.add_child(T("key.key.key"), tmp1);
        PTREE &child = pt.get_child(T("key.key"));
        BOOST_TEST(child.size() == 1);
        BOOST_TEST(child.count(T("key")) == 1);
        pt.add_child(T("key.key.key"), tmp2);
        BOOST_TEST(child.size() == 2);
        BOOST_TEST(child.count(T("key")) == 2);
    }

    // Test assigning child to tree
    {
        PTREE pt;
        pt.put(T("foo.bar"), T("baz"));
        pt = pt.get_child(T("foo"));
        BOOST_TEST(pt.size() == 1);
        BOOST_TEST(pt.get< std::basic_string<CHTYPE> >(T("bar")) == T("baz"));
    }

}

void test_equal_range(PTREE *)
{
    PTREE pt;
    pt.add_child(T("k1"), PTREE());
    pt.add_child(T("k2"), PTREE());
    pt.add_child(T("k1"), PTREE());
    pt.add_child(T("k3"), PTREE());
    pt.add_child(T("k1"), PTREE());
    pt.add_child(T("k2"), PTREE());

    BOOST_TEST(boost::distance(pt.equal_range(T("k1"))) == 3);
    BOOST_TEST(boost::distance(pt.equal_range(T("k2"))) == 2);
    BOOST_TEST(boost::distance(pt.equal_range(T("k3"))) == 1);
}

void test_path_separator(PTREE *)
{

    typedef PTREE::path_type path;

    // Check instances count
    //BOOST_TEST(PTREE::debug_get_instances_count() == 0);

    // Do insertions
    PTREE pt;
    pt.put(T("key1"), T("1"));
    pt.put(T("key2.key"), T("2"));
    pt.put(T("key3.key.key"), T("3"));
    pt.put(path(T("key4"), CHTYPE('/')), T("4"));
    pt.put(path(T("key5/key"), CHTYPE('/')), T("5"));
    pt.put(path(T("key6/key/key"), CHTYPE('/')), T("6"));

    // Check instances count
    //BOOST_TEST(PTREE::debug_get_instances_count() == 13);

    // Do correct extractions
    BOOST_TEST(pt.get(T("key1"), 0) == 1);
    BOOST_TEST(pt.get(T("key2.key"), 0) == 2);
    BOOST_TEST(pt.get(T("key3.key.key"), 0) == 3);
    BOOST_TEST(pt.get(path(T("key4"), CHTYPE('/')), 0) == 4);
    BOOST_TEST(pt.get(path(T("key5/key"), CHTYPE('/')), 0) == 5);
    BOOST_TEST(pt.get(path(T("key6/key/key"), CHTYPE('/')), 0) == 6);

    // Do incorrect extractions
    BOOST_TEST(pt.get(T("key2/key"), 0) == 0);
    BOOST_TEST(pt.get(T("key3/key/key"), 0) == 0);
    BOOST_TEST(pt.get(path(T("key5.key"), CHTYPE('/')), 0) == 0);
    BOOST_TEST(pt.get(path(T("key6.key.key"), CHTYPE('/')), 0) == 0);

}

void test_path(PTREE *)
{

    typedef PTREE::path_type path;

    // Insert
    PTREE pt;
    pt.put(T("key1.key2.key3"), 1);

    // Test operator /=
    {
        path p;
        p /= T("key1"); p /= T("key2"); p /= T("key3");
        BOOST_TEST(pt.get<int>(p, 0) == 1);
    }

    // Test operator /=
    {
        path p(T("key1"));
        p /= T("key2.key3");
        BOOST_TEST(pt.get<int>(p, 0) == 1);
    }

    // Test operator /=
    {
        path p;
        path p1(T("key1.key2"));
        path p2(T("key3"));
        p /= p1;
        p /= p2;
        BOOST_TEST(pt.get<int>(p, 0) == 1);
    }

    // Test operator /
    {
        path p = path(T("key1")) / T("key2.key3");
        BOOST_TEST(pt.get<int>(p, 0) == 1);
    }

    // Test operator /
    {
        path p = T("key1.key2") / path(T("key3"));
        BOOST_TEST(pt.get<int>(p, 0) == 1);
    }

}

void test_precision(PTREE *)
{

    typedef double real;

    // Quite precise PI value
    real pi = real(3.1415926535897932384626433832795028841971);

    // Put and get
    PTREE pt;
    pt.put_value(pi);
    real pi2 = pt.get_value<real>();

    // Test if precision is "good enough", i.e. if stream precision increase worked
    using namespace std;
    real error = abs(pi - pi2) *
        pow(real(numeric_limits<real>::radix), 
            real(numeric_limits<real>::digits));
    BOOST_TEST(error < 100);

}

void test_locale(PTREE *)
{
    typedef boost::property_tree::translator_between<
        std::basic_string<CHTYPE>, double>::type translator;
    try
    {

        // Write strings in english and french locales
        PTREE pt;
#ifdef BOOST_WINDOWS
        std::locale loc_english("english");
        std::locale loc_french("french");
#else
        std::locale loc_english("en_GB");
        std::locale loc_french("fr_FR");
#endif
        pt.put(T("english"), 1.234, translator(loc_english));
        pt.put(T("french"), 1.234, translator(loc_french));

        // Test contents
        BOOST_TEST(pt.get<PTREE::data_type>(T("english")) == T("1.234"));
        BOOST_TEST(pt.get<PTREE::data_type>(T("french")) == T("1,234"));

    }
    catch (boost::property_tree::ptree_error &)
    {
        throw;
    }
    catch (std::runtime_error &e)
    {
        std::cerr << "Required locale not supported by the platform. "
                     "Skipping locale tests (caught std::runtime_error with message " << 
                     e.what() << ").\n";
    }

}

void test_custom_data_type(PTREE *)
{

    typedef std::basic_string<CHTYPE> Str;
    typedef PTREE::key_compare Comp;

    // Property_tree with boost::any as data type
    typedef boost::property_tree::basic_ptree<Str, boost::any, Comp> my_ptree;
    my_ptree pt;

    // Put/get int value
    pt.put(T("int value"), 3);
    int int_value = pt.get<int>(T("int value"));
    BOOST_TEST(int_value == 3);

    // Put/get string value
    pt.put<std::basic_string<CHTYPE> >(T("string value"), T("foo bar"));
    std::basic_string<CHTYPE> string_value = pt.get<std::basic_string<CHTYPE> >(T("string value"));
    BOOST_TEST(string_value == T("foo bar"));

    // Put/get list<int> value
    int list_data[] = { 1, 2, 3, 4, 5 };
    pt.put<std::list<int> >(T("list value"), std::list<int>(list_data, list_data + sizeof(list_data) / sizeof(*list_data)));
    std::list<int> list_value = pt.get<std::list<int> >(T("list value"));
    BOOST_TEST(list_value.size() == 5);
    BOOST_TEST(list_value.front() == 1);
    BOOST_TEST(list_value.back() == 5);

}

void test_empty_size_max_size(PTREE *)
{

    PTREE pt;
    BOOST_TEST(pt.max_size());
    BOOST_TEST(pt.empty());
    BOOST_TEST(pt.size() == 0);

    pt.put(T("test1"), 1);
    BOOST_TEST(pt.max_size());
    BOOST_TEST(!pt.empty());
    BOOST_TEST(pt.size() == 1);

    pt.put(T("test2"), 2);
    BOOST_TEST(pt.max_size());
    BOOST_TEST(!pt.empty());
    BOOST_TEST(pt.size() == 2);

}

void test_ptree_bad_path(PTREE *)
{

    PTREE pt;

    try
    {
        pt.get<int>(T("non.existent.path"));
    }
    catch (boost::property_tree::ptree_bad_path &e)
    {
        PTREE::path_type path = e.path<PTREE::path_type>();
        std::string what = e.what();
        BOOST_TEST(what.find("non.existent.path") != std::string::npos);
        return;
    }

    BOOST_ERROR("No required exception thrown");

}

void test_ptree_bad_data(PTREE *)
{

    PTREE pt;
    pt.put_value("non convertible to int");

    try
    {
        pt.get_value<int>();
    }
    catch (boost::property_tree::ptree_bad_data &e)
    {
        PTREE::data_type data = e.data<PTREE::data_type>();
        std::string what = e.what();
        // FIXME: Bring back what translation or make it more clear that it
        // doesn't work.
        //BOOST_TEST(what.find("non convertible to int") != std::string::npos);
        return;
    }

    BOOST_ERROR("No required exception thrown");
}

void test_serialization(PTREE *)
{

    // Prepare test tree
    PTREE pt;
    pt.put_value(1);
    pt.put(T("key1"), 3);
    pt.put(T("key1.key11)"), 3.3);
    pt.put(T("key1.key12"), T("foo"));
    pt.put(T("key2"), true);
    pt.put(T("key2.key21.key211.key2111.key21111"), T("super deep!"));
    pt.put_child(T("empty"), PTREE());
    pt.put(T("loooooong"), PTREE::data_type(10000, CHTYPE('a')));

    // Endforce const for input
    const PTREE &pt1 = pt;
    
    // Test text archives
    {
        std::stringstream stream;
        boost::archive::text_oarchive oa(stream);
        oa & pt1;
        boost::archive::text_iarchive ia(stream);
        PTREE pt2;
        ia & pt2;
        BOOST_TEST(pt1 == pt2);
    }
    
    // Test binary archives
    {
        std::stringstream stream;
        boost::archive::binary_oarchive oa(stream);
        oa & pt1;
        boost::archive::binary_iarchive ia(stream);
        PTREE pt2;
        ia & pt2;
        BOOST_TEST(pt1 == pt2);
    }

    // Test XML archives
    {
        std::stringstream stream;

        {
            boost::archive::xml_oarchive oa(stream);
            oa & boost::serialization::make_nvp("pt", pt1);
        }

        PTREE pt2;

        {
            boost::archive::xml_iarchive ia(stream);
            ia & boost::serialization::make_nvp("pt", pt2);
        }

        BOOST_TEST(pt1 == pt2);
    }

}

void test_bool(PTREE *)
{

    // Prepare test tree
    PTREE pt;
    pt.put(T("bool.false.1"), false);
    pt.put(T("bool.false.2"), T("0"));
    pt.put(T("bool.true.1"), true);
    pt.put(T("bool.true.2"), 1);
    pt.put(T("bool.invalid.1"), T(""));
    pt.put(T("bool.invalid.2"), T("tt"));
    pt.put(T("bool.invalid.3"), T("ff"));
    pt.put(T("bool.invalid.4"), T("2"));
    pt.put(T("bool.invalid.5"), T("-1"));

    // Test false
    for (PTREE::iterator it = pt.get_child(T("bool.false")).begin(); it != pt.get_child(T("bool.false")).end(); ++it)
        BOOST_TEST(it->second.get_value<bool>() == false);

    // Test true
    for (PTREE::iterator it = pt.get_child(T("bool.true")).begin(); it != pt.get_child(T("bool.true")).end(); ++it)
        BOOST_TEST(it->second.get_value<bool>() == true);

    // Test invalid
    for (PTREE::iterator it = pt.get_child(T("bool.invalid")).begin(); it != pt.get_child(T("bool.invalid")).end(); ++it)
    {
        BOOST_TEST(it->second.get_value<bool>(false) == false);
        BOOST_TEST(it->second.get_value<bool>(true) == true);
    }

}

void test_char(PTREE *)
{
    typedef signed char schar;
    typedef unsigned char uchar;

    // Prepare test tree
    PTREE pt;
#if WIDECHAR == 0
    pt.put(T("char"), char('A'));
#endif
    pt.put(T("signed char"), static_cast<schar>('A'));
    pt.put(T("unsigned char"), static_cast<uchar>('A'));
    pt.put(T("signed char min"), (std::numeric_limits<schar>::min)());
    pt.put(T("signed char max"), (std::numeric_limits<schar>::max)());
    pt.put(T("signed char underflow"),
           static_cast<int>((std::numeric_limits<schar>::min)()) - 1);
    pt.put(T("signed char overflow"),
           static_cast<int>((std::numeric_limits<schar>::max)()) + 1);
    pt.put(T("unsigned char min"), (std::numeric_limits<uchar>::min)());
    pt.put(T("unsigned char max"), (std::numeric_limits<uchar>::max)());
    pt.put(T("unsigned char overflow"),
           static_cast<unsigned>((std::numeric_limits<uchar>::max)()) + 1);

    // Verify normal conversions
#if WIDECHAR == 0
    BOOST_TEST(pt.get<char>(T("char")) == 'A');
#endif
    BOOST_TEST(pt.get<schar>(T("signed char")) == static_cast<schar>('A'));
    BOOST_TEST(pt.get<uchar>(T("unsigned char")) == static_cast<uchar>('A'));

    // Verify that numbers are saved for signed and unsigned char
    BOOST_TEST(pt.get<int>(T("signed char")) == int('A'));
    BOOST_TEST(pt.get<int>(T("unsigned char")) == int('A'));

    // Verify ranges
    BOOST_TEST(pt.get<schar>(T("signed char min")) ==
        (std::numeric_limits<schar>::min)());
    BOOST_TEST(pt.get<schar>(T("signed char max")) ==
        (std::numeric_limits<schar>::max)());
    BOOST_TEST(pt.get<uchar>(T("unsigned char min")) ==
        (std::numeric_limits<uchar>::min)());
    BOOST_TEST(pt.get<uchar>(T("unsigned char max")) ==
        (std::numeric_limits<uchar>::max)());

    // Check that out-of-range throws.
    try {
        pt.get<schar>(T("signed char underflow"));
        BOOST_ERROR("expected ptree_bad_data, but nothing was thrown");
    } catch (boost::property_tree::ptree_bad_data&) {
    } catch (...) {
        BOOST_ERROR("expected ptree_bad_data, but something else was thrown");
    }
    try {
        pt.get<schar>(T("signed char overflow"));
        BOOST_ERROR("expected ptree_bad_data, but nothing was thrown");
    } catch (boost::property_tree::ptree_bad_data&) {
    } catch (...) {
        BOOST_ERROR("expected ptree_bad_data, but something else was thrown");
    }
    try {
        pt.get<uchar>(T("unsigned char overflow"));
        BOOST_ERROR("expected ptree_bad_data, but nothing was thrown");
    } catch (boost::property_tree::ptree_bad_data&) {
    } catch (...) {
        BOOST_ERROR("expected ptree_bad_data, but something else was thrown");
    }
}

void test_float(PTREE*)
{
    const double difficult = -183.12345000098765e-10;
    PTREE pt;
    pt.put(T("num"), difficult);
    double result = pt.get<double>(T("num"));

    BOOST_TEST(!(result < difficult || result > difficult));
}

void test_sort(PTREE *)
{
  PTREE pt;
  pt.put(T("one"), T("v1"));
  pt.put(T("two"), T("v2"));
  pt.put(T("three"), T("v3"));
  pt.put(T("four"), T("v4"));

  pt.sort();

  PTREE::iterator it = pt.begin();
  BOOST_TEST(std::distance(it, pt.end()) == 4);
  BOOST_TEST(it->first == T("four"));
  BOOST_TEST(it->second.data() == T("v4"));
  ++it;
  BOOST_TEST(it->first == T("one"));
  BOOST_TEST(it->second.data() == T("v1"));
  ++it;
  BOOST_TEST(it->first == T("three"));
  BOOST_TEST(it->second.data() == T("v3"));
  ++it;
  BOOST_TEST(it->first == T("two"));
  BOOST_TEST(it->second.data() == T("v2"));
}

void test_leaks(PTREE *)
{
    //BOOST_TEST(PTREE::debug_get_instances_count() == 0);
}
