1 // Formatting library for C++ - std::ostream support tests
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
8 #include "fmt/format.h"
14 // Test that there is no issues with specializations when fmt/ostream.h is
15 // included after fmt/format.h.
17 template <> struct formatter
<test
> : formatter
<int> {
18 auto format(const test
&, format_context
& ctx
) -> decltype(ctx
.out()) {
19 return formatter
<int>::format(42, ctx
);
26 #include "fmt/ostream.h"
27 #include "fmt/ranges.h"
28 #include "gmock/gmock.h"
29 #include "gtest-extra.h"
32 std::ostream
& operator<<(std::ostream
& os
, const date
& d
) {
33 os
<< d
.year() << '-' << d
.month() << '-' << d
.day();
37 std::wostream
& operator<<(std::wostream
& os
, const date
& d
) {
38 os
<< d
.year() << L
'-' << d
.month() << L
'-' << d
.day();
42 // Make sure that overloaded comma operators do no harm to is_streamable.
43 struct type_with_comma_op
{};
44 template <typename T
> void operator,(type_with_comma_op
, const T
&);
45 template <typename T
> type_with_comma_op
operator<<(T
&, const date
&);
47 enum streamable_enum
{};
49 std::ostream
& operator<<(std::ostream
& os
, streamable_enum
) {
50 return os
<< "streamable_enum";
53 enum unstreamable_enum
{};
55 TEST(ostream_test
, enum) {
56 EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum()));
57 EXPECT_EQ("0", fmt::format("{}", unstreamable_enum()));
60 TEST(ostream_test
, format
) {
61 EXPECT_EQ("a string", fmt::format("{0}", test_string("a string")));
62 EXPECT_EQ("The date is 2012-12-9",
63 fmt::format("The date is {0}", date(2012, 12, 9)));
66 TEST(ostream_test
, format_specs
) {
67 using fmt::format_error
;
68 EXPECT_EQ("def ", fmt::format("{0:<5}", test_string("def")));
69 EXPECT_EQ(" def", fmt::format("{0:>5}", test_string("def")));
70 EXPECT_EQ(" def ", fmt::format("{0:^5}", test_string("def")));
71 EXPECT_EQ("def**", fmt::format("{0:*<5}", test_string("def")));
72 EXPECT_THROW_MSG(fmt::format(runtime("{0:+}"), test_string()), format_error
,
73 "format specifier requires numeric argument");
74 EXPECT_THROW_MSG(fmt::format(runtime("{0:-}"), test_string()), format_error
,
75 "format specifier requires numeric argument");
76 EXPECT_THROW_MSG(fmt::format(runtime("{0: }"), test_string()), format_error
,
77 "format specifier requires numeric argument");
78 EXPECT_THROW_MSG(fmt::format(runtime("{0:#}"), test_string()), format_error
,
79 "format specifier requires numeric argument");
80 EXPECT_THROW_MSG(fmt::format(runtime("{0:05}"), test_string()), format_error
,
81 "format specifier requires numeric argument");
82 EXPECT_EQ("test ", fmt::format("{0:13}", test_string("test")));
83 EXPECT_EQ("test ", fmt::format("{0:{1}}", test_string("test"), 13));
84 EXPECT_EQ("te", fmt::format("{0:.2}", test_string("test")));
85 EXPECT_EQ("te", fmt::format("{0:.{1}}", test_string("test"), 2));
89 std::ostream
& operator<<(std::ostream
& os
, empty_test
) { return os
<< ""; }
91 TEST(ostream_test
, empty_custom_output
) {
92 EXPECT_EQ("", fmt::format("{}", empty_test()));
95 TEST(ostream_test
, print
) {
96 std::ostringstream os
;
97 fmt::print(os
, "Don't {}!", "panic");
98 EXPECT_EQ("Don't panic!", os
.str());
101 TEST(ostream_test
, write_to_ostream
) {
102 std::ostringstream os
;
103 fmt::memory_buffer buffer
;
104 const char* foo
= "foo";
105 buffer
.append(foo
, foo
+ std::strlen(foo
));
106 fmt::detail::write_buffer(os
, buffer
);
107 EXPECT_EQ("foo", os
.str());
110 TEST(ostream_test
, write_to_ostream_max_size
) {
111 auto max_size
= fmt::detail::max_value
<size_t>();
112 auto max_streamsize
= fmt::detail::max_value
<std::streamsize
>();
113 if (max_size
<= fmt::detail::to_unsigned(max_streamsize
)) return;
115 struct test_buffer final
: fmt::detail::buffer
<char> {
116 explicit test_buffer(size_t size
)
117 : fmt::detail::buffer
<char>(nullptr, size
, size
) {}
121 struct mock_streambuf
: std::streambuf
{
122 MOCK_METHOD2(xsputn
, std::streamsize(const void* s
, std::streamsize n
));
123 std::streamsize
xsputn(const char* s
, std::streamsize n
) {
129 struct test_ostream
: std::ostream
{
130 explicit test_ostream(mock_streambuf
& output_buffer
)
131 : std::ostream(&output_buffer
) {}
134 testing::InSequence sequence
;
135 const char* data
= nullptr;
136 using ustreamsize
= std::make_unsigned
<std::streamsize
>::type
;
137 ustreamsize size
= max_size
;
139 auto n
= std::min(size
, fmt::detail::to_unsigned(max_streamsize
));
140 EXPECT_CALL(streambuf
, xsputn(data
, static_cast<std::streamsize
>(n
)))
141 .WillOnce(testing::Return(max_streamsize
));
145 fmt::detail::write_buffer(os
, buffer
);
148 TEST(ostream_test
, join
) {
149 int v
[3] = {1, 2, 3};
150 EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v
, v
+ 3, ", ")));
153 TEST(ostream_test
, join_fallback_formatter
) {
154 auto strs
= std::vector
<test_string
>{test_string("foo"), test_string("bar")};
155 EXPECT_EQ("foo, bar", fmt::format("{}", fmt::join(strs
, ", ")));
158 #if FMT_USE_CONSTEXPR
159 TEST(ostream_test
, constexpr_string
) {
160 EXPECT_EQ("42", format(FMT_STRING("{}"), std::string("42")));
161 EXPECT_EQ("a string", format(FMT_STRING("{0}"), test_string("a string")));
168 template <typename Output
> Output
& operator<<(Output
& out
, abc
) {
171 } // namespace fmt_test
173 template <typename T
> struct test_template
{};
175 template <typename T
>
176 std::ostream
& operator<<(std::ostream
& os
, test_template
<T
>) {
181 template <typename T
> struct formatter
<test_template
<T
>> : formatter
<int> {
182 auto format(test_template
<T
>, format_context
& ctx
) -> decltype(ctx
.out()) {
183 return formatter
<int>::format(2, ctx
);
188 TEST(ostream_test
, template) {
189 EXPECT_EQ("2", fmt::format("{}", test_template
<int>()));
192 TEST(ostream_test
, format_to_n
) {
195 auto result
= fmt::format_to_n(buffer
, 3, "{}", fmt_test::abc());
196 EXPECT_EQ(3u, result
.size
);
197 EXPECT_EQ(buffer
+ 3, result
.out
);
198 EXPECT_EQ("abcx", fmt::string_view(buffer
, 4));
199 result
= fmt::format_to_n(buffer
, 3, "x{}y", fmt_test::abc());
200 EXPECT_EQ(5u, result
.size
);
201 EXPECT_EQ(buffer
+ 3, result
.out
);
202 EXPECT_EQ("xabx", fmt::string_view(buffer
, 4));
205 template <typename T
> struct convertible
{
207 explicit convertible(const T
& val
) : value(val
) {}
208 operator T() const { return value
; }
211 TEST(ostream_test
, disable_builtin_ostream_operators
) {
212 EXPECT_EQ("42", fmt::format("{:d}", convertible
<unsigned short>(42)));
213 EXPECT_EQ("foo", fmt::format("{}", convertible
<const char*>("foo")));
216 struct explicitly_convertible_to_string_like
{
217 template <typename String
,
218 typename
= typename
std::enable_if
<std::is_constructible
<
219 String
, const char*, size_t>::value
>::type
>
220 explicit operator String() const {
221 return String("foo", 3u);
225 std::ostream
& operator<<(std::ostream
& os
,
226 explicitly_convertible_to_string_like
) {
230 TEST(ostream_test
, format_explicitly_convertible_to_string_like
) {
231 EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
234 #ifdef FMT_USE_STRING_VIEW
235 struct explicitly_convertible_to_std_string_view
{
236 explicit operator fmt::detail::std_string_view
<char>() const {
241 std::ostream
& operator<<(std::ostream
& os
,
242 explicitly_convertible_to_std_string_view
) {
246 TEST(ostream_test
, format_explicitly_convertible_to_std_string_view
) {
247 EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
249 #endif // FMT_USE_STRING_VIEW
251 struct streamable_and_convertible_to_bool
{
252 operator bool() const { return true; }
255 std::ostream
& operator<<(std::ostream
& os
, streamable_and_convertible_to_bool
) {
259 TEST(ostream_test
, format_convertible_to_bool
) {
260 EXPECT_EQ("foo", fmt::format("{}", streamable_and_convertible_to_bool()));
263 struct copyfmt_test
{};
265 std::ostream
& operator<<(std::ostream
& os
, copyfmt_test
) {
266 std::ios
ios(nullptr);
271 TEST(ostream_test
, copyfmt
) {
272 EXPECT_EQ("foo", fmt::format("{}", copyfmt_test()));
275 TEST(ostream_test
, to_string
) {
276 EXPECT_EQ("abc", fmt::to_string(fmt_test::abc()));
279 TEST(ostream_test
, range
) {
280 auto strs
= std::vector
<test_string
>{test_string("foo"), test_string("bar")};
281 EXPECT_EQ("[foo, bar]", fmt::format("{}", strs
));