]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // Formatting library for C++ - std::ostream support tests |
2 | // | |
3 | // Copyright (c) 2012 - present, Victor Zverovich | |
4 | // All rights reserved. | |
5 | // | |
6 | // For the license information refer to format.h. | |
7 | ||
8 | #define FMT_STRING_ALIAS 1 | |
9 | #include "fmt/ostream.h" | |
10 | ||
11 | #include <sstream> | |
12 | #include "gmock.h" | |
13 | #include "gtest-extra.h" | |
14 | #include "util.h" | |
15 | ||
16 | using fmt::format; | |
17 | using fmt::format_error; | |
18 | ||
19 | static std::ostream &operator<<(std::ostream &os, const Date &d) { | |
20 | os << d.year() << '-' << d.month() << '-' << d.day(); | |
21 | return os; | |
22 | } | |
23 | ||
24 | static std::wostream &operator<<(std::wostream &os, const Date &d) { | |
25 | os << d.year() << L'-' << d.month() << L'-' << d.day(); | |
26 | return os; | |
27 | } | |
28 | ||
29 | enum TestEnum {}; | |
30 | static std::ostream &operator<<(std::ostream &os, TestEnum) { | |
31 | return os << "TestEnum"; | |
32 | } | |
33 | ||
34 | static std::wostream &operator<<(std::wostream &os, TestEnum) { | |
35 | return os << L"TestEnum"; | |
36 | } | |
37 | ||
38 | enum TestEnum2 {A}; | |
39 | ||
40 | TEST(OStreamTest, Enum) { | |
41 | EXPECT_FALSE((fmt::convert_to_int<TestEnum, char>::value)); | |
42 | EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum())); | |
43 | EXPECT_EQ("0", fmt::format("{}", A)); | |
44 | EXPECT_FALSE((fmt::convert_to_int<TestEnum, wchar_t>::value)); | |
45 | EXPECT_EQ(L"TestEnum", fmt::format(L"{}", TestEnum())); | |
46 | EXPECT_EQ(L"0", fmt::format(L"{}", A)); | |
47 | } | |
48 | ||
49 | typedef fmt::back_insert_range<fmt::internal::buffer> range; | |
50 | ||
51 | struct test_arg_formatter: fmt::arg_formatter<range> { | |
52 | test_arg_formatter(fmt::format_context &ctx, fmt::format_specs &s) | |
53 | : fmt::arg_formatter<range>(ctx, &s) {} | |
54 | }; | |
55 | ||
56 | TEST(OStreamTest, CustomArg) { | |
57 | fmt::memory_buffer buffer; | |
58 | fmt::internal::buffer &base = buffer; | |
59 | fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args()); | |
60 | fmt::format_specs spec; | |
61 | test_arg_formatter af(ctx, spec); | |
62 | visit(af, fmt::internal::make_arg<fmt::format_context>(TestEnum())); | |
63 | EXPECT_EQ("TestEnum", std::string(buffer.data(), buffer.size())); | |
64 | } | |
65 | ||
66 | TEST(OStreamTest, Format) { | |
67 | EXPECT_EQ("a string", format("{0}", TestString("a string"))); | |
68 | std::string s = format("The date is {0}", Date(2012, 12, 9)); | |
69 | EXPECT_EQ("The date is 2012-12-9", s); | |
70 | Date date(2012, 12, 9); | |
71 | EXPECT_EQ(L"The date is 2012-12-9", | |
72 | format(L"The date is {0}", Date(2012, 12, 9))); | |
73 | } | |
74 | ||
75 | TEST(OStreamTest, FormatSpecs) { | |
76 | EXPECT_EQ("def ", format("{0:<5}", TestString("def"))); | |
77 | EXPECT_EQ(" def", format("{0:>5}", TestString("def"))); | |
78 | EXPECT_THROW_MSG(format("{0:=5}", TestString("def")), | |
79 | format_error, "format specifier requires numeric argument"); | |
80 | EXPECT_EQ(" def ", format("{0:^5}", TestString("def"))); | |
81 | EXPECT_EQ("def**", format("{0:*<5}", TestString("def"))); | |
82 | EXPECT_THROW_MSG(format("{0:+}", TestString()), | |
83 | format_error, "format specifier requires numeric argument"); | |
84 | EXPECT_THROW_MSG(format("{0:-}", TestString()), | |
85 | format_error, "format specifier requires numeric argument"); | |
86 | EXPECT_THROW_MSG(format("{0: }", TestString()), | |
87 | format_error, "format specifier requires numeric argument"); | |
88 | EXPECT_THROW_MSG(format("{0:#}", TestString()), | |
89 | format_error, "format specifier requires numeric argument"); | |
90 | EXPECT_THROW_MSG(format("{0:05}", TestString()), | |
91 | format_error, "format specifier requires numeric argument"); | |
92 | EXPECT_EQ("test ", format("{0:13}", TestString("test"))); | |
93 | EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13)); | |
94 | EXPECT_EQ("te", format("{0:.2}", TestString("test"))); | |
95 | EXPECT_EQ("te", format("{0:.{1}}", TestString("test"), 2)); | |
96 | } | |
97 | ||
98 | struct EmptyTest {}; | |
99 | static std::ostream &operator<<(std::ostream &os, EmptyTest) { | |
100 | return os << ""; | |
101 | } | |
102 | ||
103 | TEST(OStreamTest, EmptyCustomOutput) { | |
104 | EXPECT_EQ("", fmt::format("{}", EmptyTest())); | |
105 | } | |
106 | ||
107 | TEST(OStreamTest, Print) { | |
108 | std::ostringstream os; | |
109 | fmt::print(os, "Don't {}!", "panic"); | |
110 | EXPECT_EQ("Don't panic!", os.str()); | |
111 | std::wostringstream wos; | |
112 | fmt::print(wos, L"Don't {}!", L"panic"); | |
113 | EXPECT_EQ(L"Don't panic!", wos.str()); | |
114 | } | |
115 | ||
116 | TEST(OStreamTest, WriteToOStream) { | |
117 | std::ostringstream os; | |
118 | fmt::memory_buffer buffer; | |
119 | const char *foo = "foo"; | |
120 | buffer.append(foo, foo + std::strlen(foo)); | |
121 | fmt::internal::write(os, buffer); | |
122 | EXPECT_EQ("foo", os.str()); | |
123 | } | |
124 | ||
125 | TEST(OStreamTest, WriteToOStreamMaxSize) { | |
126 | std::size_t max_size = std::numeric_limits<std::size_t>::max(); | |
127 | std::streamsize max_streamsize = std::numeric_limits<std::streamsize>::max(); | |
128 | if (max_size <= fmt::internal::to_unsigned(max_streamsize)) | |
129 | return; | |
130 | ||
131 | struct test_buffer : fmt::internal::buffer { | |
132 | explicit test_buffer(std::size_t size) { resize(size); } | |
133 | void grow(std::size_t) {} | |
134 | } buffer(max_size); | |
135 | ||
136 | struct mock_streambuf : std::streambuf { | |
137 | MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n)); | |
138 | std::streamsize xsputn(const char *s, std::streamsize n) { | |
139 | const void *v = s; | |
140 | return xsputn(v, n); | |
141 | } | |
142 | } streambuf; | |
143 | ||
144 | struct test_ostream : std::ostream { | |
145 | explicit test_ostream(mock_streambuf &buffer) : std::ostream(&buffer) {} | |
146 | } os(streambuf); | |
147 | ||
148 | testing::InSequence sequence; | |
eafe8130 TL |
149 | const char *data = FMT_NULL; |
150 | typedef std::make_unsigned<std::streamsize>::type ustreamsize; | |
151 | ustreamsize size = max_size; | |
11fdf7f2 | 152 | do { |
eafe8130 | 153 | auto n = std::min(size, fmt::internal::to_unsigned(max_streamsize)); |
11fdf7f2 TL |
154 | EXPECT_CALL(streambuf, xsputn(data, static_cast<std::streamsize>(n))) |
155 | .WillOnce(testing::Return(max_streamsize)); | |
156 | data += n; | |
157 | size -= n; | |
158 | } while (size != 0); | |
159 | fmt::internal::write(os, buffer); | |
160 | } | |
161 | ||
162 | TEST(OStreamTest, Join) { | |
163 | int v[3] = {1, 2, 3}; | |
164 | EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, v + 3, ", "))); | |
165 | } | |
166 | ||
167 | #if FMT_USE_CONSTEXPR | |
168 | TEST(OStreamTest, ConstexprString) { | |
169 | EXPECT_EQ("42", format(fmt("{}"), std::string("42"))); | |
170 | } | |
171 | #endif | |
172 | ||
173 | namespace fmt_test { | |
174 | struct ABC {}; | |
175 | ||
176 | template <typename Output> Output &operator<<(Output &out, ABC) { | |
177 | out << "ABC"; | |
178 | return out; | |
179 | } | |
180 | } // namespace fmt_test | |
181 | ||
182 | TEST(FormatTest, FormatToN) { | |
183 | char buffer[4]; | |
184 | buffer[3] = 'x'; | |
185 | auto result = fmt::format_to_n(buffer, 3, "{}", fmt_test::ABC()); | |
186 | EXPECT_EQ(3u, result.size); | |
187 | EXPECT_EQ(buffer + 3, result.out); | |
188 | EXPECT_EQ("ABCx", fmt::string_view(buffer, 4)); | |
189 | result = fmt::format_to_n(buffer, 3, "x{}y", fmt_test::ABC()); | |
190 | EXPECT_EQ(5u, result.size); | |
191 | EXPECT_EQ(buffer + 3, result.out); | |
192 | EXPECT_EQ("xABx", fmt::string_view(buffer, 4)); | |
193 | } | |
194 | ||
195 | #if FMT_USE_USER_DEFINED_LITERALS | |
196 | TEST(FormatTest, UDL) { | |
197 | using namespace fmt::literals; | |
198 | EXPECT_EQ("{}"_format("test"), "test"); | |
199 | } | |
200 | #endif |