1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <errno.h>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A helper for the StringAppendV test that follows.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Just forwards its args to StringAppendV.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void StringAppendVTestHelper(std::string* out, const char* format, ...) {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_list ap;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_start(ap, format);
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringAppendV(out, format, ap);
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  va_end(ap);
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, StringPrintfEmpty) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ("", StringPrintf("%s", ""));
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, StringPrintfMisc) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ("123hello w", StringPrintf("%3d%2s %1c", 123, "hello", 'w'));
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(L"123hello w", StringPrintf(L"%3d%2ls %1lc", 123, L"hello", 'w'));
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, StringAppendfEmptyString) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string value("Hello");
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringAppendF(&value, "%s", "");
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ("Hello", value);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring valuew(L"Hello");
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringAppendF(&valuew, L"%ls", L"");
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(L"Hello", valuew);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, StringAppendfString) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string value("Hello");
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringAppendF(&value, " %s", "World");
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ("Hello World", value);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring valuew(L"Hello");
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringAppendF(&valuew, L" %ls", L"World");
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(L"Hello World", valuew);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, StringAppendfInt) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string value("Hello");
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringAppendF(&value, " %d", 123);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ("Hello 123", value);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring valuew(L"Hello");
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringAppendF(&valuew, L" %d", 123);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(L"Hello 123", valuew);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Make sure that lengths exactly around the initial buffer size are handled
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// correctly.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, StringPrintfBounds) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kSrcLen = 1026;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char src[kSrcLen];
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(src); i++)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    src[i] = 'A';
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t srcw[kSrcLen];
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(srcw); i++)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    srcw[i] = 'A';
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 1; i < 3; i++) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    src[kSrcLen - i] = 0;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string out;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SStringPrintf(&out, "%s", src);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_STREQ(src, out.c_str());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_ANDROID)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    srcw[kSrcLen - i] = 0;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::wstring outw;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SStringPrintf(&outw, L"%ls", srcw);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_STREQ(srcw, outw.c_str());
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test very large sprintfs that will cause the buffer to grow.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, Grow) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char src[1026];
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(src); i++)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    src[i] = 'A';
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  src[1025] = 0;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* fmt = "%sB%sB%sB%sB%sB%sB%s";
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string out;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SStringPrintf(&out, fmt, src, src, src, src, src, src, src);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kRefSize = 320000;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* ref = new char[kRefSize];
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sprintf_s(ref, kRefSize, fmt, src, src, src, src, src, src, src);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  snprintf(ref, kRefSize, fmt, src, src, src, src, src, src, src);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_STREQ(ref, out.c_str());
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete[] ref;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, StringAppendV) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string out;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringAppendVTestHelper(&out, "%d foo %s", 1, "bar");
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ("1 foo bar", out);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test the boundary condition for the size of the string_util's
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// internal buffer.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, GrowBoundary) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int string_util_buf_len = 1024;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our buffer should be one larger than the size of StringAppendVT's stack
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // buffer.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int buf_len = string_util_buf_len + 1;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char src[buf_len + 1];  // Need extra one for NULL-terminator.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < buf_len; ++i)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    src[i] = 'a';
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  src[buf_len] = 0;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string out;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SStringPrintf(&out, "%s", src);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_STREQ(src, out.c_str());
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(evanm): what's the proper cross-platform test here?
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sprintf in Visual Studio fails when given U+FFFF. This tests that the
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// failure case is gracefuly handled.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, Invalid) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t invalid[2];
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  invalid[0] = 0xffff;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  invalid[1] = 0;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring out;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SStringPrintf(&out, L"%ls", invalid);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_STREQ(L"", out.c_str());
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test that the positional parameters work.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StringPrintfTest, PositionalParameters) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string out;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SStringPrintf(&out, "%1$s %1$s", "test");
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_STREQ("test test", out.c_str());
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring wout;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SStringPrintf(&wout, L"%1$ls %1$ls", L"test");
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_STREQ(L"test test", wout.c_str());
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Test that StringPrintf and StringAppendV do not change errno.
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST(StringPrintfTest, StringPrintfErrno) {
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  errno = 1;
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ("", StringPrintf("%s", ""));
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(1, errno);
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string out;
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  StringAppendVTestHelper(&out, "%d foo %s", 1, "bar");
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(1, errno);
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
189