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,EmptyString_Returns0)48 TEST(ClampedCString, EmptyString_Returns0) {
49 EXPECT_TRUE(ClampedCString("", 0).empty());
50 EXPECT_TRUE(ClampedCString("", 100).empty());
51 }
52
TEST(ClampedCString,MaxLongerThanString_ReturnsStr)53 TEST(ClampedCString, MaxLongerThanString_ReturnsStr) {
54 static constexpr char kInput[] = "12345";
55 const std::string_view result = ClampedCString(kInput, 100);
56 EXPECT_EQ(result.size(), strlen(kInput));
57 EXPECT_EQ(result.data(), &kInput[0]);
58 }
59
TEST(ClampedCString,StringMaxLongerThanMax_ClampsView)60 TEST(ClampedCString, StringMaxLongerThanMax_ClampsView) {
61 static constexpr char kInput[] = "12345";
62
63 EXPECT_TRUE(ClampedCString(kInput, 0).empty());
64
65 const std::string_view result = ClampedCString(kInput, 4);
66 EXPECT_EQ(result.size(), 4u);
67 EXPECT_EQ(result.data(), &kInput[0]);
68 }
69
TEST(ClampedCString,FullStringView)70 TEST(ClampedCString, FullStringView) {
71 static constexpr char kInput[] = "12345";
72 const std::string_view result = ClampedCString(kInput);
73 EXPECT_EQ(result.size(), strlen(kInput));
74 EXPECT_EQ(result.data(), &kInput[0]);
75 }
76
TEST(NullTerminatedLength,EmptyString_RequiresNullTerminator)77 TEST(NullTerminatedLength, EmptyString_RequiresNullTerminator) {
78 EXPECT_TRUE(NullTerminatedLength("", 0).status().IsOutOfRange());
79
80 ASSERT_TRUE(NullTerminatedLength("", 100).status().ok());
81 EXPECT_EQ(0u, NullTerminatedLength("", 100).value());
82 }
83
TEST(NullTerminatedLength,MaxLongerThanString_ReturnsStrlen)84 TEST(NullTerminatedLength, MaxLongerThanString_ReturnsStrlen) {
85 ASSERT_TRUE(NullTerminatedLength("12345", 100).status().ok());
86 EXPECT_EQ(5u, NullTerminatedLength("12345", 100).value());
87 }
88
TEST(NullTerminatedLength,StringMaxLongerThanMax_Fails)89 TEST(NullTerminatedLength, StringMaxLongerThanMax_Fails) {
90 EXPECT_TRUE(NullTerminatedLength("12345", 0).status().IsOutOfRange());
91 EXPECT_TRUE(NullTerminatedLength("12345", 4).status().IsOutOfRange());
92 }
93
TEST(NullTerminatedLength,LengthEqualsMax)94 TEST(NullTerminatedLength, LengthEqualsMax) {
95 static constexpr char kInput[] = "12345";
96 ASSERT_TRUE(NullTerminatedLength(kInput).ok());
97 EXPECT_EQ(5u, NullTerminatedLength(kInput).value());
98 }
99
100 class TestWithBuffer : public ::testing::Test {
101 protected:
102 static constexpr char kStartingString[] = "!@#$%^&*()!@#$%^&*()";
103
TestWithBuffer()104 TestWithBuffer() { std::memcpy(buffer_, kStartingString, sizeof(buffer_)); }
105
106 char buffer_[sizeof(kStartingString)];
107 };
108
109 class CopyTest : public TestWithBuffer {};
110
TEST_F(CopyTest,EmptyStringView_WritesNullTerminator)111 TEST_F(CopyTest, EmptyStringView_WritesNullTerminator) {
112 EXPECT_EQ(0u, Copy("", buffer_).size());
113 EXPECT_EQ('\0', buffer_[0]);
114 }
115
TEST_F(CopyTest,EmptyBuffer_WritesNothing)116 TEST_F(CopyTest, EmptyBuffer_WritesNothing) {
117 auto result = Copy("Hello", span(buffer_, 0));
118 EXPECT_EQ(0u, result.size());
119 EXPECT_FALSE(result.ok());
120 EXPECT_STREQ(kStartingString, buffer_);
121 }
122
TEST_F(CopyTest,TooSmall_Truncates)123 TEST_F(CopyTest, TooSmall_Truncates) {
124 auto result = Copy("Hi!", span(buffer_, 3));
125 EXPECT_EQ(2u, result.size());
126 EXPECT_FALSE(result.ok());
127 EXPECT_STREQ("Hi", buffer_);
128 }
129
TEST_F(CopyTest,ExactFit)130 TEST_F(CopyTest, ExactFit) {
131 auto result = Copy("Hi!", span(buffer_, 4));
132 EXPECT_EQ(3u, result.size());
133 EXPECT_TRUE(result.ok());
134 EXPECT_STREQ("Hi!", buffer_);
135 }
136
TEST_F(CopyTest,NullTerminatorsInString)137 TEST_F(CopyTest, NullTerminatorsInString) {
138 ASSERT_EQ(4u, Copy("\0!\0\0"sv, span(buffer_, 5)).size());
139 EXPECT_EQ("\0!\0\0"sv, std::string_view(buffer_, 4));
140 }
141
142 class InlineStringUtilTest : public ::testing::Test {
143 protected:
144 InlineString<5> string_;
145 };
146
TEST_F(InlineStringUtilTest,Assign_EmptyStringView_WritesNullTerminator)147 TEST_F(InlineStringUtilTest, Assign_EmptyStringView_WritesNullTerminator) {
148 EXPECT_EQ(OkStatus(), Assign(string_, ""));
149 EXPECT_EQ(string_, "");
150 }
151
TEST_F(InlineStringUtilTest,Assign_EmptyBuffer_WritesNothing)152 TEST_F(InlineStringUtilTest, Assign_EmptyBuffer_WritesNothing) {
153 InlineString<0> zero_capacity;
154 EXPECT_EQ(Status::ResourceExhausted(), Assign(zero_capacity, "Hello"));
155 EXPECT_TRUE(zero_capacity.empty());
156 EXPECT_EQ(zero_capacity.c_str()[0], '\0');
157 }
158
TEST_F(InlineStringUtilTest,Assign_TooSmall_Truncates)159 TEST_F(InlineStringUtilTest, Assign_TooSmall_Truncates) {
160 EXPECT_EQ(Status::ResourceExhausted(), Assign(string_, "12345HELLO?"));
161 EXPECT_EQ("12345", string_);
162 }
163
TEST_F(InlineStringUtilTest,Assign_ExactFit)164 TEST_F(InlineStringUtilTest, Assign_ExactFit) {
165 EXPECT_EQ(OkStatus(), Assign(string_, "12345"));
166 EXPECT_EQ("12345", string_);
167 }
168
TEST_F(InlineStringUtilTest,Assign_NullTerminatorsInString)169 TEST_F(InlineStringUtilTest, Assign_NullTerminatorsInString) {
170 EXPECT_EQ(OkStatus(), Assign(string_, "\0!\0\0\0"sv));
171 EXPECT_EQ("\0!\0\0\0"sv, string_);
172 }
173
TEST_F(InlineStringUtilTest,Assign_ExistingContent_Replaces)174 TEST_F(InlineStringUtilTest, Assign_ExistingContent_Replaces) {
175 string_ = "12345";
176 EXPECT_EQ(OkStatus(), Assign(string_, ""));
177 EXPECT_EQ("", string_);
178 }
179
TEST_F(InlineStringUtilTest,Assign_ExistingContent_ExactFit)180 TEST_F(InlineStringUtilTest, Assign_ExistingContent_ExactFit) {
181 string_.append("yo");
182 EXPECT_EQ(OkStatus(), Assign(string_, "12345"));
183 EXPECT_EQ("12345", string_);
184 }
185
TEST_F(InlineStringUtilTest,Assign_ExistingContent_Truncates)186 TEST_F(InlineStringUtilTest, Assign_ExistingContent_Truncates) {
187 string_.append("yo");
188 EXPECT_EQ(Status::ResourceExhausted(), Assign(string_, "1234567"));
189 EXPECT_EQ("12345", string_);
190 }
191
TEST_F(InlineStringUtilTest,Append_EmptyStringView_WritesNullTerminator)192 TEST_F(InlineStringUtilTest, Append_EmptyStringView_WritesNullTerminator) {
193 EXPECT_EQ(OkStatus(), Append(string_, ""));
194 EXPECT_EQ(string_, "");
195 }
196
TEST_F(InlineStringUtilTest,Append_EmptyBuffer_WritesNothing)197 TEST_F(InlineStringUtilTest, Append_EmptyBuffer_WritesNothing) {
198 InlineString<0> zero_capacity;
199 EXPECT_EQ(Status::ResourceExhausted(), Append(zero_capacity, "Hello"));
200 EXPECT_TRUE(zero_capacity.empty());
201 EXPECT_EQ(zero_capacity.c_str()[0], '\0');
202 }
203
TEST_F(InlineStringUtilTest,Append_TooSmall_Truncates)204 TEST_F(InlineStringUtilTest, Append_TooSmall_Truncates) {
205 EXPECT_EQ(Status::ResourceExhausted(), Append(string_, "12345HELLO?"));
206 EXPECT_EQ("12345", string_);
207 }
208
TEST_F(InlineStringUtilTest,Append_ExactFit)209 TEST_F(InlineStringUtilTest, Append_ExactFit) {
210 EXPECT_EQ(OkStatus(), Append(string_, "12345"));
211 EXPECT_EQ("12345", string_);
212 }
213
TEST_F(InlineStringUtilTest,Append_NullTerminatorsInString)214 TEST_F(InlineStringUtilTest, Append_NullTerminatorsInString) {
215 EXPECT_EQ(OkStatus(), Append(string_, "\0!\0\0\0"sv));
216 EXPECT_EQ("\0!\0\0\0"sv, string_);
217 }
218
TEST_F(InlineStringUtilTest,Append_ExistingContent_AppendNothing)219 TEST_F(InlineStringUtilTest, Append_ExistingContent_AppendNothing) {
220 string_ = "12345";
221 EXPECT_EQ(OkStatus(), Append(string_, ""));
222 EXPECT_EQ("12345", string_);
223 }
224
TEST_F(InlineStringUtilTest,Append_ExistingContent_ExactFit)225 TEST_F(InlineStringUtilTest, Append_ExistingContent_ExactFit) {
226 string_.append("yo");
227 EXPECT_EQ(OkStatus(), Append(string_, "123"));
228 EXPECT_EQ("yo123", string_);
229 }
230
TEST_F(InlineStringUtilTest,Append_ExistingContent_Truncates)231 TEST_F(InlineStringUtilTest, Append_ExistingContent_Truncates) {
232 string_.append("yo");
233 EXPECT_EQ(Status::ResourceExhausted(), Append(string_, "12345"));
234 EXPECT_EQ("yo123", string_);
235 }
236
237 class PrintableCopyTest : public TestWithBuffer {};
238
TEST_F(PrintableCopyTest,EmptyBuffer_WritesNothing)239 TEST_F(PrintableCopyTest, EmptyBuffer_WritesNothing) {
240 auto result = PrintableCopy("Hello", span(buffer_, 0));
241 EXPECT_EQ(0u, result.size());
242 EXPECT_FALSE(result.ok());
243 EXPECT_STREQ(kStartingString, buffer_);
244 }
245
TEST_F(PrintableCopyTest,TooSmall_Truncates)246 TEST_F(PrintableCopyTest, TooSmall_Truncates) {
247 auto result = PrintableCopy("Hi!", span(buffer_, 3));
248 EXPECT_EQ(2u, result.size());
249 EXPECT_FALSE(result.ok());
250 EXPECT_STREQ("Hi", buffer_);
251 }
252
TEST_F(PrintableCopyTest,ExactFit)253 TEST_F(PrintableCopyTest, ExactFit) {
254 auto result = PrintableCopy("Hi!", span(buffer_, 4));
255 EXPECT_EQ(3u, result.size());
256 EXPECT_TRUE(result.ok());
257 EXPECT_STREQ("Hi!", buffer_);
258 }
259
TEST_F(PrintableCopyTest,StartingString)260 TEST_F(PrintableCopyTest, StartingString) {
261 memset(buffer_, '\0', sizeof(buffer_));
262 auto result = PrintableCopy(kStartingString, span(buffer_));
263 EXPECT_EQ(sizeof(kStartingString) - 1, result.size());
264 EXPECT_TRUE(result.ok());
265 EXPECT_STREQ(kStartingString, buffer_);
266 }
267
TEST_F(PrintableCopyTest,NullTerminatorsInString)268 TEST_F(PrintableCopyTest, NullTerminatorsInString) {
269 ASSERT_EQ(4u, PrintableCopy("\0!\0\0"sv, span(buffer_, 5)).size());
270 EXPECT_STREQ(".!..", buffer_);
271 }
272
TEST_F(PrintableCopyTest,ControlCharsInString)273 TEST_F(PrintableCopyTest, ControlCharsInString) {
274 ASSERT_EQ(
275 14u,
276 PrintableCopy("\n!\t\n\x10\x7F\xFF\vabcd\b\r"sv, span(buffer_)).size());
277 EXPECT_STREQ(".!......abcd..", buffer_);
278 }
279
280 } // namespace
281 } // namespace pw::string
282