1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_string/util.h"
16
17 #include <cstring>
18
19 #include "pw_unit_test/framework.h"
20
21 namespace pw::string {
22 namespace {
23
24 using namespace std::literals::string_view_literals;
25
TEST(ClampedLength,Nullptr_Returns0)26 TEST(ClampedLength, Nullptr_Returns0) {
27 EXPECT_EQ(0u, internal::ClampedLength(nullptr, 100));
28 }
29
TEST(ClampedLength,EmptyString_Returns0)30 TEST(ClampedLength, EmptyString_Returns0) {
31 EXPECT_EQ(0u, internal::ClampedLength("", 0));
32 EXPECT_EQ(0u, internal::ClampedLength("", 100));
33 }
34
TEST(ClampedLength,MaxLongerThanString_ReturnsStrlen)35 TEST(ClampedLength, MaxLongerThanString_ReturnsStrlen) {
36 EXPECT_EQ(5u, internal::ClampedLength("12345", 100));
37 }
38
TEST(ClampedLength,StringMaxLongerThanMax_ReturnsMax)39 TEST(ClampedLength, StringMaxLongerThanMax_ReturnsMax) {
40 EXPECT_EQ(0u, internal::ClampedLength("12345", 0));
41 EXPECT_EQ(4u, internal::ClampedLength("12345", 4));
42 }
43
TEST(ClampedLength,LengthEqualsMax)44 TEST(ClampedLength, LengthEqualsMax) {
45 EXPECT_EQ(5u, internal::ClampedLength("12345", 5));
46 }
47
TEST(ClampedCString,NullPtr_ReturnsEmpty)48 TEST(ClampedCString, NullPtr_ReturnsEmpty) {
49 EXPECT_TRUE(ClampedCString(nullptr, 100).empty());
50 }
51
TEST(ClampedCString,EmptyString_Returns0)52 TEST(ClampedCString, EmptyString_Returns0) {
53 EXPECT_TRUE(ClampedCString("", 0).empty());
54 EXPECT_TRUE(ClampedCString("", 100).empty());
55 }
56
TEST(ClampedCString,MaxLongerThanString_ReturnsStr)57 TEST(ClampedCString, MaxLongerThanString_ReturnsStr) {
58 static constexpr char kInput[] = "12345";
59 const std::string_view result = ClampedCString(kInput, 100);
60 EXPECT_EQ(result.size(), strlen(kInput));
61 EXPECT_EQ(result.data(), &kInput[0]);
62 }
63
TEST(ClampedCString,StringMaxLongerThanMax_ClampsView)64 TEST(ClampedCString, StringMaxLongerThanMax_ClampsView) {
65 static constexpr char kInput[] = "12345";
66
67 EXPECT_TRUE(ClampedCString(kInput, 0).empty());
68
69 const std::string_view result = ClampedCString(kInput, 4);
70 EXPECT_EQ(result.size(), 4u);
71 EXPECT_EQ(result.data(), &kInput[0]);
72 }
73
TEST(ClampedCString,FullStringView)74 TEST(ClampedCString, FullStringView) {
75 static constexpr char kInput[] = "12345";
76 const std::string_view result = ClampedCString(kInput);
77 EXPECT_EQ(result.size(), strlen(kInput));
78 EXPECT_EQ(result.data(), &kInput[0]);
79 }
80
TEST(NullTerminatedLength,EmptyString_RequiresNullTerminator)81 TEST(NullTerminatedLength, EmptyString_RequiresNullTerminator) {
82 EXPECT_TRUE(NullTerminatedLength("", 0).status().IsOutOfRange());
83
84 ASSERT_TRUE(NullTerminatedLength("", 100).status().ok());
85 EXPECT_EQ(0u, NullTerminatedLength("", 100).value());
86 }
87
TEST(NullTerminatedLength,MaxLongerThanString_ReturnsStrlen)88 TEST(NullTerminatedLength, MaxLongerThanString_ReturnsStrlen) {
89 ASSERT_TRUE(NullTerminatedLength("12345", 100).status().ok());
90 EXPECT_EQ(5u, NullTerminatedLength("12345", 100).value());
91 }
92
TEST(NullTerminatedLength,StringMaxLongerThanMax_Fails)93 TEST(NullTerminatedLength, StringMaxLongerThanMax_Fails) {
94 EXPECT_TRUE(NullTerminatedLength("12345", 0).status().IsOutOfRange());
95 EXPECT_TRUE(NullTerminatedLength("12345", 4).status().IsOutOfRange());
96 }
97
TEST(NullTerminatedLength,LengthEqualsMax)98 TEST(NullTerminatedLength, LengthEqualsMax) {
99 static constexpr char kInput[] = "12345";
100 ASSERT_TRUE(NullTerminatedLength(kInput).ok());
101 EXPECT_EQ(5u, NullTerminatedLength(kInput).value());
102 }
103
104 class TestWithBuffer : public ::testing::Test {
105 protected:
106 static constexpr char kStartingString[] = "!@#$%^&*()!@#$%^&*()";
107
TestWithBuffer()108 TestWithBuffer() { std::memcpy(buffer_, kStartingString, sizeof(buffer_)); }
109
110 char buffer_[sizeof(kStartingString)];
111 };
112
113 class CopyTest : public TestWithBuffer {};
114
TEST_F(CopyTest,EmptyStringView_WritesNullTerminator)115 TEST_F(CopyTest, EmptyStringView_WritesNullTerminator) {
116 EXPECT_EQ(0u, Copy("", buffer_).size());
117 EXPECT_EQ('\0', buffer_[0]);
118 }
119
TEST_F(CopyTest,EmptyBuffer_WritesNothing)120 TEST_F(CopyTest, EmptyBuffer_WritesNothing) {
121 auto result = Copy("Hello", span(buffer_, 0));
122 EXPECT_EQ(0u, result.size());
123 EXPECT_FALSE(result.ok());
124 EXPECT_STREQ(kStartingString, buffer_);
125 }
126
TEST_F(CopyTest,TooSmall_Truncates)127 TEST_F(CopyTest, TooSmall_Truncates) {
128 auto result = Copy("Hi!", span(buffer_, 3));
129 EXPECT_EQ(2u, result.size());
130 EXPECT_FALSE(result.ok());
131 EXPECT_STREQ("Hi", buffer_);
132 }
133
TEST_F(CopyTest,ExactFit)134 TEST_F(CopyTest, ExactFit) {
135 auto result = Copy("Hi!", span(buffer_, 4));
136 EXPECT_EQ(3u, result.size());
137 EXPECT_TRUE(result.ok());
138 EXPECT_STREQ("Hi!", buffer_);
139 }
140
TEST_F(CopyTest,NullTerminatorsInString)141 TEST_F(CopyTest, NullTerminatorsInString) {
142 ASSERT_EQ(4u, Copy("\0!\0\0"sv, span(buffer_, 5)).size());
143 EXPECT_EQ("\0!\0\0"sv, std::string_view(buffer_, 4));
144 }
145
146 class InlineStringUtilTest : public ::testing::Test {
147 protected:
148 InlineString<5> string_;
149 };
150
TEST_F(InlineStringUtilTest,Assign_EmptyStringView_WritesNullTerminator)151 TEST_F(InlineStringUtilTest, Assign_EmptyStringView_WritesNullTerminator) {
152 EXPECT_EQ(OkStatus(), Assign(string_, ""));
153 EXPECT_EQ(string_, "");
154 }
155
TEST_F(InlineStringUtilTest,Assign_EmptyBuffer_WritesNothing)156 TEST_F(InlineStringUtilTest, Assign_EmptyBuffer_WritesNothing) {
157 InlineString<0> zero_capacity;
158 EXPECT_EQ(Status::ResourceExhausted(), Assign(zero_capacity, "Hello"));
159 EXPECT_TRUE(zero_capacity.empty());
160 EXPECT_EQ(zero_capacity.c_str()[0], '\0');
161 }
162
TEST_F(InlineStringUtilTest,Assign_TooSmall_Truncates)163 TEST_F(InlineStringUtilTest, Assign_TooSmall_Truncates) {
164 EXPECT_EQ(Status::ResourceExhausted(), Assign(string_, "12345HELLO?"));
165 EXPECT_EQ("12345", string_);
166 }
167
TEST_F(InlineStringUtilTest,Assign_ExactFit)168 TEST_F(InlineStringUtilTest, Assign_ExactFit) {
169 EXPECT_EQ(OkStatus(), Assign(string_, "12345"));
170 EXPECT_EQ("12345", string_);
171 }
172
TEST_F(InlineStringUtilTest,Assign_NullTerminatorsInString)173 TEST_F(InlineStringUtilTest, Assign_NullTerminatorsInString) {
174 EXPECT_EQ(OkStatus(), Assign(string_, "\0!\0\0\0"sv));
175 EXPECT_EQ("\0!\0\0\0"sv, string_);
176 }
177
TEST_F(InlineStringUtilTest,Assign_ExistingContent_Replaces)178 TEST_F(InlineStringUtilTest, Assign_ExistingContent_Replaces) {
179 string_ = "12345";
180 EXPECT_EQ(OkStatus(), Assign(string_, ""));
181 EXPECT_EQ("", string_);
182 }
183
TEST_F(InlineStringUtilTest,Assign_ExistingContent_ExactFit)184 TEST_F(InlineStringUtilTest, Assign_ExistingContent_ExactFit) {
185 string_.append("yo");
186 EXPECT_EQ(OkStatus(), Assign(string_, "12345"));
187 EXPECT_EQ("12345", string_);
188 }
189
TEST_F(InlineStringUtilTest,Assign_ExistingContent_Truncates)190 TEST_F(InlineStringUtilTest, Assign_ExistingContent_Truncates) {
191 string_.append("yo");
192 EXPECT_EQ(Status::ResourceExhausted(), Assign(string_, "1234567"));
193 EXPECT_EQ("12345", string_);
194 }
195
TEST_F(InlineStringUtilTest,Append_EmptyStringView_WritesNullTerminator)196 TEST_F(InlineStringUtilTest, Append_EmptyStringView_WritesNullTerminator) {
197 EXPECT_EQ(OkStatus(), Append(string_, ""));
198 EXPECT_EQ(string_, "");
199 }
200
TEST_F(InlineStringUtilTest,Append_EmptyBuffer_WritesNothing)201 TEST_F(InlineStringUtilTest, Append_EmptyBuffer_WritesNothing) {
202 InlineString<0> zero_capacity;
203 EXPECT_EQ(Status::ResourceExhausted(), Append(zero_capacity, "Hello"));
204 EXPECT_TRUE(zero_capacity.empty());
205 EXPECT_EQ(zero_capacity.c_str()[0], '\0');
206 }
207
TEST_F(InlineStringUtilTest,Append_TooSmall_Truncates)208 TEST_F(InlineStringUtilTest, Append_TooSmall_Truncates) {
209 EXPECT_EQ(Status::ResourceExhausted(), Append(string_, "12345HELLO?"));
210 EXPECT_EQ("12345", string_);
211 }
212
TEST_F(InlineStringUtilTest,Append_ExactFit)213 TEST_F(InlineStringUtilTest, Append_ExactFit) {
214 EXPECT_EQ(OkStatus(), Append(string_, "12345"));
215 EXPECT_EQ("12345", string_);
216 }
217
TEST_F(InlineStringUtilTest,Append_NullTerminatorsInString)218 TEST_F(InlineStringUtilTest, Append_NullTerminatorsInString) {
219 EXPECT_EQ(OkStatus(), Append(string_, "\0!\0\0\0"sv));
220 EXPECT_EQ("\0!\0\0\0"sv, string_);
221 }
222
TEST_F(InlineStringUtilTest,Append_ExistingContent_AppendNothing)223 TEST_F(InlineStringUtilTest, Append_ExistingContent_AppendNothing) {
224 string_ = "12345";
225 EXPECT_EQ(OkStatus(), Append(string_, ""));
226 EXPECT_EQ("12345", string_);
227 }
228
TEST_F(InlineStringUtilTest,Append_ExistingContent_ExactFit)229 TEST_F(InlineStringUtilTest, Append_ExistingContent_ExactFit) {
230 string_.append("yo");
231 EXPECT_EQ(OkStatus(), Append(string_, "123"));
232 EXPECT_EQ("yo123", string_);
233 }
234
TEST_F(InlineStringUtilTest,Append_ExistingContent_Truncates)235 TEST_F(InlineStringUtilTest, Append_ExistingContent_Truncates) {
236 string_.append("yo");
237 EXPECT_EQ(Status::ResourceExhausted(), Append(string_, "12345"));
238 EXPECT_EQ("yo123", string_);
239 }
240
241 class PrintableCopyTest : public TestWithBuffer {};
242
TEST_F(PrintableCopyTest,EmptyBuffer_WritesNothing)243 TEST_F(PrintableCopyTest, EmptyBuffer_WritesNothing) {
244 auto result = PrintableCopy("Hello", span(buffer_, 0));
245 EXPECT_EQ(0u, result.size());
246 EXPECT_FALSE(result.ok());
247 EXPECT_STREQ(kStartingString, buffer_);
248 }
249
TEST_F(PrintableCopyTest,TooSmall_Truncates)250 TEST_F(PrintableCopyTest, TooSmall_Truncates) {
251 auto result = PrintableCopy("Hi!", span(buffer_, 3));
252 EXPECT_EQ(2u, result.size());
253 EXPECT_FALSE(result.ok());
254 EXPECT_STREQ("Hi", buffer_);
255 }
256
TEST_F(PrintableCopyTest,ExactFit)257 TEST_F(PrintableCopyTest, ExactFit) {
258 auto result = PrintableCopy("Hi!", span(buffer_, 4));
259 EXPECT_EQ(3u, result.size());
260 EXPECT_TRUE(result.ok());
261 EXPECT_STREQ("Hi!", buffer_);
262 }
263
TEST_F(PrintableCopyTest,StartingString)264 TEST_F(PrintableCopyTest, StartingString) {
265 memset(buffer_, '\0', sizeof(buffer_));
266 auto result = PrintableCopy(kStartingString, span(buffer_));
267 EXPECT_EQ(sizeof(kStartingString) - 1, result.size());
268 EXPECT_TRUE(result.ok());
269 EXPECT_STREQ(kStartingString, buffer_);
270 }
271
TEST_F(PrintableCopyTest,NullTerminatorsInString)272 TEST_F(PrintableCopyTest, NullTerminatorsInString) {
273 ASSERT_EQ(4u, PrintableCopy("\0!\0\0"sv, span(buffer_, 5)).size());
274 EXPECT_STREQ(".!..", buffer_);
275 }
276
TEST_F(PrintableCopyTest,ControlCharsInString)277 TEST_F(PrintableCopyTest, ControlCharsInString) {
278 ASSERT_EQ(
279 14u,
280 PrintableCopy("\n!\t\n\x10\x7F\xFF\vabcd\b\r"sv, span(buffer_)).size());
281 EXPECT_STREQ(".!......abcd..", buffer_);
282 }
283
284 } // namespace
285 } // namespace pw::string
286