// // 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 "test_storage.hpp" namespace boost { namespace json { class array_test : public beast::unit_test::suite { public: void check(array const& a) { BEAST_EXPECT(a.size() == 3); BEAST_EXPECT(a[0].is_number()); BEAST_EXPECT(a[1].is_bool()); BEAST_EXPECT(a[2].is_string()); } void check( array const& a, storage_ptr const& sp) { check(a); check_storage(a, sp); } void testSpecial() { // ~array() { // implied } // array() { scoped_fail_storage fs; array a; BEAST_EXPECT(a.empty()); BEAST_EXPECT(a.size() == 0); } // array(storage_ptr) { scoped_fail_storage fs; array a(default_storage()); check_storage(a, default_storage()); } // array(size_type, value) { array a(3, true); BEAST_EXPECT(a.size() == 3); for(auto const& v : a) BEAST_EXPECT(v.is_bool()); check_storage(a, default_storage()); } // array(size_type, value, storage) fail_loop([](storage_ptr const& sp) { array a(3, true, sp); BEAST_EXPECT(a.size() == 3); check_storage(a, sp); }); // array(size_type) { array a(3); BEAST_EXPECT(a.size() == 3); for(auto const& v : a) BEAST_EXPECT(v.is_null()); check_storage(a, default_storage()); } // array(size_type, storage) fail_loop([](storage_ptr const& sp) { array a(3, sp); BEAST_EXPECT(a.size() == 3); check_storage(a, sp); }); // array(InputIt, InputIt) { std::initializer_list init = { 1, true, "hello" }; array a(init.begin(), init.end()); check(a); check_storage(a, default_storage()); } // array(InputIt, InputIt, storage) fail_loop([this](storage_ptr const& sp) { std::initializer_list init = { 1, true, "hello" }; array a(init.begin(), init.end(), sp); check(a); check_storage(a, sp); }); // array(array const&) { std::initializer_list init = { 1, true, "hello" }; array a1(init.begin(), init.end()); array a2(a1); check(a2); check_storage(a2, default_storage()); } // array(array const&, storage) fail_loop([](storage_ptr const& sp) { std::initializer_list init = { 1, true, "hello" }; array a1(init.begin(), init.end()); array a2(a1, sp); BEAST_EXPECT(a2.size() == 3); check_storage(a2, sp); }); // array(pilfered) { std::initializer_list init = { 1, true, "hello" }; array a1(init.begin(), init.end()); array a2(pilfer(a1)); BEAST_EXPECT(a1.empty()); BEAST_EXPECT(! a1.get_storage()); check(a2); check_storage(a2, default_storage()); } // array(array&&) { std::initializer_list init = { 1, true, "hello" }; array a1(init.begin(), init.end()); array a2 = std::move(a1); BEAST_EXPECT(a1.empty()); check(a2); check_storage(a2, default_storage()); } // array(array&&, storage) fail_loop([this](storage_ptr const& sp) { std::initializer_list init = { 1, true, "hello" }; array a1(init.begin(), init.end()); array a2(std::move(a1), sp); BEAST_EXPECT(! a1.empty()); check(a2); check_storage(a1, default_storage()); check_storage(a2, sp); }); // array(init_list) { array a({1, true, "hello"}); check(a); check_storage(a, default_storage()); } // array(init_list, storage) fail_loop([this](storage_ptr const& sp) { array a({1, true, "hello"}, sp); check(a, sp); check_storage(a, sp); }); // operator=(array const&) { { array a1({1, true, "hello"}); array a2({nullptr, value(kind::object), 1.f}); a2 = a1; check(a1); check(a2); check_storage(a1, default_storage()); check_storage(a2, default_storage()); } fail_loop([this](storage_ptr const& sp) { array a1({1, true, "hello"}); array a2({nullptr, value(kind::object), 1.f}, sp); a2 = a1; check(a1); check(a2); check_storage(a1, default_storage()); check_storage(a2, sp); }); } // operator=(array&&) { { array a1({1, true, "hello"}); array a2({nullptr, object{}, 1.f}); a2 = std::move(a1); BEAST_EXPECT(a1.empty()); check(a2); } fail_loop([this](storage_ptr const& sp) { array a1({1, true, "hello"}); array a2({nullptr, value(kind::object), 1.f}, sp); a2 = std::move(a1); check(a1); check(a2); check_storage(a1, default_storage()); check_storage(a2, sp); }); } // operator=(init_list) { { std::initializer_list init = { 1, true, "hello" }; array a({nullptr, value(kind::object), 1.f}); a = init; check(a); check_storage(a, default_storage()); } fail_loop([this](storage_ptr const& sp) { std::initializer_list init = { 1, true, "hello" }; array a({nullptr, value(kind::object), 1.f}, sp); a = init; check(a); check_storage(a, sp); }); } // get_storage() { // implied } } void testElementAccess() { // at(pos) { array a({1, true, "hello"}); scoped_fail_storage fs; BEAST_EXPECT(a.at(0).is_number()); BEAST_EXPECT(a.at(1).is_bool()); BEAST_EXPECT(a.at(2).is_string()); try { a.at(3); BEAST_FAIL(); } catch(std::out_of_range const&) { BEAST_PASS(); } } // at(pos) const { array const a({1, true, "hello"}); scoped_fail_storage fs; BEAST_EXPECT(a.at(0).is_number()); BEAST_EXPECT(a.at(1).is_bool()); BEAST_EXPECT(a.at(2).is_string()); try { a.at(3); BEAST_FAIL(); } catch(std::out_of_range const&) { BEAST_PASS(); } } // operator[](size_type) { array a({1, true, "hello"}); scoped_fail_storage fs; BEAST_EXPECT(a[0].is_number()); BEAST_EXPECT(a[1].is_bool()); BEAST_EXPECT(a[2].is_string()); } // operator[](size_type) const { array const a({1, true, "hello"}); scoped_fail_storage fs; BEAST_EXPECT(a[0].is_number()); BEAST_EXPECT(a[1].is_bool()); BEAST_EXPECT(a[2].is_string()); } // front() { array a({1, true, "hello"}); scoped_fail_storage fs; BEAST_EXPECT(a.front().is_number()); } // front() const { array const a({1, true, "hello"}); scoped_fail_storage fs; BEAST_EXPECT(a.front().is_number()); } // back() { array a({1, true, "hello"}); scoped_fail_storage fs; BEAST_EXPECT(a.back().is_string()); } // back() const { array const a({1, true, "hello"}); scoped_fail_storage fs; BEAST_EXPECT(a.back().is_string()); } // data() { { array a({1, true, "hello"}); scoped_fail_storage fs; BEAST_EXPECT(a.data() == &a[0]); } { BEAST_EXPECT(array{}.data() == nullptr); } } // data() const { { array const a({1, true, "hello"}); scoped_fail_storage fs; BEAST_EXPECT(a.data() == &a[0]); } { array const a; BEAST_EXPECT(a.data() == nullptr); } } } void testIterators() { array a({1, true, "hello"}); auto const& ac(a); { auto it = a.begin(); BEAST_EXPECT(it->is_number()); ++it; BEAST_EXPECT(it->is_bool()); it++; BEAST_EXPECT(it->is_string()); ++it; BEAST_EXPECT(it == a.end()); } { auto it = a.cbegin(); BEAST_EXPECT(it->is_number()); ++it; BEAST_EXPECT(it->is_bool()); it++; BEAST_EXPECT(it->is_string()); ++it; BEAST_EXPECT(it == a.cend()); } { auto it = ac.begin(); BEAST_EXPECT(it->is_number()); ++it; BEAST_EXPECT(it->is_bool()); it++; BEAST_EXPECT(it->is_string()); ++it; BEAST_EXPECT(it == ac.end()); } { auto it = a.end(); --it; BEAST_EXPECT(it->is_string()); it--; BEAST_EXPECT(it->is_bool()); --it; BEAST_EXPECT(it->is_number()); BEAST_EXPECT(it == a.begin()); } { auto it = a.cend(); --it; BEAST_EXPECT(it->is_string()); it--; BEAST_EXPECT(it->is_bool()); --it; BEAST_EXPECT(it->is_number()); BEAST_EXPECT(it == a.cbegin()); } { auto it = ac.end(); --it; BEAST_EXPECT(it->is_string()); it--; BEAST_EXPECT(it->is_bool()); --it; BEAST_EXPECT(it->is_number()); BEAST_EXPECT(it == ac.begin()); } { auto it = a.rbegin(); BEAST_EXPECT(it->is_string()); ++it; BEAST_EXPECT(it->is_bool()); it++; BEAST_EXPECT(it->is_number()); ++it; BEAST_EXPECT(it == a.rend()); } { auto it = a.crbegin(); BEAST_EXPECT(it->is_string()); ++it; BEAST_EXPECT(it->is_bool()); it++; BEAST_EXPECT(it->is_number()); ++it; BEAST_EXPECT(it == a.crend()); } { auto it = ac.rbegin(); BEAST_EXPECT(it->is_string()); ++it; BEAST_EXPECT(it->is_bool()); it++; BEAST_EXPECT(it->is_number()); ++it; BEAST_EXPECT(it == ac.rend()); } { auto it = a.rend(); --it; BEAST_EXPECT(it->is_number()); it--; BEAST_EXPECT(it->is_bool()); --it; BEAST_EXPECT(it->is_string()); BEAST_EXPECT(it == a.rbegin()); } { auto it = a.crend(); --it; BEAST_EXPECT(it->is_number()); it--; BEAST_EXPECT(it->is_bool()); --it; BEAST_EXPECT(it->is_string()); BEAST_EXPECT(it == a.crbegin()); } { auto it = ac.rend(); --it; BEAST_EXPECT(it->is_number()); it--; BEAST_EXPECT(it->is_bool()); --it; BEAST_EXPECT(it->is_string()); BEAST_EXPECT(it == ac.rbegin()); } { array a2; array const& ca2(a2); BEAST_EXPECT(std::distance( a2.begin(), a2.end()) == 0); BEAST_EXPECT(std::distance( ca2.begin(), ca2.end()) == 0); BEAST_EXPECT(std::distance( a2.rbegin(), a2.rend()) == 0); BEAST_EXPECT(std::distance( ca2.rbegin(), ca2.rend()) == 0); } } void testCapacity() { // empty() { array a; BEAST_EXPECT(a.empty()); a.emplace_back(1); BEAST_EXPECT(! a.empty()); } // size() { array a; BEAST_EXPECT(a.size() == 0); a.emplace_back(1); BEAST_EXPECT(a.size() == 1); } // max_size() { array a; BEAST_EXPECT(a.max_size() > 0); } // reserve() { array a; a.reserve(50); BEAST_EXPECT(a.capacity() >= 50); } // capacity() { array a; BEAST_EXPECT(a.capacity() == 0); } // shrink_to_fit() { fail_loop([](storage_ptr const& sp) { array a(1, sp); a.resize(a.capacity()); a.shrink_to_fit(); BEAST_EXPECT(a.size() == a.capacity()); }); fail_loop([](storage_ptr const& sp) { array a(sp); a.reserve(10); BEAST_EXPECT(a.capacity() >= 10); a.shrink_to_fit(); BEAST_EXPECT(a.capacity() == 0); }); fail_loop([](storage_ptr const& sp) { array a(3, sp); a.reserve(10); BEAST_EXPECT(a.capacity() >= 10); a.shrink_to_fit(); if(a.capacity() > 3) throw test_failure{}; }); } } void testModifiers() { // clear { { array a; BEAST_EXPECT(a.size() == 0); BEAST_EXPECT(a.capacity() == 0); a.clear(); BEAST_EXPECT(a.size() == 0); BEAST_EXPECT(a.capacity() == 0); } { array a({1, true, "hello"}); a.clear(); BEAST_EXPECT(a.size() == 0); BEAST_EXPECT(a.capacity() > 0); } } // insert(before, value_type const&) fail_loop([this](storage_ptr const& sp) { array a({1, "hello"}, sp); value v(true); a.insert(a.begin() + 1, v); check(a); check_storage(a, sp); }); // insert(before, value_type const&) fail_loop([this](storage_ptr const& sp) { array a({1, "hello"}, sp); a.insert(a.begin() + 1, true); check(a); check_storage(a, sp); }); // insert(before, size_type, value_type const&) fail_loop([this](storage_ptr const& sp) { array a({1, "hello"}, sp); a.insert(a.begin() + 1, 3, true); BEAST_EXPECT(a[0].is_number()); BEAST_EXPECT(a[1].is_bool()); BEAST_EXPECT(a[2].is_bool()); BEAST_EXPECT(a[3].is_bool()); BEAST_EXPECT(a[4].is_string()); }); // insert(before, InputIt, InputIt) fail_loop([this](storage_ptr const& sp) { std::initializer_list< value> init = {1, true}; array a({"hello"}, sp); a.insert(a.begin(), init.begin(), init.end()); check(a); }); // insert(before, init_list) fail_loop([this](storage_ptr const& sp) { array a({"hello"}, sp); a.insert(a.begin(), {1, true}); check(a); }); // emplace(before, arg) fail_loop([this](storage_ptr const& sp) { array a({1, "hello"}, sp); auto it = a.emplace( a.begin() + 1, true); BEAST_EXPECT(it == a.begin() + 1); check(a); }); // erase(pos) { array a({1, true, nullptr, "hello"}); a.erase(a.begin() + 2); check(a); } // push_back(value const&) fail_loop([this](storage_ptr const& sp) { array a({1, true}, sp); value v("hello"); a.push_back(v); BEAST_EXPECT( v.as_string() == "hello"); check(a); check_storage(a, sp); }); // push_back(value&&) { fail_loop([this](storage_ptr const& sp) { array a({1, true}, sp); value v("hello"); a.push_back(std::move(v)); check(a); check_storage(a, sp); }); } // emplace_back(arg) fail_loop([this](storage_ptr const& sp) { array a({1, true}, sp); a.emplace_back("hello"); check(a); check_storage(a, sp); }); // pop_back() fail_loop([this](storage_ptr const& sp) { array a({1, true, "hello", nullptr}, sp); a.pop_back(); check(a); check_storage(a, sp); }); // resize(size_type) { value v(array{}); v.emplace_back(1); v.emplace_back(true); v.emplace_back("hello"); fail_loop([&](storage_ptr const& sp) { array a(5, sp); a.resize(3); BEAST_EXPECT(a.size() == 3); check_storage(a, sp); }); fail_loop([&](storage_ptr const& sp) { array a(sp); a.resize(3); BEAST_EXPECT(a.size() == 3); check_storage(a, sp); }); } // resize(size_type, value_type const&) { value v(array{}); v.emplace_back(1); v.emplace_back(true); v.emplace_back("hello"); fail_loop([&](storage_ptr const& sp) { array a(5, v, sp); a.resize(3, v); BEAST_EXPECT(a.size() == 3); check_storage(a, sp); }); fail_loop([&](storage_ptr const& sp) { array a(3, v, sp); a.resize(5, v); BEAST_EXPECT(a.size() == 5); check_storage(a, sp); }); } // swap { array a1({1, true, "hello"}); array a2; a1.swap(a2); check(a2); BEAST_EXPECT(a1.empty()); } } void testExceptions() { // operator=(array const&) { array arr0({1, true, "hello"}); { auto sp = make_storage(); { array a1; while(sp->fail < 200) { try { array a(sp); a.emplace_back(nullptr); a = arr0; a1 = a; break; } catch(test_failure const&) { } } check(a1); } } } // operator=(init_list) { std::initializer_list init( {1, true, "hello"}); auto sp = make_storage(); array a1; while(sp->fail < 200) { try { array a(sp); a.emplace_back(nullptr); a = init; a1 = a; break; } catch(test_failure const&) { } } check(a1); } // insert(before, count, value_type const&) { auto sp = make_storage(); array a1; while(sp->fail < 200) { try { array a({1, true}, sp); a.insert(a.begin() + 1, 3, value(kind::null)); a1 = a; break; } catch(test_failure const&) { } } BEAST_EXPECT(a1.size() == 5); BEAST_EXPECT(a1[0].is_number()); BEAST_EXPECT(a1[1].is_null()); BEAST_EXPECT(a1[2].is_null()); BEAST_EXPECT(a1[3].is_null()); BEAST_EXPECT(a1[4].is_bool()); } #if _ITERATOR_DEBUG_LEVEL == 0 // insert(before, InputIt, InputIt) { std::initializer_list init( {1, true, "hello"}); auto sp = make_storage(); array a1; while(sp->fail < 200) { try { array a(sp); a.insert(a.end(), init.begin(), init.end()); a1 = a; break; } catch(test_failure const&) { } } check(a1); } #endif // emplace(before, arg) { auto sp = make_storage(); array a1; while(sp->fail < 200) { try { array a({1, nullptr}, sp); a.emplace(a.begin() + 1, true); a1 = a; break; } catch(test_failure const&) { } } BEAST_EXPECT(a1.size() == 3); BEAST_EXPECT(a1[0].is_number()); BEAST_EXPECT(a1[1].is_bool()); BEAST_EXPECT(a1[2].is_null()); } #if _ITERATOR_DEBUG_LEVEL == 0 // emplace(before, arg) { auto sp = make_storage(); array a1; while(sp->fail < 200) { try { array a({1, "hello"}, sp); a.emplace(a.begin() + 1, true); a1 = a; break; } catch(test_failure const&) { } } check(a1); BEAST_EXPECT(a1.size() == 3); BEAST_EXPECT(a1[0].is_number()); BEAST_EXPECT(a1[1].is_bool()); BEAST_EXPECT(a1[2].is_string()); } #endif } void testInitList() { #if 0 auto const ci = []( int n, std::initializer_list init) { array a(init); BEAST_EXPECT(a.size() == n); return a[0]; }; BEAST_EXPECT(array({}).size() == 0); array({ nullptr });array({ 1 });array({ "x" });array({ {nullptr} });array({ {nullptr, 1} });array({ {nullptr, 1, "x"} });array({ {"x", nullptr} });array({ {"x", nullptr}, {"y", nullptr} }); #endif { auto sp = default_storage(); array({nullptr, value(kind::object), 1.f, 1.f}, sp); array({nullptr, value(kind::object), 1.f, 1.f}, sp); array({nullptr, value(kind::object), 1.f, 1.f, 1.f}, sp); array({nullptr, value(kind::object), 1.f, 1.f, 1.f, 1.f}, sp); array({value(kind::object), nullptr, 1.f}, sp); array({nullptr, 1.f, value(kind::object)}, sp); array({nullptr, 1.f, value(kind::object), 1.f}, sp); array({nullptr, 1.f, value(kind::object), 1.f, 1.f}, sp); } } void run() override { testSpecial(); testElementAccess(); testIterators(); testCapacity(); testModifiers(); testExceptions(); testInitList(); } }; BEAST_DEFINE_TESTSUITE(boost,json,array); } // json } // boost