diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/fmt/test/std-format-test.cc | |
parent | Initial commit. (diff) | |
download | ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.tar.xz ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/fmt/test/std-format-test.cc')
-rw-r--r-- | src/fmt/test/std-format-test.cc | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/fmt/test/std-format-test.cc b/src/fmt/test/std-format-test.cc new file mode 100644 index 000000000..c4fb5a270 --- /dev/null +++ b/src/fmt/test/std-format-test.cc @@ -0,0 +1,157 @@ +#include <format> + +#include "gtest.h" + +TEST(StdFormatTest, Escaping) { + using namespace std; + string s = format("{0}-{{", 8); // s == "8-{" + EXPECT_EQ(s, "8-{"); +} + +TEST(StdFormatTest, Indexing) { + using namespace std; + string s0 = format("{} to {}", "a", "b"); // OK: automatic indexing + string s1 = format("{1} to {0}", "a", "b"); // OK: manual indexing + EXPECT_EQ(s0, "a to b"); + EXPECT_EQ(s1, "b to a"); + // Error: mixing automatic and manual indexing + EXPECT_THROW(string s2 = format("{0} to {}", "a", "b"), std::format_error); + // Error: mixing automatic and manual indexing + EXPECT_THROW(string s3 = format("{} to {1}", "a", "b"), std::format_error); +} + +TEST(StdFormatTest, Alignment) { + using namespace std; + char c = 120; + string s0 = format("{:6}", 42); // s0 == " 42" + string s1 = format("{:6}", 'x'); // s1 == "x " + string s2 = format("{:*<6}", 'x'); // s2 == "x*****" + string s3 = format("{:*>6}", 'x'); // s3 == "*****x" + string s4 = format("{:*^6}", 'x'); // s4 == "**x***" + // Error: '=' with charT and no integer presentation type + EXPECT_THROW(string s5 = format("{:=6}", 'x'), std::format_error); + string s6 = format("{:6d}", c); // s6 == " 120" + string s7 = format("{:6}", true); // s9 == "true " + EXPECT_EQ(s0, " 42"); + EXPECT_EQ(s1, "x "); + EXPECT_EQ(s2, "x*****"); + EXPECT_EQ(s3, "*****x"); + EXPECT_EQ(s4, "**x***"); + EXPECT_EQ(s6, " 120"); + EXPECT_EQ(s7, "true "); +} + +TEST(StdFormatTest, Float) { + using namespace std; + double inf = numeric_limits<double>::infinity(); + double nan = numeric_limits<double>::quiet_NaN(); + string s0 = format("{0:} {0:+} {0:-} {0: }", 1); // s0 == "1 +1 1 1" + string s1 = format("{0:} {0:+} {0:-} {0: }", -1); // s1 == "-1 -1 -1 -1" + string s2 = + format("{0:} {0:+} {0:-} {0: }", inf); // s2 == "inf +inf inf inf" + string s3 = + format("{0:} {0:+} {0:-} {0: }", nan); // s3 == "nan +nan nan nan" + EXPECT_EQ(s0, "1 +1 1 1"); + EXPECT_EQ(s1, "-1 -1 -1 -1"); + EXPECT_EQ(s2, "inf +inf inf inf"); + EXPECT_EQ(s3, "nan +nan nan nan"); +} + +TEST(StdFormatTest, Int) { + using namespace std; + string s0 = format("{}", 42); // s0 == "42" + string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); // s1 == "101010 42 52 2a" + string s2 = format("{0:#x} {0:#X}", 42); // s2 == "0x2a 0X2A" + string s3 = format("{:n}", 1234); // s3 == "1234" (depends on the locale) + EXPECT_EQ(s0, "42"); + EXPECT_EQ(s1, "101010 42 52 2a"); + EXPECT_EQ(s2, "0x2a 0X2A"); + EXPECT_EQ(s3, "1234"); +} + +#include <format> + +enum color { red, green, blue }; + +const char* color_names[] = {"red", "green", "blue"}; + +template <> struct std::formatter<color> : std::formatter<const char*> { + auto format(color c, format_context& ctx) { + return formatter<const char*>::format(color_names[c], ctx); + } +}; + +struct err {}; + +TEST(StdFormatTest, Formatter) { + std::string s0 = std::format("{}", 42); // OK: library-provided formatter + // std::string s1 = std::format("{}", L"foo"); // Ill-formed: disabled + // formatter + std::string s2 = std::format("{}", red); // OK: user-provided formatter + // std::string s3 = std::format("{}", err{}); // Ill-formed: disabled + // formatter + EXPECT_EQ(s0, "42"); + EXPECT_EQ(s2, "red"); +} + +struct S { + int value; +}; + +template <> struct std::formatter<S> { + size_t width_arg_id = 0; + + // Parses a width argument id in the format { <digit> }. + constexpr auto parse(format_parse_context& ctx) { + auto iter = ctx.begin(); + // auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; }; + auto get_char = [&]() { return iter != ctx.end() ? *iter : '\0'; }; + if (get_char() != '{') return iter; + ++iter; + char c = get_char(); + if (!isdigit(c) || (++iter, get_char()) != '}') + throw format_error("invalid format"); + width_arg_id = c - '0'; + ctx.check_arg_id(width_arg_id); + return ++iter; + } + + // Formats S with width given by the argument width_arg_id. + auto format(S s, format_context& ctx) { + int width = visit_format_arg( + [](auto value) -> int { + using type = decltype(value); + if constexpr (!is_integral_v<type> || is_same_v<type, bool>) + throw format_error("width is not integral"); + // else if (value < 0 || value > numeric_limits<int>::max()) + else if (fmt::detail::is_negative(value) || + value > numeric_limits<int>::max()) + throw format_error("invalid width"); + else + return static_cast<int>(value); + }, + ctx.arg(width_arg_id)); + return format_to(ctx.out(), "{0:{1}}", s.value, width); + } +}; + +TEST(StdFormatTest, Parsing) { + std::string s = std::format("{0:{1}}", S{42}, 10); // s == " 42" + EXPECT_EQ(s, " 42"); +} + +#if FMT_USE_INT128 +template <> struct std::formatter<__int128_t> : std::formatter<long long> { + auto format(__int128_t n, format_context& ctx) { + // Format as a long long since we only want to check if it is possible to + // specialize formatter for __int128_t. + return formatter<long long>::format(static_cast<long long>(n), ctx); + } +}; + +TEST(StdFormatTest, Int128) { + __int128_t n = 42; + auto s = std::format("{}", n); + EXPECT_EQ(s, "42"); +} +#endif // FMT_USE_INT128 |