2829 lines
79 KiB
C++
Raw Normal View History

2025-01-12 20:40:48 +08:00
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/string.hpp>
#include <boost/json/monotonic_resource.hpp>
#include <boost/json/parse.hpp>
#include <numeric>
#include <sstream>
#include <string>
#include <stdint.h>
#include <unordered_set>
#include "test.hpp"
#include "test_suite.hpp"
namespace boost {
namespace json {
BOOST_STATIC_ASSERT( std::is_nothrow_destructible<string>::value );
BOOST_STATIC_ASSERT( std::is_nothrow_move_constructible<string>::value );
class string_test
{
public:
#if BOOST_JSON_ARCH == 64
# define INIT1 { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n' }
# define INIT2 { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O' }
#elif BOOST_JSON_ARCH == 32
# define INIT1 { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' }
# define INIT2 { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K' }
#else
# error Unknown architecture
#endif
struct test_vectors
{
// fit in sbo
string_view v1; // "abc...
// dynamic alloc
string_view v2; // "ABC...
std::string const s1;
std::string const s2;
test_vectors()
: s1([&]
{
std::string s;
s.resize(string{}.capacity());
std::iota(s.begin(), s.end(), 'a');
return s;
}())
, s2([&]
{
std::string s;
s.resize(string{}.capacity() + 1);
std::iota(s.begin(), s.end(), 'A');
return s;
}())
{
v1 = s1;
v2 = s2;
BOOST_TEST(std::string(INIT1) == s1);
BOOST_TEST(std::string(INIT2) == s2);
}
};
static
string_view
last_of(
string_view s,
std::size_t n)
{
return s.substr(s.size() - n);
}
void
testConstruction()
{
test_vectors const t;
// string()
{
string s;
}
// string(storage_ptr)
{
auto const sp =
make_shared_resource<unique_resource>();
string s(sp);
BOOST_TEST(s.empty());
BOOST_TEST(*s.storage() == *sp.get());
}
// string(size_type, char, storage_ptr)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
BOOST_TEST(s == std::string(t.v1.size(), '*'));
});
{
string s(t.v2.size(), '*');
BOOST_TEST(s == std::string(t.v2.size(), '*'));
}
}
// string(char const*, storage_ptr)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.s1.c_str(), sp);
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.s2.c_str(), sp);
BOOST_TEST(s == t.v2);
});
{
string s(t.s1.c_str());
BOOST_TEST(s == t.v1);
}
{
string s(t.s2.c_str());
BOOST_TEST(s == t.v2);
}
}
// string(char const*, size_type, storage_ptr)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.s1.c_str(), 3, sp);
BOOST_TEST(s == "abc");
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.s2.c_str(), 3, sp);
BOOST_TEST(s == "ABC");
});
{
string s(t.s1.c_str(), 3);
BOOST_TEST(s == "abc");
}
{
string s(t.s2.c_str(), 3);
BOOST_TEST(s == "ABC");
}
}
// string(InputIt, InputIt, storage_ptr)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.begin(), t.v1.end(), sp);
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.begin(), t.v2.end(), sp);
BOOST_TEST(s == t.v2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(
make_input_iterator(t.v1.begin()),
make_input_iterator(t.v1.end()), sp);
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(
make_input_iterator(t.v2.begin()),
make_input_iterator(t.v2.end()), sp);
BOOST_TEST(s == t.v2);
});
{
string s(t.v1.begin(), t.v1.end());
BOOST_TEST(s == t.v1);
}
{
string s(t.v2.begin(), t.v2.end());
BOOST_TEST(s == t.v2);
}
{
string s(
make_input_iterator(t.v1.begin()),
make_input_iterator(t.v1.end()));
BOOST_TEST(s == t.v1);
}
{
string s(
make_input_iterator(t.v2.begin()),
make_input_iterator(t.v2.end()));
BOOST_TEST(s == t.v2);
}
}
// string(string)
{
{
string const s0(t.v1);
string s(s0);
BOOST_TEST(s == t.v1);
}
{
string const s0(t.v2);
string s(s0);
BOOST_TEST(s == t.v2);
}
}
// string(string, storage_ptr)
{
fail_loop([&](storage_ptr const& sp)
{
string const s0(t.v1);
string s(s0, sp);
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string const s0(t.v2);
string s(s0, sp);
BOOST_TEST(s == t.v2);
});
}
// string(pilfered<string>)
{
{
string s1(t.v1);
string s2(pilfer(s1));
BOOST_TEST(s2 == t.v1);
BOOST_TEST(s1.empty());
BOOST_TEST(
s1.storage() == storage_ptr());
}
{
string s1(t.v2);
string s2(pilfer(s1));
BOOST_TEST(s2 == t.v2);
BOOST_TEST(s1.empty());
BOOST_TEST(
s1.storage() == storage_ptr());
}
// ensure pilfered-from objects
// are trivially destructible
{
string s1(make_shared_resource<
monotonic_resource>());
string s2(pilfer(s1));
BOOST_TEST(s1.storage().get() ==
storage_ptr().get());
}
}
// string(string&&)
{
{
string s1(t.v1);
string s2(std::move(s1));
BOOST_TEST(s2 == t.v1);
BOOST_TEST(s1.empty());
BOOST_TEST(
*s1.storage() ==
*s2.storage());
}
{
string s1(t.v2);
string s2(std::move(s1));
BOOST_TEST(s2 == t.v2);
BOOST_TEST(s1.empty());
BOOST_TEST(
*s1.storage() ==
*s2.storage());
}
}
// string(string&&, storage_ptr)
{
// same storage
fail_loop([&](storage_ptr const& sp)
{
string s1(t.v1, sp);
string s2(std::move(s1), sp);
BOOST_TEST(s2 == t.v1);
BOOST_TEST(s1.empty());
BOOST_TEST(
*s1.storage() ==
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
string s1(t.v2, sp);
string s2(std::move(s1));
BOOST_TEST(s2 == t.v2);
BOOST_TEST(s1.empty());
BOOST_TEST(
*s1.storage() ==
*s2.storage());
});
// different storage
fail_loop([&](storage_ptr const& sp)
{
string s1(t.v1);
string s2(std::move(s1), sp);
BOOST_TEST(s2 == t.v1);
BOOST_TEST(s1 == t.v1);
BOOST_TEST(
*s1.storage() !=
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
string s1(t.v2);
string s2(std::move(s1), sp);
BOOST_TEST(s2 == t.v2);
BOOST_TEST(s1 == t.v2);
BOOST_TEST(
*s1.storage() !=
*s2.storage());
});
}
// string(string_view, storage_ptr)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
BOOST_TEST(s == t.v2);
});
{
string s(t.v1);
BOOST_TEST(s == t.v1);
}
{
string s(t.v2);
BOOST_TEST(s == t.v2);
}
}
}
void
testAssignment()
{
test_vectors const t;
// operator=(string)
{
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v1.size(), '*');
string s(c, sp);
string const s2(t.v1);
s = s2;
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v2.size(), '*');
string s(c, sp);
string const s2(t.v1);
s = s2;
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v1.size(), '*');
string s(c, sp);
string const s2(t.v2);
s = s2;
BOOST_TEST(s == t.v2);
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v2.size(), '*');
string s(c, sp);
string const s2(t.v2);
s = s2;
BOOST_TEST(s == t.v2);
});
}
// operator=(string&&)
{
// same storage
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v1.size(), '*');
string s(c, sp);
string s2(t.v1, sp);
s = std::move(s2);
BOOST_TEST(s == t.v1);
BOOST_TEST(s2.empty());
BOOST_TEST(
*s.storage() ==
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v2.size(), '*');
string s(c, sp);
string s2(t.v1, sp);
s = std::move(s2);
BOOST_TEST(s == t.v1);
BOOST_TEST(s2.empty());
BOOST_TEST(
*s.storage() ==
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v1.size(), '*');
string s(c, sp);
string s2(t.v2, sp);
s = std::move(s2);
BOOST_TEST(s == t.v2);
BOOST_TEST(s2.empty());
BOOST_TEST(
*s.storage() ==
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v2.size(), '*');
string s(c, sp);
string s2(t.v2, sp);
s = std::move(s2);
BOOST_TEST(s == t.v2);
BOOST_TEST(s2.empty());
BOOST_TEST(
*s.storage() ==
*s2.storage());
});
// different storage
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v1.size(), '*');
string s(c, sp);
string s2(t.v1);
s = std::move(s2);
BOOST_TEST(s == t.v1);
BOOST_TEST(s2 == t.v1);
BOOST_TEST(
*s.storage() !=
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v2.size(), '*');
string s(c, sp);
string s2(t.v1);
s = std::move(s2);
BOOST_TEST(s == t.v1);
BOOST_TEST(s2 == t.v1);
BOOST_TEST(
*s.storage() !=
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v1.size(), '*');
string s(c, sp);
string s2(t.v2);
s = std::move(s2);
BOOST_TEST(s == t.v2);
BOOST_TEST(s2 == t.v2);
BOOST_TEST(
*s.storage() !=
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v2.size(), '*');
string s(c, sp);
string s2(t.v2);
s = std::move(s2);
BOOST_TEST(s == t.v2);
BOOST_TEST(s2 == t.v2);
BOOST_TEST(
*s.storage() !=
*s2.storage());
});
// self
fail_loop([&](storage_ptr const& sp)
{
string s1(t.v1, sp);
string& s2 = s1;
s1 = std::move(s2);
BOOST_TEST(s1 == t.v1);
});
}
// operator=(char const*)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s = t.s1.c_str();
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s = t.s1.c_str();
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s = t.s2.c_str();
BOOST_TEST(s == t.v2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s = t.s2.c_str();
BOOST_TEST(s == t.v2);
});
}
// operator=(string_view)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s = t.v1;
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s = t.v1;
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s = t.v2;
BOOST_TEST(s == t.v2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s = t.v2;
BOOST_TEST(s == t.v2);
});
}
}
void
testAssign()
{
test_vectors const t;
// assign(size_type, char)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), 'x', sp);
s.assign(t.v1.size(), '*');
BOOST_TEST(
s == std::string(t.v1.size(), '*'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), 'x', sp);
s.assign(t.v1.size(), '*');
BOOST_TEST(
s == std::string(t.v1.size(), '*'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), 'x', sp);
s.assign(t.v2.size(), '*');
BOOST_TEST(
s == std::string(t.v2.size(), '*'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), 'x', sp);
s.assign(t.v2.size(), '*');
BOOST_TEST(
s == std::string(t.v2.size(), '*'));
});
}
// assign(string)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), 'x', sp);
s.assign(string(t.v1.size(), '*'));
BOOST_TEST(
s == std::string(t.v1.size(), '*'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), 'x', sp);
s.assign(string(t.v1.size(), '*'));
BOOST_TEST(
s == std::string(t.v1.size(), '*'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), 'x', sp);
s.assign(string(t.v2.size(), '*'));
BOOST_TEST(
s == std::string(t.v2.size(), '*'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), 'x', sp);
s.assign(string(t.v2.size(), '*'));
BOOST_TEST(
s == std::string(t.v2.size(), '*'));
});
// self-assign
{
string s(t.v1);
s = static_cast<string const&>(s);
BOOST_TEST(s == t.v1);
}
}
// assign(string&&)
{
// same storage
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v1.size(), '*');
string s(c, sp);
string s2(t.v1, sp);
s.assign(std::move(s2));
BOOST_TEST(s == t.v1);
BOOST_TEST(s2.empty());
BOOST_TEST(
*s.storage() ==
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v2.size(), '*');
string s(c, sp);
string s2(t.v1, sp);
s.assign(std::move(s2));
BOOST_TEST(s == t.v1);
BOOST_TEST(s2.empty());
BOOST_TEST(
*s.storage() ==
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v1.size(), '*');
string s(c, sp);
string s2(t.v2, sp);
s.assign(std::move(s2));
BOOST_TEST(s == t.v2);
BOOST_TEST(s2.empty());
BOOST_TEST(
*s.storage() ==
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v2.size(), '*');
string s(c, sp);
string s2(t.v2, sp);
s.assign(std::move(s2));
BOOST_TEST(s == t.v2);
BOOST_TEST(s2.empty());
BOOST_TEST(
*s.storage() ==
*s2.storage());
});
// different storage
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v1.size(), '*');
string s(c, sp);
string s2(t.v1);
s.assign(std::move(s2));
BOOST_TEST(s == t.v1);
BOOST_TEST(s2 == t.v1);
BOOST_TEST(
*s.storage() !=
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v2.size(), '*');
string s(c, sp);
string s2(t.v1);
s.assign(std::move(s2));
BOOST_TEST(s == t.v1);
BOOST_TEST(s2 == t.v1);
BOOST_TEST(
*s.storage() !=
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v1.size(), '*');
string s(c, sp);
string s2(t.v2);
s.assign(std::move(s2));
BOOST_TEST(s == t.v2);
BOOST_TEST(s2 == t.v2);
BOOST_TEST(
*s.storage() !=
*s2.storage());
});
fail_loop([&](storage_ptr const& sp)
{
std::string c(t.v2.size(), '*');
string s(c, sp);
string s2(t.v2);
s.assign(std::move(s2));
BOOST_TEST(s == t.v2);
BOOST_TEST(s2 == t.v2);
BOOST_TEST(
*s.storage() !=
*s2.storage());
});
}
// assign(char const*, size_type)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s.assign(t.s1.c_str(), 3);
BOOST_TEST(s == "abc");
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s.assign(t.s1.c_str(), 3);
BOOST_TEST(s == "abc");
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s.assign(t.s2.c_str(), 3);
BOOST_TEST(s == "ABC");
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s.assign(t.s2.c_str(), 3);
BOOST_TEST(s == "ABC");
});
};
// assign(char const* s)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s.assign(t.s1.c_str());
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s.assign(t.s1.c_str());
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s.assign(t.s2.c_str());
BOOST_TEST(s == t.v2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s.assign(t.s2.c_str());
BOOST_TEST(s == t.v2);
});
}
// assign(InputIt, InputIt)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s.assign(t.s1.begin(), t.s1.end());
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s.assign(t.s1.begin(), t.s1.end());
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s.assign(
make_input_iterator(t.s1.begin()),
make_input_iterator(t.s1.end()));
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s.assign(
make_input_iterator(t.s1.begin()),
make_input_iterator(t.s1.end()));
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s.assign(t.s2.begin(), t.s2.end());
BOOST_TEST(s == t.v2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s.assign(t.s2.begin(), t.s2.end());
BOOST_TEST(s == t.v2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s.assign(
make_input_iterator(t.s2.begin()),
make_input_iterator(t.s2.end()));
BOOST_TEST(s == t.v2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s.assign(
make_input_iterator(t.s2.begin()),
make_input_iterator(t.s2.end()));
BOOST_TEST(s == t.v2);
});
// empty range
{
string s(t.v1);
s.assign(t.s1.begin(), t.s1.begin());
BOOST_TEST(s.empty());
}
// empty range
{
string s(t.v1);
s.assign(
make_input_iterator(t.s1.begin()),
make_input_iterator(t.s1.begin()));
BOOST_TEST(s.empty());
}
}
// assign(string_view)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s.assign(t.v1);
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s.assign(t.v1);
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1.size(), '*', sp);
s.assign(t.v2);
BOOST_TEST(s == t.v2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2.size(), '*', sp);
s.assign(t.v2);
BOOST_TEST(s == t.v2);
});
}
}
void
testConversion()
{
test_vectors const t;
string s(t.s1);
auto const& cs(s);
char const* chars = cs.c_str();
BOOST_TEST(chars == t.s1);
json::string_view sv = cs;
BOOST_TEST(sv == t.s1);
#if ! defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
std::string_view std_sv = cs;
BOOST_TEST(std_sv == t.s1);
#endif
s = t.s2;
chars = cs.c_str();
BOOST_TEST(chars == t.s2);
sv = cs;
BOOST_TEST(sv == t.s2);
#if ! defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
std_sv = cs;
BOOST_TEST(std_sv == t.s2);
#endif
}
void
testElementAccess()
{
test_vectors const t;
string s1(t.v1);
string s2(t.v2);
auto const& cs1(s1);
auto const& cs2(s2);
// at(size_type)
{
BOOST_TEST(s1.at(1) == 'b');
s1.at(1) = '*';
BOOST_TEST(s1.at(1) == '*');
s1.at(1) = 'b';
BOOST_TEST(s1.at(1) == 'b');
BOOST_TEST(s2.at(1) == 'B');
s2.at(1) = '*';
BOOST_TEST(s2.at(1) == '*');
s2.at(1) = 'B';
BOOST_TEST(s2.at(1) == 'B');
BOOST_TEST_THROWS(s1.at(s2.size()),
std::out_of_range);
}
// at(size_type) const
{
BOOST_TEST(cs1.at(1) == 'b');
BOOST_TEST(cs2.at(1) == 'B');
BOOST_TEST_THROWS(cs1.at(cs2.size()),
std::out_of_range);
}
// operator[&](size_type)
{
BOOST_TEST(s1[1] == 'b');
s1[1] = '*';
BOOST_TEST(s1[1] == '*');
s1[1] = 'b';
BOOST_TEST(s1[1] == 'b');
BOOST_TEST(s2[1] == 'B');
s2[1] = '*';
BOOST_TEST(s2[1] == '*');
s2[1] = 'B';
BOOST_TEST(s2[1] == 'B');
}
// operator[&](size_type) const
{
BOOST_TEST(cs1[1] == 'b');
BOOST_TEST(cs2[1] == 'B');
}
// front()
{
BOOST_TEST(s1.front() == 'a');
s1.front() = '*';
BOOST_TEST(s1.front() == '*');
s1.front() = 'a';
BOOST_TEST(s1.front() == 'a');
BOOST_TEST(s2.front() == 'A');
s2.front() = '*';
BOOST_TEST(s2.front() == '*');
s2.front() = 'A';
BOOST_TEST(s2.front() == 'A');
}
// front() const
{
BOOST_TEST(cs1.front() == 'a');
BOOST_TEST(cs2.front() == 'A');
}
// back()
{
auto const ch1 = s1.at(s1.size()-1);
auto const ch2 = s2.at(s2.size()-1);
BOOST_TEST(s1.back() == ch1);
s1.back() = '*';
BOOST_TEST(s1.back() == '*');
s1.back() = ch1;
BOOST_TEST(s1.back() == ch1);
BOOST_TEST(s2.back() == ch2);
s2.back() = '*';
BOOST_TEST(s2.back() == '*');
s2.back() = ch2;
BOOST_TEST(s2.back() == ch2);
}
// back() const
{
auto const ch1 = s1.at(s1.size()-1);
auto const ch2 = s2.at(s2.size()-1);
BOOST_TEST(cs1.back() == ch1);
BOOST_TEST(cs2.back() == ch2);
}
// data()
{
BOOST_TEST(
string_view(s1.data()) == t.v1);
BOOST_TEST(
string_view(s2.data()) == t.v2);
}
// data() const
{
BOOST_TEST(
string_view(cs1.data()) == t.v1);
BOOST_TEST(
string_view(cs2.data()) == t.v2);
}
// c_str()
{
BOOST_TEST(
string_view(cs1.c_str()) == t.v1);
BOOST_TEST(
string_view(cs2.c_str()) == t.v2);
}
// operator string_view()
{
BOOST_TEST(cs1.subview() == t.v1);
BOOST_TEST(cs2.subview() == t.v2);
}
}
void
testIterators()
{
string s = "abc";
auto const& ac(s);
{
auto it = s.begin();
BOOST_TEST(*it == 'a'); ++it;
BOOST_TEST(*it == 'b'); it++;
BOOST_TEST(*it == 'c'); ++it;
BOOST_TEST(it == s.end());
}
{
auto it = s.cbegin();
BOOST_TEST(*it == 'a'); ++it;
BOOST_TEST(*it == 'b'); it++;
BOOST_TEST(*it == 'c'); ++it;
BOOST_TEST(it == s.cend());
}
{
auto it = ac.begin();
BOOST_TEST(*it == 'a'); ++it;
BOOST_TEST(*it == 'b'); it++;
BOOST_TEST(*it == 'c'); ++it;
BOOST_TEST(it == ac.end());
}
{
auto it = s.end();
--it; BOOST_TEST(*it == 'c');
it--; BOOST_TEST(*it == 'b');
--it; BOOST_TEST(*it == 'a');
BOOST_TEST(it == s.begin());
}
{
auto it = s.cend();
--it; BOOST_TEST(*it == 'c');
it--; BOOST_TEST(*it == 'b');
--it; BOOST_TEST(*it == 'a');
BOOST_TEST(it == s.cbegin());
}
{
auto it = ac.end();
--it; BOOST_TEST(*it == 'c');
it--; BOOST_TEST(*it == 'b');
--it; BOOST_TEST(*it == 'a');
BOOST_TEST(it == ac.begin());
}
{
auto it = s.rbegin();
BOOST_TEST(*it == 'c'); ++it;
BOOST_TEST(*it == 'b'); it++;
BOOST_TEST(*it == 'a'); ++it;
BOOST_TEST(it == s.rend());
}
{
auto it = s.crbegin();
BOOST_TEST(*it == 'c'); ++it;
BOOST_TEST(*it == 'b'); it++;
BOOST_TEST(*it == 'a'); ++it;
BOOST_TEST(it == s.crend());
}
{
auto it = ac.rbegin();
BOOST_TEST(*it == 'c'); ++it;
BOOST_TEST(*it == 'b'); it++;
BOOST_TEST(*it == 'a'); ++it;
BOOST_TEST(it == ac.rend());
}
{
auto it = s.rend();
--it; BOOST_TEST(*it == 'a');
it--; BOOST_TEST(*it == 'b');
--it; BOOST_TEST(*it == 'c');
BOOST_TEST(it == s.rbegin());
}
{
auto it = s.crend();
--it; BOOST_TEST(*it == 'a');
it--; BOOST_TEST(*it == 'b');
--it; BOOST_TEST(*it == 'c');
BOOST_TEST(it == s.crbegin());
}
{
auto it = ac.rend();
--it; BOOST_TEST(*it == 'a');
it--; BOOST_TEST(*it == 'b');
--it; BOOST_TEST(*it == 'c');
BOOST_TEST(it == ac.rbegin());
}
{
string s2;
string const& cs2(s2);
BOOST_TEST(std::distance(
s2.begin(), s2.end()) == 0);
BOOST_TEST(std::distance(
cs2.begin(), cs2.end()) == 0);
BOOST_TEST(std::distance(
s2.rbegin(), s2.rend()) == 0);
BOOST_TEST(std::distance(
cs2.rbegin(), cs2.rend()) == 0);
}
}
void
testCapacity()
{
test_vectors const t;
// empty()
{
{
string s;
BOOST_TEST(s.empty());
}
{
string s = "abc";
BOOST_TEST(! s.empty());
}
}
// size()
// max_size()
{
string s = "abc";
BOOST_TEST(s.size() == 3);
BOOST_TEST(s.max_size() < string::npos);
}
// reserve(size_type)
{
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
s.append(t.v1);
s.append(t.v2);
s.reserve(0);
BOOST_TEST(s.size() ==
t.v1.size() + t.v2.size());
s.reserve(t.v1.size() + t.v2.size());
BOOST_TEST(s.size() ==
t.v1.size() + t.v2.size());
s.reserve(s.size() * 2);
BOOST_TEST(s.capacity() >
t.v1.size() + t.v2.size());
s.resize(t.v1.size());
s.reserve(t.v1.size());
BOOST_TEST(s == t.v1);
});
}
// capacity()
{
// implied
}
// shrink_to_fit()
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
string::size_type cap;
cap = s.capacity();
s.shrink_to_fit();
BOOST_TEST(s.capacity() == cap);
s.reserve(s.capacity() + 1);
s.shrink_to_fit();
BOOST_TEST(s.capacity() == cap);
s.resize(cap * 3, '*');
cap = s.capacity();
s.resize(cap - 1);
s.shrink_to_fit();
BOOST_TEST(s.capacity() == cap);
s.resize(cap / 2);
BOOST_TEST(s.capacity() == cap);
s.shrink_to_fit();
BOOST_TEST(s.capacity() < cap);
});
}
void
testClear()
{
test_vectors const t;
// clear()
{
{
string s(t.v1);
s.clear();
BOOST_TEST(s.empty());
BOOST_TEST(s.size() == 0);
BOOST_TEST(s.capacity() > 0);
}
{
string s(t.v2);
s.clear();
BOOST_TEST(s.empty());
BOOST_TEST(s.size() == 0);
BOOST_TEST(s.capacity() > 0);
}
}
}
void
testInsert()
{
test_vectors const t;
// insert(size_type, size_type, char)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.insert(1, 3, '*');
BOOST_TEST(s == std::string(
t.v1).insert(1, 3, '*'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.insert(1, 3, '*');
BOOST_TEST(s == std::string(
t.v2).insert(1, 3, '*'));
});
// pos out of range
{
string s(t.v1);
BOOST_TEST_THROWS(
(s.insert(s.size() + 2, 1, '*')),
std::out_of_range);
}
// size > max_size
{
string s(t.v1);
BOOST_TEST_THROWS(
(s.insert(1, s.max_size(), 'a')),
std::length_error);
}
}
// insert(size_type, char const*)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.insert(1, "***");
BOOST_TEST(s == std::string(
t.v1).insert(1, "***"));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.insert(1, "***");
BOOST_TEST(s == std::string(
t.v2).insert(1, "***"));
});
// pos out of range
{
string s(t.v1);
BOOST_TEST_THROWS(
(s.insert(s.size() + 2, "*")),
std::out_of_range);
}
}
// insert(size_type, char const*, size_type)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.insert(1, "*****");
BOOST_TEST(s == std::string(
t.v1).insert(1, "*****"));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.insert(1, "*****");
BOOST_TEST(s == std::string(
t.v2).insert(1, "*****"));
});
}
// insert(size_type, string const&)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.insert(1, string(t.v2));
BOOST_TEST(s == std::string(
t.v1).insert(1, t.s2));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.insert(1, string(t.v1));
BOOST_TEST(s == std::string(
t.v2).insert(1, t.s1));
});
}
//// KRYSTIAN These tests are superseded by the new string_view overloads
//// insert(size_type, string const&, size_type, size_type)
//{
// fail_loop([&](storage_ptr const& sp)
// {
// string s(t.v1, sp);
// s.insert(1, string(t.v2), 1, 3);
// BOOST_TEST(s == std::string(
// t.v1).insert(1, t.s2, 1, 3));
// });
// fail_loop([&](storage_ptr const& sp)
// {
// string s(t.v2, sp);
// s.insert(1, string(t.v1), 1, 3);
// BOOST_TEST(s == std::string(
// t.v2).insert(1, t.s1, 1, 3));
// });
// fail_loop([&](storage_ptr const& sp)
// {
// string s(t.v1, sp);
// s.insert(1, string(t.v2), 1);
// BOOST_TEST(s == std::string(
// t.v1).insert(1, t.s2, 1, std::string::npos));
// });
// fail_loop([&](storage_ptr const& sp)
// {
// string s(t.v2, sp);
// s.insert(1, string(t.v1), 1);
// BOOST_TEST(s == std::string(
// t.v2).insert(1, t.s1, 1, std::string::npos));
// });
//}
// insert(size_type, char)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
BOOST_TEST(
s.insert(2, '*')[2] == '*');
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
BOOST_TEST(
s.insert(2, '*')[2] == '*');
});
}
// insert(const_iterator, size_type, char)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
BOOST_TEST(string_view(
&(s.insert(2, 3, '*')[2]), 5) ==
"***cd");
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
BOOST_TEST(string_view(
&(s.insert(2, 3, '*')[2]), 5) ==
"***CD");
});
}
// insert(const_iterator, InputIt, InputIt)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.insert(2, t.s2.begin(), t.s2.end());
std::string cs(t.s1);
cs.insert(2, &t.s2[0], t.s2.size());
BOOST_TEST(s == cs);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.insert(2, t.s1.begin(), t.s1.end());
std::string cs(t.s2);
cs.insert(2, &t.s1[0], t.s1.size());
BOOST_TEST(s == cs);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.insert(2,
make_input_iterator(t.s2.begin()),
make_input_iterator(t.s2.end()));
std::string cs(t.s1);
cs.insert(2, &t.s2[0], t.s2.size());
BOOST_TEST(s == cs);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.insert(2,
make_input_iterator(t.s1.begin()),
make_input_iterator(t.s1.end()));
std::string cs(t.s2);
cs.insert(2, &t.s1[0], t.s1.size());
BOOST_TEST(s == cs);
});
}
// insert(const_iterator, string_view)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.insert(2, string_view(t.v2));
std::string cs(t.v1);
cs.insert(2, t.s2);
BOOST_TEST(s == cs);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.insert(2, string_view(t.v1));
std::string cs(t.v2);
cs.insert(2, t.s1);
BOOST_TEST(s == cs);
});
}
// insert(const_iterator, string_view)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.insert(2, string_view(t.v2).substr(2, 3));
std::string cs(t.v1);
cs.insert(2, t.s2, 2, 3);
BOOST_TEST(s == cs);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.insert(2, string_view(t.v1).substr(2, 3));
std::string cs(t.v2);
cs.insert(2, t.s1, 2, 3);
BOOST_TEST(s == cs);
});
}
// insert(size_type, char const*)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.insert(1, "***");
BOOST_TEST(s == std::string(
t.v1).insert(1, "***"));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.insert(1, "***");
BOOST_TEST(s == std::string(
t.v2).insert(1, "***"));
});
// pos out of range
{
string s(t.v1);
BOOST_TEST_THROWS(
(s.insert(s.size() + 2, "*")),
std::out_of_range);
}
}
// insert tests for when source is within destination
{
// start before splice point
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.reserve(s.size() + 10);
s.insert(4, s.subview(0, 3));
std::string cs(t.v1);
cs.insert(4, cs.substr(0, 3));
BOOST_TEST(s == cs);
});
// start after splice point
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.reserve(s.size() + 10);
s.insert(0, s.subview(3, 3));
std::string cs(t.v1);
cs.insert(0, cs.substr(3, 3));
BOOST_TEST(s == cs);
});
// insert pos bisects the inserted string
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.reserve(s.size() + 10);
s.insert(2, s.subview(0, 5));
std::string cs(t.v1);
cs.insert(2, cs.substr(0, 5));
BOOST_TEST(s == cs);
});
}
// insert reallocation test
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
std::string cs(t.v2);
const auto view = t.v2.substr(0, 4);
s.append(s);
cs.append(cs);
s.insert(2, view);
cs.insert(2, view.data(), view.size());
BOOST_TEST(s == cs);
});
}
}
void
testErase()
{
test_vectors const t;
// erase(size_type, size_type)
{
{
string s(t.v1);
s.erase(1, 3);
BOOST_TEST(s ==
std::string(t.v1).erase(1, 3));
}
{
string s(t.v2);
s.erase(1, 3);
BOOST_TEST(s ==
std::string(t.v2).erase(1, 3));
}
{
string s(t.v1);
s.erase(3);
BOOST_TEST(s ==
std::string(t.v1).erase(3));
}
{
string s(t.v2);
s.erase(3);
BOOST_TEST(s ==
std::string(t.v2).erase(3));
}
{
string s(t.v1);
s.erase();
BOOST_TEST(s ==
std::string(t.v1).erase());
}
{
string s(t.v2);
s.erase();
BOOST_TEST(s ==
std::string(t.v2).erase());
}
{
string s(t.v1);
BOOST_TEST_THROWS(
(s.erase(t.v1.size() + 1, 1)),
std::out_of_range);
}
}
// iterator erase(const_iterator)
{
{
string s(t.v1);
std::string s2(t.v1);
s.erase(s.begin() + 3);
s2.erase(s2.begin() + 3);
BOOST_TEST(s == s2);
}
{
string s(t.v2);
std::string s2(t.v2);
s.erase(s.begin() + 3);
s2.erase(s2.begin() + 3);
BOOST_TEST(s == s2);
}
}
// iterator erase(const_iterator, const_iterator)
{
string s(t.v1);
std::string s2(t.v1);
s.erase(s.begin() + 1, s.begin() + 3);
s2.erase(s2.begin() + 1, s2.begin() + 3);
BOOST_TEST(s == s2);
}
}
void
testPushPop()
{
test_vectors const t;
// push_back(char)
{
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
for(auto ch : t.v1)
s.push_back(ch);
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
for(auto ch : t.v2)
s.push_back(ch);
BOOST_TEST(s == t.v2);
});
}
// pop_back(char)
{
{
string s(t.v1);
while(! s.empty())
s.pop_back();
BOOST_TEST(s.empty());
BOOST_TEST(s.capacity() > 0);
}
{
string s(t.v2);
while(! s.empty())
s.pop_back();
BOOST_TEST(s.empty());
BOOST_TEST(s.capacity() > 0);
}
}
}
void
testAppend()
{
test_vectors const t;
// append(size_type, char)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.append(t.v2.size(), '*');
BOOST_TEST(s == t.s1 +
std::string(t.v2.size(), '*'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.append(t.v1.size(), '*');
BOOST_TEST(s == t.s2 +
std::string(t.v1.size(), '*'));
});
}
// append(string_view)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.append(string(t.v2));
BOOST_TEST(s == t.s1 + t.s2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.append(string(t.v1));
BOOST_TEST(s == t.s2 + t.s1);
});
}
// append(string_view)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.append(string(t.v2).subview(3));
BOOST_TEST(s == t.s1 + t.s2.substr(3));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.append(string(t.v1).subview(3));
BOOST_TEST(s == t.s2 + t.s1.substr(3));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.append(string(t.v2).subview(2, 3));
BOOST_TEST(s == t.s1 + t.s2.substr(2, 3));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.append(string(t.v1).subview(2, 3));
BOOST_TEST(s == t.s2 + t.s1.substr(2, 3));
});
}
// append(char const*)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.append(t.s2.c_str());
BOOST_TEST(s == t.s1 + t.s2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.append(t.s1.c_str());
BOOST_TEST(s == t.s2 + t.s1);
});
}
// append(InputIt, InputIt)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.append(t.s2.begin(), t.s2.end());
BOOST_TEST(s == t.s1 + t.s2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.append(t.s1.begin(), t.s1.end());
BOOST_TEST(s == t.s2 + t.s1);
});
// Fails on Visual Studio 2017 C++2a Strict
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.append(
make_input_iterator(t.s2.begin()),
make_input_iterator(t.s2.end()));
BOOST_TEST(s == t.s1 + t.s2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.append(
make_input_iterator(t.s1.begin()),
make_input_iterator(t.s1.end()));
BOOST_TEST(s == t.s2 + t.s1);
});
}
// append(string_view)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.append(t.v2);
BOOST_TEST(s == t.s1 + t.s2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.append(t.v1);
BOOST_TEST(s == t.s2 + t.s1);
});
}
// append(string_view)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.append(t.v2.substr(2));
BOOST_TEST(s == t.s1 + t.s2.substr(2));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.append(t.v1.substr(2));
BOOST_TEST(s == t.s2 + t.s1.substr(2));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s.append(t.v2.substr(2, 3));
BOOST_TEST(s == t.s1 + t.s2.substr(2, 3));
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s.append(t.v1.substr(2, 3));
BOOST_TEST(s == t.s2 + t.s1.substr(2, 3));
});
}
}
void
testPlusEquals()
{
test_vectors const t;
// operator+=(string)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s += string(t.v2);
BOOST_TEST(s == t.s1 + t.s2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s += string(t.v1);
BOOST_TEST(s == t.s2 + t.s1);
});
}
// operator+=(char)
{
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
for(auto ch : t.v1)
s += ch;
BOOST_TEST(s == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
for(auto ch : t.v2)
s += ch;
BOOST_TEST(s == t.v2);
});
}
// operator+=(char const*)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s += t.s2.c_str();
BOOST_TEST(s == t.s1 + t.s2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s += t.s1.c_str();
BOOST_TEST(s == t.s2 + t.s1);
});
}
// operator+=(string_view)
{
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
s += t.v2;
BOOST_TEST(s == t.s1 + t.s2);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
s += t.v1;
BOOST_TEST(s == t.s2 + t.s1);
});
}
}
void
testCompare()
{
test_vectors const t;
string const v1 = t.v1;
// compare(string)
BOOST_TEST(v1.compare(string("aaaaaaa")) > 0);
BOOST_TEST(v1.compare(string(t.v1)) == 0);
BOOST_TEST(v1.compare(string("bbbbbbb")) < 0);
// compare(char const*)
BOOST_TEST(v1.compare("aaaaaaa") > 0);
BOOST_TEST(v1.compare(t.s1.c_str()) == 0);
BOOST_TEST(v1.compare("bbbbbbb") < 0);
// compare(string_view s)
BOOST_TEST(v1.compare(string_view("aaaaaaa")) > 0);
BOOST_TEST(v1.compare(t.v1) == 0);
BOOST_TEST(v1.compare(string_view("bbbbbbb")) < 0);
}
void
testStartEndsWith()
{
test_vectors const t;
string const v1 = t.v1;
string const v2 = t.v2;
// starts_with(string_view)
{
BOOST_TEST(v1.starts_with(string_view("abc")));
BOOST_TEST(v2.starts_with(string_view("ABC")));
BOOST_TEST(! v1.starts_with(string_view("xyz")));
BOOST_TEST(! v2.starts_with(string_view("XYZ")));
}
// starts_with(char)
{
BOOST_TEST(v1.starts_with('a'));
BOOST_TEST(v2.starts_with('A'));
BOOST_TEST(! v1.starts_with('x'));
BOOST_TEST(! v2.starts_with('X'));
}
// starts_with(char const*)
{
BOOST_TEST(v1.starts_with("abc"));
BOOST_TEST(v2.starts_with("ABC"));
BOOST_TEST(! v1.starts_with("xyz"));
BOOST_TEST(! v2.starts_with("XYZ"));
}
// ends_with(string_view)
{
BOOST_TEST(v1.ends_with(last_of(t.s1,3)));
BOOST_TEST(v2.ends_with(last_of(t.s2,3)));
BOOST_TEST(! v1.ends_with(string_view("abc")));
BOOST_TEST(! v2.ends_with(string_view("ABC")));
}
// ends_with(char)
{
BOOST_TEST(v1.ends_with(last_of(t.s1, 1)[0]));
BOOST_TEST(v2.ends_with(last_of(t.s2, 1)[0]));
BOOST_TEST(! v1.ends_with('a'));
BOOST_TEST(! v2.ends_with('A'));
}
// ends_with(char const*)
{
BOOST_TEST(v1.ends_with(last_of(t.s1, 3).data()));
BOOST_TEST(v2.ends_with(last_of(t.s2, 3).data()));
BOOST_TEST(! v1.ends_with("abc"));
BOOST_TEST(! v2.ends_with("ABC"));
}
}
void
testReplace()
{
test_vectors const t;
// replace(std::size_t, std::size_t, string_view)
{
// pos out of range
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
BOOST_TEST_THROWS(s.replace(s.size() + 1, 1, t.v2),
std::out_of_range);
});
// outside, shrink
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(s2.replace(0, 4, t.v2.substr(4, 2)) ==
s1.replace(0, 4, t.v2.data() + 4, 2));
});
// outside, grow
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(s2.replace(0, 1, t.v2.substr(0)) ==
s1.replace(0, 1, t.v2.data(), t.v2.size()));
});
// outside, grow, reallocate
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
s1.append(s1);
s2.append(s2);
BOOST_TEST(s2.replace(0, 1, t.v2.substr(0)) ==
s1.replace(0, 1, t.v2.data(), t.v2.size()));
});
// outside, same
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(s2.replace(0, 2, t.v2.substr(0, 2)) ==
s1.replace(0, 2, t.v2.data(), 2));
});
// replace tests for full coverage
// inside, no effect
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(s2.replace(0, 4, s2.subview(0, 4)) ==
s1.replace(0, 4, s1.data() + 0, 4));
});
// inside, shrink, split
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(s2.replace(1, 4, s2.subview(4, 2)) ==
s1.replace(1, 4, s1.data() + 4, 2));
});
// inside, grow no reallocate, split
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(s2.replace(1, 1, s2.subview(0)) ==
s1.replace(1, 1, s1.data(), s1.size()));
});
// inside, reallocate, split
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
s1.append(s1);
s2.append(s2);
BOOST_TEST(s2.replace(1, 1, s2.subview(0)) ==
s1.replace(1, 1, s1.data(), s1.size()));
});
// inside, same, split
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(s2.replace(1, 2, s2.subview(0, 2)) ==
s1.replace(1, 2, s1.data(), 2));
});
}
// replace(const_iterator, const_iterator, string_view)
{
// outside, shrink
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(
s2.replace(
s2.begin(),
s2.begin() + 4,
t.v2.substr(4, 2)) ==
s1.replace(0,
4, t.v2.data() + 4,
2));
});
// outside, grow
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(
s2.replace(
s2.begin(),
s2.begin() + 1,
t.v2.substr(0)) ==
s1.replace(0,
1, t.v2.data(),
t.v2.size()));
});
// outside, same
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(
s2.replace(
s2.begin(),
s2.begin() + 2,
t.v2.substr(0, 2)) ==
s1.replace(
0, 2,
t.v2.data(),
2));
});
// inside, shrink
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(
s2.replace(
s2.begin() + 1,
s2.begin() + 5,
s2.subview(4, 2)) ==
s1.replace(
1, 4,
s1.data() + 4,
2));
});
// inside, grow
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(
s2.replace(
s2.begin() + 1,
s2.begin() + 2,
s2.subview(0)) ==
s1.replace(
1, 1,
s1.data(),
s1.size()));
});
// inside, same
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(
s2.replace(
s2.begin() + 1,
s2.begin() + 3,
s2.subview(0, 2)) ==
s1.replace(
1, 2,
s1.data(),
2));
});
}
// replace(std::size_t, std::size_t, std::size_t, char)
{
// grow, no realloc
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(s2.replace(0, 4, 10, 'a') ==
s1.replace(0, 4, 10, 'a'));
});
// grow, realloc
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
const auto grow = (std::max)(s1.capacity(), s2.capacity());
BOOST_TEST(s2.replace(0, 4, grow, 'a') ==
s1.replace(0, 4, grow, 'a'));
});
// no change in size
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(s2.replace(0, 1, 1, 'a') ==
s1.replace(0, 1, 1, 'a'));
});
// pos out of range
fail_loop([&](storage_ptr const& sp)
{
string s(t.v2, sp);
BOOST_TEST_THROWS(s.replace(s.size() + 1, 1, 1, 'a'),
std::out_of_range);
});
}
// replace(const_iterator, const_iterator, std::size_t, char)
{
fail_loop([&](storage_ptr const& sp)
{
std::string s1(t.v2.data(), t.v2.size());
string s2(t.v2, sp);
BOOST_TEST(
s2.replace(s2.begin(), s2.begin() + 4, 10, 'a') ==
s1.replace(0, 4, 10, 'a'));
});
}
}
void
testSubStr()
{
test_vectors const t;
string const s1 = t.v1;
string const s2 = t.v2;
// subview(size_type, size_type)
BOOST_TEST(s1.subview() == t.v1);
BOOST_TEST(s1.subview(1) == t.v1.substr(1));
BOOST_TEST(s1.subview(1, 3) == t.v1.substr(1, 3));
BOOST_TEST(s2.subview() == t.v2);
BOOST_TEST(s2.subview(1) == t.v2.substr(1));
BOOST_TEST(s2.subview(1, 3) == t.v2.substr(1, 3));
}
void
testCopy()
{
test_vectors const t;
// copy(char*, count, pos)
{
{
string s(t.v1);
std::string d;
d.resize(s.size());
s.copy(&d[0], d.size(), 0);
BOOST_TEST(d == t.v1);
}
{
string s(t.v1);
std::string d;
d.resize(s.size());
s.copy(&d[0], d.size());
BOOST_TEST(d == t.v1);
}
}
}
void
testResize()
{
test_vectors const t;
// resize(size_type)
{
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
s.resize(t.v1.size());
BOOST_TEST(s.size() == t.v1.size());
BOOST_TEST(s == string(t.v1.size(), '\0'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
s.resize(t.v2.size());
BOOST_TEST(s.size() == t.v2.size());
BOOST_TEST(s == string(t.v2.size(), '\0'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
s.resize(t.v1.size());
s.resize(t.v2.size());
BOOST_TEST(s == string(t.v2.size(), '\0'));
s.resize(t.v1.size());
BOOST_TEST(s == string(t.v1.size(), '\0'));
});
}
// resize(size_type, char)
{
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
s.resize(t.v1.size(), '*');
BOOST_TEST(s.size() == t.v1.size());
BOOST_TEST(s == string(t.v1.size(), '*'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
s.resize(t.v2.size(), '*');
BOOST_TEST(s.size() == t.v2.size());
BOOST_TEST(s == string(t.v2.size(), '*'));
});
fail_loop([&](storage_ptr const& sp)
{
string s(sp);
s.resize(t.v1.size(), '*');
s.resize(t.v2.size(), '*');
BOOST_TEST(s == string(t.v2.size(), '*'));
s.resize(t.v1.size());
BOOST_TEST(s == string(t.v1.size(), '*'));
});
}
}
void
testSwap()
{
test_vectors const t;
fail_loop([&](storage_ptr const& sp)
{
string s1(t.v1, sp);
string s2(t.v2, sp);
s1.swap(s2);
BOOST_TEST(s1 == t.v2);
BOOST_TEST(s2 == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s1(t.v1, sp);
string s2(t.v2, sp);
swap(s1, s2);
BOOST_TEST(s1 == t.v2);
BOOST_TEST(s2 == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s1(t.v1);
string s2(t.v2, sp);
s1.swap(s2);
BOOST_TEST(s1 == t.v2);
BOOST_TEST(s2 == t.v1);
});
fail_loop([&](storage_ptr const& sp)
{
string s(t.v1, sp);
swap(s, s);
BOOST_TEST(s == t.v1);
});
}
void
testFind()
{
test_vectors const t;
string const s1 = t.v1;
// find(string_view, size_type)
BOOST_TEST(s1.find("bcd") == 1);
BOOST_TEST(s1.find("cde") == 2);
BOOST_TEST(s1.find("bcd", 0) == 1);
BOOST_TEST(s1.find("cde", 1) == 2);
BOOST_TEST(s1.find("efg", 5) == string::npos);
// find(char, size_type)
BOOST_TEST(s1.find('b') == 1);
BOOST_TEST(s1.find('c', 1) == 2);
BOOST_TEST(s1.find('e', 5) == string::npos);
}
void
testRfind()
{
test_vectors const t;
string const s1 = t.v1;
// rfind(string_view, size_type)
BOOST_TEST(s1.rfind("bcd") == 1);
BOOST_TEST(s1.rfind("cde") == 2);
BOOST_TEST(s1.rfind("bcd", 1) == 1);
BOOST_TEST(s1.rfind("cde", 2) == 2);
BOOST_TEST(s1.rfind("efg", 3) == string::npos);
// rfind(char, size_type)
BOOST_TEST(s1.rfind('b') == 1);
BOOST_TEST(s1.rfind('c', 2) == 2);
BOOST_TEST(s1.rfind('e', 3) == string::npos);
}
void
testFindFirstOf()
{
test_vectors const t;
string const s1 = t.v1;
// find_first_of(string_view, size_type)
BOOST_TEST(s1.find_first_of("bcd") == 1);
BOOST_TEST(s1.find_first_of("cde") == 2);
BOOST_TEST(s1.find_first_of("bcd", 0) == 1);
BOOST_TEST(s1.find_first_of("cde", 1) == 2);
BOOST_TEST(s1.find_first_of("efg", 7) == string::npos);
}
void
testFindFirstNotOf()
{
test_vectors const t;
string const s1 = t.v1;
// find_first_not_of(string_view, size_type)
BOOST_TEST(s1.find_first_not_of("abc") == 3);
BOOST_TEST(s1.find_first_not_of("cde") == 0);
BOOST_TEST(s1.find_first_not_of("bcd", 0) == 0);
BOOST_TEST(s1.find_first_not_of("cde", 2) == 5);
// find_first_not_of(char, size_type)
BOOST_TEST(s1.find_first_not_of('b') == 0);
BOOST_TEST(s1.find_first_not_of('a', 0) == 1);
BOOST_TEST(s1.find_first_not_of('e', 4) == 5);
}
void
testFindLastOf()
{
test_vectors const t;
string const s1 = t.v1;
// find_last_of(string_view, size_type)
BOOST_TEST(s1.find_last_of("bcd") == 3);
BOOST_TEST(s1.find_last_of("cde") == 4);
BOOST_TEST(s1.find_last_of("bcd", 3) == 3);
BOOST_TEST(s1.find_last_of("cde", 5) == 4);
BOOST_TEST(s1.find_last_of("efg", 3) == string::npos);
}
void
testFindLastNotOf()
{
test_vectors const t;
string const s1 = t.v1;
// find_last_not_of(string_view, size_type)
BOOST_TEST(s1.find_last_not_of("abc", 3) == 3);
BOOST_TEST(s1.find_last_not_of("bcd", 3) == 0);
BOOST_TEST(s1.find_last_not_of("efg", 4) == 3);
BOOST_TEST(s1.find_last_not_of("abc", 2) == string::npos);
// find_first_not_of(char, size_type)
BOOST_TEST(s1.find_last_not_of('a', 3) == 3);
BOOST_TEST(s1.find_last_not_of('e', 4) == 3);
BOOST_TEST(s1.find_last_not_of('a', 0) == string::npos);
}
void
testNonMembers()
{
test_vectors const t;
string const s1(t.v1);
string const s2(t.v2);
auto const v1(t.v1);
auto const v2(t.v2);
auto const c1 = t.s1.c_str();
auto const c2 = t.s2.c_str();
BOOST_TEST(! operator< (s1, s2));
BOOST_TEST(! operator< (s1, v2));
BOOST_TEST(! operator< (s1, c2));
BOOST_TEST(! operator<=(s1, s2));
BOOST_TEST(! operator<=(s1, v2));
BOOST_TEST(! operator<=(s1, c2));
BOOST_TEST(! operator==(s1, s2));
BOOST_TEST(! operator==(s1, v2));
BOOST_TEST(! operator==(s1, c2));
BOOST_TEST( operator!=(s1, s2));
BOOST_TEST( operator!=(s1, v2));
BOOST_TEST( operator!=(s1, c2));
BOOST_TEST( operator>=(s1, s2));
BOOST_TEST( operator>=(s1, v2));
BOOST_TEST( operator>=(s1, c2));
BOOST_TEST( operator> (s1, s2));
BOOST_TEST( operator> (s1, v2));
BOOST_TEST( operator> (s1, c2));
BOOST_TEST( operator< (s2, s1));
BOOST_TEST( operator< (s2, v1));
BOOST_TEST( operator< (s2, c1));
BOOST_TEST( operator<=(s2, s1));
BOOST_TEST( operator<=(s2, v1));
BOOST_TEST( operator<=(s2, c1));
BOOST_TEST( operator!=(s2, s1));
BOOST_TEST( operator!=(s2, v1));
BOOST_TEST( operator!=(s2, c1));
BOOST_TEST(! operator==(s2, s1));
BOOST_TEST(! operator==(s2, v1));
BOOST_TEST(! operator==(s2, c1));
BOOST_TEST(! operator>=(s2, s1));
BOOST_TEST(! operator>=(s2, v1));
BOOST_TEST(! operator>=(s2, c1));
BOOST_TEST(! operator> (s2, s1));
BOOST_TEST(! operator> (s2, v1));
BOOST_TEST(! operator> (s2, c1));
BOOST_TEST( operator< (s2, s1));
BOOST_TEST( operator< (v2, s1));
BOOST_TEST( operator< (c2, s1));
BOOST_TEST( operator<=(s2, s1));
BOOST_TEST( operator<=(v2, s1));
BOOST_TEST( operator<=(c2, s1));
BOOST_TEST( operator!=(s2, s1));
BOOST_TEST( operator!=(v2, s1));
BOOST_TEST( operator!=(c2, s1));
BOOST_TEST(! operator==(s2, s1));
BOOST_TEST(! operator==(v2, s1));
BOOST_TEST(! operator==(c2, s1));
BOOST_TEST(! operator>=(s2, s1));
BOOST_TEST(! operator>=(v2, s1));
BOOST_TEST(! operator>=(c2, s1));
BOOST_TEST(! operator> (s2, s1));
BOOST_TEST(! operator> (v2, s1));
BOOST_TEST(! operator> (c2, s1));
BOOST_TEST(! operator< (s1, s2));
BOOST_TEST(! operator< (v1, s2));
BOOST_TEST(! operator< (c1, s2));
BOOST_TEST(! operator<=(s1, s2));
BOOST_TEST(! operator<=(v1, s2));
BOOST_TEST(! operator<=(c1, s2));
BOOST_TEST(! operator==(s1, s2));
BOOST_TEST(! operator==(v1, s2));
BOOST_TEST(! operator==(c1, s2));
BOOST_TEST( operator!=(s1, s2));
BOOST_TEST( operator!=(v1, s2));
BOOST_TEST( operator!=(c1, s2));
BOOST_TEST( operator>=(s1, s2));
BOOST_TEST( operator>=(v1, s2));
BOOST_TEST( operator>=(c1, s2));
BOOST_TEST( operator> (s1, s2));
BOOST_TEST( operator> (v1, s2));
BOOST_TEST( operator> (c1, s2));
}
void
testHash()
{
// libstdc++ 4.8 bug
#if !defined(__GNUC__) || (__GNUC__ > 4 || \
(__GNUC__ == 4 && __GNUC_MINOR__ > 8))
{
std::unordered_set<string> us;
us.emplace("first");
us.emplace("second");
}
{
std::unordered_set<string>(
0,
std::hash<string>());
}
#endif
{
std::hash<string> h1;
std::hash<string> h2(h1);
std::hash<string> h3;
h1 = h3;
h2 = h3;
(void)h2;
}
}
void
run()
{
testConstruction();
testAssignment();
testAssign();
testConversion();
testElementAccess();
testIterators();
testCapacity();
testClear();
testInsert();
testErase();
testPushPop();
testAppend();
testPlusEquals();
testCompare();
testStartEndsWith();
testReplace();
testSubStr();
testCopy();
testResize();
testSwap();
testFind();
testRfind();
testFindFirstOf();
testFindFirstNotOf();
testFindLastOf();
testFindLastNotOf();
testNonMembers();
testHash();
}
};
TEST_SUITE(string_test, "boost.json.string");
} // namespace json
} // namespace boost