1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <set>
6
7#include "base/files/file.h"
8#include "base/files/file_path.h"
9#include "base/files/file_util.h"
10#include "base/files/scoped_temp_dir.h"
11#include "storage/browser/fileapi/native_file_util.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14using storage::FileSystemFileUtil;
15using storage::FileSystemOperation;
16using storage::NativeFileUtil;
17
18namespace content {
19
20class NativeFileUtilTest : public testing::Test {
21 public:
22  NativeFileUtilTest() {}
23
24  virtual void SetUp() {
25    ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
26  }
27
28 protected:
29  base::FilePath Path() {
30    return data_dir_.path();
31  }
32
33  base::FilePath Path(const char* file_name) {
34    return data_dir_.path().AppendASCII(file_name);
35  }
36
37  bool FileExists(const base::FilePath& path) {
38    return base::PathExists(path) &&
39           !base::DirectoryExists(path);
40  }
41
42  int64 GetSize(const base::FilePath& path) {
43    base::File::Info info;
44    base::GetFileInfo(path, &info);
45    return info.size;
46  }
47
48 private:
49  base::ScopedTempDir data_dir_;
50
51  DISALLOW_COPY_AND_ASSIGN(NativeFileUtilTest);
52};
53
54TEST_F(NativeFileUtilTest, CreateCloseAndDeleteFile) {
55  base::FilePath file_name = Path("test_file");
56  int flags = base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
57  base::File file =
58      NativeFileUtil::CreateOrOpen(file_name, base::File::FLAG_CREATE | flags);
59  ASSERT_TRUE(file.IsValid());
60  ASSERT_TRUE(file.created());
61
62  EXPECT_TRUE(base::PathExists(file_name));
63  EXPECT_TRUE(NativeFileUtil::PathExists(file_name));
64  EXPECT_EQ(0, GetSize(file_name));
65  file.Close();
66
67  file = NativeFileUtil::CreateOrOpen(file_name, base::File::FLAG_OPEN | flags);
68  ASSERT_TRUE(file.IsValid());
69  ASSERT_FALSE(file.created());
70  file.Close();
71
72  ASSERT_EQ(base::File::FILE_OK,
73            NativeFileUtil::DeleteFile(file_name));
74  EXPECT_FALSE(base::PathExists(file_name));
75  EXPECT_FALSE(NativeFileUtil::PathExists(file_name));
76}
77
78TEST_F(NativeFileUtilTest, EnsureFileExists) {
79  base::FilePath file_name = Path("foobar");
80  bool created = false;
81  ASSERT_EQ(base::File::FILE_OK,
82            NativeFileUtil::EnsureFileExists(file_name, &created));
83  ASSERT_TRUE(created);
84
85  EXPECT_TRUE(FileExists(file_name));
86  EXPECT_EQ(0, GetSize(file_name));
87
88  ASSERT_EQ(base::File::FILE_OK,
89            NativeFileUtil::EnsureFileExists(file_name, &created));
90  EXPECT_FALSE(created);
91}
92
93TEST_F(NativeFileUtilTest, CreateAndDeleteDirectory) {
94  base::FilePath dir_name = Path("test_dir");
95  ASSERT_EQ(base::File::FILE_OK,
96            NativeFileUtil::CreateDirectory(dir_name,
97                                            false /* exclusive */,
98                                            false /* recursive */));
99
100  EXPECT_TRUE(NativeFileUtil::DirectoryExists(dir_name));
101  EXPECT_TRUE(base::DirectoryExists(dir_name));
102
103  ASSERT_EQ(base::File::FILE_ERROR_EXISTS,
104            NativeFileUtil::CreateDirectory(dir_name,
105                                            true /* exclusive */,
106                                            false /* recursive */));
107
108  ASSERT_EQ(base::File::FILE_OK,
109            NativeFileUtil::DeleteDirectory(dir_name));
110  EXPECT_FALSE(base::DirectoryExists(dir_name));
111  EXPECT_FALSE(NativeFileUtil::DirectoryExists(dir_name));
112}
113
114TEST_F(NativeFileUtilTest, TouchFileAndGetFileInfo) {
115  base::FilePath file_name = Path("test_file");
116  base::File::Info native_info;
117  ASSERT_EQ(base::File::FILE_ERROR_NOT_FOUND,
118            NativeFileUtil::GetFileInfo(file_name, &native_info));
119
120  bool created = false;
121  ASSERT_EQ(base::File::FILE_OK,
122            NativeFileUtil::EnsureFileExists(file_name, &created));
123  ASSERT_TRUE(created);
124
125  base::File::Info info;
126  ASSERT_TRUE(base::GetFileInfo(file_name, &info));
127  ASSERT_EQ(base::File::FILE_OK,
128            NativeFileUtil::GetFileInfo(file_name, &native_info));
129  ASSERT_EQ(info.size, native_info.size);
130  ASSERT_EQ(info.is_directory, native_info.is_directory);
131  ASSERT_EQ(info.is_symbolic_link, native_info.is_symbolic_link);
132  ASSERT_EQ(info.last_modified, native_info.last_modified);
133  ASSERT_EQ(info.last_accessed, native_info.last_accessed);
134  ASSERT_EQ(info.creation_time, native_info.creation_time);
135
136  const base::Time new_accessed =
137      info.last_accessed + base::TimeDelta::FromHours(10);
138  const base::Time new_modified =
139      info.last_modified + base::TimeDelta::FromHours(5);
140
141  EXPECT_EQ(base::File::FILE_OK,
142            NativeFileUtil::Touch(file_name,
143                                  new_accessed, new_modified));
144
145  ASSERT_TRUE(base::GetFileInfo(file_name, &info));
146  EXPECT_EQ(new_accessed, info.last_accessed);
147  EXPECT_EQ(new_modified, info.last_modified);
148}
149
150TEST_F(NativeFileUtilTest, CreateFileEnumerator) {
151  base::FilePath path_1 = Path("dir1");
152  base::FilePath path_2 = Path("file1");
153  base::FilePath path_11 = Path("dir1").AppendASCII("file11");
154  base::FilePath path_12 = Path("dir1").AppendASCII("dir12");
155  base::FilePath path_121 =
156      Path("dir1").AppendASCII("dir12").AppendASCII("file121");
157  ASSERT_EQ(base::File::FILE_OK,
158            NativeFileUtil::CreateDirectory(path_1, false, false));
159  bool created = false;
160  ASSERT_EQ(base::File::FILE_OK,
161            NativeFileUtil::EnsureFileExists(path_2, &created));
162  ASSERT_EQ(base::File::FILE_OK,
163            NativeFileUtil::EnsureFileExists(path_11, &created));
164  ASSERT_EQ(base::File::FILE_OK,
165            NativeFileUtil::CreateDirectory(path_12, false, false));
166  ASSERT_EQ(base::File::FILE_OK,
167            NativeFileUtil::EnsureFileExists(path_121, &created));
168
169  {
170    scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator =
171        NativeFileUtil::CreateFileEnumerator(Path(), false);
172    std::set<base::FilePath> set;
173    set.insert(path_1);
174    set.insert(path_2);
175    for (base::FilePath path = enumerator->Next(); !path.empty();
176         path = enumerator->Next())
177      EXPECT_EQ(1U, set.erase(path));
178    EXPECT_TRUE(set.empty());
179  }
180
181  {
182    scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator =
183        NativeFileUtil::CreateFileEnumerator(Path(), true);
184        std::set<base::FilePath> set;
185    set.insert(path_1);
186    set.insert(path_2);
187    set.insert(path_11);
188    set.insert(path_12);
189    set.insert(path_121);
190    for (base::FilePath path = enumerator->Next(); !path.empty();
191         path = enumerator->Next())
192      EXPECT_EQ(1U, set.erase(path));
193    EXPECT_TRUE(set.empty());
194  }
195}
196
197TEST_F(NativeFileUtilTest, Truncate) {
198  base::FilePath file_name = Path("truncated");
199  bool created = false;
200  ASSERT_EQ(base::File::FILE_OK,
201            NativeFileUtil::EnsureFileExists(file_name, &created));
202  ASSERT_TRUE(created);
203
204  ASSERT_EQ(base::File::FILE_OK,
205            NativeFileUtil::Truncate(file_name, 1020));
206
207  EXPECT_TRUE(FileExists(file_name));
208  EXPECT_EQ(1020, GetSize(file_name));
209}
210
211TEST_F(NativeFileUtilTest, CopyFile) {
212  base::FilePath from_file = Path("fromfile");
213  base::FilePath to_file1 = Path("tofile1");
214  base::FilePath to_file2 = Path("tofile2");
215  const NativeFileUtil::CopyOrMoveMode nosync = NativeFileUtil::COPY_NOSYNC;
216  const NativeFileUtil::CopyOrMoveMode sync = NativeFileUtil::COPY_SYNC;
217  bool created = false;
218  ASSERT_EQ(base::File::FILE_OK,
219            NativeFileUtil::EnsureFileExists(from_file, &created));
220  ASSERT_TRUE(created);
221
222  ASSERT_EQ(base::File::FILE_OK,
223            NativeFileUtil::Truncate(from_file, 1020));
224
225  EXPECT_TRUE(FileExists(from_file));
226  EXPECT_EQ(1020, GetSize(from_file));
227
228  ASSERT_EQ(base::File::FILE_OK,
229            NativeFileUtil::CopyOrMoveFile(
230                from_file, to_file1, FileSystemOperation::OPTION_NONE, nosync));
231
232  ASSERT_EQ(base::File::FILE_OK,
233            NativeFileUtil::CopyOrMoveFile(
234                from_file, to_file2, FileSystemOperation::OPTION_NONE, sync));
235
236  EXPECT_TRUE(FileExists(from_file));
237  EXPECT_EQ(1020, GetSize(from_file));
238  EXPECT_TRUE(FileExists(to_file1));
239  EXPECT_EQ(1020, GetSize(to_file1));
240  EXPECT_TRUE(FileExists(to_file2));
241  EXPECT_EQ(1020, GetSize(to_file2));
242
243  base::FilePath dir = Path("dir");
244  ASSERT_EQ(base::File::FILE_OK,
245            NativeFileUtil::CreateDirectory(dir, false, false));
246  ASSERT_TRUE(base::DirectoryExists(dir));
247  base::FilePath to_dir_file = dir.AppendASCII("file");
248  ASSERT_EQ(base::File::FILE_OK,
249            NativeFileUtil::CopyOrMoveFile(
250                from_file, to_dir_file,
251                FileSystemOperation::OPTION_NONE, nosync));
252  EXPECT_TRUE(FileExists(to_dir_file));
253  EXPECT_EQ(1020, GetSize(to_dir_file));
254
255  // Following tests are error checking.
256  // Source doesn't exist.
257  EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
258            NativeFileUtil::CopyOrMoveFile(
259                Path("nonexists"), Path("file"),
260                FileSystemOperation::OPTION_NONE, nosync));
261
262  // Source is not a file.
263  EXPECT_EQ(base::File::FILE_ERROR_NOT_A_FILE,
264            NativeFileUtil::CopyOrMoveFile(
265                dir, Path("file"), FileSystemOperation::OPTION_NONE, nosync));
266  // Destination is not a file.
267  EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION,
268            NativeFileUtil::CopyOrMoveFile(
269                from_file, dir, FileSystemOperation::OPTION_NONE, nosync));
270  // Destination's parent doesn't exist.
271  EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
272            NativeFileUtil::CopyOrMoveFile(
273                from_file, Path("nodir").AppendASCII("file"),
274                FileSystemOperation::OPTION_NONE, nosync));
275  // Destination's parent is a file.
276  EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
277            NativeFileUtil::CopyOrMoveFile(
278                from_file, Path("tofile1").AppendASCII("file"),
279                FileSystemOperation::OPTION_NONE, nosync));
280}
281
282TEST_F(NativeFileUtilTest, MoveFile) {
283  base::FilePath from_file = Path("fromfile");
284  base::FilePath to_file = Path("tofile");
285  const NativeFileUtil::CopyOrMoveMode move = NativeFileUtil::MOVE;
286  bool created = false;
287  ASSERT_EQ(base::File::FILE_OK,
288            NativeFileUtil::EnsureFileExists(from_file, &created));
289  ASSERT_TRUE(created);
290
291  ASSERT_EQ(base::File::FILE_OK, NativeFileUtil::Truncate(from_file, 1020));
292
293  EXPECT_TRUE(FileExists(from_file));
294  EXPECT_EQ(1020, GetSize(from_file));
295
296  ASSERT_EQ(base::File::FILE_OK,
297            NativeFileUtil::CopyOrMoveFile(
298                from_file, to_file, FileSystemOperation::OPTION_NONE, move));
299
300  EXPECT_FALSE(FileExists(from_file));
301  EXPECT_TRUE(FileExists(to_file));
302  EXPECT_EQ(1020, GetSize(to_file));
303
304  ASSERT_EQ(base::File::FILE_OK,
305            NativeFileUtil::EnsureFileExists(from_file, &created));
306  ASSERT_TRUE(FileExists(from_file));
307  ASSERT_EQ(base::File::FILE_OK, NativeFileUtil::Truncate(from_file, 1020));
308
309  base::FilePath dir = Path("dir");
310  ASSERT_EQ(base::File::FILE_OK,
311            NativeFileUtil::CreateDirectory(dir, false, false));
312  ASSERT_TRUE(base::DirectoryExists(dir));
313  base::FilePath to_dir_file = dir.AppendASCII("file");
314  ASSERT_EQ(base::File::FILE_OK,
315            NativeFileUtil::CopyOrMoveFile(
316                from_file, to_dir_file,
317                FileSystemOperation::OPTION_NONE, move));
318  EXPECT_FALSE(FileExists(from_file));
319  EXPECT_TRUE(FileExists(to_dir_file));
320  EXPECT_EQ(1020, GetSize(to_dir_file));
321
322  // Following is error checking.
323  // Source doesn't exist.
324  EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
325            NativeFileUtil::CopyOrMoveFile(
326                Path("nonexists"), Path("file"),
327                FileSystemOperation::OPTION_NONE, move));
328
329  // Source is not a file.
330  EXPECT_EQ(base::File::FILE_ERROR_NOT_A_FILE,
331            NativeFileUtil::CopyOrMoveFile(
332                dir, Path("file"), FileSystemOperation::OPTION_NONE, move));
333  ASSERT_EQ(base::File::FILE_OK,
334            NativeFileUtil::EnsureFileExists(from_file, &created));
335  ASSERT_TRUE(FileExists(from_file));
336  // Destination is not a file.
337  EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION,
338            NativeFileUtil::CopyOrMoveFile(
339                from_file, dir, FileSystemOperation::OPTION_NONE, move));
340
341  ASSERT_EQ(base::File::FILE_OK,
342            NativeFileUtil::EnsureFileExists(from_file, &created));
343  ASSERT_TRUE(FileExists(from_file));
344  // Destination's parent doesn't exist.
345  EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
346            NativeFileUtil::CopyOrMoveFile(
347                from_file, Path("nodir").AppendASCII("file"),
348                FileSystemOperation::OPTION_NONE, move));
349  // Destination's parent is a file.
350  EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
351            NativeFileUtil::CopyOrMoveFile(
352                from_file, Path("tofile1").AppendASCII("file"),
353                FileSystemOperation::OPTION_NONE, move));
354}
355
356TEST_F(NativeFileUtilTest, PreserveLastModified) {
357  base::FilePath from_file = Path("fromfile");
358  base::FilePath to_file1 = Path("tofile1");
359  base::FilePath to_file2 = Path("tofile2");
360  base::FilePath to_file3 = Path("tofile3");
361  bool created = false;
362  ASSERT_EQ(base::File::FILE_OK,
363            NativeFileUtil::EnsureFileExists(from_file, &created));
364  ASSERT_TRUE(created);
365  EXPECT_TRUE(FileExists(from_file));
366
367  base::File::Info file_info1;
368  ASSERT_EQ(base::File::FILE_OK,
369            NativeFileUtil::GetFileInfo(from_file, &file_info1));
370
371  // Test for copy (nosync).
372  ASSERT_EQ(base::File::FILE_OK,
373            NativeFileUtil::CopyOrMoveFile(
374                from_file, to_file1,
375                FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED,
376                NativeFileUtil::COPY_NOSYNC));
377
378  base::File::Info file_info2;
379  ASSERT_TRUE(FileExists(to_file1));
380  ASSERT_EQ(base::File::FILE_OK,
381            NativeFileUtil::GetFileInfo(to_file1, &file_info2));
382  EXPECT_EQ(file_info1.last_modified, file_info2.last_modified);
383
384  // Test for copy (sync).
385  ASSERT_EQ(base::File::FILE_OK,
386            NativeFileUtil::CopyOrMoveFile(
387                from_file, to_file2,
388                FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED,
389                NativeFileUtil::COPY_SYNC));
390
391  ASSERT_TRUE(FileExists(to_file2));
392  ASSERT_EQ(base::File::FILE_OK,
393            NativeFileUtil::GetFileInfo(to_file1, &file_info2));
394  EXPECT_EQ(file_info1.last_modified, file_info2.last_modified);
395
396  // Test for move.
397  ASSERT_EQ(base::File::FILE_OK,
398            NativeFileUtil::CopyOrMoveFile(
399                from_file, to_file3,
400                FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED,
401                NativeFileUtil::MOVE));
402
403  ASSERT_TRUE(FileExists(to_file3));
404  ASSERT_EQ(base::File::FILE_OK,
405            NativeFileUtil::GetFileInfo(to_file2, &file_info2));
406  EXPECT_EQ(file_info1.last_modified, file_info2.last_modified);
407}
408
409}  // namespace content
410