//
// For the license information refer to format.h.
+#include <fstream>
+
#include "fmt/format.h"
using fmt::runtime;
#include <sstream>
+#include "fmt/compile.h"
#include "fmt/ostream.h"
#include "fmt/ranges.h"
#include "gmock/gmock.h"
#include "gtest-extra.h"
#include "util.h"
-std::ostream& operator<<(std::ostream& os, const date& d) {
+auto operator<<(std::ostream& os, const date& d) -> std::ostream& {
os << d.year() << '-' << d.month() << '-' << d.day();
return os;
}
-std::wostream& operator<<(std::wostream& os, const date& d) {
+auto operator<<(std::wostream& os, const date& d) -> std::wostream& {
os << d.year() << L'-' << d.month() << L'-' << d.day();
return os;
}
enum streamable_enum {};
-std::ostream& operator<<(std::ostream& os, streamable_enum) {
+auto operator<<(std::ostream& os, streamable_enum) -> std::ostream& {
return os << "streamable_enum";
}
enum unstreamable_enum {};
+auto format_as(unstreamable_enum e) -> int { return e; }
+
+struct empty_test {};
+auto operator<<(std::ostream& os, empty_test) -> std::ostream& {
+ return os << "";
+}
+
+namespace fmt {
+template <> struct formatter<test_string> : ostream_formatter {};
+template <> struct formatter<date> : ostream_formatter {};
+template <> struct formatter<streamable_enum> : ostream_formatter {};
+template <> struct formatter<empty_test> : ostream_formatter {};
+} // namespace fmt
TEST(ostream_test, enum) {
EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum()));
EXPECT_EQ(" def", fmt::format("{0:>5}", test_string("def")));
EXPECT_EQ(" def ", fmt::format("{0:^5}", test_string("def")));
EXPECT_EQ("def**", fmt::format("{0:*<5}", test_string("def")));
- EXPECT_THROW_MSG(fmt::format(runtime("{0:+}"), test_string()), format_error,
- "format specifier requires numeric argument");
- EXPECT_THROW_MSG(fmt::format(runtime("{0:-}"), test_string()), format_error,
- "format specifier requires numeric argument");
- EXPECT_THROW_MSG(fmt::format(runtime("{0: }"), test_string()), format_error,
- "format specifier requires numeric argument");
- EXPECT_THROW_MSG(fmt::format(runtime("{0:#}"), test_string()), format_error,
- "format specifier requires numeric argument");
- EXPECT_THROW_MSG(fmt::format(runtime("{0:05}"), test_string()), format_error,
- "format specifier requires numeric argument");
+ EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), test_string()),
+ format_error, "format specifier requires numeric argument");
+ EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), test_string()),
+ format_error, "format specifier requires numeric argument");
+ EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), test_string()),
+ format_error, "format specifier requires numeric argument");
+ EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), test_string()),
+ format_error, "format specifier requires numeric argument");
+ EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), test_string()),
+ format_error, "format specifier requires numeric argument");
EXPECT_EQ("test ", fmt::format("{0:13}", test_string("test")));
EXPECT_EQ("test ", fmt::format("{0:{1}}", test_string("test"), 13));
EXPECT_EQ("te", fmt::format("{0:.2}", test_string("test")));
EXPECT_EQ("te", fmt::format("{0:.{1}}", test_string("test"), 2));
}
-struct empty_test {};
-std::ostream& operator<<(std::ostream& os, empty_test) { return os << ""; }
-
TEST(ostream_test, empty_custom_output) {
EXPECT_EQ("", fmt::format("{}", empty_test()));
}
struct test_buffer final : fmt::detail::buffer<char> {
explicit test_buffer(size_t size)
: fmt::detail::buffer<char>(nullptr, size, size) {}
- void grow(size_t) {}
+ void grow(size_t) override {}
} buffer(max_size);
struct mock_streambuf : std::streambuf {
MOCK_METHOD2(xsputn, std::streamsize(const void* s, std::streamsize n));
- std::streamsize xsputn(const char* s, std::streamsize n) {
+ auto xsputn(const char* s, std::streamsize n) -> std::streamsize override {
const void* v = s;
return xsputn(v, n);
}
#if FMT_USE_CONSTEXPR
TEST(ostream_test, constexpr_string) {
- EXPECT_EQ("42", format(FMT_STRING("{}"), std::string("42")));
- EXPECT_EQ("a string", format(FMT_STRING("{0}"), test_string("a string")));
+ EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), std::string("42")));
+ EXPECT_EQ("a string",
+ fmt::format(FMT_STRING("{0}"), test_string("a string")));
}
#endif
namespace fmt_test {
struct abc {};
-template <typename Output> Output& operator<<(Output& out, abc) {
+template <typename Output> auto operator<<(Output& out, abc) -> Output& {
return out << "abc";
}
} // namespace fmt_test
template <typename T> struct test_template {};
template <typename T>
-std::ostream& operator<<(std::ostream& os, test_template<T>) {
+auto operator<<(std::ostream& os, test_template<T>) -> std::ostream& {
return os << 1;
}
return formatter<int>::format(2, ctx);
}
};
+
+template <> struct formatter<fmt_test::abc> : ostream_formatter {};
} // namespace fmt
TEST(ostream_test, template) {
EXPECT_EQ("foo", fmt::format("{}", convertible<const char*>("foo")));
}
-struct explicitly_convertible_to_string_like {
- template <typename String,
- typename = typename std::enable_if<std::is_constructible<
- String, const char*, size_t>::value>::type>
- explicit operator String() const {
- return String("foo", 3u);
- }
+struct streamable_and_convertible_to_bool {
+ operator bool() const { return true; }
};
-std::ostream& operator<<(std::ostream& os,
- explicitly_convertible_to_string_like) {
- return os << "bar";
+std::ostream& operator<<(std::ostream& os, streamable_and_convertible_to_bool) {
+ return os << "foo";
}
-TEST(ostream_test, format_explicitly_convertible_to_string_like) {
- EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
+TEST(ostream_test, format_convertible_to_bool) {
+ // operator<< is intentionally not used because of potential ODR violations.
+ EXPECT_EQ(fmt::format("{}", streamable_and_convertible_to_bool()), "true");
}
-#ifdef FMT_USE_STRING_VIEW
-struct explicitly_convertible_to_std_string_view {
- explicit operator fmt::detail::std_string_view<char>() const {
- return {"foo", 3u};
- }
+struct streamable_and_convertible_to_string_view {
+ operator fmt::string_view() const { return "foo"; }
};
std::ostream& operator<<(std::ostream& os,
- explicitly_convertible_to_std_string_view) {
+ streamable_and_convertible_to_string_view) {
return os << "bar";
}
-TEST(ostream_test, format_explicitly_convertible_to_std_string_view) {
- EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
-}
-#endif // FMT_USE_STRING_VIEW
-
-struct streamable_and_convertible_to_bool {
- operator bool() const { return true; }
-};
-
-std::ostream& operator<<(std::ostream& os, streamable_and_convertible_to_bool) {
- return os << "foo";
-}
-
-TEST(ostream_test, format_convertible_to_bool) {
- EXPECT_EQ("foo", fmt::format("{}", streamable_and_convertible_to_bool()));
+TEST(ostream_test, format_convertible_to_string_vew) {
+ // operator<< is intentionally not used because of potential ODR violations.
+ EXPECT_EQ(fmt::format("{}", streamable_and_convertible_to_string_view()),
+ "foo");
}
struct copyfmt_test {};
return os << "foo";
}
+namespace fmt {
+template <> struct formatter<copyfmt_test> : ostream_formatter {};
+} // namespace fmt
+
TEST(ostream_test, copyfmt) {
EXPECT_EQ("foo", fmt::format("{}", copyfmt_test()));
}
auto strs = std::vector<test_string>{test_string("foo"), test_string("bar")};
EXPECT_EQ("[foo, bar]", fmt::format("{}", strs));
}
+
+struct abstract {
+ virtual ~abstract() = default;
+ virtual void f() = 0;
+ friend auto operator<<(std::ostream& os, const abstract&) -> std::ostream& {
+ return os;
+ }
+};
+
+namespace fmt {
+template <> struct formatter<abstract> : ostream_formatter {};
+} // namespace fmt
+
+void format_abstract_compiles(const abstract& a) {
+ fmt::format(FMT_COMPILE("{}"), a);
+}
+
+TEST(ostream_test, is_formattable) {
+ EXPECT_TRUE(fmt::is_formattable<std::string>());
+ EXPECT_TRUE(fmt::is_formattable<fmt::detail::std_string_view<char>>());
+}
+
+struct streamable_and_unformattable {};
+
+auto operator<<(std::ostream& os, streamable_and_unformattable)
+ -> std::ostream& {
+ return os << "foo";
+}
+
+TEST(ostream_test, streamed) {
+ EXPECT_FALSE(fmt::is_formattable<streamable_and_unformattable>());
+ EXPECT_EQ(fmt::format("{}", fmt::streamed(streamable_and_unformattable())),
+ "foo");
+}
+
+TEST(ostream_test, closed_ofstream) {
+ std::ofstream ofs;
+ fmt::print(ofs, "discard");
+}