msvcrt: Use the macros for parameter checking for wcsncat_s (and fix the test).
[wine] / dlls / msvcr90 / tests / msvcr90.c
1 /*
2  * Copyright 2010 Detlef Riekenberg
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22
23 #include <windef.h>
24 #include <winbase.h>
25 #include <errno.h>
26 #include "wine/test.h"
27
28 #define DEFINE_EXPECT(func) \
29     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
30
31 #define SET_EXPECT(func) \
32     expect_ ## func = TRUE
33
34 #define CHECK_EXPECT2(func) \
35     do { \
36         ok(expect_ ##func, "unexpected call " #func "\n"); \
37         called_ ## func = TRUE; \
38     }while(0)
39
40 #define CHECK_EXPECT(func) \
41     do { \
42         CHECK_EXPECT2(func); \
43         expect_ ## func = FALSE; \
44     }while(0)
45
46 #define CHECK_CALLED(func) \
47     do { \
48         ok(called_ ## func, "expected " #func "\n"); \
49         expect_ ## func = called_ ## func = FALSE; \
50     }while(0)
51
52 DEFINE_EXPECT(invalid_parameter_handler);
53
54 static _invalid_parameter_handler (__cdecl *p_set_invalid_parameter_handler)(_invalid_parameter_handler);
55 typedef int (__cdecl *_INITTERM_E_FN)(void);
56 static int (__cdecl *p_initterm_e)(_INITTERM_E_FN *table, _INITTERM_E_FN *end);
57 static void* (__cdecl *p_encode_pointer)(void *);
58 static void* (__cdecl *p_decode_pointer)(void *);
59 static void* (__cdecl *p_encoded_null)(void);
60 static int *p_sys_nerr;
61 static int* (__cdecl *p__sys_nerr)(void);
62 static char **p_sys_errlist;
63 static char** (__cdecl *p__sys_errlist)(void);
64 static __int64 (__cdecl *p_strtoi64)(const char *, char **, int);
65 static unsigned __int64 (__cdecl *p_strtoui64)(const char *, char **, int);
66 static errno_t (__cdecl *p_itoa_s)(int,char*,size_t,int);
67 static int (__cdecl *p_wcsncat_s)(wchar_t *dst, size_t elem, const wchar_t *src, size_t count);
68
69 static void* (WINAPI *pEncodePointer)(void *);
70
71 static int cb_called[4];
72
73 /* ########## */
74
75 static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
76         const wchar_t *function, const wchar_t *file,
77         unsigned line, uintptr_t arg)
78 {
79     CHECK_EXPECT(invalid_parameter_handler);
80     ok(expression == NULL, "expression is not NULL\n");
81     ok(function == NULL, "function is not NULL\n");
82     ok(file == NULL, "file is not NULL\n");
83     ok(line == 0, "line = %u\n", line);
84     ok(arg == 0, "arg = %lx\n", (UINT_PTR)arg);
85 }
86
87 static int __cdecl initterm_cb0(void)
88 {
89     cb_called[0]++;
90     return 0;
91 }
92
93 static int __cdecl initterm_cb1(void)
94 {
95     cb_called[1]++;
96     return 1;
97 }
98
99 static int __cdecl initterm_cb2(void)
100 {
101     cb_called[2]++;
102     return 2;
103 }
104
105
106 static void test__initterm_e(void)
107 {
108     _INITTERM_E_FN table[4];
109     int res;
110
111     if (!p_initterm_e) {
112         skip("_initterm_e not found\n");
113         return;
114     }
115
116     memset(table, 0, sizeof(table));
117
118     memset(cb_called, 0, sizeof(cb_called));
119     errno = 0xdeadbeef;
120     res = p_initterm_e(table, table);
121     ok( !res && !cb_called[0] && !cb_called[1] && !cb_called[2],
122         "got %d with 0x%x {%d, %d, %d}\n",
123         res, errno, cb_called[0], cb_called[1], cb_called[2]);
124
125     memset(cb_called, 0, sizeof(cb_called));
126     errno = 0xdeadbeef;
127     res = p_initterm_e(table, NULL);
128     ok( !res && !cb_called[0] && !cb_called[1] && !cb_called[2],
129         "got %d with 0x%x {%d, %d, %d}\n",
130         res, errno, cb_called[0], cb_called[1], cb_called[2]);
131
132     if (0) {
133         /* this crash on Windows */
134         errno = 0xdeadbeef;
135         res = p_initterm_e(NULL, table);
136         trace("got %d with 0x%x\n", res, errno);
137     }
138
139     table[0] = initterm_cb0;
140     memset(cb_called, 0, sizeof(cb_called));
141     errno = 0xdeadbeef;
142     res = p_initterm_e(table, &table[1]);
143     ok( !res && (cb_called[0] == 1) && !cb_called[1] && !cb_called[2],
144         "got %d with 0x%x {%d, %d, %d}\n",
145         res, errno, cb_called[0], cb_called[1], cb_called[2]);
146
147
148     /* init-function returning failure */
149     table[1] = initterm_cb1;
150     memset(cb_called, 0, sizeof(cb_called));
151     errno = 0xdeadbeef;
152     res = p_initterm_e(table, &table[3]);
153     ok( (res == 1) && (cb_called[0] == 1) && (cb_called[1] == 1) && !cb_called[2],
154         "got %d with 0x%x {%d, %d, %d}\n",
155         res, errno, cb_called[0], cb_called[1], cb_called[2]);
156
157     /* init-function not called, when end < start */
158     memset(cb_called, 0, sizeof(cb_called));
159     errno = 0xdeadbeef;
160     res = p_initterm_e(&table[3], table);
161     ok( !res && !cb_called[0] && !cb_called[1] && !cb_called[2],
162         "got %d with 0x%x {%d, %d, %d}\n",
163         res, errno, cb_called[0], cb_called[1], cb_called[2]);
164
165     /* initialization stop after first non-zero result */
166     table[2] = initterm_cb0;
167     memset(cb_called, 0, sizeof(cb_called));
168     errno = 0xdeadbeef;
169     res = p_initterm_e(table, &table[3]);
170     ok( (res == 1) && (cb_called[0] == 1) && (cb_called[1] == 1) && !cb_called[2],
171         "got %d with 0x%x {%d, %d, %d}\n",
172         res, errno, cb_called[0], cb_called[1], cb_called[2]);
173
174     /* NULL pointer in the array are skipped */
175     table[1] = NULL;
176     table[2] = initterm_cb2;
177     memset(cb_called, 0, sizeof(cb_called));
178     errno = 0xdeadbeef;
179     res = p_initterm_e(table, &table[3]);
180     ok( (res == 2) && (cb_called[0] == 1) && !cb_called[1] && (cb_called[2] == 1),
181         "got %d with 0x%x {%d, %d, %d}\n",
182         res, errno, cb_called[0], cb_called[1], cb_called[2]);
183
184 }
185
186 /* Beware that _encode_pointer is a NOP before XP
187    (the parameter is returned unchanged) */
188 static void test__encode_pointer(void)
189 {
190     void *ptr, *res;
191
192     if(!p_encode_pointer || !p_decode_pointer || !p_encoded_null) {
193         win_skip("_encode_pointer, _decode_pointer or _encoded_null not found\n");
194         return;
195     }
196
197     ptr = (void*)0xdeadbeef;
198     res = p_encode_pointer(ptr);
199     res = p_decode_pointer(res);
200     ok(res == ptr, "Pointers are different after encoding and decoding\n");
201
202     ok(p_encoded_null() == p_encode_pointer(NULL), "Error encoding null\n");
203
204     ptr = p_encode_pointer(p_encode_pointer);
205     ok(p_decode_pointer(ptr) == p_encode_pointer, "Error decoding pointer\n");
206
207     /* Not present before XP */
208     if (!pEncodePointer) {
209         win_skip("EncodePointer not found\n");
210         return;
211     }
212
213     res = pEncodePointer(p_encode_pointer);
214     ok(ptr == res, "_encode_pointer produced different result than EncodePointer\n");
215
216 }
217
218 static void test_error_messages(void)
219 {
220     int *size, size_copy;
221
222     if(!p_sys_nerr || !p__sys_nerr || !p_sys_errlist || !p__sys_errlist) {
223         win_skip("Skipping test_error_messages tests\n");
224         return;
225     }
226
227     size = p__sys_nerr();
228     size_copy = *size;
229     ok(*p_sys_nerr == *size, "_sys_nerr = %u, size = %u\n", *p_sys_nerr, *size);
230
231     *size = 20;
232     ok(*p_sys_nerr == *size, "_sys_nerr = %u, size = %u\n", *p_sys_nerr, *size);
233
234     *size = size_copy;
235
236     ok(*p_sys_errlist == *(p__sys_errlist()), "p_sys_errlist != p__sys_errlist()\n");
237 }
238
239 static void test__strtoi64(void)
240 {
241     __int64 res;
242     unsigned __int64 ures;
243
244     if(!p_strtoi64 || !p_strtoui64) {
245         win_skip("_strtoi64 or _strtoui64 not found\n");
246         return;
247     }
248
249     if(!p_set_invalid_parameter_handler) {
250         win_skip("_set_invalid_parameter_handler not found\n");
251         return;
252     }
253
254     errno = 0xdeadbeef;
255     SET_EXPECT(invalid_parameter_handler);
256     res = p_strtoi64(NULL, NULL, 10);
257     ok(res == 0, "res != 0\n");
258     CHECK_CALLED(invalid_parameter_handler);
259
260     SET_EXPECT(invalid_parameter_handler);
261     res = p_strtoi64("123", NULL, 1);
262     ok(res == 0, "res != 0\n");
263     CHECK_CALLED(invalid_parameter_handler);
264
265     SET_EXPECT(invalid_parameter_handler);
266     res = p_strtoi64("123", NULL, 37);
267     ok(res == 0, "res != 0\n");
268     CHECK_CALLED(invalid_parameter_handler);
269
270     SET_EXPECT(invalid_parameter_handler);
271     ures = p_strtoui64(NULL, NULL, 10);
272     ok(ures == 0, "res = %d\n", (int)ures);
273     CHECK_CALLED(invalid_parameter_handler);
274
275     SET_EXPECT(invalid_parameter_handler);
276     ures = p_strtoui64("123", NULL, 1);
277     ok(ures == 0, "res = %d\n", (int)ures);
278     CHECK_CALLED(invalid_parameter_handler);
279
280     SET_EXPECT(invalid_parameter_handler);
281     ures = p_strtoui64("123", NULL, 37);
282     ok(ures == 0, "res = %d\n", (int)ures);
283     CHECK_CALLED(invalid_parameter_handler);
284     ok(errno == 0xdeadbeef, "errno = %x\n", errno);
285 }
286
287 static void test__itoa_s(void)
288 {
289     errno_t ret;
290     char buffer[33];
291
292     if (!p_itoa_s)
293     {
294         win_skip("Skipping _itoa_s tests\n");
295         return;
296     }
297
298     if(!p_set_invalid_parameter_handler) {
299         win_skip("_set_invalid_parameter_handler not found\n");
300         return;
301     }
302
303     /* _itoa_s (on msvcr90) doesn't set errno (in case of errors) while msvcrt does
304      * as we always set errno in our msvcrt implementation, don't test here that errno
305      * isn't changed
306      */
307     SET_EXPECT(invalid_parameter_handler);
308     ret = p_itoa_s(0, NULL, 0, 0);
309     ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
310     CHECK_CALLED(invalid_parameter_handler);
311
312     memset(buffer, 'X', sizeof(buffer));
313     SET_EXPECT(invalid_parameter_handler);
314     ret = p_itoa_s(0, buffer, 0, 0);
315     ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
316     ok(buffer[0] == 'X', "Expected the output buffer to be untouched\n");
317     CHECK_CALLED(invalid_parameter_handler);
318
319     memset(buffer, 'X', sizeof(buffer));
320     SET_EXPECT(invalid_parameter_handler);
321     ret = p_itoa_s(0, buffer, sizeof(buffer), 0);
322     ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
323     ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n");
324     CHECK_CALLED(invalid_parameter_handler);
325
326     memset(buffer, 'X', sizeof(buffer));
327     SET_EXPECT(invalid_parameter_handler);
328     ret = p_itoa_s(0, buffer, sizeof(buffer), 64);
329     ok(ret == EINVAL, "Expected _itoa_s to return EINVAL, got %d\n", ret);
330     ok(buffer[0] == '\0', "Expected the output buffer to be null terminated\n");
331     CHECK_CALLED(invalid_parameter_handler);
332
333     memset(buffer, 'X', sizeof(buffer));
334     SET_EXPECT(invalid_parameter_handler);
335     ret = p_itoa_s(12345678, buffer, 4, 10);
336     ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
337     ok(!memcmp(buffer, "\000765", 4),
338        "Expected the output buffer to be null terminated with truncated output\n");
339     CHECK_CALLED(invalid_parameter_handler);
340
341     memset(buffer, 'X', sizeof(buffer));
342     SET_EXPECT(invalid_parameter_handler);
343     ret = p_itoa_s(12345678, buffer, 8, 10);
344     ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
345     ok(!memcmp(buffer, "\0007654321", 8),
346        "Expected the output buffer to be null terminated with truncated output\n");
347     CHECK_CALLED(invalid_parameter_handler);
348
349     memset(buffer, 'X', sizeof(buffer));
350     SET_EXPECT(invalid_parameter_handler);
351     ret = p_itoa_s(-12345678, buffer, 9, 10);
352     ok(ret == ERANGE, "Expected _itoa_s to return ERANGE, got %d\n", ret);
353     ok(!memcmp(buffer, "\00087654321", 9),
354        "Expected the output buffer to be null terminated with truncated output\n");
355     CHECK_CALLED(invalid_parameter_handler);
356
357     ret = p_itoa_s(12345678, buffer, 9, 10);
358     ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
359     ok(!strcmp(buffer, "12345678"),
360        "Expected output buffer string to be \"12345678\", got \"%s\"\n",
361        buffer);
362
363     ret = p_itoa_s(43690, buffer, sizeof(buffer), 2);
364     ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
365     ok(!strcmp(buffer, "1010101010101010"),
366        "Expected output buffer string to be \"1010101010101010\", got \"%s\"\n",
367        buffer);
368
369     ret = p_itoa_s(1092009, buffer, sizeof(buffer), 36);
370     ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
371     ok(!strcmp(buffer, "nell"),
372        "Expected output buffer string to be \"nell\", got \"%s\"\n",
373        buffer);
374
375     ret = p_itoa_s(5704, buffer, sizeof(buffer), 18);
376     ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
377     ok(!strcmp(buffer, "hag"),
378        "Expected output buffer string to be \"hag\", got \"%s\"\n",
379        buffer);
380
381     ret = p_itoa_s(-12345678, buffer, sizeof(buffer), 10);
382     ok(ret == 0, "Expected _itoa_s to return 0, got %d\n", ret);
383     ok(!strcmp(buffer, "-12345678"),
384        "Expected output buffer string to be \"-12345678\", got \"%s\"\n",
385        buffer);
386 }
387
388 static void test_wcsncat_s(void)
389 {
390     static wchar_t abcW[] = {'a','b','c',0};
391     int ret;
392     wchar_t dst[4];
393     wchar_t src[4];
394
395     if (!p_wcsncat_s)
396     {
397         win_skip("skipping wcsncat_s tests\n");
398         return;
399     }
400
401     if(!p_set_invalid_parameter_handler) {
402         win_skip("_set_invalid_parameter_handler not found\n");
403         return;
404     }
405
406     memcpy(src, abcW, sizeof(abcW));
407     dst[0] = 0;
408     SET_EXPECT(invalid_parameter_handler);
409     ret = p_wcsncat_s(NULL, 4, src, 4);
410     ok(ret == EINVAL, "err = %d\n", ret);
411     CHECK_CALLED(invalid_parameter_handler);
412
413     SET_EXPECT(invalid_parameter_handler);
414     ret = p_wcsncat_s(dst, 0, src, 4);
415     ok(ret == EINVAL, "err = %d\n", ret);
416     CHECK_CALLED(invalid_parameter_handler);
417
418     SET_EXPECT(invalid_parameter_handler);
419     ret = p_wcsncat_s(dst, 0, src, _TRUNCATE);
420     ok(ret == EINVAL, "err = %d\n", ret);
421     CHECK_CALLED(invalid_parameter_handler);
422
423     ret = p_wcsncat_s(dst, 4, NULL, 0);
424     ok(ret == 0, "err = %d\n", ret);
425
426     dst[0] = 0;
427     SET_EXPECT(invalid_parameter_handler);
428     ret = p_wcsncat_s(dst, 2, src, 4);
429     ok(ret == ERANGE, "err = %d\n", ret);
430     CHECK_CALLED(invalid_parameter_handler);
431
432     dst[0] = 0;
433     ret = p_wcsncat_s(dst, 2, src, _TRUNCATE);
434     ok(ret == STRUNCATE, "err = %d\n", ret);
435     ok(dst[0] == 'a' && dst[1] == 0, "dst is %s\n", wine_dbgstr_w(dst));
436
437     memcpy(dst, abcW, sizeof(abcW));
438     dst[3] = 'd';
439     SET_EXPECT(invalid_parameter_handler);
440     ret = p_wcsncat_s(dst, 4, src, 4);
441     ok(ret == EINVAL, "err = %d\n", ret);
442     CHECK_CALLED(invalid_parameter_handler);
443 }
444
445 /* ########## */
446
447 START_TEST(msvcr90)
448 {
449     HMODULE hcrt;
450     HMODULE hkernel32;
451
452     SetLastError(0xdeadbeef);
453     hcrt = LoadLibraryA("msvcr90.dll");
454     if (!hcrt) {
455         win_skip("msvcr90.dll not installed (got %d)\n", GetLastError());
456         return;
457     }
458
459     p_set_invalid_parameter_handler = (void *) GetProcAddress(hcrt, "_set_invalid_parameter_handler");
460     if(p_set_invalid_parameter_handler)
461         ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
462                 "Invalid parameter handler was already set\n");
463
464     p_initterm_e = (void *) GetProcAddress(hcrt, "_initterm_e");
465     p_encode_pointer = (void *) GetProcAddress(hcrt, "_encode_pointer");
466     p_decode_pointer = (void *) GetProcAddress(hcrt, "_decode_pointer");
467     p_encoded_null = (void *) GetProcAddress(hcrt, "_encoded_null");
468     p_sys_nerr = (void *) GetProcAddress(hcrt, "_sys_nerr");
469     p__sys_nerr = (void *) GetProcAddress(hcrt, "__sys_nerr");
470     p_sys_errlist = (void *) GetProcAddress(hcrt, "_sys_errlist");
471     p__sys_errlist = (void *) GetProcAddress(hcrt, "__sys_errlist");
472     p_strtoi64 = (void *) GetProcAddress(hcrt, "_strtoi64");
473     p_strtoui64 = (void *) GetProcAddress(hcrt, "_strtoui64");
474     p_itoa_s = (void *)GetProcAddress(hcrt, "_itoa_s");
475     p_wcsncat_s = (void *)GetProcAddress( hcrt,"wcsncat_s" );
476
477     hkernel32 = GetModuleHandleA("kernel32.dll");
478     pEncodePointer = (void *) GetProcAddress(hkernel32, "EncodePointer");
479
480     test__initterm_e();
481     test__encode_pointer();
482     test_error_messages();
483     test__strtoi64();
484     test__itoa_s();
485     test_wcsncat_s();
486 }