msvcp140: Implement _Stat and _Lstat.
[wine.git] / dlls / msvcp140 / tests / msvcp140.c
blobdd2255dc8030592b218f3b21ae636f804d1f0217
1 /*
2 * Copyright 2016 Daniel Lehman
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
19 #include <stdio.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winnls.h"
25 #include "wine/test.h"
26 #include "winbase.h"
28 #define DEFINE_EXPECT(func) \
29 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
31 #define SET_EXPECT(func) \
32 do { \
33 expect_ ## func = TRUE; \
34 errno = 0xdeadbeef; \
35 }while(0)
37 #define CHECK_EXPECT2(func) \
38 do { \
39 ok(expect_ ##func, "unexpected call " #func "\n"); \
40 called_ ## func = TRUE; \
41 }while(0)
43 #define CHECK_EXPECT(func) \
44 do { \
45 CHECK_EXPECT2(func); \
46 expect_ ## func = FALSE; \
47 }while(0)
49 #define CHECK_CALLED(func) \
50 do { \
51 ok(called_ ## func, "expected " #func "\n"); \
52 expect_ ## func = called_ ## func = FALSE; \
53 }while(0)
55 #ifdef _WIN64
56 DEFINE_EXPECT(function_do_call);
57 DEFINE_EXPECT(function_do_clean);
58 #endif
60 #undef __thiscall
61 #ifdef __i386__
62 #define __thiscall __stdcall
63 #else
64 #define __thiscall __cdecl
65 #endif
67 /* Emulate a __thiscall */
68 #ifdef __i386__
70 #include "pshpack1.h"
71 struct thiscall_thunk
73 BYTE pop_eax; /* popl %eax (ret addr) */
74 BYTE pop_edx; /* popl %edx (func) */
75 BYTE pop_ecx; /* popl %ecx (this) */
76 BYTE push_eax; /* pushl %eax */
77 WORD jmp_edx; /* jmp *%edx */
79 #include "poppack.h"
81 static void * (WINAPI *call_thiscall_func1)( void *func, void *this );
82 static void * (WINAPI *call_thiscall_func2)( void *func, void *this, const void *a );
84 static void init_thiscall_thunk(void)
86 struct thiscall_thunk *thunk = VirtualAlloc( NULL, sizeof(*thunk),
87 MEM_COMMIT, PAGE_EXECUTE_READWRITE );
88 thunk->pop_eax = 0x58; /* popl %eax */
89 thunk->pop_edx = 0x5a; /* popl %edx */
90 thunk->pop_ecx = 0x59; /* popl %ecx */
91 thunk->push_eax = 0x50; /* pushl %eax */
92 thunk->jmp_edx = 0xe2ff; /* jmp *%edx */
93 call_thiscall_func1 = (void *)thunk;
94 call_thiscall_func2 = (void *)thunk;
97 #define call_func1(func,_this) call_thiscall_func1(func,_this)
98 #define call_func2(func,_this,a) call_thiscall_func2(func,_this,a)
100 #else
102 #define init_thiscall_thunk()
103 #define call_func1(func,_this) func(_this)
104 #define call_func2(func,_this,a) func(_this,a)
106 #endif /* __i386__ */
107 typedef unsigned char MSVCP_bool;
109 typedef struct {
110 void *unk0;
111 BYTE unk1;
112 } task_continuation_context;
114 typedef struct {
115 void *unused;
116 } _ContextCallback;
118 typedef struct {
119 const void *vtable;
120 void (__cdecl *func)(void);
121 int unk[4];
122 void *unk2[3];
123 void *this;
124 } function_void_cdecl_void;
126 typedef struct {
127 void *task;
128 MSVCP_bool scheduled;
129 MSVCP_bool started;
130 } _TaskEventLogger;
132 typedef struct {
133 PTP_WORK work;
134 void (__cdecl *callback)(void*);
135 void *arg;
136 } _Threadpool_chore;
138 enum file_type {
139 file_not_found = -1,
140 none_file,
141 regular_file,
142 directory_file,
143 symlink_file,
144 block_file,
145 character_file,
146 fifo_file,
147 socket_file,
148 status_unknown
151 static unsigned int (__cdecl *p__Thrd_id)(void);
152 static task_continuation_context* (__thiscall *p_task_continuation_context_ctor)(task_continuation_context*);
153 static void (__thiscall *p__ContextCallback__Assign)(_ContextCallback*, void*);
154 static void (__thiscall *p__ContextCallback__CallInContext)(const _ContextCallback*, function_void_cdecl_void, MSVCP_bool);
155 static void (__thiscall *p__ContextCallback__Capture)(_ContextCallback*);
156 static void (__thiscall *p__ContextCallback__Reset)(_ContextCallback*);
157 static MSVCP_bool (__cdecl *p__ContextCallback__IsCurrentOriginSTA)(_ContextCallback*);
158 static void (__thiscall *p__TaskEventLogger__LogCancelTask)(_TaskEventLogger*);
159 static void (__thiscall *p__TaskEventLogger__LogScheduleTask)(_TaskEventLogger*, MSVCP_bool);
160 static void (__thiscall *p__TaskEventLogger__LogTaskCompleted)(_TaskEventLogger*);
161 static void (__thiscall *p__TaskEventLogger__LogTaskExecutionCompleted)(_TaskEventLogger*);
162 static void (__thiscall *p__TaskEventLogger__LogWorkItemCompleted)(_TaskEventLogger*);
163 static void (__thiscall *p__TaskEventLogger__LogWorkItemStarted)(_TaskEventLogger*);
164 static int (__cdecl *p__Schedule_chore)(_Threadpool_chore*);
165 static int (__cdecl *p__Reschedule_chore)(const _Threadpool_chore*);
166 static void (__cdecl *p__Release_chore)(_Threadpool_chore*);
168 static MSVCP_bool (__cdecl *p_Current_get)(WCHAR *);
169 static MSVCP_bool (__cdecl *p_Current_set)(WCHAR const *);
170 static ULONGLONG (__cdecl *p_File_size)(WCHAR const *);
171 static enum file_type (__cdecl *p_Lstat)(WCHAR const *, int *);
172 static enum file_type (__cdecl *p_Stat)(WCHAR const *, int *);
173 static int (__cdecl *p_To_byte)(const WCHAR *src, char *dst);
174 static int (__cdecl *p_To_wide)(const char *src, WCHAR *dst);
176 static BOOLEAN (WINAPI *pCreateSymbolicLinkW)(const WCHAR *, const WCHAR *, DWORD);
178 static HMODULE msvcp;
179 #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y)
180 #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0)
181 static BOOL init(void)
183 HANDLE hdll;
185 msvcp = LoadLibraryA("msvcp140.dll");
186 if(!msvcp)
188 win_skip("msvcp140.dll not installed\n");
189 return FALSE;
192 SET(p__Thrd_id, "_Thrd_id");
193 SET(p__ContextCallback__IsCurrentOriginSTA, "?_IsCurrentOriginSTA@_ContextCallback@details@Concurrency@@CA_NXZ");
195 if(sizeof(void*) == 8) { /* 64-bit initialization */
196 SET(p_task_continuation_context_ctor, "??0task_continuation_context@Concurrency@@AEAA@XZ");
197 SET(p__ContextCallback__Assign, "?_Assign@_ContextCallback@details@Concurrency@@AEAAXPEAX@Z");
198 SET(p__ContextCallback__CallInContext, "?_CallInContext@_ContextCallback@details@Concurrency@@QEBAXV?$function@$$A6AXXZ@std@@_N@Z");
199 SET(p__ContextCallback__Capture, "?_Capture@_ContextCallback@details@Concurrency@@AEAAXXZ");
200 SET(p__ContextCallback__Reset, "?_Reset@_ContextCallback@details@Concurrency@@AEAAXXZ");
201 SET(p__TaskEventLogger__LogCancelTask, "?_LogCancelTask@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
202 SET(p__TaskEventLogger__LogScheduleTask, "?_LogScheduleTask@_TaskEventLogger@details@Concurrency@@QEAAX_N@Z");
203 SET(p__TaskEventLogger__LogTaskCompleted, "?_LogTaskCompleted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
204 SET(p__TaskEventLogger__LogTaskExecutionCompleted, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
205 SET(p__TaskEventLogger__LogWorkItemCompleted, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
206 SET(p__TaskEventLogger__LogWorkItemStarted, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QEAAXXZ");
207 SET(p__Schedule_chore, "?_Schedule_chore@details@Concurrency@@YAHPEAU_Threadpool_chore@12@@Z");
208 SET(p__Reschedule_chore, "?_Reschedule_chore@details@Concurrency@@YAHPEBU_Threadpool_chore@12@@Z");
209 SET(p__Release_chore, "?_Release_chore@details@Concurrency@@YAXPEAU_Threadpool_chore@12@@Z");
210 } else {
211 #ifdef __arm__
212 SET(p_task_continuation_context_ctor, "??0task_continuation_context@Concurrency@@AAA@XZ");
213 SET(p__ContextCallback__Assign, "?_Assign@_ContextCallback@details@Concurrency@@AAAXPAX@Z");
214 SET(p__ContextCallback__CallInContext, "?_CallInContext@_ContextCallback@details@Concurrency@@QBAXV?$function@$$A6AXXZ@std@@_N@Z");
215 SET(p__ContextCallback__Capture, "?_Capture@_ContextCallback@details@Concurrency@@AAAXXZ");
216 SET(p__ContextCallback__Reset, "?_Reset@_ContextCallback@details@Concurrency@@AAAXXZ");
217 SET(p__TaskEventLogger__LogCancelTask, "?_LogCancelTask@_TaskEventLogger@details@Concurrency@@QAAXXZ");
218 SET(p__TaskEventLogger__LogScheduleTask, "?_LogScheduleTask@_TaskEventLogger@details@Concurrency@@QAEX_N@Z");
219 SET(p__TaskEventLogger__LogTaskCompleted, "?_LogTaskCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
220 SET(p__TaskEventLogger__LogTaskExecutionCompleted, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
221 SET(p__TaskEventLogger__LogWorkItemCompleted, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
222 SET(p__TaskEventLogger__LogWorkItemStarted, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QAAXXZ");
223 #else
224 SET(p_task_continuation_context_ctor, "??0task_continuation_context@Concurrency@@AAE@XZ");
225 SET(p__ContextCallback__Assign, "?_Assign@_ContextCallback@details@Concurrency@@AAEXPAX@Z");
226 SET(p__ContextCallback__CallInContext, "?_CallInContext@_ContextCallback@details@Concurrency@@QBEXV?$function@$$A6AXXZ@std@@_N@Z");
227 SET(p__ContextCallback__Capture, "?_Capture@_ContextCallback@details@Concurrency@@AAEXXZ");
228 SET(p__ContextCallback__Reset, "?_Reset@_ContextCallback@details@Concurrency@@AAEXXZ");
229 SET(p__TaskEventLogger__LogCancelTask, "?_LogCancelTask@_TaskEventLogger@details@Concurrency@@QAEXXZ");
230 SET(p__TaskEventLogger__LogScheduleTask, "?_LogScheduleTask@_TaskEventLogger@details@Concurrency@@QAEX_N@Z");
231 SET(p__TaskEventLogger__LogTaskCompleted, "?_LogTaskCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
232 SET(p__TaskEventLogger__LogTaskExecutionCompleted, "?_LogTaskExecutionCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
233 SET(p__TaskEventLogger__LogWorkItemCompleted, "?_LogWorkItemCompleted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
234 SET(p__TaskEventLogger__LogWorkItemStarted, "?_LogWorkItemStarted@_TaskEventLogger@details@Concurrency@@QAEXXZ");
235 #endif
236 SET(p__Schedule_chore, "?_Schedule_chore@details@Concurrency@@YAHPAU_Threadpool_chore@12@@Z");
237 SET(p__Reschedule_chore, "?_Reschedule_chore@details@Concurrency@@YAHPBU_Threadpool_chore@12@@Z");
238 SET(p__Release_chore, "?_Release_chore@details@Concurrency@@YAXPAU_Threadpool_chore@12@@Z");
241 SET(p_Current_get, "_Current_get");
242 SET(p_Current_set, "_Current_set");
243 SET(p_File_size, "_File_size");
244 SET(p_Lstat, "_Lstat");
245 SET(p_Stat, "_Stat");
246 SET(p_To_byte, "_To_byte");
247 SET(p_To_wide, "_To_wide");
249 hdll = GetModuleHandleA("kernel32.dll");
250 pCreateSymbolicLinkW = (void*)GetProcAddress(hdll, "CreateSymbolicLinkW");
252 init_thiscall_thunk();
253 return TRUE;
256 static void test_thrd(void)
258 ok(p__Thrd_id() == GetCurrentThreadId(),
259 "expected same id, got _Thrd_id %u GetCurrentThreadId %u\n",
260 p__Thrd_id(), GetCurrentThreadId());
263 static struct {
264 int value[2];
265 const char* export_name;
266 } vbtable_size_exports_list[] = {
267 {{0x20, 0x20}, "??_8?$basic_iostream@DU?$char_traits@D@std@@@std@@7B?$basic_istream@DU?$char_traits@D@std@@@1@@"},
268 {{0x10, 0x10}, "??_8?$basic_iostream@DU?$char_traits@D@std@@@std@@7B?$basic_ostream@DU?$char_traits@D@std@@@1@@"},
269 {{0x20, 0x20}, "??_8?$basic_iostream@GU?$char_traits@G@std@@@std@@7B?$basic_istream@GU?$char_traits@G@std@@@1@@"},
270 {{0x10, 0x10}, "??_8?$basic_iostream@GU?$char_traits@G@std@@@std@@7B?$basic_ostream@GU?$char_traits@G@std@@@1@@"},
271 {{0x20, 0x20}, "??_8?$basic_iostream@_WU?$char_traits@_W@std@@@std@@7B?$basic_istream@_WU?$char_traits@_W@std@@@1@@"},
272 {{0x10, 0x10}, "??_8?$basic_iostream@_WU?$char_traits@_W@std@@@std@@7B?$basic_ostream@_WU?$char_traits@_W@std@@@1@@"},
273 {{0x18, 0x18}, "??_8?$basic_istream@DU?$char_traits@D@std@@@std@@7B@"},
274 {{0x18, 0x18}, "??_8?$basic_istream@GU?$char_traits@G@std@@@std@@7B@"},
275 {{0x18, 0x18}, "??_8?$basic_istream@_WU?$char_traits@_W@std@@@std@@7B@"},
276 {{ 0x8, 0x10}, "??_8?$basic_ostream@DU?$char_traits@D@std@@@std@@7B@"},
277 {{ 0x8, 0x10}, "??_8?$basic_ostream@GU?$char_traits@G@std@@@std@@7B@"},
278 {{ 0x8, 0x10}, "??_8?$basic_ostream@_WU?$char_traits@_W@std@@@std@@7B@"},
279 {{ 0x0, 0x0}, 0}
282 static void test_vbtable_size_exports(void)
284 int i;
285 const int *p_vbtable;
286 int arch_idx = (sizeof(void*) == 8);
288 for (i = 0; vbtable_size_exports_list[i].export_name; i++)
290 SET(p_vbtable, vbtable_size_exports_list[i].export_name);
292 ok(p_vbtable[0] == 0, "vbtable[0] wrong, got 0x%x\n", p_vbtable[0]);
293 ok(p_vbtable[1] == vbtable_size_exports_list[i].value[arch_idx],
294 "%d: %s[1] wrong, got 0x%x\n", i, vbtable_size_exports_list[i].export_name, p_vbtable[1]);
298 static void test_task_continuation_context(void)
300 task_continuation_context tcc;
302 memset(&tcc, 0xff, sizeof(tcc));
303 call_func1(p_task_continuation_context_ctor, &tcc);
304 ok(!tcc.unk0, "tcc.unk0 != NULL (%p)\n", tcc.unk0);
305 ok(!tcc.unk1, "tcc.unk1 != 0 (%x)\n", tcc.unk1);
308 #ifdef _WIN64
309 static void __cdecl function_do_call(void *this)
311 CHECK_EXPECT(function_do_call);
314 static void __cdecl function_do_clean(void *this, MSVCP_bool b)
316 CHECK_EXPECT(function_do_clean);
317 ok(b, "b == FALSE\n");
319 #endif
321 static void test__ContextCallback(void)
323 _ContextCallback cc = {0};
324 void *v = (void*)0xdeadbeef;
325 #ifdef _WIN64
326 void* function_vtbl[] = {
327 NULL,
328 NULL,
329 (void*)function_do_call,
330 NULL,
331 (void*)function_do_clean,
332 NULL
334 function_void_cdecl_void function = { function_vtbl, NULL, {0}, {NULL}, &function };
335 function_void_cdecl_void function2 = { NULL, NULL, {0}, {NULL}, &function };
336 #endif
338 call_func2(p__ContextCallback__Assign, &cc, v);
339 ok(!cc.unused, "cc.unused = %p\n", cc.unused);
340 call_func1(p__ContextCallback__Reset, &cc);
341 ok(!cc.unused, "cc.unused = %p\n", cc.unused);
342 call_func1(p__ContextCallback__Capture, &cc);
343 ok(!cc.unused, "cc.unused = %p\n", cc.unused);
344 ok(!p__ContextCallback__IsCurrentOriginSTA(&cc), "IsCurrentOriginSTA returned TRUE\n");
346 cc.unused = v;
347 call_func2(p__ContextCallback__Assign, &cc, NULL);
348 ok(cc.unused == v, "cc.unused = %p\n", cc.unused);
349 call_func1(p__ContextCallback__Reset, &cc);
350 ok(cc.unused == v, "cc.unused = %p\n", cc.unused);
351 call_func1(p__ContextCallback__Capture, &cc);
352 ok(cc.unused == v, "cc.unused = %p\n", cc.unused);
353 ok(!p__ContextCallback__IsCurrentOriginSTA(&cc), "IsCurrentOriginSTA returned TRUE\n");
354 ok(cc.unused == v, "cc.unused = %p\n", cc.unused);
356 #ifdef _WIN64
357 SET_EXPECT(function_do_call);
358 SET_EXPECT(function_do_clean);
359 p__ContextCallback__CallInContext(&cc, function, FALSE);
360 CHECK_CALLED(function_do_call);
361 CHECK_CALLED(function_do_clean);
363 SET_EXPECT(function_do_call);
364 SET_EXPECT(function_do_clean);
365 p__ContextCallback__CallInContext(&cc, function, TRUE);
366 CHECK_CALLED(function_do_call);
367 CHECK_CALLED(function_do_clean);
369 SET_EXPECT(function_do_call);
370 SET_EXPECT(function_do_clean);
371 p__ContextCallback__CallInContext(&cc, function2, FALSE);
372 CHECK_CALLED(function_do_call);
373 CHECK_CALLED(function_do_clean);
375 SET_EXPECT(function_do_call);
376 SET_EXPECT(function_do_clean);
377 p__ContextCallback__CallInContext(&cc, function2, TRUE);
378 CHECK_CALLED(function_do_call);
379 CHECK_CALLED(function_do_clean);
380 #endif
383 static void test__TaskEventLogger(void)
385 _TaskEventLogger logger;
386 memset(&logger, 0, sizeof(logger));
388 call_func1(p__TaskEventLogger__LogCancelTask, &logger);
389 ok(!logger.task, "logger.task = %p\n", logger.task);
390 ok(!logger.scheduled, "logger.scheduled = %x\n", logger.scheduled);
391 ok(!logger.started, "logger.started = %x\n", logger.started);
393 call_func2(p__TaskEventLogger__LogScheduleTask, &logger, FALSE);
394 ok(!logger.task, "logger.task = %p\n", logger.task);
395 ok(!logger.scheduled, "logger.scheduled = %x\n", logger.scheduled);
396 ok(!logger.started, "logger.started = %x\n", logger.started);
398 call_func1(p__TaskEventLogger__LogTaskCompleted, &logger);
399 ok(!logger.task, "logger.task = %p\n", logger.task);
400 ok(!logger.scheduled, "logger.scheduled = %x\n", logger.scheduled);
401 ok(!logger.started, "logger.started = %x\n", logger.started);
403 call_func1(p__TaskEventLogger__LogTaskExecutionCompleted, &logger);
404 ok(!logger.task, "logger.task = %p\n", logger.task);
405 ok(!logger.scheduled, "logger.scheduled = %x\n", logger.scheduled);
406 ok(!logger.started, "logger.started = %x\n", logger.started);
408 call_func1(p__TaskEventLogger__LogWorkItemCompleted, &logger);
409 ok(!logger.task, "logger.task = %p\n", logger.task);
410 ok(!logger.scheduled, "logger.scheduled = %x\n", logger.scheduled);
411 ok(!logger.started, "logger.started = %x\n", logger.started);
413 call_func1(p__TaskEventLogger__LogWorkItemStarted, &logger);
414 ok(!logger.task, "logger.task = %p\n", logger.task);
415 ok(!logger.scheduled, "logger.scheduled = %x\n", logger.scheduled);
416 ok(!logger.started, "logger.started = %x\n", logger.started);
418 logger.task = (void*)0xdeadbeef;
419 logger.scheduled = TRUE;
420 logger.started = TRUE;
422 call_func1(p__TaskEventLogger__LogCancelTask, &logger);
423 ok(logger.task == (void*)0xdeadbeef, "logger.task = %p\n", logger.task);
424 ok(logger.scheduled, "logger.scheduled = FALSE\n");
425 ok(logger.started, "logger.started = FALSE\n");
427 call_func2(p__TaskEventLogger__LogScheduleTask, &logger, FALSE);
428 ok(logger.task == (void*)0xdeadbeef, "logger.task = %p\n", logger.task);
429 ok(logger.scheduled, "logger.scheduled = FALSE\n");
430 ok(logger.started, "logger.started = FALSE\n");
432 call_func1(p__TaskEventLogger__LogTaskCompleted, &logger);
433 ok(logger.task == (void*)0xdeadbeef, "logger.task = %p\n", logger.task);
434 ok(logger.scheduled, "logger.scheduled = FALSE\n");
435 ok(logger.started, "logger.started = FALSE\n");
437 call_func1(p__TaskEventLogger__LogTaskExecutionCompleted, &logger);
438 ok(logger.task == (void*)0xdeadbeef, "logger.task = %p\n", logger.task);
439 ok(logger.scheduled, "logger.scheduled = FALSE\n");
440 ok(logger.started, "logger.started = FALSE\n");
442 call_func1(p__TaskEventLogger__LogWorkItemCompleted, &logger);
443 ok(logger.task == (void*)0xdeadbeef, "logger.task = %p\n", logger.task);
444 ok(logger.scheduled, "logger.scheduled = FALSE\n");
445 ok(logger.started, "logger.started = FALSE\n");
447 call_func1(p__TaskEventLogger__LogWorkItemStarted, &logger);
448 ok(logger.task == (void*)0xdeadbeef, "logger.task = %p\n", logger.task);
449 ok(logger.scheduled, "logger.scheduled = FALSE\n");
450 ok(logger.started, "logger.started = FALSE\n");
453 static void __cdecl chore_callback(void *arg)
455 HANDLE event = arg;
456 SetEvent(event);
459 static void test_chore(void)
461 HANDLE event = CreateEventW(NULL, FALSE, FALSE, NULL);
462 _Threadpool_chore chore, old_chore;
463 DWORD wait;
464 int ret;
466 memset(&chore, 0, sizeof(chore));
467 ret = p__Schedule_chore(&chore);
468 ok(!ret, "_Schedule_chore returned %d\n", ret);
469 ok(chore.work != NULL, "chore.work == NULL\n");
470 ok(!chore.callback, "chore.callback != NULL\n");
471 p__Release_chore(&chore);
473 chore.work = NULL;
474 chore.callback = chore_callback;
475 chore.arg = event;
476 ret = p__Schedule_chore(&chore);
477 ok(!ret, "_Schedule_chore returned %d\n", ret);
478 ok(chore.work != NULL, "chore.work == NULL\n");
479 ok(chore.callback == chore_callback, "chore.callback = %p, expected %p\n", chore.callback, chore_callback);
480 ok(chore.arg == event, "chore.arg = %p, expected %p\n", chore.arg, event);
481 wait = WaitForSingleObject(event, 500);
482 ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", wait);
484 old_chore = chore;
485 ret = p__Schedule_chore(&chore);
486 ok(!ret, "_Schedule_chore returned %d\n", ret);
487 ok(old_chore.work != chore.work, "new threadpool work was not created\n");
488 p__Release_chore(&old_chore);
489 wait = WaitForSingleObject(event, 500);
490 ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", wait);
492 ret = p__Reschedule_chore(&chore);
493 ok(!ret, "_Reschedule_chore returned %d\n", ret);
494 wait = WaitForSingleObject(event, 500);
495 ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %d\n", wait);
497 p__Release_chore(&chore);
498 ok(!chore.work, "chore.work != NULL\n");
499 ok(chore.callback == chore_callback, "chore.callback = %p, expected %p\n", chore.callback, chore_callback);
500 ok(chore.arg == event, "chore.arg = %p, expected %p\n", chore.arg, event);
501 p__Release_chore(&chore);
504 static void test_to_byte(void)
506 static const WCHAR test_1[] = {'T', 'E', 'S', 'T', 0};
507 static const WCHAR test_2[] = {0x9580, 0x9581, 0x9582, 0x9583, 0}; /* some CJK characters */
508 static const WCHAR *tests[] = {test_1, test_2};
510 char dst[MAX_PATH + 4] = "ABC\0XXXXXXX";
511 char compare[MAX_PATH + 4] = "ABC\0XXXXXXX";
512 int ret,expected;
513 unsigned int i, j;
514 WCHAR longstr[MAX_PATH + 3];
516 ret = p_To_byte(NULL, NULL);
517 ok(!ret, "Got unexpected result %d\n", ret);
518 ret = p_To_byte(tests[0], NULL);
519 ok(!ret, "Got unexpected result %d\n", ret);
520 ret = p_To_byte(NULL, dst);
521 ok(!ret, "Got unexpected result %d\n", ret);
523 ok(!memcmp(dst, compare, sizeof(compare)), "Destination was modified: %s\n", dst);
525 for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
527 ret = p_To_byte(tests[i], dst);
528 expected = WideCharToMultiByte(CP_ACP, 0, tests[i], -1, compare, sizeof(compare) / sizeof(*compare),
529 NULL, NULL);
530 ok(ret == expected, "Got unexpected result %d, expected %d, test case %u\n", ret, expected, i);
531 ok(!memcmp(dst, compare, sizeof(compare)), "Got unexpected output %s, test case %u\n", dst, i);
534 /* Output length is limited to MAX_PATH.*/
535 for (i = MAX_PATH - 2; i < MAX_PATH + 2; ++i)
537 for (j = 0; j < i; j++)
538 longstr[j] = 'A';
539 longstr[i] = 0;
540 memset(dst, 0xff, sizeof(dst));
541 memset(compare, 0xff, sizeof(compare));
543 ret = p_To_byte(longstr, dst);
544 expected = WideCharToMultiByte(CP_ACP, 0, longstr, -1, compare, MAX_PATH, NULL, NULL);
545 ok(ret == expected, "Got unexpected result %d, expected %d, length %u\n", ret, expected, i);
546 ok(!memcmp(dst, compare, sizeof(compare)), "Got unexpected output %s, length %u\n", dst, i);
550 static void test_to_wide(void)
552 /* öäü߀Ÿ.A.B in cp1252, the two . are an undefined value and delete.
553 * With a different system codepage it will produce different results, so do not hardcode the
554 * expected output but convert it with MultiByteToWideChar. */
555 static const char special_input[] = {0xf6, 0xe4, 0xfc, 0xdf, 0x80, 0x9f, 0x81, 0x41, 0x7f, 0x42, 0};
556 static const char *tests[] = {"Testtest", special_input};
557 WCHAR dst[MAX_PATH + 4] = {'A', 'B', 'C', 0, 'X', 'X', 'X', 'X', 'X', 'X', 'X'};
558 WCHAR compare[MAX_PATH + 4] = {'A', 'B', 'C', 0, 'X', 'X', 'X', 'X', 'X', 'X', 'X'};
559 int ret, expected;
560 unsigned int i;
561 char longstr[MAX_PATH + 3];
563 ret = p_To_wide(NULL, NULL);
564 ok(!ret, "Got unexpected result %d\n", ret);
565 ret = p_To_wide(tests[0], NULL);
566 ok(!ret, "Got unexpected result %d\n", ret);
567 ret = p_To_wide(NULL, dst);
568 ok(!ret, "Got unexpected result %d\n", ret);
569 ok(!memcmp(dst, compare, sizeof(compare)), "Destination was modified: %s\n", wine_dbgstr_w(dst));
571 for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
573 ret = p_To_wide(tests[i], dst);
574 expected = MultiByteToWideChar(CP_ACP, 0, tests[i], -1, compare, sizeof(compare) / sizeof(*compare));
575 ok(ret == expected, "Got unexpected result %d, expected %d, test case %u\n", ret, expected, i);
576 ok(!memcmp(dst, compare, sizeof(compare)), "Got unexpected output %s, test case %u\n",
577 wine_dbgstr_w(dst), i);
580 /* Output length is limited to MAX_PATH.*/
581 for (i = MAX_PATH - 2; i < MAX_PATH + 2; ++i)
583 memset(longstr, 'A', sizeof(longstr));
584 longstr[i] = 0;
585 memset(dst, 0xff, sizeof(dst));
586 memset(compare, 0xff, sizeof(compare));
588 ret = p_To_wide(longstr, dst);
589 expected = MultiByteToWideChar(CP_ACP, 0, longstr, -1, compare, MAX_PATH);
590 ok(ret == expected, "Got unexpected result %d, expected %d, length %u\n", ret, expected, i);
591 ok(!memcmp(dst, compare, sizeof(compare)), "Got unexpected output %s, length %u\n",
592 wine_dbgstr_w(dst), i);
596 static void test_File_size(void)
598 ULONGLONG val;
599 HANDLE file;
600 LARGE_INTEGER file_size;
601 WCHAR test_f1_W[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','1',0};
602 WCHAR test_f2_W[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','2',0};
603 WCHAR test_dir_W[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r',0};
604 WCHAR test_ne_W[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','n','e',0};
605 WCHAR temp_path[MAX_PATH], origin_path[MAX_PATH];
607 memset(origin_path, 0, sizeof(origin_path));
608 memset(origin_path, 0, sizeof(temp_path));
609 GetCurrentDirectoryW(MAX_PATH, origin_path);
610 GetTempPathW(MAX_PATH, temp_path);
611 ok(SetCurrentDirectoryW(temp_path), "SetCurrentDirectoryW to temp_path failed\n");
613 CreateDirectoryW(test_dir_W, NULL);
615 file = CreateFileW(test_f1_W, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
616 ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n");
617 file_size.QuadPart = 7;
618 ok(SetFilePointerEx(file, file_size, NULL, FILE_BEGIN), "SetFilePointerEx failed\n");
619 ok(SetEndOfFile(file), "SetEndOfFile failed\n");
620 CloseHandle(file);
621 val = p_File_size(test_f1_W);
622 ok(val == 7, "file_size is %s\n", wine_dbgstr_longlong(val));
624 file = CreateFileW(test_f2_W, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
625 ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n");
626 CloseHandle(file);
627 val = p_File_size(test_f2_W);
628 ok(val == 0, "file_size is %s\n", wine_dbgstr_longlong(val));
630 val = p_File_size(test_dir_W);
631 ok(val == 0, "file_size is %s\n", wine_dbgstr_longlong(val));
633 errno = 0xdeadbeef;
634 val = p_File_size(test_ne_W);
635 ok(val == ~(ULONGLONG)0, "file_size is %s\n", wine_dbgstr_longlong(val));
636 ok(errno == 0xdeadbeef, "errno = %d\n", errno);
638 errno = 0xdeadbeef;
639 val = p_File_size(NULL);
640 ok(val == ~(ULONGLONG)0, "file_size is %s\n", wine_dbgstr_longlong(val));
641 ok(errno == 0xdeadbeef, "errno = %d\n", errno);
643 ok(DeleteFileW(test_f1_W), "expect wine_test_dir/f1 to exist\n");
644 ok(DeleteFileW(test_f2_W), "expect wine_test_dir/f2 to exist\n");
645 ok(RemoveDirectoryW(test_dir_W), "expect wine_test_dir to exist\n");
646 ok(SetCurrentDirectoryW(origin_path), "SetCurrentDirectoryW to origin_path failed\n");
649 static void test_Current_get(void)
651 WCHAR temp_path[MAX_PATH], current_path[MAX_PATH], origin_path[MAX_PATH];
652 BOOL ret;
653 memset(origin_path, 0, sizeof(origin_path));
654 GetCurrentDirectoryW(MAX_PATH, origin_path);
655 memset(temp_path, 0, sizeof(temp_path));
656 GetTempPathW(MAX_PATH, temp_path);
658 ok(SetCurrentDirectoryW(temp_path), "SetCurrentDirectoryW to temp_path failed\n");
659 memset(current_path, 0, sizeof(current_path));
660 ret = p_Current_get(current_path);
661 ok(ret == TRUE, "p_Current_get returned %u\n", ret);
662 current_path[wcslen(current_path)] = '\\';
663 ok(!wcscmp(temp_path, current_path), "p_Current_get(): expect: %s, got %s\n",
664 wine_dbgstr_w(temp_path), wine_dbgstr_w(current_path));
666 ok(SetCurrentDirectoryW(origin_path), "SetCurrentDirectoryW to origin_path failed\n");
667 memset(current_path, 0, sizeof(current_path));
668 ret = p_Current_get(current_path);
669 ok(ret == TRUE, "p_Current_get returned %u\n", ret);
670 ok(!wcscmp(origin_path, current_path), "p_Current_get(): expect: %s, got %s\n",
671 wine_dbgstr_w(origin_path), wine_dbgstr_w(current_path));
674 static void test_Current_set(void)
676 WCHAR temp_path[MAX_PATH], current_path[MAX_PATH], origin_path[MAX_PATH];
677 MSVCP_bool ret;
678 WCHAR testW[] = {'.','/',0};
679 WCHAR not_exit_dirW[] = {'n', 'o', 't', '_', 'e', 'x', 'i', 's', 't', '_', 'd', 'i', 'r', 0};
680 WCHAR invalid_nameW[] = {'?', '?', 'i', 'n', 'v', 'a', 'l', 'i', 'd', '_', 'n', 'a', 'm', 'e', '>', '>', 0};
681 memset(temp_path, 0, sizeof(temp_path));
682 GetTempPathW(MAX_PATH, temp_path);
683 memset(origin_path, 0, sizeof(origin_path));
684 GetCurrentDirectoryW(MAX_PATH, origin_path);
686 ok(p_Current_set(temp_path), "p_Current_set to temp_path failed\n");
687 memset(current_path, 0, sizeof(current_path));
688 ret = p_Current_get(current_path);
689 ok(ret == TRUE, "p_Current_get returned %u\n", ret);
690 current_path[wcslen(current_path)] = '\\';
691 ok(!wcscmp(temp_path, current_path), "p_Current_get(): expect: %s, got %s\n",
692 wine_dbgstr_w(temp_path), wine_dbgstr_w(current_path));
694 ok(p_Current_set(testW), "p_Current_set to temp_path failed\n");
695 memset(current_path, 0, sizeof(current_path));
696 ret = p_Current_get(current_path);
697 ok(ret == TRUE, "p_Current_get returned %u\n", ret);
698 current_path[wcslen(current_path)] = '\\';
699 ok(!wcscmp(temp_path, current_path), "p_Current_get(): expect: %s, got %s\n",
700 wine_dbgstr_w(temp_path), wine_dbgstr_w(current_path));
702 errno = 0xdeadbeef;
703 ok(!p_Current_set(not_exit_dirW), "p_Current_set to not_exist_dir succeed\n");
704 ok(errno == 0xdeadbeef, "errno = %d\n", errno);
706 errno = 0xdeadbeef;
707 ok(!p_Current_set(invalid_nameW), "p_Current_set to ??invalid_name>> succeed\n");
708 ok(errno == 0xdeadbeef, "errno = %d\n", errno);
710 ok(p_Current_set(origin_path), "p_Current_set to origin_path failed\n");
711 memset(current_path, 0, sizeof(current_path));
712 ret = p_Current_get(current_path);
713 ok(ret == TRUE, "p_Current_get returned %u\n", ret);
714 ok(!wcscmp(origin_path, current_path), "p_Current_get(): expect: %s, got %s\n",
715 wine_dbgstr_w(origin_path), wine_dbgstr_w(current_path));
718 static void test_Stat(void)
720 int i, perms, ret;
721 HANDLE file;
722 enum file_type val;
723 WCHAR test_dirW[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r',0};
724 WCHAR test_f1W[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','1',0};
725 WCHAR test_f2W[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','2',0};
726 WCHAR pipeW[] = {'\\','\\','.','\\','P','i','P','e','\\','t','e','s','t','s','_','p','i','p','e','.','c', 0};
727 WCHAR test_neW[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','n','e',0};
728 WCHAR test_invW[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','?','?','i','n','v','a','l','i','d','_','n','a','m','e','>','>',0};
729 WCHAR test_f1_linkW[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','f','1','_','l','i','n','k',0};
730 WCHAR test_dir_linkW[] = {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','d','i','r','_','l','i','n','k',0};
731 WCHAR sys_path[MAX_PATH], origin_path[MAX_PATH], temp_path[MAX_PATH];
732 struct {
733 WCHAR const *path;
734 enum file_type ret;
735 int perms;
736 int is_todo;
737 } tests[] = {
738 { NULL, file_not_found, 0xdeadbeef, FALSE },
739 { test_dirW, directory_file, 0777, FALSE },
740 { test_f1W, regular_file, 0777, FALSE },
741 { test_f2W, regular_file, 0555, FALSE },
742 { test_neW, file_not_found, 0xdeadbeef, FALSE },
743 { test_invW, file_not_found, 0xdeadbeef, FALSE },
744 { test_f1_linkW, regular_file, 0777, TRUE },
745 { test_dir_linkW, directory_file, 0777, TRUE },
748 memset(origin_path, 0, sizeof(origin_path));
749 memset(origin_path, 0, sizeof(temp_path));
750 GetCurrentDirectoryW(MAX_PATH, origin_path);
751 GetTempPathW(MAX_PATH, temp_path);
752 ok(SetCurrentDirectoryW(temp_path), "SetCurrentDirectoryW to temp_path failed\n");
754 CreateDirectoryW(test_dirW, NULL);
756 file = CreateFileW(test_f1W, 0, 0, NULL, CREATE_ALWAYS, 0, NULL);
757 ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n");
758 ok(CloseHandle(file), "CloseHandle\n");
760 file = CreateFileW(test_f2W, 0, 0, NULL, CREATE_ALWAYS, 0, NULL);
761 ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n");
762 ok(CloseHandle(file), "CloseHandle\n");
763 SetFileAttributesW(test_f2W, FILE_ATTRIBUTE_READONLY);
765 SetLastError(0xdeadbeef);
766 ret = pCreateSymbolicLinkW && pCreateSymbolicLinkW(test_f1_linkW, test_f1W, 0);
767 if(!ret && (!pCreateSymbolicLinkW || GetLastError()==ERROR_PRIVILEGE_NOT_HELD||GetLastError()==ERROR_INVALID_FUNCTION)) {
768 tests[6].ret = tests[7].ret = file_not_found;
769 tests[6].perms = tests[7].perms = 0xdeadbeef;
770 win_skip("Privilege not held or symbolic link not supported, skipping symbolic link tests.\n");
771 }else {
772 ok(ret, "CreateSymbolicLinkW failed\n");
773 ok(pCreateSymbolicLinkW(test_dir_linkW, test_dirW, 1), "CreateSymbolicLinkW failed\n");
776 file = CreateNamedPipeW(pipeW,
777 PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, 2, 1024, 1024,
778 NMPWAIT_USE_DEFAULT_WAIT, NULL);
779 ok(file != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
780 perms = 0xdeadbeef;
781 val = p_Stat(pipeW, &perms);
782 todo_wine ok(regular_file == val, "_Stat(): expect: regular, got %d\n", val);
783 todo_wine ok(0777 == perms, "_Stat(): perms expect: 0777, got 0%o\n", perms);
784 perms = 0xdeadbeef;
785 val = p_Lstat(pipeW, &perms);
786 ok(status_unknown == val, "_Lstat(): expect: unknown, got %d\n", val);
787 ok(0xdeadbeef == perms, "_Lstat(): perms expect: 0xdeadbeef, got %x\n", perms);
788 ok(CloseHandle(file), "CloseHandle\n");
789 file = CreateNamedPipeW(pipeW,
790 PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, 2, 1024, 1024,
791 NMPWAIT_USE_DEFAULT_WAIT, NULL);
792 ok(file != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
793 perms = 0xdeadbeef;
794 val = p_Lstat(pipeW, &perms);
795 todo_wine ok(regular_file == val, "_Lstat(): expect: regular, got %d\n", val);
796 todo_wine ok(0777 == perms, "_Lstat(): perms expect: 0777, got 0%o\n", perms);
797 ok(CloseHandle(file), "CloseHandle\n");
799 for(i=0; i<sizeof(tests)/sizeof(tests[0]); i++) {
800 perms = 0xdeadbeef;
801 val = p_Stat(tests[i].path, &perms);
802 todo_wine_if(tests[i].is_todo) {
803 ok(tests[i].ret == val, "_Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
804 ok(tests[i].perms == perms, "_Stat(): test %d perms expect: 0%o, got 0%o\n",
805 i+1, tests[i].perms, perms);
807 val = p_Stat(tests[i].path, NULL);
808 todo_wine_if(tests[i].is_todo)
809 ok(tests[i].ret == val, "_Stat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
811 /* test _Lstat */
812 perms = 0xdeadbeef;
813 val = p_Lstat(tests[i].path, &perms);
814 todo_wine_if(tests[i].is_todo) {
815 ok(tests[i].ret == val, "_Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
816 ok(tests[i].perms == perms, "_Lstat(): test %d perms expect: 0%o, got 0%o\n",
817 i+1, tests[i].perms, perms);
819 val = p_Lstat(tests[i].path, NULL);
820 todo_wine_if(tests[i].is_todo)
821 ok(tests[i].ret == val, "_Lstat(): test %d expect: %d, got %d\n", i+1, tests[i].ret, val);
824 GetSystemDirectoryW(sys_path, MAX_PATH);
825 perms = 0xdeadbeef;
826 val = p_Stat(sys_path, &perms);
827 ok(directory_file == val, "_Stat(): expect: regular, got %d\n", val);
828 ok(0777 == perms, "_Stat(): perms expect: 0777, got 0%o\n", perms);
830 if(ret) {
831 todo_wine ok(DeleteFileW(test_f1_linkW), "expect tr2_test_dir/f1_link to exist\n");
832 todo_wine ok(RemoveDirectoryW(test_dir_linkW), "expect tr2_test_dir/dir_link to exist\n");
834 ok(DeleteFileW(test_f1W), "expect tr2_test_dir/f1 to exist\n");
835 SetFileAttributesW(test_f2W, FILE_ATTRIBUTE_NORMAL);
836 ok(DeleteFileW(test_f2W), "expect tr2_test_dir/f2 to exist\n");
837 ok(RemoveDirectoryW(test_dirW), "expect tr2_test_dir to exist\n");
839 ok(SetCurrentDirectoryW(origin_path), "SetCurrentDirectoryW to origin_path failed\n");
842 START_TEST(msvcp140)
844 if(!init()) return;
845 test_thrd();
846 test_vbtable_size_exports();
847 test_task_continuation_context();
848 test__ContextCallback();
849 test__TaskEventLogger();
850 test_chore();
851 test_to_byte();
852 test_to_wide();
853 test_File_size();
854 test_Current_get();
855 test_Current_set();
856 test_Stat();
857 FreeLibrary(msvcp);