1 | //===-- Unittests for string ----------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "src/__support/CPP/string.h" |
10 | #include "test/UnitTest/Test.h" |
11 | |
12 | using LIBC_NAMESPACE::cpp::string; |
13 | using LIBC_NAMESPACE::cpp::string_view; |
14 | using LIBC_NAMESPACE::cpp::to_string; |
15 | |
16 | TEST(LlvmLibcStringTest, InitializeEmpty) { |
17 | const string s; |
18 | ASSERT_EQ(s.size(), size_t(0)); |
19 | ASSERT_TRUE(s.empty()); |
20 | ASSERT_STREQ(s.data(), "" ); |
21 | ASSERT_STREQ(s.c_str(), "" ); |
22 | ASSERT_EQ(s.data(), s.c_str()); |
23 | ASSERT_EQ(s.capacity(), size_t(0)); |
24 | } |
25 | |
26 | TEST(LlvmLibcStringTest, InitializeCString) { |
27 | const char *const str = "abc" ; |
28 | const string s(str); |
29 | ASSERT_EQ(s.size(), size_t(3)); |
30 | ASSERT_FALSE(s.empty()); |
31 | ASSERT_NE(s.data(), &str[0]); |
32 | ASSERT_EQ(s[0], 'a'); |
33 | ASSERT_EQ(s[1], 'b'); |
34 | ASSERT_EQ(s[2], 'c'); |
35 | ASSERT_EQ(s.front(), 'a'); |
36 | ASSERT_EQ(s.back(), 'c'); |
37 | ASSERT_EQ(s.data(), s.c_str()); |
38 | } |
39 | |
40 | TEST(LlvmLibcStringTest, ToCString) { |
41 | const char *const str = "abc" ; |
42 | string s(str); |
43 | const char *cstr = s.c_str(); |
44 | ASSERT_EQ(s.size(), size_t(3)); |
45 | ASSERT_STREQ(str, cstr); |
46 | } |
47 | |
48 | TEST(LlvmLibcStringTest, ToStringView) { |
49 | const char *const str = "abc" ; |
50 | string s(str); |
51 | string_view view = s; |
52 | ASSERT_EQ(view, string_view(str)); |
53 | } |
54 | |
55 | TEST(LlvmLibcStringTest, InitializeCStringWithSize) { |
56 | const char *const str = "abc" ; |
57 | const string s(str, 2); |
58 | ASSERT_EQ(s.size(), size_t(2)); |
59 | ASSERT_EQ(s[0], 'a'); |
60 | ASSERT_EQ(s[1], 'b'); |
61 | ASSERT_EQ(s.front(), 'a'); |
62 | ASSERT_EQ(s.back(), 'b'); |
63 | } |
64 | |
65 | TEST(LlvmLibcStringTest, InitializeStringView) { |
66 | const string_view str = "ab" ; |
67 | const string s(str); |
68 | ASSERT_EQ(s.size(), size_t(2)); |
69 | ASSERT_EQ(s[0], 'a'); |
70 | ASSERT_EQ(s[1], 'b'); |
71 | ASSERT_EQ(s.front(), 'a'); |
72 | ASSERT_EQ(s.back(), 'b'); |
73 | } |
74 | |
75 | TEST(LlvmLibcStringTest, InitializeRepeatedChar) { |
76 | const string s(4, '1'); |
77 | ASSERT_EQ(string_view(s), string_view("1111" )); |
78 | } |
79 | |
80 | TEST(LlvmLibcStringTest, InitializeZeorChar) { |
81 | const string s(0, '1'); |
82 | ASSERT_TRUE(s.empty()); |
83 | } |
84 | |
85 | TEST(LlvmLibcStringTest, CopyConstruct) { |
86 | const char *const str = "abc" ; |
87 | string a(str); |
88 | string b(a); |
89 | // Same content |
90 | ASSERT_STREQ(a.c_str(), str); |
91 | ASSERT_STREQ(b.c_str(), str); |
92 | // Different pointers |
93 | ASSERT_NE(a.data(), b.data()); |
94 | } |
95 | |
96 | string &&move(string &value) { return static_cast<string &&>(value); } |
97 | |
98 | TEST(LlvmLibcStringTest, CopyAssign) { |
99 | const char *const str = "abc" ; |
100 | string a(str); |
101 | string b; |
102 | b = a; |
103 | // Same content |
104 | ASSERT_STREQ(a.c_str(), str); |
105 | ASSERT_STREQ(b.c_str(), str); |
106 | // Different pointers |
107 | ASSERT_NE(a.data(), b.data()); |
108 | } |
109 | |
110 | TEST(LlvmLibcStringTest, MoveConstruct) { |
111 | const char *const str = "abc" ; |
112 | string a(str); |
113 | string b(move(value&: a)); |
114 | ASSERT_STREQ(b.c_str(), str); |
115 | ASSERT_STREQ(a.c_str(), "" ); |
116 | } |
117 | |
118 | TEST(LlvmLibcStringTest, MoveAssign) { |
119 | const char *const str = "abc" ; |
120 | string a(str); |
121 | string b; |
122 | b = move(value&: a); |
123 | ASSERT_STREQ(b.c_str(), str); |
124 | ASSERT_STREQ(a.c_str(), "" ); |
125 | } |
126 | |
127 | TEST(LlvmLibcStringTest, StringViewAssign) { |
128 | const string_view str = "ab" ; |
129 | string s; |
130 | s = str; |
131 | ASSERT_EQ(s.size(), size_t(2)); |
132 | ASSERT_EQ(s[0], 'a'); |
133 | ASSERT_EQ(s[1], 'b'); |
134 | ASSERT_EQ(s.front(), 'a'); |
135 | ASSERT_EQ(s.back(), 'b'); |
136 | } |
137 | |
138 | TEST(LlvmLibcStringTest, Concat) { |
139 | const char *const str = "abc" ; |
140 | string a(str); |
141 | string b; |
142 | b += a; |
143 | ASSERT_STREQ(b.c_str(), "abc" ); |
144 | b += a; |
145 | ASSERT_STREQ(b.c_str(), "abcabc" ); |
146 | } |
147 | |
148 | TEST(LlvmLibcStringTest, AddChar) { |
149 | string a; |
150 | a += 'a'; |
151 | ASSERT_STREQ(a.c_str(), "a" ); |
152 | a += 'b'; |
153 | ASSERT_STREQ(a.c_str(), "ab" ); |
154 | } |
155 | |
156 | TEST(LlvmLibcStringTest, ResizeCapacityAndNullTermination) { |
157 | string a; |
158 | // Empty |
159 | ASSERT_EQ(a.capacity(), size_t(0)); |
160 | ASSERT_EQ(a.data()[0], '\0'); |
161 | // Still empty |
162 | a.resize(size: 0); |
163 | ASSERT_EQ(a.capacity(), size_t(0)); |
164 | ASSERT_EQ(a.data()[0], '\0'); |
165 | // One char |
166 | a.resize(size: 1); |
167 | ASSERT_EQ(a.size(), size_t(1)); |
168 | ASSERT_GE(a.capacity(), size_t(2)); |
169 | ASSERT_EQ(a.data()[1], '\0'); |
170 | // Clear |
171 | a.resize(size: 0); |
172 | ASSERT_EQ(a.size(), size_t(0)); |
173 | ASSERT_GE(a.capacity(), size_t(2)); |
174 | ASSERT_EQ(a.data()[0], '\0'); |
175 | // Resize and check zero initialized |
176 | a.resize(size: 10); |
177 | ASSERT_EQ(a.size(), size_t(10)); |
178 | ASSERT_GE(a.capacity(), size_t(10)); |
179 | for (size_t i = 0; i < 10; ++i) |
180 | ASSERT_EQ(a[i], '\0'); |
181 | } |
182 | |
183 | TEST(LlvmLibcStringTest, ConcatWithCString) { |
184 | ASSERT_STREQ((string("a" ) + string("b" )).c_str(), "ab" ); |
185 | ASSERT_STREQ((string("a" ) + "b" ).c_str(), "ab" ); |
186 | ASSERT_STREQ(("a" + string("b" )).c_str(), "ab" ); |
187 | } |
188 | |
189 | TEST(LlvmLibcStringTest, Comparison) { |
190 | // Here we simply check that comparison of string and string_view have the |
191 | // same semantic. |
192 | struct CStringPair { |
193 | const char *const a; |
194 | const char *const b; |
195 | } kTestPairs[] = {{.a: "a" , .b: "b" }, {.a: "" , .b: "xyz" }}; |
196 | for (const auto [pa, pb] : kTestPairs) { |
197 | const string sa(pa); |
198 | const string sb(pb); |
199 | const string_view sva(pa); |
200 | const string_view svb(pb); |
201 | ASSERT_EQ(sa == sb, sva == svb); |
202 | ASSERT_EQ(sa != sb, sva != svb); |
203 | ASSERT_EQ(sa >= sb, sva >= svb); |
204 | ASSERT_EQ(sa <= sb, sva <= svb); |
205 | ASSERT_EQ(sa < sb, sva < svb); |
206 | ASSERT_EQ(sa > sb, sva > svb); |
207 | } |
208 | } |
209 | |
210 | TEST(LlvmLibcStringTest, ToString) { |
211 | struct CStringPair { |
212 | const int value; |
213 | const string str; |
214 | } kTestPairs[] = {{.value: 123, .str: "123" }, {.value: 0, .str: "0" }, {.value: -321, .str: "-321" }}; |
215 | for (const auto &[value, str] : kTestPairs) { |
216 | ASSERT_EQ(to_string((int)(value)), str); |
217 | ASSERT_EQ(to_string((long)(value)), str); |
218 | ASSERT_EQ(to_string((long long)(value)), str); |
219 | if (value >= 0) { |
220 | ASSERT_EQ(to_string((unsigned int)(value)), str); |
221 | ASSERT_EQ(to_string((unsigned long)(value)), str); |
222 | ASSERT_EQ(to_string((unsigned long long)(value)), str); |
223 | } |
224 | } |
225 | } |
226 | |