File: std-format-test.cc

package info (click to toggle)
fmtlib 7.1.3%2Bds1-5
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,576 kB
  • sloc: cpp: 16,453; ansic: 1,366; python: 131; sh: 52; makefile: 24
file content (157 lines) | stat: -rw-r--r-- 5,278 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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("{:L}", 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