summaryrefslogtreecommitdiff
path: root/absl/strings/internal/str_format/checker_test.cc
blob: ea2a7681a62a646a5f9d5011ff9a7586b0136abd (plain)
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
#include <string>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/strings/str_format.h"

namespace absl {
ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
namespace {

std::string ConvToString(Conv conv) {
  std::string out;
#define CONV_SET_CASE(c) \
  if (Contains(conv, Conv::c)) out += #c;
  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )
#undef CONV_SET_CASE
  if (Contains(conv, Conv::star)) out += "*";
  return out;
}

TEST(StrFormatChecker, ArgumentToConv) {
  Conv conv = ArgumentToConv<std::string>();
  EXPECT_EQ(ConvToString(conv), "s");

  conv = ArgumentToConv<const char*>();
  EXPECT_EQ(ConvToString(conv), "sp");

  conv = ArgumentToConv<double>();
  EXPECT_EQ(ConvToString(conv), "fFeEgGaA");

  conv = ArgumentToConv<int>();
  EXPECT_EQ(ConvToString(conv), "cdiouxXfFeEgGaA*");

  conv = ArgumentToConv<std::string*>();
  EXPECT_EQ(ConvToString(conv), "p");
}

#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER

struct Case {
  bool result;
  const char* format;
};

template <typename... Args>
constexpr Case ValidFormat(const char* format) {
  return {ValidFormatImpl<ArgumentToConv<Args>()...>(format), format};
}

TEST(StrFormatChecker, ValidFormat) {
  // We want to make sure these expressions are constexpr and they have the
  // expected value.
  // If they are not constexpr the attribute will just ignore them and not give
  // a compile time error.
  enum e {};
  enum class e2 {};
  constexpr Case trues[] = {
      ValidFormat<>("abc"),  //

      ValidFormat<e>("%d"),                             //
      ValidFormat<e2>("%d"),                            //
      ValidFormat<int>("%% %d"),                        //
      ValidFormat<int>("%ld"),                          //
      ValidFormat<int>("%lld"),                         //
      ValidFormat<std::string>("%s"),                   //
      ValidFormat<std::string>("%10s"),                 //
      ValidFormat<int>("%.10x"),                        //
      ValidFormat<int, int>("%*.3x"),                   //
      ValidFormat<int>("%1.d"),                         //
      ValidFormat<int>("%.d"),                          //
      ValidFormat<int, double>("%d %g"),                //
      ValidFormat<int, std::string>("%*s"),             //
      ValidFormat<int, double>("%.*f"),                 //
      ValidFormat<void (*)(), volatile int*>("%p %p"),  //
      ValidFormat<string_view, const char*, double, void*>(
          "string_view=%s const char*=%s double=%f void*=%p)"),

      ValidFormat<int>("%% %1$d"),               //
      ValidFormat<int>("%1$ld"),                 //
      ValidFormat<int>("%1$lld"),                //
      ValidFormat<std::string>("%1$s"),          //
      ValidFormat<std::string>("%1$10s"),        //
      ValidFormat<int>("%1$.10x"),               //
      ValidFormat<int>("%1$*1$.*1$d"),           //
      ValidFormat<int, int>("%1$*2$.3x"),        //
      ValidFormat<int>("%1$1.d"),                //
      ValidFormat<int>("%1$.d"),                 //
      ValidFormat<double, int>("%2$d %1$g"),     //
      ValidFormat<int, std::string>("%2$*1$s"),  //
      ValidFormat<int, double>("%2$.*1$f"),      //
      ValidFormat<void*, string_view, const char*, double>(
          "string_view=%2$s const char*=%3$s double=%4$f void*=%1$p "
          "repeat=%3$s)")};

  for (Case c : trues) {
    EXPECT_TRUE(c.result) << c.format;
  }

  constexpr Case falses[] = {
      ValidFormat<int>(""),  //

      ValidFormat<e>("%s"),                  //
      ValidFormat<e2>("%s"),                 //
      ValidFormat<>("%s"),                   //
      ValidFormat<>("%r"),                   //
      ValidFormat<int>("%s"),                //
      ValidFormat<int>("%.1.d"),             //
      ValidFormat<int>("%*1d"),              //
      ValidFormat<int>("%1-d"),              //
      ValidFormat<std::string, int>("%*s"),  //
      ValidFormat<int>("%*d"),               //
      ValidFormat<std::string>("%p"),        //
      ValidFormat<int (*)(int)>("%d"),       //

      ValidFormat<>("%3$d"),                     //
      ValidFormat<>("%1$r"),                     //
      ValidFormat<int>("%1$s"),                  //
      ValidFormat<int>("%1$.1.d"),               //
      ValidFormat<int>("%1$*2$1d"),              //
      ValidFormat<int>("%1$1-d"),                //
      ValidFormat<std::string, int>("%2$*1$s"),  //
      ValidFormat<std::string>("%1$p"),

      ValidFormat<int, int>("%d %2$d"),  //
  };

  for (Case c : falses) {
    EXPECT_FALSE(c.result) << c.format;
  }
}

TEST(StrFormatChecker, LongFormat) {
#define CHARS_X_40 "1234567890123456789012345678901234567890"
#define CHARS_X_400                                                            \
  CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 \
      CHARS_X_40 CHARS_X_40 CHARS_X_40
#define CHARS_X_4000                                                      \
  CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400 \
      CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400
  constexpr char long_format[] =
      CHARS_X_4000 "%d" CHARS_X_4000 "%s" CHARS_X_4000;
  constexpr bool is_valid = ValidFormat<int, std::string>(long_format).result;
  EXPECT_TRUE(is_valid);
}

#endif  // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER

}  // namespace
}  // namespace str_format_internal
ABSL_NAMESPACE_END
}  // namespace absl