Fix harmless Clang warning about an unused function.
[wxWidgets.git] / tests / filename / filenametest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/filename/filename.cpp
3 // Purpose: wxFileName unit test
4 // Author: Vadim Zeitlin
5 // Created: 2004-07-25
6 // RCS-ID: $Id$
7 // Copyright: (c) 2004 Vadim Zeitlin
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // ----------------------------------------------------------------------------
11 // headers
12 // ----------------------------------------------------------------------------
13
14 #include "testprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 #ifndef WX_PRECOMP
21 #include "wx/utils.h"
22 #endif // WX_PRECOMP
23
24 #include "wx/filename.h"
25 #include "wx/filefn.h"
26 #include "wx/stdpaths.h"
27 #include "wx/scopeguard.h"
28
29 #ifdef __WINDOWS__
30 #include "wx/msw/registry.h"
31 #endif // __WINDOWS__
32
33 #ifdef __UNIX__
34 #include <unistd.h>
35 #endif // __UNIX__
36
37 #include "testfile.h"
38 #include "testdate.h"
39
40 // ----------------------------------------------------------------------------
41 // test data
42 // ----------------------------------------------------------------------------
43
44 static struct TestFileNameInfo
45 {
46 const char *fullname;
47 const char *volume;
48 const char *path;
49 const char *name;
50 const char *ext;
51 bool isAbsolute;
52 wxPathFormat format;
53 } filenames[] =
54 {
55 // the empty string
56 { "", "", "", "", "", false, wxPATH_UNIX },
57 { "", "", "", "", "", false, wxPATH_DOS },
58 { "", "", "", "", "", false, wxPATH_VMS },
59
60 // Unix file names
61 { "/usr/bin/ls", "", "/usr/bin", "ls", "", true, wxPATH_UNIX },
62 { "/usr/bin/", "", "/usr/bin", "", "", true, wxPATH_UNIX },
63 { "~/.zshrc", "", "~", ".zshrc", "", true, wxPATH_UNIX },
64 { "../../foo", "", "../..", "foo", "", false, wxPATH_UNIX },
65 { "foo.bar", "", "", "foo", "bar", false, wxPATH_UNIX },
66 { "~/foo.bar", "", "~", "foo", "bar", true, wxPATH_UNIX },
67 { "~user/foo.bar", "", "~user", "foo", "bar", true, wxPATH_UNIX },
68 { "~user/", "", "~user", "", "", true, wxPATH_UNIX },
69 { "/foo", "", "/", "foo", "", true, wxPATH_UNIX },
70 { "Mahogany-0.60/foo.bar", "", "Mahogany-0.60", "foo", "bar", false, wxPATH_UNIX },
71 { "/tmp/wxwin.tar.bz", "", "/tmp", "wxwin.tar", "bz", true, wxPATH_UNIX },
72
73 // Windows file names
74 { "foo.bar", "", "", "foo", "bar", false, wxPATH_DOS },
75 { "\\foo.bar", "", "\\", "foo", "bar", false, wxPATH_DOS },
76 { "c:foo.bar", "c", "", "foo", "bar", false, wxPATH_DOS },
77 { "c:\\foo.bar", "c", "\\", "foo", "bar", true, wxPATH_DOS },
78 { "c:\\Windows\\command.com", "c", "\\Windows", "command", "com", true, wxPATH_DOS },
79 { "\\\\?\\Volume{8089d7d7-d0ac-11db-9dd0-806d6172696f}\\",
80 "Volume{8089d7d7-d0ac-11db-9dd0-806d6172696f}", "\\", "", "", true, wxPATH_DOS },
81 { "\\\\?\\Volume{8089d7d7-d0ac-11db-9dd0-806d6172696f}\\Program Files\\setup.exe",
82 "Volume{8089d7d7-d0ac-11db-9dd0-806d6172696f}", "\\Program Files", "setup", "exe", true, wxPATH_DOS },
83
84 #if 0
85 // NB: when using the wxFileName::GetLongPath() function on these two
86 // strings, the program will hang for several seconds blocking inside
87 // Win32 GetLongPathName() function
88 { "\\\\server\\foo.bar", "server", "\\", "foo", "bar", true, wxPATH_DOS },
89 { "\\\\server\\dir\\foo.bar", "server", "\\dir", "foo", "bar", true, wxPATH_DOS },
90 #endif
91
92 // consecutive [back]slashes should be treated as single occurrences of
93 // them and not interpreted as share names if there is a volume name
94 { "c:\\aaa\\bbb\\ccc", "c", "\\aaa\\bbb", "ccc", "", true, wxPATH_DOS },
95 { "c:\\\\aaa\\bbb\\ccc", "c", "\\\\aaa\\bbb", "ccc", "", true, wxPATH_DOS },
96
97 // wxFileName support for Mac file names is broken currently
98 #if 0
99 // Mac file names
100 { "Volume:Dir:File", "Volume", "Dir", "File", "", true, wxPATH_MAC },
101 { "Volume:Dir:Subdir:File", "Volume", "Dir:Subdir", "File", "", true, wxPATH_MAC },
102 { "Volume:", "Volume", "", "", "", true, wxPATH_MAC },
103 { ":Dir:File", "", "Dir", "File", "", false, wxPATH_MAC },
104 { ":File.Ext", "", "", "File", ".Ext", false, wxPATH_MAC },
105 { "File.Ext", "", "", "File", ".Ext", false, wxPATH_MAC },
106 #endif // 0
107
108 #if 0
109 // VMS file names
110 // NB: on Windows they have the same effect of the \\server\\ strings
111 // (see the note above)
112 { "device:[dir1.dir2.dir3]file.txt", "device", "dir1.dir2.dir3", "file", "txt", true, wxPATH_VMS },
113 #endif
114 { "file.txt", "", "", "file", "txt", false, wxPATH_VMS },
115 };
116
117 // ----------------------------------------------------------------------------
118 // test class
119 // ----------------------------------------------------------------------------
120
121 class FileNameTestCase : public CppUnit::TestCase
122 {
123 public:
124 FileNameTestCase() { }
125
126 private:
127 CPPUNIT_TEST_SUITE( FileNameTestCase );
128 CPPUNIT_TEST( TestConstruction );
129 CPPUNIT_TEST( TestComparison );
130 CPPUNIT_TEST( TestSplit );
131 CPPUNIT_TEST( TestSetPath );
132 CPPUNIT_TEST( TestStrip );
133 CPPUNIT_TEST( TestNormalize );
134 CPPUNIT_TEST( TestReplace );
135 CPPUNIT_TEST( TestGetHumanReadable );
136 #ifdef __WINDOWS__
137 CPPUNIT_TEST( TestShortLongPath );
138 #endif // __WINDOWS__
139 CPPUNIT_TEST( TestUNC );
140 CPPUNIT_TEST( TestVolumeUniqueName );
141 CPPUNIT_TEST( TestCreateTempFileName );
142 CPPUNIT_TEST( TestGetTimes );
143 CPPUNIT_TEST( TestSetTimes );
144 CPPUNIT_TEST( TestExists );
145 CPPUNIT_TEST( TestIsSame );
146 #if defined(__UNIX__)
147 CPPUNIT_TEST( TestSymlinks );
148 #endif // __UNIX__
149 CPPUNIT_TEST_SUITE_END();
150
151 void TestConstruction();
152 void TestComparison();
153 void TestSplit();
154 void TestSetPath();
155 void TestStrip();
156 void TestNormalize();
157 void TestReplace();
158 void TestGetHumanReadable();
159 #ifdef __WINDOWS__
160 void TestShortLongPath();
161 #endif // __WINDOWS__
162 void TestUNC();
163 void TestVolumeUniqueName();
164 void TestCreateTempFileName();
165 void TestGetTimes();
166 void TestSetTimes();
167 void TestExists();
168 void TestIsSame();
169 #if defined(__UNIX__)
170 void TestSymlinks();
171 #endif // __UNIX__
172
173 DECLARE_NO_COPY_CLASS(FileNameTestCase)
174 };
175
176 // register in the unnamed registry so that these tests are run by default
177 CPPUNIT_TEST_SUITE_REGISTRATION( FileNameTestCase );
178
179 // also include in its own registry so that these tests can be run alone
180 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( FileNameTestCase, "FileNameTestCase" );
181
182 void FileNameTestCase::TestConstruction()
183 {
184 for ( size_t n = 0; n < WXSIZEOF(filenames); n++ )
185 {
186 const TestFileNameInfo& fni = filenames[n];
187
188 wxFileName fn(fni.fullname, fni.format);
189
190 // the original full name could contain consecutive [back]slashes,
191 // squeeze them except for the double backslash in the beginning in
192 // Windows filenames where it has special meaning
193 wxString fullnameOrig;
194 if ( fni.format == wxPATH_DOS )
195 {
196 // copy the backslashes at beginning unchanged
197 const char *p = fni.fullname;
198 while ( *p == '\\' )
199 fullnameOrig += *p++;
200
201 // replace consecutive slashes with single ones in the rest
202 for ( char chPrev = '\0'; *p; p++ )
203 {
204 if ( *p == '\\' && chPrev == '\\' )
205 continue;
206
207 chPrev = *p;
208 fullnameOrig += chPrev;
209 }
210 }
211 else // !wxPATH_DOS
212 {
213 fullnameOrig = fni.fullname;
214 }
215
216 fullnameOrig.Replace("//", "/");
217
218
219 wxString fullname = fn.GetFullPath(fni.format);
220 CPPUNIT_ASSERT_EQUAL( fullnameOrig, fullname );
221
222 // notice that we use a dummy working directory to ensure that paths
223 // with "../.." in them could be normalized, otherwise this would fail
224 // if the test is run from root directory or its direct subdirectory
225 CPPUNIT_ASSERT_MESSAGE
226 (
227 (const char *)wxString::Format("Normalize(%s) failed", fni.fullname).mb_str(),
228 fn.Normalize(wxPATH_NORM_ALL, "/foo/bar/baz", fni.format)
229 );
230
231 if ( *fni.volume && *fni.path )
232 {
233 // check that specifying the volume separately or as part of the
234 // path doesn't make any difference
235 wxString pathWithVolume = fni.volume;
236 pathWithVolume += wxFileName::GetVolumeSeparator(fni.format);
237 pathWithVolume += fni.path;
238
239 CPPUNIT_ASSERT_EQUAL( wxFileName(pathWithVolume,
240 fni.name,
241 fni.ext,
242 fni.format), fn );
243 }
244 }
245
246 wxFileName fn;
247
248 // empty strings
249 fn.AssignDir(wxEmptyString);
250 CPPUNIT_ASSERT( !fn.IsOk() );
251
252 fn.Assign(wxEmptyString);
253 CPPUNIT_ASSERT( !fn.IsOk() );
254
255 fn.Assign(wxEmptyString, wxEmptyString);
256 CPPUNIT_ASSERT( !fn.IsOk() );
257
258 fn.Assign(wxEmptyString, wxEmptyString, wxEmptyString);
259 CPPUNIT_ASSERT( !fn.IsOk() );
260
261 fn.Assign(wxEmptyString, wxEmptyString, wxEmptyString, wxEmptyString);
262 CPPUNIT_ASSERT( !fn.IsOk() );
263 }
264
265 void FileNameTestCase::TestComparison()
266 {
267 wxFileName fn1(wxT("/tmp/file1"));
268 wxFileName fn2(wxT("/tmp/dir2/../file2"));
269 fn1.Normalize();
270 fn2.Normalize();
271 CPPUNIT_ASSERT_EQUAL(fn1.GetPath(), fn2.GetPath());
272 }
273
274 void FileNameTestCase::TestSplit()
275 {
276 for ( size_t n = 0; n < WXSIZEOF(filenames); n++ )
277 {
278 const TestFileNameInfo& fni = filenames[n];
279 wxString volume, path, name, ext;
280 wxFileName::SplitPath(fni.fullname,
281 &volume, &path, &name, &ext, fni.format);
282
283 CPPUNIT_ASSERT_EQUAL( wxString(fni.volume), volume );
284 CPPUNIT_ASSERT_EQUAL( wxString(fni.path), path );
285 CPPUNIT_ASSERT_EQUAL( wxString(fni.name), name );
286 CPPUNIT_ASSERT_EQUAL( wxString(fni.ext), ext );
287 }
288
289 // special case of empty extension
290 wxFileName fn("foo.");
291 CPPUNIT_ASSERT_EQUAL( wxString("foo."), fn.GetFullPath() );
292 }
293
294 void FileNameTestCase::TestSetPath()
295 {
296 wxFileName fn("d:\\test\\foo.bar", wxPATH_DOS);
297 fn.SetPath("c:\\temp", wxPATH_DOS);
298 CPPUNIT_ASSERT( fn.SameAs(wxFileName("c:\\temp\\foo.bar", wxPATH_DOS)) );
299
300 fn = wxFileName("/usr/bin/ls", wxPATH_UNIX);
301 fn.SetPath("/usr/local/bin", wxPATH_UNIX);
302 CPPUNIT_ASSERT( fn.SameAs(wxFileName("/usr/local/bin/ls", wxPATH_UNIX)) );
303 }
304
305 void FileNameTestCase::TestNormalize()
306 {
307 // prepare some data to be used later
308 wxString sep = wxFileName::GetPathSeparator();
309 wxString cwd = wxGetCwd();
310 wxString home = wxGetUserHome();
311
312 cwd.Replace(sep, wxT("/"));
313 if (cwd.Last() != wxT('/'))
314 cwd += wxT('/');
315 home.Replace(sep, wxT("/"));
316 if (home.Last() != wxT('/'))
317 home += wxT('/');
318
319 // since we will always be testing paths using the wxPATH_UNIX
320 // format, we need to remove the volume, if present
321 if (home.Contains(wxT(':')))
322 home = home.AfterFirst(wxT(':'));
323 if (cwd.Contains(wxT(':')))
324 cwd = cwd.AfterFirst(wxT(':'));
325
326 static const struct FileNameTest
327 {
328 const char *original;
329 int flags;
330 const char *expected;
331 wxPathFormat fmt;
332 } tests[] =
333 {
334 // test wxPATH_NORM_ENV_VARS
335 #ifdef __WINDOWS__
336 { "%ABCDEF%/g/h/i", wxPATH_NORM_ENV_VARS, "abcdef/g/h/i", wxPATH_UNIX },
337 #else
338 { "$(ABCDEF)/g/h/i", wxPATH_NORM_ENV_VARS, "abcdef/g/h/i", wxPATH_UNIX },
339 #endif
340
341 // test wxPATH_NORM_DOTS
342 { "a/.././b/c/../../", wxPATH_NORM_DOTS, "", wxPATH_UNIX },
343 { "", wxPATH_NORM_DOTS, "", wxPATH_UNIX },
344 { "./foo", wxPATH_NORM_DOTS, "foo", wxPATH_UNIX },
345 { "b/../bar", wxPATH_NORM_DOTS, "bar", wxPATH_UNIX },
346 { "c/../../quux", wxPATH_NORM_DOTS, "../quux", wxPATH_UNIX },
347 { "/c/../../quux", wxPATH_NORM_DOTS, "/quux", wxPATH_UNIX },
348
349 // test wxPATH_NORM_TILDE: notice that ~ is only interpreted specially
350 // when it is the first character in the file name
351 { "/a/b/~", wxPATH_NORM_TILDE, "/a/b/~", wxPATH_UNIX },
352 { "/~/a/b", wxPATH_NORM_TILDE, "/~/a/b", wxPATH_UNIX },
353 { "~/a/b", wxPATH_NORM_TILDE, "HOME/a/b", wxPATH_UNIX },
354
355 // test wxPATH_NORM_CASE
356 { "Foo", wxPATH_NORM_CASE, "Foo", wxPATH_UNIX },
357 { "Foo", wxPATH_NORM_CASE, "foo", wxPATH_DOS },
358 { "C:\\Program Files\\wx", wxPATH_NORM_CASE,
359 "c:\\program files\\wx", wxPATH_DOS },
360 { "C:/Program Files/wx", wxPATH_NORM_ALL | wxPATH_NORM_CASE,
361 "c:\\program files\\wx", wxPATH_DOS },
362 { "C:\\Users\\zeitlin", wxPATH_NORM_ALL | wxPATH_NORM_CASE,
363 "c:\\users\\zeitlin", wxPATH_DOS },
364
365 // test wxPATH_NORM_ABSOLUTE
366 { "a/b/", wxPATH_NORM_ABSOLUTE, "CWD/a/b/", wxPATH_UNIX },
367 { "a/b/c.ext", wxPATH_NORM_ABSOLUTE, "CWD/a/b/c.ext", wxPATH_UNIX },
368 { "/a", wxPATH_NORM_ABSOLUTE, "/a", wxPATH_UNIX },
369
370 // test giving no flags at all to Normalize()
371 { "a/b/", 0, "a/b/", wxPATH_UNIX },
372 { "a/b/c.ext", 0, "a/b/c.ext", wxPATH_UNIX },
373 { "/a", 0, "/a", wxPATH_UNIX },
374
375 // test handling dots without wxPATH_NORM_DOTS and wxPATH_NORM_ABSOLUTE
376 // for both existing and non-existent files (this is important under
377 // MSW where GetLongPathName() works only for the former)
378 { "./foo", wxPATH_NORM_LONG, "./foo", wxPATH_UNIX },
379 { "../foo", wxPATH_NORM_LONG, "../foo", wxPATH_UNIX },
380 { ".\\test.bkl", wxPATH_NORM_LONG, ".\\test.bkl", wxPATH_DOS },
381 { ".\\foo", wxPATH_NORM_LONG, ".\\foo", wxPATH_DOS },
382 { "..\\Makefile.in", wxPATH_NORM_LONG, "..\\Makefile.in", wxPATH_DOS },
383 { "..\\foo", wxPATH_NORM_LONG, "..\\foo", wxPATH_DOS },
384 };
385
386 // set the env var ABCDEF
387 wxSetEnv("ABCDEF", "abcdef");
388
389 for ( size_t i = 0; i < WXSIZEOF(tests); i++ )
390 {
391 const FileNameTest& fnt = tests[i];
392 wxFileName fn(fnt.original, fnt.fmt);
393
394 // be sure this normalization does not fail
395 WX_ASSERT_MESSAGE
396 (
397 ("#%d: Normalize(%s) failed", (int)i, fnt.original),
398 fn.Normalize(fnt.flags, cwd, fnt.fmt)
399 );
400
401 // compare result with expected string
402 wxString expected(tests[i].expected);
403 expected.Replace("HOME/", home);
404 expected.Replace("CWD/", cwd);
405 WX_ASSERT_EQUAL_MESSAGE
406 (
407 ("array element #%d", (int)i),
408 expected, fn.GetFullPath(fnt.fmt)
409 );
410 }
411
412 // MSW-only test for wxPATH_NORM_LONG: notice that we only run it if short
413 // names generation is not disabled for this system as otherwise the file
414 // MKINST~1 doesn't exist at all and normalizing it fails (it's possible
415 // that we're on a FAT partition in which case the test would still succeed
416 // and also that the registry key was changed recently and didn't take
417 // effect yet but these are marginal cases which we consciously choose to
418 // ignore for now)
419 #ifdef __WINDOWS__
420 long shortNamesDisabled;
421 if ( wxRegKey
422 (
423 wxRegKey::HKLM,
424 "SYSTEM\\CurrentControlSet\\Control\\FileSystem"
425 ).QueryValue("NtfsDisable8dot3NameCreation", &shortNamesDisabled) &&
426 !shortNamesDisabled )
427 {
428 wxFileName fn("..\\MKINST~1");
429 CPPUNIT_ASSERT( fn.Normalize(wxPATH_NORM_LONG, cwd) );
430 CPPUNIT_ASSERT_EQUAL( "..\\mkinstalldirs", fn.GetFullPath() );
431 }
432 //else: when in doubt, don't run the test
433 #endif // __WINDOWS__
434 }
435
436 void FileNameTestCase::TestReplace()
437 {
438 static const struct FileNameTest
439 {
440 const char *original;
441 const char *env_contents;
442 const char *replace_fmtstring;
443 const char *expected;
444 wxPathFormat fmt;
445 } tests[] =
446 {
447 { "/usr/a/strange path/lib/someFile.ext", "/usr/a/strange path", "$%s", "$TEST_VAR/lib/someFile.ext", wxPATH_UNIX },
448 { "/usr/a/path/lib/someFile.ext", "/usr/a/path", "$%s", "$TEST_VAR/lib/someFile.ext", wxPATH_UNIX },
449 { "/usr/a/path/lib/someFile", "/usr/a/path/", "$%s", "$TEST_VARlib/someFile", wxPATH_UNIX },
450 { "/usr/a/path/lib/", "/usr/a/path/", "$(%s)", "$(TEST_VAR)lib/", wxPATH_UNIX },
451 { "/usr/a/path/lib/", "/usr/a/path/", "${{%s}}", "${{TEST_VAR}}lib/", wxPATH_UNIX },
452 { "/usr/a/path/lib/", "/usr/a/path/", "%s", "TEST_VARlib/", wxPATH_UNIX },
453 { "/usr/a/path/lib/", "/usr/a/path/", "%s//", "TEST_VAR/lib/", wxPATH_UNIX },
454 // note: empty directory components are automatically removed by wxFileName thus
455 // using // in the replace format string has no effect
456
457 { "/usr/../a/path/lib/", "/usr/a/path/", "%s", "/usr/../a/path/lib/", wxPATH_UNIX },
458 { "/usr/a/path/usr/usr", "/usr", "%s", "TEST_VAR/a/pathTEST_VAR/usr", wxPATH_UNIX },
459 { "/usr/a/path/usr/usr", "/usr", "$%s", "$TEST_VAR/a/path$TEST_VAR/usr", wxPATH_UNIX },
460 { "/a/b/c/d", "a/", "%s", "/TEST_VARb/c/d", wxPATH_UNIX },
461
462 { "C:\\A\\Strange Path\\lib\\someFile", "C:\\A\\Strange Path", "%%%s%%", "%TEST_VAR%\\lib\\someFile", wxPATH_WIN },
463 { "C:\\A\\Path\\lib\\someFile", "C:\\A\\Path", "%%%s%%", "%TEST_VAR%\\lib\\someFile", wxPATH_WIN },
464 { "C:\\A\\Path\\lib\\someFile", "C:\\A\\Path", "$(%s)", "$(TEST_VAR)\\lib\\someFile", wxPATH_WIN }
465 };
466
467 for ( size_t i = 0; i < WXSIZEOF(tests); i++ )
468 {
469 const FileNameTest& fnt = tests[i];
470 wxFileName fn(fnt.original, fnt.fmt);
471
472 // set the environment variable
473 wxSetEnv("TEST_VAR", fnt.env_contents);
474
475 // be sure this ReplaceEnvVariable does not fail
476 WX_ASSERT_MESSAGE
477 (
478 ("#%d: ReplaceEnvVariable(%s) failed", (int)i, fnt.replace_fmtstring),
479 fn.ReplaceEnvVariable("TEST_VAR", fnt.replace_fmtstring, fnt.fmt)
480 );
481
482 // compare result with expected string
483 wxString expected(fnt.expected);
484 WX_ASSERT_EQUAL_MESSAGE
485 (
486 ("array element #%d", (int)i),
487 expected, fn.GetFullPath(fnt.fmt)
488 );
489 }
490
491 // now test ReplaceHomeDir
492
493 wxFileName fn = wxFileName::DirName(wxGetHomeDir());
494 fn.AppendDir("test1");
495 fn.AppendDir("test2");
496 fn.AppendDir("test3");
497 fn.SetName("some file");
498
499 WX_ASSERT_MESSAGE
500 (
501 ("ReplaceHomeDir(%s) failed", fn.GetFullPath()),
502 fn.ReplaceHomeDir()
503 );
504
505 CPPUNIT_ASSERT_EQUAL( wxString("~/test1/test2/test3/some file"),
506 fn.GetFullPath(wxPATH_UNIX) );
507 }
508
509 void FileNameTestCase::TestGetHumanReadable()
510 {
511 static const struct TestData
512 {
513 const char *result;
514 int size;
515 int prec;
516 wxSizeConvention conv;
517 } testData[] =
518 {
519 { "NA", 0, 1, wxSIZE_CONV_TRADITIONAL },
520 { "2.0 KB", 2000, 1, wxSIZE_CONV_TRADITIONAL },
521 { "1.953 KiB", 2000, 3, wxSIZE_CONV_IEC },
522 { "2.000 KB", 2000, 3, wxSIZE_CONV_SI },
523 { "297 KB", 304351, 0, wxSIZE_CONV_TRADITIONAL },
524 { "304 KB", 304351, 0, wxSIZE_CONV_SI },
525 };
526
527 CLocaleSetter loc; // we want to use "C" locale for LC_NUMERIC
528 // so that regardless of the system's locale
529 // the decimal point used by GetHumanReadableSize()
530 // is always '.'
531 for ( unsigned n = 0; n < WXSIZEOF(testData); n++ )
532 {
533 const TestData& td = testData[n];
534
535 // take care of using the decimal point for the current locale before
536 // the actual comparison
537 CPPUNIT_ASSERT_EQUAL
538 (
539 td.result,
540 wxFileName::GetHumanReadableSize(td.size, "NA", td.prec, td.conv)
541 );
542 }
543
544 // also test the default convention value
545 CPPUNIT_ASSERT_EQUAL( "1.4 MB", wxFileName::GetHumanReadableSize(1512993, "") );
546 }
547
548 void FileNameTestCase::TestStrip()
549 {
550 CPPUNIT_ASSERT_EQUAL( "", wxFileName::StripExtension("") );
551 CPPUNIT_ASSERT_EQUAL( ".", wxFileName::StripExtension(".") );
552 CPPUNIT_ASSERT_EQUAL( ".vimrc", wxFileName::StripExtension(".vimrc") );
553 CPPUNIT_ASSERT_EQUAL( "bad", wxFileName::StripExtension("bad") );
554 CPPUNIT_ASSERT_EQUAL( "good", wxFileName::StripExtension("good.wav") );
555 CPPUNIT_ASSERT_EQUAL( "good.wav", wxFileName::StripExtension("good.wav.wav") );
556 }
557
558 #ifdef __WINDOWS__
559
560 void FileNameTestCase::TestShortLongPath()
561 {
562 wxFileName fn("C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe");
563
564 // incredibly enough, GetLongPath() used to return different results during
565 // the first and subsequent runs, test for this
566 CPPUNIT_ASSERT_EQUAL( fn.GetLongPath(), fn.GetLongPath() );
567 CPPUNIT_ASSERT_EQUAL( fn.GetShortPath(), fn.GetShortPath() );
568 }
569
570 #endif // __WINDOWS__
571
572 void FileNameTestCase::TestUNC()
573 {
574 wxFileName fn("//share/path/name.ext", wxPATH_DOS);
575 CPPUNIT_ASSERT_EQUAL( "share", fn.GetVolume() );
576 CPPUNIT_ASSERT_EQUAL( "\\path", fn.GetPath(wxPATH_NO_SEPARATOR, wxPATH_DOS) );
577
578 fn.Assign("\\\\share2\\path2\\name.ext", wxPATH_DOS);
579 CPPUNIT_ASSERT_EQUAL( "share2", fn.GetVolume() );
580 CPPUNIT_ASSERT_EQUAL( "\\path2", fn.GetPath(wxPATH_NO_SEPARATOR, wxPATH_DOS) );
581 }
582
583 void FileNameTestCase::TestVolumeUniqueName()
584 {
585 wxFileName fn("\\\\?\\Volume{8089d7d7-d0ac-11db-9dd0-806d6172696f}\\",
586 wxPATH_DOS);
587 CPPUNIT_ASSERT_EQUAL( "Volume{8089d7d7-d0ac-11db-9dd0-806d6172696f}",
588 fn.GetVolume() );
589 CPPUNIT_ASSERT_EQUAL( "\\", fn.GetPath(wxPATH_NO_SEPARATOR, wxPATH_DOS) );
590 CPPUNIT_ASSERT_EQUAL( "\\\\?\\Volume{8089d7d7-d0ac-11db-9dd0-806d6172696f}\\",
591 fn.GetFullPath(wxPATH_DOS) );
592
593 fn.Assign("\\\\?\\Volume{8089d7d7-d0ac-11db-9dd0-806d6172696f}\\"
594 "Program Files\\setup.exe", wxPATH_DOS);
595 CPPUNIT_ASSERT_EQUAL( "Volume{8089d7d7-d0ac-11db-9dd0-806d6172696f}",
596 fn.GetVolume() );
597 CPPUNIT_ASSERT_EQUAL( "\\Program Files",
598 fn.GetPath(wxPATH_NO_SEPARATOR, wxPATH_DOS) );
599 CPPUNIT_ASSERT_EQUAL( "\\\\?\\Volume{8089d7d7-d0ac-11db-9dd0-806d6172696f}\\"
600 "Program Files\\setup.exe",
601 fn.GetFullPath(wxPATH_DOS) );
602 }
603
604 void FileNameTestCase::TestCreateTempFileName()
605 {
606 static const struct TestData
607 {
608 const char *prefix;
609 const char *expectedFolder;
610 bool shouldSucceed;
611 } testData[] =
612 {
613 { "", "$SYSTEM_TEMP", true },
614 { "foo", "$SYSTEM_TEMP", true },
615 { "..", "$SYSTEM_TEMP", true },
616 { "../bar", "..", true },
617 #ifdef __WINDOWS__
618 { "$USER_DOCS_DIR\\", "$USER_DOCS_DIR", true },
619 { "c:\\a\\directory\\which\\does\\not\\exist", "", false },
620 #elif defined( __UNIX__ )
621 { "$USER_DOCS_DIR/", "$USER_DOCS_DIR", true },
622 { "/tmp/foo", "/tmp", true },
623 { "/tmp/a/directory/which/does/not/exist", "", false },
624 #endif // __UNIX__
625 };
626
627 for ( size_t n = 0; n < WXSIZEOF(testData); n++ )
628 {
629 wxString prefix = testData[n].prefix;
630 prefix.Replace("$USER_DOCS_DIR", wxStandardPaths::Get().GetDocumentsDir());
631
632 std::string errDesc = wxString::Format("failed on prefix '%s'", prefix).ToStdString();
633
634 wxString path = wxFileName::CreateTempFileName(prefix);
635 CPPUNIT_ASSERT_EQUAL_MESSAGE( errDesc, !testData[n].shouldSucceed, path.empty() );
636
637 if (testData[n].shouldSucceed)
638 {
639 errDesc += "; path is " + path.ToStdString();
640
641 // test the place where the temp file has been created
642 wxString expected = testData[n].expectedFolder;
643 expected.Replace("$SYSTEM_TEMP", wxStandardPaths::Get().GetTempDir());
644 expected.Replace("$USER_DOCS_DIR", wxStandardPaths::Get().GetDocumentsDir());
645 CPPUNIT_ASSERT_EQUAL_MESSAGE( errDesc, expected, wxFileName(path).GetPath() );
646
647 // the temporary file is created with full permissions for the current process
648 // so we should always be able to remove it:
649 CPPUNIT_ASSERT_MESSAGE( errDesc, wxRemoveFile(path) );
650 }
651 }
652 }
653
654 void FileNameTestCase::TestGetTimes()
655 {
656 wxFileName fn(wxFileName::CreateTempFileName("filenametest"));
657 CPPUNIT_ASSERT( fn.IsOk() );
658 wxON_BLOCK_EXIT1( wxRemoveFile, fn.GetFullPath() );
659
660 wxDateTime dtAccess, dtMod, dtCreate;
661 CPPUNIT_ASSERT( fn.GetTimes(&dtAccess, &dtMod, &dtCreate) );
662
663 // make sure all retrieved dates are equal to the current date&time
664 // with an accuracy up to 1 minute
665 CPPUNIT_ASSERT(dtCreate.IsEqualUpTo(wxDateTime::Now(), wxTimeSpan(0,1)));
666 CPPUNIT_ASSERT(dtMod.IsEqualUpTo(wxDateTime::Now(), wxTimeSpan(0,1)));
667 CPPUNIT_ASSERT(dtAccess.IsEqualUpTo(wxDateTime::Now(), wxTimeSpan(0,1)));
668 }
669
670 void FileNameTestCase::TestSetTimes()
671 {
672 wxFileName fn(wxFileName::CreateTempFileName("filenametest"));
673 CPPUNIT_ASSERT( fn.IsOk() );
674 wxON_BLOCK_EXIT1( wxRemoveFile, fn.GetFullPath() );
675
676 const wxDateTime dtAccess(1, wxDateTime::Jan, 2013);
677 const wxDateTime dtModify(1, wxDateTime::Feb, 2013);
678 const wxDateTime dtCreate(1, wxDateTime::Mar, 2013);
679
680 CPPUNIT_ASSERT( fn.SetTimes(&dtAccess, &dtModify, &dtCreate) );
681
682 wxDateTime dtAccess2,
683 dtModify2,
684 dtCreate2;
685 CPPUNIT_ASSERT( fn.GetTimes(&dtAccess2, &dtModify2, &dtCreate2) );
686 CPPUNIT_ASSERT_EQUAL( dtAccess, dtAccess2 );
687 CPPUNIT_ASSERT_EQUAL( dtModify, dtModify2 );
688
689 // Under Unix the creation time can't be set.
690 #ifdef __WINDOWS__
691 CPPUNIT_ASSERT_EQUAL( dtCreate, dtCreate2 );
692 #endif // __WINDOWS__
693 }
694
695 void FileNameTestCase::TestExists()
696 {
697 wxFileName fn(wxFileName::CreateTempFileName("filenametest"));
698 CPPUNIT_ASSERT( fn.IsOk() );
699 wxON_BLOCK_EXIT1( wxRemoveFile, fn.GetFullPath() );
700
701 CPPUNIT_ASSERT( fn.FileExists() );
702 CPPUNIT_ASSERT( !wxFileName::DirExists(fn.GetFullPath()) );
703
704 // FIXME-VC6: This compiler crashes with
705 //
706 // fatal error C1001: INTERNAL COMPILER ERROR
707 // (compiler file 'msc1.cpp', line 1794)
708 //
709 // when compiling calls to Exists() with parameter for some reason, just
710 // disable these tests there.
711 #ifndef __VISUALC6__
712 CPPUNIT_ASSERT( fn.Exists(wxFILE_EXISTS_REGULAR) );
713 CPPUNIT_ASSERT( !fn.Exists(wxFILE_EXISTS_DIR) );
714 #endif
715 CPPUNIT_ASSERT( fn.Exists() );
716
717 const wxString& tempdir = wxFileName::GetTempDir();
718
719 wxFileName fileInTempDir(tempdir, "bloordyblop");
720 CPPUNIT_ASSERT( !fileInTempDir.Exists() );
721 CPPUNIT_ASSERT( fileInTempDir.DirExists() );
722
723 wxFileName dirTemp(wxFileName::DirName(tempdir));
724 CPPUNIT_ASSERT( !dirTemp.FileExists() );
725 CPPUNIT_ASSERT( dirTemp.DirExists() );
726
727 #ifndef __VISUALC6__
728 CPPUNIT_ASSERT( dirTemp.Exists(wxFILE_EXISTS_DIR) );
729 CPPUNIT_ASSERT( !dirTemp.Exists(wxFILE_EXISTS_REGULAR) );
730 #endif
731 CPPUNIT_ASSERT( dirTemp.Exists() );
732
733 #ifdef __UNIX__
734 CPPUNIT_ASSERT( !wxFileName::FileExists("/dev/null") );
735 CPPUNIT_ASSERT( !wxFileName::DirExists("/dev/null") );
736 CPPUNIT_ASSERT( wxFileName::Exists("/dev/null") );
737 CPPUNIT_ASSERT( wxFileName::Exists("/dev/null", wxFILE_EXISTS_DEVICE) );
738 #ifdef __LINUX__
739 // These files are only guaranteed to exist under Linux.
740 // No need for wxFILE_EXISTS_NO_FOLLOW here; wxFILE_EXISTS_SYMLINK implies it
741 CPPUNIT_ASSERT( wxFileName::Exists("/dev/core", wxFILE_EXISTS_SYMLINK) );
742 CPPUNIT_ASSERT( wxFileName::Exists("/dev/log", wxFILE_EXISTS_SOCKET) );
743 #endif // __LINUX__
744 #ifndef __VMS
745 wxString fifo = dirTemp.GetPath() + "/fifo";
746 if (mkfifo(fifo.c_str(), 0600) == 0)
747 {
748 wxON_BLOCK_EXIT1(wxRemoveFile, fifo);
749
750 CPPUNIT_ASSERT( wxFileName::Exists(fifo, wxFILE_EXISTS_FIFO) );
751 }
752 #endif
753 #endif // __UNIX__
754 }
755
756 void FileNameTestCase::TestIsSame()
757 {
758 wxFileName fn1( wxFileName::CreateTempFileName( "filenametest1" ) );
759 CPPUNIT_ASSERT( fn1.IsOk() );
760 wxON_BLOCK_EXIT1( wxRemoveFile, fn1.GetFullPath() );
761
762 wxFileName fn2( wxFileName::CreateTempFileName( "filenametest2" ) );
763 CPPUNIT_ASSERT( fn2.IsOk() );
764 wxON_BLOCK_EXIT1( wxRemoveFile, fn2.GetFullPath() );
765
766 CPPUNIT_ASSERT( fn1.SameAs( fn1 ) );
767 CPPUNIT_ASSERT( !fn1.SameAs( fn2 ) );
768
769 #if defined(__UNIX__)
770 // We need to create a temporary directory and a temporary link.
771 // Unfortunately we can't use wxFileName::CreateTempFileName() for neither
772 // as it creates plain files, so use tempnam() explicitly instead.
773 char* tn = tempnam(NULL, "wxfn1");
774 const wxString tempdir1 = wxString::From8BitData(tn);
775 free(tn);
776
777 CPPUNIT_ASSERT( wxFileName::Mkdir(tempdir1) );
778 // Unfortunately the casts are needed to select the overload we need here.
779 wxON_BLOCK_EXIT2( static_cast<bool (*)(const wxString&, int)>(wxFileName::Rmdir),
780 tempdir1, static_cast<int>(wxPATH_RMDIR_RECURSIVE) );
781
782 tn = tempnam(NULL, "wxfn2");
783 const wxString tempdir2 = wxString::From8BitData(tn);
784 free(tn);
785 CPPUNIT_ASSERT_EQUAL( 0, symlink(tempdir1.c_str(), tempdir2.c_str()) );
786 wxON_BLOCK_EXIT1( wxRemoveFile, tempdir2 );
787
788
789 wxFileName fn3(tempdir1, "foo");
790 wxFileName fn4(tempdir2, "foo");
791
792 // These files have different paths, hence are different.
793 CPPUNIT_ASSERT( !fn3.SameAs(fn4) );
794
795 // Create and close a file to trigger creating it.
796 wxFile(fn3.GetFullPath(), wxFile::write);
797
798 // Now that both files do exist we should be able to detect that they are
799 // actually the same file.
800 CPPUNIT_ASSERT( fn3.SameAs(fn4) );
801 #endif // __UNIX__
802 }
803
804 #if defined(__UNIX__)
805
806 // Tests for functions that are changed by ShouldFollowLink()
807 void FileNameTestCase::TestSymlinks()
808 {
809 const wxString tmpdir(wxStandardPaths::Get().GetTempDir());
810
811 wxFileName tmpfn(wxFileName::DirName(tmpdir));
812
813 wxDateTime dtAccessTmp, dtModTmp, dtCreateTmp;
814 CPPUNIT_ASSERT(tmpfn.GetTimes(&dtAccessTmp, &dtModTmp, &dtCreateTmp));
815
816 // Create a temporary directory
817 #ifdef __VMS
818 wxString name = tmpdir + ".filenametestXXXXXX]";
819 mkdir( name.char_str() , 0222 );
820 wxString tempdir = name;
821 #else
822 wxString name = tmpdir + "/filenametestXXXXXX";
823 wxString tempdir = wxString::From8BitData(mkdtemp(name.char_str()));
824 tempdir << wxFileName::GetPathSeparator();
825 #endif
826 wxFileName tempdirfn(wxFileName::DirName(tempdir));
827 CPPUNIT_ASSERT(tempdirfn.DirExists());
828
829 // Create a regular file in that dir, to act as a symlink target
830 wxFileName targetfn(wxFileName::CreateTempFileName(tempdir));
831 CPPUNIT_ASSERT(targetfn.FileExists());
832
833 // Create a symlink to that file
834 wxFileName linktofile(tempdir, "linktofile");
835 CPPUNIT_ASSERT_EQUAL(0, symlink(targetfn.GetFullPath().c_str(),
836 linktofile.GetFullPath().c_str()));
837
838 // ... and another to the temporary directory
839 const wxString linktodirName(tempdir + "/linktodir");
840 wxFileName linktodir(wxFileName::DirName(linktodirName));
841 CPPUNIT_ASSERT_EQUAL(0, symlink(tmpfn.GetFullPath().c_str(),
842 linktodirName.c_str()));
843
844 // And symlinks to both of those symlinks
845 wxFileName linktofilelnk(tempdir, "linktofilelnk");
846 CPPUNIT_ASSERT_EQUAL(0, symlink(linktofile.GetFullPath().c_str(),
847 linktofilelnk.GetFullPath().c_str()));
848 wxFileName linktodirlnk(tempdir, "linktodirlnk");
849 CPPUNIT_ASSERT_EQUAL(0, symlink(linktodir.GetFullPath().c_str(),
850 linktodirlnk.GetFullPath().c_str()));
851
852 // Run the tests twice: once in the default symlink following mode and the
853 // second time without following symlinks.
854 bool deref = true;
855 for ( int n = 0; n < 2; ++n, deref = !deref )
856 {
857 const std::string msg(deref ? " failed for the link target"
858 : " failed for the path itself");
859
860 if ( !deref )
861 {
862 linktofile.DontFollowLink();
863 linktodir.DontFollowLink();
864 linktofilelnk.DontFollowLink();
865 linktodirlnk.DontFollowLink();
866 }
867
868 // Test SameAs()
869 CPPUNIT_ASSERT_EQUAL_MESSAGE
870 (
871 "Comparison with file" + msg,
872 deref, linktofile.SameAs(targetfn)
873 );
874
875 CPPUNIT_ASSERT_EQUAL_MESSAGE
876 (
877 "Comparison with directory" + msg,
878 deref, linktodir.SameAs(tmpfn)
879 );
880
881 // A link-to-a-link should dereference through to the final target
882 CPPUNIT_ASSERT_EQUAL_MESSAGE
883 (
884 "Comparison with link to a file" + msg,
885 deref,
886 linktofilelnk.SameAs(targetfn)
887 );
888 CPPUNIT_ASSERT_EQUAL_MESSAGE
889 (
890 "Comparison with link to a directory" + msg,
891 deref,
892 linktodirlnk.SameAs(tmpfn)
893 );
894
895 // Test GetTimes()
896 wxDateTime dtAccess, dtMod, dtCreate;
897 CPPUNIT_ASSERT_MESSAGE
898 (
899 "Getting times of a directory" + msg,
900 linktodir.GetTimes(&dtAccess, &dtMod, &dtCreate)
901 );
902
903 // IsEqualTo() should be true only when dereferencing. Don't test each
904 // individually: accessing to create the link will have updated some
905 bool equal = dtCreate.IsEqualTo(dtCreateTmp) &&
906 dtMod.IsEqualTo(dtModTmp) &&
907 dtAccess.IsEqualTo(dtAccessTmp);
908 CPPUNIT_ASSERT_EQUAL_MESSAGE
909 (
910 "Comparing directory times" + msg,
911 deref,
912 equal
913 );
914
915 // Test (File|Dir)Exists()
916 CPPUNIT_ASSERT_EQUAL_MESSAGE
917 (
918 "Testing file existence" + msg,
919 deref,
920 linktofile.FileExists()
921 );
922 CPPUNIT_ASSERT_EQUAL_MESSAGE
923 (
924 "Testing directory existence" + msg,
925 deref,
926 linktodir.DirExists()
927 );
928
929 // Test wxFileName::Exists
930 // The wxFILE_EXISTS_NO_FOLLOW flag should override DontFollowLink()
931 CPPUNIT_ASSERT_EQUAL_MESSAGE
932 (
933 "Testing file existence" + msg,
934 false,
935 linktofile.Exists(wxFILE_EXISTS_REGULAR | wxFILE_EXISTS_NO_FOLLOW)
936 );
937 CPPUNIT_ASSERT_EQUAL_MESSAGE
938 (
939 "Testing directory existence" + msg,
940 false,
941 linktodir.Exists(wxFILE_EXISTS_DIR | wxFILE_EXISTS_NO_FOLLOW)
942 );
943 // and the static versions
944 CPPUNIT_ASSERT_EQUAL_MESSAGE
945 (
946 "Testing file existence" + msg,
947 false,
948 wxFileName::Exists(linktofile.GetFullPath(), wxFILE_EXISTS_REGULAR | wxFILE_EXISTS_NO_FOLLOW)
949 );
950 CPPUNIT_ASSERT_EQUAL_MESSAGE
951 (
952 "Testing file existence" + msg,
953 true,
954 wxFileName::Exists(linktofile.GetFullPath(), wxFILE_EXISTS_REGULAR)
955 );
956 CPPUNIT_ASSERT_EQUAL_MESSAGE
957 (
958 "Testing directory existence" + msg,
959 false,
960 wxFileName::Exists(linktodir.GetFullPath(), wxFILE_EXISTS_DIR | wxFILE_EXISTS_NO_FOLLOW)
961 );
962 CPPUNIT_ASSERT_EQUAL_MESSAGE
963 (
964 "Testing directory existence" + msg,
965 true,
966 wxFileName::Exists(linktodir.GetFullPath(), wxFILE_EXISTS_DIR)
967 );
968 }
969
970 // Finally test Exists() after removing the file.
971 CPPUNIT_ASSERT(wxRemoveFile(targetfn.GetFullPath()));
972 // This should succeed, as the symlink still exists and
973 // the default wxFILE_EXISTS_ANY implies wxFILE_EXISTS_NO_FOLLOW
974 CPPUNIT_ASSERT(wxFileName(tempdir, "linktofile").Exists());
975 // So should this one, as wxFILE_EXISTS_SYMLINK does too
976 CPPUNIT_ASSERT(wxFileName(tempdir, "linktofile").
977 Exists(wxFILE_EXISTS_SYMLINK));
978 // but not this one, as the now broken symlink is followed
979 CPPUNIT_ASSERT(!wxFileName(tempdir, "linktofile").
980 Exists(wxFILE_EXISTS_REGULAR));
981 CPPUNIT_ASSERT(linktofile.Exists());
982
983 // This is also a convenient place to test Rmdir() as we have things to
984 // remove.
985
986 // First, check that removing a symlink to a directory fails.
987 CPPUNIT_ASSERT( !wxFileName::Rmdir(linktodirName) );
988
989 // And recursively removing it only removes the symlink itself, not the
990 // directory.
991 CPPUNIT_ASSERT( wxFileName::Rmdir(linktodirName, wxPATH_RMDIR_RECURSIVE) );
992 CPPUNIT_ASSERT( tmpfn.Exists() );
993
994 // Finally removing the directory itself does remove everything.
995 CPPUNIT_ASSERT(tempdirfn.Rmdir(wxPATH_RMDIR_RECURSIVE));
996 CPPUNIT_ASSERT( !tempdirfn.Exists() );
997 }
998
999 #endif // __UNIX__