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