Mercurial > minori
comparison dep/fmt/test/std-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++ - tests of formatters for standard library types | |
| 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 "fmt/std.h" | |
| 9 | |
| 10 #include <bitset> | |
| 11 #include <stdexcept> | |
| 12 #include <string> | |
| 13 #include <vector> | |
| 14 | |
| 15 #include "fmt/os.h" // fmt::system_category | |
| 16 #include "fmt/ranges.h" | |
| 17 #include "gtest-extra.h" // StartsWith | |
| 18 | |
| 19 #ifdef __cpp_lib_filesystem | |
| 20 TEST(std_test, path) { | |
| 21 using std::filesystem::path; | |
| 22 EXPECT_EQ(fmt::format("{}", path("/usr/bin")), "/usr/bin"); | |
| 23 EXPECT_EQ(fmt::format("{:?}", path("/usr/bin")), "\"/usr/bin\""); | |
| 24 EXPECT_EQ(fmt::format("{:8}", path("foo")), "foo "); | |
| 25 | |
| 26 EXPECT_EQ(fmt::format("{}", path("foo\"bar")), "foo\"bar"); | |
| 27 EXPECT_EQ(fmt::format("{:?}", path("foo\"bar")), "\"foo\\\"bar\""); | |
| 28 | |
| 29 EXPECT_EQ(fmt::format("{:g}", path("/usr/bin")), "/usr/bin"); | |
| 30 # ifdef _WIN32 | |
| 31 EXPECT_EQ(fmt::format("{}", path("C:\\foo")), "C:\\foo"); | |
| 32 EXPECT_EQ(fmt::format("{:g}", path("C:\\foo")), "C:/foo"); | |
| 33 | |
| 34 EXPECT_EQ(fmt::format("{}", path(L"\x0428\x0447\x0443\x0447\x044B\x043D\x0448" | |
| 35 L"\x0447\x044B\x043D\x0430")), | |
| 36 "Шчучыншчына"); | |
| 37 EXPECT_EQ(fmt::format("{}", path(L"\xd800")), "�"); | |
| 38 EXPECT_EQ(fmt::format("{:?}", path(L"\xd800")), "\"\\ud800\""); | |
| 39 # endif | |
| 40 } | |
| 41 | |
| 42 // Test ambiguity problem described in #2954. | |
| 43 TEST(ranges_std_test, format_vector_path) { | |
| 44 auto p = std::filesystem::path("foo/bar.txt"); | |
| 45 auto c = std::vector<std::string>{"abc", "def"}; | |
| 46 EXPECT_EQ(fmt::format("path={}, range={}", p, c), | |
| 47 "path=foo/bar.txt, range=[\"abc\", \"def\"]"); | |
| 48 } | |
| 49 | |
| 50 // Test that path is not escaped twice in the debug mode. | |
| 51 TEST(ranges_std_test, format_quote_path) { | |
| 52 auto vec = | |
| 53 std::vector<std::filesystem::path>{"path1/file1.txt", "path2/file2.txt"}; | |
| 54 EXPECT_EQ(fmt::format("{}", vec), | |
| 55 "[\"path1/file1.txt\", \"path2/file2.txt\"]"); | |
| 56 # ifdef __cpp_lib_optional | |
| 57 auto o = std::optional<std::filesystem::path>("path/file.txt"); | |
| 58 EXPECT_EQ(fmt::format("{}", o), "optional(\"path/file.txt\")"); | |
| 59 EXPECT_EQ(fmt::format("{:?}", o), "optional(\"path/file.txt\")"); | |
| 60 # endif | |
| 61 } | |
| 62 #endif | |
| 63 | |
| 64 TEST(std_test, thread_id) { | |
| 65 EXPECT_FALSE(fmt::format("{}", std::this_thread::get_id()).empty()); | |
| 66 } | |
| 67 | |
| 68 #ifdef __cpp_lib_source_location | |
| 69 TEST(std_test, source_location) { | |
| 70 std::source_location loc = std::source_location::current(); | |
| 71 EXPECT_EQ(fmt::format("{}", loc), | |
| 72 fmt::format("{}:{}:{}: {}", loc.file_name(), loc.line(), | |
| 73 loc.column(), loc.function_name())); | |
| 74 } | |
| 75 #endif | |
| 76 | |
| 77 TEST(std_test, optional) { | |
| 78 #ifdef __cpp_lib_optional | |
| 79 EXPECT_EQ(fmt::format("{}", std::optional<int>{}), "none"); | |
| 80 EXPECT_EQ(fmt::format("{}", std::pair{1, "second"}), "(1, \"second\")"); | |
| 81 EXPECT_EQ(fmt::format("{}", std::vector{std::optional{1}, std::optional{2}, | |
| 82 std::optional{3}}), | |
| 83 "[optional(1), optional(2), optional(3)]"); | |
| 84 EXPECT_EQ( | |
| 85 fmt::format("{}", std::optional<std::optional<const char*>>{{"nested"}}), | |
| 86 "optional(optional(\"nested\"))"); | |
| 87 EXPECT_EQ( | |
| 88 fmt::format("{:<{}}", std::optional{std::string{"left aligned"}}, 30), | |
| 89 "optional(\"left aligned\" )"); | |
| 90 EXPECT_EQ( | |
| 91 fmt::format("{::d}", std::optional{std::vector{'h', 'e', 'l', 'l', 'o'}}), | |
| 92 "optional([104, 101, 108, 108, 111])"); | |
| 93 EXPECT_EQ(fmt::format("{}", std::optional{std::string{"string"}}), | |
| 94 "optional(\"string\")"); | |
| 95 EXPECT_EQ(fmt::format("{}", std::optional{'C'}), "optional(\'C\')"); | |
| 96 EXPECT_EQ(fmt::format("{:.{}f}", std::optional{3.14}, 1), "optional(3.1)"); | |
| 97 | |
| 98 struct unformattable {}; | |
| 99 EXPECT_FALSE((fmt::is_formattable<unformattable>::value)); | |
| 100 EXPECT_FALSE((fmt::is_formattable<std::optional<unformattable>>::value)); | |
| 101 EXPECT_TRUE((fmt::is_formattable<std::optional<int>>::value)); | |
| 102 #endif | |
| 103 } | |
| 104 | |
| 105 namespace my_nso { | |
| 106 enum class my_number { | |
| 107 one, | |
| 108 two, | |
| 109 }; | |
| 110 auto format_as(my_number number) -> fmt::string_view { | |
| 111 return number == my_number::one ? "first" : "second"; | |
| 112 } | |
| 113 | |
| 114 class my_class { | |
| 115 public: | |
| 116 int av; | |
| 117 | |
| 118 private: | |
| 119 friend auto format_as(const my_class& elm) -> std::string { | |
| 120 return fmt::to_string(elm.av); | |
| 121 } | |
| 122 }; | |
| 123 } // namespace my_nso | |
| 124 TEST(std_test, optional_format_as) { | |
| 125 #ifdef __cpp_lib_optional | |
| 126 EXPECT_EQ(fmt::format("{}", std::optional<my_nso::my_number>{}), "none"); | |
| 127 EXPECT_EQ(fmt::format("{}", std::optional{my_nso::my_number::one}), | |
| 128 "optional(\"first\")"); | |
| 129 EXPECT_EQ(fmt::format("{}", std::optional<my_nso::my_class>{}), "none"); | |
| 130 EXPECT_EQ(fmt::format("{}", std::optional{my_nso::my_class{7}}), | |
| 131 "optional(\"7\")"); | |
| 132 #endif | |
| 133 } | |
| 134 | |
| 135 struct throws_on_move { | |
| 136 throws_on_move() = default; | |
| 137 | |
| 138 [[noreturn]] throws_on_move(throws_on_move&&) { | |
| 139 throw std::runtime_error("Thrown by throws_on_move"); | |
| 140 } | |
| 141 | |
| 142 throws_on_move(const throws_on_move&) = default; | |
| 143 }; | |
| 144 | |
| 145 namespace fmt { | |
| 146 template <> struct formatter<throws_on_move> : formatter<string_view> { | |
| 147 auto format(const throws_on_move&, format_context& ctx) const | |
| 148 -> decltype(ctx.out()) { | |
| 149 string_view str("<throws_on_move>"); | |
| 150 return formatter<string_view>::format(str, ctx); | |
| 151 } | |
| 152 }; | |
| 153 } // namespace fmt | |
| 154 | |
| 155 TEST(std_test, variant) { | |
| 156 #ifdef __cpp_lib_variant | |
| 157 EXPECT_EQ(fmt::format("{}", std::monostate{}), "monostate"); | |
| 158 using V0 = std::variant<int, float, std::string, char>; | |
| 159 V0 v0(42); | |
| 160 V0 v1(1.5f); | |
| 161 V0 v2("hello"); | |
| 162 V0 v3('i'); | |
| 163 EXPECT_EQ(fmt::format("{}", v0), "variant(42)"); | |
| 164 EXPECT_EQ(fmt::format("{}", v1), "variant(1.5)"); | |
| 165 EXPECT_EQ(fmt::format("{}", v2), "variant(\"hello\")"); | |
| 166 EXPECT_EQ(fmt::format("{}", v3), "variant('i')"); | |
| 167 | |
| 168 struct unformattable {}; | |
| 169 EXPECT_FALSE((fmt::is_formattable<unformattable>::value)); | |
| 170 EXPECT_FALSE((fmt::is_formattable<std::variant<unformattable>>::value)); | |
| 171 EXPECT_FALSE((fmt::is_formattable<std::variant<unformattable, int>>::value)); | |
| 172 EXPECT_FALSE((fmt::is_formattable<std::variant<int, unformattable>>::value)); | |
| 173 EXPECT_FALSE( | |
| 174 (fmt::is_formattable<std::variant<unformattable, unformattable>>::value)); | |
| 175 EXPECT_TRUE((fmt::is_formattable<std::variant<int, float>>::value)); | |
| 176 | |
| 177 using V1 = std::variant<std::monostate, std::string, std::string>; | |
| 178 V1 v4{}; | |
| 179 V1 v5{std::in_place_index<1>, "yes, this is variant"}; | |
| 180 | |
| 181 EXPECT_EQ(fmt::format("{}", v4), "variant(monostate)"); | |
| 182 EXPECT_EQ(fmt::format("{}", v5), "variant(\"yes, this is variant\")"); | |
| 183 | |
| 184 volatile int i = 42; // Test compile error before GCC 11 described in #3068. | |
| 185 EXPECT_EQ(fmt::format("{}", i), "42"); | |
| 186 | |
| 187 std::variant<std::monostate, throws_on_move> v6; | |
| 188 | |
| 189 try { | |
| 190 throws_on_move thrower; | |
| 191 v6.emplace<throws_on_move>(std::move(thrower)); | |
| 192 } catch (const std::runtime_error&) { | |
| 193 } | |
| 194 // v6 is now valueless by exception | |
| 195 | |
| 196 EXPECT_EQ(fmt::format("{}", v6), "variant(valueless by exception)"); | |
| 197 | |
| 198 #endif | |
| 199 } | |
| 200 | |
| 201 TEST(std_test, error_code) { | |
| 202 EXPECT_EQ("generic:42", | |
| 203 fmt::format(FMT_STRING("{0}"), | |
| 204 std::error_code(42, std::generic_category()))); | |
| 205 EXPECT_EQ("system:42", | |
| 206 fmt::format(FMT_STRING("{0}"), | |
| 207 std::error_code(42, fmt::system_category()))); | |
| 208 EXPECT_EQ("system:-42", | |
| 209 fmt::format(FMT_STRING("{0}"), | |
| 210 std::error_code(-42, fmt::system_category()))); | |
| 211 } | |
| 212 | |
| 213 template <typename Catch> void exception_test() { | |
| 214 try { | |
| 215 throw std::runtime_error("Test Exception"); | |
| 216 } catch (const Catch& ex) { | |
| 217 EXPECT_EQ("Test Exception", fmt::format("{}", ex)); | |
| 218 EXPECT_EQ("std::runtime_error: Test Exception", fmt::format("{:t}", ex)); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 namespace my_ns1 { | |
| 223 namespace my_ns2 { | |
| 224 struct my_exception : public std::exception { | |
| 225 private: | |
| 226 std::string msg; | |
| 227 | |
| 228 public: | |
| 229 my_exception(const std::string& s) : msg(s) {} | |
| 230 const char* what() const noexcept override; | |
| 231 }; | |
| 232 const char* my_exception::what() const noexcept { return msg.c_str(); } | |
| 233 } // namespace my_ns2 | |
| 234 } // namespace my_ns1 | |
| 235 | |
| 236 TEST(std_test, exception) { | |
| 237 using testing::StartsWith; | |
| 238 exception_test<std::exception>(); | |
| 239 exception_test<std::runtime_error>(); | |
| 240 | |
| 241 try { | |
| 242 using namespace my_ns1::my_ns2; | |
| 243 throw my_exception("My Exception"); | |
| 244 } catch (const std::exception& ex) { | |
| 245 EXPECT_EQ("my_ns1::my_ns2::my_exception: My Exception", | |
| 246 fmt::format("{:t}", ex)); | |
| 247 EXPECT_EQ("My Exception", fmt::format("{:}", ex)); | |
| 248 } | |
| 249 | |
| 250 try { | |
| 251 throw std::system_error(std::error_code(), "message"); | |
| 252 } catch (const std::system_error& ex) { | |
| 253 EXPECT_THAT(fmt::format("{:t}", ex), StartsWith("std::system_error: ")); | |
| 254 } | |
| 255 | |
| 256 #ifdef __cpp_lib_filesystem | |
| 257 // Tests that the inline namespace is stripped out, e.g. | |
| 258 // std::filesystem::__cxx11::* -> std::filesystem::*. | |
| 259 try { | |
| 260 throw std::filesystem::filesystem_error("message", std::error_code()); | |
| 261 } catch (const std::filesystem::filesystem_error& ex) { | |
| 262 EXPECT_THAT(fmt::format("{:t}", ex), | |
| 263 StartsWith("std::filesystem::filesystem_error: ")); | |
| 264 } | |
| 265 #endif | |
| 266 } | |
| 267 | |
| 268 TEST(std_test, format_bit_reference) { | |
| 269 std::bitset<2> bs(1); | |
| 270 EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); | |
| 271 std::vector<bool> v = {true, false}; | |
| 272 EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); | |
| 273 } | |
| 274 | |
| 275 TEST(std_test, format_const_bit_reference) { | |
| 276 const std::bitset<2> bs(1); | |
| 277 EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); | |
| 278 const std::vector<bool> v = {true, false}; | |
| 279 EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); | |
| 280 } | |
| 281 | |
| 282 TEST(std_test, format_bitset) { | |
| 283 auto bs = std::bitset<6>(42); | |
| 284 EXPECT_EQ(fmt::format("{}", bs), "101010"); | |
| 285 EXPECT_EQ(fmt::format("{:0>8}", bs), "00101010"); | |
| 286 EXPECT_EQ(fmt::format("{:-^12}", bs), "---101010---"); | |
| 287 } | |
| 288 | |
| 289 TEST(std_test, format_atomic) { | |
| 290 std::atomic<bool> b(false); | |
| 291 EXPECT_EQ(fmt::format("{}", b), "false"); | |
| 292 | |
| 293 const std::atomic<bool> cb(true); | |
| 294 EXPECT_EQ(fmt::format("{}", cb), "true"); | |
| 295 } | |
| 296 | |
| 297 #ifdef __cpp_lib_atomic_flag_test | |
| 298 TEST(std_test, format_atomic_flag) { | |
| 299 std::atomic_flag f = ATOMIC_FLAG_INIT; | |
| 300 (void)f.test_and_set(); | |
| 301 EXPECT_EQ(fmt::format("{}", f), "true"); | |
| 302 | |
| 303 const std::atomic_flag cf = ATOMIC_FLAG_INIT; | |
| 304 EXPECT_EQ(fmt::format("{}", cf), "false"); | |
| 305 } | |
| 306 #endif // __cpp_lib_atomic_flag_test | 
