1 /* 2 printf tests. 3 4 Copyright (c) 2012-2014, Victor Zverovich 5 All rights reserved. 6 7 Redistribution and use in source and binary forms, with or without 8 modification, are permitted provided that the following conditions are met: 9 10 1. Redistributions of source code must retain the above copyright notice, this 11 list of conditions and the following disclaimer. 12 2. Redistributions in binary form must reproduce the above copyright notice, 13 this list of conditions and the following disclaimer in the documentation 14 and/or other materials provided with the distribution. 15 16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <cctype> 29 #include <climits> 30 #include <cstring> 31 32 #include "fmt/printf.h" 33 #include "fmt/format.h" 34 #include "gtest-extra.h" 35 #include "util.h" 36 37 using fmt::format; 38 using fmt::FormatError; 39 40 const unsigned BIG_NUM = INT_MAX + 1u; 41 42 // Makes format string argument positional. 43 std::string make_positional(fmt::StringRef format) { 44 std::string s(format.to_string()); 45 s.replace(s.find('%'), 1, "%1$"); 46 return s; 47 } 48 49 #define EXPECT_PRINTF(expected_output, format, arg) \ 50 EXPECT_EQ(expected_output, fmt::sprintf(format, arg)) \ 51 << "format: " << format; \ 52 EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg)) 53 54 TEST(PrintfTest, NoArgs) { 55 EXPECT_EQ("test", fmt::sprintf("test")); 56 } 57 58 TEST(PrintfTest, Escape) { 59 EXPECT_EQ("%", fmt::sprintf("%%")); 60 EXPECT_EQ("before %", fmt::sprintf("before %%")); 61 EXPECT_EQ("% after", fmt::sprintf("%% after")); 62 EXPECT_EQ("before % after", fmt::sprintf("before %% after")); 63 EXPECT_EQ("%s", fmt::sprintf("%%s")); 64 } 65 66 TEST(PrintfTest, PositionalArgs) { 67 EXPECT_EQ("42", fmt::sprintf("%1$d", 42)); 68 EXPECT_EQ("before 42", fmt::sprintf("before %1$d", 42)); 69 EXPECT_EQ("42 after", fmt::sprintf("%1$d after",42)); 70 EXPECT_EQ("before 42 after", fmt::sprintf("before %1$d after", 42)); 71 EXPECT_EQ("answer = 42", fmt::sprintf("%1$s = %2$d", "answer", 42)); 72 EXPECT_EQ("42 is the answer", 73 fmt::sprintf("%2$d is the %1$s", "answer", 42)); 74 EXPECT_EQ("abracadabra", fmt::sprintf("%1$s%2$s%1$s", "abra", "cad")); 75 } 76 77 TEST(PrintfTest, AutomaticArgIndexing) { 78 EXPECT_EQ("abc", fmt::sprintf("%c%c%c", 'a', 'b', 'c')); 79 } 80 81 TEST(PrintfTest, NumberIsTooBigInArgIndex) { 82 EXPECT_THROW_MSG(fmt::sprintf(format("%{}$", BIG_NUM)), 83 FormatError, "number is too big"); 84 EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM)), 85 FormatError, "number is too big"); 86 } 87 88 TEST(PrintfTest, SwitchArgIndexing) { 89 EXPECT_THROW_MSG(fmt::sprintf("%1$d%", 1, 2), 90 FormatError, "invalid format string"); 91 EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2), 92 FormatError, "number is too big"); 93 EXPECT_THROW_MSG(fmt::sprintf("%1$d%d", 1, 2), 94 FormatError, "cannot switch from manual to automatic argument indexing"); 95 96 EXPECT_THROW_MSG(fmt::sprintf("%d%1$", 1, 2), 97 FormatError, "invalid format string"); 98 EXPECT_THROW_MSG(fmt::sprintf(format("%d%{}$d", BIG_NUM), 1, 2), 99 FormatError, "number is too big"); 100 EXPECT_THROW_MSG(fmt::sprintf("%d%1$d", 1, 2), 101 FormatError, "cannot switch from automatic to manual argument indexing"); 102 103 // Indexing errors override width errors. 104 EXPECT_THROW_MSG(fmt::sprintf(format("%d%1${}d", BIG_NUM), 1, 2), 105 FormatError, "number is too big"); 106 EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2), 107 FormatError, "number is too big"); 108 } 109 110 TEST(PrintfTest, InvalidArgIndex) { 111 EXPECT_THROW_MSG(fmt::sprintf("%0$d", 42), FormatError, 112 "argument index out of range"); 113 EXPECT_THROW_MSG(fmt::sprintf("%2$d", 42), FormatError, 114 "argument index out of range"); 115 EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", INT_MAX), 42), 116 FormatError, "argument index out of range"); 117 118 EXPECT_THROW_MSG(fmt::sprintf("%2$", 42), 119 FormatError, "invalid format string"); 120 EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM), 42), 121 FormatError, "number is too big"); 122 } 123 124 TEST(PrintfTest, DefaultAlignRight) { 125 EXPECT_PRINTF(" 42", "%5d", 42); 126 EXPECT_PRINTF(" abc", "%5s", "abc"); 127 } 128 129 TEST(PrintfTest, ZeroFlag) { 130 EXPECT_PRINTF("00042", "%05d", 42); 131 EXPECT_PRINTF("-0042", "%05d", -42); 132 133 EXPECT_PRINTF("00042", "%05d", 42); 134 EXPECT_PRINTF("-0042", "%05d", -42); 135 EXPECT_PRINTF("-004.2", "%06g", -4.2); 136 137 EXPECT_PRINTF("+00042", "%00+6d", 42); 138 139 // '0' flag is ignored for non-numeric types. 140 EXPECT_PRINTF(" x", "%05c", 'x'); 141 } 142 143 TEST(PrintfTest, PlusFlag) { 144 EXPECT_PRINTF("+42", "%+d", 42); 145 EXPECT_PRINTF("-42", "%+d", -42); 146 EXPECT_PRINTF("+0042", "%+05d", 42); 147 EXPECT_PRINTF("+0042", "%0++5d", 42); 148 149 // '+' flag is ignored for non-numeric types. 150 EXPECT_PRINTF("x", "%+c", 'x'); 151 } 152 153 TEST(PrintfTest, MinusFlag) { 154 EXPECT_PRINTF("abc ", "%-5s", "abc"); 155 EXPECT_PRINTF("abc ", "%0--5s", "abc"); 156 } 157 158 TEST(PrintfTest, SpaceFlag) { 159 EXPECT_PRINTF(" 42", "% d", 42); 160 EXPECT_PRINTF("-42", "% d", -42); 161 EXPECT_PRINTF(" 0042", "% 05d", 42); 162 EXPECT_PRINTF(" 0042", "%0 5d", 42); 163 164 // ' ' flag is ignored for non-numeric types. 165 EXPECT_PRINTF("x", "% c", 'x'); 166 } 167 168 TEST(PrintfTest, HashFlag) { 169 EXPECT_PRINTF("042", "%#o", 042); 170 EXPECT_PRINTF(fmt::format("0{:o}", static_cast<unsigned>(-042)), "%#o", -042); 171 EXPECT_PRINTF("0", "%#o", 0); 172 173 EXPECT_PRINTF("0x42", "%#x", 0x42); 174 EXPECT_PRINTF("0X42", "%#X", 0x42); 175 EXPECT_PRINTF( 176 fmt::format("0x{:x}", static_cast<unsigned>(-0x42)), "%#x", -0x42); 177 EXPECT_PRINTF("0", "%#x", 0); 178 179 EXPECT_PRINTF("0x0042", "%#06x", 0x42); 180 EXPECT_PRINTF("0x0042", "%0##6x", 0x42); 181 182 EXPECT_PRINTF("-42.000000", "%#f", -42.0); 183 EXPECT_PRINTF("-42.000000", "%#F", -42.0); 184 185 char buffer[BUFFER_SIZE]; 186 safe_sprintf(buffer, "%#e", -42.0); 187 EXPECT_PRINTF(buffer, "%#e", -42.0); 188 safe_sprintf(buffer, "%#E", -42.0); 189 EXPECT_PRINTF(buffer, "%#E", -42.0); 190 191 EXPECT_PRINTF("-42.0000", "%#g", -42.0); 192 EXPECT_PRINTF("-42.0000", "%#G", -42.0); 193 194 safe_sprintf(buffer, "%#a", 16.0); 195 EXPECT_PRINTF(buffer, "%#a", 16.0); 196 safe_sprintf(buffer, "%#A", 16.0); 197 EXPECT_PRINTF(buffer, "%#A", 16.0); 198 199 // '#' flag is ignored for non-numeric types. 200 EXPECT_PRINTF("x", "%#c", 'x'); 201 } 202 203 TEST(PrintfTest, Width) { 204 EXPECT_PRINTF(" abc", "%5s", "abc"); 205 206 // Width cannot be specified twice. 207 EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), FormatError, 208 "unknown format code '-' for integer"); 209 210 EXPECT_THROW_MSG(fmt::sprintf(format("%{}d", BIG_NUM), 42), 211 FormatError, "number is too big"); 212 EXPECT_THROW_MSG(fmt::sprintf(format("%1${}d", BIG_NUM), 42), 213 FormatError, "number is too big"); 214 } 215 216 TEST(PrintfTest, DynamicWidth) { 217 EXPECT_EQ(" 42", fmt::sprintf("%*d", 5, 42)); 218 EXPECT_EQ("42 ", fmt::sprintf("%*d", -5, 42)); 219 EXPECT_THROW_MSG(fmt::sprintf("%*d", 5.0, 42), FormatError, 220 "width is not integer"); 221 EXPECT_THROW_MSG(fmt::sprintf("%*d"), FormatError, 222 "argument index out of range"); 223 EXPECT_THROW_MSG(fmt::sprintf("%*d", BIG_NUM, 42), FormatError, 224 "number is too big"); 225 } 226 227 TEST(PrintfTest, IntPrecision) { 228 EXPECT_PRINTF("00042", "%.5d", 42); 229 EXPECT_PRINTF("-00042", "%.5d", -42); 230 EXPECT_PRINTF("00042", "%.5x", 0x42); 231 EXPECT_PRINTF("0x00042", "%#.5x", 0x42); 232 EXPECT_PRINTF("00042", "%.5o", 042); 233 EXPECT_PRINTF("00042", "%#.5o", 042); 234 235 EXPECT_PRINTF(" 00042", "%7.5d", 42); 236 EXPECT_PRINTF(" 00042", "%7.5x", 0x42); 237 EXPECT_PRINTF(" 0x00042", "%#10.5x", 0x42); 238 EXPECT_PRINTF(" 00042", "%7.5o", 042); 239 EXPECT_PRINTF(" 00042", "%#10.5o", 042); 240 241 EXPECT_PRINTF("00042 ", "%-7.5d", 42); 242 EXPECT_PRINTF("00042 ", "%-7.5x", 0x42); 243 EXPECT_PRINTF("0x00042 ", "%-#10.5x", 0x42); 244 EXPECT_PRINTF("00042 ", "%-7.5o", 042); 245 EXPECT_PRINTF("00042 ", "%-#10.5o", 042); 246 } 247 248 TEST(PrintfTest, FloatPrecision) { 249 char buffer[BUFFER_SIZE]; 250 safe_sprintf(buffer, "%.3e", 1234.5678); 251 EXPECT_PRINTF(buffer, "%.3e", 1234.5678); 252 EXPECT_PRINTF("1234.568", "%.3f", 1234.5678); 253 safe_sprintf(buffer, "%.3g", 1234.5678); 254 EXPECT_PRINTF(buffer, "%.3g", 1234.5678); 255 safe_sprintf(buffer, "%.3a", 1234.5678); 256 EXPECT_PRINTF(buffer, "%.3a", 1234.5678); 257 } 258 259 TEST(PrintfTest, IgnorePrecisionForNonNumericArg) { 260 EXPECT_PRINTF("abc", "%.5s", "abc"); 261 } 262 263 TEST(PrintfTest, DynamicPrecision) { 264 EXPECT_EQ("00042", fmt::sprintf("%.*d", 5, 42)); 265 EXPECT_EQ("42", fmt::sprintf("%.*d", -5, 42)); 266 EXPECT_THROW_MSG(fmt::sprintf("%.*d", 5.0, 42), FormatError, 267 "precision is not integer"); 268 EXPECT_THROW_MSG(fmt::sprintf("%.*d"), FormatError, 269 "argument index out of range"); 270 EXPECT_THROW_MSG(fmt::sprintf("%.*d", BIG_NUM, 42), FormatError, 271 "number is too big"); 272 if (sizeof(fmt::LongLong) != sizeof(int)) { 273 fmt::LongLong prec = static_cast<fmt::LongLong>(INT_MIN) - 1; 274 EXPECT_THROW_MSG(fmt::sprintf("%.*d", prec, 42), FormatError, 275 "number is too big"); 276 } 277 } 278 279 template <typename T> 280 struct MakeSigned { typedef T Type; }; 281 282 #define SPECIALIZE_MAKE_SIGNED(T, S) \ 283 template <> \ 284 struct MakeSigned<T> { typedef S Type; } 285 286 SPECIALIZE_MAKE_SIGNED(char, signed char); 287 SPECIALIZE_MAKE_SIGNED(unsigned char, signed char); 288 SPECIALIZE_MAKE_SIGNED(unsigned short, short); 289 SPECIALIZE_MAKE_SIGNED(unsigned, int); 290 SPECIALIZE_MAKE_SIGNED(unsigned long, long); 291 SPECIALIZE_MAKE_SIGNED(fmt::ULongLong, fmt::LongLong); 292 293 // Test length format specifier ``length_spec``. 294 template <typename T, typename U> 295 void TestLength(const char *length_spec, U value) { 296 fmt::LongLong signed_value = 0; 297 fmt::ULongLong unsigned_value = 0; 298 // Apply integer promotion to the argument. 299 using std::numeric_limits; 300 fmt::ULongLong max = numeric_limits<U>::max(); 301 using fmt::internal::const_check; 302 if (const_check(max <= static_cast<unsigned>(numeric_limits<int>::max()))) { 303 signed_value = static_cast<int>(value); 304 unsigned_value = static_cast<unsigned>(value); 305 } else if (const_check(max <= numeric_limits<unsigned>::max())) { 306 signed_value = static_cast<unsigned>(value); 307 unsigned_value = static_cast<unsigned>(value); 308 } 309 using fmt::internal::MakeUnsigned; 310 if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) { 311 signed_value = static_cast<fmt::LongLong>(value); 312 unsigned_value = static_cast<typename MakeUnsigned<unsigned>::Type>(value); 313 } else { 314 signed_value = static_cast<typename MakeSigned<T>::Type>(value); 315 unsigned_value = static_cast<typename MakeUnsigned<T>::Type>(value); 316 } 317 std::ostringstream os; 318 os << signed_value; 319 EXPECT_PRINTF(os.str(), fmt::format("%{}d", length_spec), value); 320 EXPECT_PRINTF(os.str(), fmt::format("%{}i", length_spec), value); 321 os.str(""); 322 os << unsigned_value; 323 EXPECT_PRINTF(os.str(), fmt::format("%{}u", length_spec), value); 324 os.str(""); 325 os << std::oct << unsigned_value; 326 EXPECT_PRINTF(os.str(), fmt::format("%{}o", length_spec), value); 327 os.str(""); 328 os << std::hex << unsigned_value; 329 EXPECT_PRINTF(os.str(), fmt::format("%{}x", length_spec), value); 330 os.str(""); 331 os << std::hex << std::uppercase << unsigned_value; 332 EXPECT_PRINTF(os.str(), fmt::format("%{}X", length_spec), value); 333 } 334 335 template <typename T> 336 void TestLength(const char *length_spec) { 337 T min = std::numeric_limits<T>::min(), max = std::numeric_limits<T>::max(); 338 TestLength<T>(length_spec, 42); 339 TestLength<T>(length_spec, -42); 340 TestLength<T>(length_spec, min); 341 TestLength<T>(length_spec, max); 342 TestLength<T>(length_spec, fmt::LongLong(min) - 1); 343 fmt::ULongLong long_long_max = std::numeric_limits<fmt::LongLong>::max(); 344 if (static_cast<fmt::ULongLong>(max) < long_long_max) 345 TestLength<T>(length_spec, fmt::LongLong(max) + 1); 346 TestLength<T>(length_spec, std::numeric_limits<short>::min()); 347 TestLength<T>(length_spec, std::numeric_limits<unsigned short>::max()); 348 TestLength<T>(length_spec, std::numeric_limits<int>::min()); 349 TestLength<T>(length_spec, std::numeric_limits<int>::max()); 350 TestLength<T>(length_spec, std::numeric_limits<unsigned>::min()); 351 TestLength<T>(length_spec, std::numeric_limits<unsigned>::max()); 352 TestLength<T>(length_spec, std::numeric_limits<fmt::LongLong>::min()); 353 TestLength<T>(length_spec, std::numeric_limits<fmt::LongLong>::max()); 354 TestLength<T>(length_spec, std::numeric_limits<fmt::ULongLong>::min()); 355 TestLength<T>(length_spec, std::numeric_limits<fmt::ULongLong>::max()); 356 } 357 358 TEST(PrintfTest, Length) { 359 TestLength<char>("hh"); 360 TestLength<signed char>("hh"); 361 TestLength<unsigned char>("hh"); 362 TestLength<short>("h"); 363 TestLength<unsigned short>("h"); 364 TestLength<long>("l"); 365 TestLength<unsigned long>("l"); 366 TestLength<fmt::LongLong>("ll"); 367 TestLength<fmt::ULongLong>("ll"); 368 TestLength<intmax_t>("j"); 369 TestLength<std::size_t>("z"); 370 TestLength<std::ptrdiff_t>("t"); 371 long double max = std::numeric_limits<long double>::max(); 372 EXPECT_PRINTF(fmt::format("{}", max), "%g", max); 373 EXPECT_PRINTF(fmt::format("{}", max), "%Lg", max); 374 } 375 376 TEST(PrintfTest, Bool) { 377 EXPECT_PRINTF("1", "%d", true); 378 EXPECT_PRINTF("true", "%s", true); 379 } 380 381 TEST(PrintfTest, Int) { 382 EXPECT_PRINTF("-42", "%d", -42); 383 EXPECT_PRINTF("-42", "%i", -42); 384 unsigned u = 0 - 42u; 385 EXPECT_PRINTF(fmt::format("{}", u), "%u", -42); 386 EXPECT_PRINTF(fmt::format("{:o}", u), "%o", -42); 387 EXPECT_PRINTF(fmt::format("{:x}", u), "%x", -42); 388 EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42); 389 } 390 391 TEST(PrintfTest, LongLong) { 392 // fmt::printf allows passing long long arguments to %d without length 393 // specifiers. 394 fmt::LongLong max = std::numeric_limits<fmt::LongLong>::max(); 395 EXPECT_PRINTF(fmt::format("{}", max), "%d", max); 396 } 397 398 TEST(PrintfTest, Float) { 399 EXPECT_PRINTF("392.650000", "%f", 392.65); 400 EXPECT_PRINTF("392.650000", "%F", 392.65); 401 char buffer[BUFFER_SIZE]; 402 safe_sprintf(buffer, "%e", 392.65); 403 EXPECT_PRINTF(buffer, "%e", 392.65); 404 safe_sprintf(buffer, "%E", 392.65); 405 EXPECT_PRINTF(buffer, "%E", 392.65); 406 EXPECT_PRINTF("392.65", "%g", 392.65); 407 EXPECT_PRINTF("392.65", "%G", 392.65); 408 safe_sprintf(buffer, "%a", -392.65); 409 EXPECT_EQ(buffer, format("{:a}", -392.65)); 410 safe_sprintf(buffer, "%A", -392.65); 411 EXPECT_EQ(buffer, format("{:A}", -392.65)); 412 } 413 414 TEST(PrintfTest, Inf) { 415 double inf = std::numeric_limits<double>::infinity(); 416 for (const char* type = "fega"; *type; ++type) { 417 EXPECT_PRINTF("inf", fmt::format("%{}", *type), inf); 418 char upper = std::toupper(*type); 419 EXPECT_PRINTF("INF", fmt::format("%{}", upper), inf); 420 } 421 } 422 423 TEST(PrintfTest, Char) { 424 EXPECT_PRINTF("x", "%c", 'x'); 425 int max = std::numeric_limits<int>::max(); 426 EXPECT_PRINTF(fmt::format("{}", static_cast<char>(max)), "%c", max); 427 //EXPECT_PRINTF("x", "%lc", L'x'); 428 // TODO: test wchar_t 429 } 430 431 TEST(PrintfTest, String) { 432 EXPECT_PRINTF("abc", "%s", "abc"); 433 const char *null_str = 0; 434 EXPECT_PRINTF("(null)", "%s", null_str); 435 EXPECT_PRINTF(" (null)", "%10s", null_str); 436 // TODO: wide string 437 } 438 439 TEST(PrintfTest, Pointer) { 440 int n; 441 void *p = &n; 442 EXPECT_PRINTF(fmt::format("{}", p), "%p", p); 443 p = 0; 444 EXPECT_PRINTF("(nil)", "%p", p); 445 EXPECT_PRINTF(" (nil)", "%10p", p); 446 const char *s = "test"; 447 EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s); 448 const char *null_str = 0; 449 EXPECT_PRINTF("(nil)", "%p", null_str); 450 } 451 452 TEST(PrintfTest, Location) { 453 // TODO: test %n 454 } 455 456 enum E { A = 42 }; 457 458 TEST(PrintfTest, Enum) { 459 EXPECT_PRINTF("42", "%d", A); 460 } 461 462 #if FMT_USE_FILE_DESCRIPTORS 463 TEST(PrintfTest, Examples) { 464 const char *weekday = "Thursday"; 465 const char *month = "August"; 466 int day = 21; 467 EXPECT_WRITE(stdout, fmt::printf("%1$s, %3$d %2$s", weekday, month, day), 468 "Thursday, 21 August"); 469 } 470 471 TEST(PrintfTest, PrintfError) { 472 fmt::File read_end, write_end; 473 fmt::File::pipe(read_end, write_end); 474 int result = fmt::fprintf(read_end.fdopen("r").get(), "test"); 475 EXPECT_LT(result, 0); 476 } 477 #endif 478 479 TEST(PrintfTest, WideString) { 480 EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc")); 481 } 482 483 TEST(PrintfTest, PrintfCustom) { 484 EXPECT_EQ("abc", fmt::sprintf("%s", TestString("abc"))); 485 } 486 487 TEST(PrintfTest, OStream) { 488 std::ostringstream os; 489 int ret = fmt::fprintf(os, "Don't %s!", "panic"); 490 EXPECT_EQ("Don't panic!", os.str()); 491 EXPECT_EQ(12, ret); 492 } 493