// Copyright 2023 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include #include #include #include #include "pw_unit_test/framework.h" namespace bt_lib_cpp_string { namespace { constexpr size_t kStackBufferSize = 1024u; // Note: |runnable| can't be a reference since that'd make the behavior of // |va_start()| undefined. template std::string VAListHelper(Runnable runnable, ...) { va_list ap; va_start(ap, runnable); std::string rv = runnable(ap); va_end(ap); return rv; } TEST(StringPrintfTest, StringPrintfBasic) { EXPECT_EQ("", StringPrintf("")); EXPECT_EQ("hello", StringPrintf("hello")); EXPECT_EQ("hello-123", StringPrintf("hello%d", -123)); EXPECT_EQ("hello0123FACE", StringPrintf("%s%04d%X", "hello", 123, 0xfaceU)); } TEST(StringPrintfTest, StringVPrintf_Basic) { EXPECT_EQ("", VAListHelper([](va_list ap) -> std::string { return StringVPrintf("", ap); })); EXPECT_EQ("hello", VAListHelper([](va_list ap) -> std::string { return StringVPrintf("hello", ap); })); EXPECT_EQ("hello-123", VAListHelper( [](va_list ap) -> std::string { return StringVPrintf("hello%d", ap); }, -123)); EXPECT_EQ("hello0123FACE", VAListHelper( [](va_list ap) -> std::string { return StringVPrintf("%s%04d%X", ap); }, "hello", 123, 0xfaceU)); } TEST(StringPrintfTest, StringAppendfBasic) { { std::string s = "existing"; StringAppendf(&s, ""); EXPECT_EQ("existing", s); } { std::string s = "existing"; StringAppendf(&s, "hello"); EXPECT_EQ("existinghello", s); } { std::string s = "existing"; StringAppendf(&s, "hello%d", -123); EXPECT_EQ("existinghello-123", s); } { std::string s = "existing"; StringAppendf(&s, "%s%04d%X", "hello", 123, 0xfaceU); EXPECT_EQ("existinghello0123FACE", s); } } TEST(StringPrintfTest, StringVAppendfBasic) { EXPECT_EQ("existing", VAListHelper([](va_list ap) -> std::string { std::string s = "existing"; StringVAppendf(&s, "", ap); return s; })); EXPECT_EQ("existinghello", VAListHelper([](va_list ap) -> std::string { std::string s = "existing"; StringVAppendf(&s, "hello", ap); return s; })); EXPECT_EQ("existinghello-123", VAListHelper( [](va_list ap) -> std::string { std::string s = "existing"; StringVAppendf(&s, "hello%d", ap); return s; }, -123)); EXPECT_EQ("existinghello0123FACE", VAListHelper( [](va_list ap) -> std::string { std::string s = "existing"; StringVAppendf(&s, "%s%04d%X", ap); return s; }, "hello", 123, 0xfaceU)); } // Generally, we assume that everything forwards to |StringVAppendf()|, so // testing |StringPrintf()| more carefully suffices. TEST(StringPrintfTest, StringPrintfMaxSize) { std::string stuff(kStackBufferSize - 1, 'x'); std::string format = "%s"; EXPECT_EQ(stuff, StringPrintf(format.c_str(), stuff.c_str())); } TEST(StringPrintfTest, StringPrintfTruncated) { std::string stuff(kStackBufferSize, 'x'); std::string format = "%s"; // One char in kStackBufferSize will be used for null terminator, so one char // in |stuff| will be truncated. std::string expected(kStackBufferSize - 1, 'x'); EXPECT_EQ(expected, StringPrintf(format.c_str(), stuff.c_str())); } } // namespace } // namespace bt_lib_cpp_string