Coverage Report

Created: 2018-09-25 14:53

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