substitute_test.cc (11145B)
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> 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 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 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 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 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> 262 void AbslStringify(Sink& sink, EnumWithStringify e) { 263 sink.Append(e == EnumWithStringify::Many ? "Many" : "Choices"); 264 } 265 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 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