2 * Unit test suite for dir functions
4 * Copyright 2006 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "wine/test.h"
35 static int (__cdecl
*p_makepath_s
)(char *, size_t, const char *, const char *, const char *, const char *);
36 static int (__cdecl
*p_wmakepath_s
)(wchar_t *, size_t, const wchar_t *,const wchar_t *, const wchar_t *, const wchar_t *);
38 static void init(void)
40 HMODULE hmod
= GetModuleHandleA("msvcrt.dll");
42 p_makepath_s
= (void *)GetProcAddress(hmod
, "_makepath_s");
43 p_wmakepath_s
= (void *)GetProcAddress(hmod
, "_wmakepath_s");
56 #define USE_BUFF ((char*)~0ul)
57 static const makepath_case makepath_cases
[] =
59 { NULL
, NULL
, NULL
, NULL
, NULL
, "" }, /* 0 */
60 { NULL
, "c", NULL
, NULL
, NULL
, "c:" },
61 { NULL
, "c:", NULL
, NULL
, NULL
, "c:" },
62 { NULL
, "c:\\", NULL
, NULL
, NULL
, "c:" },
63 { NULL
, NULL
, "dir", NULL
, NULL
, "dir\\" },
64 { NULL
, NULL
, "dir\\", NULL
, NULL
, "dir\\" },
65 { NULL
, NULL
, "\\dir", NULL
, NULL
, "\\dir\\" },
66 { NULL
, NULL
, NULL
, "file", NULL
, "file" },
67 { NULL
, NULL
, NULL
, "\\file", NULL
, "\\file" },
68 { NULL
, NULL
, NULL
, "file", NULL
, "file" },
69 { NULL
, NULL
, NULL
, NULL
, "ext", ".ext" }, /* 10 */
70 { NULL
, NULL
, NULL
, NULL
, ".ext", ".ext" },
71 { "foo", NULL
, NULL
, NULL
, NULL
, "" },
72 { "foo", USE_BUFF
, NULL
, NULL
, NULL
, "f:" },
73 { "foo", NULL
, USE_BUFF
, NULL
, NULL
, "foo\\" },
74 { "foo", NULL
, NULL
, USE_BUFF
, NULL
, "foo" },
75 { "foo", NULL
, USE_BUFF
, "file", NULL
, "foo\\file" },
76 { "foo", NULL
, USE_BUFF
, "file", "ext", "foo\\file.ext" },
77 { "foo", NULL
, NULL
, USE_BUFF
, "ext", "foo.ext" },
78 /* remaining combinations of USE_BUFF crash native */
79 { NULL
, "c", "dir", "file", "ext", "c:dir\\file.ext" },
80 { NULL
, "c:", "dir", "file", "ext", "c:dir\\file.ext" }, /* 20 */
81 { NULL
, "c:\\", "dir", "file", "ext", "c:dir\\file.ext" }
84 static void test_makepath(void)
86 WCHAR driveW
[MAX_PATH
];
88 WCHAR fileW
[MAX_PATH
];
90 WCHAR bufferW
[MAX_PATH
];
91 char buffer
[MAX_PATH
];
95 for (i
= 0; i
< sizeof(makepath_cases
)/sizeof(makepath_cases
[0]); ++i
)
97 const makepath_case
* p
= &makepath_cases
[i
];
99 memset(buffer
, 'X', MAX_PATH
);
101 strcpy(buffer
, p
->buffer
);
105 p
->drive
== USE_BUFF
? buffer
: p
->drive
,
106 p
->dir
== USE_BUFF
? buffer
: p
->dir
,
107 p
->file
== USE_BUFF
? buffer
: p
->file
,
108 p
->ext
== USE_BUFF
? buffer
: p
->ext
);
110 buffer
[MAX_PATH
- 1] = '\0';
111 ok(!strcmp(p
->expected
, buffer
), "got '%s' for case %d\n", buffer
, i
);
114 if (p
->drive
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->drive
, -1, driveW
, MAX_PATH
);
115 if (p
->dir
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->dir
, -1, dirW
, MAX_PATH
);
116 if (p
->file
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->file
, -1, fileW
, MAX_PATH
);
117 if (p
->ext
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->ext
, -1, extW
, MAX_PATH
);
119 memset(buffer
, 0, MAX_PATH
);
120 for (n
= 0; n
< MAX_PATH
; ++n
)
122 if (p
->buffer
) MultiByteToWideChar( CP_ACP
, 0, p
->buffer
, -1, bufferW
, MAX_PATH
);
125 p
->drive
== USE_BUFF
? bufferW
: p
->drive
? driveW
: NULL
,
126 p
->dir
== USE_BUFF
? bufferW
: p
->dir
? dirW
: NULL
,
127 p
->file
== USE_BUFF
? bufferW
: p
->file
? fileW
: NULL
,
128 p
->ext
== USE_BUFF
? bufferW
: p
->ext
? extW
: NULL
);
130 bufferW
[MAX_PATH
- 1] = '\0';
131 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
132 ok(!strcmp(p
->expected
, buffer
), "got '%s' for unicode case %d\n", buffer
, i
);
136 static const WCHAR expected0
[] = {'\0','X','X','X','X','X','X','X','X','X','X','X','X'};
137 static const WCHAR expected1
[] = {'\0','X','X','X','X','X','X','X','X','X','X','X','X'};
138 static const WCHAR expected2
[] = {'\0',':','X','X','X','X','X','X','X','X','X','X','X'};
139 static const WCHAR expected3
[] = {'\0',':','d','X','X','X','X','X','X','X','X','X','X'};
140 static const WCHAR expected4
[] = {'\0',':','d','\\','X','X','X','X','X','X','X','X','X'};
141 static const WCHAR expected5
[] = {'\0',':','d','\\','f','X','X','X','X','X','X','X','X'};
142 static const WCHAR expected6
[] = {'\0',':','d','\\','f','i','X','X','X','X','X','X','X'};
143 static const WCHAR expected7
[] = {'\0',':','d','\\','f','i','l','X','X','X','X','X','X'};
144 static const WCHAR expected8
[] = {'\0',':','d','\\','f','i','l','e','X','X','X','X','X'};
145 static const WCHAR expected9
[] = {'\0',':','d','\\','f','i','l','e','.','X','X','X','X'};
146 static const WCHAR expected10
[] = {'\0',':','d','\\','f','i','l','e','.','e','X','X','X'};
147 static const WCHAR expected11
[] = {'\0',':','d','\\','f','i','l','e','.','e','x','X','X'};
149 static const WCHAR expected12
[] = {'\0',':','X','X','X','X','X','X','X','X'};
150 static const WCHAR expected13
[] = {'\0',':','d','X','X','X','X','X','X','X'};
151 static const WCHAR expected14
[] = {'\0',':','d','i','X','X','X','X','X','X'};
152 static const WCHAR expected15
[] = {'\0',':','d','i','r','X','X','X','X','X'};
153 static const WCHAR expected16
[] = {'\0',':','d','i','r','\\','X','X','X','X'};
155 static const WCHAR expected17
[] = {'\0','o','o'};
156 static const WCHAR expected18
[] = {'\0','o','o','\0','X'};
157 static const WCHAR expected19
[] = {'\0','o','o','\0'};
158 static const WCHAR expected20
[] = {'\0','o','o','\0','X','X','X','X','X'};
159 static const WCHAR expected21
[] = {'\0','o','o','\\','f','i','l','X','X'};
160 static const WCHAR expected22
[] = {'\0','o','o','\0','X','X','X','X','X','X','X','X','X'};
161 static const WCHAR expected23
[] = {'\0','o','o','\\','f','i','l','X','X','X','X','X','X'};
162 static const WCHAR expected24
[] = {'\0','o','o','\\','f','i','l','e','.','e','x','X','X'};
163 static const WCHAR expected25
[] = {'\0','o','o','\0','X','X','X','X'};
164 static const WCHAR expected26
[] = {'\0','o','o','.','e','x','X','X'};
174 const char* expected
;
175 const WCHAR
*expected_unicode
;
176 size_t expected_length
;
179 static const makepath_s_case makepath_s_cases
[] =
181 /* Behavior with directory parameter containing backslash. */
182 {NULL
, 1, "c:", "d\\", "file", "ext", "\0XXXXXXXXXXXX", expected0
, 13},
183 {NULL
, 2, "c:", "d\\", "file", "ext", "\0XXXXXXXXXXXX", expected1
, 13},
184 {NULL
, 3, "c:", "d\\", "file", "ext", "\0:XXXXXXXXXXX", expected2
, 13},
185 {NULL
, 4, "c:", "d\\", "file", "ext", "\0:dXXXXXXXXXX", expected3
, 13},
186 {NULL
, 5, "c:", "d\\", "file", "ext", "\0:d\\XXXXXXXXX", expected4
, 13},
187 {NULL
, 6, "c:", "d\\", "file", "ext", "\0:d\\fXXXXXXXX", expected5
, 13},
188 {NULL
, 7, "c:", "d\\", "file", "ext", "\0:d\\fiXXXXXXX", expected6
, 13},
189 {NULL
, 8, "c:", "d\\", "file", "ext", "\0:d\\filXXXXXX", expected7
, 13},
190 {NULL
, 9, "c:", "d\\", "file", "ext", "\0:d\\fileXXXXX", expected8
, 13},
191 {NULL
, 10, "c:", "d\\", "file", "ext", "\0:d\\file.XXXX", expected9
, 13},
192 {NULL
, 11, "c:", "d\\", "file", "ext", "\0:d\\file.eXXX", expected10
, 13},
193 {NULL
, 12, "c:", "d\\", "file", "ext", "\0:d\\file.exXX", expected11
, 13},
194 /* Behavior with directory parameter lacking backslash. */
195 {NULL
, 3, "c:", "dir", "f", "ext", "\0:XXXXXXXX", expected12
, 10},
196 {NULL
, 4, "c:", "dir", "f", "ext", "\0:dXXXXXXX", expected13
, 10},
197 {NULL
, 5, "c:", "dir", "f", "ext", "\0:diXXXXXX", expected14
, 10},
198 {NULL
, 6, "c:", "dir", "f", "ext", "\0:dirXXXXX", expected15
, 10},
199 {NULL
, 7, "c:", "dir", "f", "ext", "\0:dir\\XXXX", expected16
, 10},
200 /* Behavior with overlapped buffer. */
201 {"foo", 2, USE_BUFF
, NULL
, NULL
, NULL
, "\0oo", expected17
, 3},
202 {"foo", 4, NULL
, USE_BUFF
, NULL
, NULL
, "\0oo\0X", expected18
, 5},
203 {"foo", 3, NULL
, NULL
, USE_BUFF
, NULL
, "\0oo\0", expected19
, 4},
204 {"foo", 4, NULL
, USE_BUFF
, "file", NULL
, "\0oo\0XXXXX", expected20
, 9},
205 {"foo", 8, NULL
, USE_BUFF
, "file", NULL
, "\0oo\\filXX", expected21
, 9},
206 {"foo", 4, NULL
, USE_BUFF
, "file", "ext", "\0oo\0XXXXXXXXX", expected22
, 13},
207 {"foo", 8, NULL
, USE_BUFF
, "file", "ext", "\0oo\\filXXXXXX", expected23
, 13},
208 {"foo", 12, NULL
, USE_BUFF
, "file", "ext", "\0oo\\file.exXX", expected24
, 13},
209 {"foo", 4, NULL
, NULL
, USE_BUFF
, "ext", "\0oo\0XXXX", expected25
, 8},
210 {"foo", 7, NULL
, NULL
, USE_BUFF
, "ext", "\0oo.exXX", expected26
, 8},
213 static void test_makepath_s(void)
215 WCHAR driveW
[MAX_PATH
];
216 WCHAR dirW
[MAX_PATH
];
217 WCHAR fileW
[MAX_PATH
];
218 WCHAR extW
[MAX_PATH
];
219 WCHAR bufferW
[MAX_PATH
];
220 char buffer
[MAX_PATH
];
224 if (!p_makepath_s
|| !p_wmakepath_s
)
226 win_skip("Safe makepath functions are not available\n");
231 ret
= p_makepath_s(NULL
, 0, NULL
, NULL
, NULL
, NULL
);
232 ok(ret
== EINVAL
, "Expected _makepath_s to return EINVAL, got %d\n", ret
);
233 ok(errno
== EINVAL
, "Expected errno to be EINVAL, got %d\n", errno
);
236 ret
= p_makepath_s(buffer
, 0, NULL
, NULL
, NULL
, NULL
);
237 ok(ret
== EINVAL
, "Expected _makepath_s to return EINVAL, got %d\n", ret
);
238 ok(errno
== EINVAL
, "Expected errno to be EINVAL, got %d\n", errno
);
241 ret
= p_wmakepath_s(NULL
, 0, NULL
, NULL
, NULL
, NULL
);
242 ok(ret
== EINVAL
, "Expected _wmakepath_s to return EINVAL, got %d\n", ret
);
243 ok(errno
== EINVAL
, "Expected errno to be EINVAL, got %d\n", errno
);
246 ret
= p_wmakepath_s(bufferW
, 0, NULL
, NULL
, NULL
, NULL
);
247 ok(ret
== EINVAL
, "Expected _wmakepath_s to return EINVAL, got %d\n", ret
);
248 ok(errno
== EINVAL
, "Expected errno to be EINVAL, got %d\n", errno
);
250 /* Test with the normal _makepath cases. */
251 for (i
= 0; i
< sizeof(makepath_cases
)/sizeof(makepath_cases
[0]); i
++)
253 const makepath_case
*p
= makepath_cases
+ i
;
255 memset(buffer
, 'X', MAX_PATH
);
257 strcpy(buffer
, p
->buffer
);
260 ret
= p_makepath_s(buffer
, MAX_PATH
,
261 p
->drive
== USE_BUFF
? buffer
: p
->drive
,
262 p
->dir
== USE_BUFF
? buffer
: p
->dir
,
263 p
->file
== USE_BUFF
? buffer
: p
->file
,
264 p
->ext
== USE_BUFF
? buffer
: p
->ext
);
265 ok(ret
== 0, "[%d] Expected _makepath_s to return 0, got %d\n", i
, ret
);
267 buffer
[MAX_PATH
- 1] = '\0';
268 ok(!strcmp(p
->expected
, buffer
), "got '%s' for case %d\n", buffer
, i
);
271 if (p
->drive
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->drive
, -1, driveW
, MAX_PATH
);
272 if (p
->dir
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->dir
, -1, dirW
, MAX_PATH
);
273 if (p
->file
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->file
, -1, fileW
, MAX_PATH
);
274 if (p
->ext
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->ext
, -1, extW
, MAX_PATH
);
276 memset(buffer
, 0, MAX_PATH
);
277 for (n
= 0; n
< MAX_PATH
; ++n
)
279 if (p
->buffer
) MultiByteToWideChar( CP_ACP
, 0, p
->buffer
, -1, bufferW
, MAX_PATH
);
281 ret
= p_wmakepath_s(bufferW
, MAX_PATH
,
282 p
->drive
== USE_BUFF
? bufferW
: p
->drive
? driveW
: NULL
,
283 p
->dir
== USE_BUFF
? bufferW
: p
->dir
? dirW
: NULL
,
284 p
->file
== USE_BUFF
? bufferW
: p
->file
? fileW
: NULL
,
285 p
->ext
== USE_BUFF
? bufferW
: p
->ext
? extW
: NULL
);
286 ok(ret
== 0, "[%d] Expected _wmakepath_s to return 0, got %d\n", i
, ret
);
288 bufferW
[MAX_PATH
- 1] = '\0';
289 WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, buffer
, MAX_PATH
, NULL
, NULL
);
290 ok(!strcmp(p
->expected
, buffer
), "got '%s' for unicode case %d\n", buffer
, i
);
293 /* Try insufficient length cases. */
294 for (i
= 0; i
< sizeof(makepath_s_cases
)/sizeof(makepath_s_cases
[0]); i
++)
296 const makepath_s_case
*p
= makepath_s_cases
+ i
;
298 memset(buffer
, 'X', MAX_PATH
);
300 strcpy(buffer
, p
->buffer
);
304 ret
= p_makepath_s(buffer
, p
->length
,
305 p
->drive
== USE_BUFF
? buffer
: p
->drive
,
306 p
->dir
== USE_BUFF
? buffer
: p
->dir
,
307 p
->file
== USE_BUFF
? buffer
: p
->file
,
308 p
->ext
== USE_BUFF
? buffer
: p
->ext
);
309 ok(ret
== ERANGE
, "[%d] Expected _makepath_s to return ERANGE, got %d\n", i
, ret
);
310 ok(errno
== ERANGE
, "[%d] Expected errno to be ERANGE, got %d\n", i
, errno
);
311 ok(!memcmp(p
->expected
, buffer
, p
->expected_length
), "unexpected output for case %d\n", i
);
314 if (p
->drive
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->drive
, -1, driveW
, MAX_PATH
);
315 if (p
->dir
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->dir
, -1, dirW
, MAX_PATH
);
316 if (p
->file
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->file
, -1, fileW
, MAX_PATH
);
317 if (p
->ext
!= USE_BUFF
) MultiByteToWideChar(CP_ACP
, 0, p
->ext
, -1, extW
, MAX_PATH
);
319 memset(buffer
, 0, MAX_PATH
);
320 for (n
= 0; n
< MAX_PATH
; ++n
)
322 if (p
->buffer
) MultiByteToWideChar( CP_ACP
, 0, p
->buffer
, -1, bufferW
, MAX_PATH
);
325 ret
= p_wmakepath_s(bufferW
, p
->length
,
326 p
->drive
== USE_BUFF
? bufferW
: p
->drive
? driveW
: NULL
,
327 p
->dir
== USE_BUFF
? bufferW
: p
->dir
? dirW
: NULL
,
328 p
->file
== USE_BUFF
? bufferW
: p
->file
? fileW
: NULL
,
329 p
->ext
== USE_BUFF
? bufferW
: p
->ext
? extW
: NULL
);
330 ok(ret
== ERANGE
, "[%d] Expected _wmakepath_s to return ERANGE, got %d\n", i
, ret
);
331 ok(errno
== ERANGE
, "[%d] Expected errno to be ERANGE, got %d\n", i
, errno
);
333 ok(!memcmp(p
->expected_unicode
, bufferW
, p
->expected_length
* sizeof(WCHAR
)), "unexpected output for case %d\n", i
);
337 static void test_fullpath(void)
340 char tmppath
[MAX_PATH
];
341 char prevpath
[MAX_PATH
];
342 char level1
[MAX_PATH
];
343 char level2
[MAX_PATH
];
344 char teststring
[MAX_PATH
];
349 GetCurrentDirectoryA(MAX_PATH
, prevpath
);
350 GetTempPathA(MAX_PATH
,tmppath
);
351 strcpy(level1
,tmppath
);
352 strcat(level1
,"msvcrt-test\\");
354 rc
= CreateDirectoryA(level1
,NULL
);
355 if (!rc
&& GetLastError()==ERROR_ALREADY_EXISTS
)
358 strcpy(level2
,level1
);
359 strcat(level2
,"nextlevel\\");
360 rc
= CreateDirectoryA(level2
,NULL
);
361 if (!rc
&& GetLastError()==ERROR_ALREADY_EXISTS
)
363 SetCurrentDirectoryA(level2
);
365 ok(_fullpath(full
,"test", MAX_PATH
)!=NULL
,"_fullpath failed\n");
366 strcpy(teststring
,level2
);
367 strcat(teststring
,"test");
368 ok(strcmp(full
,teststring
)==0,"Invalid Path returned %s\n",full
);
369 ok(_fullpath(full
,"\\test", MAX_PATH
)!=NULL
,"_fullpath failed\n");
370 memcpy(teststring
,level2
,3);
372 strcat(teststring
,"test");
373 ok(strcmp(full
,teststring
)==0,"Invalid Path returned %s\n",full
);
374 ok(_fullpath(full
,"..\\test", MAX_PATH
)!=NULL
,"_fullpath failed\n");
375 strcpy(teststring
,level1
);
376 strcat(teststring
,"test");
377 ok(strcmp(full
,teststring
)==0,"Invalid Path returned %s\n",full
);
378 ok(_fullpath(full
,"..\\test", 10)==NULL
,"_fullpath failed to generate error\n");
380 freeme
= _fullpath(NULL
,"test", 0);
381 ok(freeme
!=NULL
,"No path returned\n");
382 strcpy(teststring
,level2
);
383 strcat(teststring
,"test");
384 ok(strcmp(freeme
,teststring
)==0,"Invalid Path returned %s\n",freeme
);
387 SetCurrentDirectoryA(prevpath
);
389 RemoveDirectoryA(level2
);
391 RemoveDirectoryA(level1
);
394 static void test_splitpath(void)
396 const char* path
= "c:\\\x83\x5c\x83\x74\x83\x67.bin";
397 char drive
[3], dir
[MAX_PATH
], fname
[MAX_PATH
], ext
[MAX_PATH
];
398 int prev_cp
= _getmbcp();
402 _splitpath(path
, drive
, dir
, fname
, ext
);
403 ok(!strcmp(drive
, "c:"), "got %s\n", drive
);
404 ok(!strcmp(dir
, "\\\x83\x5c"), "got %s\n", dir
);
405 ok(!strcmp(fname
, "\x83\x74\x83\x67"), "got %s\n", fname
);
406 ok(!strcmp(ext
, ".bin"), "got %s\n", ext
);
408 /* MBCS (Japanese) codepage */
410 _splitpath(path
, drive
, dir
, fname
, ext
);
411 ok(!strcmp(drive
, "c:"), "got %s\n", drive
);
412 ok(!strcmp(dir
, "\\"), "got %s\n", dir
);
413 ok(!strcmp(fname
, "\x83\x5c\x83\x74\x83\x67"), "got %s\n", fname
);
414 ok(!strcmp(ext
, ".bin"), "got %s\n", ext
);