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
4 : *
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/
9 : *
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
13 : * License.
14 : *
15 : * The Original Code is XPCOM file tests.
16 : *
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.
20 : *
21 : * Contributor(s):
22 : *
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.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "prio.h"
38 : #include "prsystem.h"
39 :
40 : #include "TestHarness.h"
41 :
42 : #include "nsILocalFile.h"
43 : #include "nsDirectoryServiceDefs.h"
44 : #include "nsDirectoryServiceUtils.h"
45 :
46 : static const char* gFunction = "main";
47 :
48 148 : static bool VerifyResult(nsresult aRV, const char* aMsg)
49 : {
50 148 : if (NS_FAILED(aRV)) {
51 0 : fail("%s %s, rv=%x", gFunction, aMsg, aRV);
52 0 : return false;
53 : }
54 148 : return true;
55 : }
56 :
57 29 : static already_AddRefed<nsILocalFile> NewFile(nsIFile* aBase)
58 : {
59 : nsresult rv;
60 : nsCOMPtr<nsILocalFile> file =
61 58 : do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
62 29 : VerifyResult(rv, "Creating nsILocalFile");
63 58 : nsCOMPtr<nsILocalFile> localBase = do_QueryInterface(aBase);
64 29 : if (!localBase) {
65 0 : fail("%s Base directory not a local file", gFunction);
66 0 : return nsnull;
67 : }
68 29 : rv = file->InitWithFile(localBase);
69 29 : VerifyResult(rv, "InitWithFile");
70 29 : return file.forget();
71 : }
72 :
73 22 : static nsCString FixName(const char* aName)
74 : {
75 22 : nsCString name;
76 182 : for (PRUint32 i = 0; aName[i]; ++i) {
77 160 : char ch = aName[i];
78 : // PR_GetPathSeparator returns the wrong value on Mac so don't use it
79 : #if defined(XP_WIN) || defined(XP_OS2)
80 : if (ch == '/') {
81 : ch = '\\';
82 : }
83 : #endif
84 160 : name.Append(ch);
85 : }
86 : return name;
87 : }
88 :
89 : // Test nsIFile::AppendNative, verifying that aName is not a valid file name
90 1 : static bool TestInvalidFileName(nsIFile* aBase, const char* aName)
91 : {
92 1 : gFunction = "TestInvalidFileName";
93 2 : nsCOMPtr<nsILocalFile> file = NewFile(aBase);
94 1 : if (!file)
95 0 : return false;
96 :
97 2 : nsCString name = FixName(aName);
98 1 : nsresult rv = file->AppendNative(name);
99 1 : if (NS_SUCCEEDED(rv)) {
100 0 : fail("%s AppendNative with invalid filename %s", gFunction, name.get());
101 0 : return false;
102 : }
103 :
104 1 : return true;
105 : }
106 :
107 : // Test nsIFile::Create, verifying that the file exists and did not exist before,
108 : // and leaving it there for future tests
109 3 : static bool TestCreate(nsIFile* aBase, const char* aName, PRInt32 aType, PRInt32 aPerm)
110 : {
111 3 : gFunction = "TestCreate";
112 6 : nsCOMPtr<nsILocalFile> file = NewFile(aBase);
113 3 : if (!file)
114 0 : return false;
115 :
116 6 : nsCString name = FixName(aName);
117 3 : nsresult rv = file->AppendNative(name);
118 3 : if (!VerifyResult(rv, "AppendNative"))
119 0 : return false;
120 :
121 : bool exists;
122 3 : rv = file->Exists(&exists);
123 3 : if (!VerifyResult(rv, "Exists (before)"))
124 0 : return false;
125 3 : if (exists) {
126 0 : fail("%s File %s already exists", gFunction, name.get());
127 0 : return false;
128 : }
129 :
130 3 : rv = file->Create(aType, aPerm);
131 3 : if (!VerifyResult(rv, "Create"))
132 0 : return false;
133 :
134 3 : rv = file->Exists(&exists);
135 3 : if (!VerifyResult(rv, "Exists (after)"))
136 0 : return false;
137 3 : if (!exists) {
138 0 : fail("%s File %s was not created", gFunction, name.get());
139 0 : return false;
140 : }
141 :
142 3 : return true;
143 : }
144 :
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 4 : static bool TestCreateUnique(nsIFile* aBase, const char* aName, PRInt32 aType, PRInt32 aPerm)
149 : {
150 4 : gFunction = "TestCreateUnique";
151 8 : nsCOMPtr<nsILocalFile> file = NewFile(aBase);
152 4 : if (!file)
153 0 : return false;
154 :
155 8 : nsCString name = FixName(aName);
156 4 : nsresult rv = file->AppendNative(name);
157 4 : if (!VerifyResult(rv, "AppendNative"))
158 0 : return false;
159 :
160 : bool existsBefore;
161 4 : rv = file->Exists(&existsBefore);
162 4 : if (!VerifyResult(rv, "Exists (before)"))
163 0 : return false;
164 :
165 4 : rv = file->CreateUnique(aType, aPerm);
166 4 : if (!VerifyResult(rv, "Create"))
167 0 : return false;
168 :
169 : bool existsAfter;
170 4 : rv = file->Exists(&existsAfter);
171 4 : if (!VerifyResult(rv, "Exists (after)"))
172 0 : return false;
173 4 : if (!existsAfter) {
174 0 : fail("%s File %s was not created", gFunction, name.get());
175 0 : return false;
176 : }
177 :
178 4 : if (existsBefore) {
179 4 : nsCAutoString leafName;
180 2 : rv = file->GetNativeLeafName(leafName);
181 2 : if (!VerifyResult(rv, "GetNativeLeafName"))
182 0 : return false;
183 2 : if (leafName.Equals(name)) {
184 0 : fail("%s File %s was not given a new name by CreateUnique", gFunction, name.get());
185 0 : return false;
186 : }
187 : }
188 :
189 4 : return true;
190 : }
191 :
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 1 : static bool TestDeleteOnClose(nsIFile* aBase, const char* aName, PRInt32 aFlags, PRInt32 aPerm)
195 : {
196 1 : gFunction = "TestDeleteOnClose";
197 2 : nsCOMPtr<nsILocalFile> file = NewFile(aBase);
198 1 : if (!file)
199 0 : return false;
200 :
201 2 : nsCString name = FixName(aName);
202 1 : nsresult rv = file->AppendNative(name);
203 1 : if (!VerifyResult(rv, "AppendNative"))
204 0 : return false;
205 :
206 : bool exists;
207 1 : rv = file->Exists(&exists);
208 1 : if (!VerifyResult(rv, "Exists (before)"))
209 0 : return false;
210 1 : if (exists) {
211 0 : fail("%s File %s already exists", gFunction, name.get());
212 0 : return false;
213 : }
214 :
215 : PRFileDesc* fileDesc;
216 1 : rv = file->OpenNSPRFileDesc(aFlags | nsILocalFile::DELETE_ON_CLOSE, aPerm, &fileDesc);
217 1 : if (!VerifyResult(rv, "OpenNSPRFileDesc"))
218 0 : return false;
219 1 : PRStatus status = PR_Close(fileDesc);
220 1 : if (status != PR_SUCCESS) {
221 0 : fail("%s File %s could not be closed", gFunction, name.get());
222 0 : return false;
223 : }
224 :
225 1 : rv = file->Exists(&exists);
226 1 : if (!VerifyResult(rv, "Exists (after)"))
227 0 : return false;
228 1 : if (exists) {
229 0 : fail("%s File %s was not removed on close!", gFunction, name.get());
230 0 : return false;
231 : }
232 :
233 1 : return true;
234 : }
235 :
236 : // Test nsIFile::Remove, verifying that the file does not exist and did before
237 2 : static bool TestRemove(nsIFile* aBase, const char* aName, bool aRecursive)
238 : {
239 2 : gFunction = "TestDelete";
240 4 : nsCOMPtr<nsILocalFile> file = NewFile(aBase);
241 2 : if (!file)
242 0 : return false;
243 :
244 4 : nsCString name = FixName(aName);
245 2 : nsresult rv = file->AppendNative(name);
246 2 : if (!VerifyResult(rv, "AppendNative"))
247 0 : return false;
248 :
249 : bool exists;
250 2 : rv = file->Exists(&exists);
251 2 : if (!VerifyResult(rv, "Exists (before)"))
252 0 : return false;
253 2 : if (!exists) {
254 0 : fail("%s File %s does not exist", gFunction, name.get());
255 0 : return false;
256 : }
257 :
258 2 : rv = file->Remove(aRecursive);
259 2 : if (!VerifyResult(rv, "Remove"))
260 0 : return false;
261 :
262 2 : rv = file->Exists(&exists);
263 2 : if (!VerifyResult(rv, "Exists (after)"))
264 0 : return false;
265 2 : if (exists) {
266 0 : fail("%s File %s was not removed", gFunction, name.get());
267 0 : return false;
268 : }
269 :
270 2 : return true;
271 : }
272 :
273 : // Test nsIFile::MoveToNative, verifying that the file did not exist at the new location
274 : // before and does afterward, and that it does not exist at the old location anymore
275 3 : static bool TestMove(nsIFile* aBase, nsIFile* aDestDir, const char* aName, const char* aNewName)
276 : {
277 3 : gFunction = "TestMove";
278 6 : nsCOMPtr<nsILocalFile> file = NewFile(aBase);
279 3 : if (!file)
280 0 : return false;
281 :
282 6 : nsCString name = FixName(aName);
283 3 : nsresult rv = file->AppendNative(name);
284 3 : if (!VerifyResult(rv, "AppendNative"))
285 0 : return false;
286 :
287 : bool exists;
288 3 : rv = file->Exists(&exists);
289 3 : if (!VerifyResult(rv, "Exists (before)"))
290 0 : return false;
291 3 : if (!exists) {
292 0 : fail("%s File %s does not exist", gFunction, name.get());
293 0 : return false;
294 : }
295 :
296 6 : nsCOMPtr<nsILocalFile> newFile = NewFile(file);
297 6 : nsCString newName = FixName(aNewName);
298 3 : rv = newFile->MoveToNative(aDestDir, newName);
299 3 : if (!VerifyResult(rv, "MoveToNative"))
300 0 : return false;
301 :
302 3 : rv = file->Exists(&exists);
303 3 : if (!VerifyResult(rv, "Exists (after)"))
304 0 : return false;
305 3 : if (exists) {
306 0 : fail("%s File %s was not moved", gFunction, name.get());
307 0 : return false;
308 : }
309 :
310 3 : file = NewFile(aDestDir);
311 3 : if (!file)
312 0 : return false;
313 3 : rv = file->AppendNative(newName);
314 3 : if (!VerifyResult(rv, "AppendNative"))
315 0 : return false;
316 : bool equal;
317 3 : rv = file->Equals(newFile, &equal);
318 3 : if (!VerifyResult(rv, "Equals"))
319 0 : return false;
320 3 : if (!equal) {
321 0 : fail("%s file object was not updated to destination", gFunction);
322 0 : return false;
323 : }
324 :
325 3 : rv = file->Exists(&exists);
326 3 : if (!VerifyResult(rv, "Exists (new after)"))
327 0 : return false;
328 3 : if (!exists) {
329 0 : fail("%s Destination file %s was not created", gFunction, newName.get());
330 0 : return false;
331 : }
332 :
333 3 : return true;
334 : }
335 :
336 : // Test nsIFile::CopyToNative, verifying that the file did not exist at the new location
337 : // before and does afterward, and that it does exist at the old location too
338 2 : static bool TestCopy(nsIFile* aBase, nsIFile* aDestDir, const char* aName, const char* aNewName)
339 : {
340 2 : gFunction = "TestCopy";
341 4 : nsCOMPtr<nsILocalFile> file = NewFile(aBase);
342 2 : if (!file)
343 0 : return false;
344 :
345 4 : nsCString name = FixName(aName);
346 2 : nsresult rv = file->AppendNative(name);
347 2 : if (!VerifyResult(rv, "AppendNative"))
348 0 : return false;
349 :
350 : bool exists;
351 2 : rv = file->Exists(&exists);
352 2 : if (!VerifyResult(rv, "Exists (before)"))
353 0 : return false;
354 2 : if (!exists) {
355 0 : fail("%s File %s does not exist", gFunction, name.get());
356 0 : return false;
357 : }
358 :
359 4 : nsCOMPtr<nsILocalFile> newFile = NewFile(file);
360 4 : nsCString newName = FixName(aNewName);
361 2 : rv = newFile->CopyToNative(aDestDir, newName);
362 2 : if (!VerifyResult(rv, "MoveToNative"))
363 0 : return false;
364 : bool equal;
365 2 : rv = file->Equals(newFile, &equal);
366 2 : if (!VerifyResult(rv, "Equals"))
367 0 : return false;
368 2 : if (!equal) {
369 0 : fail("%s file object updated unexpectedly", gFunction);
370 0 : return false;
371 : }
372 :
373 2 : rv = file->Exists(&exists);
374 2 : if (!VerifyResult(rv, "Exists (after)"))
375 0 : return false;
376 2 : if (!exists) {
377 0 : fail("%s File %s was removed", gFunction, name.get());
378 0 : return false;
379 : }
380 :
381 2 : file = NewFile(aDestDir);
382 2 : if (!file)
383 0 : return false;
384 2 : rv = file->AppendNative(newName);
385 2 : if (!VerifyResult(rv, "AppendNative"))
386 0 : return false;
387 :
388 2 : rv = file->Exists(&exists);
389 2 : if (!VerifyResult(rv, "Exists (new after)"))
390 0 : return false;
391 2 : if (!exists) {
392 0 : fail("%s Destination file %s was not created", gFunction, newName.get());
393 0 : return false;
394 : }
395 :
396 2 : return true;
397 : }
398 :
399 : // Test nsIFile::GetParent
400 1 : static bool TestParent(nsIFile* aBase, nsIFile* aStart)
401 : {
402 1 : gFunction = "TestParent";
403 2 : nsCOMPtr<nsILocalFile> file = NewFile(aStart);
404 1 : if (!file)
405 0 : return false;
406 :
407 2 : nsCOMPtr<nsIFile> parent;
408 1 : nsresult rv = file->GetParent(getter_AddRefs(parent));
409 1 : VerifyResult(rv, "GetParent");
410 :
411 : bool equal;
412 1 : rv = parent->Equals(aBase, &equal);
413 1 : VerifyResult(rv, "Equals");
414 1 : if (!equal) {
415 0 : fail("%s Incorrect parent", gFunction);
416 0 : return false;
417 : }
418 :
419 1 : return true;
420 : }
421 :
422 : // Test nsIFile::Normalize and native path setting/getting
423 1 : static bool TestNormalizeNativePath(nsIFile* aBase, nsIFile* aStart)
424 : {
425 1 : gFunction = "TestNormalizeNativePath";
426 2 : nsCOMPtr<nsILocalFile> file = NewFile(aStart);
427 1 : if (!file)
428 0 : return false;
429 :
430 2 : nsCAutoString path;
431 1 : nsresult rv = file->GetNativePath(path);
432 1 : VerifyResult(rv, "GetNativePath");
433 1 : path.Append(FixName("/./.."));
434 1 : rv = file->InitWithNativePath(path);
435 1 : VerifyResult(rv, "InitWithNativePath");
436 1 : rv = file->Normalize();
437 1 : VerifyResult(rv, "Normalize");
438 1 : rv = file->GetNativePath(path);
439 1 : VerifyResult(rv, "GetNativePath (after normalization)");
440 :
441 2 : nsCAutoString basePath;
442 1 : rv = aBase->GetNativePath(basePath);
443 1 : VerifyResult(rv, "GetNativePath (base)");
444 :
445 1 : if (!path.Equals(basePath)) {
446 0 : fail("%s Incorrect normalization");
447 0 : return false;
448 : }
449 :
450 1 : return true;
451 : }
452 :
453 1 : int main(int argc, char** argv)
454 : {
455 2 : ScopedXPCOM xpcom("nsLocalFile");
456 1 : if (xpcom.failed())
457 0 : return 1;
458 :
459 2 : nsCOMPtr<nsIFile> base;
460 1 : nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(base));
461 1 : if (!VerifyResult(rv, "Getting temp directory"))
462 0 : return 1;
463 1 : rv = base->AppendNative(nsDependentCString("mozfiletests"));
464 1 : if (!VerifyResult(rv, "Appending mozfiletests to temp directory name"))
465 0 : return 1;
466 : // Remove the directory in case tests failed and left it behind.
467 : // don't check result since it might not be there
468 1 : base->Remove(true);
469 :
470 : // Now create the working directory we're going to use
471 1 : rv = base->Create(nsIFile::DIRECTORY_TYPE, 0700);
472 1 : if (!VerifyResult(rv, "Creating temp directory"))
473 0 : return 1;
474 : // Now we can safely normalize the path
475 1 : rv = base->Normalize();
476 1 : if (!VerifyResult(rv, "Normalizing temp directory name"))
477 0 : return 1;
478 :
479 : // Initialize subdir object for later use
480 2 : nsCOMPtr<nsILocalFile> subdir = NewFile(base);
481 1 : if (!subdir)
482 0 : return 1;
483 1 : rv = subdir->AppendNative(nsDependentCString("subdir"));
484 1 : if (!VerifyResult(rv, "Appending 'subdir' to test dir name"))
485 0 : return 1;
486 :
487 1 : passed("Setup");
488 :
489 : // Test path parsing
490 1 : if (TestInvalidFileName(base, "a/b")) {
491 1 : passed("AppendNative with invalid file name");
492 : }
493 1 : if (TestParent(base, subdir)) {
494 1 : passed("GetParent");
495 : }
496 :
497 : // Test file creation
498 1 : if (TestCreate(base, "file.txt", nsIFile::NORMAL_FILE_TYPE, 0600)) {
499 1 : passed("Create file");
500 : }
501 1 : if (TestRemove(base, "file.txt", false)) {
502 1 : passed("Remove file");
503 : }
504 :
505 : // Test directory creation
506 1 : if (TestCreate(base, "subdir", nsIFile::DIRECTORY_TYPE, 0700)) {
507 1 : passed("Create directory");
508 : }
509 :
510 : // Test move and copy in the base directory
511 2 : if (TestCreate(base, "file.txt", nsIFile::NORMAL_FILE_TYPE, 0600) &&
512 1 : TestMove(base, base, "file.txt", "file2.txt")) {
513 1 : passed("MoveTo rename file");
514 : }
515 1 : if (TestCopy(base, base, "file2.txt", "file3.txt")) {
516 1 : passed("CopyTo copy file");
517 : }
518 : // Test moving across directories
519 1 : if (TestMove(base, subdir, "file2.txt", "file2.txt")) {
520 1 : passed("MoveTo move file");
521 : }
522 : // Test moving across directories and renaming at the same time
523 1 : if (TestMove(subdir, base, "file2.txt", "file4.txt")) {
524 1 : passed("MoveTo move and rename file");
525 : }
526 : // Test copying across directoreis
527 1 : if (TestCopy(base, subdir, "file4.txt", "file5.txt")) {
528 1 : passed("CopyTo copy file across directories");
529 : }
530 :
531 : // Run normalization tests while the directory exists
532 1 : if (TestNormalizeNativePath(base, subdir)) {
533 1 : passed("Normalize with native paths");
534 : }
535 :
536 : // Test recursive directory removal
537 1 : if (TestRemove(base, "subdir", true)) {
538 1 : passed("Remove directory");
539 : }
540 :
541 2 : if (TestCreateUnique(base, "foo", nsIFile::NORMAL_FILE_TYPE, 0600) &&
542 1 : TestCreateUnique(base, "foo", nsIFile::NORMAL_FILE_TYPE, 0600)) {
543 1 : passed("CreateUnique file");
544 : }
545 2 : if (TestCreateUnique(base, "bar.xx", nsIFile::DIRECTORY_TYPE, 0700) &&
546 1 : TestCreateUnique(base, "bar.xx", nsIFile::DIRECTORY_TYPE, 0700)) {
547 1 : passed("CreateUnique directory");
548 : }
549 :
550 1 : if (TestDeleteOnClose(base, "file7.txt", PR_RDWR | PR_CREATE_FILE, 0600)) {
551 1 : passed("OpenNSPRFileDesc DELETE_ON_CLOSE");
552 : }
553 :
554 1 : gFunction = "main";
555 : // Clean up temporary stuff
556 1 : rv = base->Remove(true);
557 1 : VerifyResult(rv, "Cleaning up temp directory");
558 :
559 1 : return gFailCount > 0;
560 : }
|