1 // Copyright 2023 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 <cpp-string/string_printf.h>
16 #include <errno.h>
17 #include <stdarg.h>
18
19 #include <string>
20
21 #include "pw_unit_test/framework.h"
22
23 namespace bt_lib_cpp_string {
24 namespace {
25
26 constexpr size_t kStackBufferSize = 1024u;
27
28 // Note: |runnable| can't be a reference since that'd make the behavior of
29 // |va_start()| undefined.
30 template <typename Runnable>
VAListHelper(Runnable runnable,...)31 std::string VAListHelper(Runnable runnable, ...) {
32 va_list ap;
33 va_start(ap, runnable);
34 std::string rv = runnable(ap);
35 va_end(ap);
36 return rv;
37 }
38
TEST(StringPrintfTest,StringPrintfBasic)39 TEST(StringPrintfTest, StringPrintfBasic) {
40 EXPECT_EQ("", StringPrintf(""));
41 EXPECT_EQ("hello", StringPrintf("hello"));
42 EXPECT_EQ("hello-123", StringPrintf("hello%d", -123));
43 EXPECT_EQ("hello0123FACE", StringPrintf("%s%04d%X", "hello", 123, 0xfaceU));
44 }
45
TEST(StringPrintfTest,StringVPrintf_Basic)46 TEST(StringPrintfTest, StringVPrintf_Basic) {
47 EXPECT_EQ("", VAListHelper([](va_list ap) -> std::string {
48 return StringVPrintf("", ap);
49 }));
50 EXPECT_EQ("hello", VAListHelper([](va_list ap) -> std::string {
51 return StringVPrintf("hello", ap);
52 }));
53 EXPECT_EQ("hello-123",
54 VAListHelper(
55 [](va_list ap) -> std::string {
56 return StringVPrintf("hello%d", ap);
57 },
58 -123));
59 EXPECT_EQ("hello0123FACE",
60 VAListHelper(
61 [](va_list ap) -> std::string {
62 return StringVPrintf("%s%04d%X", ap);
63 },
64 "hello",
65 123,
66 0xfaceU));
67 }
68
TEST(StringPrintfTest,StringAppendfBasic)69 TEST(StringPrintfTest, StringAppendfBasic) {
70 {
71 std::string s = "existing";
72 StringAppendf(&s, "");
73 EXPECT_EQ("existing", s);
74 }
75 {
76 std::string s = "existing";
77 StringAppendf(&s, "hello");
78 EXPECT_EQ("existinghello", s);
79 }
80 {
81 std::string s = "existing";
82 StringAppendf(&s, "hello%d", -123);
83 EXPECT_EQ("existinghello-123", s);
84 }
85 {
86 std::string s = "existing";
87 StringAppendf(&s, "%s%04d%X", "hello", 123, 0xfaceU);
88 EXPECT_EQ("existinghello0123FACE", s);
89 }
90 }
91
TEST(StringPrintfTest,StringVAppendfBasic)92 TEST(StringPrintfTest, StringVAppendfBasic) {
93 EXPECT_EQ("existing", VAListHelper([](va_list ap) -> std::string {
94 std::string s = "existing";
95 StringVAppendf(&s, "", ap);
96 return s;
97 }));
98 EXPECT_EQ("existinghello", VAListHelper([](va_list ap) -> std::string {
99 std::string s = "existing";
100 StringVAppendf(&s, "hello", ap);
101 return s;
102 }));
103 EXPECT_EQ("existinghello-123",
104 VAListHelper(
105 [](va_list ap) -> std::string {
106 std::string s = "existing";
107 StringVAppendf(&s, "hello%d", ap);
108 return s;
109 },
110 -123));
111 EXPECT_EQ("existinghello0123FACE",
112 VAListHelper(
113 [](va_list ap) -> std::string {
114 std::string s = "existing";
115 StringVAppendf(&s, "%s%04d%X", ap);
116 return s;
117 },
118 "hello",
119 123,
120 0xfaceU));
121 }
122
123 // Generally, we assume that everything forwards to |StringVAppendf()|, so
124 // testing |StringPrintf()| more carefully suffices.
125
TEST(StringPrintfTest,StringPrintfMaxSize)126 TEST(StringPrintfTest, StringPrintfMaxSize) {
127 std::string stuff(kStackBufferSize - 1, 'x');
128 std::string format = "%s";
129 EXPECT_EQ(stuff, StringPrintf(format.c_str(), stuff.c_str()));
130 }
131
TEST(StringPrintfTest,StringPrintfTruncated)132 TEST(StringPrintfTest, StringPrintfTruncated) {
133 std::string stuff(kStackBufferSize, 'x');
134 std::string format = "%s";
135 // One char in kStackBufferSize will be used for null terminator, so one char
136 // in |stuff| will be truncated.
137 std::string expected(kStackBufferSize - 1, 'x');
138 EXPECT_EQ(expected, StringPrintf(format.c_str(), stuff.c_str()));
139 }
140
141 } // namespace
142 } // namespace bt_lib_cpp_string
143