blob: e34288a4a962081dbeac2474fd618da71c3a4342 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/stdcompat/string_view.h>
#include <cstring>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>
#include "gtest.h"
#include "test_helper.h"
namespace {
TEST(StringViewTest, CreateFromStdString) {
std::string str = "1";
cpp17::string_view v_str(str);
EXPECT_FALSE(v_str.empty());
EXPECT_EQ(str.data(), v_str.data());
EXPECT_EQ(str.length(), v_str.length());
}
TEST(StringViewTest, CreateFromCArray) {
constexpr char kStr[] = "1";
cpp17::string_view v_str(kStr);
EXPECT_FALSE(v_str.empty());
EXPECT_EQ(kStr, v_str.data());
EXPECT_EQ(std::strlen(kStr), v_str.length());
}
TEST(StringViewTest, CreateFromConstChar) {
const char* kStr = "1";
cpp17::string_view v_str(kStr);
EXPECT_FALSE(v_str.empty());
EXPECT_EQ(kStr, v_str.data());
EXPECT_EQ(std::strlen(kStr), v_str.length());
}
TEST(StringViewTest, CreateFromStringView) {
cpp17::string_view str_view("12345");
cpp17::string_view v_str(str_view);
EXPECT_FALSE(v_str.empty());
EXPECT_EQ(str_view.data(), v_str.data());
EXPECT_EQ(str_view.length(), v_str.length());
}
TEST(StringViewTest, CreateFromConstexprStringView) {
constexpr cpp17::string_view kLiteral = "12345";
cpp17::string_view v_str(kLiteral);
EXPECT_EQ(kLiteral.data(), v_str.data());
EXPECT_EQ(kLiteral.length(), v_str.length());
}
TEST(StringViewTest, CreateFromConstexprStringViewConstructor) {
constexpr cpp17::string_view kLiteral("12345");
EXPECT_EQ(5u, kLiteral.size());
EXPECT_EQ(5u, kLiteral.length());
}
TEST(StringViewTest, CreateFromStringViewLiteral) {
{
using namespace cpp17::literals;
constexpr cpp17::string_view kLiteral = "12345"_sv;
EXPECT_EQ(5u, kLiteral.size());
EXPECT_EQ(5u, kLiteral.length());
constexpr cpp17::wstring_view kWLiteral = L"12345"_sv;
EXPECT_EQ(5u, kWLiteral.size());
EXPECT_EQ(5u, kWLiteral.length());
constexpr cpp17::u16string_view ku16Literal = u"12345"_sv;
EXPECT_EQ(5u, ku16Literal.size());
EXPECT_EQ(5u, ku16Literal.length());
constexpr cpp17::u16string_view ku32Literal = u"12345"_sv;
EXPECT_EQ(5u, ku32Literal.size());
EXPECT_EQ(5u, ku32Literal.length());
}
{
using namespace cpp17::string_view_literals;
constexpr cpp17::string_view kLiteral __attribute__((unused)) = "12345"_sv;
constexpr cpp17::wstring_view kWLiteral __attribute__((unused)) = L"12345"_sv;
constexpr cpp17::u16string_view ku16Literal __attribute__((unused)) = u"12345"_sv;
constexpr cpp17::u16string_view ku32Literal __attribute__((unused)) = u"12345"_sv;
}
{
using namespace cpp17::literals::string_view_literals;
constexpr cpp17::string_view kLiteral __attribute__((unused)) = "12345"_sv;
constexpr cpp17::wstring_view kWLiteral __attribute__((unused)) = L"12345"_sv;
constexpr cpp17::u16string_view ku16Literal __attribute__((unused)) = u"12345"_sv;
constexpr cpp17::u16string_view ku32Literal __attribute__((unused)) = u"12345"_sv;
}
}
TEST(StringViewTest, SizeIsSameAsLength) {
constexpr cpp17::string_view kLiteral = "12345";
EXPECT_EQ(5u, kLiteral.size());
EXPECT_EQ(5u, kLiteral.length());
}
TEST(StringViewTest, ArrayAccessOperator) {
// Need static duration to enforce subobject constexpr, otherwise it is not allowed.
constexpr static char const kLiteral[] = "12345";
constexpr cpp17::string_view kFitLiteral(kLiteral);
for (std::size_t i = 0; i < kFitLiteral.size(); ++i) {
EXPECT_EQ(kLiteral[i], kFitLiteral[i]) << "Array access returned wrong value.";
EXPECT_EQ(&kLiteral[i], &kFitLiteral[i]) << "Array access returned value at different address.";
}
}
TEST(StringViewTest, BeginPointsToFirstElement) {
constexpr cpp17::string_view kLiteral = "12345";
EXPECT_EQ(&kLiteral[0], &(*kLiteral.begin()));
EXPECT_EQ(&kLiteral[4], &(*kLiteral.rbegin()));
}
TEST(StringViewTest, EndPointsOnePastLastElement) {
constexpr cpp17::string_view kLiteral = "12345";
EXPECT_EQ(&kLiteral[4], &(*(kLiteral.end() - 1)));
EXPECT_EQ(&kLiteral[0], &(*(kLiteral.rend() - 1)));
}
TEST(StringViewTest, EndPointsPastLastElement) {
constexpr cpp17::string_view kLiteral = "12345";
EXPECT_EQ(kLiteral.begin() + 5, kLiteral.end());
EXPECT_EQ(kLiteral.rbegin() + 5, kLiteral.rend());
}
TEST(StringViewTest, WhenEmptyBeginIsSameAsEnd) {
constexpr cpp17::string_view kLiteral = "";
EXPECT_EQ(kLiteral.begin(), kLiteral.end());
EXPECT_EQ(kLiteral.rbegin(), kLiteral.rend());
}
TEST(StringViewTest, FrontReturnsRefToFirstElement) {
constexpr cpp17::string_view kLiteral = "12345";
EXPECT_EQ(&(*kLiteral.begin()), &kLiteral.front());
}
TEST(StringViewTest, BackReturnsRefToLastElement) {
constexpr cpp17::string_view kLiteral = "12345";
EXPECT_EQ(&(*(kLiteral.begin() + 4)), &kLiteral.back());
}
TEST(StringViewTest, EmptyIsTrueForEmptyString) {
constexpr cpp17::string_view kStr;
ASSERT_TRUE(kStr.empty());
ASSERT_EQ(0u, kStr.size());
ASSERT_EQ(0u, kStr.length());
}
TEST(StringViewTest, AtReturnsElementAtIndex) {
// Need static duration to enforce subobject constexpr, otherwise it is not allowed.
constexpr static char const kLiteral[] = "12345";
constexpr cpp17::string_view kFitLiteral(kLiteral);
for (std::size_t i = 0; i < kFitLiteral.size(); ++i) {
EXPECT_EQ(kLiteral[i], kFitLiteral.at(i)) << "Array access returned wrong value.";
EXPECT_EQ(&kLiteral[i], &kFitLiteral.at(i))
<< "Array access returned value at different address.";
}
}
TEST(StringViewTest, AtThrowsExceptionWhenIndexIsOOR) {
ASSERT_THROW_OR_ABORT(
{
constexpr cpp17::string_view kFitLiteral("12345");
kFitLiteral.at(1000);
},
std::out_of_range);
}
// Even though we use a custom compare implementation, because we lack a constexpr compare
// function, we use this test to verify that the expectations are equivalent.
TEST(StringViewTest, CompareVerification) {
constexpr cpp17::string_view kStr1 = "1234";
// Same string
{
constexpr cpp17::string_view kStr2 = "1234";
constexpr cpp17::string_view kStr3 = "01234";
EXPECT_EQ(0, cpp17::string_view::traits_type::compare(kStr1.data(), kStr2.data(), 4));
EXPECT_EQ(0, kStr1.compare(kStr2));
EXPECT_EQ(0, kStr3.compare(1, kStr3.length() - 1, kStr2));
EXPECT_EQ(0, kStr1.compare(1, kStr1.length() - 2, kStr2, 1, kStr2.length() - 2));
EXPECT_EQ(0, kStr1.compare("1234"));
EXPECT_EQ(0, kStr1.compare(1, kStr1.length() - 1, "234"));
EXPECT_EQ(0, kStr1.compare(2, kStr1.length() - 2, "234", 1, 2));
}
// Same Length higher character
{
constexpr cpp17::string_view kStr2 = "1235";
EXPECT_LT(cpp17::string_view::traits_type::compare(kStr1.data(), kStr2.data(), 4), 0);
EXPECT_LT(kStr1.compare(kStr2), 0);
EXPECT_LT(kStr1.compare(0, kStr1.length(), kStr2), 0);
EXPECT_LT(kStr1.compare(1, kStr1.length() - 2, kStr2, 1, kStr2.length() - 1), 0);
EXPECT_LT(kStr1.compare("1235"), 0);
EXPECT_LT(kStr1.compare(1, kStr1.length() - 1, "235"), 0);
EXPECT_LT(kStr1.compare(1, kStr1.length() - 2, "1235", 1, 3), 0);
}
// Same Length lower character
{
constexpr cpp17::string_view kStr2 = "1232";
EXPECT_GT(cpp17::string_view::traits_type::compare(kStr1.data(), kStr2.data(), 4), 0);
EXPECT_GT(kStr1.compare(kStr2), 0);
EXPECT_GT(kStr2.compare(1, kStr2.length() - 1, kStr1), 0);
EXPECT_GT(kStr1.compare(1, kStr1.length() - 1, kStr2, 1, kStr2.length() - 1), 0);
EXPECT_GT(kStr1.compare("1232"), 0);
EXPECT_GT(kStr1.compare(1, kStr1.length() - 1, "232"), 0);
EXPECT_GT(kStr1.compare(1, kStr1.length() - 2, "22", 1, kStr2.length() - 2), 0);
}
// Greater Length
{
constexpr cpp17::string_view kStr2 = "12345";
constexpr cpp17::string_view kStr3 = "2345";
EXPECT_LT(kStr1.compare(kStr2), 0);
EXPECT_LT(kStr1.compare(1, kStr1.length() - 1, kStr3), 0);
EXPECT_LT(kStr1.compare(1, kStr1.length() - 1, kStr2, 1, kStr2.length() - 1), 0);
EXPECT_LT(kStr1.compare(kStr2.data()), 0);
EXPECT_LT(kStr1.compare(1, kStr1.length() - 1, kStr3.data()), 0);
EXPECT_LT(kStr1.compare(1, kStr1.length() - 1, kStr2.data(), 1, kStr2.length() - 1), 0);
}
// Shorter Length
{
constexpr cpp17::string_view kStr2 = "123";
constexpr cpp17::string_view kStr3 = "23";
EXPECT_GT(kStr1.compare(kStr2), 0);
EXPECT_GT(kStr1.compare(1, kStr1.length() - 1, kStr3), 0);
EXPECT_GT(kStr1.compare(1, kStr1.length() - 1, kStr2, 1, kStr2.length() - 1), 0);
EXPECT_GT(kStr1.compare(kStr2.data()), 0);
EXPECT_GT(kStr1.compare(1, kStr1.length() - 1, kStr3.data()), 0);
EXPECT_GT(kStr1.compare(1, kStr1.length() - 1, kStr2.data(), 1, kStr2.length() - 1), 0);
}
}
// Check that they calls are equivalent to what the standard expects.
TEST(StringViewTest, CompareOverloadCheck) {
constexpr cpp17::string_view kString1 = "123";
constexpr cpp17::string_view kString2 = "1234";
{
cpp17::string_view expected = kString1.substr(1, 2);
EXPECT_EQ(kString1.substr(1, 2).compare(expected), kString1.compare(1, 2, expected));
}
{
EXPECT_EQ(kString1.substr(1, 2).compare(kString2.substr(1, 2)),
kString1.compare(1, 2, kString2, 1, 2));
}
{ EXPECT_EQ(kString1.compare(cpp17::string_view("123")), kString1.compare("123")); }
{
EXPECT_EQ(kString1.substr(1, 2).compare(cpp17::string_view("123")),
kString1.compare(1, 2, "123"));
}
{
EXPECT_EQ(kString1.substr(1, 2).compare(cpp17::string_view("123")),
kString1.compare(1, 2, "123"));
}
}
TEST(StringViewTest, OperatorEq) {
constexpr cpp17::string_view kStrView = "Self1234";
EXPECT_EQ(kStrView, kStrView);
EXPECT_EQ(kStrView, cpp17::string_view("Self1234"));
EXPECT_EQ(kStrView, cpp17::string_view("Self12345").substr(0, kStrView.length()));
EXPECT_EQ(kStrView, "Self1234");
EXPECT_EQ("Self1234", kStrView);
}
TEST(StringViewTest, OperatorNe) {
constexpr cpp17::string_view kStrView = "Self1234";
EXPECT_NE(kStrView, cpp17::string_view());
EXPECT_NE(kStrView, cpp17::string_view("Self12345"));
EXPECT_NE(kStrView, "Self12345");
EXPECT_NE("Self12345", kStrView);
}
TEST(StringViewTest, OperatorLess) {
constexpr cpp17::string_view kStrView = "Self1234";
EXPECT_TRUE(kStrView < "Self12345");
EXPECT_TRUE("Self123" < kStrView);
EXPECT_TRUE(kStrView < cpp17::string_view("Self12345"));
}
TEST(StringViewTest, OperatorLessOrEq) {
constexpr cpp17::string_view kStrView = "Self1234";
EXPECT_TRUE(kStrView <= "Self12345");
EXPECT_TRUE("Self123" <= kStrView);
EXPECT_TRUE(kStrView <= cpp17::string_view("Self12345"));
EXPECT_TRUE(kStrView <= cpp17::string_view("Self1234"));
}
TEST(StringViewTest, OperatorGreater) {
constexpr cpp17::string_view kStrView = "Self1234";
EXPECT_TRUE(kStrView > "Self123");
EXPECT_TRUE("Self12345" > kStrView);
EXPECT_TRUE(kStrView > cpp17::string_view("Self123"));
}
TEST(StringViewTest, OperatorGreaterOrEq) {
constexpr cpp17::string_view kStrView = "Self1234";
EXPECT_TRUE(kStrView >= "Self123");
EXPECT_TRUE("Self12345" >= kStrView);
EXPECT_TRUE(kStrView >= cpp17::string_view("Self123"));
EXPECT_TRUE(kStrView >= cpp17::string_view("Self1234"));
}
TEST(StringViewTest, RemovePrefix) {
constexpr cpp17::string_view kPrefixWithSuffix = "PrefixSuffix";
cpp17::string_view str_view = kPrefixWithSuffix;
str_view.remove_prefix(6);
EXPECT_EQ(kPrefixWithSuffix.length() - 6, str_view.length());
auto no_suffix = kPrefixWithSuffix.substr(6, kPrefixWithSuffix.length() - 6);
EXPECT_EQ(no_suffix, str_view);
EXPECT_EQ("Suffix", str_view);
}
TEST(StringViewTest, RemoveSuffix) {
constexpr cpp17::string_view kPrefixWithSuffix = "PrefixSuffix";
cpp17::string_view str_view = kPrefixWithSuffix;
str_view.remove_suffix(6);
EXPECT_EQ(kPrefixWithSuffix.length() - 6, str_view.length());
auto no_suffix = kPrefixWithSuffix.substr(0, kPrefixWithSuffix.length() - 6);
EXPECT_EQ(no_suffix, str_view);
EXPECT_EQ("Prefix", str_view);
}
TEST(StringViewTest, SubstrNoArgsAreEqual) {
constexpr cpp17::string_view kLiteral = "12345";
EXPECT_EQ(kLiteral, kLiteral.substr());
}
TEST(StringViewTest, SubstrWithPosIsMatchesSubstring) {
constexpr cpp17::string_view kLiteral = "12345";
constexpr cpp17::string_view kExpectedLiteral = "345";
EXPECT_EQ(kExpectedLiteral, kLiteral.substr(2));
}
TEST(StringViewTest, SubstrWithPosAndCountIsMatchesSubstring) {
constexpr cpp17::string_view kLiteral = "12345";
constexpr cpp17::string_view kExpectedLiteral = "34";
EXPECT_EQ(kExpectedLiteral, kLiteral.substr(2, 2));
}
TEST(StringViewTest, Swap) {
cpp17::string_view str_1 = "12345";
cpp17::string_view str_2 = "34";
str_1.swap(str_2);
EXPECT_EQ("34", str_1);
EXPECT_EQ("12345", str_2);
}
TEST(StringViewTest, Copy) {
constexpr cpp17::string_view kBase = "Base";
constexpr cpp17::string_view::size_type kSize = 2;
cpp17::string_view::value_type dest[kSize + 1] = {'\0'};
cpp17::string_view::value_type dest_traits[kSize + 1] = {'\0'};
EXPECT_EQ(kSize, kBase.copy(dest, kSize, 0));
EXPECT_EQ(dest_traits, cpp17::string_view::traits_type::copy(dest_traits, kBase.data(), kSize));
EXPECT_STREQ(dest_traits, dest);
}
TEST(StringViewTest, CopyThrowsExceptionOnOOR) {
ASSERT_THROW_OR_ABORT(
{
constexpr cpp17::string_view v_str = "Base";
cpp17::string_view::value_type dest[v_str.length()] = {};
memset(dest, '\0', v_str.length());
v_str.copy(dest, v_str.length(), v_str.length() + 1);
},
std::out_of_range);
}
TEST(StringViewTest, SubstrThrowsExceptionOnOOR) {
ASSERT_THROW_OR_ABORT(
{
constexpr cpp17::string_view v_str = "Base";
[[gnu::unused]] auto s_str = v_str.substr(v_str.length() + 1);
},
std::out_of_range);
}
TEST(StringViewTest, MaxSizeIsMaxAddressableSize) {
cpp17::string_view str_view("12345");
EXPECT_EQ(std::numeric_limits<cpp17::string_view::size_type>::max(), str_view.max_size());
}
TEST(StringViewTest, FindReturnsFirstCharTypeMatch) {
constexpr cpp17::string_view kString = "12345678901234567890";
EXPECT_EQ(0u, kString.find('1'));
EXPECT_EQ(1u, kString.find('2'));
EXPECT_EQ(2u, kString.find('3'));
EXPECT_EQ(3u, kString.find('4'));
EXPECT_EQ(4u, kString.find('5'));
EXPECT_EQ(5u, kString.find('6'));
EXPECT_EQ(6u, kString.find('7'));
EXPECT_EQ(7u, kString.find('8'));
EXPECT_EQ(8u, kString.find('9'));
EXPECT_EQ(9u, kString.find('0'));
}
TEST(StringViewTest, FindWithPosReturnsFirstCharTypeMatch) {
constexpr cpp17::string_view kString = "12345678901234567890";
EXPECT_EQ(10u, kString.find('1', 10));
EXPECT_EQ(11u, kString.find('2', 10));
EXPECT_EQ(12u, kString.find('3', 10));
EXPECT_EQ(13u, kString.find('4', 10));
EXPECT_EQ(14u, kString.find('5', 10));
EXPECT_EQ(15u, kString.find('6', 10));
EXPECT_EQ(16u, kString.find('7', 10));
EXPECT_EQ(17u, kString.find('8', 10));
EXPECT_EQ(18u, kString.find('9', 10));
EXPECT_EQ(19u, kString.find('0', 10));
}
TEST(StringViewTest, FindReturnsNposWhenNoCharTypeMatch) {
constexpr cpp17::string_view kString = "123456789123456789";
EXPECT_EQ(cpp17::string_view::npos, kString.find('0'));
}
TEST(StringViewTest, FindReturnsFirstMatch) {
constexpr cpp17::string_view kString = "12345678901234567890";
EXPECT_EQ(0u, kString.find(""));
EXPECT_EQ(0u, kString.find("12"));
EXPECT_EQ(1u, kString.find("23"));
EXPECT_EQ(2u, kString.find("34"));
EXPECT_EQ(3u, kString.find("45"));
EXPECT_EQ(4u, kString.find("56"));
EXPECT_EQ(5u, kString.find("67"));
EXPECT_EQ(6u, kString.find("78"));
EXPECT_EQ(7u, kString.find("89"));
EXPECT_EQ(8u, kString.find("90"));
EXPECT_EQ(9u, kString.find("01"));
EXPECT_EQ(9u, kString.find("01234"));
}
TEST(StringViewTest, FindWithPosReturnsFirstMatch) {
constexpr cpp17::string_view kString = "12345678901234567890";
EXPECT_EQ(10u, kString.find("", 10));
EXPECT_EQ(10u, kString.find("1", 10));
EXPECT_EQ(11u, kString.find("2", 10));
EXPECT_EQ(12u, kString.find("3", 10));
EXPECT_EQ(13u, kString.find("4", 10));
EXPECT_EQ(14u, kString.find("5", 10));
EXPECT_EQ(15u, kString.find("6", 10));
EXPECT_EQ(16u, kString.find("7", 10));
EXPECT_EQ(17u, kString.find("8", 10));
EXPECT_EQ(18u, kString.find("9", 10));
EXPECT_EQ(19u, kString.find("0", 10));
// String of size > 1.
EXPECT_EQ(13u, kString.find("456", 10));
}
TEST(StringViewTest, FindReturnsNposWhenNoMatch) {
constexpr cpp17::string_view kString = "12345678901234567890";
// String of size > 1.
EXPECT_EQ(cpp17::string_view::npos, kString.find("A"));
EXPECT_EQ(cpp17::string_view::npos, kString.find("02"));
EXPECT_EQ(cpp17::string_view::npos, kString.find("42321"));
}
TEST(StringViewTest, FindReturnsNposWhenNeedleIsBiggerThanHaystack) {
constexpr cpp17::string_view kString = "123";
// String of size > 1.
EXPECT_EQ(cpp17::string_view::npos, kString.find("1234"));
}
TEST(StringViewTest, RfindReturnsFirstCharTypeMatch) {
constexpr cpp17::string_view kString = "12345678901234567890";
EXPECT_EQ(10u, kString.rfind('1'));
EXPECT_EQ(11u, kString.rfind('2'));
EXPECT_EQ(12u, kString.rfind('3'));
EXPECT_EQ(13u, kString.rfind('4'));
EXPECT_EQ(14u, kString.rfind('5'));
EXPECT_EQ(15u, kString.rfind('6'));
EXPECT_EQ(16u, kString.rfind('7'));
EXPECT_EQ(17u, kString.rfind('8'));
EXPECT_EQ(18u, kString.rfind('9'));
EXPECT_EQ(19u, kString.rfind('0'));
}
TEST(StringViewTest, RfindWithPosReturnsFirstCharTypeMatch) {
constexpr cpp17::string_view kString = "12345678901234567890";
EXPECT_EQ(10u, kString.rfind('1', 10));
EXPECT_EQ(1u, kString.rfind('2', 10));
EXPECT_EQ(2u, kString.rfind('3', 10));
EXPECT_EQ(3u, kString.rfind('4', 10));
EXPECT_EQ(4u, kString.rfind('5', 10));
EXPECT_EQ(5u, kString.rfind('6', 10));
EXPECT_EQ(6u, kString.rfind('7', 10));
EXPECT_EQ(7u, kString.rfind('8', 10));
EXPECT_EQ(8u, kString.rfind('9', 10));
EXPECT_EQ(9u, kString.rfind('0', 10));
}
TEST(StringViewTest, RfindReturnsNposWhenNoCharTypeMatch) {
constexpr cpp17::string_view kString = "123456789123456789";
EXPECT_EQ(cpp17::string_view::npos, kString.rfind('0'));
}
TEST(StringViewTest, RfindReturnsFirstMatch) {
constexpr cpp17::string_view kString = "12345678901234567890";
EXPECT_EQ(20u, kString.rfind(""));
EXPECT_EQ(10u, kString.rfind("12"));
EXPECT_EQ(11u, kString.rfind("23"));
EXPECT_EQ(12u, kString.rfind("34"));
EXPECT_EQ(13u, kString.rfind("45"));
EXPECT_EQ(14u, kString.rfind("56"));
EXPECT_EQ(15u, kString.rfind("67"));
EXPECT_EQ(16u, kString.rfind("78"));
EXPECT_EQ(17u, kString.rfind("89"));
EXPECT_EQ(18u, kString.rfind("90"));
EXPECT_EQ(9u, kString.rfind("01"));
EXPECT_EQ(9u, kString.rfind("01234"));
}
TEST(StringViewTest, RfindWithPosReturnsFirstMatch) {
constexpr cpp17::string_view kString = "12345678901234567890";
EXPECT_EQ(10u, kString.rfind("", 10));
EXPECT_EQ(10u, kString.rfind("1", 10));
EXPECT_EQ(1u, kString.rfind("2", 10));
EXPECT_EQ(2u, kString.rfind("3", 10));
EXPECT_EQ(3u, kString.rfind("4", 10));
EXPECT_EQ(4u, kString.rfind("5", 10));
EXPECT_EQ(5u, kString.rfind("6", 10));
EXPECT_EQ(6u, kString.rfind("7", 10));
EXPECT_EQ(7u, kString.rfind("8", 10));
EXPECT_EQ(8u, kString.rfind("9", 10));
EXPECT_EQ(9u, kString.rfind("0", 10));
// String of size > 1.
EXPECT_EQ(3u, kString.rfind("456", 10));
}
TEST(StringViewTest, RfindReturnsNposWhenNoMatch) {
constexpr cpp17::string_view kString = "12345678901234567890";
EXPECT_EQ(cpp17::string_view::npos, kString.rfind("A"));
EXPECT_EQ(cpp17::string_view::npos, kString.rfind("02"));
EXPECT_EQ(cpp17::string_view::npos, kString.rfind("42321"));
EXPECT_EQ(cpp17::string_view::npos, kString.rfind('A'));
}
TEST(StringViewTest, RfindReturnsNposWhenNeedleIsBiggerThanHaystack) {
constexpr cpp17::string_view kString = "123";
// String of size > 1.
EXPECT_EQ(cpp17::string_view::npos, kString.rfind("1234"));
EXPECT_EQ(cpp17::string_view::npos, cpp17::string_view().find('1'));
}
TEST(StringViewTest, FindFirstOfReturnsFirstMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234";
constexpr cpp17::string_view kMatchers = "123";
// Verify that order of chartacters in |s| does not change first match.
EXPECT_EQ(5u, kString.find_first_of("321"));
EXPECT_EQ(5u, kString.find_first_of("123"));
EXPECT_EQ(5u, kString.find_first_of("231"));
EXPECT_EQ(5u, kString.find_first_of("213"));
EXPECT_EQ(5u, kString.find_first_of(kMatchers));
EXPECT_EQ(6u, kString.find_first_of('2'));
}
TEST(StringViewTest, FindFirstOfWithPosReturnsFirstMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234";
constexpr cpp17::string_view kMatchers = "123";
// Verify that order of chartacters in |s| does not change first match.
EXPECT_EQ(14u, kString.find_first_of("321", 9));
EXPECT_EQ(14u, kString.find_first_of("123", 9));
EXPECT_EQ(14u, kString.find_first_of("231", 9));
EXPECT_EQ(14u, kString.find_first_of("213", 9));
EXPECT_EQ(14u, kString.find_first_of(kMatchers, 9));
EXPECT_EQ(5u, kString.find_first_of('1'));
}
TEST(StringViewTest, FindFirstOfWithPosAndCountReturnsFirstMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234";
// Verify that order of chartacters in |s| does not change first match.
EXPECT_EQ(14u, kString.find_first_of("123", 9, 1));
EXPECT_EQ(15u, kString.find_first_of("231", 9, 1));
EXPECT_EQ(15u, kString.find_first_of("213", 9, 1));
EXPECT_EQ(16u, kString.find_first_of("321", 9, 1));
}
TEST(StringViewTest, FindFirstOfReturnsNposWhenNoMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234";
// Verify that order of chartacters in |s| does not change first match.
EXPECT_EQ(cpp17::string_view::npos, kString.find_first_of("GHIJK"));
EXPECT_EQ(cpp17::string_view::npos, kString.find_first_of("G"));
EXPECT_EQ(cpp17::string_view::npos, kString.find_first_of('G'));
}
TEST(StringViewTest, FindLastOfReturnsLastMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234F";
constexpr cpp17::string_view kMatchers = "123";
// Verify that order of chartacters in |s| does not change last match.
EXPECT_EQ(16u, kString.find_last_of("321"));
EXPECT_EQ(16u, kString.find_last_of("123"));
EXPECT_EQ(16u, kString.find_last_of("231"));
EXPECT_EQ(16u, kString.find_last_of("213"));
EXPECT_EQ(18u, kString.find_last_of("F"));
EXPECT_EQ(16u, kString.find_last_of(kMatchers));
EXPECT_EQ(15u, kString.find_last_of('2'));
EXPECT_EQ(18u, kString.find_last_of('F'));
}
TEST(StringViewTest, FindLastOfWithPosReturnsLastMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234F";
constexpr cpp17::string_view kMatchers = "123";
// Verify that order of chartacters in |s| does not change last match.
EXPECT_EQ(7u, kString.find_last_of("321", 9));
EXPECT_EQ(7u, kString.find_last_of("123", 9));
EXPECT_EQ(7u, kString.find_last_of("231", 9));
EXPECT_EQ(7u, kString.find_last_of("213", 9));
EXPECT_EQ(0u, kString.find_last_of("A", 0));
EXPECT_EQ(18u, kString.find_last_of("F", kString.length() + 1));
EXPECT_EQ(7u, kString.find_last_of(kMatchers, 9));
EXPECT_EQ(5u, kString.find_last_of('1', 9));
}
TEST(StringViewTest, FindLastOfWithPosAndCountReturnsLastMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234";
// Verify that order of chartacters in |s| does not change last match.
EXPECT_EQ(5u, kString.find_last_of("123", 9, 1));
EXPECT_EQ(6u, kString.find_last_of("231", 9, 1));
EXPECT_EQ(6u, kString.find_last_of("213", 9, 1));
EXPECT_EQ(7u, kString.find_last_of("321", 9, 1));
}
TEST(StringViewTest, FindLastOfReturnsNposWhenNoMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234";
// Verify that order of chartacters in |s| does not change last match.
EXPECT_EQ(cpp17::string_view::npos, kString.find_last_of("GHIJK"));
EXPECT_EQ(cpp17::string_view::npos, kString.find_last_of("G"));
EXPECT_EQ(cpp17::string_view::npos, kString.find_last_of('G'));
EXPECT_EQ(cpp17::string_view::npos, kString.find_last_of('H', 0));
}
TEST(StringViewTest, FindFirstNotOfReturnsFirstNonMatch) {
constexpr cpp17::string_view kString = "123ABC123";
constexpr cpp17::string_view kMatchers = "123";
// Verify that order of chartacters in |s| does not change first match.
EXPECT_EQ(0u, kString.find_first_not_of(""));
EXPECT_EQ(3u, kString.find_first_not_of("321"));
EXPECT_EQ(3u, kString.find_first_not_of("123"));
EXPECT_EQ(3u, kString.find_first_not_of("231"));
EXPECT_EQ(3u, kString.find_first_not_of("213"));
EXPECT_EQ(3u, kString.find_first_not_of(kMatchers));
EXPECT_EQ(1u, kString.find_first_not_of('1'));
}
TEST(StringViewTest, FindFirstNotOfWithPosReturnsFirstNonMatch) {
constexpr cpp17::string_view kString = "123ABC123A";
constexpr cpp17::string_view kMatchers = "123";
// Verify that order of chartacters in |s| does not change first match.
EXPECT_EQ(6u, kString.find_first_not_of("", 6));
EXPECT_EQ(9u, kString.find_first_not_of("321", 6));
EXPECT_EQ(9u, kString.find_first_not_of("123", 6));
EXPECT_EQ(9u, kString.find_first_not_of("231", 6));
EXPECT_EQ(9u, kString.find_first_not_of("213", 6));
EXPECT_EQ(9u, kString.find_first_not_of(kMatchers, 9));
EXPECT_EQ(7u, kString.find_first_not_of('1', 6));
}
TEST(StringViewTest, FindFirstNotOfWithPosAndCountReturnsFirstNonMatch) {
constexpr cpp17::string_view kString = "123ABC123A";
// Verify that order of chartacters in |s| does not change first match.
EXPECT_EQ(7u, kString.find_first_not_of("123", 6, 1));
EXPECT_EQ(6u, kString.find_first_not_of("231", 6, 1));
EXPECT_EQ(6u, kString.find_first_not_of("213", 6, 1));
EXPECT_EQ(6u, kString.find_first_not_of("321", 6, 1));
}
TEST(StringViewTest, FindFirstNotOfReturnsNposWhenNoMatch) {
constexpr cpp17::string_view kString = "GGGGGGGGGGGGG";
// Verify that order of chartacters in |s| does not change first match.
EXPECT_EQ(cpp17::string_view::npos, kString.find_first_not_of("ABCG"));
EXPECT_EQ(cpp17::string_view::npos, kString.find_first_not_of("G"));
EXPECT_EQ(cpp17::string_view::npos, kString.find_first_not_of('G'));
}
TEST(StringViewTest, FindLastNotOfReturnsLastMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234";
constexpr cpp17::string_view kMatchers = "1234";
// Verify that order of chartacters in |s| does not change last_not match.
EXPECT_EQ(13u, kString.find_last_not_of("3214"));
EXPECT_EQ(13u, kString.find_last_not_of("1234"));
EXPECT_EQ(13u, kString.find_last_not_of("2314"));
EXPECT_EQ(13u, kString.find_last_not_of("2134"));
EXPECT_EQ(13u, kString.find_last_not_of(kMatchers));
EXPECT_EQ(16u, kString.find_last_not_of('4'));
}
TEST(StringViewTest, FindLastNotOfWithPosReturnsLastMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234";
constexpr cpp17::string_view kMatchers = "1234";
// Verify that order of chartacters in |s| does not change last_not match.
EXPECT_EQ(4u, kString.find_last_not_of("3214", 8));
EXPECT_EQ(4u, kString.find_last_not_of("1234", 8));
EXPECT_EQ(4u, kString.find_last_not_of("2314", 8));
EXPECT_EQ(4u, kString.find_last_not_of("2134", 8));
EXPECT_EQ(4u, kString.find_last_not_of(kMatchers, 8));
EXPECT_EQ(7u, kString.find_last_not_of('4', 8));
}
TEST(StringViewTest, FindLastNotOfWithPosAndCountReturnsLastMatch) {
constexpr cpp17::string_view kString = "ABCDE1234ABCDE1234";
// Verify that order of chartacters in |s| does not change last_not match.
EXPECT_EQ(8u, kString.find_last_not_of("1234", 8, 1));
EXPECT_EQ(8u, kString.find_last_not_of("2314", 8, 2));
EXPECT_EQ(5u, kString.find_last_not_of("4321", 8, 3));
EXPECT_EQ(4u, kString.find_last_not_of("3214", 8, 4));
}
TEST(StringViewTest, FindLastNotOfReturnsNposWhenNoMatch) {
constexpr cpp17::string_view kString = "GGGGGGG";
// Verify that order of chartacters in |s| does not change last_not match.
EXPECT_EQ(cpp17::string_view::npos, kString.find_last_not_of("GHIJK"));
EXPECT_EQ(cpp17::string_view::npos, kString.find_last_not_of("G"));
EXPECT_EQ(cpp17::string_view::npos, kString.find_last_not_of('G'));
}
TEST(StringViewTest, StartsWith) {
constexpr cpp17::string_view kString = "ABCdef";
// By convention, a string view always "starts" with an empty or NUL string.
EXPECT_TRUE(cpp20::starts_with(kString, cpp17::string_view{}));
EXPECT_TRUE(cpp20::starts_with(kString, ""));
EXPECT_TRUE(cpp20::starts_with(kString, cpp17::string_view{""}));
EXPECT_TRUE(cpp20::starts_with(kString, std::string{""}));
EXPECT_TRUE(cpp20::starts_with(kString, 'A'));
EXPECT_FALSE(cpp20::starts_with(kString, 'B'));
EXPECT_FALSE(cpp20::starts_with(kString, 'f'));
EXPECT_TRUE(cpp20::starts_with(kString, "A"));
EXPECT_TRUE(cpp20::starts_with(kString, cpp17::string_view{"A"}));
EXPECT_TRUE(cpp20::starts_with(kString, std::string{"A"}));
EXPECT_TRUE(cpp20::starts_with(kString, "AB"));
EXPECT_TRUE(cpp20::starts_with(kString, cpp17::string_view{"AB"}));
EXPECT_TRUE(cpp20::starts_with(kString, "ABC"));
EXPECT_TRUE(cpp20::starts_with(kString, cpp17::string_view{"ABC"}));
EXPECT_TRUE(cpp20::starts_with(kString, "ABCd"));
EXPECT_TRUE(cpp20::starts_with(kString, cpp17::string_view{"ABCd"}));
EXPECT_TRUE(cpp20::starts_with(kString, "ABCde"));
EXPECT_TRUE(cpp20::starts_with(kString, cpp17::string_view{"ABCde"}));
// A string view should start with itself.
EXPECT_TRUE(cpp20::starts_with(kString, "ABCdef"));
EXPECT_TRUE(cpp20::starts_with(kString, kString));
EXPECT_TRUE(cpp20::starts_with(kString, "ABCdef\0"));
EXPECT_TRUE(cpp20::starts_with(kString, cpp17::string_view{"ABCdef\0"}));
EXPECT_FALSE(cpp20::starts_with(kString, "rAnDoM"));
EXPECT_FALSE(cpp20::starts_with(kString, cpp17::string_view{"rAnDoM"}));
EXPECT_FALSE(cpp20::starts_with(kString, "longer than kString"));
EXPECT_FALSE(cpp20::starts_with(kString, cpp17::string_view{"longer than kString"}));
}
TEST(StringViewTest, EndsWith) {
constexpr cpp17::string_view kString = "ABCdef";
// By convention, a string view always "ends" with an empty or NUL string.
EXPECT_TRUE(cpp20::ends_with(kString, cpp17::string_view{}));
EXPECT_TRUE(cpp20::ends_with(kString, ""));
EXPECT_TRUE(cpp20::ends_with(kString, cpp17::string_view{""}));
EXPECT_TRUE(cpp20::ends_with(kString, std::string{""}));
EXPECT_TRUE(cpp20::ends_with(kString, 'f'));
EXPECT_FALSE(cpp20::ends_with(kString, 'e'));
EXPECT_FALSE(cpp20::ends_with(kString, 'A'));
EXPECT_TRUE(cpp20::ends_with(kString, "f"));
EXPECT_TRUE(cpp20::ends_with(kString, cpp17::string_view{"f"}));
EXPECT_TRUE(cpp20::ends_with(kString, std::string{"f"}));
EXPECT_TRUE(cpp20::ends_with(kString, "ef"));
EXPECT_TRUE(cpp20::ends_with(kString, cpp17::string_view{"ef"}));
EXPECT_TRUE(cpp20::ends_with(kString, "def"));
EXPECT_TRUE(cpp20::ends_with(kString, cpp17::string_view{"def"}));
EXPECT_TRUE(cpp20::ends_with(kString, "Cdef"));
EXPECT_TRUE(cpp20::ends_with(kString, cpp17::string_view{"Cdef"}));
EXPECT_TRUE(cpp20::ends_with(kString, "BCdef"));
EXPECT_TRUE(cpp20::ends_with(kString, cpp17::string_view{"BCdef"}));
// A string view should end with itself.
EXPECT_TRUE(cpp20::ends_with(kString, "ABCdef"));
EXPECT_TRUE(cpp20::ends_with(kString, kString));
EXPECT_TRUE(cpp20::ends_with(kString, "ABCdef\0"));
EXPECT_TRUE(cpp20::ends_with(kString, cpp17::string_view{"ABCdef\0"}));
EXPECT_FALSE(cpp20::ends_with(kString, "rAnDoM"));
EXPECT_FALSE(cpp20::ends_with(kString, cpp17::string_view{"rAnDoM"}));
EXPECT_FALSE(cpp20::ends_with(kString, "longer than kString"));
EXPECT_FALSE(cpp20::ends_with(kString, cpp17::string_view{"longer than kString"}));
}
TEST(StringViewTest, HashVaidation) {
constexpr cpp17::string_view kStringView1 = "1234";
constexpr cpp17::string_view kStringView2 = "123456";
const std::string kString = "123";
// Hash of the full view matches the hash of an equivalent string.
EXPECT_EQ(std::hash<std::string>()(std::string(kStringView1.data())),
std::hash<cpp17::string_view>()(kStringView1));
EXPECT_EQ(std::hash<std::string>()(std::string(kStringView2.data())),
std::hash<cpp17::string_view>()(kStringView2));
// Hash uses the view, not the full string.
EXPECT_EQ(std::hash<cpp17::string_view>()(kStringView1),
std::hash<cpp17::string_view>()(kStringView2.substr(0, kStringView1.length())));
// Hash matches the hash for a string with the same content.
EXPECT_EQ(std::hash<std::string>()(kString),
std::hash<cpp17::string_view>()(kStringView2.substr(0, kString.length())));
EXPECT_EQ(std::hash<std::string>()(kString),
std::hash<cpp17::string_view>()(kStringView1.substr(0, kString.length())));
// If the hash of the contents are different in the default hash of the string, they should be
// different in the specialized hash. We should make no assumptions on whether the values will hit
// the same bucket or not.
EXPECT_EQ(std::hash<std::string>()(std::string(kStringView1.data())) !=
std::hash<std::string>()(std::string(kStringView2.data())),
std::hash<cpp17::string_view>()(kStringView1) !=
std::hash<cpp17::string_view>()(kStringView2));
}
TEST(StringViewTest, OutputStreamOperatorFitsWithinWidth) {
constexpr cpp17::string_view kStringView = "1234";
std::ostringstream oss;
oss.width(kStringView.length());
oss << kStringView;
EXPECT_EQ(oss.str(), kStringView);
}
TEST(StringViewTest, OutputStreamOperatorExpandsToStringViewWidth) {
constexpr cpp17::string_view kStringView = "1234";
std::ostringstream oss;
oss.width(kStringView.length() - 1);
oss << kStringView;
EXPECT_EQ(oss.str(), kStringView);
EXPECT_EQ(oss.width(), 0);
}
TEST(StringViewTest, OutputStreamOperatorFillsExtraSpaceToTheRight) {
constexpr cpp17::string_view kStringView = "1234";
constexpr cpp17::string_view kExpected = "000001234";
std::ostringstream oss;
oss.fill('0');
oss.width(kExpected.length());
oss << kStringView;
EXPECT_EQ(oss.str(), kExpected);
}
TEST(StringViewTest, OutputStreamOperatorFillsExtraSpaceToTheLeft) {
constexpr cpp17::string_view kStringView = "1234";
constexpr cpp17::string_view kExpected = "123400000";
std::ostringstream oss;
oss.fill('0');
oss.setf(std::ios_base::left);
oss.width(kExpected.length());
oss << kStringView;
EXPECT_EQ(oss.str(), kExpected);
}
TEST(StringViewTest, OutputStreamOperatorResetsWidthToZero) {
constexpr cpp17::string_view kStringView = "1234";
std::ostringstream oss;
oss.fill('0');
oss.width(10);
oss << kStringView;
EXPECT_EQ(0, oss.width());
}
TEST(StringViewTest, BracketOperatorAssersOnUB) {
DEBUG_ASSERT_DEATH({
constexpr cpp17::string_view kView = "1234";
kView[kView.size()];
});
}
TEST(StringViewTest, RemovePrefixAssertsOnUB) {
DEBUG_ASSERT_DEATH({
cpp17::string_view kView = "1234";
kView.remove_prefix(kView.size() + 1);
});
}
TEST(StringViewTest, RemoveSuffixAssertOnUB) {
DEBUG_ASSERT_DEATH({
cpp17::string_view kView = "1234";
kView.remove_suffix(kView.size() + 1);
});
}
} // namespace