• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/format.h"
10 
11 struct test {};
12 
13 // Test that there is no issues with specializations when fmt/ostream.h is
14 // included after fmt/format.h.
15 namespace fmt {
16 template <> struct formatter<test> : formatter<int> {
17   template <typename FormatContext>
formatfmt::formatter18   typename FormatContext::iterator format(const test&, FormatContext& ctx) {
19     return formatter<int>::format(42, ctx);
20   }
21 };
22 }  // namespace fmt
23 
24 #include "fmt/ostream.h"
25 
26 #include <sstream>
27 #include "gmock.h"
28 #include "gtest-extra.h"
29 #include "util.h"
30 
31 using fmt::format;
32 using fmt::format_error;
33 
operator <<(std::ostream & os,const Date & d)34 static std::ostream& operator<<(std::ostream& os, const Date& d) {
35   os << d.year() << '-' << d.month() << '-' << d.day();
36   return os;
37 }
38 
operator <<(std::wostream & os,const Date & d)39 static std::wostream& operator<<(std::wostream& os, const Date& d) {
40   os << d.year() << L'-' << d.month() << L'-' << d.day();
41   return os;
42 }
43 
44 // Make sure that overloaded comma operators do no harm to is_streamable.
45 struct type_with_comma_op {};
46 template <typename T> void operator,(type_with_comma_op, const T&);
47 template <typename T> type_with_comma_op operator<<(T&, const Date&);
48 
49 enum streamable_enum {};
operator <<(std::ostream & os,streamable_enum)50 static std::ostream& operator<<(std::ostream& os, streamable_enum) {
51   return os << "streamable_enum";
52 }
53 
operator <<(std::wostream & os,streamable_enum)54 static std::wostream& operator<<(std::wostream& os, streamable_enum) {
55   return os << L"streamable_enum";
56 }
57 
58 enum unstreamable_enum {};
59 
TEST(OStreamTest,Enum)60 TEST(OStreamTest, Enum) {
61   EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum()));
62   EXPECT_EQ("0", fmt::format("{}", unstreamable_enum()));
63   EXPECT_EQ(L"streamable_enum", fmt::format(L"{}", streamable_enum()));
64   EXPECT_EQ(L"0", fmt::format(L"{}", unstreamable_enum()));
65 }
66 
67 using range = fmt::buffer_range<char>;
68 
69 struct test_arg_formatter : fmt::arg_formatter<range> {
70   fmt::format_parse_context parse_ctx;
test_arg_formattertest_arg_formatter71   test_arg_formatter(fmt::format_context& ctx, fmt::format_specs& s)
72       : fmt::arg_formatter<range>(ctx, &parse_ctx, &s), parse_ctx("") {}
73 };
74 
TEST(OStreamTest,CustomArg)75 TEST(OStreamTest, CustomArg) {
76   fmt::memory_buffer buffer;
77   fmt::internal::buffer<char>& base = buffer;
78   fmt::format_context ctx(std::back_inserter(base), fmt::format_args());
79   fmt::format_specs spec;
80   test_arg_formatter af(ctx, spec);
81   fmt::visit_format_arg(
82       af, fmt::internal::make_arg<fmt::format_context>(streamable_enum()));
83   EXPECT_EQ("streamable_enum", std::string(buffer.data(), buffer.size()));
84 }
85 
TEST(OStreamTest,Format)86 TEST(OStreamTest, Format) {
87   EXPECT_EQ("a string", format("{0}", TestString("a string")));
88   std::string s = format("The date is {0}", Date(2012, 12, 9));
89   EXPECT_EQ("The date is 2012-12-9", s);
90   Date date(2012, 12, 9);
91   EXPECT_EQ(L"The date is 2012-12-9",
92             format(L"The date is {0}", Date(2012, 12, 9)));
93 }
94 
TEST(OStreamTest,FormatSpecs)95 TEST(OStreamTest, FormatSpecs) {
96   EXPECT_EQ("def  ", format("{0:<5}", TestString("def")));
97   EXPECT_EQ("  def", format("{0:>5}", TestString("def")));
98 #if FMT_NUMERIC_ALIGN
99   EXPECT_THROW_MSG(format("{0:=5}", TestString("def")), format_error,
100                    "format specifier requires numeric argument");
101 #endif
102   EXPECT_EQ(" def ", format("{0:^5}", TestString("def")));
103   EXPECT_EQ("def**", format("{0:*<5}", TestString("def")));
104   EXPECT_THROW_MSG(format("{0:+}", TestString()), format_error,
105                    "format specifier requires numeric argument");
106   EXPECT_THROW_MSG(format("{0:-}", TestString()), format_error,
107                    "format specifier requires numeric argument");
108   EXPECT_THROW_MSG(format("{0: }", TestString()), format_error,
109                    "format specifier requires numeric argument");
110   EXPECT_THROW_MSG(format("{0:#}", TestString()), format_error,
111                    "format specifier requires numeric argument");
112   EXPECT_THROW_MSG(format("{0:05}", TestString()), format_error,
113                    "format specifier requires numeric argument");
114   EXPECT_EQ("test         ", format("{0:13}", TestString("test")));
115   EXPECT_EQ("test         ", format("{0:{1}}", TestString("test"), 13));
116   EXPECT_EQ("te", format("{0:.2}", TestString("test")));
117   EXPECT_EQ("te", format("{0:.{1}}", TestString("test"), 2));
118 }
119 
120 struct EmptyTest {};
operator <<(std::ostream & os,EmptyTest)121 static std::ostream& operator<<(std::ostream& os, EmptyTest) {
122   return os << "";
123 }
124 
TEST(OStreamTest,EmptyCustomOutput)125 TEST(OStreamTest, EmptyCustomOutput) {
126   EXPECT_EQ("", fmt::format("{}", EmptyTest()));
127 }
128 
TEST(OStreamTest,Print)129 TEST(OStreamTest, Print) {
130   std::ostringstream os;
131   fmt::print(os, "Don't {}!", "panic");
132   EXPECT_EQ("Don't panic!", os.str());
133   std::wostringstream wos;
134   fmt::print(wos, L"Don't {}!", L"panic");
135   EXPECT_EQ(L"Don't panic!", wos.str());
136 }
137 
TEST(OStreamTest,WriteToOStream)138 TEST(OStreamTest, WriteToOStream) {
139   std::ostringstream os;
140   fmt::memory_buffer buffer;
141   const char* foo = "foo";
142   buffer.append(foo, foo + std::strlen(foo));
143   fmt::internal::write(os, buffer);
144   EXPECT_EQ("foo", os.str());
145 }
146 
TEST(OStreamTest,WriteToOStreamMaxSize)147 TEST(OStreamTest, WriteToOStreamMaxSize) {
148   std::size_t max_size = fmt::internal::max_value<std::size_t>();
149   std::streamsize max_streamsize = fmt::internal::max_value<std::streamsize>();
150   if (max_size <= fmt::internal::to_unsigned(max_streamsize)) return;
151 
152   struct test_buffer : fmt::internal::buffer<char> {
153     explicit test_buffer(std::size_t size) { resize(size); }
154     void grow(std::size_t) {}
155   } buffer(max_size);
156 
157   struct mock_streambuf : std::streambuf {
158     MOCK_METHOD2(xsputn, std::streamsize(const void* s, std::streamsize n));
159     std::streamsize xsputn(const char* s, std::streamsize n) {
160       const void* v = s;
161       return xsputn(v, n);
162     }
163   } streambuf;
164 
165   struct test_ostream : std::ostream {
166     explicit test_ostream(mock_streambuf& buffer) : std::ostream(&buffer) {}
167   } os(streambuf);
168 
169   testing::InSequence sequence;
170   const char* data = nullptr;
171   typedef std::make_unsigned<std::streamsize>::type ustreamsize;
172   ustreamsize size = max_size;
173   do {
174     auto n = std::min(size, fmt::internal::to_unsigned(max_streamsize));
175     EXPECT_CALL(streambuf, xsputn(data, static_cast<std::streamsize>(n)))
176         .WillOnce(testing::Return(max_streamsize));
177     data += n;
178     size -= n;
179   } while (size != 0);
180   fmt::internal::write(os, buffer);
181 }
182 
TEST(OStreamTest,Join)183 TEST(OStreamTest, Join) {
184   int v[3] = {1, 2, 3};
185   EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, v + 3, ", ")));
186 }
187 
188 #if FMT_USE_CONSTEXPR
TEST(OStreamTest,ConstexprString)189 TEST(OStreamTest, ConstexprString) {
190   EXPECT_EQ("42", format(FMT_STRING("{}"), std::string("42")));
191   EXPECT_EQ("a string", format(FMT_STRING("{0}"), TestString("a string")));
192 }
193 #endif
194 
195 namespace fmt_test {
196 struct ABC {};
197 
operator <<(Output & out,ABC)198 template <typename Output> Output& operator<<(Output& out, ABC) {
199   out << "ABC";
200   return out;
201 }
202 }  // namespace fmt_test
203 
204 template <typename T> struct TestTemplate {};
205 
206 template <typename T>
operator <<(std::ostream & os,TestTemplate<T>)207 std::ostream& operator<<(std::ostream& os, TestTemplate<T>) {
208   return os << 1;
209 }
210 
211 namespace fmt {
212 template <typename T> struct formatter<TestTemplate<T>> : formatter<int> {
213   template <typename FormatContext>
formatfmt::formatter214   typename FormatContext::iterator format(TestTemplate<T>, FormatContext& ctx) {
215     return formatter<int>::format(2, ctx);
216   }
217 };
218 }  // namespace fmt
219 
220 #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 407
TEST(OStreamTest,Template)221 TEST(OStreamTest, Template) {
222   EXPECT_EQ("2", fmt::format("{}", TestTemplate<int>()));
223 }
224 
TEST(FormatTest,FormatToN)225 TEST(FormatTest, FormatToN) {
226   char buffer[4];
227   buffer[3] = 'x';
228   auto result = fmt::format_to_n(buffer, 3, "{}", fmt_test::ABC());
229   EXPECT_EQ(3u, result.size);
230   EXPECT_EQ(buffer + 3, result.out);
231   EXPECT_EQ("ABCx", fmt::string_view(buffer, 4));
232   result = fmt::format_to_n(buffer, 3, "x{}y", fmt_test::ABC());
233   EXPECT_EQ(5u, result.size);
234   EXPECT_EQ(buffer + 3, result.out);
235   EXPECT_EQ("xABx", fmt::string_view(buffer, 4));
236 }
237 #endif
238 
239 #if FMT_USE_USER_DEFINED_LITERALS
TEST(FormatTest,UDL)240 TEST(FormatTest, UDL) {
241   using namespace fmt::literals;
242   EXPECT_EQ("{}"_format("test"), "test");
243 }
244 #endif
245 
246 template <typename T> struct convertible {
247   T value;
convertibleconvertible248   explicit convertible(const T& val) : value(val) {}
operator Tconvertible249   operator T() const { return value; }
250 };
251 
TEST(OStreamTest,DisableBuiltinOStreamOperators)252 TEST(OStreamTest, DisableBuiltinOStreamOperators) {
253   EXPECT_EQ("42", fmt::format("{:d}", convertible<unsigned short>(42)));
254   EXPECT_EQ(L"42", fmt::format(L"{:d}", convertible<unsigned short>(42)));
255   EXPECT_EQ("foo", fmt::format("{}", convertible<const char*>("foo")));
256 }
257 
258 struct explicitly_convertible_to_string_like {
259   template <typename String,
260             typename = typename std::enable_if<std::is_constructible<
261                 String, const char*, std::size_t>::value>::type>
operator Stringexplicitly_convertible_to_string_like262   explicit operator String() const {
263     return String("foo", 3u);
264   }
265 };
266 
TEST(FormatterTest,FormatExplicitlyConvertibleToStringLike)267 TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) {
268   EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like()));
269 }
270 
operator <<(std::ostream & os,explicitly_convertible_to_string_like)271 std::ostream& operator<<(std::ostream& os,
272                          explicitly_convertible_to_string_like) {
273   return os << "bar";
274 }
275 
TEST(FormatterTest,FormatExplicitlyConvertibleToStringLikeIgnoreInserter)276 TEST(FormatterTest, FormatExplicitlyConvertibleToStringLikeIgnoreInserter) {
277   EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like()));
278 }
279