// // Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com) // // 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) // // Official repository: https://github.com/vinniefalco/BeastLounge // // Test that header file is self-contained. #include #include #include #include #include #include "test_storage.hpp" namespace boost { namespace json { class object_test : public beast::unit_test::suite { public: template struct is_equal_comparable : std::false_type {}; template struct is_equal_comparable() == std::declval() )>> : std::true_type {}; template struct is_unequal_comparable : std::false_type {}; template struct is_unequal_comparable() != std::declval() )>> : std::true_type {}; BOOST_STATIC_ASSERT( std::is_constructible::value); BOOST_STATIC_ASSERT(! std::is_constructible::value); BOOST_STATIC_ASSERT( std::is_constructible::value); BOOST_STATIC_ASSERT( std::is_constructible::value); BOOST_STATIC_ASSERT( std::is_assignable::value); BOOST_STATIC_ASSERT(! std::is_assignable::value); BOOST_STATIC_ASSERT( std::is_assignable::value); BOOST_STATIC_ASSERT( std::is_assignable::value); BOOST_STATIC_ASSERT(is_equal_comparable::value); BOOST_STATIC_ASSERT(is_equal_comparable::value); BOOST_STATIC_ASSERT(is_equal_comparable::value); BOOST_STATIC_ASSERT(is_equal_comparable::value); BOOST_STATIC_ASSERT(is_unequal_comparable::value); BOOST_STATIC_ASSERT(is_unequal_comparable::value); BOOST_STATIC_ASSERT(is_unequal_comparable::value); BOOST_STATIC_ASSERT(is_unequal_comparable::value); static void check( object const& o, std::size_t capacity) { BEAST_EXPECT(! o.empty()); BEAST_EXPECT(o.size() == 3); BEAST_EXPECT( o.capacity() == capacity); BEAST_EXPECT(o.at("a").as_number() == 1); BEAST_EXPECT(o.at("b").as_bool()); BEAST_EXPECT(o.at("c").as_string() == "hello"); // ordering, storage auto it = o.begin(); BEAST_EXPECT(it->first == "a"); BEAST_EXPECT( *it->second.get_storage() == *o.get_storage()); ++it; BEAST_EXPECT(it->first == "b"); BEAST_EXPECT( *it->second.get_storage() == *o.get_storage()); it++; BEAST_EXPECT(it->first == "c"); BEAST_EXPECT( *it->second.get_storage() == *o.get_storage()); } void testSpecial() { // ~object() { // implied } // object() { scoped_fail_storage fs; object o; BEAST_EXPECT(o.empty()); BEAST_EXPECT(o.size() == 0); BEAST_EXPECT(o.capacity() == 0); } // object(storage_ptr) fail_loop([](storage_ptr const& sp) { object o(sp); check_storage(o, sp); }); // object(size_type) fail_loop([] { object o(50); BEAST_EXPECT(o.empty()); BEAST_EXPECT(o.size() == 0); BEAST_EXPECT(o.capacity() == 53); }); // object(size_type, storage_ptr) fail_loop([](storage_ptr const& sp) { object o(50, sp); BEAST_EXPECT(o.empty()); BEAST_EXPECT(o.size() == 0); BEAST_EXPECT(o.capacity() == 53); check_storage(o, sp); }); // object(InputIt, InputIt, size_type, storage_ptr) { fail_loop([] { std::initializer_list> init = { {"a", 1}, {"b", true}, {"c", "hello"}}; object o(init.begin(), init.end()); check(o, 3); }); fail_loop([] { std::initializer_list> init = { {"a", 1}, {"b", true}, {"c", "hello"}}; object o(init.begin(), init.end(), 5); check(o, 7); }); fail_loop([](storage_ptr const& sp) { std::initializer_list> init = { {"a", 1}, {"b", true}, {"c", "hello"}}; object o(init.begin(), init.end(), 5, sp); BEAST_EXPECT(! o.empty()); BEAST_EXPECT(o.size() == 3); BEAST_EXPECT(o.capacity() == 7); check(o, 7); check_storage(o, sp); }); } // object(object&&) { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"} }); check(obj1, 3); auto const sp = default_storage(); scoped_fail_storage fs; object obj2(std::move(obj1)); BEAST_EXPECT(obj1.empty()); BEAST_EXPECT(obj1.size() == 0); check(obj2, 3); check_storage(obj1, sp); check_storage(obj2, sp); } // object(pilfered) { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"} }); scoped_fail_storage fs; object obj2(pilfer(obj1)); BEAST_EXPECT( obj1.get_storage() == nullptr); BEAST_EXPECT(obj1.empty()); check(obj2, 3); } auto const sp = make_storage(); auto const sp0 = default_storage(); // object(object&&, storage_ptr) fail_loop([](storage_ptr const& sp) { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"} }); object obj2(std::move(obj1), sp); BEAST_EXPECT(! obj1.empty()); check(obj2, 3); check_storage(obj1, default_storage()); check_storage(obj2, sp); }); // object(object const&) fail_loop([] { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"} }); object obj2(obj1); BEAST_EXPECT(! obj1.empty()); check(obj2, 3); }); // object(object const&, storage_ptr) fail_loop([](storage_ptr const& sp) { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"} }); object obj2(obj1, sp); BEAST_EXPECT(! obj1.empty()); check(obj2, 3); check_storage(obj2, sp); }); // object(initializer_list) fail_loop([] { object o({ {"a", 1}, {"b", true}, {"c", "hello"} }); check(o, 3); }); // object(initializer_list, size_type) fail_loop([] { object o({ {"a", 1}, {"b", true}, {"c", "hello"} }, 5); check(o, 7); }); // object(initializer_list, storage_ptr) fail_loop([](storage_ptr const& sp) { object o({ {"a", 1}, {"b", true}, {"c", "hello"} }, sp); check(o, 3); check_storage(o, sp); }); // object(initializer_list, size_type, storage_ptr) { object o({ {"a", 1}, {"b", true}, {"c", "hello"} }, 5, sp); BEAST_EXPECT( *o.get_storage() == *sp); check(o, 7); } // operator=(object&&) { { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"}}); object obj2; obj2 = std::move(obj1); check(obj2, 3); BEAST_EXPECT(obj1.empty()); check_storage(obj1, default_storage()); check_storage(obj2, default_storage()); } fail_loop([](storage_ptr const& sp) { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"}}); object obj2(sp); obj2 = std::move(obj1); check(obj1, 3); check(obj2, 3); check_storage(obj1, default_storage()); check_storage(obj2, sp); }); } // operator=(object const&) { fail_loop([] { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"}}); object obj2; obj2 = obj1; check(obj1, 3); check(obj2, 3); check_storage(obj1, default_storage()); check_storage(obj2, default_storage()); }); fail_loop([](storage_ptr const& sp) { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"}}); object obj2(sp); obj2 = obj1; check(obj1, 3); check(obj2, 3); check_storage(obj1, default_storage()); check_storage(obj2, sp); }); } // operator=(initializer_list) { fail_loop([] { object o; o = { {"a", 1}, {"b", true}, {"c", "hello"} }, check(o, 3); check_storage(o, default_storage()); }); fail_loop([](storage_ptr const& sp) { object o(sp); o = { {"a", 1}, {"b", true}, {"c", "hello"} }, BEAST_EXPECT( *o.get_storage() == *sp); check(o, 3); check_storage(o, sp); }); } } void testIterators() { object o({ {"a", 1}, {"b", true}, {"c", "hello"}}); auto const& co = o; object no; auto const& cno = no; // empty container { BEAST_EXPECT(no.begin() == no.end()); BEAST_EXPECT(cno.begin() == cno.end()); BEAST_EXPECT(no.cbegin() == no.cend()); } // begin() { { auto it = o.begin(); BEAST_EXPECT(it->first == "a"); ++it; BEAST_EXPECT(it->first == "b"); it++; BEAST_EXPECT(it->first == "c"); ++it; BEAST_EXPECT(it == o.end()); } } // begin() const { auto it = co.begin(); BEAST_EXPECT(it->first == "a"); ++it; BEAST_EXPECT(it->first == "b"); it++; BEAST_EXPECT(it->first == "c"); ++it; BEAST_EXPECT(it == co.end()); } // cbegin() { auto it = o.cbegin(); BEAST_EXPECT(it->first == "a"); ++it; BEAST_EXPECT(it->first == "b"); it++; BEAST_EXPECT(it->first == "c"); ++it; BEAST_EXPECT(it == o.cend()); } // end() { auto it = o.end(); --it; BEAST_EXPECT(it->first == "c"); it--; BEAST_EXPECT(it->first == "b"); --it; BEAST_EXPECT(it->first == "a"); BEAST_EXPECT(it == o.begin()); } // end() const { auto it = co.end(); --it; BEAST_EXPECT(it->first == "c"); it--; BEAST_EXPECT(it->first == "b"); --it; BEAST_EXPECT(it->first == "a"); BEAST_EXPECT(it == co.begin()); } // cend() { auto it = o.cend(); --it; BEAST_EXPECT(it->first == "c"); it--; BEAST_EXPECT(it->first == "b"); --it; BEAST_EXPECT(it->first == "a"); BEAST_EXPECT(it == o.cbegin()); } #if 0 { auto it = o.rbegin(); BEAST_EXPECT(it->first == "c"); ++it; BEAST_EXPECT(it->first == "b"); it++; BEAST_EXPECT(it->first == "a"); ++it; BEAST_EXPECT(it == o.rend()); } { auto it = o.crbegin(); BEAST_EXPECT(it->first == "c"); ++it; BEAST_EXPECT(it->first == "b"); it++; BEAST_EXPECT(it->first == "a"); ++it; BEAST_EXPECT(it == o.crend()); } { auto it = static_cast< object const&>(o).rbegin(); BEAST_EXPECT(it->first == "c"); ++it; BEAST_EXPECT(it->first == "b"); it++; BEAST_EXPECT(it->first == "a"); ++it; BEAST_EXPECT(it == static_cast< object const&>(o).rend()); } { auto it = o.rend(); --it; BEAST_EXPECT(it->first == "a"); it--; BEAST_EXPECT(it->first == "b"); --it; BEAST_EXPECT(it->first == "c"); BEAST_EXPECT(it == o.rbegin()); } { auto it = o.crend(); --it; BEAST_EXPECT(it->first == "a"); it--; BEAST_EXPECT(it->first == "b"); --it; BEAST_EXPECT(it->first == "c"); BEAST_EXPECT(it == o.crbegin()); } { auto it = static_cast< object const&>(o).rend(); --it; BEAST_EXPECT(it->first == "a"); it--; BEAST_EXPECT(it->first == "b"); --it; BEAST_EXPECT(it->first == "c"); BEAST_EXPECT(it == static_cast< object const&>(o).rbegin()); } #endif } //-------------------------------------------------------------------------- void testModifiers() { // clear { object o; o.emplace("x", 1); BEAST_EXPECT(! o.empty()); o.clear(); BEAST_EXPECT(o.empty()); } // insert(value_type&&) fail_loop([] { object o; auto v = object::value_type("a", 1); auto result = o.insert(std::move(v)); BEAST_EXPECT(result.second); BEAST_EXPECT(result.first->first == "a"); auto v2 = object::value_type("a", 2); BEAST_EXPECT( o.insert(std::move(v2)).first == result.first); BEAST_EXPECT( ! o.insert(std::move(v2)).second); }); // insert(value_type const&) fail_loop([] { object o; auto v = object::value_type("a", 1); auto result = o.insert(v); BEAST_EXPECT(! v.second.is_null()); BEAST_EXPECT(result.second); BEAST_EXPECT(result.first->first == "a"); auto v2 = object::value_type("a", 2); BEAST_EXPECT( o.insert(v2).first == result.first); BEAST_EXPECT(! o.insert(v2).second); }); // insert(P&&) { fail_loop([] { object o; auto result = o.insert( std::make_pair("x", 1)); BEAST_EXPECT(result.second); BEAST_EXPECT(result.first->first == "x"); BEAST_EXPECT(result.first->second.as_number() == 1); }); fail_loop([] { object o; auto const p = std::make_pair("x", 1); auto result = o.insert(p); BEAST_EXPECT(result.second); BEAST_EXPECT(result.first->first == "x"); BEAST_EXPECT(result.first->second.as_number() == 1); }); } // insert(before, value_type const&) fail_loop([] { object o; o.emplace("a", 1); o.emplace("c", "hello"); object::value_type const p("b", true); o.insert(o.find("c"), p); check(o, 3); }); // insert(before, value_type&&) fail_loop([] { object o; o.emplace("a", 1); o.emplace("c", "hello"); o.insert(o.find("c"), { "b", true }); check(o, 3); }); // insert(before, P&&) { fail_loop([] { object o; o.emplace("a", 1); o.emplace("c", "hello"); o.insert(o.find("c"), std::make_pair("b", true)); check(o, 3); }); fail_loop([] { object o; o.emplace("a", 1); o.emplace("c", "hello"); auto const p = std::make_pair("b", true); o.insert(o.find("c"), p); check(o, 3); }); } // insert(InputIt, InputIt) fail_loop([] { std::initializer_list> init = { {"a", 1}, {"b", true}, {"c", "hello"}}; object o; o.insert(init.begin(), init.end()); check(o, 3); }); // insert(initializer_list) fail_loop([] { object o; o.emplace("a", 1); o.insert({ { "b", true }, { "c", "hello" }}); check(o, 3); }); // insert(before, initializer_list) fail_loop([] { object o; o.emplace("c", "hello"); o.insert( o.find("c"), { { "a", 1 }, { "b", true } }); check(o, 3); }); // insert(node_type&&) { { object o; object::node_type nh; o.insert(std::move(nh)); } { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"}}); object obj2; obj2.insert(obj1.extract(obj1.begin())); obj2.insert(obj1.extract("b")); auto result = obj2.insert(obj1.extract(obj1.find("c"))); check(obj2, 3); BEAST_EXPECT(obj1.empty()); BEAST_EXPECT(result.inserted == true); BEAST_EXPECT(result.node.empty()); BEAST_EXPECT(result.position->first == "c"); } { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"}}); object obj2({ {"b", true}}); auto nh = obj2.extract("b"); auto const result = obj1.insert(std::move(nh)); // failed insertion BEAST_EXPECT(result.inserted == false); BEAST_EXPECT(result.position->first == "b"); BEAST_EXPECT(! result.node.empty()); } } // insert(before, node_type&&) { { object o; object::node_type nh; o.insert(o.end(), std::move(nh)); } { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"}}); object obj2; obj2.insert(obj1.extract(obj1.begin())); obj2.insert(obj1.extract(obj1.find("c"))); scoped_fail_storage fs; auto result = obj2.insert(obj2.find("c"), obj1.extract("b")); check(obj2, 3); BEAST_EXPECT(obj1.empty()); BEAST_EXPECT(result.inserted == true); BEAST_EXPECT(result.position->first == "b"); BEAST_EXPECT(result.node.empty()); } { object obj1({ {"a", 1}, {"b", true}, {"c", "hello"}}); object obj2({ {"b", true}}); auto nh = obj2.extract("b"); auto const result = obj1.insert( obj2.find("c"), std::move(nh)); // failed insertion BEAST_EXPECT(result.inserted == false); BEAST_EXPECT(result.position->first == "b"); BEAST_EXPECT(! result.node.empty()); } } // insert_or_assign(key, o); { fail_loop([] { object o({{"a", 1}}); o.insert_or_assign("b", true); o.insert_or_assign("c", "hello"); check(o, 3); }); fail_loop([] { object o({{"a", 1}}); BEAST_EXPECT( ! o.insert_or_assign("a", 2).second); BEAST_EXPECT(o["a"].as_number() == 2); }); } // insert_or_assign(before, key, o); { fail_loop([] { object o({{"a", 1}}); o.insert_or_assign("c", "hello"); o.insert_or_assign(o.find("c"), "b", true); check(o, 3); }); fail_loop([] { object o({{"a", 1}}); o.insert_or_assign("b", true); o.insert_or_assign("c", "hello"); BEAST_EXPECT(! o.insert_or_assign( o.find("b"), "a", 2).second); BEAST_EXPECT(o["a"].as_number() == 2); }); } // emplace(key, arg) fail_loop([] { object o; o.emplace("a", 1); o.emplace("b", true); o.emplace("c", "hello"); check(o, 3); }); // emplace(before, key, arg) fail_loop([] { object o; o.emplace("a", 1); o.emplace("c", "hello"); o.emplace(o.find("c"), "b", true); check(o, 3); }); // erase(pos) fail_loop([] { object o({ {"d", nullptr }, {"a", 1}, {"b", true}, {"c", "hello"}}); auto it = o.erase(o.begin()); BEAST_EXPECT(it->first == "a"); BEAST_EXPECT(it->second.as_number() == 1); check(o, 7); }); // erase(first, last) fail_loop([] { object o({ {"a", 1}, {"b", true}, {"b2", 2}, {"b3", 3}, {"b4", 4}, {"c", "hello"}}); auto first = o.find("b2"); auto last = std::next(first, 3); auto it = o.erase(first, last); BEAST_EXPECT(it->first == "c"); BEAST_EXPECT( it->second.as_string() == "hello"); check(o, 7); }); // erase(key) { { object o({ {"a", 1}, {"b", true}, {"c", "hello"}}); scoped_fail_storage fs; BEAST_EXPECT(o.erase("b2") == 0); check(o, 3); } { object o({ {"a", 1}, {"b", true}, {"b2", 2}, {"c", "hello"}}); scoped_fail_storage fs; BEAST_EXPECT(o.erase("b2") == 1); check(o, 7); } } // swap(object&) { { object o1 = {{"a",1}, {"b",true}, {"c", "hello"}}; object o2 = {{"d",{1,2,3}}}; scoped_fail_storage fs; swap(o1, o2); BEAST_EXPECT(o1.size() == 1); BEAST_EXPECT(o2.size() == 3); BEAST_EXPECT(o1.count("d") == 1); } fail_loop([](storage_ptr const& sp) { object o1 = {{"a",1}, {"b",true}, {"c", "hello"}}; object o2({{"d",{1,2,3}}}, sp); swap(o1, o2); BEAST_EXPECT(o1.size() == 1); BEAST_EXPECT(o2.size() == 3); BEAST_EXPECT(o1.count("d") == 1); }); } // extract(const_iterator) { object o = { {"a",1}, {"b",true}, {"c", "hello"}}; auto nh = o.extract(o.find("b")); BEAST_EXPECT(! nh.empty()); BEAST_EXPECT(nh.key() == "b"); BEAST_EXPECT(nh.mapped().is_bool()); BEAST_EXPECT(nh.mapped().as_bool()); } // extract(key) { object o = { {"a",1}, {"b",true}, {"c", "hello"}}; { auto nh = o.extract("d"); BEAST_EXPECT(nh.empty()); } { auto nh = o.extract("b"); BEAST_EXPECT(! nh.empty()); BEAST_EXPECT(nh.key() == "b"); BEAST_EXPECT(nh.mapped().is_bool()); BEAST_EXPECT(nh.mapped().as_bool()); } { auto nh = o.extract("b"); BEAST_EXPECT(nh.empty()); } } } //-------------------------------------------------------------------------- void testLookup() { object o1({ {"a", 1}, {"b", true}, {"c", "hello"}}); auto const& co1 = o1; object o2; auto const& co2 = o2; // at(key) { BEAST_EXPECT( o1.at("a").is_number()); BEAST_THROWS((o2.at("a")), std::out_of_range); } // at(key) const { BEAST_EXPECT( co1.at("a").is_number()); BEAST_THROWS((co2.at("a")), std::out_of_range); } // operator[](key) { BEAST_EXPECT(o1.count("d") == 0);; BEAST_EXPECT(o1["a"].is_number()); BEAST_EXPECT(o1["d"].is_null()); BEAST_EXPECT(o1.count("d") == 1); } // count(key) { BEAST_EXPECT(o1.count("a") == 1); BEAST_EXPECT(o1.count("d") == 1); BEAST_EXPECT(o1.count("e") == 0); BEAST_EXPECT(o2.count("a") == 0); } // find(key) { BEAST_EXPECT( o1.find("a")->first == "a"); BEAST_EXPECT( o1.find("e") == o1.end()); BEAST_EXPECT( o2.find("e") == o2.end()); } // contains(key) { BEAST_EXPECT(o1.contains("a")); BEAST_EXPECT(o1.contains("d")); BEAST_EXPECT(! o1.contains("e")); BEAST_EXPECT(! o2.contains("a")); BEAST_EXPECT(! o2.contains("d")); } } void testBuckets() { // TODO } void testHashPolicy() { object o; for(std::size_t i = 0; i < 1000; ++i) o.emplace(std::to_string(i), i); // max_load_factor() { BEAST_EXPECT( o.max_load_factor() == 1); } // reserve(size_type) { o.reserve(200); BEAST_EXPECT(o.capacity() >= std::ceil(200 / o.max_load_factor())); } } void testObservers() { // hash_function() { object o; object::hasher h = o.hash_function(); boost::ignore_unused(h); } // key_eq() { object o; object::key_equal eq = o.key_eq(); BEAST_EXPECT(eq("a", "a")); } } //-------------------------------------------------------------------------- void testNodeType() { BOOST_STATIC_ASSERT( std::is_same< object::node_type::key_type, object::key_type>::value); BOOST_STATIC_ASSERT( std::is_same< object::node_type::mapped_type, object::mapped_type>::value); // node_type() { object::node_type nh; BEAST_EXPECT(nh.empty()); BEAST_EXPECT(! nh); BEAST_EXPECT( nh.get_storage() == nullptr); } // node_type(node_type&&) { { object::node_type nh1; object::node_type nh2(std::move(nh1)); BEAST_EXPECT(nh1.empty()); BEAST_EXPECT(nh2.empty()); BEAST_EXPECT( nh1.get_storage() == nullptr); BEAST_EXPECT( nh2.get_storage() == nullptr); } { object o({ {"a", 1}, {"b", true}, {"c", "hello"}}); object::node_type nh1(o.extract("b")); object::node_type nh2(std::move(nh1)); BEAST_EXPECT(nh1.empty()); BEAST_EXPECT(nh1.get_storage() == nullptr); BEAST_EXPECT(nh2.key() == "b"); BEAST_EXPECT( nh2.get_storage() == o.get_storage()); } } // operator=(node_type&&) { object o({ {"a", 1}, {"b", true}, {"c", "hello"}}); object::node_type nh1(o.extract("b")); object::node_type nh2; nh2 = std::move(nh1); BEAST_EXPECT(nh1.empty()); BEAST_EXPECT(nh1.get_storage() == nullptr); BEAST_EXPECT(nh2.key() == "b"); BEAST_EXPECT( nh2.get_storage() == o.get_storage()); } // empty { object::node_type nh; BEAST_EXPECT(nh.empty()); } // operator bool { object::node_type nh; BEAST_EXPECT(! nh); } // get_storage() { object::node_type nh; BEAST_EXPECT( nh.get_storage() == nullptr); } // key() // mapped() // mapped() const { object o({ {"a", 1}, {"b", true}, {"c", "hello"}}); object::node_type nh( o.extract("b")); auto const& cnh = nh; BEAST_EXPECT(nh.key() == "b"); BEAST_EXPECT(nh.mapped().is_bool()); BEAST_EXPECT(cnh.mapped().is_bool()); } // swap(node_type&) { object o1({ {"a", 1}, {"b", true}, {"c", "hello"}}); object o2({ {"d", {1,2,3}}}); check(o1, 3); auto nh1 = o1.extract("b"); auto nh2 = o2.extract("d"); BEAST_EXPECT(nh1.key() == "b"); nh1.swap(nh2); BEAST_EXPECT(nh2.key() == "b"); BEAST_EXPECT(nh1.key() == "d"); } // ::swap(object&, object&) { object o1({ {"a", 1}, {"b", true}, {"c", "hello"}}); object o2({ {"d", {1,2,3}}}); check(o1, 3); auto nh1 = o1.extract("b"); auto nh2 = o2.extract("d"); BEAST_EXPECT(nh1.key() == "b"); swap(nh1, nh2); BEAST_EXPECT(nh2.key() == "b"); BEAST_EXPECT(nh1.key() == "d"); } } void testImplementation() { // insert duplicate keys { object o({ {"a", 1}, {"b", true}, {"b", {1,2,3}}, {"c", "hello"}}); BEAST_EXPECT(o.at("a").as_number() == 1); BEAST_EXPECT(o.at("b").as_bool()); BEAST_EXPECT(o.at("c").as_string() == "hello"); } // insert, not at end, causing a rehash { object o({ {"a", 1}, {"b", true}, {"c", "hello"}}); BEAST_EXPECT(o.capacity() == 3); o.insert(o.begin(), {"d", {1,2,3}}); BEAST_EXPECT(o.capacity() > 3); } // insert before first element of non-empty container { object o({ {"b", true}, {"c", "hello"}}); o.insert(o.begin(), {"a", 1}); check(o, 3); } } void run() override { testSpecial(); testIterators(); testModifiers(); testLookup(); testBuckets(); testHashPolicy(); testObservers(); testNodeType(); testImplementation(); } }; BEAST_DEFINE_TESTSUITE(boost,json,object); } // json } // boost