| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/strings/cstring_view.h" |
| |
| #include <concepts> |
| #include <limits> |
| #include <sstream> |
| #include <type_traits> |
| |
| #include "base/containers/span.h" |
| #include "base/debug/alias.h" |
| #include "base/strings/strcat.h" |
| #include "base/test/gtest_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace base { |
| namespace { |
| |
| static_assert(std::is_default_constructible_v<cstring_view>); |
| static_assert(std::is_trivially_copy_constructible_v<cstring_view>); |
| static_assert(std::is_trivially_copy_assignable_v<cstring_view>); |
| static_assert(std::is_trivially_move_constructible_v<cstring_view>); |
| static_assert(std::is_trivially_move_assignable_v<cstring_view>); |
| static_assert(std::is_trivially_destructible_v<cstring_view>); |
| |
| static_assert(std::ranges::contiguous_range<cstring_view>); |
| static_assert(std::ranges::borrowed_range<cstring_view>); |
| |
| // The view is the size of 2 pointers (technically, pointer and address). |
| static_assert(sizeof(cstring_view) == sizeof(uintptr_t) + sizeof(size_t)); |
| |
| static_assert(cstring_view::npos == std::string_view::npos); |
| static_assert(u16cstring_view::npos == std::u16string_view::npos); |
| static_assert(u16cstring_view::npos == std::u32string_view::npos); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view::npos == std::wstring_view::npos); |
| #endif |
| |
| TEST(CStringViewTest, DefaultConstructed) { |
| constexpr auto c = cstring_view(); |
| static_assert(std::same_as<decltype(c), const cstring_view>); |
| static_assert(c.size() == 0u); |
| static_assert(c[c.size()] == '\0'); |
| } |
| |
| TEST(CStringViewTest, LiteralConstructed) { |
| constexpr auto empty = cstring_view(""); |
| constexpr auto stuff = cstring_view("stuff"); |
| constexpr auto other = cstring_view("other"); |
| static_assert(std::same_as<decltype(empty), const cstring_view>); |
| static_assert(std::same_as<decltype(stuff), const cstring_view>); |
| static_assert(std::same_as<decltype(other), const cstring_view>); |
| |
| static_assert(empty.size() == 0u); |
| static_assert(stuff.size() == 5u); |
| static_assert(other.size() == 5u); |
| |
| static_assert(empty[empty.size()] == '\0'); |
| static_assert(stuff[stuff.size()] == '\0'); |
| static_assert(other[other.size()] == '\0'); |
| |
| // Implicit construction. |
| { |
| cstring_view s = "stuff"; |
| EXPECT_EQ(s, cstring_view("stuff")); |
| } |
| } |
| |
| TEST(CStringViewTest, PointerSizeConstructed) { |
| constexpr const char* c_empty = ""; |
| constexpr auto empty = UNSAFE_BUFFERS(cstring_view(c_empty, 0u)); |
| static_assert(std::same_as<const cstring_view, decltype(empty)>); |
| EXPECT_EQ(empty.data(), c_empty); |
| EXPECT_EQ(empty.size(), 0u); |
| |
| constexpr const char* c_stuff = "stuff"; |
| constexpr auto stuff = UNSAFE_BUFFERS(cstring_view(c_stuff, 5u)); |
| static_assert(std::same_as<const cstring_view, decltype(stuff)>); |
| EXPECT_EQ(stuff.data(), c_stuff); |
| EXPECT_EQ(stuff.size(), 5u); |
| } |
| |
| TEST(CStringViewTest, StringConstructed) { |
| std::string empty; |
| { |
| auto c = cstring_view(empty); |
| EXPECT_EQ(c.size(), 0u); |
| } |
| std::string stuff = "stuff"; |
| { |
| auto c = cstring_view(stuff); |
| EXPECT_EQ(c.c_str(), stuff.c_str()); |
| EXPECT_EQ(c.size(), 5u); |
| } |
| std::u16string stuff16 = u"stuff"; |
| { |
| auto c = u16cstring_view(stuff16); |
| EXPECT_EQ(c.c_str(), stuff16.c_str()); |
| EXPECT_EQ(c.size(), 5u); |
| } |
| std::u32string stuff32 = U"stuff"; |
| { |
| auto c = u32cstring_view(stuff32); |
| EXPECT_EQ(c.c_str(), stuff32.c_str()); |
| EXPECT_EQ(c.size(), 5u); |
| } |
| #if BUILDFLAG(IS_WIN) |
| std::wstring stuffw = L"stuff"; |
| { |
| auto c = wcstring_view(stuffw); |
| EXPECT_EQ(c.c_str(), stuffw.c_str()); |
| EXPECT_EQ(c.size(), 5u); |
| } |
| #endif |
| |
| // Implicit construction. |
| { |
| auto s = std::string("stuff"); |
| cstring_view v = s; |
| EXPECT_EQ(v, cstring_view("stuff")); |
| } |
| } |
| |
| TEST(CStringViewTest, Equality) { |
| constexpr auto stuff = cstring_view("stuff"); |
| |
| static_assert(stuff != cstring_view()); |
| static_assert(stuff == cstring_view("stuff")); |
| static_assert(stuff != cstring_view("other")); |
| |
| // Implicit conversion to cstring_view from literal in comparison. |
| static_assert(stuff == "stuff"); |
| } |
| |
| TEST(CStringViewTest, Ordering) { |
| constexpr auto stuff = cstring_view("stuff"); |
| |
| static_assert(stuff <=> stuff == std::weak_ordering::equivalent); |
| static_assert(stuff <=> cstring_view() == std::weak_ordering::greater); |
| static_assert(stuff <=> cstring_view("stuff") == |
| std::weak_ordering::equivalent); |
| static_assert(stuff <=> cstring_view("zz") == std::weak_ordering::less); |
| |
| // Implicit conversion to cstring_view from literal in ordering compare. |
| static_assert(stuff <=> "stuff" == std::weak_ordering::equivalent); |
| } |
| |
| TEST(CStringViewTest, Iterate) { |
| constexpr auto def = cstring_view(); |
| static_assert(def.begin() == def.end()); |
| static_assert(def.cbegin() == def.cend()); |
| |
| constexpr auto stuff = cstring_view("stuff"); |
| static_assert(stuff.begin() != stuff.end()); |
| static_assert(stuff.cbegin() != stuff.cend()); |
| static_assert(std::same_as<const char&, decltype(*stuff.begin())>); |
| |
| { |
| size_t i = 0u; |
| for (auto& c : stuff) { |
| static_assert(std::same_as<const char&, decltype(c)>); |
| EXPECT_EQ(&c, &stuff[i]); |
| ++i; |
| } |
| EXPECT_EQ(i, 5u); |
| } |
| } |
| |
| TEST(CStringViewTest, IterateReverse) { |
| constexpr auto def = cstring_view(); |
| static_assert(def.rbegin() == def.rend()); |
| static_assert(def.rcbegin() == def.rcend()); |
| |
| constexpr auto stuff = cstring_view("stuff"); |
| static_assert(stuff.rbegin() != stuff.rend()); |
| static_assert(stuff.rcbegin() != stuff.rcend()); |
| static_assert(std::same_as<const char&, decltype(*stuff.rbegin())>); |
| |
| { |
| size_t i = 0u; |
| for (auto it = stuff.rbegin(); it != stuff.rend(); ++it) { |
| static_assert(std::same_as<const char&, decltype(*it)>); |
| EXPECT_EQ(&*it, &stuff[4u - i]); |
| ++i; |
| } |
| EXPECT_EQ(i, 5u); |
| } |
| } |
| |
| TEST(CStringViewDeathTest, IterateBoundsChecked) { |
| auto use = [](auto x) { base::debug::Alias(&x); }; |
| |
| constexpr auto stuff = cstring_view("stuff"); |
| |
| // The NUL terminator is out of bounds for iterating (checked by indexing into |
| // the iterator) since it's not included in the range that the iterator walks |
| // (but is in bounds for indexing on the view). |
| BASE_EXPECT_DEATH(use(*stuff.end()), ""); // Can't deref end. |
| BASE_EXPECT_DEATH(use(stuff.begin()[5]), ""); // Can't index end. |
| BASE_EXPECT_DEATH(use(stuff.begin() + 6), ""); // Can't move past end. |
| BASE_EXPECT_DEATH(use(stuff.begin() - 1), ""); // Can't move past begin. |
| |
| BASE_EXPECT_DEATH(use(*stuff.rend()), ""); |
| BASE_EXPECT_DEATH(use(stuff.rbegin()[5]), ""); |
| BASE_EXPECT_DEATH(use(stuff.rbegin() + 6), ""); |
| BASE_EXPECT_DEATH(use(stuff.rbegin() - 1), ""); |
| } |
| |
| TEST(CStringViewTest, Index) { |
| constexpr auto empty = cstring_view(); |
| static_assert(empty[0u] == '\0'); |
| |
| static_assert(empty.at(0u) == '\0'); |
| |
| constexpr auto stuff = cstring_view("stuff"); |
| static_assert(stuff[0u] == 's'); |
| static_assert(&stuff[0u] == stuff.data()); |
| static_assert(stuff[5u] == '\0'); |
| static_assert(&stuff[5u] == UNSAFE_BUFFERS(stuff.data() + 5u)); |
| |
| static_assert(stuff.at(0u) == 's'); |
| static_assert(&stuff.at(0u) == stuff.data()); |
| static_assert(stuff.at(5u) == '\0'); |
| static_assert(&stuff.at(5u) == UNSAFE_BUFFERS(stuff.data() + 5u)); |
| } |
| |
| TEST(CStringViewDeathTest, IndexChecked) { |
| auto use = [](auto x) { base::debug::Alias(&x); }; |
| |
| constexpr auto empty = cstring_view(); |
| BASE_EXPECT_DEATH(use(empty[1u]), ""); |
| BASE_EXPECT_DEATH(use(empty[std::numeric_limits<size_t>::max()]), ""); |
| |
| BASE_EXPECT_DEATH(use(empty.at(1u)), ""); |
| BASE_EXPECT_DEATH(use(empty.at(std::numeric_limits<size_t>::max())), ""); |
| |
| constexpr auto stuff = cstring_view("stuff"); |
| BASE_EXPECT_DEATH(use(stuff[6u]), ""); |
| BASE_EXPECT_DEATH(use(stuff[std::numeric_limits<size_t>::max()]), ""); |
| |
| BASE_EXPECT_DEATH(use(stuff.at(6u)), ""); |
| BASE_EXPECT_DEATH(use(stuff.at(std::numeric_limits<size_t>::max())), ""); |
| } |
| |
| TEST(CStringViewTest, FrontBack) { |
| constexpr auto stuff = cstring_view("stuff"); |
| static_assert(stuff.front() == 's'); |
| static_assert(&stuff.front() == stuff.data()); |
| static_assert(stuff.back() == 'f'); |
| static_assert(&stuff.back() == UNSAFE_BUFFERS(stuff.data() + 4u)); |
| |
| constexpr auto one = cstring_view("1"); |
| static_assert(one.front() == '1'); |
| static_assert(&one.front() == one.data()); |
| static_assert(one.back() == '1'); |
| static_assert(&one.back() == one.data()); |
| } |
| |
| TEST(CStringViewDeathTest, FrontBackChecked) { |
| auto use = [](auto x) { base::debug::Alias(&x); }; |
| |
| constexpr auto empty = cstring_view(); |
| BASE_EXPECT_DEATH(use(empty.front()), ""); |
| BASE_EXPECT_DEATH(use(empty.back()), ""); |
| } |
| |
| TEST(CStringViewTest, Size) { |
| constexpr auto empty = cstring_view(); |
| static_assert(empty.size() == 0u); |
| static_assert(empty.size_bytes() == 0u); |
| constexpr auto stuff = cstring_view("stuff"); |
| static_assert(stuff.size() == 5u); |
| static_assert(stuff.size_bytes() == 5u); |
| |
| constexpr auto empty16 = u16cstring_view(); |
| static_assert(empty16.size() == 0u); |
| static_assert(empty16.size_bytes() == 0u); |
| constexpr auto stuff16 = u16cstring_view(u"stuff"); |
| static_assert(stuff16.size() == 5u); |
| static_assert(stuff16.size_bytes() == 10u); |
| |
| constexpr auto empty32 = u32cstring_view(); |
| static_assert(empty32.size() == 0u); |
| static_assert(empty32.size_bytes() == 0u); |
| constexpr auto stuff32 = u32cstring_view(U"stuff"); |
| static_assert(stuff32.size() == 5u); |
| static_assert(stuff32.size_bytes() == 20u); |
| |
| #if BUILDFLAG(IS_WIN) |
| constexpr auto emptyw = wcstring_view(); |
| static_assert(emptyw.size() == 0u); |
| static_assert(emptyw.size_bytes() == 0u); |
| constexpr auto stuffw = wcstring_view(L"stuff"); |
| static_assert(stuffw.size() == 5u); |
| static_assert(stuffw.size_bytes() == 10u); |
| #endif |
| } |
| |
| TEST(CStringViewTest, Empty) { |
| constexpr auto empty = cstring_view(); |
| static_assert(empty.empty()); |
| constexpr auto one = cstring_view("1"); |
| static_assert(!one.empty()); |
| constexpr auto stuff = cstring_view("stuff"); |
| static_assert(!stuff.empty()); |
| |
| constexpr auto empty16 = u16cstring_view(); |
| static_assert(empty16.empty()); |
| constexpr auto stuff16 = u16cstring_view(u"stuff"); |
| static_assert(!stuff16.empty()); |
| |
| constexpr auto empty32 = u32cstring_view(); |
| static_assert(empty32.empty()); |
| constexpr auto stuff32 = u32cstring_view(U"stuff"); |
| static_assert(!stuff32.empty()); |
| |
| #if BUILDFLAG(IS_WIN) |
| constexpr auto emptyw = wcstring_view(); |
| static_assert(emptyw.empty()); |
| constexpr auto stuffw = wcstring_view(L"stuff"); |
| static_assert(!stuffw.empty()); |
| #endif |
| } |
| |
| TEST(CStringViewTest, MaxSize) { |
| static_assert(cstring_view().max_size() == |
| std::numeric_limits<size_t>::max()); |
| static_assert(u16cstring_view().max_size() == |
| std::numeric_limits<size_t>::max() / 2u); |
| static_assert(u32cstring_view().max_size() == |
| std::numeric_limits<size_t>::max() / 4u); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view().max_size() == |
| std::numeric_limits<size_t>::max() / 2u); |
| #endif |
| } |
| |
| TEST(CStringViewTest, ToSpan) { |
| constexpr auto empty = cstring_view(); |
| { |
| auto s = base::span(empty); |
| static_assert(std::same_as<base::span<const char>, decltype(s)>); |
| EXPECT_EQ(s.data(), empty.data()); |
| EXPECT_EQ(s.size(), 0u); |
| EXPECT_EQ(s.size_bytes(), 0u); |
| } |
| constexpr auto stuff = cstring_view("stuff"); |
| { |
| auto s = base::span(stuff); |
| static_assert(std::same_as<base::span<const char>, decltype(s)>); |
| EXPECT_EQ(s.data(), stuff.data()); |
| EXPECT_EQ(s.size(), 5u); |
| EXPECT_EQ(s.size_bytes(), 5u); |
| } |
| constexpr auto stuff16 = u16cstring_view(u"stuff"); |
| { |
| auto s = base::span(stuff16); |
| static_assert(std::same_as<base::span<const char16_t>, decltype(s)>); |
| EXPECT_EQ(s.data(), stuff16.data()); |
| EXPECT_EQ(s.size(), 5u); |
| EXPECT_EQ(s.size_bytes(), 10u); |
| } |
| constexpr auto stuff32 = u32cstring_view(U"stuff"); |
| { |
| auto s = base::span(stuff32); |
| static_assert(std::same_as<base::span<const char32_t>, decltype(s)>); |
| EXPECT_EQ(s.data(), stuff32.data()); |
| EXPECT_EQ(s.size(), 5u); |
| EXPECT_EQ(s.size_bytes(), 20u); |
| } |
| } |
| |
| TEST(CStringViewTest, Cstr) { |
| constexpr auto empty = cstring_view(); |
| constexpr auto stuff = cstring_view("stuff"); |
| |
| static_assert(*stuff.c_str() == 's'); |
| |
| EXPECT_STREQ(empty.c_str(), ""); |
| EXPECT_STREQ(stuff.c_str(), "stuff"); |
| } |
| |
| TEST(CStringViewTest, CopyConstuct) { |
| static_assert(std::is_trivially_copy_constructible_v<cstring_view>); |
| |
| auto stuff = cstring_view("stuff"); |
| auto other = stuff; |
| EXPECT_EQ(other.data(), stuff.data()); |
| EXPECT_EQ(other.size(), stuff.size()); |
| } |
| |
| TEST(CStringViewTest, CopyAssign) { |
| static_assert(std::is_trivially_copy_assignable_v<cstring_view>); |
| |
| auto empty = cstring_view(); |
| auto stuff = cstring_view("stuff"); |
| empty = stuff; |
| EXPECT_EQ(empty.data(), stuff.data()); |
| EXPECT_EQ(empty.size(), stuff.size()); |
| } |
| |
| TEST(CStringViewTest, RemovePrefix) { |
| auto empty = cstring_view(); |
| auto mod_empty = empty; |
| mod_empty.remove_prefix(0u); |
| EXPECT_EQ(mod_empty.data(), &empty[0u]); |
| EXPECT_EQ(mod_empty.size(), 0u); |
| |
| auto stuff = cstring_view("stuff"); |
| auto mod_stuff = stuff; |
| mod_stuff.remove_prefix(0u); |
| EXPECT_EQ(mod_stuff.data(), &stuff[0u]); |
| EXPECT_EQ(mod_stuff.size(), 5u); |
| mod_stuff.remove_prefix(2u); |
| EXPECT_EQ(mod_stuff.data(), &stuff[2u]); |
| EXPECT_EQ(mod_stuff.size(), 3u); |
| mod_stuff.remove_prefix(1u); |
| EXPECT_EQ(mod_stuff.data(), &stuff[3u]); |
| EXPECT_EQ(mod_stuff.size(), 2u); |
| mod_stuff.remove_prefix(2u); |
| EXPECT_EQ(mod_stuff.data(), &stuff[5u]); |
| EXPECT_EQ(mod_stuff.size(), 0u); |
| |
| static_assert([] { |
| auto stuff = cstring_view("stuff"); |
| stuff.remove_prefix(2u); |
| return stuff; |
| }() == "uff"); |
| |
| auto stuff16 = u16cstring_view(u"stuff"); |
| auto mod_stuff16 = stuff16; |
| mod_stuff16.remove_prefix(2u); |
| EXPECT_EQ(mod_stuff16.data(), &stuff16[2u]); |
| EXPECT_EQ(mod_stuff16.size(), 3u); |
| |
| auto stuff32 = u32cstring_view(U"stuff"); |
| auto mod_stuff32 = stuff32; |
| mod_stuff32.remove_prefix(2u); |
| EXPECT_EQ(mod_stuff32.data(), &stuff32[2u]); |
| EXPECT_EQ(mod_stuff32.size(), 3u); |
| |
| #if BUILDFLAG(IS_WIN) |
| auto stuffw = wcstring_view(L"stuff"); |
| auto mod_stuffw = stuffw; |
| mod_stuffw.remove_prefix(2u); |
| EXPECT_EQ(mod_stuffw.data(), &stuffw[2u]); |
| EXPECT_EQ(mod_stuffw.size(), 3u); |
| #endif |
| } |
| |
| TEST(CStringViewDeathTest, RemovePrefixChecked) { |
| auto empty = cstring_view(); |
| BASE_EXPECT_DEATH(empty.remove_prefix(1u), ""); |
| |
| auto stuff = cstring_view("stuff"); |
| BASE_EXPECT_DEATH(stuff.remove_prefix(6u), ""); |
| stuff.remove_prefix(4u); |
| BASE_EXPECT_DEATH(stuff.remove_prefix(2u), ""); |
| } |
| |
| TEST(CStringViewTest, Swap) { |
| auto empty = cstring_view(); |
| auto stuff = cstring_view("stuff"); |
| empty.swap(stuff); |
| EXPECT_EQ(stuff, cstring_view("")); |
| EXPECT_EQ(empty, cstring_view("stuff")); |
| |
| static_assert([] { |
| auto abc = cstring_view("abc"); |
| auto ef = cstring_view("ef"); |
| abc.swap(ef); |
| return ef; |
| }() == "abc"); |
| |
| auto one16 = u16cstring_view(u"one"); |
| auto two16 = u16cstring_view(u"twotwo"); |
| one16.swap(two16); |
| EXPECT_EQ(one16, u16cstring_view(u"twotwo")); |
| EXPECT_EQ(two16, u16cstring_view(u"one")); |
| } |
| |
| TEST(CStringViewTest, Substr) { |
| auto substr = cstring_view("hello").substr(1u); |
| static_assert(std::same_as<std::string_view, decltype(substr)>); |
| |
| static_assert(cstring_view("").substr(0u) == ""); |
| static_assert(cstring_view("").substr(0u, 0u) == ""); |
| static_assert(cstring_view("stuff").substr(0u) == "stuff"); |
| static_assert(cstring_view("stuff").substr(0u, 2u) == "st"); |
| static_assert(cstring_view("stuff").substr(2u) == "uff"); |
| static_assert(cstring_view("stuff").substr(2u, 3u) == "uff"); |
| static_assert(cstring_view("stuff").substr(2u, 1u) == "u"); |
| static_assert(cstring_view("stuff").substr(2u, 0u) == ""); |
| |
| // `count` going off the end is clamped. Same as for string_view with |
| // hardening. |
| static_assert(cstring_view("stuff").substr(2u, 4u) == "uff"); |
| static_assert(std::string_view("stuff").substr(2u, 4u) == "uff"); |
| } |
| |
| TEST(CStringViewDeathTest, SubstrBoundsChecked) { |
| auto use = [](auto x) { base::debug::Alias(&x); }; |
| |
| auto stuff = cstring_view("stuff"); |
| |
| // `pos` going off the end is CHECKed. Same as for string_view with hardening. |
| BASE_EXPECT_DEATH(use(stuff.substr(6u, 0u)), ""); |
| BASE_EXPECT_DEATH(use(std::string_view("stuff").substr(6u, 0u)), ""); |
| BASE_EXPECT_DEATH(use(stuff.substr(6u, 1u)), ""); |
| BASE_EXPECT_DEATH(use(std::string_view("stuff").substr(6u, 1u)), ""); |
| } |
| |
| TEST(CStringViewTest, StartsWith) { |
| // Comparison with `const char*`. |
| static_assert(!cstring_view("").starts_with("hello")); |
| static_assert(cstring_view("").starts_with("")); |
| static_assert(cstring_view("hello").starts_with("hello")); |
| static_assert(cstring_view("hello").starts_with("")); |
| static_assert(cstring_view("hello").starts_with("he")); |
| static_assert(!cstring_view("hello").starts_with("ello")); |
| constexpr const char* query = "ello"; |
| static_assert(!cstring_view("hello").starts_with(query)); |
| |
| static_assert(u16cstring_view(u"hello").starts_with(u"he")); |
| static_assert(u32cstring_view(U"hello").starts_with(U"he")); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").starts_with(L"he")); |
| #endif |
| |
| // Comparison with `string/string_view/cstring_view`. |
| static_assert(cstring_view("hello").starts_with(std::string("he"))); |
| static_assert(!cstring_view("hello").starts_with(std::string("el"))); |
| static_assert(cstring_view("hello").starts_with(std::string_view("he"))); |
| static_assert(!cstring_view("hello").starts_with(std::string_view("el"))); |
| static_assert(cstring_view("hello").starts_with(cstring_view("he"))); |
| static_assert(!cstring_view("hello").starts_with(cstring_view("el"))); |
| |
| static_assert(!cstring_view("hello").starts_with(std::string("hellos"))); |
| static_assert(!cstring_view("hello").starts_with(std::string_view("hellos"))); |
| static_assert(!cstring_view("hello").starts_with(cstring_view("hellos"))); |
| |
| static_assert(u16cstring_view(u"hello").starts_with(std::u16string(u"he"))); |
| static_assert(u32cstring_view(U"hello").starts_with(std::u32string(U"he"))); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").starts_with(std::wstring(L"he"))); |
| #endif |
| |
| // Comparison with a character. |
| static_assert(!cstring_view("").starts_with('h')); |
| static_assert(cstring_view("hello").starts_with('h')); |
| static_assert(!cstring_view("hello").starts_with('e')); |
| |
| static_assert(u16cstring_view(u"hello").starts_with(u'h')); |
| static_assert(u32cstring_view(U"hello").starts_with(U'h')); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").starts_with(L'h')); |
| #endif |
| } |
| |
| TEST(CStringViewTest, EndsWith) { |
| // Comparison with `const char*`. |
| static_assert(!cstring_view("").ends_with("hello")); |
| static_assert(cstring_view("").ends_with("")); |
| static_assert(cstring_view("hello").ends_with("hello")); |
| static_assert(cstring_view("hello").ends_with("")); |
| static_assert(cstring_view("hello").ends_with("lo")); |
| static_assert(!cstring_view("hello").ends_with("hel")); |
| constexpr const char* query = "hel"; |
| static_assert(!cstring_view("hello").ends_with(query)); |
| |
| static_assert(u16cstring_view(u"hello").ends_with(u"lo")); |
| static_assert(u32cstring_view(U"hello").ends_with(U"lo")); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").ends_with(L"lo")); |
| #endif |
| |
| // Comparison with `string/string_view/cstring_view`. |
| static_assert(cstring_view("hello").ends_with(std::string("lo"))); |
| static_assert(!cstring_view("hello").ends_with(std::string("ell"))); |
| static_assert(cstring_view("hello").ends_with(std::string_view("lo"))); |
| static_assert(!cstring_view("hello").ends_with(std::string_view("ell"))); |
| static_assert(cstring_view("hello").ends_with(cstring_view("lo"))); |
| static_assert(!cstring_view("hello").ends_with(cstring_view("ell"))); |
| |
| static_assert(!cstring_view("hello").ends_with(std::string("shello"))); |
| static_assert(!cstring_view("hello").ends_with(std::string_view("shello"))); |
| static_assert(!cstring_view("hello").ends_with(cstring_view("shello"))); |
| |
| static_assert(u16cstring_view(u"hello").ends_with(std::u16string(u"lo"))); |
| static_assert(u32cstring_view(U"hello").ends_with(std::u32string(U"lo"))); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").ends_with(std::wstring(L"lo"))); |
| #endif |
| |
| // Comparison with a character. |
| static_assert(!cstring_view("").ends_with('h')); |
| static_assert(cstring_view("hello").ends_with('o')); |
| static_assert(!cstring_view("hello").ends_with('l')); |
| |
| static_assert(u16cstring_view(u"hello").ends_with(u'o')); |
| static_assert(u32cstring_view(U"hello").ends_with(U'o')); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").ends_with(L'o')); |
| #endif |
| } |
| |
| TEST(CStringViewTest, Find) { |
| // OOB `pos` will return npos. The NUL is never searched. |
| static_assert(cstring_view("hello").find('h', 1000u) == cstring_view::npos); |
| static_assert(cstring_view("hello").find('\0', 5u) == cstring_view::npos); |
| |
| // Searching for a Char. |
| static_assert(cstring_view("hello").find('e') == 1u); |
| static_assert(cstring_view("hello").find('z') == cstring_view::npos); |
| static_assert(cstring_view("hello").find('l') == 2u); |
| static_assert(cstring_view("hello").find('l', 3u) == 3u); |
| |
| static_assert(u16cstring_view(u"hello").find(u'e') == 1u); |
| static_assert(u16cstring_view(u"hello").find(u'z') == cstring_view::npos); |
| static_assert(u16cstring_view(u"hello").find(u'l') == 2u); |
| static_assert(u16cstring_view(u"hello").find(u'l', 3u) == 3u); |
| |
| static_assert(u32cstring_view(U"hello").find(U'e') == 1u); |
| static_assert(u32cstring_view(U"hello").find(U'z') == cstring_view::npos); |
| static_assert(u32cstring_view(U"hello").find(U'l') == 2u); |
| static_assert(u32cstring_view(U"hello").find(U'l', 3u) == 3u); |
| |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").find(L'e') == 1u); |
| static_assert(wcstring_view(L"hello").find(L'z') == cstring_view::npos); |
| static_assert(wcstring_view(L"hello").find(L'l') == 2u); |
| static_assert(wcstring_view(L"hello").find(L'l', 3u) == 3u); |
| #endif |
| |
| // Searching for a string. |
| static_assert(cstring_view("hello hello").find("lo") == 3u); |
| static_assert(cstring_view("hello hello").find("lol") == cstring_view::npos); |
| static_assert(u16cstring_view(u"hello hello").find(u"lo") == 3u); |
| static_assert(u16cstring_view(u"hello hello").find(u"lol") == |
| cstring_view::npos); |
| static_assert(u32cstring_view(U"hello hello").find(U"lo") == 3u); |
| static_assert(u32cstring_view(U"hello hello").find(U"lol") == |
| cstring_view::npos); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello hello").find(L"lo") == 3u); |
| static_assert(wcstring_view(L"hello hello").find(L"lol") == |
| cstring_view::npos); |
| #endif |
| } |
| |
| TEST(CStringViewTest, Rfind) { |
| // OOB `pos` will clamp to the end of the view. The NUL is never searched. |
| static_assert(cstring_view("hello").rfind('h', 0u) == 0u); |
| static_assert(cstring_view("hello").rfind('h', 1000u) == 0u); |
| static_assert(cstring_view("hello").rfind('\0', 5u) == cstring_view::npos); |
| |
| // Searching for a Char. |
| static_assert(cstring_view("hello").rfind('e') == 1u); |
| static_assert(cstring_view("hello").rfind('z') == cstring_view::npos); |
| static_assert(cstring_view("hello").rfind('l') == 3u); |
| static_assert(cstring_view("hello").rfind('l', 2u) == 2u); |
| |
| static_assert(u16cstring_view(u"hello").rfind(u'e') == 1u); |
| static_assert(u16cstring_view(u"hello").rfind(u'z') == cstring_view::npos); |
| static_assert(u16cstring_view(u"hello").rfind(u'l') == 3u); |
| static_assert(u16cstring_view(u"hello").rfind(u'l', 2u) == 2u); |
| |
| static_assert(u32cstring_view(U"hello").rfind(U'e') == 1u); |
| static_assert(u32cstring_view(U"hello").rfind(U'z') == cstring_view::npos); |
| static_assert(u32cstring_view(U"hello").rfind(U'l') == 3u); |
| static_assert(u32cstring_view(U"hello").rfind(U'l', 2u) == 2u); |
| |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").rfind(L'e') == 1u); |
| static_assert(wcstring_view(L"hello").rfind(L'z') == cstring_view::npos); |
| static_assert(wcstring_view(L"hello").rfind(L'l') == 3u); |
| static_assert(wcstring_view(L"hello").rfind(L'l', 2u) == 2u); |
| #endif |
| |
| // Searching for a string. |
| static_assert(cstring_view("hello hello").rfind("lo") == 9u); |
| static_assert(cstring_view("hello hello").rfind("lol") == cstring_view::npos); |
| static_assert(u16cstring_view(u"hello hello").rfind(u"lo") == 9u); |
| static_assert(u16cstring_view(u"hello hello").rfind(u"lol") == |
| cstring_view::npos); |
| static_assert(u32cstring_view(U"hello hello").rfind(U"lo") == 9u); |
| static_assert(u32cstring_view(U"hello hello").rfind(U"lol") == |
| cstring_view::npos); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello hello").rfind(L"lo") == 9u); |
| static_assert(wcstring_view(L"hello hello").rfind(L"lol") == |
| cstring_view::npos); |
| #endif |
| } |
| |
| TEST(CStringViewTest, FindFirstOf) { |
| // OOB `pos` will return npos. The NUL is never searched. |
| static_assert(cstring_view("hello").find_first_of('h', 1000u) == |
| cstring_view::npos); |
| static_assert(cstring_view("hello").find_first_of('\0', 5u) == |
| cstring_view::npos); |
| |
| // Searching for a Char. |
| static_assert(cstring_view("hello").find_first_of('e') == 1u); |
| static_assert(cstring_view("hello").find_first_of('z') == cstring_view::npos); |
| static_assert(cstring_view("hello").find_first_of('l') == 2u); |
| static_assert(cstring_view("hello").find_first_of('l', 3u) == 3u); |
| |
| static_assert(u16cstring_view(u"hello").find_first_of(u'e') == 1u); |
| static_assert(u16cstring_view(u"hello").find_first_of(u'z') == |
| cstring_view::npos); |
| static_assert(u16cstring_view(u"hello").find_first_of(u'l') == 2u); |
| static_assert(u16cstring_view(u"hello").find_first_of(u'l', 3u) == 3u); |
| |
| static_assert(u32cstring_view(U"hello").find_first_of(U'e') == 1u); |
| static_assert(u32cstring_view(U"hello").find_first_of(U'z') == |
| cstring_view::npos); |
| static_assert(u32cstring_view(U"hello").find_first_of(U'l') == 2u); |
| static_assert(u32cstring_view(U"hello").find_first_of(U'l', 3u) == 3u); |
| |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").find_first_of(L'e') == 1u); |
| static_assert(wcstring_view(L"hello").find_first_of(L'z') == |
| cstring_view::npos); |
| static_assert(wcstring_view(L"hello").find_first_of(L'l') == 2u); |
| static_assert(wcstring_view(L"hello").find_first_of(L'l', 3u) == 3u); |
| #endif |
| |
| // Searching for a string. |
| static_assert(cstring_view("hello hello").find_first_of("ol") == 2u); |
| static_assert(cstring_view("hello hello").find_first_of("zz") == |
| cstring_view::npos); |
| static_assert(u16cstring_view(u"hello hello").find_first_of(u"ol") == 2u); |
| static_assert(u16cstring_view(u"hello hello").find_first_of(u"zz") == |
| cstring_view::npos); |
| static_assert(u32cstring_view(U"hello hello").find_first_of(U"ol") == 2u); |
| static_assert(u32cstring_view(U"hello hello").find_first_of(U"zz") == |
| cstring_view::npos); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello hello").find_first_of(L"ol") == 2u); |
| static_assert(wcstring_view(L"hello hello").find_first_of(L"zz") == |
| cstring_view::npos); |
| #endif |
| } |
| |
| TEST(CStringViewTest, FindLastOf) { |
| // OOB `pos` will clamp to the end of the view. The NUL is never searched. |
| static_assert(cstring_view("hello").find_last_of('h', 0u) == 0u); |
| static_assert(cstring_view("hello").find_last_of('h', 1000u) == 0u); |
| static_assert(cstring_view("hello").find_last_of('\0', 5u) == |
| cstring_view::npos); |
| |
| // Searching for a Char. |
| static_assert(cstring_view("hello").find_last_of('e') == 1u); |
| static_assert(cstring_view("hello").find_last_of('z') == cstring_view::npos); |
| static_assert(cstring_view("hello").find_last_of('l') == 3u); |
| static_assert(cstring_view("hello").find_last_of('l', 2u) == 2u); |
| |
| static_assert(u16cstring_view(u"hello").find_last_of(u'e') == 1u); |
| static_assert(u16cstring_view(u"hello").find_last_of(u'z') == |
| cstring_view::npos); |
| static_assert(u16cstring_view(u"hello").find_last_of(u'l') == 3u); |
| static_assert(u16cstring_view(u"hello").find_last_of(u'l', 2u) == 2u); |
| |
| static_assert(u32cstring_view(U"hello").find_last_of(U'e') == 1u); |
| static_assert(u32cstring_view(U"hello").find_last_of(U'z') == |
| cstring_view::npos); |
| static_assert(u32cstring_view(U"hello").find_last_of(U'l') == 3u); |
| static_assert(u32cstring_view(U"hello").find_last_of(U'l', 2u) == 2u); |
| |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").find_last_of(L'e') == 1u); |
| static_assert(wcstring_view(L"hello").find_last_of(L'z') == |
| cstring_view::npos); |
| static_assert(wcstring_view(L"hello").find_last_of(L'l') == 3u); |
| static_assert(wcstring_view(L"hello").find_last_of(L'l', 2u) == 2u); |
| #endif |
| |
| // Searching for a string. |
| static_assert(cstring_view("hello hello").find_last_of("lo") == 10u); |
| static_assert(cstring_view("hello hello").find_last_of("zz") == |
| cstring_view::npos); |
| static_assert(u16cstring_view(u"hello hello").find_last_of(u"lo") == 10u); |
| static_assert(u16cstring_view(u"hello hello").find_last_of(u"zz") == |
| cstring_view::npos); |
| static_assert(u32cstring_view(U"hello hello").find_last_of(U"lo") == 10u); |
| static_assert(u32cstring_view(U"hello hello").find_last_of(U"zz") == |
| cstring_view::npos); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello hello").find_last_of(L"lo") == 10u); |
| static_assert(wcstring_view(L"hello hello").find_last_of(L"zz") == |
| cstring_view::npos); |
| #endif |
| } |
| |
| TEST(CStringViewTest, FindFirstNotOf) { |
| // OOB `pos` will return npos. The NUL is never searched. |
| static_assert(cstring_view("hello").find_first_not_of('a', 1000u) == |
| cstring_view::npos); |
| static_assert(cstring_view("hello").find_first_not_of('a', 5u) == |
| cstring_view::npos); |
| |
| // Searching for a Char. |
| static_assert(cstring_view("hello").find_first_not_of('h') == 1u); |
| static_assert(cstring_view("hello").find_first_not_of('e') == 0u); |
| static_assert(cstring_view("hello").find_first_not_of("eloh") == |
| cstring_view::npos); |
| |
| static_assert(u16cstring_view(u"hello").find_first_not_of(u'h') == 1u); |
| static_assert(u16cstring_view(u"hello").find_first_not_of(u'e') == 0u); |
| static_assert(u16cstring_view(u"hello").find_first_not_of(u"eloh") == |
| cstring_view::npos); |
| |
| static_assert(u32cstring_view(U"hello").find_first_not_of(U'h') == 1u); |
| static_assert(u32cstring_view(U"hello").find_first_not_of(U'e') == 0u); |
| static_assert(u32cstring_view(U"hello").find_first_not_of(U"eloh") == |
| cstring_view::npos); |
| |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").find_first_not_of(L'h') == 1u); |
| static_assert(wcstring_view(L"hello").find_first_not_of(L'e') == 0u); |
| static_assert(wcstring_view(L"hello").find_first_not_of(L"eloh") == |
| cstring_view::npos); |
| #endif |
| |
| // Searching for a string. |
| static_assert(cstring_view("hello hello").find_first_not_of("eh") == 2u); |
| static_assert(cstring_view("hello hello").find_first_not_of("hello ") == |
| cstring_view::npos); |
| static_assert(u16cstring_view(u"hello hello").find_first_not_of(u"eh") == 2u); |
| static_assert(u16cstring_view(u"hello hello").find_first_not_of(u"hello ") == |
| cstring_view::npos); |
| static_assert(u32cstring_view(U"hello hello").find_first_not_of(U"eh") == 2u); |
| static_assert(u32cstring_view(U"hello hello").find_first_not_of(U"hello ") == |
| cstring_view::npos); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello hello").find_first_not_of(L"eh") == 2u); |
| static_assert(wcstring_view(L"hello hello").find_first_not_of(L"hello ") == |
| cstring_view::npos); |
| #endif |
| } |
| |
| TEST(CStringViewTest, FindLastNotOf) { |
| // OOB `pos` will clamp to the end of the view. The NUL is never searched. |
| static_assert(cstring_view("hello").find_last_not_of('a', 1000u) == 4u); |
| static_assert(cstring_view("hello").find_last_not_of('a', 5u) == 4u); |
| |
| // Searching for a Char. |
| static_assert(cstring_view("hello").find_last_not_of('l') == 4u); |
| static_assert(cstring_view("hello").find_last_not_of('o') == 3u); |
| static_assert(cstring_view("hello").find_last_not_of("eloh") == |
| cstring_view::npos); |
| |
| static_assert(u16cstring_view(u"hello").find_last_not_of(u'l') == 4u); |
| static_assert(u16cstring_view(u"hello").find_last_not_of(u'o') == 3u); |
| static_assert(u16cstring_view(u"hello").find_last_not_of(u"eloh") == |
| cstring_view::npos); |
| |
| static_assert(u32cstring_view(U"hello").find_last_not_of(U'l') == 4u); |
| static_assert(u32cstring_view(U"hello").find_last_not_of(U'o') == 3u); |
| static_assert(u32cstring_view(U"hello").find_last_not_of(U"eloh") == |
| cstring_view::npos); |
| |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello").find_last_not_of(L'l') == 4u); |
| static_assert(wcstring_view(L"hello").find_last_not_of(L'o') == 3u); |
| static_assert(wcstring_view(L"hello").find_last_not_of(L"eloh") == |
| cstring_view::npos); |
| #endif |
| |
| // Searching for a string. |
| static_assert(cstring_view("hello hello").find_last_not_of("lo") == 7u); |
| static_assert(cstring_view("hello hello").find_last_not_of("hello ") == |
| cstring_view::npos); |
| static_assert(u16cstring_view(u"hello hello").find_last_not_of(u"lo") == 7u); |
| static_assert(u16cstring_view(u"hello hello").find_last_not_of(u"hello ") == |
| cstring_view::npos); |
| static_assert(u32cstring_view(U"hello hello").find_last_not_of(U"lo") == 7u); |
| static_assert(u32cstring_view(U"hello hello").find_last_not_of(U"hello ") == |
| cstring_view::npos); |
| #if BUILDFLAG(IS_WIN) |
| static_assert(wcstring_view(L"hello hello").find_last_not_of(L"lo") == 7u); |
| static_assert(wcstring_view(L"hello hello").find_last_not_of(L"hello ") == |
| cstring_view::npos); |
| #endif |
| } |
| |
| TEST(CStringViewTest, ToString) { |
| // Streaming support like std::string_view. |
| std::ostringstream s; |
| s << cstring_view("hello"); |
| EXPECT_EQ(s.str(), "hello"); |
| |
| #if BUILDFLAG(IS_WIN) |
| std::wostringstream sw; |
| sw << wcstring_view(L"hello"); |
| EXPECT_EQ(sw.str(), L"hello"); |
| #endif |
| |
| // Gtest printing support. |
| EXPECT_EQ(testing::PrintToString(cstring_view("hello")), "hello"); |
| } |
| |
| TEST(CStringViewTest, Hash) { |
| [[maybe_unused]] auto s = std::hash<cstring_view>()(cstring_view("hello")); |
| static_assert(std::same_as<size_t, decltype(s)>); |
| |
| [[maybe_unused]] auto s16 = |
| std::hash<u16cstring_view>()(u16cstring_view(u"hello")); |
| static_assert(std::same_as<size_t, decltype(s)>); |
| |
| [[maybe_unused]] auto s32 = |
| std::hash<u32cstring_view>()(u32cstring_view(U"hello")); |
| static_assert(std::same_as<size_t, decltype(s)>); |
| |
| #if BUILDFLAG(IS_WIN) |
| [[maybe_unused]] auto sw = |
| std::hash<wcstring_view>()(wcstring_view(L"hello")); |
| static_assert(std::same_as<size_t, decltype(s)>); |
| #endif |
| } |
| |
| TEST(CStringViewTest, IntoStdStringView) { |
| // string_view implicitly constructs from const char*, and so also from |
| // cstring_view. |
| std::string_view sc = "hello"; |
| std::string_view s = cstring_view("hello"); |
| EXPECT_EQ(s, sc); |
| |
| static_assert(std::string_view(cstring_view("hello")) == "hello"); |
| } |
| |
| TEST(CStringViewTest, IntoStdString) { |
| // string implicitly constructs from const char*, but not from |
| // std::string_view or cstring_view. |
| static_assert(std::convertible_to<const char*, std::string>); |
| static_assert(!std::convertible_to<std::string_view, std::string>); |
| static_assert(!std::convertible_to<cstring_view, std::string>); |
| |
| static_assert(std::constructible_from<std::string, const char*>); |
| static_assert(std::constructible_from<std::string, std::string_view>); |
| static_assert(std::constructible_from<std::string, cstring_view>); |
| |
| auto sv = std::string(std::string_view("hello")); |
| auto cs = std::string(cstring_view("hello")); |
| EXPECT_EQ(cs, sv); |
| |
| static_assert(std::string(cstring_view("hello")) == "hello"); |
| } |
| |
| TEST(CStringViewTest, StringPlus) { |
| { |
| auto s = cstring_view("hello") + std::string("world"); |
| static_assert(std::same_as<std::string, decltype(s)>); |
| EXPECT_EQ(s, "helloworld"); |
| } |
| { |
| auto s = std::string("hello") + cstring_view("world"); |
| static_assert(std::same_as<std::string, decltype(s)>); |
| EXPECT_EQ(s, "helloworld"); |
| } |
| { |
| auto s = std::u16string(u"hello") + u16cstring_view(u"world"); |
| static_assert(std::same_as<std::u16string, decltype(s)>); |
| EXPECT_EQ(s, u"helloworld"); |
| } |
| { |
| auto s = std::u32string(U"hello") + u32cstring_view(U"world"); |
| static_assert(std::same_as<std::u32string, decltype(s)>); |
| EXPECT_EQ(s, U"helloworld"); |
| } |
| { |
| #if BUILDFLAG(IS_WIN) |
| auto s = std::wstring(L"hello") + wcstring_view(L"world"); |
| static_assert(std::same_as<std::wstring, decltype(s)>); |
| EXPECT_EQ(s, L"helloworld"); |
| #endif |
| } |
| |
| // From lvalues. |
| { |
| auto h = cstring_view("hello"); |
| auto w = std::string("world"); |
| auto s = h + w; |
| static_assert(std::same_as<std::string, decltype(s)>); |
| EXPECT_EQ(s, "helloworld"); |
| } |
| |
| static_assert(cstring_view("hello") + std::string("world") == "helloworld"); |
| static_assert(std::string("hello") + cstring_view("world") == "helloworld"); |
| } |
| |
| TEST(CStringViewTest, StringAppend) { |
| std::string s = "hello"; |
| // string::append() can accept cstring_view like const char*. |
| s.append(cstring_view("world")); |
| EXPECT_EQ(s, "helloworld"); |
| } |
| |
| TEST(CStringViewTest, StringInsert) { |
| std::string s = "world"; |
| // string::insert() can accept cstring_view like const char*. |
| s.insert(0u, cstring_view("hello")); |
| EXPECT_EQ(s, "helloworld"); |
| } |
| |
| TEST(CStringViewTest, StringReplace) { |
| std::string s = "goodbyeworld"; |
| // string::replace() can accept cstring_view like const char*. |
| s.replace(0u, 7u, cstring_view("hello")); |
| EXPECT_EQ(s, "helloworld"); |
| } |
| |
| TEST(CStringViewTest, StringFind) { |
| const std::string s = "helloworld"; |
| // string::find() can accept cstring_view like const char*. |
| EXPECT_EQ(s.find(cstring_view("owo")), 4u); |
| } |
| |
| TEST(CStringViewTest, StringCompare) { |
| const std::string s = "hello"; |
| // string::compare() can accept cstring_view like const char*. |
| EXPECT_EQ(s.compare(cstring_view("hello")), 0); |
| // string::operator== can accept cstring_view like const char*. |
| EXPECT_EQ(s, cstring_view("hello")); |
| // string::operator<=> can accept cstring_view like const char*. |
| EXPECT_EQ(s <=> cstring_view("hello"), std::weak_ordering::equivalent); |
| // string::operator<= etc can accept cstring_view like const char*. This |
| // follows from <=> normally but std::string has more overloads. |
| EXPECT_LE(s, cstring_view("hello")); |
| } |
| |
| TEST(CStringViewTest, StringStartsEndsWith) { |
| const std::string s = "hello"; |
| // string::starts_with() can accept cstring_view like const char*. |
| EXPECT_EQ(s.starts_with(cstring_view("hel")), true); |
| EXPECT_EQ(s.starts_with(cstring_view("lo")), false); |
| // string::ends_with() can accept cstring_view like const char*. |
| EXPECT_EQ(s.ends_with(cstring_view("hel")), false); |
| EXPECT_EQ(s.ends_with(cstring_view("lo")), true); |
| } |
| |
| TEST(CStringViewTest, StrCat) { |
| EXPECT_EQ(base::StrCat({cstring_view("hello"), std::string_view("world")}), |
| "helloworld"); |
| } |
| |
| TEST(CStringViewTest, Example_CtorLiteral) { |
| const char kLiteral[] = "hello world"; |
| auto s = base::cstring_view(kLiteral); |
| CHECK(s == "hello world"); |
| auto s2 = base::cstring_view("this works too"); |
| CHECK(s2 == "this works too"); |
| } |
| |
| } // namespace |
| } // namespace base |