aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/core/lib/strings/stringprintf_test.cc
blob: 737ed5c0e05598849c8bcc52a9aedc3a0e8d4c20 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "tensorflow/core/lib/strings/stringprintf.h"

#include <string>

#include <gtest/gtest.h>

namespace tensorflow {
namespace strings {
namespace {

TEST(PrintfTest, Empty) {
  EXPECT_EQ("", Printf("%s", string().c_str()));
  EXPECT_EQ("", Printf("%s", ""));
}

TEST(PrintfTest, Misc) {
// MSVC does not support $ format specifier.
#if !defined(COMPILER_MSVC)
  EXPECT_EQ("123hello w", Printf("%3$d%2$s %1$c", 'w', "hello", 123));
#endif  // !COMPILER_MSVC
}

TEST(AppendfTest, Empty) {
  string value("Hello");
  const char* empty = "";
  Appendf(&value, "%s", empty);
  EXPECT_EQ("Hello", value);
}

TEST(AppendfTest, EmptyString) {
  string value("Hello");
  Appendf(&value, "%s", "");
  EXPECT_EQ("Hello", value);
}

TEST(AppendfTest, String) {
  string value("Hello");
  Appendf(&value, " %s", "World");
  EXPECT_EQ("Hello World", value);
}

TEST(AppendfTest, Int) {
  string value("Hello");
  Appendf(&value, " %d", 123);
  EXPECT_EQ("Hello 123", value);
}

TEST(PrintfTest, Multibyte) {
  // If we are in multibyte mode and feed invalid multibyte sequence,
  // Printf should return an empty string instead of running
  // out of memory while trying to determine destination buffer size.
  // see b/4194543.

  char* old_locale = setlocale(LC_CTYPE, NULL);
  // Push locale with multibyte mode
  setlocale(LC_CTYPE, "en_US.utf8");

  const char kInvalidCodePoint[] = "\375\067s";
  string value = Printf("%.*s", 3, kInvalidCodePoint);

  // In some versions of glibc (e.g. eglibc-2.11.1, aka GRTEv2), snprintf
  // returns error given an invalid codepoint. Other versions
  // (e.g. eglibc-2.15, aka pre-GRTEv3) emit the codepoint verbatim.
  // We test that the output is one of the above.
  EXPECT_TRUE(value.empty() || value == kInvalidCodePoint);

  // Repeat with longer string, to make sure that the dynamically
  // allocated path in StringAppendV is handled correctly.
  int n = 2048;
  char* buf = new char[n + 1];
  memset(buf, ' ', n - 3);
  memcpy(buf + n - 3, kInvalidCodePoint, 4);
  value = Printf("%.*s", n, buf);
  // See GRTEv2 vs. GRTEv3 comment above.
  EXPECT_TRUE(value.empty() || value == buf);
  delete[] buf;

  setlocale(LC_CTYPE, old_locale);
}

TEST(PrintfTest, NoMultibyte) {
  // No multibyte handling, but the string contains funny chars.
  char* old_locale = setlocale(LC_CTYPE, NULL);
  setlocale(LC_CTYPE, "POSIX");
  string value = Printf("%.*s", 3, "\375\067s");
  setlocale(LC_CTYPE, old_locale);
  EXPECT_EQ("\375\067s", value);
}

TEST(PrintfTest, DontOverwriteErrno) {
  // Check that errno isn't overwritten unless we're printing
  // something significantly larger than what people are normally
  // printing in their badly written PLOG() statements.
  errno = ECHILD;
  string value = Printf("Hello, %s!", "World");
  EXPECT_EQ(ECHILD, errno);
}

TEST(PrintfTest, LargeBuf) {
  // Check that the large buffer is handled correctly.
  int n = 2048;
  char* buf = new char[n + 1];
  memset(buf, ' ', n);
  buf[n] = 0;
  string value = Printf("%s", buf);
  EXPECT_EQ(buf, value);
  delete[] buf;
}

}  // namespace

}  // namespace strings
}  // namespace tensorflow