1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is XPCOM file tests.
17 * The Initial Developer of the Original Code is Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1999
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
40 #include "TestHarness.h"
42 #include "nsILocalFile.h"
43 #include "nsDirectoryServiceDefs.h"
44 #include "nsDirectoryServiceUtils.h"
46 static const char* gFunction
= "main";
48 static PRBool
VerifyResult(nsresult aRV
, const char* aMsg
)
51 fail("%s %s, rv=%x", gFunction
, aMsg
, aRV
);
57 static already_AddRefed
<nsILocalFile
> NewFile(nsIFile
* aBase
)
60 nsCOMPtr
<nsILocalFile
> file
=
61 do_CreateInstance(NS_LOCAL_FILE_CONTRACTID
, &rv
);
62 VerifyResult(rv
, "Creating nsILocalFile");
63 nsCOMPtr
<nsILocalFile
> localBase
= do_QueryInterface(aBase
);
65 fail("%s Base directory not a local file", gFunction
);
68 rv
= file
->InitWithFile(localBase
);
69 VerifyResult(rv
, "InitWithFile");
73 static nsCString
FixName(const char* aName
)
76 for (PRUint32 i
= 0; aName
[i
]; ++i
) {
78 // PR_GetPathSeparator returns the wrong value on Mac so don't use it
79 #if defined(XP_WIN) || defined(XP_OS2)
89 // Test nsIFile::AppendNative, verifying that aName is not a valid file name
90 static PRBool
TestInvalidFileName(nsIFile
* aBase
, const char* aName
)
92 gFunction
= "TestInvalidFileName";
93 nsCOMPtr
<nsILocalFile
> file
= NewFile(aBase
);
97 nsCString name
= FixName(aName
);
98 nsresult rv
= file
->AppendNative(name
);
99 if (NS_SUCCEEDED(rv
)) {
100 fail("%s AppendNative with invalid filename %s", gFunction
, name
.get());
107 // Test nsIFile::Create, verifying that the file exists and did not exist before,
108 // and leaving it there for future tests
109 static PRBool
TestCreate(nsIFile
* aBase
, const char* aName
, PRInt32 aType
, PRInt32 aPerm
)
111 gFunction
= "TestCreate";
112 nsCOMPtr
<nsILocalFile
> file
= NewFile(aBase
);
116 nsCString name
= FixName(aName
);
117 nsresult rv
= file
->AppendNative(name
);
118 if (!VerifyResult(rv
, "AppendNative"))
122 rv
= file
->Exists(&exists
);
123 if (!VerifyResult(rv
, "Exists (before)"))
126 fail("%s File %s already exists", gFunction
, name
.get());
130 rv
= file
->Create(aType
, aPerm
);
131 if (!VerifyResult(rv
, "Create"))
134 rv
= file
->Exists(&exists
);
135 if (!VerifyResult(rv
, "Exists (after)"))
138 fail("%s File %s was not created", gFunction
, name
.get());
145 // Test nsIFile::CreateUnique, verifying that the new file exists and if it existed before,
146 // the new file has a different name.
147 // The new file is left in place.
148 static PRBool
TestCreateUnique(nsIFile
* aBase
, const char* aName
, PRInt32 aType
, PRInt32 aPerm
)
150 gFunction
= "TestCreateUnique";
151 nsCOMPtr
<nsILocalFile
> file
= NewFile(aBase
);
155 nsCString name
= FixName(aName
);
156 nsresult rv
= file
->AppendNative(name
);
157 if (!VerifyResult(rv
, "AppendNative"))
161 rv
= file
->Exists(&existsBefore
);
162 if (!VerifyResult(rv
, "Exists (before)"))
165 rv
= file
->CreateUnique(aType
, aPerm
);
166 if (!VerifyResult(rv
, "Create"))
170 rv
= file
->Exists(&existsAfter
);
171 if (!VerifyResult(rv
, "Exists (after)"))
174 fail("%s File %s was not created", gFunction
, name
.get());
179 nsCAutoString leafName
;
180 rv
= file
->GetNativeLeafName(leafName
);
181 if (!VerifyResult(rv
, "GetNativeLeafName"))
183 if (leafName
.Equals(name
)) {
184 fail("%s File %s was not given a new name by CreateUnique", gFunction
, name
.get());
192 // Test nsILocalFile::OpenNSPRFileDesc with DELETE_ON_CLOSE, verifying that the file exists
193 // and did not exist before, and leaving it there for future tests
194 static PRBool
TestDeleteOnClose(nsIFile
* aBase
, const char* aName
, PRInt32 aFlags
, PRInt32 aPerm
)
196 gFunction
= "TestDeleteOnClose";
197 #ifndef WINCE // Windows CE doesn't have the concept of delete on close, punt
198 nsCOMPtr
<nsILocalFile
> file
= NewFile(aBase
);
202 nsCString name
= FixName(aName
);
203 nsresult rv
= file
->AppendNative(name
);
204 if (!VerifyResult(rv
, "AppendNative"))
208 rv
= file
->Exists(&exists
);
209 if (!VerifyResult(rv
, "Exists (before)"))
212 fail("%s File %s already exists", gFunction
, name
.get());
216 PRFileDesc
* fileDesc
;
217 rv
= file
->OpenNSPRFileDesc(aFlags
| nsILocalFile::DELETE_ON_CLOSE
, aPerm
, &fileDesc
);
218 if (!VerifyResult(rv
, "OpenNSPRFileDesc"))
220 PRStatus status
= PR_Close(fileDesc
);
221 if (status
!= PR_SUCCESS
) {
222 fail("%s File %s could not be closed", gFunction
, name
.get());
226 rv
= file
->Exists(&exists
);
227 if (!VerifyResult(rv
, "Exists (after)"))
230 fail("%s File %s was not removed on close!", gFunction
, name
.get());
237 // Test nsIFile::Remove, verifying that the file does not exist and did before
238 static PRBool
TestRemove(nsIFile
* aBase
, const char* aName
, PRBool aRecursive
)
240 gFunction
= "TestDelete";
241 nsCOMPtr
<nsILocalFile
> file
= NewFile(aBase
);
245 nsCString name
= FixName(aName
);
246 nsresult rv
= file
->AppendNative(name
);
247 if (!VerifyResult(rv
, "AppendNative"))
251 rv
= file
->Exists(&exists
);
252 if (!VerifyResult(rv
, "Exists (before)"))
255 fail("%s File %s does not exist", gFunction
, name
.get());
259 rv
= file
->Remove(aRecursive
);
260 if (!VerifyResult(rv
, "Remove"))
263 rv
= file
->Exists(&exists
);
264 if (!VerifyResult(rv
, "Exists (after)"))
267 fail("%s File %s was not removed", gFunction
, name
.get());
274 // Test nsIFile::MoveToNative, verifying that the file did not exist at the new location
275 // before and does afterward, and that it does not exist at the old location anymore
276 static PRBool
TestMove(nsIFile
* aBase
, nsIFile
* aDestDir
, const char* aName
, const char* aNewName
)
278 gFunction
= "TestMove";
279 nsCOMPtr
<nsILocalFile
> file
= NewFile(aBase
);
283 nsCString name
= FixName(aName
);
284 nsresult rv
= file
->AppendNative(name
);
285 if (!VerifyResult(rv
, "AppendNative"))
289 rv
= file
->Exists(&exists
);
290 if (!VerifyResult(rv
, "Exists (before)"))
293 fail("%s File %s does not exist", gFunction
, name
.get());
297 nsCOMPtr
<nsILocalFile
> newFile
= NewFile(file
);
298 nsCString newName
= FixName(aNewName
);
299 rv
= newFile
->MoveToNative(aDestDir
, newName
);
300 if (!VerifyResult(rv
, "MoveToNative"))
303 rv
= file
->Exists(&exists
);
304 if (!VerifyResult(rv
, "Exists (after)"))
307 fail("%s File %s was not moved", gFunction
, name
.get());
311 file
= NewFile(aDestDir
);
314 rv
= file
->AppendNative(newName
);
315 if (!VerifyResult(rv
, "AppendNative"))
318 rv
= file
->Equals(newFile
, &equal
);
319 if (!VerifyResult(rv
, "Equals"))
322 fail("%s file object was not updated to destination", gFunction
);
326 rv
= file
->Exists(&exists
);
327 if (!VerifyResult(rv
, "Exists (new after)"))
330 fail("%s Destination file %s was not created", gFunction
, newName
.get());
337 // Test nsIFile::CopyToNative, verifying that the file did not exist at the new location
338 // before and does afterward, and that it does exist at the old location too
339 static PRBool
TestCopy(nsIFile
* aBase
, nsIFile
* aDestDir
, const char* aName
, const char* aNewName
)
341 gFunction
= "TestCopy";
342 nsCOMPtr
<nsILocalFile
> file
= NewFile(aBase
);
346 nsCString name
= FixName(aName
);
347 nsresult rv
= file
->AppendNative(name
);
348 if (!VerifyResult(rv
, "AppendNative"))
352 rv
= file
->Exists(&exists
);
353 if (!VerifyResult(rv
, "Exists (before)"))
356 fail("%s File %s does not exist", gFunction
, name
.get());
360 nsCOMPtr
<nsILocalFile
> newFile
= NewFile(file
);
361 nsCString newName
= FixName(aNewName
);
362 rv
= newFile
->CopyToNative(aDestDir
, newName
);
363 if (!VerifyResult(rv
, "MoveToNative"))
366 rv
= file
->Equals(newFile
, &equal
);
367 if (!VerifyResult(rv
, "Equals"))
370 fail("%s file object updated unexpectedly", gFunction
);
374 rv
= file
->Exists(&exists
);
375 if (!VerifyResult(rv
, "Exists (after)"))
378 fail("%s File %s was removed", gFunction
, name
.get());
382 file
= NewFile(aDestDir
);
385 rv
= file
->AppendNative(newName
);
386 if (!VerifyResult(rv
, "AppendNative"))
389 rv
= file
->Exists(&exists
);
390 if (!VerifyResult(rv
, "Exists (new after)"))
393 fail("%s Destination file %s was not created", gFunction
, newName
.get());
400 // Test nsIFile::GetParent
401 static PRBool
TestParent(nsIFile
* aBase
, nsIFile
* aStart
)
403 gFunction
= "TestParent";
404 nsCOMPtr
<nsILocalFile
> file
= NewFile(aStart
);
408 nsCOMPtr
<nsIFile
> parent
;
409 nsresult rv
= file
->GetParent(getter_AddRefs(parent
));
410 VerifyResult(rv
, "GetParent");
413 rv
= parent
->Equals(aBase
, &equal
);
414 VerifyResult(rv
, "Equals");
416 fail("%s Incorrect parent", gFunction
);
423 // Test nsIFile::Normalize and native path setting/getting
424 static PRBool
TestNormalizeNativePath(nsIFile
* aBase
, nsIFile
* aStart
)
426 gFunction
= "TestNormalizeNativePath";
427 nsCOMPtr
<nsILocalFile
> file
= NewFile(aStart
);
432 nsresult rv
= file
->GetNativePath(path
);
433 VerifyResult(rv
, "GetNativePath");
434 path
.Append(FixName("/./.."));
435 rv
= file
->InitWithNativePath(path
);
436 VerifyResult(rv
, "InitWithNativePath");
437 rv
= file
->Normalize();
438 VerifyResult(rv
, "Normalize");
439 rv
= file
->GetNativePath(path
);
440 VerifyResult(rv
, "GetNativePath (after normalization)");
442 nsCAutoString basePath
;
443 rv
= aBase
->GetNativePath(basePath
);
444 VerifyResult(rv
, "GetNativePath (base)");
446 if (!path
.Equals(basePath
)) {
447 fail("%s Incorrect normalization");
454 int main(int argc
, char** argv
)
456 ScopedXPCOM
xpcom("nsLocalFile");
460 nsCOMPtr
<nsIFile
> base
;
461 nsresult rv
= NS_GetSpecialDirectory(NS_OS_TEMP_DIR
, getter_AddRefs(base
));
462 if (!VerifyResult(rv
, "Getting temp directory"))
464 rv
= base
->AppendNative(nsDependentCString("mozfiletests"));
465 if (!VerifyResult(rv
, "Appending mozfiletests to temp directory name"))
467 // Remove the directory in case tests failed and left it behind.
468 // don't check result since it might not be there
469 base
->Remove(PR_TRUE
);
471 // Now create the working directory we're going to use
472 rv
= base
->Create(nsIFile::DIRECTORY_TYPE
, 0700);
473 if (!VerifyResult(rv
, "Creating temp directory"))
475 // Now we can safely normalize the path
476 rv
= base
->Normalize();
477 if (!VerifyResult(rv
, "Normalizing temp directory name"))
480 // Initialize subdir object for later use
481 nsCOMPtr
<nsILocalFile
> subdir
= NewFile(base
);
484 rv
= subdir
->AppendNative(nsDependentCString("subdir"));
485 if (!VerifyResult(rv
, "Appending 'subdir' to test dir name"))
491 if (TestInvalidFileName(base
, "a/b")) {
492 passed("AppendNative with invalid file name");
494 if (TestParent(base
, subdir
)) {
498 // Test file creation
499 if (TestCreate(base
, "file.txt", nsIFile::NORMAL_FILE_TYPE
, 0600)) {
500 passed("Create file");
502 if (TestRemove(base
, "file.txt", PR_FALSE
)) {
503 passed("Remove file");
506 // Test directory creation
507 if (TestCreate(base
, "subdir", nsIFile::DIRECTORY_TYPE
, 0700)) {
508 passed("Create directory");
511 // Test move and copy in the base directory
512 if (TestCreate(base
, "file.txt", nsIFile::NORMAL_FILE_TYPE
, 0600) &&
513 TestMove(base
, base
, "file.txt", "file2.txt")) {
514 passed("MoveTo rename file");
516 if (TestCopy(base
, base
, "file2.txt", "file3.txt")) {
517 passed("CopyTo copy file");
519 // Test moving across directories
520 if (TestMove(base
, subdir
, "file2.txt", "file2.txt")) {
521 passed("MoveTo move file");
523 // Test moving across directories and renaming at the same time
524 if (TestMove(subdir
, base
, "file2.txt", "file4.txt")) {
525 passed("MoveTo move and rename file");
527 // Test copying across directoreis
528 if (TestCopy(base
, subdir
, "file4.txt", "file5.txt")) {
529 passed("CopyTo copy file across directories");
532 // Run normalization tests while the directory exists
533 if (TestNormalizeNativePath(base
, subdir
)) {
534 passed("Normalize with native paths");
537 // Test recursive directory removal
538 if (TestRemove(base
, "subdir", PR_TRUE
)) {
539 passed("Remove directory");
542 if (TestCreateUnique(base
, "foo", nsIFile::NORMAL_FILE_TYPE
, 0600) &&
543 TestCreateUnique(base
, "foo", nsIFile::NORMAL_FILE_TYPE
, 0600)) {
544 passed("CreateUnique file");
546 if (TestCreateUnique(base
, "bar.xx", nsIFile::DIRECTORY_TYPE
, 0700) &&
547 TestCreateUnique(base
, "bar.xx", nsIFile::DIRECTORY_TYPE
, 0700)) {
548 passed("CreateUnique directory");
551 if (TestDeleteOnClose(base
, "file7.txt", PR_RDWR
| PR_CREATE_FILE
, 0600)) {
552 passed("OpenNSPRFileDesc DELETE_ON_CLOSE");
556 // Clean up temporary stuff
557 rv
= base
->Remove(PR_TRUE
);
558 VerifyResult(rv
, "Cleaning up temp directory");
560 return gFailCount
> 0;