Reactos
at master 903 lines 41 kB view raw
1/* 2 * Conformance tests for *printf functions. 3 * 4 * Copyright 2002 Uwe Bonnes 5 * Copyright 2004 Aneurin Price 6 * Copyright 2005 Mike McCormack 7 * Copyright 2015 Martin Storsjo 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 24#include <stdio.h> 25#include <errno.h> 26#include <math.h> 27#include <inttypes.h> 28 29#include "windef.h" 30#include "winbase.h" 31#include "winnls.h" 32 33#include "wine/test.h" 34 35#define DEFINE_EXPECT(func) \ 36 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE 37 38#define SET_EXPECT(func) \ 39 expect_ ## func = TRUE 40 41#define CHECK_EXPECT2(func) \ 42 do { \ 43 ok(expect_ ##func, "unexpected call " #func "\n"); \ 44 called_ ## func = TRUE; \ 45 }while(0) 46 47#define CHECK_EXPECT(func) \ 48 do { \ 49 CHECK_EXPECT2(func); \ 50 expect_ ## func = FALSE; \ 51 }while(0) 52 53#define CHECK_CALLED(func) \ 54 do { \ 55 ok(called_ ## func, "expected " #func "\n"); \ 56 expect_ ## func = called_ ## func = FALSE; \ 57 }while(0) 58 59DEFINE_EXPECT(invalid_parameter_handler); 60 61static inline float __port_ind(void) 62{ 63 static const unsigned __ind_bytes = 0xffc00000; 64 return *(const float *)&__ind_bytes; 65} 66#define IND __port_ind() 67 68static void __cdecl test_invalid_parameter_handler(const wchar_t *expression, 69 const wchar_t *function, const wchar_t *file, 70 unsigned line, uintptr_t arg) 71{ 72 CHECK_EXPECT(invalid_parameter_handler); 73 ok(expression == NULL, "expression is not NULL\n"); 74 ok(function == NULL, "function is not NULL\n"); 75 ok(file == NULL, "file is not NULL\n"); 76 ok(line == 0, "line = %u\n", line); 77 ok(arg == 0, "arg = %Ix\n", arg); 78} 79 80static int WINAPIV vsprintf_wrapper(unsigned __int64 options, char *str, 81 size_t len, const char *format, ...) 82{ 83 int ret; 84 va_list valist; 85 va_start(valist, format); 86 ret = __stdio_common_vsprintf(options, str, len, format, NULL, valist); 87 va_end(valist); 88 return ret; 89} 90 91static void test_snprintf (void) 92{ 93 const char *tests[] = {"short", "justfit", "justfits", "muchlonger", "", "1"}; 94 char buffer[8]; 95 int bufsizes[] = { 0, 1, sizeof(buffer) }; 96 unsigned int i, j; 97 98 for (j = 0; j < ARRAY_SIZE(bufsizes); j++) { 99 const int bufsiz = bufsizes[j]; 100 /* Legacy _snprintf style termination */ 101 for (i = 0; i < ARRAY_SIZE(tests); i++) { 102 const char *fmt = tests[i]; 103 const int expect = strlen(fmt) > bufsiz ? -1 : strlen(fmt); 104 const int n = vsprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, bufsiz, fmt); 105 const int valid = n < 0 ? bufsiz : (n == bufsiz ? n : n+1); 106 107 ok (n == expect, "\"%s\": expected %d, returned %d\n", 108 fmt, expect, n); 109 ok (!memcmp (fmt, buffer, valid), 110 "\"%s\": rendered \"%.*s\"\n", fmt, valid, buffer); 111 } 112 113 /* C99 snprintf style termination */ 114 for (i = 0; i < ARRAY_SIZE(tests); i++) { 115 const char *fmt = tests[i]; 116 const int expect = strlen(fmt); 117 const int n = vsprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, bufsiz, fmt); 118 const int valid = n >= bufsiz ? (bufsiz > 0 ? bufsiz - 1 : 0) : n < 0 ? 0 : n; 119 120 ok (n == expect, "\"%s\": expected %d, returned %d\n", 121 fmt, expect, n); 122 ok (!memcmp (fmt, buffer, valid), 123 "\"%s\": rendered \"%.*s\" bufsiz %d\n", fmt, valid, buffer, bufsiz); 124 ok (bufsiz == 0 || buffer[valid] == '\0', 125 "\"%s\": Missing null termination (ret %d) - is %d (bufsiz %d)\n", fmt, n, buffer[valid], bufsiz); 126 } 127 128 /* swprintf style termination */ 129 for (i = 0; i < ARRAY_SIZE(tests); i++) { 130 const char *fmt = tests[i]; 131 const int expect = strlen(fmt) >= bufsiz ? bufsiz > 0 ? -2 : -1 : strlen(fmt); 132 const int n = vsprintf_wrapper (0, buffer, bufsiz, fmt); 133 const int valid = n < 0 ? bufsiz > 0 ? bufsiz - 1 : 0 : n; 134 135 ok (n == expect, "\"%s\": expected %d, returned %d\n", 136 fmt, expect, n); 137 ok (!memcmp (fmt, buffer, valid), 138 "\"%s\": rendered \"%.*s\" bufsiz %d\n", fmt, valid, buffer, bufsiz); 139 ok (bufsiz == 0 || buffer[valid] == '\0', 140 "\"%s\": Missing null termination (ret %d) - is %d\n", fmt, n, buffer[valid]); 141 } 142 } 143 144 ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, NULL, 0, "abcd") == 4, 145 "Failure to snprintf to NULL\n"); 146 ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, NULL, 0, "abcd") == 4, 147 "Failure to snprintf to NULL\n"); 148 ok (vsprintf_wrapper (0, NULL, 0, "abcd") == 4, 149 "Failure to snprintf to NULL\n"); 150 ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, 0, "abcd") == 4, 151 "Failure to snprintf to zero length buffer\n"); 152 ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, 0, "abcd") == -1, 153 "Failure to snprintf to zero length buffer\n"); 154 ok (vsprintf_wrapper (0, buffer, 0, "abcd") == -1, 155 "Failure to snprintf to zero length buffer\n"); 156 ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, 0, "") == 0, 157 "Failure to snprintf a zero length string to a zero length buffer\n"); 158 ok (vsprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, 0, "") == 0, 159 "Failure to snprintf a zero length string to a zero length buffer\n"); 160 ok (vsprintf_wrapper (0, buffer, 0, "") == -1, 161 "Failure to snprintf a zero length string to a zero length buffer\n"); 162} 163 164static int WINAPIV vswprintf_wrapper(unsigned __int64 options, wchar_t *str, 165 size_t len, const wchar_t *format, ...) 166{ 167 int ret; 168 va_list valist; 169 va_start(valist, format); 170 ret = __stdio_common_vswprintf(options, str, len, format, NULL, valist); 171 va_end(valist); 172 return ret; 173} 174 175static void test_swprintf (void) 176{ 177 const wchar_t str_short[] = {'s','h','o','r','t',0}; 178 const wchar_t str_justfit[] = {'j','u','s','t','f','i','t',0}; 179 const wchar_t str_justfits[] = {'j','u','s','t','f','i','t','s',0}; 180 const wchar_t str_muchlonger[] = {'m','u','c','h','l','o','n','g','e','r',0}; 181 const wchar_t str_empty[] = {0}; 182 const wchar_t *tests[] = {str_short, str_justfit, str_justfits, str_muchlonger}; 183 184 wchar_t buffer[8]; 185 char narrow[8], narrow_fmt[16]; 186 const int bufsiz = ARRAY_SIZE(buffer); 187 unsigned int i; 188 189 /* Legacy _snprintf style termination */ 190 for (i = 0; i < ARRAY_SIZE(tests); i++) { 191 const wchar_t *fmt = tests[i]; 192 const int expect = wcslen(fmt) > bufsiz ? -1 : wcslen(fmt); 193 const int n = vswprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, bufsiz, fmt); 194 const int valid = n < 0 ? bufsiz : (n == bufsiz ? n : n+1); 195 196 WideCharToMultiByte (CP_ACP, 0, buffer, -1, narrow, sizeof(narrow), NULL, NULL); 197 WideCharToMultiByte (CP_ACP, 0, fmt, -1, narrow_fmt, sizeof(narrow_fmt), NULL, NULL); 198 ok (n == expect, "\"%s\": expected %d, returned %d\n", 199 narrow_fmt, expect, n); 200 ok (!memcmp (fmt, buffer, valid * sizeof(wchar_t)), 201 "\"%s\": rendered \"%.*s\"\n", narrow_fmt, valid, narrow); 202 } 203 204 /* C99 snprintf style termination */ 205 for (i = 0; i < ARRAY_SIZE(tests); i++) { 206 const wchar_t *fmt = tests[i]; 207 const int expect = wcslen(fmt); 208 const int n = vswprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, bufsiz, fmt); 209 const int valid = n >= bufsiz ? bufsiz - 1 : n < 0 ? 0 : n; 210 211 WideCharToMultiByte (CP_ACP, 0, buffer, -1, narrow, sizeof(narrow), NULL, NULL); 212 WideCharToMultiByte (CP_ACP, 0, fmt, -1, narrow_fmt, sizeof(narrow_fmt), NULL, NULL); 213 ok (n == expect, "\"%s\": expected %d, returned %d\n", 214 narrow_fmt, expect, n); 215 ok (!memcmp (fmt, buffer, valid * sizeof(wchar_t)), 216 "\"%s\": rendered \"%.*s\"\n", narrow_fmt, valid, narrow); 217 ok (buffer[valid] == '\0', 218 "\"%s\": Missing null termination (ret %d) - is %d\n", narrow_fmt, n, buffer[valid]); 219 } 220 221 /* swprintf style termination */ 222 for (i = 0; i < ARRAY_SIZE(tests); i++) { 223 const wchar_t *fmt = tests[i]; 224 const int expect = wcslen(fmt) >= bufsiz ? -2 : wcslen(fmt); 225 const int n = vswprintf_wrapper (0, buffer, bufsiz, fmt); 226 const int valid = n < 0 ? bufsiz - 1 : n; 227 228 WideCharToMultiByte (CP_ACP, 0, buffer, -1, narrow, sizeof(narrow), NULL, NULL); 229 WideCharToMultiByte (CP_ACP, 0, fmt, -1, narrow_fmt, sizeof(narrow_fmt), NULL, NULL); 230 ok (n == expect, "\"%s\": expected %d, returned %d\n", 231 narrow_fmt, expect, n); 232 ok (!memcmp (fmt, buffer, valid * sizeof(wchar_t)), 233 "\"%s\": rendered \"%.*s\"\n", narrow_fmt, valid, narrow); 234 ok (buffer[valid] == '\0', 235 "\"%s\": Missing null termination (ret %d) - is %d\n", narrow_fmt, n, buffer[valid]); 236 } 237 238 ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, NULL, 0, str_short) == 5, 239 "Failure to swprintf to NULL\n"); 240 ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, NULL, 0, str_short) == 5, 241 "Failure to swprintf to NULL\n"); 242 ok (vswprintf_wrapper (0, NULL, 0, str_short) == 5, 243 "Failure to swprintf to NULL\n"); 244 ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, 0, str_short) == 5, 245 "Failure to swprintf to a zero length buffer\n"); 246 ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, 0, str_short) == -1, 247 "Failure to swprintf to a zero length buffer\n"); 248 ok (vswprintf_wrapper (0, buffer, 0, str_short) == -1, 249 "Failure to swprintf to a zero length buffer\n"); 250 ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR, buffer, 0, str_empty) == 0, 251 "Failure to swprintf a zero length string to a zero length buffer\n"); 252 ok (vswprintf_wrapper (_CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION, buffer, 0, str_empty) == 0, 253 "Failure to swprintf a zero length string to a zero length buffer\n"); 254 ok (vswprintf_wrapper (0, buffer, 0, str_empty) == -1, 255 "Failure to swprintf a zero length string to a zero length buffer\n"); 256} 257 258static int WINAPIV vfprintf_wrapper(FILE *file, 259 const char *format, ...) 260{ 261 int ret; 262 va_list valist; 263 va_start(valist, format); 264 ret = __stdio_common_vfprintf(0, file, format, NULL, valist); 265 va_end(valist); 266 return ret; 267} 268 269static void test_fprintf(void) 270{ 271 static const char file_name[] = "fprintf.tst"; 272 273 FILE *fp = fopen(file_name, "wb"); 274 char buf[1024]; 275 int ret; 276 277 ret = vfprintf_wrapper(fp, "simple test\n"); 278 ok(ret == 12, "ret = %d\n", ret); 279 ret = ftell(fp); 280 ok(ret == 12, "ftell returned %d\n", ret); 281 282 ret = vfprintf_wrapper(fp, "contains%cnull\n", '\0'); 283 ok(ret == 14, "ret = %d\n", ret); 284 ret = ftell(fp); 285 ok(ret == 26, "ftell returned %d\n", ret); 286 287 fclose(fp); 288 289 fp = fopen(file_name, "rb"); 290 fgets(buf, sizeof(buf), fp); 291 ret = ftell(fp); 292 ok(ret == 12, "ftell returned %d\n", ret); 293 ok(!strcmp(buf, "simple test\n"), "buf = %s\n", buf); 294 295 fgets(buf, sizeof(buf), fp); 296 ret = ftell(fp); 297 ok(ret == 26, "ret = %d\n", ret); 298 ok(!memcmp(buf, "contains\0null\n", 14), "buf = %s\n", buf); 299 300 fclose(fp); 301 302 fp = fopen(file_name, "wt"); 303 304 ret = vfprintf_wrapper(fp, "simple test\n"); 305 ok(ret == 12, "ret = %d\n", ret); 306 ret = ftell(fp); 307 ok(ret == 13, "ftell returned %d\n", ret); 308 309 ret = vfprintf_wrapper(fp, "contains%cnull\n", '\0'); 310 ok(ret == 14, "ret = %d\n", ret); 311 ret = ftell(fp); 312 ok(ret == 28, "ftell returned %d\n", ret); 313 314 fclose(fp); 315 316 fp = fopen(file_name, "rb"); 317 fgets(buf, sizeof(buf), fp); 318 ret = ftell(fp); 319 ok(ret == 13, "ftell returned %d\n", ret); 320 ok(!strcmp(buf, "simple test\r\n"), "buf = %s\n", buf); 321 322 fgets(buf, sizeof(buf), fp); 323 ret = ftell(fp); 324 ok(ret == 28, "ret = %d\n", ret); 325 ok(!memcmp(buf, "contains\0null\r\n", 15), "buf = %s\n", buf); 326 327 fclose(fp); 328 unlink(file_name); 329} 330 331static int WINAPIV vfwprintf_wrapper(FILE *file, 332 const wchar_t *format, ...) 333{ 334 int ret; 335 va_list valist; 336 va_start(valist, format); 337 ret = __stdio_common_vfwprintf(0, file, format, NULL, valist); 338 va_end(valist); 339 return ret; 340} 341 342static void test_fwprintf(void) 343{ 344 static const char file_name[] = "fprintf.tst"; 345 static const WCHAR simple[] = {'s','i','m','p','l','e',' ','t','e','s','t','\n',0}; 346 static const WCHAR cont_fmt[] = {'c','o','n','t','a','i','n','s','%','c','n','u','l','l','\n',0}; 347 static const WCHAR cont[] = {'c','o','n','t','a','i','n','s','\0','n','u','l','l','\n',0}; 348 349 FILE *fp = fopen(file_name, "wb"); 350 wchar_t bufw[1024]; 351 char bufa[1024]; 352 int ret; 353 354 ret = vfwprintf_wrapper(fp, simple); 355 ok(ret == 12, "ret = %d\n", ret); 356 ret = ftell(fp); 357 ok(ret == 24, "ftell returned %d\n", ret); 358 359 ret = vfwprintf_wrapper(fp, cont_fmt, '\0'); 360 ok(ret == 14, "ret = %d\n", ret); 361 ret = ftell(fp); 362 ok(ret == 52, "ftell returned %d\n", ret); 363 364 fclose(fp); 365 366 fp = fopen(file_name, "rb"); 367 fgetws(bufw, ARRAY_SIZE(bufw), fp); 368 ret = ftell(fp); 369 ok(ret == 24, "ftell returned %d\n", ret); 370 ok(!wcscmp(bufw, simple), "buf = %s\n", wine_dbgstr_w(bufw)); 371 372 fgetws(bufw, ARRAY_SIZE(bufw), fp); 373 ret = ftell(fp); 374 ok(ret == 52, "ret = %d\n", ret); 375 ok(!memcmp(bufw, cont, 28), "buf = %s\n", wine_dbgstr_w(bufw)); 376 377 fclose(fp); 378 379 fp = fopen(file_name, "wt"); 380 381 ret = vfwprintf_wrapper(fp, simple); 382 ok(ret == 12, "ret = %d\n", ret); 383 ret = ftell(fp); 384 ok(ret == 13, "ftell returned %d\n", ret); 385 386 ret = vfwprintf_wrapper(fp, cont_fmt, '\0'); 387 ok(ret == 14, "ret = %d\n", ret); 388 ret = ftell(fp); 389 ok(ret == 28, "ftell returned %d\n", ret); 390 391 fclose(fp); 392 393 fp = fopen(file_name, "rb"); 394 fgets(bufa, sizeof(bufa), fp); 395 ret = ftell(fp); 396 ok(ret == 13, "ftell returned %d\n", ret); 397 ok(!strcmp(bufa, "simple test\r\n"), "buf = %s\n", bufa); 398 399 fgets(bufa, sizeof(bufa), fp); 400 ret = ftell(fp); 401 ok(ret == 28, "ret = %d\n", ret); 402 ok(!memcmp(bufa, "contains\0null\r\n", 15), "buf = %s\n", bufa); 403 404 fclose(fp); 405 unlink(file_name); 406 407 /* NULL format */ 408 errno = 0xdeadbeef; 409 SET_EXPECT(invalid_parameter_handler); 410 ret = vfwprintf_wrapper(fp, NULL); 411 ok(errno == EINVAL, "expected errno EINVAL, got %d\n", errno); 412 ok(ret == -1, "expected ret -1, got %d\n", ret); 413 CHECK_CALLED(invalid_parameter_handler); 414 415 /* NULL file */ 416 errno = 0xdeadbeef; 417 SET_EXPECT(invalid_parameter_handler); 418 ret = vfwprintf_wrapper(NULL, simple); 419 ok(errno == EINVAL, "expected errno EINVAL, got %d\n", errno); 420 ok(ret == -1, "expected ret -1, got %d\n", ret); 421 CHECK_CALLED(invalid_parameter_handler); 422 423 /* format using % with NULL arglist*/ 424 /* crashes on Windows */ 425 /* ret = __stdio_common_vfwprintf(0, fp, cont_fmt, NULL, NULL); */ 426} 427 428static int WINAPIV _vsnprintf_s_wrapper(char *str, size_t sizeOfBuffer, 429 size_t count, const char *format, ...) 430{ 431 int ret; 432 va_list valist; 433 va_start(valist, format); 434 ret = __stdio_common_vsnprintf_s(0, str, sizeOfBuffer, count, format, NULL, valist); 435 va_end(valist); 436 return ret; 437} 438 439static void test_vsnprintf_s(void) 440{ 441 const char format[] = "AB%uC"; 442 const char out7[] = "AB123C"; 443 const char out6[] = "AB123"; 444 const char out2[] = "A"; 445 const char out1[] = ""; 446 char buffer[14] = { 0 }; 447 int exp, got; 448 449 /* Enough room. */ 450 exp = strlen(out7); 451 452 got = _vsnprintf_s_wrapper(buffer, 14, _TRUNCATE, format, 123); 453 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 454 ok( !strcmp(out7, buffer), "buffer wrong, got=%s\n", buffer); 455 456 got = _vsnprintf_s_wrapper(buffer, 12, _TRUNCATE, format, 123); 457 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 458 ok( !strcmp(out7, buffer), "buffer wrong, got=%s\n", buffer); 459 460 got = _vsnprintf_s_wrapper(buffer, 7, _TRUNCATE, format, 123); 461 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 462 ok( !strcmp(out7, buffer), "buffer wrong, got=%s\n", buffer); 463 464 /* Not enough room. */ 465 exp = -1; 466 467 got = _vsnprintf_s_wrapper(buffer, 6, _TRUNCATE, format, 123); 468 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 469 ok( !strcmp(out6, buffer), "buffer wrong, got=%s\n", buffer); 470 471 got = _vsnprintf_s_wrapper(buffer, 2, _TRUNCATE, format, 123); 472 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 473 ok( !strcmp(out2, buffer), "buffer wrong, got=%s\n", buffer); 474 475 got = _vsnprintf_s_wrapper(buffer, 1, _TRUNCATE, format, 123); 476 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 477 ok( !strcmp(out1, buffer), "buffer wrong, got=%s\n", buffer); 478} 479 480static int WINAPIV _vsnwprintf_s_wrapper(WCHAR *str, size_t sizeOfBuffer, 481 size_t count, const WCHAR *format, ...) 482{ 483 int ret; 484 va_list valist; 485 va_start(valist, format); 486 ret = __stdio_common_vsnwprintf_s(0, str, sizeOfBuffer, count, format, NULL, valist); 487 va_end(valist); 488 return ret; 489} 490 491static void test_vsnwprintf_s(void) 492{ 493 const WCHAR format[] = {'A','B','%','u','C',0}; 494 const WCHAR out7[] = {'A','B','1','2','3','C',0}; 495 const WCHAR out6[] = {'A','B','1','2','3',0}; 496 const WCHAR out2[] = {'A',0}; 497 const WCHAR out1[] = {0}; 498 WCHAR buffer[14] = { 0 }; 499 int exp, got; 500 501 /* Enough room. */ 502 exp = lstrlenW(out7); 503 504 got = _vsnwprintf_s_wrapper(buffer, 14, _TRUNCATE, format, 123); 505 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 506 ok( !lstrcmpW(out7, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); 507 508 got = _vsnwprintf_s_wrapper(buffer, 12, _TRUNCATE, format, 123); 509 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 510 ok( !lstrcmpW(out7, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); 511 512 got = _vsnwprintf_s_wrapper(buffer, 7, _TRUNCATE, format, 123); 513 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 514 ok( !lstrcmpW(out7, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); 515 516 /* Not enough room. */ 517 exp = -1; 518 519 got = _vsnwprintf_s_wrapper(buffer, 6, _TRUNCATE, format, 123); 520 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 521 ok( !lstrcmpW(out6, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); 522 523 got = _vsnwprintf_s_wrapper(buffer, 2, _TRUNCATE, format, 123); 524 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 525 ok( !lstrcmpW(out2, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); 526 527 got = _vsnwprintf_s_wrapper(buffer, 1, _TRUNCATE, format, 123); 528 ok( exp == got, "length wrong, expect=%d, got=%d\n", exp, got); 529 ok( !lstrcmpW(out1, buffer), "buffer wrong, got=%s\n", wine_dbgstr_w(buffer)); 530} 531 532static void test_printf_legacy_wide(void) 533{ 534 const wchar_t wide[] = {'A','B','C','D',0}; 535 const char narrow[] = "abcd"; 536 const char out[] = "abcd ABCD"; 537 /* The legacy wide flag doesn't affect narrow printfs, so the same 538 * format should behave the same both with and without the flag. */ 539 const char narrow_fmt[] = "%s %ls"; 540 /* The standard behaviour is to use the same format as for the narrow 541 * case, while the legacy case has got a different meaning for %s. */ 542 const wchar_t std_wide_fmt[] = {'%','s',' ','%','l','s',0}; 543 const wchar_t legacy_wide_fmt[] = {'%','h','s',' ','%','s',0}; 544 char buffer[20]; 545 wchar_t wbuffer[20]; 546 547 vsprintf_wrapper(0, buffer, sizeof(buffer), narrow_fmt, narrow, wide); 548 ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer); 549 vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS, buffer, sizeof(buffer), narrow_fmt, narrow, wide); 550 ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer); 551 552 vswprintf_wrapper(0, wbuffer, sizeof(wbuffer), std_wide_fmt, narrow, wide); 553 WideCharToMultiByte(CP_ACP, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL); 554 ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer); 555 vswprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS, wbuffer, sizeof(wbuffer), legacy_wide_fmt, narrow, wide); 556 WideCharToMultiByte(CP_ACP, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL); 557 ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer); 558} 559 560static void test_printf_legacy_msvcrt(void) 561{ 562 char buf[50]; 563 564 /* In standard mode, %F is a float format conversion, while it is a 565 * length modifier in legacy msvcrt mode. In legacy mode, N is also 566 * a length modifier. */ 567 vsprintf_wrapper(0, buf, sizeof(buf), "%F", 1.23); 568 ok(!strcmp(buf, "1.230000"), "buf = %s\n", buf); 569 vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY, buf, sizeof(buf), "%Fd %Nd", 123, 456); 570 ok(!strcmp(buf, "123 456"), "buf = %s\n", buf); 571 572 vsprintf_wrapper(0, buf, sizeof(buf), "%f %F %f %e %E %g %G", INFINITY, INFINITY, -INFINITY, INFINITY, INFINITY, INFINITY, INFINITY); 573 ok(!strcmp(buf, "inf INF -inf inf INF inf INF"), "buf = %s\n", buf); 574 vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY, buf, sizeof(buf), "%f", INFINITY); 575 ok(!strcmp(buf, "1.#INF00"), "buf = %s\n", buf); 576 vsprintf_wrapper(0, buf, sizeof(buf), "%f %F", NAN, NAN); 577 ok(!strcmp(buf, "nan NAN"), "buf = %s\n", buf); 578 vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY, buf, sizeof(buf), "%f", NAN); 579 ok(!strcmp(buf, "1.#QNAN0"), "buf = %s\n", buf); 580 vsprintf_wrapper(0, buf, sizeof(buf), "%f %F", IND, IND); 581 ok(!strcmp(buf, "-nan(ind) -NAN(IND)"), "buf = %s\n", buf); 582 vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY, buf, sizeof(buf), "%f", IND); 583 ok(!strcmp(buf, "-1.#IND00"), "buf = %s\n", buf); 584} 585 586static void test_printf_legacy_three_digit_exp(void) 587{ 588 char buf[20]; 589 590 vsprintf_wrapper(0, buf, sizeof(buf), "%E", 1.23); 591 ok(!strcmp(buf, "1.230000E+00"), "buf = %s\n", buf); 592 vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS, buf, sizeof(buf), "%E", 1.23); 593 ok(!strcmp(buf, "1.230000E+000"), "buf = %s\n", buf); 594 vsprintf_wrapper(0, buf, sizeof(buf), "%E", 1.23e+123); 595 ok(!strcmp(buf, "1.230000E+123"), "buf = %s\n", buf); 596} 597 598static void test_printf_c99(void) 599{ 600 char buf[30]; 601 int i; 602 603 /* The msvcrt compatibility flag doesn't affect whether 'z' is interpreted 604 * as size_t size for integers. */ 605 for (i = 0; i < 2; i++) { 606 unsigned __int64 options = (i == 0) ? 0 : 607 _CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY; 608 609 /* z modifier accepts size_t argument */ 610 vsprintf_wrapper(options, buf, sizeof(buf), "%zx %d", SIZE_MAX, 1); 611 if (sizeof(size_t) == 8) 612 ok(!strcmp(buf, "ffffffffffffffff 1"), "buf = %s\n", buf); 613 else 614 ok(!strcmp(buf, "ffffffff 1"), "buf = %s\n", buf); 615 616 /* j modifier with signed format accepts intmax_t argument */ 617 vsprintf_wrapper(options, buf, sizeof(buf), "%jd %d", INTMAX_MIN, 1); 618 ok(!strcmp(buf, "-9223372036854775808 1"), "buf = %s\n", buf); 619 620 /* j modifier with unsigned format accepts uintmax_t argument */ 621 vsprintf_wrapper(options, buf, sizeof(buf), "%ju %d", UINTMAX_MAX, 1); 622 ok(!strcmp(buf, "18446744073709551615 1"), "buf = %s\n", buf); 623 624 /* t modifier accepts ptrdiff_t argument */ 625 vsprintf_wrapper(options, buf, sizeof(buf), "%td %d", PTRDIFF_MIN, 1); 626 if (sizeof(ptrdiff_t) == 8) 627 ok(!strcmp(buf, "-9223372036854775808 1"), "buf = %s\n", buf); 628 else 629 ok(!strcmp(buf, "-2147483648 1"), "buf = %s\n", buf); 630 } 631} 632 633static void test_printf_natural_string(void) 634{ 635 const wchar_t wide[] = {'A','B','C','D',0}; 636 const char narrow[] = "abcd"; 637 const char narrow_fmt[] = "%s %Ts"; 638 const char narrow_out[] = "abcd abcd"; 639 const wchar_t wide_fmt[] = {'%','s',' ','%','T','s',0}; 640 const wchar_t wide_out[] = {'a','b','c','d',' ','A','B','C','D',0}; 641 char buffer[20]; 642 wchar_t wbuffer[20]; 643 644 vsprintf_wrapper(0, buffer, sizeof(buffer), narrow_fmt, narrow, narrow); 645 ok(!strcmp(buffer, narrow_out), "buffer wrong, got=%s\n", buffer); 646 647 vswprintf_wrapper(0, wbuffer, sizeof(wbuffer), wide_fmt, narrow, wide); 648 ok(!lstrcmpW(wbuffer, wide_out), "buffer wrong, got=%s\n", wine_dbgstr_w(wbuffer)); 649} 650 651static void test_printf_fp(void) 652{ 653 static const int flags[] = { 654 0, 655 _CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY, 656 _CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS, 657 _CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY 658 | _CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS, 659 _CRT_INTERNAL_PRINTF_LEGACY_MSVCRT_COMPATIBILITY 660 | _CRT_INTERNAL_PRINTF_LEGACY_THREE_DIGIT_EXPONENTS 661 | _CRT_INTERNAL_PRINTF_STANDARD_ROUNDING 662 }; 663 const struct { 664 const char *fmt; 665 double d; 666 const char *res[ARRAY_SIZE(flags)]; 667 const char *broken[ARRAY_SIZE(flags)]; 668 } tests[] = { 669 { "%a", NAN, { "nan", "0x1.#QNAN00000000p+0", "nan", "0x1.#QNAN00000000p+0" }}, 670 { "%A", NAN, { "NAN", "0X1.#QNAN00000000P+0", "NAN", "0X1.#QNAN00000000P+0" }}, 671 { "%e", NAN, { "nan", "1.#QNAN0e+00", "nan", "1.#QNAN0e+000" }}, 672 { "%E", NAN, { "NAN", "1.#QNAN0E+00", "NAN", "1.#QNAN0E+000" }}, 673 { "%g", NAN, { "nan", "1.#QNAN", "nan", "1.#QNAN" }}, 674 { "%G", NAN, { "NAN", "1.#QNAN", "NAN", "1.#QNAN" }}, 675 { "%21a", NAN, { " nan", " 0x1.#QNAN00000000p+0", " nan", " 0x1.#QNAN00000000p+0" }}, 676 { "%20e", NAN, { " nan", " 1.#QNAN0e+00", " nan", " 1.#QNAN0e+000" }}, 677 { "%20g", NAN, { " nan", " 1.#QNAN", " nan", " 1.#QNAN" }}, 678 { "%.21a", NAN, { "nan", "0x1.#QNAN0000000000000000p+0", "nan", "0x1.#QNAN0000000000000000p+0" }}, 679 { "%.20e", NAN, { "nan", "1.#QNAN000000000000000e+00", "nan", "1.#QNAN000000000000000e+000" }}, 680 { "%.20g", NAN, { "nan", "1.#QNAN", "nan", "1.#QNAN" }}, 681 { "%.021a", NAN, { "nan", "0x1.#QNAN0000000000000000p+0", "nan", "0x1.#QNAN0000000000000000p+0" }}, 682 { "%.020e", NAN, { "nan", "1.#QNAN000000000000000e+00", "nan", "1.#QNAN000000000000000e+000" }}, 683 { "%.020g", NAN, { "nan", "1.#QNAN", "nan", "1.#QNAN" }}, 684 { "%#.21a", NAN, { "nan", "0x1.#QNAN0000000000000000p+0", "nan", "0x1.#QNAN0000000000000000p+0" }}, 685 { "%#.20e", NAN, { "nan", "1.#QNAN000000000000000e+00", "nan", "1.#QNAN000000000000000e+000" }}, 686 { "%#.20g", NAN, { "nan", "1.#QNAN00000000000000", "nan", "1.#QNAN00000000000000" }}, 687 { "%.1g", NAN, { "nan", "1", "nan", "1" }}, 688 { "%.2g", NAN, { "nan", "1.$", "nan", "1.$" }}, 689 { "%.3g", NAN, { "nan", "1.#R", "nan", "1.#R" }}, 690 691 { "%a", IND, { "-nan(ind)", "-0x1.#IND000000000p+0", "-nan(ind)", "-0x1.#IND000000000p+0" }}, 692 { "%e", IND, { "-nan(ind)", "-1.#IND00e+00", "-nan(ind)", "-1.#IND00e+000" }}, 693 { "%g", IND, { "-nan(ind)", "-1.#IND", "-nan(ind)", "-1.#IND" }}, 694 { "%21a", IND, { " -nan(ind)", "-0x1.#IND000000000p+0", " -nan(ind)", "-0x1.#IND000000000p+0" }}, 695 { "%20e", IND, { " -nan(ind)", " -1.#IND00e+00", " -nan(ind)", " -1.#IND00e+000" }}, 696 { "%20g", IND, { " -nan(ind)", " -1.#IND", " -nan(ind)", " -1.#IND" }}, 697 { "%.21a", IND, { "-nan(ind)", "-0x1.#IND00000000000000000p+0", "-nan(ind)", "-0x1.#IND00000000000000000p+0" }}, 698 { "%.20e", IND, { "-nan(ind)", "-1.#IND0000000000000000e+00", "-nan(ind)", "-1.#IND0000000000000000e+000" }}, 699 { "%.20g", IND, { "-nan(ind)", "-1.#IND", "-nan(ind)", "-1.#IND" }}, 700 { "%.021a", IND, { "-nan(ind)", "-0x1.#IND00000000000000000p+0", "-nan(ind)", "-0x1.#IND00000000000000000p+0" }}, 701 { "%.020e", IND, { "-nan(ind)", "-1.#IND0000000000000000e+00", "-nan(ind)", "-1.#IND0000000000000000e+000" }}, 702 { "%.020g", IND, { "-nan(ind)", "-1.#IND", "-nan(ind)", "-1.#IND" }}, 703 { "%#.21a", IND, { "-nan(ind)", "-0x1.#IND00000000000000000p+0", "-nan(ind)", "-0x1.#IND00000000000000000p+0" }}, 704 { "%#.20e", IND, { "-nan(ind)", "-1.#IND0000000000000000e+00", "-nan(ind)", "-1.#IND0000000000000000e+000" }}, 705 { "%#.20g", IND, { "-nan(ind)", "-1.#IND000000000000000", "-nan(ind)", "-1.#IND000000000000000" }}, 706 707 { "%a", INFINITY, { "inf", "0x1.#INF000000000p+0", "inf", "0x1.#INF000000000p+0" }}, 708 { "%e", INFINITY, { "inf", "1.#INF00e+00", "inf", "1.#INF00e+000" }}, 709 { "%g", INFINITY, { "inf", "1.#INF", "inf", "1.#INF" }}, 710 { "%21a", INFINITY, { " inf", " 0x1.#INF000000000p+0", " inf", " 0x1.#INF000000000p+0" }}, 711 { "%20e", INFINITY, { " inf", " 1.#INF00e+00", " inf", " 1.#INF00e+000" }}, 712 { "%20g", INFINITY, { " inf", " 1.#INF", " inf", " 1.#INF" }}, 713 { "%.21a", INFINITY, { "inf", "0x1.#INF00000000000000000p+0", "inf", "0x1.#INF00000000000000000p+0" }}, 714 { "%.20e", INFINITY, { "inf", "1.#INF0000000000000000e+00", "inf", "1.#INF0000000000000000e+000" }}, 715 { "%.20g", INFINITY, { "inf", "1.#INF", "inf", "1.#INF" }}, 716 { "%.021a", INFINITY, { "inf", "0x1.#INF00000000000000000p+0", "inf", "0x1.#INF00000000000000000p+0" }}, 717 { "%.020e", INFINITY, { "inf", "1.#INF0000000000000000e+00", "inf", "1.#INF0000000000000000e+000" }}, 718 { "%.020g", INFINITY, { "inf", "1.#INF", "inf", "1.#INF" }}, 719 { "%#.21a", INFINITY, { "inf", "0x1.#INF00000000000000000p+0", "inf", "0x1.#INF00000000000000000p+0" }}, 720 { "%#.20e", INFINITY, { "inf", "1.#INF0000000000000000e+00", "inf", "1.#INF0000000000000000e+000" }}, 721 { "%#.20g", INFINITY, { "inf", "1.#INF000000000000000", "inf", "1.#INF000000000000000" }}, 722 723 { "%a", -INFINITY, { "-inf", "-0x1.#INF000000000p+0", "-inf", "-0x1.#INF000000000p+0" }}, 724 { "%e", -INFINITY, { "-inf", "-1.#INF00e+00", "-inf", "-1.#INF00e+000" }}, 725 { "%g", -INFINITY, { "-inf", "-1.#INF", "-inf", "-1.#INF" }}, 726 { "%21a", -INFINITY, { " -inf", "-0x1.#INF000000000p+0", " -inf", "-0x1.#INF000000000p+0" }}, 727 { "%20e", -INFINITY, { " -inf", " -1.#INF00e+00", " -inf", " -1.#INF00e+000" }}, 728 { "%20g", -INFINITY, { " -inf", " -1.#INF", " -inf", " -1.#INF" }}, 729 { "%.21a", -INFINITY, { "-inf", "-0x1.#INF00000000000000000p+0", "-inf", "-0x1.#INF00000000000000000p+0" }}, 730 { "%.20e", -INFINITY, { "-inf", "-1.#INF0000000000000000e+00", "-inf", "-1.#INF0000000000000000e+000" }}, 731 { "%.20g", -INFINITY, { "-inf", "-1.#INF", "-inf", "-1.#INF" }}, 732 { "%.021a", -INFINITY, { "-inf", "-0x1.#INF00000000000000000p+0", "-inf", "-0x1.#INF00000000000000000p+0" }}, 733 { "%.020e", -INFINITY, { "-inf", "-1.#INF0000000000000000e+00", "-inf", "-1.#INF0000000000000000e+000" }}, 734 { "%.020g", -INFINITY, { "-inf", "-1.#INF", "-inf", "-1.#INF" }}, 735 { "%#.21a", -INFINITY, { "-inf", "-0x1.#INF00000000000000000p+0", "-inf", "-0x1.#INF00000000000000000p+0" }}, 736 { "%#.20e", -INFINITY, { "-inf", "-1.#INF0000000000000000e+00", "-inf", "-1.#INF0000000000000000e+000" }}, 737 { "%#.20g", -INFINITY, { "-inf", "-1.#INF000000000000000", "-inf", "-1.#INF000000000000000" }}, 738 739 { "%a", 0, { "0x0.0000000000000p+0" }}, 740 { "%A", 0, { "0X0.0000000000000P+0" }}, 741 { "%a", 0.5, { "0x1.0000000000000p-1" }}, 742 { "%a", 1, { "0x1.0000000000000p+0" }}, 743 { "%a", 20, { "0x1.4000000000000p+4" }}, 744 { "%a", -1, { "-0x1.0000000000000p+0" }}, 745 { "%a", 0.1, { "0x1.999999999999ap-4" }}, 746 { "%24a", 0.1, { " 0x1.999999999999ap-4" }}, 747 { "%024a", 0.1, { "0x00001.999999999999ap-4" }}, 748 { "%.2a", 0.1, { "0x1.9ap-4" }}, 749 { "%.20a", 0.1, { "0x1.999999999999a0000000p-4" }}, 750 { "%.a", 0.1e-20, { "0x1p-70" }}, 751 { "%a", 0.1e-20, { "0x1.2e3b40a0e9b4fp-70" }}, 752 { "%a", 4.9406564584124654e-324, { "0x0.0000000000001p-1022" }}, 753 { "%.0a", -1.5, { "-0x2p+0" }, { "-0x1p+0" }}, 754 { "%.0a", -0.5, { "-0x1p-1" }}, 755 { "%.0a", 0.5, { "0x1p-1" }}, 756 { "%.0a", 1.5, { "0x2p+0" }, { "0x1p+0" }}, 757 { "%.0a", 1.99, { "0x2p+0" }}, 758 { "%.0a", 2, { "0x1p+1" }}, 759 { "%.0a", 9.5, { "0x1p+3" }}, 760 { "%.0a", 10.5, { "0x1p+3" }}, 761 { "%#.0a", -1.5, { "-0x2.p+0" }, { "-0x1.p+0" }}, 762 { "%#.0a", -0.5, { "-0x1.p-1" }}, 763 { "%#.0a", 0.5, { "0x1.p-1" }}, 764 { "%#.0a", 1.5, { "0x2.p+0" }, { "0x1.p+0" }}, 765 { "%#.1a", 1.03125, { "0x1.1p+0", NULL, NULL, NULL, "0x1.0p+0" }, { "0x1.0p+0" }}, 766 { "%#.1a", 1.09375, { "0x1.2p+0" }, { "0x1.1p+0" }}, 767 { "%#.1a", 1.15625, { "0x1.3p+0", NULL, NULL, NULL, "0x1.2p+0" }, { "0x1.2p+0" }}, 768 769 { "%f", 0, { "0.000000" }}, 770 { "%e", 0, { "0.000000e+00", NULL, "0.000000e+000" }}, 771 { "%g", 0, { "0" }}, 772 { "%21f", 0, { " 0.000000" }}, 773 { "%20e", 0, { " 0.000000e+00", NULL, " 0.000000e+000" }}, 774 { "%20g", 0, { " 0" }}, 775 { "%.21f", 0, { "0.000000000000000000000" }}, 776 { "%.20e", 0, { "0.00000000000000000000e+00", NULL, "0.00000000000000000000e+000" }}, 777 { "%.20g", 0, { "0" }}, 778 { "%.021f", 0, { "0.000000000000000000000" }}, 779 { "%.020e", 0, { "0.00000000000000000000e+00", NULL, "0.00000000000000000000e+000" }}, 780 { "%.020g", 0, { "0" }}, 781 { "%#.21f", 0, { "0.000000000000000000000" }}, 782 { "%#.20e", 0, { "0.00000000000000000000e+00", NULL, "0.00000000000000000000e+000" }}, 783 { "%#.20g", 0, { "0.0000000000000000000" }, { "0.00000000000000000000" }}, 784 785 { "%f", 123, { "123.000000" }}, 786 { "%e", 123, { "1.230000e+02", NULL, "1.230000e+002" }}, 787 { "%g", 123, { "123" }}, 788 { "%21f", 123, { " 123.000000" }}, 789 { "%20e", 123, { " 1.230000e+02", NULL, " 1.230000e+002" }}, 790 { "%20g", 123, { " 123" }}, 791 { "%.21f", 123, { "123.000000000000000000000" }}, 792 { "%.20e", 123, { "1.23000000000000000000e+02", NULL, "1.23000000000000000000e+002" }}, 793 { "%.20g", 123, { "123" }}, 794 { "%.021f", 123, { "123.000000000000000000000" }}, 795 { "%.020e", 123, { "1.23000000000000000000e+02", NULL, "1.23000000000000000000e+002" }}, 796 { "%.020g", 123, { "123" }}, 797 { "%#.21f", 123, { "123.000000000000000000000" }}, 798 { "%#.20e", 123, { "1.23000000000000000000e+02", NULL, "1.23000000000000000000e+002" }}, 799 { "%#.20g", 123, { "123.00000000000000000" }}, 800 801 { "%f", -765, { "-765.000000" }}, 802 { "%e", -765, { "-7.650000e+02", NULL, "-7.650000e+002" }}, 803 { "%g", -765, { "-765" }}, 804 { "%21f", -765, { " -765.000000" }}, 805 { "%20e", -765, { " -7.650000e+02", NULL, " -7.650000e+002" }}, 806 { "%20g", -765, { " -765" }}, 807 { "%.21f", -765, { "-765.000000000000000000000" }}, 808 { "%.20e", -765, { "-7.65000000000000000000e+02", NULL, "-7.65000000000000000000e+002" }}, 809 { "%.20g", -765, { "-765" }}, 810 { "%.021f", -765, { "-765.000000000000000000000" }}, 811 { "%.020e", -765, { "-7.65000000000000000000e+02", NULL, "-7.65000000000000000000e+002" }}, 812 { "%.020g", -765, { "-765" }}, 813 { "%#.21f", -765, { "-765.000000000000000000000" }}, 814 { "%#.20e", -765, { "-7.65000000000000000000e+02", NULL, "-7.65000000000000000000e+002" }}, 815 { "%#.20g", -765, { "-765.00000000000000000" }}, 816 { "%.30f", 1.0/3.0, { "0.333333333333333314829616256247" }}, 817 { "%.30lf", sqrt(2), { "1.414213562373095145474621858739" }}, 818 { "%f", 3.141592653590000, { "3.141593" }}, 819 { "%.10f", 3.141592653590000, { "3.1415926536" }}, 820 { "%.11f", 3.141592653590000, { "3.14159265359" }}, 821 { "%.15f", 3.141592653590000, { "3.141592653590000" }}, 822 { "%.15f", M_PI, { "3.141592653589793" }}, 823 { "%.13f", 37.866261574537077, { "37.8662615745371" }}, 824 { "%.14f", 37.866261574537077, { "37.86626157453708" }}, 825 { "%.15f", 37.866261574537077, { "37.866261574537077" }}, 826 { "%.0g", 9.8949714229143402e-05, { "0.0001" }}, 827 { "%.0f", 0.5, { "1", NULL, NULL, NULL, "0" }, {NULL, NULL, NULL, NULL, "1" }}, 828 { "%.0f", 1.5, { "2" }}, 829 { "%.0f", 2.5, { "3", NULL, NULL, NULL, "2" }, {NULL, NULL, NULL, NULL, "3" }}, 830 { "%g", 9.999999999999999e-5, { "0.0001" }}, 831 832 { "%g", 0.0005, { "0.0005" }}, 833 { "%g", 0.00005, { "5e-05", NULL, "5e-005" }}, 834 { "%g", 0.000005, { "5e-06", NULL, "5e-006" }}, 835 { "%g", 999999999999999.0, { "1e+15", NULL, "1e+015" }}, 836 { "%g", 1000000000000000.0, { "1e+15", NULL, "1e+015" }}, 837 { "%.15g", 0.0005, { "0.0005" }}, 838 { "%.15g", 0.00005, { "5e-05", NULL, "5e-005" }}, 839 { "%.15g", 0.000005, { "5e-06", NULL, "5e-006" }}, 840 { "%.15g", 999999999999999.0, { "999999999999999" }}, 841 { "%.15g", 1000000000000000.0, { "1e+15", NULL, "1e+015" }}, 842 }; 843 844 const char *res = NULL; 845 const char *broken_res; 846 char buf[100]; 847 int i, j, r; 848 849 for (i = 0; i < ARRAY_SIZE(tests); i++) 850 { 851 broken_res = NULL; 852 853 for (j = 0; j < ARRAY_SIZE(flags); j++) 854 { 855 if (tests[i].res[j]) res = tests[i].res[j]; 856 if (tests[i].broken[j]) broken_res = tests[i].broken[j]; 857 858 r = vsprintf_wrapper(flags[j], buf, sizeof(buf), tests[i].fmt, tests[i].d); 859 ok(r == strlen(res) || broken(broken_res && r == strlen(broken_res)), 860 "%d,%d) r = %d, expected %Id\n", i, j, r, strlen(res)); 861 ok(!strcmp(buf, res) || broken(broken_res && !strcmp(buf, broken_res)), 862 "%d,%d) buf = %s, expected %s\n", i, j, buf, res); 863 } 864 } 865} 866 867static void test_printf_width_specification(void) 868{ 869 int r; 870 char buffer[20]; 871 872 r = vsprintf_wrapper(0, buffer, sizeof(buffer), "%0*2d", 1, 3); 873 ok(r == 2, "r = %d\n", r); 874 ok(!strcmp(buffer, "03"), "buffer wrong, got=%s\n", buffer); 875 876 r = vsprintf_wrapper(0, buffer, sizeof(buffer), "%*0d", 1, 2); 877 ok(r == 1, "r = %d\n", r); 878 ok(!strcmp(buffer, "2"), "buffer wrong, got=%s\n", buffer); 879 880 r = vsprintf_wrapper(0, buffer, sizeof(buffer), "% *2d", 0, 7); 881 ok(r == 2, "r = %d\n", r); 882 ok(!strcmp(buffer, " 7"), "buffer wrong, got=%s\n", buffer); 883} 884 885START_TEST(printf) 886{ 887 ok(_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL, 888 "Invalid parameter handler was already set\n"); 889 890 test_snprintf(); 891 test_swprintf(); 892 test_fprintf(); 893 test_fwprintf(); 894 test_vsnprintf_s(); 895 test_vsnwprintf_s(); 896 test_printf_legacy_wide(); 897 test_printf_legacy_msvcrt(); 898 test_printf_legacy_three_digit_exp(); 899 test_printf_c99(); 900 test_printf_natural_string(); 901 test_printf_fp(); 902 test_printf_width_specification(); 903}