xpcom/tests/TestFile.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:07b507117692
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 }

mercurial