// ---------------------------------------------------------------------------- // 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_CHECK(PTREE::debug_get_instances_count() == 0); { // Create ptrees PTREE pt1, pt2; BOOST_CHECK(PTREE::debug_get_instances_count() == 2); // Create PTREE PTREE *pt3 = new PTREE; BOOST_CHECK(PTREE::debug_get_instances_count() == 3); // Insert pt1.push_back(std::make_pair(T("key"), *pt3)); BOOST_CHECK(PTREE::debug_get_instances_count() == 4); // Insert pt2.push_back(std::make_pair(T("key"), *pt3)); BOOST_CHECK(PTREE::debug_get_instances_count() == 5); // Clear pt1.clear(); BOOST_CHECK(PTREE::debug_get_instances_count() == 4); // Clear pt2.clear(); BOOST_CHECK(PTREE::debug_get_instances_count() == 3); // Delete delete pt3; BOOST_CHECK(PTREE::debug_get_instances_count() == 2); } // Check count BOOST_CHECK(PTREE::debug_get_instances_count() == 0); #endif } void test_constructor_destructor_assignment(PTREE *) { { // Test constructor from string PTREE pt1(T("data")); BOOST_CHECK(pt1.data() == T("data")); //BOOST_CHECK(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_CHECK(PTREE::debug_get_instances_count() == 5); // Make a copy using copy constructor PTREE *pt2 = new PTREE(pt1); BOOST_CHECK(*pt2 == pt1); //BOOST_CHECK(PTREE::debug_get_instances_count() == 10); // Make a copy using = operator PTREE *pt3 = new PTREE; *pt3 = *pt2; BOOST_CHECK(*pt3 == *pt2); //BOOST_CHECK(PTREE::debug_get_instances_count() == 15); // Test self assignment pt1 = pt1; BOOST_CHECK(pt1 == *pt2); BOOST_CHECK(pt1 == *pt3); //BOOST_CHECK(PTREE::debug_get_instances_count() == 15); // Destroy delete pt2; //BOOST_CHECK(PTREE::debug_get_instances_count() == 10); // Destroy delete pt3; //BOOST_CHECK(PTREE::debug_get_instances_count() == 5); } // Check count //BOOST_CHECK(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_CHECK(PTREE::debug_get_instances_count() == 11); // Check contents BOOST_CHECK(pt.get(T("key1"), T("")) == T("data1")); BOOST_CHECK(pt.get(T("key2"), T("")) == T("data2")); BOOST_CHECK(pt.get(T("key1.key3"), T("")) == T("data3")); BOOST_CHECK(pt.get(T("key1.key4"), T("")) == T("data4")); BOOST_CHECK(pt.get(T("key2.key3"), T("")) == T("data3")); BOOST_CHECK(pt.get(T("key2.key4"), T("")) == T("data4")); // Check sequence PTREE::iterator it = it2; ++it; BOOST_CHECK(it == it1); ++it; BOOST_CHECK(it == pt.end()); it = it4; ++it; BOOST_CHECK(it == it3); ++it; BOOST_CHECK(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_CHECK(PTREE::debug_get_instances_count() == 11); // Test range erase PTREE::iterator it = it1->second.erase(it1->second.begin(), it1->second.end()); BOOST_CHECK(it == it1->second.end()); //BOOST_CHECK(PTREE::debug_get_instances_count() == 9); // Test single erase PTREE::size_type n = pt.erase(T("key1")); BOOST_CHECK(n == 1); //BOOST_CHECK(PTREE::debug_get_instances_count() == 8); // Test multiple erase n = it2->second.erase(T("key")); BOOST_CHECK(n == 2); //BOOST_CHECK(PTREE::debug_get_instances_count() == 6); // Test one more erase n = pt.erase(T("key2")); BOOST_CHECK(n == 1); //BOOST_CHECK(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_CHECK(PTREE::debug_get_instances_count() == 2); // Test clear pt.clear(); BOOST_CHECK(pt.empty()); BOOST_CHECK(pt.data().empty()); //BOOST_CHECK(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_CHECK(PTREE::debug_get_instances_count() == 9); // Check sequence PTREE::iterator it = pt.begin(); BOOST_CHECK(it->first == T("key1")); ++it; BOOST_CHECK(it->first == T("key2")); ++it; BOOST_CHECK(it->first == T("key3")); ++it; BOOST_CHECK(it->first == T("key4")); ++it; BOOST_CHECK(it == pt.end()); // Test pops pt.pop_back(); //BOOST_CHECK(PTREE::debug_get_instances_count() == 8); BOOST_CHECK(pt.front().second.data() == T("data1")); BOOST_CHECK(pt.back().second.data() == T("data3")); pt.pop_front(); //BOOST_CHECK(PTREE::debug_get_instances_count() == 7); BOOST_CHECK(pt.front().second.data() == T("data2")); BOOST_CHECK(pt.back().second.data() == T("data3")); pt.pop_back(); //BOOST_CHECK(PTREE::debug_get_instances_count() == 6); BOOST_CHECK(pt.front().second.data() == T("data2")); BOOST_CHECK(pt.back().second.data() == T("data2")); pt.pop_front(); //BOOST_CHECK(PTREE::debug_get_instances_count() == 5); BOOST_CHECK(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_CHECK(it->first == T("key3")); ++it; BOOST_CHECK(it->first == T("key1")); ++it; BOOST_CHECK(it->first == T("key4")); ++it; BOOST_CHECK(it->first == T("key2")); ++it; BOOST_CHECK(it == pt.end()); } // const_iterator { PTREE::const_iterator it = pt.begin(); BOOST_CHECK(it->first == T("key3")); ++it; BOOST_CHECK(it->first == T("key1")); ++it; BOOST_CHECK(it->first == T("key4")); ++it; BOOST_CHECK(it->first == T("key2")); ++it; BOOST_CHECK(it == pt.end()); } // reverse_iterator { PTREE::reverse_iterator it = pt.rbegin(); BOOST_CHECK(it->first == T("key2")); ++it; BOOST_CHECK(it->first == T("key4")); ++it; BOOST_CHECK(it->first == T("key1")); ++it; BOOST_CHECK(it->first == T("key3")); ++it; BOOST_CHECK(it == pt.rend()); } // const_reverse_iterator { PTREE::const_reverse_iterator it = pt.rbegin(); BOOST_CHECK(it->first == T("key2")); ++it; BOOST_CHECK(it->first == T("key4")); ++it; BOOST_CHECK(it->first == T("key1")); ++it; BOOST_CHECK(it->first == T("key3")); ++it; BOOST_CHECK(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_CHECK(PTREE::debug_get_instances_count() == 6); BOOST_CHECK(pt1.size() == 2); BOOST_CHECK(pt1.get_child(T("key1")).size() == 2); BOOST_CHECK(pt2.size() == 0); // Swap using member function pt1.swap(pt2); // Check counts //BOOST_CHECK(PTREE::debug_get_instances_count() == 6); BOOST_CHECK(pt2.size() == 2); BOOST_CHECK(pt2.get_child(T("key1")).size() == 2); BOOST_CHECK(pt1.size() == 0); // Swap using free function swap(pt1, pt2); // Check counts //BOOST_CHECK(PTREE::debug_get_instances_count() == 6); BOOST_CHECK(pt1.size() == 2); BOOST_CHECK(pt1.get_child(T("key1")).size() == 2); BOOST_CHECK(pt2.size() == 0); // Swap using std algorithm std::swap(pt1, pt2); // Check counts //BOOST_CHECK(PTREE::debug_get_instances_count() == 6); BOOST_CHECK(pt2.size() == 2); BOOST_CHECK(pt2.get_child(T("key1")).size() == 2); BOOST_CHECK(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_CHECK(it->first == T("key3")); ++it; BOOST_CHECK(it->first == T("key4")); ++it; BOOST_CHECK(it->first == T("key1")); ++it; BOOST_CHECK(it->first == T("key2")); ++it; BOOST_CHECK(it == pt.end()); } // Check sequence using find to check if index is ok { PTREE::iterator it = pt.begin(); BOOST_CHECK(it == pt.to_iterator(pt.find(T("key3")))); ++it; BOOST_CHECK(it == pt.to_iterator(pt.find(T("key4")))); ++it; BOOST_CHECK(it == pt.to_iterator(pt.find(T("key1")))); ++it; BOOST_CHECK(it == pt.to_iterator(pt.find(T("key2")))); ++it; BOOST_CHECK(it == pt.end()); } // Sort pt.sort(SortPred()); // Check sequence { PTREE::iterator it = pt.begin(); BOOST_CHECK(it->first == T("key1")); ++it; BOOST_CHECK(it->first == T("key2")); ++it; BOOST_CHECK(it->first == T("key3")); ++it; BOOST_CHECK(it->first == T("key4")); ++it; BOOST_CHECK(it == pt.end()); } // Check sequence (using find to check if index is ok) { PTREE::iterator it = pt.begin(); BOOST_CHECK(it == pt.to_iterator(pt.find(T("key1")))); ++it; BOOST_CHECK(it == pt.to_iterator(pt.find(T("key2")))); ++it; BOOST_CHECK(it == pt.to_iterator(pt.find(T("key3")))); ++it; BOOST_CHECK(it == pt.to_iterator(pt.find(T("key4")))); ++it; BOOST_CHECK(it == pt.end()); } // Sort reverse pt.sort(SortPredRev()); // Check sequence { PTREE::iterator it = pt.begin(); BOOST_CHECK(it->first == T("key4")); ++it; BOOST_CHECK(it->first == T("key3")); ++it; BOOST_CHECK(it->first == T("key2")); ++it; BOOST_CHECK(it->first == T("key1")); ++it; BOOST_CHECK(it == pt.end()); } // Check sequence (using find to check if index is ok) { PTREE::iterator it = pt.begin(); BOOST_CHECK(it == pt.to_iterator(pt.find(T("key4")))); ++it; BOOST_CHECK(it == pt.to_iterator(pt.find(T("key3")))); ++it; BOOST_CHECK(it == pt.to_iterator(pt.find(T("key2")))); ++it; BOOST_CHECK(it == pt.to_iterator(pt.find(T("key1")))); ++it; BOOST_CHECK(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_CHECK(PTREE::debug_get_instances_count() == 7); BOOST_CHECK(pt.get(T("key1"), T("")) == T("data1")); BOOST_CHECK(pt.get(T("key2"), T("")) == T("")); BOOST_CHECK(pt.get(T("key1.key3"), T("")) == T("")); BOOST_CHECK(pt.get(T("KEY1.key4"), T("")) == T("data4")); #else //BOOST_CHECK(PTREE::debug_get_instances_count() == 5); BOOST_CHECK(pt.get(T("key1"), T("1")) == pt.get(T("KEY1"), T("2"))); BOOST_CHECK(pt.get(T("key2"), T("1")) == pt.get(T("KEY2"), T("2"))); BOOST_CHECK(pt.get(T("key1.key3"), T("1")) == pt.get(T("KEY1.KEY3"), T("2"))); BOOST_CHECK(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_CHECK(pt.count(T("key1")) == 3); BOOST_CHECK(pt.count(T("KEY1")) == 1); BOOST_CHECK(pt.count(T("key2")) == 0); BOOST_CHECK(pt.count(T("KEY2")) == 1); BOOST_CHECK(pt.count(T("key3")) == 0); BOOST_CHECK(pt.count(T("KEY3")) == 0); #else BOOST_CHECK(pt.count(T("key1")) == 3); BOOST_CHECK(pt.count(T("KEY1")) == 3); BOOST_CHECK(pt.count(T("key2")) == 1); BOOST_CHECK(pt.count(T("KEY2")) == 1); BOOST_CHECK(pt.count(T("key3")) == 0); BOOST_CHECK(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_CHECK(pt1 == pt2); BOOST_CHECK(pt2 == pt1); BOOST_CHECK(!(pt1 != pt2)); BOOST_CHECK(!(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_CHECK(pt1 == pt2); BOOST_CHECK(pt2 == pt1); BOOST_CHECK(!(pt1 != pt2)); BOOST_CHECK(!(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_CHECK(pt1 == pt2); BOOST_CHECK(pt2 == pt1); BOOST_CHECK(!(pt1 != pt2)); BOOST_CHECK(!(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_CHECK(!(pt1 == pt2)); BOOST_CHECK(!(pt2 == pt1)); BOOST_CHECK(pt1 != pt2); BOOST_CHECK(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_CHECK(!(pt1 == pt2)); BOOST_CHECK(!(pt2 == pt1)); BOOST_CHECK(pt1 != pt2); BOOST_CHECK(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_CHECK(!(pt1 == pt2)); BOOST_CHECK(!(pt2 == pt1)); BOOST_CHECK(pt1 != pt2); BOOST_CHECK(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_CHECK(!(pt1 == pt2)); BOOST_CHECK(!(pt2 == pt1)); BOOST_CHECK(pt1 != pt2); BOOST_CHECK(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_CHECK(pt.front().first == T("key1")); BOOST_CHECK(pt.back().first == T("key2")); } void test_get_put(PTREE *) { typedef std::basic_string str_t; // Temporary storage str_t tmp_string; boost::optional opt_int; boost::optional opt_long; boost::optional opt_double; boost::optional opt_float; boost::optional opt_string; boost::optional opt_char; boost::optional 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_CHECK(PTREE::debug_get_instances_count() == 17); // Check if const char * version returns std::string BOOST_CHECK(typeid(pt.get_value(T(""))) == typeid(str_t)); // Do extractions via get (throwing version) BOOST_CHECK(pt.get(T("k1")) == 1); BOOST_CHECK(pt.get(T("k1")) == 1); BOOST_CHECK(pt.get(T("k2.k")) == 2.5); BOOST_CHECK(pt.get(T("k2.k")) == 2.5f); BOOST_CHECK(pt.get(T("k3.k.k")) == str_t(T("ala ma kota"))); BOOST_CHECK(pt.get(T("k4.k.k.k")) == CHTYPE('c')); BOOST_CHECK(pt.get(T("k5.k.k.k.f")) == false); BOOST_CHECK(pt.get(T("k5.k.k.k.t")) == true); // Do extractions via get (default value version) BOOST_CHECK(pt.get(T("k1"), 0) == 1); BOOST_CHECK(pt.get(T("k1"), 0L) == 1); BOOST_CHECK(pt.get(T("k2.k"), 0.0) == 2.5); BOOST_CHECK(pt.get(T("k2.k"), 0.0f) == 2.5f); BOOST_CHECK(pt.get(T("k3.k.k"), str_t()) == str_t(T("ala ma kota"))); BOOST_CHECK(pt.get(T("k3.k.k"), T("")) == T("ala ma kota")); BOOST_CHECK(pt.get(T("k4.k.k.k"), CHTYPE('\0')) == CHTYPE('c')); BOOST_CHECK(pt.get(T("k5.k.k.k.f"), true) == false); BOOST_CHECK(pt.get(T("k5.k.k.k.t"), false) == true); // Do extractions via get (optional version) opt_int = pt.get_optional(T("k1")); BOOST_CHECK(opt_int && *opt_int == 1); opt_long = pt.get_optional(T("k1")); BOOST_CHECK(opt_long && *opt_long == 1); opt_double = pt.get_optional(T("k2.k")); BOOST_CHECK(opt_double && *opt_double == 2.5); opt_float = pt.get_optional(T("k2.k")); BOOST_CHECK(opt_float && *opt_float == 2.5f); opt_string = pt.get_optional(T("k3.k.k")); BOOST_CHECK(opt_string && *opt_string == str_t(T("ala ma kota"))); opt_char = pt.get_optional(T("k4.k.k.k")); BOOST_CHECK(opt_char && *opt_char == CHTYPE('c')); opt_bool = pt.get_optional(T("k5.k.k.k.f")); BOOST_CHECK(opt_bool && *opt_bool == false); opt_bool = pt.get_optional(T("k5.k.k.k.t")); BOOST_CHECK(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_CHECK(pt1.get_value() == 1); BOOST_CHECK(pt1.get_value() == 1); BOOST_CHECK(pt2.get_value() == 2.5); BOOST_CHECK(pt2.get_value() == 2.5f); BOOST_CHECK(pt3.get_value() == str_t(T("ala ma kota"))); BOOST_CHECK(pt4.get_value() == CHTYPE('c')); BOOST_CHECK(pt5.get_value() == false); BOOST_CHECK(pt6.get_value() == true); // Do extractions via get_value (default value version) BOOST_CHECK(pt1.get_value(0) == 1); BOOST_CHECK(pt1.get_value(0L) == 1); BOOST_CHECK(pt2.get_value(0.0) == 2.5); BOOST_CHECK(pt2.get_value(0.0f) == 2.5f); BOOST_CHECK(pt3.get_value(str_t()) == str_t(T("ala ma kota"))); BOOST_CHECK(pt3.get_value(T("")) == T("ala ma kota")); BOOST_CHECK(pt4.get_value(CHTYPE('\0')) == CHTYPE('c')); BOOST_CHECK(pt5.get_value(true) == false); BOOST_CHECK(pt6.get_value(false) == true); // Do extractions via get_value (optional version) opt_int = pt1.get_value_optional(); BOOST_CHECK(opt_int && *opt_int == 1); opt_long = pt1.get_value_optional(); BOOST_CHECK(opt_long && *opt_long == 1); opt_double = pt2.get_value_optional(); BOOST_CHECK(opt_double && *opt_double == 2.5); opt_float = pt2.get_value_optional(); BOOST_CHECK(opt_float && *opt_float == 2.5f); opt_string = pt3.get_value_optional(); BOOST_CHECK(opt_string && *opt_string == str_t(T("ala ma kota"))); opt_char = pt4.get_value_optional(); BOOST_CHECK(opt_char && *opt_char == CHTYPE('c')); opt_bool = pt5.get_value_optional(); BOOST_CHECK(opt_bool && *opt_bool == false); opt_bool = pt6.get_value_optional(); BOOST_CHECK(opt_bool && *opt_bool == true); // Do incorrect extractions (throwing version) try { pt.get(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(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_CHECK(pt.get(T("k2.k"), -7) == -7); BOOST_CHECK(pt.get(T("k3.k.k"), -7) == -7); BOOST_CHECK(pt.get(T("k4.k.k.k"), -7) == -7); // Do incorrect extractions (optional version) BOOST_CHECK(!pt.get_optional(T("k2.k"))); BOOST_CHECK(!pt.get_optional(T("k3.k.k"))); BOOST_CHECK(!pt.get_optional(T("k4.k.k.k"))); // Test multiple puts with the same key { PTREE pt; pt.put(T("key"), 1); BOOST_CHECK(pt.get(T("key")) == 1); BOOST_CHECK(pt.size() == 1); pt.put(T("key"), 2); BOOST_CHECK(pt.get(T("key")) == 2); BOOST_CHECK(pt.size() == 1); pt.put(T("key.key.key"), 1); PTREE &child = pt.get_child(T("key.key")); BOOST_CHECK(pt.get(T("key.key.key")) == 1); BOOST_CHECK(child.size() == 1); BOOST_CHECK(child.count(T("key")) == 1); pt.put(T("key.key.key"), 2); BOOST_CHECK(pt.get(T("key.key.key")) == 2); BOOST_CHECK(child.size() == 1); BOOST_CHECK(child.count(T("key")) == 1); } // Test multiple puts with the same key { PTREE pt; pt.put(T("key"), 1); BOOST_CHECK(pt.get(T("key")) == 1); BOOST_CHECK(pt.size() == 1); pt.put(T("key"), 2); BOOST_CHECK(pt.get(T("key")) == 2); BOOST_CHECK(pt.size() == 1); pt.put(T("key.key.key"), 1); PTREE &child = pt.get_child(T("key.key")); BOOST_CHECK(child.size() == 1); BOOST_CHECK(child.count(T("key")) == 1); pt.add(T("key.key.key"), 2); BOOST_CHECK(child.size() == 2); BOOST_CHECK(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_CHECK(pt.get(T("key1"), 0) == 1); BOOST_CHECK(pt.get(T("key1.key2"), 0) == 2); pt.put(T("key1"), 2); BOOST_CHECK(pt.get(T("key1"), 0) == 2); BOOST_CHECK(pt.get(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(); BOOST_CHECK(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_CHECK(pt.get_value(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_CHECK(pt1.get_child(T("k1")).empty()); BOOST_CHECK(pt1.get_child(T("k2.k")).empty()); BOOST_CHECK(pt2.get_child(T("k1")) == pt); BOOST_CHECK(pt2.get_child(T("k2.k")) == pt); BOOST_CHECK(cpt1.get_child(T("k1")).empty()); BOOST_CHECK(cpt1.get_child(T("k2.k")).empty()); BOOST_CHECK(cpt2.get_child(T("k1")) == pt); BOOST_CHECK(cpt2.get_child(T("k2.k")) == pt); // Do correct extractions via get_child (default value version) BOOST_CHECK(pt1.get_child(T("k1"), PTREE(T("def"))) != PTREE(T("def"))); BOOST_CHECK(pt1.get_child(T("k2.k"), PTREE(T("def"))) != PTREE(T("def"))); BOOST_CHECK(pt2.get_child(T("k1"), PTREE(T("def"))) == pt); BOOST_CHECK(pt2.get_child(T("k2.k"), PTREE(T("def"))) == pt); BOOST_CHECK(cpt1.get_child(T("k1"), PTREE(T("def"))) != PTREE(T("def"))); BOOST_CHECK(cpt1.get_child(T("k2.k"), PTREE(T("def"))) != PTREE(T("def"))); BOOST_CHECK(cpt2.get_child(T("k1"), PTREE(T("def"))) == pt); BOOST_CHECK(cpt2.get_child(T("k2.k"), PTREE(T("def"))) == pt); // Do correct extractions via get_child (optional version) boost::optional opt; boost::optional copt; opt = pt1.get_child_optional(T("k1")); BOOST_CHECK(opt); opt = pt1.get_child_optional(T("k2.k")); BOOST_CHECK(opt); opt = pt2.get_child_optional(T("k1")); BOOST_CHECK(opt && *opt == pt); opt = pt2.get_child_optional(T("k2.k")); BOOST_CHECK(opt && *opt == pt); copt = cpt1.get_child_optional(T("k1")); BOOST_CHECK(copt); copt = cpt1.get_child_optional(T("k2.k")); BOOST_CHECK(copt); copt = cpt2.get_child_optional(T("k1")); BOOST_CHECK(copt && *copt == pt); copt = cpt2.get_child_optional(T("k2.k")); BOOST_CHECK(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_CHECK(&pt.get_child(T("k2.k.bogus.path"), pt3) == &pt3); // Do incorrect extractions via get_child (optional version) BOOST_CHECK(!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_CHECK(pt.get_child(T("key")) == tmp1); BOOST_CHECK(pt.size() == 1); pt.put_child(T("key"), tmp2); BOOST_CHECK(pt.get_child(T("key")) == tmp2); BOOST_CHECK(pt.size() == 1); pt.put_child(T("key.key.key"), tmp1); PTREE &child = pt.get_child(T("key.key")); BOOST_CHECK(child.size() == 1); pt.put_child(T("key.key.key"), tmp2); BOOST_CHECK(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_CHECK(pt.size() == 1); pt.add_child(T("key"), tmp2); BOOST_CHECK(pt.size() == 2); BOOST_CHECK(pt.count(T("key")) == 2); pt.add_child(T("key.key.key"), tmp1); PTREE &child = pt.get_child(T("key.key")); BOOST_CHECK(child.size() == 1); BOOST_CHECK(child.count(T("key")) == 1); pt.add_child(T("key.key.key"), tmp2); BOOST_CHECK(child.size() == 2); BOOST_CHECK(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_CHECK(pt.size() == 1); BOOST_CHECK(pt.get< std::basic_string >(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_CHECK(boost::distance(pt.equal_range(T("k1"))) == 3); BOOST_CHECK(boost::distance(pt.equal_range(T("k2"))) == 2); BOOST_CHECK(boost::distance(pt.equal_range(T("k3"))) == 1); } void test_path_separator(PTREE *) { typedef PTREE::path_type path; // Check instances count //BOOST_CHECK(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_CHECK(PTREE::debug_get_instances_count() == 13); // Do correct extractions BOOST_CHECK(pt.get(T("key1"), 0) == 1); BOOST_CHECK(pt.get(T("key2.key"), 0) == 2); BOOST_CHECK(pt.get(T("key3.key.key"), 0) == 3); BOOST_CHECK(pt.get(path(T("key4"), CHTYPE('/')), 0) == 4); BOOST_CHECK(pt.get(path(T("key5/key"), CHTYPE('/')), 0) == 5); BOOST_CHECK(pt.get(path(T("key6/key/key"), CHTYPE('/')), 0) == 6); // Do incorrect extractions BOOST_CHECK(pt.get(T("key2/key"), 0) == 0); BOOST_CHECK(pt.get(T("key3/key/key"), 0) == 0); BOOST_CHECK(pt.get(path(T("key5.key"), CHTYPE('/')), 0) == 0); BOOST_CHECK(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_CHECK(pt.get(p, 0) == 1); } // Test operator /= { path p(T("key1")); p /= T("key2.key3"); BOOST_CHECK(pt.get(p, 0) == 1); } // Test operator /= { path p; path p1(T("key1.key2")); path p2(T("key3")); p /= p1; p /= p2; BOOST_CHECK(pt.get(p, 0) == 1); } // Test operator / { path p = path(T("key1")) / T("key2.key3"); BOOST_CHECK(pt.get(p, 0) == 1); } // Test operator / { path p = T("key1.key2") / path(T("key3")); BOOST_CHECK(pt.get(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(); // 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::radix), real(numeric_limits::digits)); BOOST_CHECK(error < 100); } void test_locale(PTREE *) { typedef boost::property_tree::translator_between< std::basic_string, 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_CHECK(pt.get(T("english")) == T("1.234")); BOOST_CHECK(pt.get(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 Str; typedef PTREE::key_compare Comp; // Property_tree with boost::any as data type typedef boost::property_tree::basic_ptree my_ptree; my_ptree pt; // Put/get int value pt.put(T("int value"), 3); int int_value = pt.get(T("int value")); BOOST_CHECK(int_value == 3); // Put/get string value pt.put >(T("string value"), T("foo bar")); std::basic_string string_value = pt.get >(T("string value")); BOOST_CHECK(string_value == T("foo bar")); // Put/get list value int list_data[] = { 1, 2, 3, 4, 5 }; pt.put >(T("list value"), std::list(list_data, list_data + sizeof(list_data) / sizeof(*list_data))); std::list list_value = pt.get >(T("list value")); BOOST_CHECK(list_value.size() == 5); BOOST_CHECK(list_value.front() == 1); BOOST_CHECK(list_value.back() == 5); } void test_empty_size_max_size(PTREE *) { PTREE pt; BOOST_CHECK(pt.max_size()); BOOST_CHECK(pt.empty()); BOOST_CHECK(pt.size() == 0); pt.put(T("test1"), 1); BOOST_CHECK(pt.max_size()); BOOST_CHECK(!pt.empty()); BOOST_CHECK(pt.size() == 1); pt.put(T("test2"), 2); BOOST_CHECK(pt.max_size()); BOOST_CHECK(!pt.empty()); BOOST_CHECK(pt.size() == 2); } void test_ptree_bad_path(PTREE *) { PTREE pt; try { pt.get(T("non.existent.path")); } catch (boost::property_tree::ptree_bad_path &e) { PTREE::path_type path = e.path(); std::string what = e.what(); BOOST_CHECK(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(); } catch (boost::property_tree::ptree_bad_data &e) { PTREE::data_type data = e.data(); std::string what = e.what(); // FIXME: Bring back what translation or make it more clear that it // doesn't work. //BOOST_CHECK(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_CHECK(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_CHECK(pt1 == pt2); } // Test XML archives { std::stringstream stream; boost::archive::xml_oarchive oa(stream); oa & boost::serialization::make_nvp("pt", pt1); boost::archive::xml_iarchive ia(stream); PTREE pt2; ia & boost::serialization::make_nvp("pt", pt2); BOOST_CHECK(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_CHECK(it->second.get_value() == false); // Test true for (PTREE::iterator it = pt.get_child(T("bool.true")).begin(); it != pt.get_child(T("bool.true")).end(); ++it) BOOST_CHECK(it->second.get_value() == true); // Test invalid for (PTREE::iterator it = pt.get_child(T("bool.invalid")).begin(); it != pt.get_child(T("bool.invalid")).end(); ++it) { BOOST_CHECK(it->second.get_value(false) == false); BOOST_CHECK(it->second.get_value(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('A')); pt.put(T("unsigned char"), static_cast('A')); pt.put(T("signed char min"), (std::numeric_limits::min)()); pt.put(T("signed char max"), (std::numeric_limits::max)()); pt.put(T("signed char underflow"), static_cast((std::numeric_limits::min)()) - 1); pt.put(T("signed char overflow"), static_cast((std::numeric_limits::max)()) + 1); pt.put(T("unsigned char min"), (std::numeric_limits::min)()); pt.put(T("unsigned char max"), (std::numeric_limits::max)()); pt.put(T("unsigned char overflow"), static_cast((std::numeric_limits::max)()) + 1); // Verify normal conversions #if WIDECHAR == 0 BOOST_CHECK(pt.get(T("char")) == 'A'); #endif BOOST_CHECK(pt.get(T("signed char")) == static_cast('A')); BOOST_CHECK(pt.get(T("unsigned char")) == static_cast('A')); // Verify that numbers are saved for signed and unsigned char BOOST_CHECK(pt.get(T("signed char")) == int('A')); BOOST_CHECK(pt.get(T("unsigned char")) == int('A')); // Verify ranges BOOST_CHECK(pt.get(T("signed char min")) == (std::numeric_limits::min)()); BOOST_CHECK(pt.get(T("signed char max")) == (std::numeric_limits::max)()); BOOST_CHECK(pt.get(T("unsigned char min")) == (std::numeric_limits::min)()); BOOST_CHECK(pt.get(T("unsigned char max")) == (std::numeric_limits::max)()); // Check that out-of-range throws. try { pt.get(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(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(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(T("num")); BOOST_CHECK(!(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_CHECK(std::distance(it, pt.end()) == 4); BOOST_CHECK(it->first == T("four")); BOOST_CHECK(it->second.data() == T("v4")); ++it; BOOST_CHECK(it->first == T("one")); BOOST_CHECK(it->second.data() == T("v1")); ++it; BOOST_CHECK(it->first == T("three")); BOOST_CHECK(it->second.data() == T("v3")); ++it; BOOST_CHECK(it->first == T("two")); BOOST_CHECK(it->second.data() == T("v2")); } void test_leaks(PTREE *) { //BOOST_CHECK(PTREE::debug_get_instances_count() == 0); }