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
|