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