• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <format>
2 
3 #include "gtest.h"
4 
TEST(StdFormatTest,Escaping)5 TEST(StdFormatTest, Escaping) {
6   using namespace std;
7   string s = format("{0}-{{", 8);  // s == "8-{"
8   EXPECT_EQ(s, "8-{");
9 }
10 
TEST(StdFormatTest,Indexing)11 TEST(StdFormatTest, Indexing) {
12   using namespace std;
13   string s0 = format("{} to {}", "a", "b");    // OK: automatic indexing
14   string s1 = format("{1} to {0}", "a", "b");  // OK: manual indexing
15   EXPECT_EQ(s0, "a to b");
16   EXPECT_EQ(s1, "b to a");
17   // Error: mixing automatic and manual indexing
18   EXPECT_THROW(string s2 = format("{0} to {}", "a", "b"), std::format_error);
19   // Error: mixing automatic and manual indexing
20   EXPECT_THROW(string s3 = format("{} to {1}", "a", "b"), std::format_error);
21 }
22 
TEST(StdFormatTest,Alignment)23 TEST(StdFormatTest, Alignment) {
24   using namespace std;
25   char c = 120;
26   string s0 = format("{:6}", 42);     // s0 == "    42"
27   string s1 = format("{:6}", 'x');    // s1 == "x     "
28   string s2 = format("{:*<6}", 'x');  // s2 == "x*****"
29   string s3 = format("{:*>6}", 'x');  // s3 == "*****x"
30   string s4 = format("{:*^6}", 'x');  // s4 == "**x***"
31   // Error: '=' with charT and no integer presentation type
32   EXPECT_THROW(string s5 = format("{:=6}", 'x'), std::format_error);
33   string s6 = format("{:6d}", c);    // s6 == "   120"
34   string s7 = format("{:6}", true);  // s9 == "true  "
35   EXPECT_EQ(s0, "    42");
36   EXPECT_EQ(s1, "x     ");
37   EXPECT_EQ(s2, "x*****");
38   EXPECT_EQ(s3, "*****x");
39   EXPECT_EQ(s4, "**x***");
40   EXPECT_EQ(s6, "   120");
41   EXPECT_EQ(s7, "true  ");
42 }
43 
TEST(StdFormatTest,Float)44 TEST(StdFormatTest, Float) {
45   using namespace std;
46   double inf = numeric_limits<double>::infinity();
47   double nan = numeric_limits<double>::quiet_NaN();
48   string s0 = format("{0:} {0:+} {0:-} {0: }", 1);   // s0 == "1 +1 1  1"
49   string s1 = format("{0:} {0:+} {0:-} {0: }", -1);  // s1 == "-1 -1 -1 -1"
50   string s2 =
51       format("{0:} {0:+} {0:-} {0: }", inf);  // s2 == "inf +inf inf  inf"
52   string s3 =
53       format("{0:} {0:+} {0:-} {0: }", nan);  // s3 == "nan +nan nan  nan"
54   EXPECT_EQ(s0, "1 +1 1  1");
55   EXPECT_EQ(s1, "-1 -1 -1 -1");
56   EXPECT_EQ(s2, "inf +inf inf  inf");
57   EXPECT_EQ(s3, "nan +nan nan  nan");
58 }
59 
TEST(StdFormatTest,Int)60 TEST(StdFormatTest, Int) {
61   using namespace std;
62   string s0 = format("{}", 42);                       // s0 == "42"
63   string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42);  // s1 == "101010 42 52 2a"
64   string s2 = format("{0:#x} {0:#X}", 42);            // s2 == "0x2a 0X2A"
65   string s3 = format("{:L}", 1234);  // s3 == "1234" (depends on the locale)
66   EXPECT_EQ(s0, "42");
67   EXPECT_EQ(s1, "101010 42 52 2a");
68   EXPECT_EQ(s2, "0x2a 0X2A");
69   EXPECT_EQ(s3, "1234");
70 }
71 
72 #include <format>
73 
74 enum color { red, green, blue };
75 
76 const char* color_names[] = {"red", "green", "blue"};
77 
78 template <> struct std::formatter<color> : std::formatter<const char*> {
formatstd::formatter79   auto format(color c, format_context& ctx) {
80     return formatter<const char*>::format(color_names[c], ctx);
81   }
82 };
83 
84 struct err {};
85 
TEST(StdFormatTest,Formatter)86 TEST(StdFormatTest, Formatter) {
87   std::string s0 = std::format("{}", 42);  // OK: library-provided formatter
88   // std::string s1 = std::format("{}", L"foo"); // Ill-formed: disabled
89   // formatter
90   std::string s2 = std::format("{}", red);  // OK: user-provided formatter
91   // std::string s3 = std::format("{}", err{});  // Ill-formed: disabled
92   // formatter
93   EXPECT_EQ(s0, "42");
94   EXPECT_EQ(s2, "red");
95 }
96 
97 struct S {
98   int value;
99 };
100 
101 template <> struct std::formatter<S> {
102   size_t width_arg_id = 0;
103 
104   // Parses a width argument id in the format { <digit> }.
parsestd::formatter105   constexpr auto parse(format_parse_context& ctx) {
106     auto iter = ctx.begin();
107     // auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; };
108     auto get_char = [&]() { return iter != ctx.end() ? *iter : '\0'; };
109     if (get_char() != '{') return iter;
110     ++iter;
111     char c = get_char();
112     if (!isdigit(c) || (++iter, get_char()) != '}')
113       throw format_error("invalid format");
114     width_arg_id = c - '0';
115     ctx.check_arg_id(width_arg_id);
116     return ++iter;
117   }
118 
119   // Formats S with width given by the argument width_arg_id.
formatstd::formatter120   auto format(S s, format_context& ctx) {
121     int width = visit_format_arg(
122         [](auto value) -> int {
123           using type = decltype(value);
124           if constexpr (!is_integral_v<type> || is_same_v<type, bool>)
125             throw format_error("width is not integral");
126           // else if (value < 0 || value > numeric_limits<int>::max())
127           else if (fmt::detail::is_negative(value) ||
128                    value > numeric_limits<int>::max())
129             throw format_error("invalid width");
130           else
131             return static_cast<int>(value);
132         },
133         ctx.arg(width_arg_id));
134     return format_to(ctx.out(), "{0:{1}}", s.value, width);
135   }
136 };
137 
TEST(StdFormatTest,Parsing)138 TEST(StdFormatTest, Parsing) {
139   std::string s = std::format("{0:{1}}", S{42}, 10);  // s == "        42"
140   EXPECT_EQ(s, "        42");
141 }
142 
143 #if FMT_USE_INT128
144 template <> struct std::formatter<__int128_t> : std::formatter<long long> {
formatstd::formatter145   auto format(__int128_t n, format_context& ctx) {
146     // Format as a long long since we only want to check if it is possible to
147     // specialize formatter for __int128_t.
148     return formatter<long long>::format(static_cast<long long>(n), ctx);
149   }
150 };
151 
TEST(StdFormatTest,Int128)152 TEST(StdFormatTest, Int128) {
153   __int128_t n = 42;
154   auto s = std::format("{}", n);
155   EXPECT_EQ(s, "42");
156 }
157 #endif  // FMT_USE_INT128
158