1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/strings/substitute.h"
16
17 #include <cstdint>
18 #include <cstring>
19 #include <string>
20 #include <vector>
21
22 #include "gtest/gtest.h"
23 #include "absl/strings/str_cat.h"
24 #include "absl/strings/string_view.h"
25
26 namespace {
27
28 struct MyStruct {
29 template <typename Sink>
AbslStringify(Sink & sink,const MyStruct & s)30 friend void AbslStringify(Sink& sink, const MyStruct& s) {
31 sink.Append("MyStruct{.value = ");
32 sink.Append(absl::StrCat(s.value));
33 sink.Append("}");
34 }
35 int value;
36 };
37
TEST(SubstituteTest,Substitute)38 TEST(SubstituteTest, Substitute) {
39 // Basic.
40 EXPECT_EQ("Hello, world!", absl::Substitute("$0, $1!", "Hello", "world"));
41
42 // Non-char* types.
43 EXPECT_EQ("123 0.2 0.1 foo true false x",
44 absl::Substitute("$0 $1 $2 $3 $4 $5 $6", 123, 0.2, 0.1f,
45 std::string("foo"), true, false, 'x'));
46
47 // All int types.
48 EXPECT_EQ(
49 "-32767 65535 "
50 "-1234567890 3234567890 "
51 "-1234567890 3234567890 "
52 "-1234567890123456789 9234567890123456789",
53 absl::Substitute(
54 "$0 $1 $2 $3 $4 $5 $6 $7",
55 static_cast<short>(-32767), // NOLINT(runtime/int)
56 static_cast<unsigned short>(65535), // NOLINT(runtime/int)
57 -1234567890, 3234567890U, -1234567890L, 3234567890UL,
58 -int64_t{1234567890123456789}, uint64_t{9234567890123456789u}));
59
60 // Hex format
61 EXPECT_EQ("0 1 f ffff0ffff 0123456789abcdef",
62 absl::Substitute("$0$1$2$3$4 $5", //
63 absl::Hex(0), absl::Hex(1, absl::kSpacePad2),
64 absl::Hex(0xf, absl::kSpacePad2),
65 absl::Hex(int16_t{-1}, absl::kSpacePad5),
66 absl::Hex(int16_t{-1}, absl::kZeroPad5),
67 absl::Hex(0x123456789abcdef, absl::kZeroPad16)));
68
69 // Dec format
70 EXPECT_EQ("0 115 -1-0001 81985529216486895",
71 absl::Substitute("$0$1$2$3$4 $5", //
72 absl::Dec(0), absl::Dec(1, absl::kSpacePad2),
73 absl::Dec(0xf, absl::kSpacePad2),
74 absl::Dec(int16_t{-1}, absl::kSpacePad5),
75 absl::Dec(int16_t{-1}, absl::kZeroPad5),
76 absl::Dec(0x123456789abcdef, absl::kZeroPad16)));
77
78 // Pointer.
79 const int* int_p = reinterpret_cast<const int*>(0x12345);
80 std::string str = absl::Substitute("$0", int_p);
81 EXPECT_EQ(absl::StrCat("0x", absl::Hex(int_p)), str);
82
83 // Volatile Pointer.
84 // Like C++ streamed I/O, such pointers implicitly become bool
85 volatile int vol = 237;
86 volatile int* volatile volptr = &vol;
87 str = absl::Substitute("$0", volptr);
88 EXPECT_EQ("true", str);
89
90 // null is special. StrCat prints 0x0. Substitute prints NULL.
91 const uint64_t* null_p = nullptr;
92 str = absl::Substitute("$0", null_p);
93 EXPECT_EQ("NULL", str);
94
95 // char* is also special.
96 const char* char_p = "print me";
97 str = absl::Substitute("$0", char_p);
98 EXPECT_EQ("print me", str);
99
100 char char_buf[16];
101 strncpy(char_buf, "print me too", sizeof(char_buf));
102 str = absl::Substitute("$0", char_buf);
103 EXPECT_EQ("print me too", str);
104
105 // null char* is "doubly" special. Represented as the empty string.
106 char_p = nullptr;
107 str = absl::Substitute("$0", char_p);
108 EXPECT_EQ("", str);
109
110 // Out-of-order.
111 EXPECT_EQ("b, a, c, b", absl::Substitute("$1, $0, $2, $1", "a", "b", "c"));
112
113 // Literal $
114 EXPECT_EQ("$", absl::Substitute("$$"));
115
116 EXPECT_EQ("$1", absl::Substitute("$$1"));
117
118 // Test all overloads.
119 EXPECT_EQ("a", absl::Substitute("$0", "a"));
120 EXPECT_EQ("a b", absl::Substitute("$0 $1", "a", "b"));
121 EXPECT_EQ("a b c", absl::Substitute("$0 $1 $2", "a", "b", "c"));
122 EXPECT_EQ("a b c d", absl::Substitute("$0 $1 $2 $3", "a", "b", "c", "d"));
123 EXPECT_EQ("a b c d e",
124 absl::Substitute("$0 $1 $2 $3 $4", "a", "b", "c", "d", "e"));
125 EXPECT_EQ("a b c d e f", absl::Substitute("$0 $1 $2 $3 $4 $5", "a", "b", "c",
126 "d", "e", "f"));
127 EXPECT_EQ("a b c d e f g", absl::Substitute("$0 $1 $2 $3 $4 $5 $6", "a", "b",
128 "c", "d", "e", "f", "g"));
129 EXPECT_EQ("a b c d e f g h",
130 absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7", "a", "b", "c", "d", "e",
131 "f", "g", "h"));
132 EXPECT_EQ("a b c d e f g h i",
133 absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8", "a", "b", "c", "d",
134 "e", "f", "g", "h", "i"));
135 EXPECT_EQ("a b c d e f g h i j",
136 absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9", "a", "b", "c",
137 "d", "e", "f", "g", "h", "i", "j"));
138 EXPECT_EQ("a b c d e f g h i j b0",
139 absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $10", "a", "b", "c",
140 "d", "e", "f", "g", "h", "i", "j"));
141
142 const char* null_cstring = nullptr;
143 EXPECT_EQ("Text: ''", absl::Substitute("Text: '$0'", null_cstring));
144
145 MyStruct s1 = MyStruct{17};
146 MyStruct s2 = MyStruct{1043};
147 EXPECT_EQ("MyStruct{.value = 17}, MyStruct{.value = 1043}",
148 absl::Substitute("$0, $1", s1, s2));
149 }
150
TEST(SubstituteTest,SubstituteAndAppend)151 TEST(SubstituteTest, SubstituteAndAppend) {
152 std::string str = "Hello";
153 absl::SubstituteAndAppend(&str, ", $0!", "world");
154 EXPECT_EQ("Hello, world!", str);
155
156 // Test all overloads.
157 str.clear();
158 absl::SubstituteAndAppend(&str, "$0", "a");
159 EXPECT_EQ("a", str);
160 str.clear();
161 absl::SubstituteAndAppend(&str, "$0 $1", "a", "b");
162 EXPECT_EQ("a b", str);
163 str.clear();
164 absl::SubstituteAndAppend(&str, "$0 $1 $2", "a", "b", "c");
165 EXPECT_EQ("a b c", str);
166 str.clear();
167 absl::SubstituteAndAppend(&str, "$0 $1 $2 $3", "a", "b", "c", "d");
168 EXPECT_EQ("a b c d", str);
169 str.clear();
170 absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4", "a", "b", "c", "d", "e");
171 EXPECT_EQ("a b c d e", str);
172 str.clear();
173 absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5", "a", "b", "c", "d", "e",
174 "f");
175 EXPECT_EQ("a b c d e f", str);
176 str.clear();
177 absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6", "a", "b", "c", "d",
178 "e", "f", "g");
179 EXPECT_EQ("a b c d e f g", str);
180 str.clear();
181 absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7", "a", "b", "c", "d",
182 "e", "f", "g", "h");
183 EXPECT_EQ("a b c d e f g h", str);
184 str.clear();
185 absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7 $8", "a", "b", "c",
186 "d", "e", "f", "g", "h", "i");
187 EXPECT_EQ("a b c d e f g h i", str);
188 str.clear();
189 absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7 $8 $9", "a", "b",
190 "c", "d", "e", "f", "g", "h", "i", "j");
191 EXPECT_EQ("a b c d e f g h i j", str);
192
193 str.clear();
194 MyStruct s1 = MyStruct{17};
195 MyStruct s2 = MyStruct{1043};
196 absl::SubstituteAndAppend(&str, "$0, $1", s1, s2);
197 EXPECT_EQ("MyStruct{.value = 17}, MyStruct{.value = 1043}", str);
198 }
199
TEST(SubstituteTest,VectorBoolRef)200 TEST(SubstituteTest, VectorBoolRef) {
201 std::vector<bool> v = {true, false};
202 const auto& cv = v;
203 EXPECT_EQ("true false true false",
204 absl::Substitute("$0 $1 $2 $3", v[0], v[1], cv[0], cv[1]));
205
206 std::string str = "Logic be like: ";
207 absl::SubstituteAndAppend(&str, "$0 $1 $2 $3", v[0], v[1], cv[0], cv[1]);
208 EXPECT_EQ("Logic be like: true false true false", str);
209 }
210
TEST(SubstituteTest,Enums)211 TEST(SubstituteTest, Enums) {
212 enum UnscopedEnum { kEnum0 = 0, kEnum1 = 1 };
213 EXPECT_EQ("0 1", absl::Substitute("$0 $1", UnscopedEnum::kEnum0,
214 UnscopedEnum::kEnum1));
215
216 enum class ScopedEnum { kEnum0 = 0, kEnum1 = 1 };
217 EXPECT_EQ("0 1",
218 absl::Substitute("$0 $1", ScopedEnum::kEnum0, ScopedEnum::kEnum1));
219
220 enum class ScopedEnumInt32 : int32_t { kEnum0 = 989, kEnum1 = INT32_MIN };
221 EXPECT_EQ("989 -2147483648",
222 absl::Substitute("$0 $1", ScopedEnumInt32::kEnum0,
223 ScopedEnumInt32::kEnum1));
224
225 enum class ScopedEnumUInt32 : uint32_t { kEnum0 = 1, kEnum1 = UINT32_MAX };
226 EXPECT_EQ("1 4294967295", absl::Substitute("$0 $1", ScopedEnumUInt32::kEnum0,
227 ScopedEnumUInt32::kEnum1));
228
229 enum class ScopedEnumInt64 : int64_t { kEnum0 = -1, kEnum1 = 42949672950 };
230 EXPECT_EQ("-1 42949672950", absl::Substitute("$0 $1", ScopedEnumInt64::kEnum0,
231 ScopedEnumInt64::kEnum1));
232
233 enum class ScopedEnumUInt64 : uint64_t { kEnum0 = 1, kEnum1 = 42949672950 };
234 EXPECT_EQ("1 42949672950", absl::Substitute("$0 $1", ScopedEnumUInt64::kEnum0,
235 ScopedEnumUInt64::kEnum1));
236
237 enum class ScopedEnumChar : signed char { kEnum0 = -1, kEnum1 = 1 };
238 EXPECT_EQ("-1 1", absl::Substitute("$0 $1", ScopedEnumChar::kEnum0,
239 ScopedEnumChar::kEnum1));
240
241 enum class ScopedEnumUChar : unsigned char {
242 kEnum0 = 0,
243 kEnum1 = 1,
244 kEnumMax = 255
245 };
246 EXPECT_EQ("0 1 255", absl::Substitute("$0 $1 $2", ScopedEnumUChar::kEnum0,
247 ScopedEnumUChar::kEnum1,
248 ScopedEnumUChar::kEnumMax));
249
250 enum class ScopedEnumInt16 : int16_t { kEnum0 = -100, kEnum1 = 10000 };
251 EXPECT_EQ("-100 10000", absl::Substitute("$0 $1", ScopedEnumInt16::kEnum0,
252 ScopedEnumInt16::kEnum1));
253
254 enum class ScopedEnumUInt16 : uint16_t { kEnum0 = 0, kEnum1 = 10000 };
255 EXPECT_EQ("0 10000", absl::Substitute("$0 $1", ScopedEnumUInt16::kEnum0,
256 ScopedEnumUInt16::kEnum1));
257 }
258
259 enum class EnumWithStringify { Many = 0, Choices = 1 };
260
261 template <typename Sink>
AbslStringify(Sink & sink,EnumWithStringify e)262 void AbslStringify(Sink& sink, EnumWithStringify e) {
263 sink.Append(e == EnumWithStringify::Many ? "Many" : "Choices");
264 }
265
TEST(SubstituteTest,AbslStringifyWithEnum)266 TEST(SubstituteTest, AbslStringifyWithEnum) {
267 const auto e = EnumWithStringify::Choices;
268 EXPECT_EQ(absl::Substitute("$0", e), "Choices");
269 }
270
271 #if GTEST_HAS_DEATH_TEST
272
TEST(SubstituteDeathTest,SubstituteDeath)273 TEST(SubstituteDeathTest, SubstituteDeath) {
274 EXPECT_DEBUG_DEATH(
275 static_cast<void>(absl::Substitute(absl::string_view("-$2"), "a", "b")),
276 "Invalid absl::Substitute\\(\\) format string: asked for \"\\$2\", "
277 "but only 2 args were given.");
278 EXPECT_DEBUG_DEATH(
279 static_cast<void>(absl::Substitute(absl::string_view("-$z-"))),
280 "Invalid absl::Substitute\\(\\) format string: \"-\\$z-\"");
281 EXPECT_DEBUG_DEATH(
282 static_cast<void>(absl::Substitute(absl::string_view("-$"))),
283 "Invalid absl::Substitute\\(\\) format string: \"-\\$\"");
284 }
285
286 #endif // GTEST_HAS_DEATH_TEST
287
288 } // namespace
289