2 * Copyright 2016 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
39 #include "wine/test.h"
41 #define DEFINE_EXPECT(func) \
42 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
44 #define SET_EXPECT(func) \
45 expect_ ## func = TRUE
47 #define CHECK_EXPECT2(func) \
49 ok(expect_ ##func, "unexpected call " #func "\n"); \
50 called_ ## func = TRUE; \
53 #define CHECK_EXPECT(func) \
55 CHECK_EXPECT2(func); \
56 expect_ ## func = FALSE; \
59 #define CHECK_CALLED(func) \
61 ok(called_ ## func, "expected " #func "\n"); \
62 expect_ ## func = called_ ## func = FALSE; \
65 static inline double __port_min_pos_double(void)
67 static const UINT64 __min_pos_double
= 0x10000000000000;
68 return *(const double *)&__min_pos_double
;
71 static inline double __port_max_double(void)
73 static const UINT64 __max_double
= 0x7FEFFFFFFFFFFFFF;
74 return *(const double *)&__max_double
;
77 DEFINE_EXPECT(global_invalid_parameter_handler
);
78 DEFINE_EXPECT(thread_invalid_parameter_handler
);
81 const char *short_wday
[7];
83 const char *short_mon
[12];
87 const char *short_date
;
92 const wchar_t *short_wdayW
[7];
93 const wchar_t *wdayW
[7];
94 const wchar_t *short_monW
[12];
95 const wchar_t *monW
[12];
98 const wchar_t *short_dateW
;
100 const wchar_t *timeW
;
101 const wchar_t *locnameW
;
104 typedef void (__cdecl
*_se_translator_function
)(unsigned int code
, struct _EXCEPTION_POINTERS
*info
);
106 static LONGLONG crt_init_end
;
108 _ACRTIMP
int __cdecl
_o__initialize_onexit_table(_onexit_table_t
*table
);
109 _ACRTIMP
int __cdecl
_o__register_onexit_function(_onexit_table_t
*table
, _onexit_t func
);
110 _ACRTIMP
int __cdecl
_o__execute_onexit_table(_onexit_table_t
*table
);
111 _ACRTIMP
void *__cdecl
_o_malloc(size_t);
112 _se_translator_function __cdecl
_set_se_translator(_se_translator_function func
);
113 void** __cdecl
__current_exception(void);
114 int* __cdecl
__processing_throw(void);
116 static void test__initialize_onexit_table(void)
118 _onexit_table_t table
, table2
;
121 ret
= _initialize_onexit_table(NULL
);
122 ok(ret
== -1, "got %d\n", ret
);
124 memset(&table
, 0, sizeof(table
));
125 ret
= _initialize_onexit_table(&table
);
126 ok(ret
== 0, "got %d\n", ret
);
127 ok(table
._first
== table
._last
&& table
._first
== table
._end
, "got first %p, last %p, end %p\n",
128 table
._first
, table
._last
, table
._end
);
130 memset(&table2
, 0, sizeof(table2
));
131 ret
= _initialize_onexit_table(&table2
);
132 ok(ret
== 0, "got %d\n", ret
);
133 ok(table2
._first
== table
._first
, "got %p, %p\n", table2
._first
, table
._first
);
134 ok(table2
._last
== table
._last
, "got %p, %p\n", table2
._last
, table
._last
);
135 ok(table2
._end
== table
._end
, "got %p, %p\n", table2
._end
, table
._end
);
137 memset(&table2
, 0, sizeof(table2
));
138 ret
= _o__initialize_onexit_table(&table2
);
139 ok(ret
== 0, "got %d\n", ret
);
140 ok(table2
._first
== table
._first
, "got %p, %p\n", table2
._first
, table
._first
);
141 ok(table2
._last
== table
._last
, "got %p, %p\n", table2
._last
, table
._last
);
142 ok(table2
._end
== table
._end
, "got %p, %p\n", table2
._end
, table
._end
);
144 /* uninitialized table */
145 table
._first
= table
._last
= table
._end
= (void*)0x123;
146 ret
= _initialize_onexit_table(&table
);
147 ok(ret
== 0, "got %d\n", ret
);
148 ok(table
._first
== table
._last
&& table
._first
== table
._end
, "got first %p, last %p, end %p\n",
149 table
._first
, table
._last
, table
._end
);
150 ok(table
._first
!= (void*)0x123, "got %p\n", table
._first
);
152 table
._first
= (void*)0x123;
153 table
._last
= (void*)0x456;
154 table
._end
= (void*)0x123;
155 ret
= _initialize_onexit_table(&table
);
156 ok(ret
== 0, "got %d\n", ret
);
157 ok(table
._first
== table
._last
&& table
._first
== table
._end
, "got first %p, last %p, end %p\n",
158 table
._first
, table
._last
, table
._end
);
159 ok(table
._first
!= (void*)0x123, "got %p\n", table
._first
);
161 table
._first
= (void*)0x123;
162 table
._last
= (void*)0x456;
163 table
._end
= (void*)0x789;
164 ret
= _initialize_onexit_table(&table
);
165 ok(ret
== 0, "got %d\n", ret
);
166 ok(table
._first
== (void*)0x123, "got %p\n", table
._first
);
167 ok(table
._last
== (void*)0x456, "got %p\n", table
._last
);
168 ok(table
._end
== (void*)0x789, "got %p\n", table
._end
);
171 table
._last
= (void*)0x456;
173 ret
= _initialize_onexit_table(&table
);
174 ok(ret
== 0, "got %d\n", ret
);
175 ok(table
._first
== table
._last
&& table
._first
== table
._end
, "got first %p, last %p, end %p\n",
176 table
._first
, table
._last
, table
._end
);
179 static int g_onexit_called
;
180 static int CDECL
onexit_func(void)
186 static int CDECL
onexit_func2(void)
188 ok(g_onexit_called
== 0, "got %d\n", g_onexit_called
);
193 static void test__register_onexit_function(void)
195 _onexit_table_t table
;
199 memset(&table
, 0, sizeof(table
));
200 ret
= _initialize_onexit_table(&table
);
201 ok(ret
== 0, "got %d\n", ret
);
203 ret
= _register_onexit_function(NULL
, NULL
);
204 ok(ret
== -1, "got %d\n", ret
);
206 ret
= _register_onexit_function(NULL
, onexit_func
);
207 ok(ret
== -1, "got %d\n", ret
);
210 ret
= _register_onexit_function(&table
, NULL
);
211 ok(ret
== 0, "got %d\n", ret
);
212 ok(f
!= table
._last
, "got %p, initial %p\n", table
._last
, f
);
214 ret
= _register_onexit_function(&table
, onexit_func
);
215 ok(ret
== 0, "got %d\n", ret
);
218 ret
= _register_onexit_function(&table
, onexit_func
);
219 ok(ret
== 0, "got %d\n", ret
);
220 ok(f
!= table
._last
, "got %p, initial %p\n", table
._last
, f
);
223 ret
= _o__register_onexit_function(&table
, NULL
);
224 ok(ret
== 0, "got %d\n", ret
);
225 ok(f
!= table
._last
, "got %p, initial %p\n", table
._last
, f
);
228 ret
= _o__register_onexit_function(&table
, onexit_func
);
229 ok(ret
== 0, "got %d\n", ret
);
230 ok(f
!= table
._last
, "got %p, initial %p\n", table
._last
, f
);
232 ret
= _execute_onexit_table(&table
);
233 ok(ret
== 0, "got %d\n", ret
);
236 static void test__execute_onexit_table(void)
238 _onexit_table_t table
;
241 ret
= _execute_onexit_table(NULL
);
242 ok(ret
== -1, "got %d\n", ret
);
244 memset(&table
, 0, sizeof(table
));
245 ret
= _initialize_onexit_table(&table
);
246 ok(ret
== 0, "got %d\n", ret
);
248 /* execute empty table */
249 ret
= _execute_onexit_table(&table
);
250 ok(ret
== 0, "got %d\n", ret
);
252 /* same function registered multiple times */
253 ret
= _register_onexit_function(&table
, onexit_func
);
254 ok(ret
== 0, "got %d\n", ret
);
256 ret
= _register_onexit_function(&table
, NULL
);
257 ok(ret
== 0, "got %d\n", ret
);
259 ret
= _register_onexit_function(&table
, onexit_func
);
260 ok(ret
== 0, "got %d\n", ret
);
262 ret
= _o__register_onexit_function(&table
, onexit_func
);
263 ok(ret
== 0, "got %d\n", ret
);
265 ok(table
._first
!= table
._end
, "got %p, %p\n", table
._first
, table
._end
);
267 ret
= _execute_onexit_table(&table
);
268 ok(ret
== 0, "got %d\n", ret
);
269 ok(g_onexit_called
== 3, "got %d\n", g_onexit_called
);
270 ok(table
._first
== table
._end
, "got %p, %p\n", table
._first
, table
._end
);
272 ret
= _register_onexit_function(&table
, onexit_func
);
273 ok(ret
== 0, "got %d\n", ret
);
275 ret
= _register_onexit_function(&table
, NULL
);
276 ok(ret
== 0, "got %d\n", ret
);
278 ret
= _register_onexit_function(&table
, onexit_func
);
279 ok(ret
== 0, "got %d\n", ret
);
281 ret
= _o__register_onexit_function(&table
, onexit_func
);
282 ok(ret
== 0, "got %d\n", ret
);
284 ok(table
._first
!= table
._end
, "got %p, %p\n", table
._first
, table
._end
);
286 ret
= _o__execute_onexit_table(&table
);
287 ok(ret
== 0, "got %d\n", ret
);
288 ok(g_onexit_called
== 3, "got %d\n", g_onexit_called
);
289 ok(table
._first
== table
._end
, "got %p, %p\n", table
._first
, table
._end
);
291 /* execute again, table is already empty */
293 ret
= _execute_onexit_table(&table
);
294 ok(ret
== 0, "got %d\n", ret
);
295 ok(g_onexit_called
== 0, "got %d\n", g_onexit_called
);
297 /* check call order */
298 memset(&table
, 0, sizeof(table
));
299 ret
= _initialize_onexit_table(&table
);
300 ok(ret
== 0, "got %d\n", ret
);
302 ret
= _register_onexit_function(&table
, onexit_func
);
303 ok(ret
== 0, "got %d\n", ret
);
305 ret
= _register_onexit_function(&table
, onexit_func2
);
306 ok(ret
== 0, "got %d\n", ret
);
309 ret
= _execute_onexit_table(&table
);
310 ok(ret
== 0, "got %d\n", ret
);
311 ok(g_onexit_called
== 2, "got %d\n", g_onexit_called
);
314 static void test___fpe_flt_rounds(void)
316 unsigned int cfp
= _controlfp(0, 0);
320 skip("_controlfp not supported\n");
324 ok((_controlfp(_RC_NEAR
, _RC_CHOP
) & _RC_CHOP
) == _RC_NEAR
, "_controlfp(_RC_NEAR, _RC_CHOP) failed\n");
325 ret
= __fpe_flt_rounds();
326 ok(ret
== 1, "__fpe_flt_rounds returned %d\n", ret
);
328 ok((_controlfp(_RC_UP
, _RC_CHOP
) & _RC_CHOP
) == _RC_UP
, "_controlfp(_RC_UP, _RC_CHOP) failed\n");
329 ret
= __fpe_flt_rounds();
330 ok(ret
== 2 || broken(ret
== 3) /* w1064v1507 */, "__fpe_flt_rounds returned %d\n", ret
);
332 ok((_controlfp(_RC_DOWN
, _RC_CHOP
) & _RC_CHOP
) == _RC_DOWN
, "_controlfp(_RC_DOWN, _RC_CHOP) failed\n");
333 ret
= __fpe_flt_rounds();
334 ok(ret
== 3 || broken(ret
== 2) /* w1064v1507 */, "__fpe_flt_rounds returned %d\n", ret
);
336 ok((_controlfp(_RC_CHOP
, _RC_CHOP
) & _RC_CHOP
) == _RC_CHOP
, "_controlfp(_RC_CHOP, _RC_CHOP) failed\n");
337 ret
= __fpe_flt_rounds();
338 ok(ret
== 0, "__fpe_flt_rounds returned %d\n", ret
);
340 _controlfp(cfp
, _MCW_EM
| _MCW_RC
| _MCW_PC
);
343 static void test__control87_2(void)
346 unsigned int x86_cw_init
, sse2_cw_init
, x86_cw
, sse2_cw
, r
;
348 r
= __control87_2(0, 0, &x86_cw_init
, &sse2_cw_init
);
349 ok(r
== 1, "__control87_2 returned %d\n", r
);
351 r
= __control87_2(0, _EM_INVALID
, &x86_cw
, NULL
);
352 ok(r
== 1, "__control87_2 returned %d\n", r
);
353 ok(x86_cw
== (x86_cw_init
& ~_EM_INVALID
), "x86_cw = %x, x86_cw_init = %x\n", x86_cw
, x86_cw_init
);
355 r
= __control87_2(0, 0, &x86_cw
, &sse2_cw
);
356 ok(r
== 1, "__control87_2 returned %d\n", r
);
357 ok(x86_cw
== (x86_cw_init
& ~_EM_INVALID
), "x86_cw = %x, x86_cw_init = %x\n", x86_cw
, x86_cw_init
);
358 ok(sse2_cw
== sse2_cw_init
, "sse2_cw = %x, sse2_cw_init = %x\n", sse2_cw
, sse2_cw_init
);
360 r
= _control87(0, 0);
361 ok(r
== (x86_cw
| sse2_cw
| _EM_AMBIGUOUS
), "r = %x, expected %x\n",
362 r
, x86_cw
| sse2_cw
| _EM_AMBIGUOUS
);
364 _control87(x86_cw_init
, ~0);
368 static void __cdecl
global_invalid_parameter_handler(
369 const wchar_t *expression
, const wchar_t *function
,
370 const wchar_t *file
, unsigned line
, uintptr_t arg
)
372 CHECK_EXPECT2(global_invalid_parameter_handler
);
375 static void __cdecl
thread_invalid_parameter_handler(
376 const wchar_t *expression
, const wchar_t *function
,
377 const wchar_t *file
, unsigned line
, uintptr_t arg
)
379 CHECK_EXPECT(thread_invalid_parameter_handler
);
382 static void test_invalid_parameter_handler(void)
384 _invalid_parameter_handler ret
;
386 ret
= _get_invalid_parameter_handler();
387 ok(!ret
, "ret != NULL\n");
389 ret
= _get_thread_local_invalid_parameter_handler();
390 ok(!ret
, "ret != NULL\n");
392 ret
= _set_thread_local_invalid_parameter_handler(thread_invalid_parameter_handler
);
393 ok(!ret
, "ret != NULL\n");
395 ret
= _get_thread_local_invalid_parameter_handler();
396 ok(ret
== thread_invalid_parameter_handler
, "ret = %p\n", ret
);
398 ret
= _get_invalid_parameter_handler();
399 ok(!ret
, "ret != NULL\n");
401 ret
= _set_invalid_parameter_handler(global_invalid_parameter_handler
);
402 ok(!ret
, "ret != NULL\n");
404 ret
= _get_invalid_parameter_handler();
405 ok(ret
== global_invalid_parameter_handler
, "ret = %p\n", ret
);
407 ret
= _get_thread_local_invalid_parameter_handler();
408 ok(ret
== thread_invalid_parameter_handler
, "ret = %p\n", ret
);
410 SET_EXPECT(thread_invalid_parameter_handler
);
411 _ltoa_s(0, NULL
, 0, 0);
412 CHECK_CALLED(thread_invalid_parameter_handler
);
414 ret
= _set_thread_local_invalid_parameter_handler(NULL
);
415 ok(ret
== thread_invalid_parameter_handler
, "ret = %p\n", ret
);
417 SET_EXPECT(global_invalid_parameter_handler
);
418 _ltoa_s(0, NULL
, 0, 0);
419 CHECK_CALLED(global_invalid_parameter_handler
);
421 ret
= _set_invalid_parameter_handler(NULL
);
422 ok(ret
== global_invalid_parameter_handler
, "ret = %p\n", ret
);
424 ret
= _set_invalid_parameter_handler(global_invalid_parameter_handler
);
425 ok(!ret
, "ret != NULL\n");
428 static void test__get_narrow_winmain_command_line(char *path
)
430 PROCESS_INFORMATION proc
;
431 STARTUPINFOA startup
;
432 char cmd
[MAX_PATH
+32];
433 char *ret
, *cmdline
, *name
;
436 ret
= _get_narrow_winmain_command_line();
437 cmdline
= GetCommandLineA();
438 len
= strlen(cmdline
);
439 ok(ret
>cmdline
&& ret
<cmdline
+len
, "ret = %p, cmdline = %p (len = %d)\n", ret
, cmdline
, len
);
442 ok(!lstrcmpA(ret
, "\"misc\" cmd"), "ret = %s\n", ret
);
446 for(len
= strlen(path
); len
>0; len
--)
447 if(path
[len
-1]=='\\' || path
[len
-1]=='/') break;
448 if(len
) name
= path
+len
;
451 sprintf(cmd
, "\"\"%c\"\"\"%s\" \t \"misc\" cmd", name
[0], name
+1);
452 memset(&startup
, 0, sizeof(startup
));
453 startup
.cb
= sizeof(startup
);
454 CreateProcessA(path
, cmd
, NULL
, NULL
, TRUE
,
455 CREATE_DEFAULT_ERROR_MODE
|NORMAL_PRIORITY_CLASS
,
456 NULL
, NULL
, &startup
, &proc
);
457 wait_child_process(proc
.hProcess
);
458 CloseHandle(proc
.hProcess
);
459 CloseHandle(proc
.hThread
);
462 static void test__sopen_dispatch(void)
467 tempf
= _tempnam(".", "wne");
470 ret
= _sopen_dispatch(tempf
, _O_CREAT
, _SH_DENYWR
, 0xff, &fd
, 0);
471 ok(!ret
, "got %d\n", ret
);
472 ok(fd
> 0, "got fd %d\n", fd
);
476 SET_EXPECT(global_invalid_parameter_handler
);
478 ret
= _sopen_dispatch(tempf
, _O_CREAT
, _SH_DENYWR
, 0xff, &fd
, 1);
479 ok(ret
== EINVAL
, "got %d\n", ret
);
480 ok(fd
== -1, "got fd %d\n", fd
);
481 CHECK_CALLED(global_invalid_parameter_handler
);
491 static void test__sopen_s(void)
496 tempf
= _tempnam(".", "wne");
499 ret
= _sopen_s(&fd
, tempf
, _O_CREAT
, _SH_DENYWR
, 0);
500 ok(!ret
, "got %d\n", ret
);
501 ok(fd
> 0, "got fd %d\n", fd
);
505 /* _open() does not validate pmode */
506 fd
= _open(tempf
, _O_CREAT
, 0xff);
507 ok(fd
> 0, "got fd %d\n", fd
);
511 /* _sopen_s() invokes invalid parameter handler on invalid pmode */
512 SET_EXPECT(global_invalid_parameter_handler
);
514 ret
= _sopen_s(&fd
, tempf
, _O_CREAT
, _SH_DENYWR
, 0xff);
515 ok(ret
== EINVAL
, "got %d\n", ret
);
516 ok(fd
== -1, "got fd %d\n", fd
);
517 CHECK_CALLED(global_invalid_parameter_handler
);
522 static void test_lldiv(void)
526 r
= lldiv(((LONGLONG
)0x111 << 32) + 0x222, (LONGLONG
)1 << 32);
527 ok(r
.quot
== 0x111, "quot = %s\n", wine_dbgstr_longlong(r
.quot
));
528 ok(r
.rem
== 0x222, "rem = %s\n", wine_dbgstr_longlong(r
.rem
));
530 r
= lldiv(((LONGLONG
)0x69CF0012 << 32) + 0x0033E78A, 0x30);
531 ok(r
.quot
== ((LONGLONG
)0x02345000 << 32) + 0x600114D2, "quot = %s\n", wine_dbgstr_longlong(r
.quot
));
532 ok(r
.rem
== 0x2A, "rem = %s\n", wine_dbgstr_longlong(r
.rem
));
534 r
= lldiv(((LONGLONG
)0x243A5678 << 32) + 0x9ABCDEF0, (LONGLONG
)0x12 << 48);
535 ok(r
.quot
== 0x0203, "quot = %s\n", wine_dbgstr_longlong(r
.quot
));
536 ok(r
.rem
== ((LONGLONG
)0x00045678 << 32) + 0x9ABCDEF0, "rem = %s\n", wine_dbgstr_longlong(r
.rem
));
539 static void test_isblank(void)
543 for(c
= 0; c
<= 0xff; c
++) {
544 if(c
== '\t' || c
== ' ') {
546 ok(!_isctype(c
, _BLANK
), "tab shouldn't be blank\n");
548 ok(_isctype(c
, _BLANK
), "space should be blank\n");
549 ok(isblank(c
), "%d should be blank\n", c
);
550 ok(_isblank_l(c
, NULL
), "%d should be blank\n", c
);
552 ok(!_isctype(c
, _BLANK
), "%d shouldn't be blank\n", c
);
553 ok(!isblank(c
), "%d shouldn't be blank\n", c
);
554 ok(!_isblank_l(c
, NULL
), "%d shouldn't be blank\n", c
);
558 for(c
= 0; c
<= 0xffff; c
++) {
559 if(c
== '\t' || c
== ' ' || c
== 0x3000 || c
== 0xfeff) {
561 ok(!_iswctype_l(c
, _BLANK
, NULL
), "tab shouldn't be blank\n");
563 ok(_iswctype_l(c
, _BLANK
, NULL
), "%d should be blank\n", c
);
564 ok(iswblank(c
), "%d should be blank\n", c
);
565 ok(_iswblank_l(c
, NULL
), "%d should be blank\n", c
);
567 ok(!_iswctype_l(c
, _BLANK
, NULL
), "%d shouldn't be blank\n", c
);
568 ok(!iswblank(c
), "%d shouldn't be blank\n", c
);
569 ok(!_iswblank_l(c
, NULL
), "%d shouldn't be blank\n", c
);
574 static struct _exception exception
;
576 static int CDECL
matherr_callback(struct _exception
*e
)
580 if (!strcmp(e
->name
, "acos") && e
->arg1
== 2)
585 static void test_math_errors(void)
593 {"_logb", -INFINITY
, -1, -1},
594 {"_logb", -1, -1, -1},
595 {"_logb", 0, ERANGE
, _SING
},
596 {"_logb", INFINITY
, -1, -1},
597 {"acos", -INFINITY
, EDOM
, _DOMAIN
},
598 {"acos", -2, EDOM
, _DOMAIN
},
599 {"acos", -1, -1, -1},
601 {"acos", 2, EDOM
, _DOMAIN
},
602 {"acos", INFINITY
, EDOM
, _DOMAIN
},
603 {"acosh", -INFINITY
, EDOM
, -1},
604 {"acosh", 0, EDOM
, -1},
605 {"acosh", 1, -1, -1},
606 {"acosh", INFINITY
, -1, -1},
607 {"asin", -INFINITY
, EDOM
, _DOMAIN
},
608 {"asin", -2, EDOM
, _DOMAIN
},
609 {"asin", -1, -1, -1},
611 {"asin", 2, EDOM
, _DOMAIN
},
612 {"asin", INFINITY
, EDOM
, _DOMAIN
},
613 {"asinh", -INFINITY
, -1, -1},
614 {"asinh", INFINITY
, -1, -1},
615 {"atan", -INFINITY
, -1, -1},
617 {"atan", INFINITY
, -1, -1},
618 {"atanh", -INFINITY
, EDOM
, -1},
619 {"atanh", -2, EDOM
, -1},
620 {"atanh", -1, ERANGE
, -1},
621 {"atanh", 1, ERANGE
, -1},
622 {"atanh", 2, EDOM
, -1},
623 {"atanh", INFINITY
, EDOM
, -1},
624 {"cos", -INFINITY
, EDOM
, _DOMAIN
},
625 {"cos", INFINITY
, EDOM
, _DOMAIN
},
626 {"cosh", -INFINITY
, -1, -1},
628 {"cosh", INFINITY
, -1, -1},
629 {"exp", -INFINITY
, -1, -1},
630 {"exp", -1e100
, -1, _UNDERFLOW
},
631 {"exp", 1e100
, ERANGE
, _OVERFLOW
},
632 {"exp", INFINITY
, -1, -1},
633 {"exp2", -INFINITY
, -1, -1},
634 {"exp2", -1e100
, -1, -1},
635 {"exp2", 1e100
, ERANGE
, -1},
636 {"exp2", INFINITY
, -1, -1},
637 {"expm1", -INFINITY
, -1, -1},
638 {"expm1", INFINITY
, -1, -1},
639 {"log", -INFINITY
, EDOM
, _DOMAIN
},
640 {"log", -1, EDOM
, _DOMAIN
},
641 {"log", 0, ERANGE
, _SING
},
642 {"log", INFINITY
, -1, -1},
643 {"log10", -INFINITY
, EDOM
, _DOMAIN
},
644 {"log10", -1, EDOM
, _DOMAIN
},
645 {"log10", 0, ERANGE
, _SING
},
646 {"log10", INFINITY
, -1, -1},
647 {"log1p", -INFINITY
, EDOM
, -1},
648 {"log1p", -2, EDOM
, -1},
649 {"log1p", -1, ERANGE
, -1},
650 {"log1p", INFINITY
, -1, -1},
651 {"log2", INFINITY
, -1, -1},
652 {"sin", -INFINITY
, EDOM
, _DOMAIN
},
653 {"sin", INFINITY
, EDOM
, _DOMAIN
},
654 {"sinh", -INFINITY
, -1, -1},
656 {"sinh", INFINITY
, -1, -1},
657 {"sqrt", -INFINITY
, EDOM
, _DOMAIN
},
658 {"sqrt", -1, EDOM
, _DOMAIN
},
660 {"sqrt", INFINITY
, -1, -1},
661 {"tan", -INFINITY
, EDOM
, _DOMAIN
},
662 {"tan", -M_PI_2
, -1, -1},
663 {"tan", M_PI_2
, -1, -1},
664 {"tan", INFINITY
, EDOM
, _DOMAIN
},
665 {"tanh", -INFINITY
, -1, -1},
667 {"tanh", INFINITY
, -1, -1},
676 {"atan2", -INFINITY
, 0, -1, -1},
677 {"atan2", 0, 0, -1, -1},
678 {"atan2", INFINITY
, 0, -1, -1},
679 {"atan2", 0, -INFINITY
, -1, -1},
680 {"atan2", 0, INFINITY
, -1, -1},
681 {"pow", -INFINITY
, -2, -1, -1},
682 {"pow", -INFINITY
, -1, -1, -1},
683 {"pow", -INFINITY
, 0, -1, -1},
684 {"pow", -INFINITY
, 1, -1, -1},
685 {"pow", -INFINITY
, 2, -1, -1},
686 {"pow", -1e100
, -10, -1, _UNDERFLOW
},
687 {"pow", -1e100
, 10, ERANGE
, _OVERFLOW
},
688 {"pow", -1, 1.5, EDOM
, _DOMAIN
},
689 {"pow", 0, -2, ERANGE
, _SING
},
690 {"pow", 0, -1, ERANGE
, _SING
},
691 {"pow", 0.5, -INFINITY
, -1, -1},
692 {"pow", 0.5, INFINITY
, -1, -1},
693 {"pow", 2, -INFINITY
, -1, -1},
694 {"pow", 2, -1e100
, -1, _UNDERFLOW
},
695 {"pow", 2, 1e100
, ERANGE
, _OVERFLOW
},
696 {"pow", 2, INFINITY
, -1, -1},
697 {"pow", 1e100
, -10, -1, _UNDERFLOW
},
698 {"pow", 1e100
, 10, ERANGE
, _OVERFLOW
},
699 {"pow", INFINITY
, -2, -1, -1},
700 {"pow", INFINITY
, -1, -1, -1},
701 {"pow", INFINITY
, 0, -1, -1},
702 {"pow", INFINITY
, 1, -1, -1},
703 {"pow", INFINITY
, 2, -1, -1},
713 /* 0 * inf --> EDOM */
714 {"fma", INFINITY
, 0, 0, EDOM
, -1},
715 {"fma", 0, INFINITY
, 0, EDOM
, -1},
716 /* inf - inf -> EDOM */
717 {"fma", INFINITY
, 1, -INFINITY
, EDOM
, -1},
718 {"fma", -INFINITY
, 1, INFINITY
, EDOM
, -1},
719 {"fma", 1, INFINITY
, -INFINITY
, EDOM
, -1},
720 {"fma", 1, -INFINITY
, INFINITY
, EDOM
, -1},
722 {"fma", NAN
, 0, 0, -1, -1},
723 {"fma", 0, NAN
, 0, -1, -1},
724 {"fma", 0, 0, NAN
, -1, -1},
726 {"fma", __port_max_double(), __port_max_double(), __port_max_double(), -1, -1},
727 {"fma", __port_min_pos_double(), __port_min_pos_double(), 1, -1, -1},
736 {"_scalb", -INFINITY
, 1, -1, -1},
737 {"_scalb", -1e100
, 1, -1, -1},
738 {"_scalb", 0, 1, -1, -1},
739 {"_scalb", 1e100
, 1, -1, -1},
740 {"_scalb", INFINITY
, 1, -1, -1},
741 {"_scalb", 1, 1e9
, ERANGE
, _OVERFLOW
},
742 {"ldexp", -INFINITY
, 1, -1, -1},
743 {"ldexp", -1e100
, 1, -1, -1},
744 {"ldexp", 0, 1, -1, -1},
745 {"ldexp", 1e100
, 1, -1, -1},
746 {"ldexp", INFINITY
, 1, -1, -1},
747 {"ldexp", 1, -1e9
, -1, _UNDERFLOW
},
748 {"ldexp", 1, 1e9
, ERANGE
, _OVERFLOW
},
750 double (CDECL
*p_funcd
)(double);
751 double (CDECL
*p_func2d
)(double, double);
752 double (CDECL
*p_func3d
)(double, double, double);
753 double (CDECL
*p_funcdl
)(double, long);
758 __setusermatherr(matherr_callback
);
759 module
= GetModuleHandleW(L
"ucrtbase.dll");
761 /* necessary so that exp(1e100)==INFINITY on glibc, we can remove this if we change our implementation */
762 fesetround(FE_TONEAREST
);
764 for(i
= 0; i
< ARRAY_SIZE(testsd
); i
++) {
765 p_funcd
= (void*)GetProcAddress(module
, testsd
[i
].func
);
768 p_funcd(testsd
[i
].x
);
769 ok(errno
== testsd
[i
].error
,
770 "%s(%f) got errno %d\n", testsd
[i
].func
, testsd
[i
].x
, errno
);
771 ok(exception
.type
== testsd
[i
].exception
,
772 "%s(%f) got exception type %d\n", testsd
[i
].func
, testsd
[i
].x
, exception
.type
);
773 if(exception
.type
== -1) continue;
774 ok(exception
.arg1
== testsd
[i
].x
,
775 "%s(%f) got exception arg1 %f\n", testsd
[i
].func
, testsd
[i
].x
, exception
.arg1
);
778 for(i
= 0; i
< ARRAY_SIZE(tests2d
); i
++) {
779 p_func2d
= (void*)GetProcAddress(module
, tests2d
[i
].func
);
782 p_func2d(tests2d
[i
].a
, tests2d
[i
].b
);
783 ok(errno
== tests2d
[i
].error
,
784 "%s(%f, %f) got errno %d\n", tests2d
[i
].func
, tests2d
[i
].a
, tests2d
[i
].b
, errno
);
785 ok(exception
.type
== tests2d
[i
].exception
,
786 "%s(%f, %f) got exception type %d\n", tests2d
[i
].func
, tests2d
[i
].a
, tests2d
[i
].b
, exception
.type
);
787 if(exception
.type
== -1) continue;
788 ok(exception
.arg1
== tests2d
[i
].a
,
789 "%s(%f, %f) got exception arg1 %f\n", tests2d
[i
].func
, tests2d
[i
].a
, tests2d
[i
].b
, exception
.arg1
);
790 ok(exception
.arg2
== tests2d
[i
].b
,
791 "%s(%f, %f) got exception arg2 %f\n", tests2d
[i
].func
, tests2d
[i
].a
, tests2d
[i
].b
, exception
.arg2
);
794 for(i
= 0; i
< ARRAY_SIZE(tests3d
); i
++) {
795 p_func3d
= (void*)GetProcAddress(module
, tests3d
[i
].func
);
798 p_func3d(tests3d
[i
].a
, tests3d
[i
].b
, tests3d
[i
].c
);
799 ok(errno
== tests3d
[i
].error
,
800 "%s(%f, %f, %f) got errno %d\n", tests3d
[i
].func
, tests3d
[i
].a
, tests3d
[i
].b
, tests3d
[i
].c
, errno
);
801 ok(exception
.type
== tests3d
[i
].exception
,
802 "%s(%f, %f, %f) got exception type %d\n", tests3d
[i
].func
, tests3d
[i
].a
, tests3d
[i
].b
, tests3d
[i
].c
, exception
.type
);
803 if(exception
.type
== -1) continue;
804 ok(exception
.arg1
== tests3d
[i
].a
,
805 "%s(%f, %f, %f) got exception arg1 %f\n", tests3d
[i
].func
, tests3d
[i
].a
, tests3d
[i
].b
, tests3d
[i
].c
, exception
.arg1
);
806 ok(exception
.arg2
== tests3d
[i
].b
,
807 "%s(%f, %f, %f) got exception arg2 %f\n", tests3d
[i
].func
, tests3d
[i
].a
, tests3d
[i
].b
, tests3d
[i
].c
, exception
.arg2
);
810 for(i
= 0; i
< ARRAY_SIZE(testsdl
); i
++) {
811 p_funcdl
= (void*)GetProcAddress(module
, testsdl
[i
].func
);
814 p_funcdl(testsdl
[i
].a
, testsdl
[i
].b
);
815 ok(errno
== testsdl
[i
].error
,
816 "%s(%f, %ld) got errno %d\n", testsdl
[i
].func
, testsdl
[i
].a
, testsdl
[i
].b
, errno
);
817 ok(exception
.type
== testsdl
[i
].exception
,
818 "%s(%f, %ld) got exception type %d\n", testsdl
[i
].func
, testsdl
[i
].a
, testsdl
[i
].b
, exception
.type
);
819 if(exception
.type
== -1) continue;
820 ok(exception
.arg1
== testsdl
[i
].a
,
821 "%s(%f, %ld) got exception arg1 %f\n", testsdl
[i
].func
, testsdl
[i
].a
, testsdl
[i
].b
, exception
.arg1
);
822 ok(exception
.arg2
== testsdl
[i
].b
,
823 "%s(%f, %ld) got exception arg2 %f\n", testsdl
[i
].func
, testsdl
[i
].a
, testsdl
[i
].b
, exception
.arg2
);
827 ok(d
== -1.0, "failed to change log10 return value: %e\n", d
);
830 static void test_asctime(void)
832 const struct tm epoch
= { 0, 0, 0, 1, 0, 70, 4, 0, 0 };
835 ret
= asctime(&epoch
);
836 ok(!strcmp(ret
, "Thu Jan 1 00:00:00 1970\n"), "asctime returned %s\n", ret
);
839 static void test_strftime(void)
848 {"%C", "", { 0, 0, 0, 1, 0, -2000, 4, 0, 0 }},
849 {"%C", "", { 0, 0, 0, 1, 0, -1901, 4, 0, 0 }},
850 {"%C", "00", { 0, 0, 0, 1, 0, -1900, 4, 0, 0 }},
851 {"%C", "18", { 0, 0, 0, 1, 0, -1, 4, 0, 0 }},
852 {"%C", "19", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
853 {"%C", "99", { 0, 0, 0, 1, 0, 8099, 4, 0, 0 }},
854 {"%C", "", { 0, 0, 0, 1, 0, 8100, 4, 0, 0 }},
855 {"%d", "", { 0, 0, 0, 0, 0, 70, 4, 0, 0 }},
856 {"%d", "01", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
857 {"%d", "31", { 0, 0, 0, 31, 0, 70, 4, 0, 0 }},
858 {"%d", "", { 0, 0, 0, 32, 0, 70, 4, 0, 0 }},
859 {"%D", "", { 0, 0, 0, 1, 0, -1901, 4, 0, 0 }},
860 {"%D", "01/01/00", { 0, 0, 0, 1, 0, -1900, 4, 0, 0 }},
861 {"%D", "01/01/99", { 0, 0, 0, 1, 0, -1, 4, 0, 0 }},
862 {"%D", "01/01/70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
863 {"%D", "01/01/99", { 0, 0, 0, 1, 0, 8099, 4, 0, 0 }},
864 {"%D", "", { 0, 0, 0, 1, 0, 8100, 4, 0, 0 }},
865 {"%#D", "1/1/70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
866 {"%e", "", { 0, 0, 0, 0, 0, 70, 4, 0, 0 }},
867 {"%e", " 1", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
868 {"%e", "31", { 0, 0, 0, 31, 0, 70, 4, 0, 0 }},
869 {"%e", "", { 0, 0, 0, 32, 0, 70, 4, 0, 0 }},
870 {"%#e", "1", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
871 {"%F", "1970-01-01", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
872 {"%#F", "1970-1-1", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
873 {"%R", "00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
874 {"%#R", "0:0", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
875 {"%T", "00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
876 {"%#T", "0:0:0", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
877 {"%u", "", { 0, 0, 0, 1, 0, 117, -1, 0, 0 }},
878 {"%u", "7", { 0, 0, 0, 1, 0, 117, 0, 0, 0 }},
879 {"%u", "1", { 0, 0, 0, 1, 0, 117, 1, 0, 0 }},
880 {"%u", "6", { 0, 0, 0, 1, 0, 117, 6, 0, 0 }},
881 {"%u", "", { 0, 0, 0, 1, 0, 117, 7, 0, 0 }},
882 {"%h", "Jan", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
883 {"%I", "", { 0, 0, -1, 1, 0, 70, 4, 0, 0 }},
884 {"%I", "12", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
885 {"%I", "01", { 0, 0, 1, 1, 0, 70, 4, 0, 0 }},
886 {"%I", "11", { 0, 0, 11, 1, 0, 70, 4, 0, 0 }},
887 {"%I", "12", { 0, 0, 12, 1, 0, 70, 4, 0, 0 }},
888 {"%I", "01", { 0, 0, 13, 1, 0, 70, 4, 0, 0 }},
889 {"%I", "11", { 0, 0, 23, 1, 0, 70, 4, 0, 0 }},
890 {"%I", "", { 0, 0, 24, 1, 0, 70, 4, 0, 0 }},
891 {"%n", "\n", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
892 {"%r", "12:00:00 AM", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
893 {"%r", "02:00:00 PM", { 0, 0, 14, 1, 0, 121, 6, 0, 0 }},
894 {"%#r", "12:0:0 AM", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
895 {"%#r", "2:0:0 PM", { 0, 0, 14, 1, 0, 121, 6, 0, 0 }},
896 {"%t", "\t", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
897 {"%g", "", { 0, 0, 0, 1, 0, -1901, 4, 0, 0 }},
898 {"%g", "", { 0, 0, 0, 1, 0, -1901, 3, 364, 0 }},
899 {"%g", "00", { 0, 0, 0, 1, 0, -1900, 4, 0, 0 }},
900 {"%g", "70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
901 {"%g", "71", { 0, 0, 0, 2, 0, 72, 0, 1, 0 }},
902 {"%g", "72", { 0, 0, 0, 3, 0, 72, 1, 2, 0 }},
903 {"%g", "16", { 0, 0, 0, 1, 0, 117, 0, 0, 0 }},
904 {"%g", "99", { 0, 0, 0, 1, 0, 8099, 4, 0, 0 }},
905 {"%g", "00", { 0, 0, 0, 1, 0, 8099, 3, 364, 0 }},
906 {"%g", "", { 0, 0, 0, 1, 0, 8100, 0, 0, 0 }},
907 {"%g", "", { 0, 0, 0, 1, 0, 8100, 4, 0, 0 }},
908 {"%G", "1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
909 {"%G", "1971", { 0, 0, 0, 2, 0, 72, 0, 1, 0 }},
910 {"%G", "1972", { 0, 0, 0, 3, 0, 72, 1, 2, 0 }},
911 {"%G", "2016", { 0, 0, 0, 1, 0, 117, 0, 0, 0 }},
912 {"%V", "01", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
913 {"%V", "52", { 0, 0, 0, 1, 0, 117, 0, 0, 0 }},
914 {"%V", "53", { 0, 0, 14, 1, 0, 121, 6, 0, 0 }},
915 {"%y", "", { 0, 0, 0, 0, 0, -1901, 0, 0, 0 }},
916 {"%y", "00", { 0, 0, 0, 0, 0, -1900, 0, 0, 0 }},
917 {"%y", "99", { 0, 0, 0, 0, 0, 8099, 0, 0, 0 }},
918 {"%y", "", { 0, 0, 0, 0, 0, 8100, 0, 0, 0 }},
919 {"%c", "Thu Jan 1 00:00:00 1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
920 {"%c", "Thu Feb 30 00:00:00 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
921 {"%#c", "Thursday, January 01, 1970 00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
922 {"%#c", "Thursday, February 30, 1970 00:00:00", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
923 {"%x", "01/01/70", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
924 {"%x", "02/30/70", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
925 {"%#x", "Thursday, January 01, 1970", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
926 {"%#x", "Thursday, February 30, 1970", { 0, 0, 0, 30, 1, 70, 4, 0, 0 }},
927 {"%#x", "", { 0, 0, 0, 30, 1, 70, 7, 0, 0 }},
928 {"%#x", "", { 0, 0, 0, 30, 12, 70, 4, 0, 0 }},
929 {"%X", "00:00:00", { 0, 0, 0, 1, 0, 70, 4, 0, 0 }},
930 {"%X", "14:00:00", { 0, 0, 14, 1, 0, 70, 4, 0, 0 }},
931 {"%X", "23:59:60", { 60, 59, 23, 1, 0, 70, 4, 0, 0 }},
937 const wchar_t *short_date
;
943 { "%c", "x z", L
"x", L
"y", L
"z", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
944 { "%#c", "y z", L
"x", L
"y", L
"z", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
945 { "%X", "M1", 0, 0, L
"MMM", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
946 { "%X", "1", 0, 0, L
"h", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
947 { "%X", "01", 0, 0, L
"hh", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
948 { "%X", "h01", 0, 0, L
"hhh", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
949 { "%X", "hh01", 0, 0, L
"hhhh", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
950 { "%X", "1", 0, 0, L
"H", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
951 { "%X", "01", 0, 0, L
"HH", { 0, 0, 1, 1, 0, 70, 0, 0, 0 }},
952 { "%X", "H13", 0, 0, L
"HHH", { 0, 0, 13, 1, 0, 70, 0, 0, 0 }},
953 { "%X", "0", 0, 0, L
"m", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
954 { "%X", "00", 0, 0, L
"mm", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
955 { "%X", "m00", 0, 0, L
"mmm", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
956 { "%X", "0", 0, 0, L
"s", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
957 { "%X", "00", 0, 0, L
"ss", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
958 { "%X", "s00", 0, 0, L
"sss", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
959 { "%X", "T", 0, 0, L
"t", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
960 { "%X", "TAM", 0, 0, L
"tt", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
961 { "%X", "TAM", 0, 0, L
"ttttttttt", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
962 { "%X", "TAM", 0, 0, L
"a", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
963 { "%X", "TAM", 0, 0, L
"aaaaa", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
964 { "%X", "TAM", 0, 0, L
"A", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
965 { "%X", "TAM", 0, 0, L
"AAAAA", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
966 { "%x", "1", L
"d", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
967 { "%x", "01", L
"dd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
968 { "%x", "D1", L
"ddd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
969 { "%x", "Day1", L
"dddd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
970 { "%x", "dDay1", L
"ddddd", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
971 { "%x", "1", L
"M", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
972 { "%x", "01", L
"MM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
973 { "%x", "M1", L
"MMM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
974 { "%x", "Mon1", L
"MMMM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
975 { "%x", "MMon1", L
"MMMMM", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
976 { "%x", "y", L
"y", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
977 { "%x", "70", L
"yy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
978 { "%x", "y70", L
"yyy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
979 { "%x", "1970", L
"yyyy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
980 { "%x", "y1970", L
"yyyyy", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
981 { "%x", "ggggggggggg", L
"ggggggggggg", 0, 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
982 { "%#x", "1", 0, L
"d", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
983 { "%#x", "01", 0, L
"dd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
984 { "%#x", "D1", 0, L
"ddd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
985 { "%#x", "Day1", 0, L
"dddd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
986 { "%#x", "dDay1", 0, L
"ddddd", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
987 { "%#x", "1", 0, L
"M", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
988 { "%#x", "01", 0, L
"MM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
989 { "%#x", "M1", 0, L
"MMM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
990 { "%#x", "Mon1", 0, L
"MMMM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
991 { "%#x", "MMon1", 0, L
"MMMMM", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
992 { "%#x", "y", 0, L
"y", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
993 { "%#x", "70", 0, L
"yy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
994 { "%#x", "y70", 0, L
"yyy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
995 { "%#x", "1970", 0, L
"yyyy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
996 { "%#x", "y1970", 0, L
"yyyyy", 0, { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
997 { "%r", "z", L
"x", L
"y", L
"z", { 0, 0, 0, 1, 0, 70, 0, 0, 0 }},
1005 { 100, 0, { "99 52", "00 01", "00 01", "00 01", "00 01", "99 53", "99 52" }},
1006 { 100, 1, { "99 52", "00 01", "00 01", "00 01", "00 01", "00 01", "99 53" }},
1007 { 100, 2, { "99 53", "00 01", "00 01", "00 01", "00 01", "00 01", "00 01" }},
1008 { 100, 3, { "00 01", "00 01", "00 01", "00 01", "00 01", "00 01", "00 01" }},
1009 { 100, 4, { "00 01", "00 02", "00 01", "00 01", "00 01", "00 01", "00 01" }},
1010 { 100, 5, { "00 01", "00 02", "00 02", "00 01", "00 01", "00 01", "00 01" }},
1011 { 100, 6, { "00 01", "00 02", "00 02", "00 02", "00 01", "00 01", "00 01" }},
1012 { 100, 358, { "00 51", "00 52", "00 52", "00 52", "00 52", "00 52", "00 51" }},
1013 { 100, 359, { "00 51", "00 52", "00 52", "00 52", "00 52", "00 52", "00 52" }},
1014 { 100, 360, { "00 52", "00 52", "00 52", "00 52", "00 52", "00 52", "00 52" }},
1015 { 100, 361, { "00 52", "00 53", "00 52", "00 52", "00 52", "00 52", "00 52" }},
1016 { 100, 362, { "00 52", "00 53", "00 53", "00 52", "00 52", "00 52", "00 52" }},
1017 { 100, 363, { "00 52", "01 01", "00 53", "00 53", "00 52", "00 52", "00 52" }},
1018 { 100, 364, { "00 52", "01 01", "01 01", "00 53", "00 53", "00 52", "00 52" }},
1019 { 100, 365, { "00 52", "01 01", "01 01", "01 01", "00 53", "00 53", "00 52" }},
1020 { 101, 0, { "00 52", "01 01", "01 01", "01 01", "01 01", "00 53", "00 53" }},
1021 { 101, 1, { "00 53", "01 01", "01 01", "01 01", "01 01", "01 01", "00 53" }},
1022 { 101, 2, { "00 53", "01 01", "01 01", "01 01", "01 01", "01 01", "01 01" }},
1023 { 101, 3, { "01 01", "01 01", "01 01", "01 01", "01 01", "01 01", "01 01" }},
1024 { 101, 4, { "01 01", "01 02", "01 01", "01 01", "01 01", "01 01", "01 01" }},
1025 { 101, 5, { "01 01", "01 02", "01 02", "01 01", "01 01", "01 01", "01 01" }},
1026 { 101, 6, { "01 01", "01 02", "01 02", "01 02", "01 01", "01 01", "01 01" }},
1027 { 101, 358, { "01 51", "01 52", "01 52", "01 52", "01 52", "01 52", "01 51" }},
1028 { 101, 359, { "01 51", "01 52", "01 52", "01 52", "01 52", "01 52", "01 52" }},
1029 { 101, 360, { "01 52", "01 52", "01 52", "01 52", "01 52", "01 52", "01 52" }},
1030 { 101, 361, { "01 52", "01 53", "01 52", "01 52", "01 52", "01 52", "01 52" }},
1031 { 101, 362, { "01 52", "02 01", "01 53", "01 52", "01 52", "01 52", "01 52" }},
1032 { 101, 363, { "01 52", "02 01", "02 01", "01 53", "01 52", "01 52", "01 52" }},
1033 { 101, 364, { "01 52", "02 01", "02 01", "02 01", "01 53", "01 52", "01 52" }},
1036 __lc_time_data time_data
= {
1037 { "d1", "d2", "d3", "d4", "d5", "d6", "d7" },
1038 { "day1", "day2", "day3", "day4", "day5", "day6", "day7" },
1039 { "m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9", "m10", "m11", "m12" },
1040 { "mon1", "mon2", "mon3", "mon4", "mon5", "mon6", "mon7", "mon8", "mon9", "mon10", "mon11", "mon12" },
1041 "tam", "tpm", 0, 0, 0, 1, 0,
1042 { L
"D1", L
"D2", L
"D3", L
"D4", L
"D5", L
"D6", L
"D7" },
1043 { L
"Day1", L
"Day2", L
"Day3", L
"Day4", L
"Day5", L
"Day6", L
"Day7" },
1044 { L
"M1", L
"M2", L
"M3", L
"M4", L
"M5", L
"M6", L
"M7", L
"M8", L
"M9", L
"M10", L
"M11", L
"M12" },
1045 { L
"Mon1", L
"Mon2", L
"Mon3", L
"Mon4", L
"Mon5", L
"Mon6", L
"Mon7", L
"Mon8", L
"Mon9", L
"Mon10", L
"Mon11", L
"Mon12" },
1049 const struct tm epoch
= { 0, 0, 0, 1, 0, 70, 4, 0, 0 };
1050 struct tm tm_yweek
= { 0, 0, 0, 1, 0, 70, 0, 0, 0 };
1054 for (i
=0; i
<ARRAY_SIZE(tests
); i
++)
1056 todo_wine_if(tests
[i
].todo_handler
) {
1057 if (!tests
[i
].ret
[0])
1058 SET_EXPECT(global_invalid_parameter_handler
);
1059 ret
= strftime(buf
, sizeof(buf
), tests
[i
].format
, &tests
[i
].tm
);
1060 if (!tests
[i
].ret
[0])
1061 CHECK_CALLED(global_invalid_parameter_handler
);
1064 todo_wine_if(tests
[i
].todo_value
) {
1065 ok(ret
== strlen(tests
[i
].ret
), "%d) ret = %d\n", i
, ret
);
1066 ok(!strcmp(buf
, tests
[i
].ret
), "%d) buf = \"%s\", expected \"%s\"\n",
1067 i
, buf
, tests
[i
].ret
);
1071 ret
= strftime(buf
, sizeof(buf
), "%z", &epoch
);
1072 ok(ret
== 5, "expected 5, got %d\n", ret
);
1073 ok((buf
[0] == '+' || buf
[0] == '-') &&
1074 isdigit(buf
[1]) && isdigit(buf
[2]) &&
1075 isdigit(buf
[3]) && isdigit(buf
[4]), "got %s\n", buf
);
1077 for (i
=0; i
<ARRAY_SIZE(tests_td
); i
++)
1079 time_data
.short_dateW
= tests_td
[i
].short_date
;
1080 time_data
.dateW
= tests_td
[i
].date
;
1081 time_data
.timeW
= tests_td
[i
].time
;
1082 ret
= _Strftime(buf
, sizeof(buf
), tests_td
[i
].format
, &tests_td
[i
].tm
, &time_data
);
1083 ok(ret
== strlen(buf
), "%d) ret = %d\n", i
, ret
);
1084 todo_wine_if(tests_td
[i
].todo
) {
1085 ok(!strcmp(buf
, tests_td
[i
].ret
), "%d) buf = \"%s\", expected \"%s\"\n",
1086 i
, buf
, tests_td
[i
].ret
);
1090 for (i
=0; i
<ARRAY_SIZE(tests_yweek
); i
++)
1093 tm_yweek
.tm_year
= tests_yweek
[i
].year
;
1094 tm_yweek
.tm_yday
= tests_yweek
[i
].yday
;
1097 tm_yweek
.tm_wday
= j
;
1098 strftime(buf
, sizeof(buf
), "%g %V", &tm_yweek
);
1099 ok(!strcmp(buf
, tests_yweek
[i
].ret
[j
]), "%d,%d) buf = \"%s\", expected \"%s\"\n",
1100 i
, j
, buf
, tests_yweek
[i
].ret
[j
]);
1104 if(!setlocale(LC_ALL
, "fr-FR")) {
1105 win_skip("fr-FR locale not available\n");
1108 ret
= strftime(buf
, sizeof(buf
), "%c", &epoch
);
1109 ok(ret
== 19, "ret = %d\n", ret
);
1110 ok(!strcmp(buf
, "01/01/1970 00:00:00"), "buf = \"%s\", expected \"%s\"\n", buf
, "01/01/1970 00:00:00");
1111 ret
= strftime(buf
, sizeof(buf
), "%r", &epoch
);
1112 ok(ret
== 8, "ret = %d\n", ret
);
1113 ok(!strcmp(buf
, "00:00:00"), "buf = \"%s\", expected \"%s\"\n", buf
, "00:00:00");
1114 setlocale(LC_ALL
, "C");
1116 if(!setlocale(LC_TIME
, "Japanese_Japan.932")) {
1117 win_skip("Japanese_Japan.932 locale not available\n");
1120 ret
= strftime(buf
, sizeof(buf
), "%a", &epoch
);
1121 ok(ret
== 2 || broken(ret
== 1), "ret = %d\n", ret
);
1122 ok(!strcmp(buf
, "\x96\xd8"), "buf = %s, expected \"\\x96\\xd8\"\n", wine_dbgstr_an(buf
, 2));
1123 setlocale(LC_ALL
, "C");
1126 static LONG
* get_failures_counter(HANDLE
*map
)
1128 *map
= CreateFileMappingA(INVALID_HANDLE_VALUE
, NULL
, PAGE_READWRITE
,
1129 0, sizeof(LONG
), "winetest_failures_counter");
1130 return MapViewOfFile(*map
, FILE_MAP_ALL_ACCESS
, 0, 0, sizeof(LONG
));
1133 static void free_failures_counter(LONG
*mem
, HANDLE map
)
1135 UnmapViewOfFile(mem
);
1139 static void set_failures_counter(LONG add
)
1141 HANDLE failures_map
;
1144 failures
= get_failures_counter(&failures_map
);
1146 free_failures_counter(failures
, failures_map
);
1149 static void test_exit(const char *argv0
)
1151 PROCESS_INFORMATION proc
;
1152 STARTUPINFOA startup
= {0};
1153 char path
[MAX_PATH
];
1154 HANDLE failures_map
, exit_event
, quick_exit_event
;
1158 exit_event
= CreateEventA(NULL
, FALSE
, FALSE
, "exit_event");
1159 quick_exit_event
= CreateEventA(NULL
, FALSE
, FALSE
, "quick_exit_event");
1161 failures
= get_failures_counter(&failures_map
);
1162 sprintf(path
, "%s misc exit", argv0
);
1163 startup
.cb
= sizeof(startup
);
1164 CreateProcessA(NULL
, path
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &proc
);
1165 ret
= WaitForSingleObject(proc
.hProcess
, INFINITE
);
1166 ok(ret
== WAIT_OBJECT_0
, "child process wait failed\n");
1167 GetExitCodeProcess(proc
.hProcess
, &ret
);
1168 ok(ret
== 1, "child process exited with code %d\n", ret
);
1169 CloseHandle(proc
.hProcess
);
1170 CloseHandle(proc
.hThread
);
1171 ok(!*failures
, "%d tests failed in child process\n", *failures
);
1172 free_failures_counter(failures
, failures_map
);
1175 ret
= WaitForSingleObject(exit_event
, 0);
1176 ok(ret
== WAIT_OBJECT_0
, "exit_event was not set (%x)\n", ret
);
1177 ret
= WaitForSingleObject(quick_exit_event
, 0);
1178 ok(ret
== WAIT_TIMEOUT
, "quick_exit_event should not have be set (%x)\n", ret
);
1180 CloseHandle(exit_event
);
1181 CloseHandle(quick_exit_event
);
1184 static int atexit_called
;
1186 static void CDECL
at_exit_func1(void)
1188 HANDLE exit_event
= CreateEventA(NULL
, FALSE
, FALSE
, "exit_event");
1190 ok(exit_event
!= NULL
, "CreateEvent failed: %d\n", GetLastError());
1191 ok(atexit_called
== 1, "atexit_called = %d\n", atexit_called
);
1193 SetEvent(exit_event
);
1194 CloseHandle(exit_event
);
1195 set_failures_counter(winetest_get_failures());
1198 static void CDECL
at_exit_func2(void)
1200 ok(!atexit_called
, "atexit_called = %d\n", atexit_called
);
1202 set_failures_counter(winetest_get_failures());
1205 static int atquick_exit_called
;
1207 static void CDECL
at_quick_exit_func1(void)
1209 HANDLE quick_exit_event
= CreateEventA(NULL
, FALSE
, FALSE
, "quick_exit_event");
1211 ok(quick_exit_event
!= NULL
, "CreateEvent failed: %d\n", GetLastError());
1212 ok(atquick_exit_called
== 1, "atquick_exit_called = %d\n", atquick_exit_called
);
1213 atquick_exit_called
++;
1214 SetEvent(quick_exit_event
);
1215 CloseHandle(quick_exit_event
);
1216 set_failures_counter(winetest_get_failures());
1219 static void CDECL
at_quick_exit_func2(void)
1221 ok(!atquick_exit_called
, "atquick_exit_called = %d\n", atquick_exit_called
);
1222 atquick_exit_called
++;
1223 set_failures_counter(winetest_get_failures());
1226 static void test_call_exit(void)
1228 ok(!_crt_atexit(at_exit_func1
), "_crt_atexit failed\n");
1229 ok(!_crt_atexit(at_exit_func2
), "_crt_atexit failed\n");
1231 ok(!_crt_at_quick_exit(at_quick_exit_func1
), "_crt_at_quick_exit failed\n");
1232 ok(!_crt_at_quick_exit(at_quick_exit_func2
), "_crt_at_quick_exit failed\n");
1234 set_failures_counter(winetest_get_failures());
1238 static void test_call_quick_exit(void)
1240 ok(!_crt_atexit(at_exit_func1
), "_crt_atexit failed\n");
1241 ok(!_crt_atexit(at_exit_func2
), "_crt_atexit failed\n");
1243 ok(!_crt_at_quick_exit(at_quick_exit_func1
), "_crt_at_quick_exit failed\n");
1244 ok(!_crt_at_quick_exit(at_quick_exit_func2
), "_crt_at_quick_exit failed\n");
1246 set_failures_counter(winetest_get_failures());
1250 static void test_quick_exit(const char *argv0
)
1252 PROCESS_INFORMATION proc
;
1253 STARTUPINFOA startup
= {0};
1254 char path
[MAX_PATH
];
1255 HANDLE failures_map
, exit_event
, quick_exit_event
;
1259 exit_event
= CreateEventA(NULL
, FALSE
, FALSE
, "exit_event");
1260 quick_exit_event
= CreateEventA(NULL
, FALSE
, FALSE
, "quick_exit_event");
1262 failures
= get_failures_counter(&failures_map
);
1263 sprintf(path
, "%s misc quick_exit", argv0
);
1264 startup
.cb
= sizeof(startup
);
1265 CreateProcessA(NULL
, path
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startup
, &proc
);
1266 ret
= WaitForSingleObject(proc
.hProcess
, INFINITE
);
1267 ok(ret
== WAIT_OBJECT_0
, "child process wait failed\n");
1268 GetExitCodeProcess(proc
.hProcess
, &ret
);
1269 ok(ret
== 2, "child process exited with code %d\n", ret
);
1270 CloseHandle(proc
.hProcess
);
1271 CloseHandle(proc
.hThread
);
1272 ok(!*failures
, "%d tests failed in child process\n", *failures
);
1273 free_failures_counter(failures
, failures_map
);
1275 ret
= WaitForSingleObject(quick_exit_event
, 0);
1276 ok(ret
== WAIT_OBJECT_0
, "quick_exit_event was not set (%x)\n", ret
);
1277 ret
= WaitForSingleObject(exit_event
, 0);
1278 ok(ret
== WAIT_TIMEOUT
, "exit_event should not have be set (%x)\n", ret
);
1280 CloseHandle(exit_event
);
1281 CloseHandle(quick_exit_event
);
1284 static void test__stat32(void)
1286 static const char test_file
[] = "\\stat_file.tst";
1287 static const char test_dir
[] = "\\stat_dir.tst";
1289 char path
[2*MAX_PATH
];
1294 len
= GetTempPathA(MAX_PATH
, path
);
1295 ok(len
, "GetTempPathA failed\n");
1297 ret
= _stat32("c:", &buf
);
1298 ok(ret
== -1, "_stat32('c:') returned %d\n", ret
);
1299 ret
= _stat32("c:\\", &buf
);
1300 ok(!ret
, "_stat32('c:\\') returned %d\n", ret
);
1302 memcpy(path
+len
, test_file
, sizeof(test_file
));
1303 if((fd
= open(path
, O_WRONLY
| O_CREAT
| O_BINARY
, _S_IREAD
|_S_IWRITE
)) >= 0)
1305 ret
= _stat32(path
, &buf
);
1306 ok(!ret
, "_stat32('%s') returned %d\n", path
, ret
);
1308 ret
= _stat32(path
, &buf
);
1309 todo_wine
ok(ret
, "_stat32('%s') returned %d\n", path
, ret
);
1314 memcpy(path
+len
, test_dir
, sizeof(test_dir
));
1317 ret
= _stat32(path
, &buf
);
1318 ok(!ret
, "_stat32('%s') returned %d\n", path
, ret
);
1320 ret
= _stat32(path
, &buf
);
1321 ok(!ret
, "_stat32('%s') returned %d\n", path
, ret
);
1326 static void test__o_malloc(void)
1332 ok(m
!= NULL
, "p__o_malloc(1) returned NULL\n");
1335 ok(s
== 1, "_msize returned %d\n", (int)s
);
1340 static void test_clock(void)
1342 static const int thresh
= 100, max_load_delay
= 1000;
1346 GetSystemTimeAsFileTime(&cur
);
1349 expect_min
= (((LONGLONG
)cur
.dwHighDateTime
<< 32) + cur
.dwLowDateTime
- crt_init_end
) / 10000;
1350 ok(c
>= expect_min
- thresh
&& c
< expect_min
+ max_load_delay
, "clock() = %d, expected range [%d, %d]\n",
1351 c
, expect_min
- thresh
, expect_min
+ max_load_delay
);
1354 static void __cdecl
se_translator(unsigned int u
, EXCEPTION_POINTERS
*ep
)
1358 static void test_thread_storage(void)
1360 void **current_exception
;
1361 void *processing_throw
;
1363 _set_se_translator(se_translator
);
1364 current_exception
= __current_exception();
1365 processing_throw
= __processing_throw();
1367 ok(current_exception
+2 == processing_throw
,
1368 "current_exception = %p, processing_throw = %p\n",
1369 current_exception
, processing_throw
);
1370 ok(current_exception
[-2] == se_translator
,
1371 "can't find se_translator in thread storage\n");
1380 GetSystemTimeAsFileTime(&cur
);
1381 crt_init_end
= ((LONGLONG
)cur
.dwHighDateTime
<< 32) + cur
.dwLowDateTime
;
1383 arg_c
= winetest_get_mainargs(&arg_v
);
1385 if(!strcmp(arg_v
[2], "cmd"))
1386 test__get_narrow_winmain_command_line(NULL
);
1387 else if(!strcmp(arg_v
[2], "exit"))
1389 else if(!strcmp(arg_v
[2], "quick_exit"))
1390 test_call_quick_exit();
1394 test_invalid_parameter_handler();
1395 test__initialize_onexit_table();
1396 test__register_onexit_function();
1397 test__execute_onexit_table();
1398 test___fpe_flt_rounds();
1399 test__control87_2();
1400 test__get_narrow_winmain_command_line(arg_v
[0]);
1401 test__sopen_dispatch();
1408 test_exit(arg_v
[0]);
1409 test_quick_exit(arg_v
[0]);
1413 test_thread_storage();