xref: /aosp_15_r20/external/pigweed/pw_string/string_builder_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 <string_view>
22 
23 #include "pw_span/span.h"
24 #include "pw_string/format.h"
25 #include "pw_unit_test/framework.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 <>
ToString(const this_pw_test::CustomType &,span<char> buffer)47 StatusWithSize ToString<this_pw_test::CustomType>(
48     const this_pw_test::CustomType&, 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 
TEST(StringBuilder,EmptyBuffer_SizeAndMaxSizeAreCorrect)59 TEST(StringBuilder, EmptyBuffer_SizeAndMaxSizeAreCorrect) {
60   StringBuilder sb(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 
TEST(StringBuilder,EmptyBuffer_StreamOutput_WritesNothing)71 TEST(StringBuilder, EmptyBuffer_StreamOutput_WritesNothing) {
72   char buffer[kNoTouch.size()];
73   std::memcpy(buffer, kNoTouch.data(), sizeof(buffer));
74 
75   StringBuilder sb(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 
TEST(StringBuilder,EmptyBuffer_Append_WritesNothing)82 TEST(StringBuilder, EmptyBuffer_Append_WritesNothing) {
83   char buffer[kNoTouch.size()];
84   std::memcpy(buffer, kNoTouch.data(), sizeof(buffer));
85 
86   StringBuilder sb(span(buffer, 0));
87 
88   EXPECT_FALSE(sb.append("Hello").ok());
89   EXPECT_EQ(kNoTouch, std::string_view(buffer, sizeof(buffer)));
90 }
91 
TEST(StringBuilder,EmptyBuffer_Resize_WritesNothing)92 TEST(StringBuilder, EmptyBuffer_Resize_WritesNothing) {
93   char buffer[kNoTouch.size()];
94   std::memcpy(buffer, kNoTouch.data(), sizeof(buffer));
95 
96   StringBuilder sb(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 
TEST(StringBuilder,EmptyBuffer_AppendEmpty_ResourceExhausted)103 TEST(StringBuilder, EmptyBuffer_AppendEmpty_ResourceExhausted) {
104   StringBuilder sb(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 
TEST(StringBuilder,Status_StartsOk)114 TEST(StringBuilder, Status_StartsOk) {
115   StringBuffer<16> sb;
116   EXPECT_EQ(OkStatus(), sb.status());
117   EXPECT_EQ(OkStatus(), sb.last_status());
118 }
119 
TEST(StringBuilder,Status_StatusAndLastStatusUpdate)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 
TEST(StringBuilder,Status_ClearStatus_SetsStatuesToOk)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 
TEST(StringBuilder,StreamOutput_OutputSelf)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 
TEST(StringBuilder,PushBack)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 
TEST(StringBuilder,PushBack_Full)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 
TEST(StringBuilder,PopBack)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 
TEST(StringBuilder,PopBack_Empty)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 
TEST(StringBuilder,Append_NonTerminatedString)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 
TEST(StringBuilder,Append_Chars)192 TEST(StringBuilder, Append_Chars) {
193   StringBuffer<8> sb;
194 
195   size_t count = 7;
196   EXPECT_TRUE(sb.append(count, '?').ok());
197   EXPECT_STREQ("???????", sb.data());
198 }
199 
TEST(StringBuilder,Append_Chars_Full)200 TEST(StringBuilder, Append_Chars_Full) {
201   StringBuffer<8> sb;
202 
203   size_t count = 8;
204   EXPECT_EQ(Status::ResourceExhausted(), sb.append(count, '?').last_status());
205   EXPECT_STREQ("???????", sb.data());
206 }
207 
TEST(StringBuilder,Append_Chars_ToEmpty)208 TEST(StringBuilder, Append_Chars_ToEmpty) {
209   StringBuilder sb(span<char>{});
210 
211   size_t count = 1;
212   EXPECT_EQ(Status::ResourceExhausted(), sb.append(count, '?').last_status());
213 }
214 
TEST(StringBuilder,Append_PartialCString)215 TEST(StringBuilder, Append_PartialCString) {
216   StringBuffer<12> sb;
217   size_t count = 4;
218   EXPECT_TRUE(sb.append("123456", count).ok());
219   EXPECT_EQ(4u, sb.size());
220   EXPECT_STREQ("1234", sb.data());
221 }
222 
TEST(StringBuilder,Append_CString)223 TEST(StringBuilder, Append_CString) {
224   auto sb = MakeString("hello");
225   EXPECT_TRUE(sb.append(" goodbye").ok());
226   EXPECT_STREQ("hello goodbye", sb.data());
227   EXPECT_EQ(13u, sb.size());
228 }
229 
TEST(StringBuilder,Append_CString_Full)230 TEST(StringBuilder, Append_CString_Full) {
231   auto sb = MakeString<6>("hello");
232   size_t count = 1;
233   EXPECT_EQ(Status::ResourceExhausted(),
234             sb.append("890123", count).last_status());
235   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
236   EXPECT_EQ(sb.max_size(), sb.size());
237   EXPECT_STREQ("hello", sb.data());
238 }
239 
TEST(StringBuilder,Append_StringView)240 TEST(StringBuilder, Append_StringView) {
241   auto sb = MakeString<32>("hello");
242   EXPECT_TRUE(sb.append("???"sv).ok());
243   EXPECT_EQ("hello???"sv, sb);
244 }
245 
TEST(StringBuilder,Append_StringView_Substring)246 TEST(StringBuilder, Append_StringView_Substring) {
247   auto sb = MakeString<32>("I like ");
248   size_t position = 5;
249   size_t count = 5;
250   EXPECT_TRUE(sb.append("your shoes!!!"sv, position, count).ok());
251   EXPECT_EQ("I like shoes"sv, sb);
252 }
253 
TEST(StringBuilder,Append_StringView_RemainingSubstring)254 TEST(StringBuilder, Append_StringView_RemainingSubstring) {
255   auto sb = MakeString<32>("I like ");
256   size_t count = 5;
257   EXPECT_TRUE(sb.append("your shoes!!!"sv, count).ok());
258   EXPECT_EQ("I like shoes!!!"sv, sb);
259 }
260 
TEST(StringBuilder,Resize_Smaller)261 TEST(StringBuilder, Resize_Smaller) {
262   auto sb = MakeString<12>("Four");
263   sb.resize(2);
264   EXPECT_TRUE(sb.ok());
265   EXPECT_EQ(2u, sb.size());
266   EXPECT_STREQ("Fo", sb.data());
267 }
268 
TEST(StringBuilder,Resize_Clear)269 TEST(StringBuilder, Resize_Clear) {
270   auto sb = MakeString<12>("Four");
271   sb.resize(0);
272   EXPECT_TRUE(sb.ok());
273   EXPECT_EQ(0u, sb.size());
274   EXPECT_STREQ("", sb.data());
275 }
276 
TEST(StringBuilder,Resize_Larger_Fails)277 TEST(StringBuilder, Resize_Larger_Fails) {
278   auto sb = MakeString<12>("Four");
279   EXPECT_EQ(4u, sb.size());
280   sb.resize(10);
281   EXPECT_EQ(sb.status(), Status::OutOfRange());
282   EXPECT_EQ(4u, sb.size());
283 }
284 
TEST(StringBuilder,Resize_LargerThanCapacity_Fails)285 TEST(StringBuilder, Resize_LargerThanCapacity_Fails) {
286   auto sb = MakeString<12>("Four");
287   sb.resize(1234);
288   EXPECT_EQ(sb.status(), Status::OutOfRange());
289   EXPECT_EQ(4u, sb.size());
290   EXPECT_STREQ("Four", sb.data());
291 }
292 
TEST(StringBuilder,Format_Normal)293 TEST(StringBuilder, Format_Normal) {
294   std::byte buffer[64];
295   StringBuilder sb(buffer);
296   EXPECT_TRUE(sb.Format("0x%x", 0xabc).ok());
297   EXPECT_STREQ("0xabc", sb.data());
298 
299   sb << "def";
300 
301   EXPECT_TRUE(sb.Format("GHI").ok());
302   EXPECT_STREQ("0xabcdefGHI", sb.data());
303 }
304 
TEST(StringBuilder,Format_ExhaustBuffer)305 TEST(StringBuilder, Format_ExhaustBuffer) {
306   StringBuffer<6> sb;
307   EXPECT_EQ(Status::ResourceExhausted(), sb.Format("012345").status());
308 
309   EXPECT_STREQ("01234", sb.data());
310   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
311 }
312 
TEST(StringBuilder,StreamOutput_MultipleTypes)313 TEST(StringBuilder, StreamOutput_MultipleTypes) {
314   constexpr const char* kExpected = "This is -1true example\n of this";
315   constexpr const char* kExample = "example";
316 
317   StringBuffer<64> sb;
318   sb << "This is " << -1 << true << ' ' << kExample << '\n' << " of this";
319 
320   EXPECT_STREQ(kExpected, sb.data());
321   EXPECT_EQ(std::strlen(kExpected), sb.size());
322 }
323 
TEST(StringBuilder,StreamOutput_FullBufferIgnoresExtraStrings)324 TEST(StringBuilder, StreamOutput_FullBufferIgnoresExtraStrings) {
325   StringBuffer<6> sb;
326   EXPECT_EQ(5u, sb.max_size());  // max_size() excludes the null terminator
327 
328   sb << 1 - 1;
329   EXPECT_TRUE(sb.ok());
330   EXPECT_STREQ("0", sb.data());
331 
332   sb << true << "Now it's way " << static_cast<unsigned char>(2) << " long";
333   EXPECT_FALSE(sb.ok());
334   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
335   EXPECT_STREQ("0true", sb.data());
336 }
337 
TEST(StringBuilder,StreamOutput_ExhaustBuffer_InOneString)338 TEST(StringBuilder, StreamOutput_ExhaustBuffer_InOneString) {
339   StringBuffer<9> sb;
340   EXPECT_EQ(8u, sb.max_size());
341 
342   sb << "0123456789";  // write 10 chars
343   EXPECT_FALSE(sb.ok());
344   EXPECT_STREQ("01234567", sb.data());  // only can fit 8
345   EXPECT_EQ(8u, sb.size());
346 
347   sb << "no"
348      << " more "
349      << "room" << '?';
350   EXPECT_STREQ("01234567", sb.data());
351 }
352 
TEST(StringBuilder,StreamOutput_ExhaustBuffer_InTwoStrings)353 TEST(StringBuilder, StreamOutput_ExhaustBuffer_InTwoStrings) {
354   StringBuffer<4> sb;
355 
356   sb << "01";  // fill 3/4 of buffer
357   EXPECT_EQ(2u, sb.size());
358   sb << "234";
359   EXPECT_STREQ("012", sb.data());
360   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
361   EXPECT_EQ(3u, sb.size());
362 }
363 
TEST(StringBuilder,StreamOutput_NonTerminatedString)364 TEST(StringBuilder, StreamOutput_NonTerminatedString) {
365   static char bad_string[256];
366   std::memset(bad_string, '?', sizeof(bad_string));
367 
368   StringBuffer<6> sb;
369   sb << "hey" << bad_string;
370 
371   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
372   EXPECT_STREQ("hey??", sb.data());
373 }
374 
TEST(StringBuilder,SteamOutput_StringView)375 TEST(StringBuilder, SteamOutput_StringView) {
376   StringBuffer<6> buffer;
377   constexpr std::string_view hello("hello");
378 
379   buffer << hello;
380   EXPECT_EQ(OkStatus(), buffer.status());
381   EXPECT_STREQ("hello", buffer.data());
382 }
383 
TEST(StringBuilder,StreamOutput_EmptyStringView)384 TEST(StringBuilder, StreamOutput_EmptyStringView) {
385   StringBuffer<4> buffer;
386   buffer << "hi" << std::string_view() << "!";
387   EXPECT_TRUE(buffer.ok());
388   EXPECT_STREQ("hi!", buffer.data());
389 }
390 
TEST(StringBuilder,StreamOutput_ByteArray)391 TEST(StringBuilder, StreamOutput_ByteArray) {
392   StringBuffer<7> buffer;
393   std::array<std::byte, 3> data{
394       {std::byte(0xc8), std::byte(0x02), std::byte(0x41)}};
395   buffer << data;
396   EXPECT_EQ(buffer.status(), OkStatus());
397   EXPECT_STREQ("c80241", buffer.data());
398 }
399 
TEST(StringBuilder,StreamOutput_ByteSpan)400 TEST(StringBuilder, StreamOutput_ByteSpan) {
401   StringBuffer<11> buffer;
402   std::array<std::byte, 5> data{{std::byte(0),
403                                  std::byte(0xc8),
404                                  std::byte(0x02),
405                                  std::byte(0x41),
406                                  std::byte(0xe0)}};
407   buffer << as_bytes(span(data));
408   EXPECT_EQ(buffer.status(), OkStatus());
409   EXPECT_STREQ("00c80241e0", buffer.data());
410 }
411 
TEST(StringBuilder,StreamOutput_ByteSpanOutOfSpace)412 TEST(StringBuilder, StreamOutput_ByteSpanOutOfSpace) {
413   StringBuffer<4> buffer;
414   std::array<uint8_t, 3> data{{0xc8, 0x02, 0x41}};
415   buffer << as_bytes(span(data));
416   EXPECT_EQ(buffer.status(), Status::ResourceExhausted());
417   EXPECT_STREQ("", buffer.data());
418 }
419 
TEST(StringBuffer,Assign)420 TEST(StringBuffer, Assign) {
421   StringBuffer<10> one;
422   StringBuffer<10> two;
423 
424   one << "What";
425   ASSERT_STREQ("What", one.data());
426   two = one;
427   EXPECT_STREQ("What", two.data());
428   EXPECT_NE(one.data(), two.data());
429   one << " the";
430   two << " heck";
431 
432   EXPECT_STREQ("What the", one.data());
433   EXPECT_STREQ("What heck", two.data());
434 
435   two << "0123456789";
436   ASSERT_STREQ("What heck", two.data());
437   ASSERT_EQ(Status::ResourceExhausted(), two.status());
438   ASSERT_EQ(Status::ResourceExhausted(), two.last_status());
439 
440   one = two;
441   EXPECT_STREQ("What heck", one.data());
442   EXPECT_EQ(Status::ResourceExhausted(), one.status());
443   EXPECT_EQ(Status::ResourceExhausted(), one.last_status());
444 
445   StringBuffer<12> three;
446   three = two;
447   EXPECT_STREQ(three.data(), two.data());
448   EXPECT_EQ(three.size(), two.size());
449 }
450 
TEST(StringBuffer,CopyConstructFromSameSize)451 TEST(StringBuffer, CopyConstructFromSameSize) {
452   StringBuffer<10> one;
453 
454   one << "What";
455   ASSERT_STREQ("What", one.data());
456   StringBuffer<10> two(one);
457   EXPECT_STREQ("What", two.data());
458   EXPECT_NE(one.data(), two.data());
459   one << " the";
460   two << " heck";
461 
462   EXPECT_STREQ("What the", one.data());
463   EXPECT_STREQ("What heck", two.data());
464 
465   two << "0123456789";
466   two << "";
467   ASSERT_STREQ("What heck", two.data());
468   ASSERT_EQ(Status::ResourceExhausted(), two.status());
469   ASSERT_EQ(OkStatus(), two.last_status());
470 }
471 
TEST(StringBuffer,CopyConstructFromSmaller)472 TEST(StringBuffer, CopyConstructFromSmaller) {
473   StringBuffer<10> one = MakeString<10>("You are the chosen one.");
474   StringBuffer<12> two(one);
475 
476   EXPECT_STREQ("You are t", two.data());
477   EXPECT_EQ(Status::ResourceExhausted(), two.status());
478 }
479 
TEST(StringBuilder,Object)480 TEST(StringBuilder, Object) {
481   StringBuffer<64> sb;
482   sb << CustomType();
483 
484   EXPECT_STREQ(CustomType::kToString, sb.data());
485   EXPECT_EQ(std::strlen(CustomType::kToString), sb.size());
486 }
487 
TEST(StringBuilder,UseStringAsBuffer)488 TEST(StringBuilder, UseStringAsBuffer) {
489   InlineString<32> string;
490   StringBuilder sb(string);
491 
492   sb << 123 << "456";
493 
494   EXPECT_EQ(sb.data(), string.data());
495   EXPECT_EQ(sb.size(), string.size());
496   EXPECT_EQ(6u, string.size());
497 
498   EXPECT_STREQ(sb.c_str(), "123456");
499   EXPECT_STREQ(string.c_str(), "123456");
500 }
501 
TEST(StringBuilder,OverflowStringAsBuffer)502 TEST(StringBuilder, OverflowStringAsBuffer) {
503   InlineString<5> string;
504   StringBuilder sb(string);
505 
506   sb << 123 << "456";
507 
508   EXPECT_EQ(sb.status(), Status::ResourceExhausted());
509   EXPECT_EQ(string.size(), 5u);
510   EXPECT_STREQ(string.c_str(), "12345");
511 }
512 
TEST(MakeString,Object)513 TEST(MakeString, Object) {
514   CustomType custom;
515   const auto sb = MakeString<64>(custom);
516 
517   EXPECT_STREQ(CustomType::kToString, sb.data());
518   EXPECT_EQ(std::strlen(CustomType::kToString), sb.size());
519 }
520 
TEST(MakeString,IntegerTypes)521 TEST(MakeString, IntegerTypes) {
522   EXPECT_STREQ("0123-4567",
523                MakeString(0ll,
524                           1u,
525                           2l,
526                           3,
527                           -4,
528                           static_cast<unsigned short>(5),
529                           static_cast<short>(6),
530                           static_cast<unsigned char>(7))
531                    .data());
532 }
533 
TEST(MakeString,Char)534 TEST(MakeString, Char) {
535   EXPECT_STREQ("a b c", MakeString('a', ' ', 'b', ' ', 'c').data());
536 }
537 
TEST(MakeString,Float)538 TEST(MakeString, Float) { EXPECT_STREQ("-inf", MakeString(-INFINITY).data()); }
539 
TEST(MakeString,Pointer_Null)540 TEST(MakeString, Pointer_Null) {
541   EXPECT_STREQ("(null)", MakeString(nullptr).data());
542   EXPECT_STREQ("(null)", MakeString(static_cast<void*>(nullptr)).data());
543 }
544 
TEST(MakeString,Pointer_NonNull)545 TEST(MakeString, Pointer_NonNull) {
546   EXPECT_STREQ("1", MakeString(reinterpret_cast<void*>(0x1)).data());
547   EXPECT_STREQ("123", MakeString(reinterpret_cast<int*>(0x123)).data());
548 }
549 
TEST(MakeString,Pointer_CustomType)550 TEST(MakeString, Pointer_CustomType) {
551   char expected[32] = {};
552 
553   CustomType custom;
554   std::snprintf(expected,
555                 sizeof(expected),
556                 "%" PRIxPTR,
557                 reinterpret_cast<uintptr_t>(&custom));
558 
559   EXPECT_STREQ(expected, MakeString(&custom).data());
560 }
561 
TEST(MakeString,Bool)562 TEST(MakeString, Bool) {
563   EXPECT_STREQ("true", MakeString(true).data());
564   EXPECT_STREQ("false", MakeString(false).data());
565 }
566 
TEST(MakeString,MutableString)567 TEST(MakeString, MutableString) {
568   char chars[] = {'C', 'o', 'o', 'l', '\0'};
569   EXPECT_STREQ("Cool?", MakeString(chars, "?").data());
570 }
571 
TEST(MakeString,Empty_IsEmpty)572 TEST(MakeString, Empty_IsEmpty) { EXPECT_TRUE(MakeString().empty()); }
573 
574 constexpr char kLongestString[] = "18446744073709551615";  // largest uint64_t
575 
TEST(MakeString,DefaultSizeString_FitsWholeString)576 TEST(MakeString, DefaultSizeString_FitsWholeString) {
577   EXPECT_STREQ(
578       kLongestString,
579       MakeString(184, "467", u'\x04', "40", '7', '3', '7', "0", "", 955ul, 1615)
580           .data());
581 }
582 
TEST(MakeString,LargerThanDefaultSize_Truncates)583 TEST(MakeString, LargerThanDefaultSize_Truncates) {
584   auto sb = MakeString("1844674407", 3709551615, 123456);
585 
586   EXPECT_EQ(Status::ResourceExhausted(), sb.status());
587   EXPECT_STREQ(kLongestString, sb.data());
588 }
589 
TEST(MakeString,StringLiteral_ResizesToFitWholeLiteral)590 TEST(MakeString, StringLiteral_ResizesToFitWholeLiteral) {
591   EXPECT_STREQ("", MakeString().data());
592 
593   [[maybe_unused]] auto normal = MakeString("");
594   static_assert(normal.max_size() == decltype(MakeString(1))::max_size());
595   EXPECT_EQ(normal.max_size(), decltype(MakeString(1))::max_size());
596 
597   [[maybe_unused]] auto resized =
598       MakeString("This string is reeeeeeeeeaaaaallly long!!!!!");
599   static_assert(resized.max_size() > decltype(MakeString(1))::max_size());
600   static_assert(resized.max_size() ==
601                 sizeof("This string is reeeeeeeeeaaaaallly long!!!!!") - 1);
602   EXPECT_GT(resized.max_size(), decltype(MakeString(1))::max_size());
603   EXPECT_EQ(resized.max_size(),
604             sizeof("This string is reeeeeeeeeaaaaallly long!!!!!") - 1);
605 }
606 
TEST(MakeString,StringLiteral_UsesLongerFixedSize)607 TEST(MakeString, StringLiteral_UsesLongerFixedSize) {
608   auto fixed_size = MakeString<64>("");
609   static_assert(fixed_size.max_size() == 63u);
610   EXPECT_EQ(fixed_size.max_size(), 63u);
611   EXPECT_STREQ("", fixed_size.data());
612 }
613 
TEST(MakeString,StringLiteral_TruncatesShorterFixedSize)614 TEST(MakeString, StringLiteral_TruncatesShorterFixedSize) {
615   EXPECT_STREQ("Goo", MakeString<4>("Google").data());
616   EXPECT_STREQ("Google", MakeString<7>("Google").data());
617   EXPECT_EQ(MakeString().max_size(), MakeString("Google").max_size());
618   EXPECT_STREQ("Google", MakeString("Google").data());
619 }
620 
TEST(MakeString,DefaultSize_FitsMaxAndMinInts)621 TEST(MakeString, DefaultSize_FitsMaxAndMinInts) {
622   EXPECT_STREQ("-9223372036854775808",
623                MakeString(std::numeric_limits<int64_t>::min()).data());
624   EXPECT_STREQ("18446744073709551615",
625                MakeString(std::numeric_limits<uint64_t>::max()).data());
626 }
627 
TEST(MakeString,OutputToTemporaryStringBuffer)628 TEST(MakeString, OutputToTemporaryStringBuffer) {
629   EXPECT_STREQ("hello", (MakeString<6>("hello ") << "world").data());
630   EXPECT_STREQ("hello world", (MakeString("hello ") << "world").data());
631 }
632 
633 // Test MakeString's default size calculations.
634 template <typename... Args>
DefaultStringBufferSize(Args &&...)635 constexpr size_t DefaultStringBufferSize(Args&&...) {
636   return string_internal::DefaultStringBufferSize<Args...>();
637 }
638 
639 // Default sizes are rounded up to 24 bytes.
640 static_assert(DefaultStringBufferSize("") == 24);
641 static_assert(DefaultStringBufferSize("123") == 24);
642 static_assert(DefaultStringBufferSize("123", "456", "78901234567890") == 24);
643 static_assert(DefaultStringBufferSize("1234567890", "1234567890", "123") == 24);
644 static_assert(DefaultStringBufferSize(1234, 5678, 9012) == 24);
645 
646 // The buffer is sized to fix strings needing more than 24 bytes.
647 static_assert(DefaultStringBufferSize("1234567890", "1234567890", "1234") ==
648               25);
649 static_assert(DefaultStringBufferSize("1234567890", "1234567890", "12345") ==
650               26);
651 static_assert(DefaultStringBufferSize("1234567890", "1234567890", "12345678") ==
652               29);
653 
654 // Four bytes are allocated for each non-string argument.
655 static_assert(DefaultStringBufferSize(1234, 5678, 9012, 3456, 7890, 1234) ==
656               25);
657 static_assert(DefaultStringBufferSize('a', nullptr, 'b', 4, 5, 6, 7, 8) == 33);
658 
659 struct SomeCustomType {};
660 
operator <<(StringBuilder & sb,const SomeCustomType &)661 StringBuilder& operator<<(StringBuilder& sb, const SomeCustomType&) {
662   return sb << "SomeCustomType was here!";
663 }
664 
TEST(StringBuilder,ShiftOperatorOverload_SameNamsepace)665 TEST(StringBuilder, ShiftOperatorOverload_SameNamsepace) {
666   pw::StringBuffer<48> buffer;
667   buffer << SomeCustomType{};
668 
669   EXPECT_STREQ("SomeCustomType was here!", buffer.c_str());
670 }
671 
672 }  // namespace
673 }  // namespace pw
674 
675 namespace some_other_ns {
676 
677 struct MyCustomType {
678   int item;
679 };
680 
operator <<(pw::StringBuilder & sb,const MyCustomType & value)681 pw::StringBuilder& operator<<(pw::StringBuilder& sb,
682                               const MyCustomType& value) {
683   return sb << "MyCustomType(" << value.item << ')';
684 }
685 
686 }  // namespace some_other_ns
687 
688 namespace pw_test_namespace {
689 
TEST(StringBuilder,ShiftOperatorOverload_DifferentNamsepace)690 TEST(StringBuilder, ShiftOperatorOverload_DifferentNamsepace) {
691   pw::StringBuffer<48> buffer;
692   buffer << "This is " << some_other_ns::MyCustomType{1138};
693 
694   EXPECT_STREQ("This is MyCustomType(1138)", buffer.data());
695 }
696 
697 }  // namespace pw_test_namespace
698