Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_string / string_builder_test.cc
1 // Copyright 2019 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/string_builder.h"
16
17 #include <cinttypes>
18 #include <cmath>
19 #include <cstdint>
20 #include <cstring>
21 #include <span>
22 #include <string_view>
23
24 #include "gtest/gtest.h"
25 #include "pw_string/format.h"
26
27 namespace this_pw_test {
28
29 struct CustomType {
30   uint32_t a;
31   uint32_t b;
32
33   static constexpr const char* kToString = "This is a CustomType";
34
35   CustomType() = default;
36
37   // Non-copyable to verify StringBuffer's << operator doesn't copy it.
38   CustomType(const CustomType&) = delete;
39   CustomType& operator=(const CustomType&) = delete;
40 };
41
42 }  // namespace this_pw_test
43
44 namespace pw {
45
46 template <>
47 StatusWithSize ToString<this_pw_test::CustomType>(
48     const this_pw_test::CustomType&, std::span<char> buffer) {
49   return string::Format(buffer, this_pw_test::CustomType::kToString);
50 }
51
52 }  // namespace pw
53
54 namespace pw {
55 namespace {
56
57 using this_pw_test::CustomType;
58
59 TEST(StringBuilder, EmptyBuffer_SizeAndMaxSizeAreCorrect) {
60   StringBuilder sb(std::span<char>{});
61
62   EXPECT_TRUE(sb.empty());
63   EXPECT_EQ(0u, sb.size());
64   EXPECT_EQ(0u, sb.max_size());
65 }
66
67 using namespace std::literals::string_view_literals;
68
69 constexpr std::string_view kNoTouch = "DO NOT TOUCH\0VALUE SHOULD NOT CHANGE"sv;
70
71 TEST(StringBuilder, EmptyBuffer_StreamOutput_WritesNothing) {
72   char buffer[kNoTouch.size()];
73   std::memcpy(buffer, kNoTouch.data(), sizeof(buffer));
74
75   StringBuilder sb(std::span(buffer, 0));
76
77   sb << CustomType() << " is " << 12345;
78   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
79   EXPECT_EQ(kNoTouch, std::string_view(buffer, sizeof(buffer)));
80 }
81
82 TEST(StringBuilder, EmptyBuffer_Append_WritesNothing) {
83   char buffer[kNoTouch.size()];
84   std::memcpy(buffer, kNoTouch.data(), sizeof(buffer));
85
86   StringBuilder sb(std::span(buffer, 0));
87
88   EXPECT_FALSE(sb.append("Hello").ok());
89   EXPECT_EQ(kNoTouch, std::string_view(buffer, sizeof(buffer)));
90 }
91
92 TEST(StringBuilder, EmptyBuffer_Resize_WritesNothing) {
93   char buffer[kNoTouch.size()];
94   std::memcpy(buffer, kNoTouch.data(), sizeof(buffer));
95
96   StringBuilder sb(std::span(buffer, 0));
97
98   sb.resize(0);
99   EXPECT_TRUE(sb.ok());
100   EXPECT_EQ(kNoTouch, std::string_view(buffer, sizeof(buffer)));
101 }
102
103 TEST(StringBuilder, EmptyBuffer_AppendEmpty_ResourceExhausted) {
104   StringBuilder sb(std::span<char>{});
105   EXPECT_EQ(OkStatus(), sb.last_status());
106   EXPECT_EQ(OkStatus(), sb.status());
107
108   sb << "";
109
110   EXPECT_EQ(Status::ResourceExhausted(), sb.last_status());
111   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
112 }
113
114 TEST(StringBuilder, Status_StartsOk) {
115   StringBuffer<16> sb;
116   EXPECT_EQ(OkStatus(), sb.status());
117   EXPECT_EQ(OkStatus(), sb.last_status());
118 }
119
120 TEST(StringBuilder, Status_StatusAndLastStatusUpdate) {
121   StringBuffer<16> sb;
122   sb << "Well, if only there were enough room in here for this string";
123   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
124   EXPECT_EQ(Status::ResourceExhausted(), sb.last_status());
125
126   sb.resize(1029);
127   EXPECT_EQ(Status::OutOfRange(), sb.status());
128   EXPECT_EQ(Status::OutOfRange(), sb.last_status());
129
130   sb << "";
131   EXPECT_EQ(Status::OutOfRange(), sb.status());
132   EXPECT_EQ(OkStatus(), sb.last_status());
133 }
134
135 TEST(StringBuilder, Status_ClearStatus_SetsStatuesToOk) {
136   StringBuffer<2> sb = MakeString<2>("Won't fit!!!!!");
137   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
138   EXPECT_EQ(Status::ResourceExhausted(), sb.last_status());
139
140   sb.clear_status();
141   EXPECT_EQ(OkStatus(), sb.status());
142   EXPECT_EQ(OkStatus(), sb.last_status());
143 }
144
145 TEST(StringBuilder, StreamOutput_OutputSelf) {
146   auto sb = MakeString<32>("echo!");
147   sb << sb;
148
149   EXPECT_STREQ("echo!echo!", sb.data());
150   EXPECT_EQ(10u, sb.size());
151 }
152
153 TEST(StringBuilder, PushBack) {
154   StringBuffer<12> sb;
155   sb.push_back('?');
156   EXPECT_EQ(OkStatus(), sb.last_status());
157   EXPECT_EQ(1u, sb.size());
158   EXPECT_STREQ("?", sb.data());
159 }
160
161 TEST(StringBuilder, PushBack_Full) {
162   StringBuffer<1> sb;
163   sb.push_back('!');
164   EXPECT_EQ(Status::ResourceExhausted(), sb.last_status());
165   EXPECT_EQ(0u, sb.size());
166 }
167
168 TEST(StringBuilder, PopBack) {
169   auto sb = MakeString<12>("Welcome!");
170   sb.pop_back();
171   EXPECT_EQ(OkStatus(), sb.last_status());
172   EXPECT_EQ(7u, sb.size());
173   EXPECT_STREQ("Welcome", sb.data());
174 }
175
176 TEST(StringBuilder, PopBack_Empty) {
177   StringBuffer<12> sb;
178   sb.pop_back();
179   EXPECT_EQ(Status::OutOfRange(), sb.last_status());
180   EXPECT_EQ(0u, sb.size());
181 }
182
183 TEST(StringBuilder, Append_NonTerminatedString) {
184   static char bad_string[256];
185   std::memset(bad_string, '?', sizeof(bad_string));
186
187   StringBuffer<6> sb;
188   EXPECT_EQ(Status::ResourceExhausted(), sb.append(bad_string).last_status());
189   EXPECT_STREQ("?????", sb.data());
190 }
191
192 TEST(StringBuilder, Append_Chars) {
193   StringBuffer<8> sb;
194
195   EXPECT_TRUE(sb.append(7, '?').ok());
196   EXPECT_STREQ("???????", sb.data());
197 }
198
199 TEST(StringBuilder, Append_Chars_Full) {
200   StringBuffer<8> sb;
201
202   EXPECT_EQ(Status::ResourceExhausted(), sb.append(8, '?').last_status());
203   EXPECT_STREQ("???????", sb.data());
204 }
205
206 TEST(StringBuilder, Append_PartialCString) {
207   StringBuffer<12> sb;
208   EXPECT_TRUE(sb.append("123456", 4).ok());
209   EXPECT_EQ(4u, sb.size());
210   EXPECT_STREQ("1234", sb.data());
211 }
212
213 TEST(StringBuilder, Append_CString) {
214   auto sb = MakeString("hello");
215   EXPECT_TRUE(sb.append(" goodbye").ok());
216   EXPECT_STREQ("hello goodbye", sb.data());
217   EXPECT_EQ(13u, sb.size());
218 }
219
220 TEST(StringBuilder, Append_CString_Full) {
221   auto sb = MakeString<6>("hello");
222   EXPECT_EQ(Status::ResourceExhausted(), sb.append("890123", 1).last_status());
223   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
224   EXPECT_EQ(sb.max_size(), sb.size());
225   EXPECT_STREQ("hello", sb.data());
226 }
227
228 TEST(StringBuilder, Append_StringView) {
229   auto sb = MakeString<32>("hello");
230   EXPECT_TRUE(sb.append("???"sv).ok());
231   EXPECT_EQ("hello???"sv, sb);
232 }
233
234 TEST(StringBuilder, Append_StringView_Substring) {
235   auto sb = MakeString<32>("I like ");
236   EXPECT_TRUE(sb.append("your shoes!!!"sv, 5, 5).ok());
237   EXPECT_EQ("I like shoes"sv, sb);
238 }
239
240 TEST(StringBuilder, Append_StringView_RemainingSubstring) {
241   auto sb = MakeString<32>("I like ");
242   EXPECT_TRUE(sb.append("your shoes!!!"sv, 5).ok());
243   EXPECT_EQ("I like shoes!!!"sv, sb);
244 }
245
246 TEST(StringBuilder, Resize_Smaller) {
247   auto sb = MakeString<12>("Four");
248   sb.resize(2);
249   EXPECT_TRUE(sb.ok());
250   EXPECT_EQ(2u, sb.size());
251   EXPECT_STREQ("Fo", sb.data());
252 }
253
254 TEST(StringBuilder, Resize_Clear) {
255   auto sb = MakeString<12>("Four");
256   sb.resize(0);
257   EXPECT_TRUE(sb.ok());
258   EXPECT_EQ(0u, sb.size());
259   EXPECT_STREQ("", sb.data());
260 }
261
262 TEST(StringBuilder, Resize_Larger_Fails) {
263   auto sb = MakeString<12>("Four");
264   EXPECT_EQ(4u, sb.size());
265   sb.resize(10);
266   EXPECT_EQ(sb.status(), Status::OutOfRange());
267   EXPECT_EQ(4u, sb.size());
268 }
269
270 TEST(StringBuilder, Resize_LargerThanCapacity_Fails) {
271   auto sb = MakeString<12>("Four");
272   sb.resize(1234);
273   EXPECT_EQ(sb.status(), Status::OutOfRange());
274   EXPECT_EQ(4u, sb.size());
275   EXPECT_STREQ("Four", sb.data());
276 }
277
278 TEST(StringBuilder, Format_Normal) {
279   std::byte buffer[64];
280   StringBuilder sb(buffer);
281   EXPECT_TRUE(sb.Format("0x%x", 0xabc).ok());
282   EXPECT_STREQ("0xabc", sb.data());
283
284   sb << "def";
285
286   EXPECT_TRUE(sb.Format("GHI").ok());
287   EXPECT_STREQ("0xabcdefGHI", sb.data());
288 }
289
290 TEST(StringBuilder, Format_ExhaustBuffer) {
291   StringBuffer<6> sb;
292   EXPECT_EQ(Status::ResourceExhausted(), sb.Format("012345").status());
293
294   EXPECT_STREQ("01234", sb.data());
295   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
296 }
297
298 TEST(StringBuilder, StreamOutput_MultipleTypes) {
299   constexpr const char* kExpected = "This is -1true example\n of this";
300   constexpr const char* kExample = "example";
301
302   StringBuffer<64> sb;
303   sb << "This is " << -1 << true << ' ' << kExample << '\n' << " of this";
304
305   EXPECT_STREQ(kExpected, sb.data());
306   EXPECT_EQ(std::strlen(kExpected), sb.size());
307 }
308
309 TEST(StringBuilder, StreamOutput_FullBufferIgnoresExtraStrings) {
310   StringBuffer<6> sb;
311   EXPECT_EQ(5u, sb.max_size());  // max_size() excludes the null terminator
312
313   sb << 1 - 1;
314   EXPECT_TRUE(sb.ok());
315   EXPECT_STREQ("0", sb.data());
316
317   sb << true << "Now it's way " << static_cast<unsigned char>(2) << " long";
318   EXPECT_FALSE(sb.ok());
319   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
320   EXPECT_STREQ("0true", sb.data());
321 }
322
323 TEST(StringBuilder, StreamOutput_ExhaustBuffer_InOneString) {
324   StringBuffer<9> sb;
325   EXPECT_EQ(8u, sb.max_size());
326
327   sb << "0123456789";  // write 10 chars
328   EXPECT_FALSE(sb.ok());
329   EXPECT_STREQ("01234567", sb.data());  // only can fit 8
330   EXPECT_EQ(8u, sb.size());
331
332   sb << "no"
333      << " more "
334      << "room" << '?';
335   EXPECT_STREQ("01234567", sb.data());
336 }
337
338 TEST(StringBuilder, StreamOutput_ExhaustBuffer_InTwoStrings) {
339   StringBuffer<4> sb;
340
341   sb << "01";  // fill 3/4 of buffer
342   EXPECT_EQ(2u, sb.size());
343   sb << "234";
344   EXPECT_STREQ("012", sb.data());
345   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
346   EXPECT_EQ(3u, sb.size());
347 }
348
349 TEST(StringBuilder, StreamOutput_NonTerminatedString) {
350   static char bad_string[256];
351   std::memset(bad_string, '?', sizeof(bad_string));
352
353   StringBuffer<6> sb;
354   sb << "hey" << bad_string;
355
356   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
357   EXPECT_STREQ("hey??", sb.data());
358 }
359
360 TEST(StringBuilder, SteamOutput_StringView) {
361   StringBuffer<6> buffer;
362   constexpr std::string_view hello("hello");
363
364   buffer << hello;
365   EXPECT_EQ(OkStatus(), buffer.status());
366   EXPECT_STREQ("hello", buffer.data());
367 }
368
369 TEST(StringBuilder, StreamOutput_EmptyStringView) {
370   StringBuffer<4> buffer;
371   buffer << "hi" << std::string_view() << "!";
372   EXPECT_TRUE(buffer.ok());
373   EXPECT_STREQ("hi!", buffer.data());
374 }
375
376 TEST(StringBuffer, Assign) {
377   StringBuffer<10> one;
378   StringBuffer<10> two;
379
380   one << "What";
381   ASSERT_STREQ("What", one.data());
382   two = one;
383   EXPECT_STREQ("What", two.data());
384   EXPECT_NE(one.data(), two.data());
385   one << " the";
386   two << " heck";
387
388   EXPECT_STREQ("What the", one.data());
389   EXPECT_STREQ("What heck", two.data());
390
391   two << "0123456789";
392   ASSERT_STREQ("What heck", two.data());
393   ASSERT_EQ(Status::ResourceExhausted(), two.status());
394   ASSERT_EQ(Status::ResourceExhausted(), two.last_status());
395
396   one = two;
397   EXPECT_STREQ("What heck", one.data());
398   EXPECT_EQ(Status::ResourceExhausted(), one.status());
399   EXPECT_EQ(Status::ResourceExhausted(), one.last_status());
400
401   StringBuffer<12> three;
402   three = two;
403   EXPECT_STREQ(three.data(), two.data());
404   EXPECT_EQ(three.size(), two.size());
405 }
406
407 TEST(StringBuffer, CopyConstructFromSameSize) {
408   StringBuffer<10> one;
409
410   one << "What";
411   ASSERT_STREQ("What", one.data());
412   StringBuffer<10> two(one);
413   EXPECT_STREQ("What", two.data());
414   EXPECT_NE(one.data(), two.data());
415   one << " the";
416   two << " heck";
417
418   EXPECT_STREQ("What the", one.data());
419   EXPECT_STREQ("What heck", two.data());
420
421   two << "0123456789";
422   two << "";
423   ASSERT_STREQ("What heck", two.data());
424   ASSERT_EQ(Status::ResourceExhausted(), two.status());
425   ASSERT_EQ(OkStatus(), two.last_status());
426 }
427
428 TEST(StringBuffer, CopyConstructFromSmaller) {
429   StringBuffer<10> one = MakeString<10>("You are the chosen one.");
430   StringBuffer<12> two(one);
431
432   EXPECT_STREQ("You are t", two.data());
433   EXPECT_EQ(Status::ResourceExhausted(), two.status());
434 }
435
436 TEST(StringBuilder, Object) {
437   StringBuffer<64> sb;
438   sb << CustomType();
439
440   EXPECT_STREQ(CustomType::kToString, sb.data());
441   EXPECT_EQ(std::strlen(CustomType::kToString), sb.size());
442 }
443
444 TEST(MakeString, Object) {
445   CustomType custom;
446   const auto sb = MakeString<64>(custom);
447
448   EXPECT_STREQ(CustomType::kToString, sb.data());
449   EXPECT_EQ(std::strlen(CustomType::kToString), sb.size());
450 }
451
452 TEST(MakeString, IntegerTypes) {
453   EXPECT_STREQ("0123-4567",
454                MakeString(0ll,
455                           1u,
456                           2l,
457                           3,
458                           -4,
459                           static_cast<unsigned short>(5),
460                           static_cast<short>(6),
461                           static_cast<unsigned char>(7))
462                    .data());
463 }
464
465 TEST(MakeString, Char) {
466   EXPECT_STREQ("a b c", MakeString('a', ' ', 'b', ' ', 'c').data());
467 }
468
469 TEST(MakeString, Float) { EXPECT_STREQ("-inf", MakeString(-INFINITY).data()); }
470
471 TEST(MakeString, Pointer_Null) {
472   EXPECT_STREQ("(null)", MakeString(nullptr).data());
473   EXPECT_STREQ("(null)", MakeString(static_cast<void*>(nullptr)).data());
474 }
475
476 TEST(MakeString, Pointer_NonNull) {
477   EXPECT_STREQ("1", MakeString(reinterpret_cast<void*>(0x1)).data());
478   EXPECT_STREQ("123", MakeString(reinterpret_cast<int*>(0x123)).data());
479 }
480
481 TEST(MakeString, Pointer_CustomType) {
482   char expected[32] = {};
483
484   CustomType custom;
485   std::snprintf(expected,
486                 sizeof(expected),
487                 "%" PRIxPTR,
488                 reinterpret_cast<uintptr_t>(&custom));
489
490   EXPECT_STREQ(expected, MakeString(&custom).data());
491 }
492
493 TEST(MakeString, Bool) {
494   EXPECT_STREQ("true", MakeString(true).data());
495   EXPECT_STREQ("false", MakeString(false).data());
496 }
497
498 TEST(MakeString, MutableString) {
499   char chars[] = {'C', 'o', 'o', 'l', '\0'};
500   EXPECT_STREQ("Cool?", MakeString(chars, "?").data());
501 }
502
503 TEST(MakeString, Empty_IsEmpty) { EXPECT_TRUE(MakeString().empty()); }
504
505 constexpr char kLongestString[] = "18446744073709551615";  // largest uint64_t
506
507 TEST(MakeString, DefaultSizeString_FitsWholeString) {
508   EXPECT_STREQ(
509       kLongestString,
510       MakeString(184, "467", u'\x04', "40", '7', '3', '7', "0", "", 955ul, 1615)
511           .data());
512 }
513
514 TEST(MakeString, LargerThanDefaultSize_Truncates) {
515   auto sb = MakeString("1844674407", 3709551615, 123456);
516
517   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
518   EXPECT_STREQ(kLongestString, sb.data());
519 }
520
521 TEST(MakeString, StringLiteral_ResizesToFitWholeLiteral) {
522   EXPECT_STREQ("", MakeString().data());
523
524   auto normal = MakeString("");
525   static_assert(normal.max_size() == decltype(MakeString(1))::max_size());
526
527   auto resized = MakeString("This string is reeeeeeeeeaaaaallly long!!!!!");
528   static_assert(resized.max_size() > decltype(MakeString(1))::max_size());
529   static_assert(resized.max_size() ==
530                 sizeof("This string is reeeeeeeeeaaaaallly long!!!!!") - 1);
531 }
532
533 TEST(MakeString, StringLiteral_UsesLongerFixedSize) {
534   auto fixed_size = MakeString<64>("");
535   static_assert(fixed_size.max_size() == 63u);
536   EXPECT_EQ(fixed_size.max_size(), 63u);
537   EXPECT_STREQ("", fixed_size.data());
538 }
539
540 TEST(MakeString, StringLiteral_TruncatesShorterFixedSize) {
541   EXPECT_STREQ("Goo", MakeString<4>("Google").data());
542   EXPECT_STREQ("Google", MakeString<7>("Google").data());
543   EXPECT_EQ(MakeString().max_size(), MakeString("Google").max_size());
544   EXPECT_STREQ("Google", MakeString("Google").data());
545 }
546
547 TEST(MakeString, DefaultSize_FitsMaxAndMinInts) {
548   EXPECT_STREQ("-9223372036854775808",
549                MakeString(std::numeric_limits<int64_t>::min()).data());
550   EXPECT_STREQ("18446744073709551615",
551                MakeString(std::numeric_limits<uint64_t>::max()).data());
552 }
553
554 TEST(MakeString, OutputToTemporaryStringBuffer) {
555   EXPECT_STREQ("hello", (MakeString<6>("hello ") << "world").data());
556   EXPECT_STREQ("hello world", (MakeString("hello ") << "world").data());
557 }
558
559 // Test MakeString's default size calculations.
560 template <typename... Args>
561 constexpr size_t DefaultStringBufferSize(Args&&...) {
562   return string_internal::DefaultStringBufferSize<Args...>();
563 }
564
565 // Default sizes are rounded up to 24 bytes.
566 static_assert(DefaultStringBufferSize("") == 24);
567 static_assert(DefaultStringBufferSize("123") == 24);
568 static_assert(DefaultStringBufferSize("123", "456", "78901234567890") == 24);
569 static_assert(DefaultStringBufferSize("1234567890", "1234567890", "123") == 24);
570 static_assert(DefaultStringBufferSize(1234, 5678, 9012) == 24);
571
572 // The buffer is sized to fix strings needing more than 24 bytes.
573 static_assert(DefaultStringBufferSize("1234567890", "1234567890", "1234") ==
574               25);
575 static_assert(DefaultStringBufferSize("1234567890", "1234567890", "12345") ==
576               26);
577 static_assert(DefaultStringBufferSize("1234567890", "1234567890", "12345678") ==
578               29);
579
580 // Four bytes are allocated for each non-string argument.
581 static_assert(DefaultStringBufferSize(1234, 5678, 9012, 3456, 7890, 1234) ==
582               25);
583 static_assert(DefaultStringBufferSize('a', nullptr, 'b', 4, 5, 6, 7, 8) == 33);
584
585 }  // namespace
586 }  // namespace pw