Fixed some issues found by winapi_check.
[wine] / dlls / kernel / tests / path.c
1 /*
2  * Unit test suite for Get*PathNamesA and (Get|Set)CurrentDirectoryA.
3  *
4  * Copyright 2002 Geoffrey Hausheer
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdio.h>
22 #include "wine/test.h"
23 #include "winbase.h"
24 #include "winuser.h"
25 #include "winerror.h"
26
27 #define WIN2K_PLUS(version) (version.dwMajorVersion==5)
28 #define WIN98_PLUS(version) (version.dwMajorVersion==4 && \
29                              version.dwMinorVersion>0)
30 #define HAS_TRAIL_SLASH_A(string) (string[lstrlenA(string)-1]=='\\')
31
32 #define LONGFILE "Long File test.path"
33 #define SHORTFILE "pathtest.pth"
34 #define SHORTDIR "shortdir"
35 #define LONGDIR "Long Directory"
36 #define NONFILE_SHORT "noexist.pth"
37 #define NONFILE_LONG "Non Existant File"
38 #define NONDIR_SHORT "notadir"
39 #define NONDIR_LONG "Non Existant Directory"
40
41 #define NOT_A_VALID_DRIVE '@'
42
43 static OSVERSIONINFOA version;
44 /* the following characters don't work well with GetFullPathNameA
45    in Win98.  I don't know if this is a FAT thing, or if it is an OS thing
46    but I don't test these characters now.
47    NOTE: Win2k allows GetFullPathNameA to work with them though
48       |<>
49 */
50 static const CHAR funny_chars[]="!@#$%^&*()=+{}[],?'`\"";
51 static const CHAR is_char_ok[] ="111111101111111110110";
52 static const CHAR wine_todo[]  ="111111101100110000110";
53
54 static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR,LPSTR,DWORD);
55
56 /* a structure to deal with wine todos somewhat cleanly */
57 typedef struct {
58   DWORD shortlen;
59   DWORD shorterror;
60   DWORD s2llen;
61   DWORD s2lerror;
62   DWORD longlen;
63   DWORD longerror;
64 } SLpassfail;
65
66 /* function that tests GetFullPathNameA, GetShortPathNameA,GetLongPathNameA */
67 /* NOTE: the passfail structure is used to allow cutomizeable todo checking
68          for wine.  It is not very pretty, but it sure beats duplicating this
69          function lots of times
70 */
71 static void test_ValidPathA(CHAR *curdir, CHAR *subdir, CHAR *filename,
72                          CHAR *shortstr, SLpassfail *passfail, CHAR *errstr) {
73   CHAR tmpstr[MAX_PATH],
74        fullpath[MAX_PATH],      /*full path to the file (not short/long) */
75        subpath[MAX_PATH],       /*relative path to the file */
76        fullpathshort[MAX_PATH], /*absolue path to the file (short format) */
77        fullpathlong[MAX_PATH],  /*absolute path to the file (long format) */
78        curdirshort[MAX_PATH],   /*absolute path to the current dir (short) */
79        curdirlong[MAX_PATH];    /*absolute path to the current dir (long) */
80   LPSTR strptr;                 /*ptr to the filename portion of the path */
81   DWORD len;
82 /* if passfail is NULL, we can perform all checks within this function,
83    otherwise, we will return the relevant data in the passfail struct, so
84    we must initialize it first
85 */
86   if(passfail!=NULL) {
87     passfail->shortlen=-1;passfail->s2llen=-1;passfail->longlen=-1;
88     passfail->shorterror=0;passfail->s2lerror=0;passfail->longerror=0;
89   }
90 /* GetLongPathNameA is only supported on Win2k+ and Win98+ */
91   if(pGetLongPathNameA) {
92     ok((len=pGetLongPathNameA(curdir,curdirlong,MAX_PATH)),
93        "%s: GetLongPathNameA failed",errstr);
94 /*GetLongPathNameA can return a trailing '\\' but shouldn't do so here */
95     ok(! HAS_TRAIL_SLASH_A(curdirlong),
96        "%s: GetLongPathNameA should not have a trailing \\",errstr);
97   }
98   ok((len=GetShortPathNameA(curdir,curdirshort,MAX_PATH)),
99      "%s: GetShortPathNameA failed",errstr);
100 /*GetShortPathNameA can return a trailing '\\' but shouldn't do so here */
101   ok(! HAS_TRAIL_SLASH_A(curdirshort),
102      "%s: GetShortPathNameA should not have a trailing \\",errstr);
103 /* build relative and absolute paths from inputs */
104   if(lstrlenA(subdir)) {
105     sprintf(subpath,"%s\\%s",subdir,filename);
106   } else {
107     lstrcpyA(subpath,filename);
108   }
109   sprintf(fullpath,"%s\\%s",curdir,subpath);
110   sprintf(fullpathshort,"%s\\%s",curdirshort,subpath);
111   sprintf(fullpathlong,"%s\\%s",curdirlong,subpath);
112 /* Test GetFullPathNameA functionality */
113   len=GetFullPathNameA(subpath,MAX_PATH,tmpstr,&strptr);
114   ok(len, "GetFullPathNameA failed for: '%s'",subpath);
115   if(HAS_TRAIL_SLASH_A(subpath)) {
116 /* Wine strips off the trailing '\\'. Neither Win98 nor Win2k do this. */
117     todo_wine {
118       ok(strptr==NULL,
119          "%s: GetFullPathNameA should not return a filename ptr",errstr);
120       ok(lstrcmpiA(fullpath,tmpstr)==0,
121          "%s: GetFullPathNameA returned '%s' instead of '%s'",
122          errstr,tmpstr,fullpath);
123     }
124   } else {
125     ok(lstrcmpiA(strptr,filename)==0,
126        "%s: GetFullPathNameA returned '%s' instead of '%s'",
127        errstr,strptr,filename);
128     ok(lstrcmpiA(fullpath,tmpstr)==0,
129        "%s: GetFullPathNameA returned '%s' instead of '%s'",
130        errstr,tmpstr,fullpath);
131   }
132 /* Test GetShortPathNameA functionality */
133   SetLastError(0);
134   len=GetShortPathNameA(fullpathshort,shortstr,MAX_PATH);
135   if(passfail==NULL) {
136     ok(len, "%s: GetShortPathNameA failed",errstr);
137   } else {
138     passfail->shortlen=len;
139     passfail->shorterror=GetLastError();
140   }
141 /* Test GetLongPathNameA functionality
142    We test both conversion from GetFullPathNameA and from GetShortPathNameA
143 */
144   if(pGetLongPathNameA) {
145     if(len==0) {
146       SetLastError(0);
147       len=pGetLongPathNameA(shortstr,tmpstr,MAX_PATH);
148       if(passfail==NULL) {
149         ok(len,
150           "%s: GetLongPathNameA failed during Short->Long conversion", errstr);
151         ok(lstrcmpiA(fullpathlong,tmpstr)==0,
152            "%s: GetLongPathNameA returned '%s' instead of '%s'",
153            errstr,tmpstr,fullpathlong);
154       } else {
155         passfail->s2llen=len;
156         passfail->s2lerror=GetLastError();
157       }
158     }
159     SetLastError(0);
160     len=pGetLongPathNameA(fullpath,tmpstr,MAX_PATH);
161     if(passfail==NULL) {
162       ok(len, "%s: GetLongPathNameA failed",errstr);
163       if(HAS_TRAIL_SLASH_A(fullpath)) {
164 /* Wine strips off the trailing '\\'  Neither Win98 nor Win2k do this */
165         todo_wine {
166           ok(lstrcmpiA(fullpathlong,tmpstr)==0,
167            "%s: GetLongPathNameA returned '%s' instead of '%s'",
168            errstr,tmpstr,fullpathlong);
169         }
170       } else {
171         ok(lstrcmpiA(fullpathlong,tmpstr)==0,
172           "%s: GetLongPathNameA returned '%s' instead of '%s'",
173           errstr,tmpstr,fullpathlong);
174       }
175     } else {
176       passfail->longlen=len;
177       passfail->longerror=GetLastError();
178     }
179   }
180 }
181
182 /* split path into leading directory, and 8.3 filename */
183 static void test_SplitShortPathA(CHAR *path,CHAR *dir,CHAR *eight,CHAR *three) {
184   DWORD len,done,error;
185   DWORD ext,fil;
186   INT i;
187   len=lstrlenA(path);
188   ext=len; fil=len; done=0; error=0;
189 /* walk backwards over path looking for '.' or '\\' seperators */
190   for(i=len-1;(i>=0) && (!done);i--) {
191     if(path[i]=='.')
192       if(ext!=len) error=1; else ext=i;
193     else if(path[i]=='\\') {
194       if(i==len-1) {
195         error=1;
196       } else {
197         fil=i;
198         done=1;
199       }
200     }
201   }
202 /* Check that we didn't find a trailing '\\' or multiple '.' */
203   ok(!error,"Illegal file found in 8.3 path '%s'",path);
204 /* Seperate dir, root, and extension */
205   if(ext!=len) lstrcpyA(three,path+ext+1); else lstrcpyA(three,"");
206   if(fil!=len) {
207     lstrcpynA(eight,path+fil+1,ext-fil);
208     lstrcpynA(dir,path,fil+1);
209   } else {
210     lstrcpynA(eight,path,ext+1);
211     lstrcpyA(dir,"");
212   }
213 /* Validate that root and extension really are 8.3 */
214   ok(lstrlenA(eight)<=8 && lstrlenA(three)<=3,
215      "GetShortPathNAmeA did not return an 8.3 path");
216 }
217
218 /* Check that GetShortPathNameA returns a valid 8.3 path */
219 static void test_LongtoShortA(CHAR *teststr,CHAR *goodstr,
220                               CHAR *ext,CHAR *errstr) {
221   CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
222
223   test_SplitShortPathA(teststr,dir,eight,three);
224   ok(lstrcmpiA(dir,goodstr)==0,
225      "GetShortPathNameA returned '%s' instead of '%s'",dir,goodstr);
226   ok(lstrcmpiA(three,ext)==0,
227      "GetShortPathNameA returned '%s' with incorrect extension",three);
228 }
229
230 /* Test that Get(Short|Long|Full)PathNameA work correctly with interesting
231    characters in the filename.
232      'valid' indicates whether this would be an allowed filename
233      'todo' indictaes that wine doesn't get this right yet.
234    NOTE: We always call this routine with a non-existant filename, so
235          Get(Short|Long)PathNameA should never pass, but GetFullPathNameA
236          should.
237 */
238 static void test_FunnyChars(CHAR *curdir,CHAR *filename,
239                              INT valid,INT todo,CHAR *errstr) {
240   CHAR tmpstr[MAX_PATH];
241   SLpassfail passfail;
242
243   test_ValidPathA(curdir,"",filename,tmpstr,&passfail,errstr);
244   if(todo) {
245     todo_wine {
246       ok(passfail.shortlen==0,
247          "%s: GetShortPathNameA passed when it shouldn't have",errstr);
248     }
249   } else {
250     ok(passfail.shortlen==0,
251        "%s: GetShortPathNameA passed when it shouldn't have",errstr);
252   }
253   if(valid) {
254     if(todo) {
255       todo_wine {
256         ok(passfail.shorterror==ERROR_FILE_NOT_FOUND,
257            "%s: GetShortPathA returned %ld and not %d",
258            errstr,passfail.shorterror,ERROR_FILE_NOT_FOUND);
259       }
260     } else {
261       ok(passfail.shorterror==ERROR_FILE_NOT_FOUND,
262          "%s: GetShortPathA returned %ld and not %d",
263           errstr,passfail.shorterror,ERROR_FILE_NOT_FOUND);
264     }
265   } else {
266     if(todo) {
267       todo_wine {
268 /* Win2k returns ERROR_INVALID_NAME, Win98, wine return ERROR_FILE_NOT_FOUND */
269         ok(passfail.shorterror==ERROR_INVALID_NAME ||
270            passfail.shorterror==ERROR_FILE_NOT_FOUND,
271            "%s: GetShortPathA returned %ld and not %d or %d",
272            errstr,passfail.shorterror,ERROR_INVALID_NAME,ERROR_FILE_NOT_FOUND);
273       }
274     } else {
275       ok(passfail.shorterror==ERROR_INVALID_NAME ||
276          passfail.shorterror==ERROR_FILE_NOT_FOUND,
277          "%s: GetShortPathA returned %ld and not %d or %d",
278          errstr,passfail.shorterror,ERROR_INVALID_NAME,ERROR_FILE_NOT_FOUND);
279     }
280   }
281   if(pGetLongPathNameA) {
282     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
283     if(valid) {
284       ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
285          "%s: GetLongPathA returned %ld and not %d",
286          errstr,passfail.longerror,ERROR_FILE_NOT_FOUND);
287     } else {
288       ok(passfail.longerror==ERROR_INVALID_NAME ||
289          passfail.longerror==ERROR_FILE_NOT_FOUND,
290          "%s: GetLongPathA returned %ld and not %d or %d'",
291          errstr, passfail.longerror,ERROR_INVALID_NAME,ERROR_FILE_NOT_FOUND);
292     }
293   }
294 }
295
296 /* Routine to test that SetCurrentDirectory behaves as expected. */
297 static void test_setdir(CHAR *olddir,CHAR *newdir,
298                         CHAR *cmprstr, INT pass,CHAR *errstr)
299 {
300   CHAR tmppath[MAX_PATH], *dirptr;
301   DWORD val,len,chklen;
302
303   val=SetCurrentDirectoryA(newdir);
304   len=GetCurrentDirectoryA(MAX_PATH,tmppath);
305 /* if 'pass' then the SetDirectoryA was supposed to pass */
306   if(pass) {
307     dirptr=(cmprstr==NULL) ? newdir : cmprstr;
308     chklen=lstrlenA(dirptr);
309     ok(val,"%s: SetCurrentDirectoryA failed",errstr);
310     ok(len==chklen,
311        "%s: SetCurrentDirectory did not change the directory, though it passed",
312        errstr);
313     ok(lstrcmpiA(dirptr,tmppath)==0,
314        "%s: SetCurrentDirectory did not change the directory, though it passed",
315        errstr);
316     ok(SetCurrentDirectoryA(olddir),
317        "%s: Couldn't set directory to it's original value",errstr);
318   } else {
319 /* else thest that it fails correctly */
320     chklen=lstrlenA(olddir);
321     ok(val==0,
322        "%s: SetCurrentDirectoryA passed when it should have failed",errstr);
323     ok(len==chklen,
324        "%s: SetCurrentDirectory changed the directrory, though it failed",
325        errstr);
326     ok(lstrcmpiA(olddir,tmppath)==0,
327        "%s: SetCurrentDirectory changed the directrory, though it failed",
328        errstr);
329   }
330 }
331 static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive)
332 {
333   CHAR tmppath[MAX_PATH], /*path to TEMP */
334        tmpstr[MAX_PATH],
335        tmpstr1[MAX_PATH];
336   DWORD len,len1,drives;
337   INT id;
338   HANDLE hndl;
339
340   *curDrive = *otherDrive = NOT_A_VALID_DRIVE;
341
342 /* Get the current drive letter */
343   if( GetCurrentDirectoryA( MAX_PATH, tmpstr))
344     *curDrive = tmpstr[0];
345   else
346     trace( "Unable to discover current drive, some tests will not be conducted.\n");
347
348 /* Test GetTempPathA */
349   len=GetTempPathA(MAX_PATH,tmppath);
350   ok(len!=0 && len < MAX_PATH,"GetTempPathA failed");
351   ok(HAS_TRAIL_SLASH_A(tmppath),
352      "GetTempPathA returned a path that did not end in '\\'");
353   lstrcpyA(tmpstr,"aaaaaaaa");
354   len1=GetTempPathA(len,tmpstr);
355   ok(len1==len+1,
356      "GetTempPathA should return string length %ld instead of %ld",len+1,len1);
357   if(WIN2K_PLUS(version)) {
358 /* in Win2k, the path won't be modified, but in win98, wine  it is */
359     todo_wine {
360       ok(lstrcmpiA(tmpstr,"aaaaaaaa")==0,
361          "GetTempPathA should not have modified the buffer");
362     }
363   }
364 /* Test GetTmpFileNameA
365    The only test we do here is whether GetTempFileNameA passes or not.
366    We do not thoroughly test this function yet (specifically, whether
367    it behaves correctly when 'unique' is non zero)
368 */
369   ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed");
370   sprintf(tmpstr,"pat%.4x.tmp",id);
371   sprintf(tmpstr1,"pat%x.tmp",id);
372   ok(lstrcmpiA(newdir+(lstrlenA(newdir)-lstrlenA(tmpstr)),tmpstr)==0 ||
373      lstrcmpiA(newdir+(lstrlenA(newdir)-lstrlenA(tmpstr1)),tmpstr1)==0,
374      "GetTempPath returned '%s' which doesn't match '%s' or '%s'",
375      newdir,tmpstr,tmpstr1);
376
377 /* Find first valid drive letter that is neither newdir[0] nor curDrive */
378   drives = GetLogicalDrives() & ~(1<<(newdir[0]-'A'));
379   if( *curDrive != NOT_A_VALID_DRIVE)
380     drives &= ~(1<<(*curDrive-'A'));
381   if( drives)
382     for( *otherDrive='A'; (drives & 1) == 0; drives>>=1, (*otherDrive)++);
383   else
384     trace( "Could not find alternative drive, some tests will not be conducted.\n");
385
386 /* Do some CreateDirectoryA tests */
387 /* It would be nice to do test the SECURITY_ATTRIBUTES, but I don't
388    really understand how they work.
389    More formal tests should be done along with CreateFile tests
390 */
391   ok(CreateDirectoryA(newdir,NULL)==0,
392      "CreateDirectoryA succeeded even though a file of the same name exists");
393   ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created");
394   ok(CreateDirectoryA(newdir,NULL),"CreateDirectoryA failed");
395 /* Create some files to test other functions.  Note, we will test CreateFileA
396    at some later point
397 */
398   sprintf(tmpstr,"%s\\%s",newdir,SHORTDIR);
399   ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed");
400   sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
401   ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed");
402   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,SHORTFILE);
403   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
404                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,(HANDLE)NULL);
405   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed");
406   ok(CloseHandle(hndl),"CloseHandle failed");
407   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,LONGFILE);
408   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
409                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,(HANDLE)NULL);
410   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed");
411   ok(CloseHandle(hndl),"CloseHandle failed");
412   sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,SHORTFILE);
413   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
414                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,(HANDLE)NULL);
415   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed");
416   ok(CloseHandle(hndl),"CloseHandle failed");
417   sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,LONGFILE);
418   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
419                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,(HANDLE)NULL);
420   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed");
421   ok(CloseHandle(hndl),"CloseHandle failed");
422 }
423
424 /* Test GetCurrentDirectory & SetCurrentDirectory */
425 static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir)
426 {
427   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
428   DWORD len,len1;
429 /* Save the original directory, so that we can return to it at the end
430    of the test
431 */
432   len=GetCurrentDirectoryA(MAX_PATH,origdir);
433   ok(len!=0 && len < MAX_PATH,"GetCurrentDirectoryA failed");
434   ok(lstrcmpiA(origdir+(len-1),"\\")!=0,
435      "GetCurrentDirectoryA should not have a trailing \\");
436 /* Make sure that CetCurrentDirectoryA doesn't overwrite the buffer when the
437    buffer size is too small to hold the current directory
438 */
439   lstrcpyA(tmpstr,"aaaaaaa");
440   len1=GetCurrentDirectoryA(len,tmpstr);
441   ok(len1==len+1, "GetCurrentDirectoryA returned %ld instead of %ld",len1,len+1);
442   ok(lstrcmpiA(tmpstr,"aaaaaaa")==0,
443      "GetCurrentDirectoryA should not have modified the buffer");
444 /* SetCurrentDirectoryA shouldn't care whether the string has a
445    trailing '\\' or not
446 */
447   sprintf(tmpstr,"%s\\",newdir);
448   test_setdir(origdir,tmpstr,newdir,1,"check 1");
449   test_setdir(origdir,newdir,NULL,1,"check 2");
450 /* Set the directory to the working area.  We just tested that this works,
451    so why check it again.
452 */
453   SetCurrentDirectoryA(newdir);
454 /* Check that SetCurrentDirectory fails when a non-existant dir is specified */
455   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_SHORT);
456   test_setdir(newdir,tmpstr,NULL,0,"check 3");
457 /* Check that SetCurrentDirectory fails for a non-existant lond directory */
458   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_LONG);
459   test_setdir(newdir,tmpstr,NULL,0,"check 4");
460 /* Check that SetCurrentDirectory passes with a long directory */
461   sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
462   test_setdir(newdir,tmpstr,NULL,1,"check 5");
463 /* Check that SetCurrentDirectory passes with a short relative directory */
464   sprintf(tmpstr,"%s",SHORTDIR);
465   sprintf(tmpstr1,"%s\\%s",newdir,SHORTDIR);
466   test_setdir(newdir,tmpstr,tmpstr1,1,"check 6");
467 /* starting with a '.' */
468   sprintf(tmpstr,".\\%s",SHORTDIR);
469   test_setdir(newdir,tmpstr,tmpstr1,1,"check 7");
470 /* Check that SetCurrentDirectory passes with a short relative directory */
471   sprintf(tmpstr,"%s",LONGDIR);
472   sprintf(tmpstr1,"%s\\%s",newdir,LONGDIR);
473   test_setdir(newdir,tmpstr,tmpstr1,1,"check 8");
474 /* starting with a '.' */
475   sprintf(tmpstr,".\\%s",LONGDIR);
476   test_setdir(newdir,tmpstr,tmpstr1,1,"check 9");
477 }
478
479 /* Cleanup the mess we made while executing these tests */
480 static void test_CleanupPathA(CHAR *origdir, CHAR *curdir)
481 {
482   CHAR tmpstr[MAX_PATH];
483   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
484   ok(DeleteFileA(tmpstr),"DeleteFileA failed");
485   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,LONGFILE);
486   ok(DeleteFileA(tmpstr),"DeleteFileA failed");
487   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,SHORTFILE);
488   ok(DeleteFileA(tmpstr),"DeleteFileA failed");
489   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
490   ok(DeleteFileA(tmpstr),"DeleteFileA failed");
491   sprintf(tmpstr,"%s\\%s",curdir,SHORTDIR);
492   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed");
493   sprintf(tmpstr,"%s\\%s",curdir,LONGDIR);
494   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed");
495   ok(SetCurrentDirectoryA(origdir),"SetCurrentDirectoryA failed");
496   ok(RemoveDirectoryA(curdir),"RemoveDirectoryA failed");
497 }
498
499 /* This routine will test Get(Full|Short|Long)PathNameA */
500 static void test_PathNameA(CHAR *curdir, CHAR curDrive, CHAR otherDrive)
501 {
502   CHAR curdir_short[MAX_PATH],
503        longdir_short[MAX_PATH];
504   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
505   LPSTR strptr;                 /*ptr to the filename portion of the path */
506   DWORD len;
507   INT i;
508   CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
509   SLpassfail passfail;
510
511 /* Get the short form of the current directory */
512   ok((len=GetShortPathNameA(curdir,curdir_short,MAX_PATH)),
513      "GetShortPathNameA failed");
514   ok(!HAS_TRAIL_SLASH_A(curdir_short),
515      "GetShortPathNameA should not have a trailing \\");
516 /* Get the short form of the absolute-path to LONGDIR */
517   sprintf(tmpstr,"%s\\%s",curdir_short,LONGDIR);
518   ok((len=GetShortPathNameA(tmpstr,longdir_short,MAX_PATH)),
519      "GetShortPathNameA failed");
520   ok(lstrcmpiA(longdir_short+(len-1),"\\")!=0,
521      "GetShortPathNameA should not have a trailing \\");
522
523 /* Check the cases where both file and directory exist first */
524 /* Start with a 8.3 directory, 8.3 filename */
525   test_ValidPathA(curdir,SHORTDIR,SHORTFILE,tmpstr,NULL,"test1");
526   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,SHORTFILE);
527   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
528      "GetShortPathNameA returned '%s' instead of '%s'",tmpstr,tmpstr1);
529 /* Now try a 8.3 directory, long file name */
530   test_ValidPathA(curdir,SHORTDIR,LONGFILE,tmpstr,NULL,"test2");
531   sprintf(tmpstr1,"%s\\%s",curdir_short,SHORTDIR);
532   test_LongtoShortA(tmpstr,tmpstr1,"PAT","test2");
533 /* Next is a long directory, 8.3 file */
534   test_ValidPathA(curdir,LONGDIR,SHORTFILE,tmpstr,NULL,"test3");
535   sprintf(tmpstr1,"%s\\%s",longdir_short,SHORTFILE);
536   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
537      "GetShortPathNameA returned '%s' instead of '%s'",tmpstr,tmpstr1);
538 /*Lastly a long directory, long file */
539   test_ValidPathA(curdir,LONGDIR,LONGFILE,tmpstr,NULL,"test4");
540   test_LongtoShortA(tmpstr,longdir_short,"PAT","test4");
541
542 /* Now check all of the invalid file w/ valid directroy combinations */
543 /* Start with a 8.3 directory, 8.3 filename */
544   test_ValidPathA(curdir,SHORTDIR,NONFILE_SHORT,tmpstr,&passfail,"test5");
545   todo_wine {
546     ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have");
547     ok(passfail.shorterror==ERROR_FILE_NOT_FOUND,
548        "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'");
549   }
550   if(pGetLongPathNameA) {
551     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
552     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
553        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'");
554   }
555 /* Now try a 8.3 directory, long file name */
556   test_ValidPathA(curdir,SHORTDIR,NONFILE_LONG,tmpstr,&passfail,"test6");
557   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have");
558   ok(passfail.shorterror==ERROR_FILE_NOT_FOUND,
559      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'");
560   if(pGetLongPathNameA) {
561     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
562     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
563        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'");
564   }
565 /* Next is a long directory, 8.3 file */
566   test_ValidPathA(curdir,LONGDIR,NONFILE_SHORT,tmpstr,&passfail,"test7");
567   todo_wine {
568     ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have");
569     ok(passfail.shorterror==ERROR_FILE_NOT_FOUND,
570        "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'");
571   }
572   if(pGetLongPathNameA) {
573     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
574     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
575       "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'");
576   }
577 /*Lastly a long directory, long file */
578   test_ValidPathA(curdir,LONGDIR,NONFILE_LONG,tmpstr,&passfail,"test8");
579   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have");
580   ok(passfail.shorterror==ERROR_FILE_NOT_FOUND,
581      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'");
582   if(pGetLongPathNameA) {
583     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
584     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
585        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'");
586   }
587 /* Now try again with directories that don't exist */
588 /* 8.3 directory, 8.3 filename */
589   test_ValidPathA(curdir,NONDIR_SHORT,SHORTFILE,tmpstr,&passfail,"test9");
590   todo_wine {
591     ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have");
592     ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
593        passfail.shorterror==ERROR_FILE_NOT_FOUND,
594        "GetShortPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'",
595         passfail.shorterror);
596   }
597   if(pGetLongPathNameA) {
598     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
599     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
600        passfail.longerror==ERROR_FILE_NOT_FOUND,
601        "GetLongPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'",
602        passfail.longerror);
603   }
604 /* Now try a 8.3 directory, long file name */
605   test_ValidPathA(curdir,NONDIR_SHORT,LONGFILE,tmpstr,&passfail,"test10");
606   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have");
607   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
608      passfail.shorterror==ERROR_FILE_NOT_FOUND,
609      "GetShortPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'",
610       passfail.shorterror);
611   if(pGetLongPathNameA) {
612     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
613     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
614        passfail.longerror==ERROR_FILE_NOT_FOUND,
615        "GetLongPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'",
616        passfail.longerror);
617   }
618 /* Next is a long directory, 8.3 file */
619   test_ValidPathA(curdir,NONDIR_LONG,SHORTFILE,tmpstr,&passfail,"test11");
620   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have");
621   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
622      passfail.shorterror==ERROR_FILE_NOT_FOUND,
623      "GetShortPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'",
624       passfail.shorterror);
625   if(pGetLongPathNameA) {
626     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
627     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
628        passfail.longerror==ERROR_FILE_NOT_FOUND,
629        "GetLongPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'",
630        passfail.longerror);
631   }
632 /*Lastly a long directory, long file */
633   test_ValidPathA(curdir,NONDIR_LONG,LONGFILE,tmpstr,&passfail,"test12");
634   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have");
635   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
636      passfail.shorterror==ERROR_FILE_NOT_FOUND,
637      "GetShortPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'",
638       passfail.shorterror);
639   if(pGetLongPathNameA) {
640     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
641     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
642        passfail.longerror==ERROR_FILE_NOT_FOUND,
643        "GetLongPathA returned %ld and not 'ERROR_PATH_NOT_FOUND'",
644        passfail.longerror);
645   }
646 /* Next try directories ending with '\\' */
647 /* Existing Directories */
648   sprintf(tmpstr,"%s\\",SHORTDIR);
649   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test13");
650   sprintf(tmpstr,"%s\\",LONGDIR);
651   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test14");
652 /* Non-existant directories */
653   sprintf(tmpstr,"%s\\",NONDIR_SHORT);
654   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test15");
655   todo_wine {
656     ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have");
657     ok(passfail.shorterror==ERROR_FILE_NOT_FOUND,
658      "GetShortPathA returned %ld and not 'ERROR_FILE_NOT_FOUND'",
659       passfail.shorterror);
660   }
661   if(pGetLongPathNameA) {
662     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
663     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
664        "GetLongPathA returned %ld and not 'ERROR_FILE_NOT_FOUND'",
665        passfail.longerror);
666   }
667   sprintf(tmpstr,"%s\\",NONDIR_LONG);
668   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test16");
669   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have");
670   ok(passfail.shorterror==ERROR_FILE_NOT_FOUND,
671      "GetShortPathA returned %ld and not 'ERROR_FILE_NOT_FOUND'",
672       passfail.shorterror);
673   if(pGetLongPathNameA) {
674     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have");
675     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
676        "GetLongPathA returned %ld and not 'ERROR_FILE_NOT_FOUND'",
677        passfail.longerror);
678   }
679 /* Test GetFullPathNameA with drive letters */
680   if( curDrive != NOT_A_VALID_DRIVE) {
681     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
682     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed");
683     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
684        "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr);
685     ok(lstrcmpiA(SHORTFILE,strptr)==0,
686        "GetLongPathNameA returned part '%s' instead of '%s'",strptr,SHORTFILE);
687   }
688 /* Without a leading slash, insert the current directory if on the current drive */
689   sprintf(tmpstr,"%c:%s\\%s",curdir[0],SHORTDIR,SHORTFILE);
690   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed");
691   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
692   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
693       "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr);
694   ok(lstrcmpiA(SHORTFILE,strptr)==0,
695       "GetLongPathNameA returned part '%s' instead of '%s'",strptr,SHORTFILE);
696 /* Otherwise insert the missing leading slash */
697   if( otherDrive != NOT_A_VALID_DRIVE) {
698     sprintf(tmpstr,"%c:%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
699     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed for %s", tmpstr);
700     sprintf(tmpstr,"%c:\\%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
701     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
702        "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr);
703     ok(lstrcmpiA(SHORTFILE,strptr)==0,
704        "GetLongPathNameA returned part '%s' instead of '%s'",strptr,SHORTFILE);
705   }
706 /* Xilinx tools like to mix Unix and DOS formats, which Windows handles fine.
707    So test for them. */
708   if( curDrive != NOT_A_VALID_DRIVE) {
709     sprintf(tmpstr,"%c:/%s\\%s",curDrive,SHORTDIR,SHORTFILE);
710     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed");
711     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
712     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
713        "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr);
714     ok(lstrcmpiA(SHORTFILE,strptr)==0,
715        "GetLongPathNameA returned part '%s' instead of '%s'",strptr,SHORTFILE);
716   }
717 /**/
718   sprintf(tmpstr,"%c:%s/%s",curdir[0],SHORTDIR,SHORTFILE);
719   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed");
720   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
721   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
722       "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr);
723   ok(lstrcmpiA(SHORTFILE,strptr)==0,
724       "GetLongPathNameA returned part '%s' instead of '%s'",strptr,SHORTFILE);
725 /* Windows will insert a drive letter in front of an absolute UNIX path, but
726     Wine probably shouldn't. */
727   sprintf(tmpstr,"/%s/%s",SHORTDIR,SHORTFILE);
728   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed");
729   todo_wine {
730     if( curDrive != NOT_A_VALID_DRIVE) {
731       sprintf(tmpstr,"C:\\%s\\%s",SHORTDIR,SHORTFILE);
732       ok(lstrcmpiA(tmpstr,tmpstr1)==0,
733          "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr);
734     }
735   }
736 /* This passes in Wine because it still contains the pointer from the previous test */
737   ok(lstrcmpiA(SHORTFILE,strptr)==0,
738       "GetLongPathNameA returned part '%s' instead of '%s'",strptr,SHORTFILE);
739
740 /* Now try some relative paths */
741   ok(GetShortPathNameA(LONGDIR,tmpstr,MAX_PATH),"GetShortPathNameA failed");
742   test_SplitShortPathA(tmpstr,dir,eight,three);
743   if(pGetLongPathNameA) {
744     ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed");
745     todo_wine {
746       ok(lstrcmpiA(tmpstr1,LONGDIR)==0,
747          "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,LONGDIR);
748     }
749   }
750   sprintf(tmpstr,".\\%s",LONGDIR);
751   ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed");
752   test_SplitShortPathA(tmpstr1,dir,eight,three);
753   ok(lstrcmpiA(dir,".")==0,"GetShortPathNameA did not keep relative directory");
754   if(pGetLongPathNameA) {
755     ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetShortPathNameA failed");
756     todo_wine {
757       ok(lstrcmpiA(tmpstr1,tmpstr)==0,
758          "GetLongPathNameA returned '%s' instead of '%s'",tmpstr1,tmpstr);
759     }
760   }
761 /* Check out Get*PathNameA on some funny characters */
762   for(i=0;i<lstrlenA(funny_chars);i++) {
763     INT valid,todo;
764     valid=(is_char_ok[i]=='0') ? 0 : 1;
765     todo=(wine_todo[i]=='0') ? 0 : 1;
766     sprintf(tmpstr1,"check%d-1",i);
767     sprintf(tmpstr,"file%c000.ext",funny_chars[i]);
768     test_FunnyChars(curdir,tmpstr,valid,todo,tmpstr1);
769     sprintf(tmpstr1,"check%d-2",i);
770     sprintf(tmpstr,"file000.e%ct",funny_chars[i]);
771     test_FunnyChars(curdir,tmpstr,valid,todo,tmpstr1);
772     sprintf(tmpstr1,"check%d-3",i);
773     sprintf(tmpstr,"%cfile000.ext",funny_chars[i]);
774     test_FunnyChars(curdir,tmpstr,valid,todo,tmpstr1);
775     sprintf(tmpstr1,"check%d-4",i);
776     sprintf(tmpstr,"file000%c.ext",funny_chars[i]);
777     test_FunnyChars(curdir,tmpstr,valid,todo,tmpstr1);
778     sprintf(tmpstr1,"check%d-5",i);
779     sprintf(tmpstr,"Long %c File",funny_chars[i]);
780     test_FunnyChars(curdir,tmpstr,valid,0,tmpstr1);
781     sprintf(tmpstr1,"check%d-6",i);
782     sprintf(tmpstr,"%c Long File",funny_chars[i]);
783     test_FunnyChars(curdir,tmpstr,valid,0,tmpstr1);
784     sprintf(tmpstr1,"check%d-7",i);
785     sprintf(tmpstr,"Long File %c",funny_chars[i]);
786     test_FunnyChars(curdir,tmpstr,valid,0,tmpstr1);
787   }
788 /* ':' is a special case and is allowed only in certain cases */
789     test_FunnyChars(curdir,"file:000.ext",1,1,"check-1");
790     test_FunnyChars(curdir,"file000.e:t" ,1,1,"check-2");
791     test_FunnyChars(curdir,":file000.ext",0,1,"check-3");
792     test_FunnyChars(curdir,"file000:.ext",1,1,"check-4");
793     test_FunnyChars(curdir,"Long : File" ,1,0,"check-5");
794     test_FunnyChars(curdir,": Long File" ,0,0,"check-6");
795     test_FunnyChars(curdir,"Long File :" ,0,0,"check-7");
796 }
797
798 START_TEST(path)
799 {
800     CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
801     version.dwOSVersionInfoSize=sizeof(OSVERSIONINFOA);
802     ok(GetVersionExA(&version),"GetVersionEx failed: %ld",GetLastError());
803     pGetLongPathNameA = (void*)GetProcAddress( GetModuleHandleA("kernel32.dll"),
804                                                "GetLongPathNameA" );
805     test_InitPathA(curdir, &curDrive, &otherDrive);
806     test_CurrentDirectoryA(origdir,curdir);
807     test_PathNameA(curdir, curDrive, otherDrive);
808     test_CleanupPathA(origdir,curdir);
809 }