xref: /aosp_15_r20/external/fmtlib/test/ostream-test.cc (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
1*5c90c05cSAndroid Build Coastguard Worker // Formatting library for C++ - std::ostream support tests
2*5c90c05cSAndroid Build Coastguard Worker //
3*5c90c05cSAndroid Build Coastguard Worker // Copyright (c) 2012 - present, Victor Zverovich
4*5c90c05cSAndroid Build Coastguard Worker // All rights reserved.
5*5c90c05cSAndroid Build Coastguard Worker //
6*5c90c05cSAndroid Build Coastguard Worker // For the license information refer to format.h.
7*5c90c05cSAndroid Build Coastguard Worker 
8*5c90c05cSAndroid Build Coastguard Worker #include <fstream>
9*5c90c05cSAndroid Build Coastguard Worker 
10*5c90c05cSAndroid Build Coastguard Worker #include "fmt/format.h"
11*5c90c05cSAndroid Build Coastguard Worker 
12*5c90c05cSAndroid Build Coastguard Worker using fmt::runtime;
13*5c90c05cSAndroid Build Coastguard Worker 
14*5c90c05cSAndroid Build Coastguard Worker struct test {};
15*5c90c05cSAndroid Build Coastguard Worker 
16*5c90c05cSAndroid Build Coastguard Worker // Test that there is no issues with specializations when fmt/ostream.h is
17*5c90c05cSAndroid Build Coastguard Worker // included after fmt/format.h.
18*5c90c05cSAndroid Build Coastguard Worker namespace fmt {
19*5c90c05cSAndroid Build Coastguard Worker template <> struct formatter<test> : formatter<int> {
formatfmt::formatter20*5c90c05cSAndroid Build Coastguard Worker   auto format(const test&, format_context& ctx) const -> decltype(ctx.out()) {
21*5c90c05cSAndroid Build Coastguard Worker     return formatter<int>::format(42, ctx);
22*5c90c05cSAndroid Build Coastguard Worker   }
23*5c90c05cSAndroid Build Coastguard Worker };
24*5c90c05cSAndroid Build Coastguard Worker }  // namespace fmt
25*5c90c05cSAndroid Build Coastguard Worker 
26*5c90c05cSAndroid Build Coastguard Worker #include <sstream>
27*5c90c05cSAndroid Build Coastguard Worker 
28*5c90c05cSAndroid Build Coastguard Worker #include "fmt/compile.h"
29*5c90c05cSAndroid Build Coastguard Worker #include "fmt/ostream.h"
30*5c90c05cSAndroid Build Coastguard Worker #include "fmt/ranges.h"
31*5c90c05cSAndroid Build Coastguard Worker #include "gmock/gmock.h"
32*5c90c05cSAndroid Build Coastguard Worker #include "gtest-extra.h"
33*5c90c05cSAndroid Build Coastguard Worker #include "util.h"
34*5c90c05cSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const date & d)35*5c90c05cSAndroid Build Coastguard Worker auto operator<<(std::ostream& os, const date& d) -> std::ostream& {
36*5c90c05cSAndroid Build Coastguard Worker   os << d.year() << '-' << d.month() << '-' << d.day();
37*5c90c05cSAndroid Build Coastguard Worker   return os;
38*5c90c05cSAndroid Build Coastguard Worker }
39*5c90c05cSAndroid Build Coastguard Worker 
operator <<(std::wostream & os,const date & d)40*5c90c05cSAndroid Build Coastguard Worker auto operator<<(std::wostream& os, const date& d) -> std::wostream& {
41*5c90c05cSAndroid Build Coastguard Worker   os << d.year() << L'-' << d.month() << L'-' << d.day();
42*5c90c05cSAndroid Build Coastguard Worker   return os;
43*5c90c05cSAndroid Build Coastguard Worker }
44*5c90c05cSAndroid Build Coastguard Worker 
45*5c90c05cSAndroid Build Coastguard Worker // Make sure that overloaded comma operators do no harm to is_streamable.
46*5c90c05cSAndroid Build Coastguard Worker struct type_with_comma_op {};
47*5c90c05cSAndroid Build Coastguard Worker template <typename T> void operator,(type_with_comma_op, const T&);
48*5c90c05cSAndroid Build Coastguard Worker template <typename T> type_with_comma_op operator<<(T&, const date&);
49*5c90c05cSAndroid Build Coastguard Worker 
50*5c90c05cSAndroid Build Coastguard Worker enum streamable_enum {};
51*5c90c05cSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,streamable_enum)52*5c90c05cSAndroid Build Coastguard Worker auto operator<<(std::ostream& os, streamable_enum) -> std::ostream& {
53*5c90c05cSAndroid Build Coastguard Worker   return os << "streamable_enum";
54*5c90c05cSAndroid Build Coastguard Worker }
55*5c90c05cSAndroid Build Coastguard Worker 
56*5c90c05cSAndroid Build Coastguard Worker enum unstreamable_enum {};
format_as(unstreamable_enum e)57*5c90c05cSAndroid Build Coastguard Worker auto format_as(unstreamable_enum e) -> int { return e; }
58*5c90c05cSAndroid Build Coastguard Worker 
59*5c90c05cSAndroid Build Coastguard Worker struct empty_test {};
operator <<(std::ostream & os,empty_test)60*5c90c05cSAndroid Build Coastguard Worker auto operator<<(std::ostream& os, empty_test) -> std::ostream& {
61*5c90c05cSAndroid Build Coastguard Worker   return os << "";
62*5c90c05cSAndroid Build Coastguard Worker }
63*5c90c05cSAndroid Build Coastguard Worker 
64*5c90c05cSAndroid Build Coastguard Worker namespace fmt {
65*5c90c05cSAndroid Build Coastguard Worker template <> struct formatter<test_string> : ostream_formatter {};
66*5c90c05cSAndroid Build Coastguard Worker template <> struct formatter<date> : ostream_formatter {};
67*5c90c05cSAndroid Build Coastguard Worker template <> struct formatter<streamable_enum> : ostream_formatter {};
68*5c90c05cSAndroid Build Coastguard Worker template <> struct formatter<empty_test> : ostream_formatter {};
69*5c90c05cSAndroid Build Coastguard Worker }  // namespace fmt
70*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,enum)71*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, enum) {
72*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum()));
73*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("0", fmt::format("{}", unstreamable_enum()));
74*5c90c05cSAndroid Build Coastguard Worker }
75*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,format)76*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, format) {
77*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("a string", fmt::format("{0}", test_string("a string")));
78*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("The date is 2012-12-9",
79*5c90c05cSAndroid Build Coastguard Worker             fmt::format("The date is {0}", date(2012, 12, 9)));
80*5c90c05cSAndroid Build Coastguard Worker }
81*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,format_specs)82*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, format_specs) {
83*5c90c05cSAndroid Build Coastguard Worker   using fmt::format_error;
84*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("def  ", fmt::format("{0:<5}", test_string("def")));
85*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("  def", fmt::format("{0:>5}", test_string("def")));
86*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ(" def ", fmt::format("{0:^5}", test_string("def")));
87*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("def**", fmt::format("{0:*<5}", test_string("def")));
88*5c90c05cSAndroid Build Coastguard Worker   EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), test_string()),
89*5c90c05cSAndroid Build Coastguard Worker                    format_error, "invalid format specifier");
90*5c90c05cSAndroid Build Coastguard Worker   EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), test_string()),
91*5c90c05cSAndroid Build Coastguard Worker                    format_error, "invalid format specifier");
92*5c90c05cSAndroid Build Coastguard Worker   EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), test_string()),
93*5c90c05cSAndroid Build Coastguard Worker                    format_error, "invalid format specifier");
94*5c90c05cSAndroid Build Coastguard Worker   EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), test_string()),
95*5c90c05cSAndroid Build Coastguard Worker                    format_error, "invalid format specifier");
96*5c90c05cSAndroid Build Coastguard Worker   EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), test_string()),
97*5c90c05cSAndroid Build Coastguard Worker                    format_error, "format specifier requires numeric argument");
98*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("test         ", fmt::format("{0:13}", test_string("test")));
99*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("test         ", fmt::format("{0:{1}}", test_string("test"), 13));
100*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("te", fmt::format("{0:.2}", test_string("test")));
101*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("te", fmt::format("{0:.{1}}", test_string("test"), 2));
102*5c90c05cSAndroid Build Coastguard Worker }
103*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,empty_custom_output)104*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, empty_custom_output) {
105*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("", fmt::format("{}", empty_test()));
106*5c90c05cSAndroid Build Coastguard Worker }
107*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,print)108*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, print) {
109*5c90c05cSAndroid Build Coastguard Worker   {
110*5c90c05cSAndroid Build Coastguard Worker     std::ostringstream os;
111*5c90c05cSAndroid Build Coastguard Worker     fmt::print(os, "Don't {}!", "panic");
112*5c90c05cSAndroid Build Coastguard Worker     EXPECT_EQ("Don't panic!", os.str());
113*5c90c05cSAndroid Build Coastguard Worker   }
114*5c90c05cSAndroid Build Coastguard Worker 
115*5c90c05cSAndroid Build Coastguard Worker   {
116*5c90c05cSAndroid Build Coastguard Worker     std::ostringstream os;
117*5c90c05cSAndroid Build Coastguard Worker     fmt::println(os, "Don't {}!", "panic");
118*5c90c05cSAndroid Build Coastguard Worker     EXPECT_EQ("Don't panic!\n", os.str());
119*5c90c05cSAndroid Build Coastguard Worker   }
120*5c90c05cSAndroid Build Coastguard Worker }
121*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,write_to_ostream)122*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, write_to_ostream) {
123*5c90c05cSAndroid Build Coastguard Worker   std::ostringstream os;
124*5c90c05cSAndroid Build Coastguard Worker   fmt::memory_buffer buffer;
125*5c90c05cSAndroid Build Coastguard Worker   const char* foo = "foo";
126*5c90c05cSAndroid Build Coastguard Worker   buffer.append(foo, foo + std::strlen(foo));
127*5c90c05cSAndroid Build Coastguard Worker   fmt::detail::write_buffer(os, buffer);
128*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("foo", os.str());
129*5c90c05cSAndroid Build Coastguard Worker }
130*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,write_to_ostream_max_size)131*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, write_to_ostream_max_size) {
132*5c90c05cSAndroid Build Coastguard Worker   auto max_size = fmt::detail::max_value<size_t>();
133*5c90c05cSAndroid Build Coastguard Worker   auto max_streamsize = fmt::detail::max_value<std::streamsize>();
134*5c90c05cSAndroid Build Coastguard Worker   if (max_size <= fmt::detail::to_unsigned(max_streamsize)) return;
135*5c90c05cSAndroid Build Coastguard Worker 
136*5c90c05cSAndroid Build Coastguard Worker   struct test_buffer final : fmt::detail::buffer<char> {
137*5c90c05cSAndroid Build Coastguard Worker     explicit test_buffer(size_t size)
138*5c90c05cSAndroid Build Coastguard Worker         : fmt::detail::buffer<char>([](buffer<char>&, size_t) {}, nullptr, size,
139*5c90c05cSAndroid Build Coastguard Worker                                     size) {}
140*5c90c05cSAndroid Build Coastguard Worker   } buffer(max_size);
141*5c90c05cSAndroid Build Coastguard Worker 
142*5c90c05cSAndroid Build Coastguard Worker   struct mock_streambuf : std::streambuf {
143*5c90c05cSAndroid Build Coastguard Worker     MOCK_METHOD(std::streamsize, xsputn, (const void*, std::streamsize));
144*5c90c05cSAndroid Build Coastguard Worker     auto xsputn(const char* s, std::streamsize n) -> std::streamsize override {
145*5c90c05cSAndroid Build Coastguard Worker       const void* v = s;
146*5c90c05cSAndroid Build Coastguard Worker       return xsputn(v, n);
147*5c90c05cSAndroid Build Coastguard Worker     }
148*5c90c05cSAndroid Build Coastguard Worker   } streambuf;
149*5c90c05cSAndroid Build Coastguard Worker 
150*5c90c05cSAndroid Build Coastguard Worker   struct test_ostream : std::ostream {
151*5c90c05cSAndroid Build Coastguard Worker     explicit test_ostream(mock_streambuf& output_buffer)
152*5c90c05cSAndroid Build Coastguard Worker         : std::ostream(&output_buffer) {}
153*5c90c05cSAndroid Build Coastguard Worker   } os(streambuf);
154*5c90c05cSAndroid Build Coastguard Worker 
155*5c90c05cSAndroid Build Coastguard Worker   testing::InSequence sequence;
156*5c90c05cSAndroid Build Coastguard Worker   const char* data = nullptr;
157*5c90c05cSAndroid Build Coastguard Worker   using ustreamsize = std::make_unsigned<std::streamsize>::type;
158*5c90c05cSAndroid Build Coastguard Worker   ustreamsize size = max_size;
159*5c90c05cSAndroid Build Coastguard Worker   do {
160*5c90c05cSAndroid Build Coastguard Worker     auto n = std::min(size, fmt::detail::to_unsigned(max_streamsize));
161*5c90c05cSAndroid Build Coastguard Worker     EXPECT_CALL(streambuf, xsputn(data, static_cast<std::streamsize>(n)))
162*5c90c05cSAndroid Build Coastguard Worker         .WillOnce(testing::Return(max_streamsize));
163*5c90c05cSAndroid Build Coastguard Worker     data += n;
164*5c90c05cSAndroid Build Coastguard Worker     size -= n;
165*5c90c05cSAndroid Build Coastguard Worker   } while (size != 0);
166*5c90c05cSAndroid Build Coastguard Worker   fmt::detail::write_buffer(os, buffer);
167*5c90c05cSAndroid Build Coastguard Worker }
168*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,join)169*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, join) {
170*5c90c05cSAndroid Build Coastguard Worker   int v[3] = {1, 2, 3};
171*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, v + 3, ", ")));
172*5c90c05cSAndroid Build Coastguard Worker }
173*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,join_fallback_formatter)174*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, join_fallback_formatter) {
175*5c90c05cSAndroid Build Coastguard Worker   auto strs = std::vector<test_string>{test_string("foo"), test_string("bar")};
176*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("foo, bar", fmt::format("{}", fmt::join(strs, ", ")));
177*5c90c05cSAndroid Build Coastguard Worker }
178*5c90c05cSAndroid Build Coastguard Worker 
179*5c90c05cSAndroid Build Coastguard Worker #if FMT_USE_CONSTEXPR
TEST(ostream_test,constexpr_string)180*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, constexpr_string) {
181*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), std::string("42")));
182*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("a string",
183*5c90c05cSAndroid Build Coastguard Worker             fmt::format(FMT_STRING("{0}"), test_string("a string")));
184*5c90c05cSAndroid Build Coastguard Worker }
185*5c90c05cSAndroid Build Coastguard Worker #endif
186*5c90c05cSAndroid Build Coastguard Worker 
187*5c90c05cSAndroid Build Coastguard Worker namespace fmt_test {
188*5c90c05cSAndroid Build Coastguard Worker struct abc {};
189*5c90c05cSAndroid Build Coastguard Worker 
operator <<(Output & out,abc)190*5c90c05cSAndroid Build Coastguard Worker template <typename Output> auto operator<<(Output& out, abc) -> Output& {
191*5c90c05cSAndroid Build Coastguard Worker   return out << "abc";
192*5c90c05cSAndroid Build Coastguard Worker }
193*5c90c05cSAndroid Build Coastguard Worker }  // namespace fmt_test
194*5c90c05cSAndroid Build Coastguard Worker 
195*5c90c05cSAndroid Build Coastguard Worker template <typename T> struct test_template {};
196*5c90c05cSAndroid Build Coastguard Worker 
197*5c90c05cSAndroid Build Coastguard Worker template <typename T>
operator <<(std::ostream & os,test_template<T>)198*5c90c05cSAndroid Build Coastguard Worker auto operator<<(std::ostream& os, test_template<T>) -> std::ostream& {
199*5c90c05cSAndroid Build Coastguard Worker   return os << 1;
200*5c90c05cSAndroid Build Coastguard Worker }
201*5c90c05cSAndroid Build Coastguard Worker 
202*5c90c05cSAndroid Build Coastguard Worker namespace fmt {
203*5c90c05cSAndroid Build Coastguard Worker template <typename T> struct formatter<test_template<T>> : formatter<int> {
formatfmt::formatter204*5c90c05cSAndroid Build Coastguard Worker   auto format(test_template<T>, format_context& ctx) const
205*5c90c05cSAndroid Build Coastguard Worker       -> decltype(ctx.out()) {
206*5c90c05cSAndroid Build Coastguard Worker     return formatter<int>::format(2, ctx);
207*5c90c05cSAndroid Build Coastguard Worker   }
208*5c90c05cSAndroid Build Coastguard Worker };
209*5c90c05cSAndroid Build Coastguard Worker 
210*5c90c05cSAndroid Build Coastguard Worker template <> struct formatter<fmt_test::abc> : ostream_formatter {};
211*5c90c05cSAndroid Build Coastguard Worker }  // namespace fmt
212*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,template)213*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, template) {
214*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("2", fmt::format("{}", test_template<int>()));
215*5c90c05cSAndroid Build Coastguard Worker }
216*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,format_to_n)217*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, format_to_n) {
218*5c90c05cSAndroid Build Coastguard Worker   char buffer[4];
219*5c90c05cSAndroid Build Coastguard Worker   buffer[3] = 'x';
220*5c90c05cSAndroid Build Coastguard Worker   auto result = fmt::format_to_n(buffer, 3, "{}", fmt_test::abc());
221*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ(3u, result.size);
222*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ(buffer + 3, result.out);
223*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("abcx", fmt::string_view(buffer, 4));
224*5c90c05cSAndroid Build Coastguard Worker   result = fmt::format_to_n(buffer, 3, "x{}y", fmt_test::abc());
225*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ(5u, result.size);
226*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ(buffer + 3, result.out);
227*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("xabx", fmt::string_view(buffer, 4));
228*5c90c05cSAndroid Build Coastguard Worker }
229*5c90c05cSAndroid Build Coastguard Worker 
230*5c90c05cSAndroid Build Coastguard Worker struct copyfmt_test {};
231*5c90c05cSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,copyfmt_test)232*5c90c05cSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, copyfmt_test) {
233*5c90c05cSAndroid Build Coastguard Worker   std::ios ios(nullptr);
234*5c90c05cSAndroid Build Coastguard Worker   ios.copyfmt(os);
235*5c90c05cSAndroid Build Coastguard Worker   return os << "foo";
236*5c90c05cSAndroid Build Coastguard Worker }
237*5c90c05cSAndroid Build Coastguard Worker 
238*5c90c05cSAndroid Build Coastguard Worker namespace fmt {
239*5c90c05cSAndroid Build Coastguard Worker template <> struct formatter<copyfmt_test> : ostream_formatter {};
240*5c90c05cSAndroid Build Coastguard Worker }  // namespace fmt
241*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,copyfmt)242*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, copyfmt) {
243*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("foo", fmt::format("{}", copyfmt_test()));
244*5c90c05cSAndroid Build Coastguard Worker }
245*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,to_string)246*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, to_string) {
247*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("abc", fmt::to_string(fmt_test::abc()));
248*5c90c05cSAndroid Build Coastguard Worker }
249*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,range)250*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, range) {
251*5c90c05cSAndroid Build Coastguard Worker   auto strs = std::vector<test_string>{test_string("foo"), test_string("bar")};
252*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ("[foo, bar]", fmt::format("{}", strs));
253*5c90c05cSAndroid Build Coastguard Worker }
254*5c90c05cSAndroid Build Coastguard Worker 
255*5c90c05cSAndroid Build Coastguard Worker struct abstract {
256*5c90c05cSAndroid Build Coastguard Worker   virtual ~abstract() = default;
257*5c90c05cSAndroid Build Coastguard Worker   virtual void f() = 0;
operator <<(std::ostream & os,const abstract &)258*5c90c05cSAndroid Build Coastguard Worker   friend auto operator<<(std::ostream& os, const abstract&) -> std::ostream& {
259*5c90c05cSAndroid Build Coastguard Worker     return os;
260*5c90c05cSAndroid Build Coastguard Worker   }
261*5c90c05cSAndroid Build Coastguard Worker };
262*5c90c05cSAndroid Build Coastguard Worker 
263*5c90c05cSAndroid Build Coastguard Worker namespace fmt {
264*5c90c05cSAndroid Build Coastguard Worker template <> struct formatter<abstract> : ostream_formatter {};
265*5c90c05cSAndroid Build Coastguard Worker }  // namespace fmt
266*5c90c05cSAndroid Build Coastguard Worker 
format_abstract_compiles(const abstract & a)267*5c90c05cSAndroid Build Coastguard Worker void format_abstract_compiles(const abstract& a) {
268*5c90c05cSAndroid Build Coastguard Worker   fmt::format(FMT_COMPILE("{}"), a);
269*5c90c05cSAndroid Build Coastguard Worker }
270*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,is_formattable)271*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, is_formattable) {
272*5c90c05cSAndroid Build Coastguard Worker   EXPECT_TRUE(fmt::is_formattable<std::string>());
273*5c90c05cSAndroid Build Coastguard Worker   EXPECT_TRUE(fmt::is_formattable<fmt::detail::std_string_view<char>>());
274*5c90c05cSAndroid Build Coastguard Worker }
275*5c90c05cSAndroid Build Coastguard Worker 
276*5c90c05cSAndroid Build Coastguard Worker struct streamable_and_unformattable {};
277*5c90c05cSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,streamable_and_unformattable)278*5c90c05cSAndroid Build Coastguard Worker auto operator<<(std::ostream& os, streamable_and_unformattable)
279*5c90c05cSAndroid Build Coastguard Worker     -> std::ostream& {
280*5c90c05cSAndroid Build Coastguard Worker   return os << "foo";
281*5c90c05cSAndroid Build Coastguard Worker }
282*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,streamed)283*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, streamed) {
284*5c90c05cSAndroid Build Coastguard Worker   EXPECT_FALSE(fmt::is_formattable<streamable_and_unformattable>());
285*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ(fmt::format("{}", fmt::streamed(streamable_and_unformattable())),
286*5c90c05cSAndroid Build Coastguard Worker             "foo");
287*5c90c05cSAndroid Build Coastguard Worker }
288*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,closed_ofstream)289*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, closed_ofstream) {
290*5c90c05cSAndroid Build Coastguard Worker   std::ofstream ofs;
291*5c90c05cSAndroid Build Coastguard Worker   fmt::print(ofs, "discard");
292*5c90c05cSAndroid Build Coastguard Worker }
293*5c90c05cSAndroid Build Coastguard Worker 
294*5c90c05cSAndroid Build Coastguard Worker struct unlocalized {};
295*5c90c05cSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,unlocalized)296*5c90c05cSAndroid Build Coastguard Worker auto operator<<(std::ostream& os, unlocalized) -> std::ostream& {
297*5c90c05cSAndroid Build Coastguard Worker   return os << 12345;
298*5c90c05cSAndroid Build Coastguard Worker }
299*5c90c05cSAndroid Build Coastguard Worker 
300*5c90c05cSAndroid Build Coastguard Worker namespace fmt {
301*5c90c05cSAndroid Build Coastguard Worker template <> struct formatter<unlocalized> : ostream_formatter {};
302*5c90c05cSAndroid Build Coastguard Worker }  // namespace fmt
303*5c90c05cSAndroid Build Coastguard Worker 
TEST(ostream_test,unlocalized)304*5c90c05cSAndroid Build Coastguard Worker TEST(ostream_test, unlocalized) {
305*5c90c05cSAndroid Build Coastguard Worker   auto loc = get_locale("en_US.UTF-8");
306*5c90c05cSAndroid Build Coastguard Worker   std::locale::global(loc);
307*5c90c05cSAndroid Build Coastguard Worker   EXPECT_EQ(fmt::format(loc, "{}", unlocalized()), "12345");
308*5c90c05cSAndroid Build Coastguard Worker }
309