//===-- Unittests for string ----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "src/__support/CPP/string.h" #include "test/UnitTest/Test.h" using LIBC_NAMESPACE::cpp::string; using LIBC_NAMESPACE::cpp::string_view; using LIBC_NAMESPACE::cpp::to_string; TEST(LlvmLibcStringTest, InitializeEmpty) { const string s; ASSERT_EQ(s.size(), size_t(0)); ASSERT_TRUE(s.empty()); ASSERT_STREQ(s.data(), ""); ASSERT_STREQ(s.c_str(), ""); ASSERT_EQ(s.data(), s.c_str()); ASSERT_EQ(s.capacity(), size_t(0)); } TEST(LlvmLibcStringTest, InitializeCString) { const char *const str = "abc"; const string s(str); ASSERT_EQ(s.size(), size_t(3)); ASSERT_FALSE(s.empty()); ASSERT_NE(s.data(), &str[0]); ASSERT_EQ(s[0], 'a'); ASSERT_EQ(s[1], 'b'); ASSERT_EQ(s[2], 'c'); ASSERT_EQ(s.front(), 'a'); ASSERT_EQ(s.back(), 'c'); ASSERT_EQ(s.data(), s.c_str()); } TEST(LlvmLibcStringTest, ToCString) { const char *const str = "abc"; string s(str); const char *cstr = s.c_str(); ASSERT_EQ(s.size(), size_t(3)); ASSERT_STREQ(str, cstr); } TEST(LlvmLibcStringTest, ToStringView) { const char *const str = "abc"; string s(str); string_view view = s; ASSERT_EQ(view, string_view(str)); } TEST(LlvmLibcStringTest, InitializeCStringWithSize) { const char *const str = "abc"; const string s(str, 2); ASSERT_EQ(s.size(), size_t(2)); ASSERT_EQ(s[0], 'a'); ASSERT_EQ(s[1], 'b'); ASSERT_EQ(s.front(), 'a'); ASSERT_EQ(s.back(), 'b'); } TEST(LlvmLibcStringTest, InitializeStringView) { const string_view str = "ab"; const string s(str); ASSERT_EQ(s.size(), size_t(2)); ASSERT_EQ(s[0], 'a'); ASSERT_EQ(s[1], 'b'); ASSERT_EQ(s.front(), 'a'); ASSERT_EQ(s.back(), 'b'); } TEST(LlvmLibcStringTest, InitializeRepeatedChar) { const string s(4, '1'); ASSERT_EQ(string_view(s), string_view("1111")); } TEST(LlvmLibcStringTest, InitializeZeorChar) { const string s(0, '1'); ASSERT_TRUE(s.empty()); } TEST(LlvmLibcStringTest, CopyConstruct) { const char *const str = "abc"; string a(str); string b(a); // Same content ASSERT_STREQ(a.c_str(), str); ASSERT_STREQ(b.c_str(), str); // Different pointers ASSERT_NE(a.data(), b.data()); } string &&move(string &value) { return static_cast(value); } TEST(LlvmLibcStringTest, CopyAssign) { const char *const str = "abc"; string a(str); string b; b = a; // Same content ASSERT_STREQ(a.c_str(), str); ASSERT_STREQ(b.c_str(), str); // Different pointers ASSERT_NE(a.data(), b.data()); } TEST(LlvmLibcStringTest, MoveConstruct) { const char *const str = "abc"; string a(str); string b(move(a)); ASSERT_STREQ(b.c_str(), str); ASSERT_STREQ(a.c_str(), ""); } TEST(LlvmLibcStringTest, MoveAssign) { const char *const str = "abc"; string a(str); string b; b = move(a); ASSERT_STREQ(b.c_str(), str); ASSERT_STREQ(a.c_str(), ""); } TEST(LlvmLibcStringTest, StringViewAssign) { const string_view str = "ab"; string s; s = str; ASSERT_EQ(s.size(), size_t(2)); ASSERT_EQ(s[0], 'a'); ASSERT_EQ(s[1], 'b'); ASSERT_EQ(s.front(), 'a'); ASSERT_EQ(s.back(), 'b'); } TEST(LlvmLibcStringTest, Concat) { const char *const str = "abc"; string a(str); string b; b += a; ASSERT_STREQ(b.c_str(), "abc"); b += a; ASSERT_STREQ(b.c_str(), "abcabc"); } TEST(LlvmLibcStringTest, AddChar) { string a; a += 'a'; ASSERT_STREQ(a.c_str(), "a"); a += 'b'; ASSERT_STREQ(a.c_str(), "ab"); } TEST(LlvmLibcStringTest, ResizeCapacityAndNullTermination) { string a; // Empty ASSERT_EQ(a.capacity(), size_t(0)); ASSERT_EQ(a.data()[0], '\0'); // Still empty a.resize(0); ASSERT_EQ(a.capacity(), size_t(0)); ASSERT_EQ(a.data()[0], '\0'); // One char a.resize(1); ASSERT_EQ(a.size(), size_t(1)); ASSERT_GE(a.capacity(), size_t(2)); ASSERT_EQ(a.data()[1], '\0'); // Clear a.resize(0); ASSERT_EQ(a.size(), size_t(0)); ASSERT_GE(a.capacity(), size_t(2)); ASSERT_EQ(a.data()[0], '\0'); // Resize and check zero initialized a.resize(10); ASSERT_EQ(a.size(), size_t(10)); ASSERT_GE(a.capacity(), size_t(10)); for (size_t i = 0; i < 10; ++i) ASSERT_EQ(a[i], '\0'); } TEST(LlvmLibcStringTest, ConcatWithCString) { ASSERT_STREQ((string("a") + string("b")).c_str(), "ab"); ASSERT_STREQ((string("a") + "b").c_str(), "ab"); ASSERT_STREQ(("a" + string("b")).c_str(), "ab"); } TEST(LlvmLibcStringTest, Comparison) { // Here we simply check that comparison of string and string_view have the // same semantic. struct CStringPair { const char *const a; const char *const b; } kTestPairs[] = {{"a", "b"}, {"", "xyz"}}; for (const auto [pa, pb] : kTestPairs) { const string sa(pa); const string sb(pb); const string_view sva(pa); const string_view svb(pb); ASSERT_EQ(sa == sb, sva == svb); ASSERT_EQ(sa != sb, sva != svb); ASSERT_EQ(sa >= sb, sva >= svb); ASSERT_EQ(sa <= sb, sva <= svb); ASSERT_EQ(sa < sb, sva < svb); ASSERT_EQ(sa > sb, sva > svb); } } TEST(LlvmLibcStringTest, ToString) { struct CStringPair { const int value; const string str; } kTestPairs[] = {{123, "123"}, {0, "0"}, {-321, "-321"}}; for (const auto &[value, str] : kTestPairs) { ASSERT_EQ(to_string((int)(value)), str); ASSERT_EQ(to_string((long)(value)), str); ASSERT_EQ(to_string((long long)(value)), str); if (value >= 0) { ASSERT_EQ(to_string((unsigned int)(value)), str); ASSERT_EQ(to_string((unsigned long)(value)), str); ASSERT_EQ(to_string((unsigned long long)(value)), str); } } }