• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 <string>
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 "base/message_loop/message_loop_proxy.h"
12 #include "base/run_loop.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "content/public/test/async_file_test_helper.h"
16 #include "content/public/test/test_file_system_context.h"
17 #include "storage/browser/fileapi/async_file_util_adapter.h"
18 #include "storage/browser/fileapi/file_system_context.h"
19 #include "storage/browser/fileapi/file_system_file_util.h"
20 #include "storage/browser/fileapi/file_system_operation_context.h"
21 #include "storage/browser/fileapi/local_file_util.h"
22 #include "storage/browser/fileapi/native_file_util.h"
23 #include "storage/common/fileapi/file_system_types.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 using content::AsyncFileTestHelper;
27 using storage::AsyncFileUtilAdapter;
28 using storage::FileSystemContext;
29 using storage::FileSystemOperationContext;
30 using storage::FileSystemURL;
31 using storage::LocalFileUtil;
32 
33 namespace content {
34 
35 namespace {
36 
37 const GURL kOrigin("http://foo/");
38 const storage::FileSystemType kFileSystemType = storage::kFileSystemTypeTest;
39 
40 }  // namespace
41 
42 class LocalFileUtilTest : public testing::Test {
43  public:
LocalFileUtilTest()44   LocalFileUtilTest() {}
45 
SetUp()46   virtual void SetUp() {
47     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
48     file_system_context_ = CreateFileSystemContextForTesting(
49         NULL, data_dir_.path());
50   }
51 
TearDown()52   virtual void TearDown() {
53     file_system_context_ = NULL;
54     base::RunLoop().RunUntilIdle();
55   }
56 
57  protected:
NewContext()58   FileSystemOperationContext* NewContext() {
59     FileSystemOperationContext* context =
60         new FileSystemOperationContext(file_system_context_.get());
61     context->set_update_observers(
62         *file_system_context_->GetUpdateObservers(kFileSystemType));
63     return context;
64   }
65 
file_util()66   LocalFileUtil* file_util() {
67     AsyncFileUtilAdapter* adapter = static_cast<AsyncFileUtilAdapter*>(
68         file_system_context_->GetAsyncFileUtil(kFileSystemType));
69     return static_cast<LocalFileUtil*>(adapter->sync_file_util());
70   }
71 
CreateURL(const std::string & file_name)72   FileSystemURL CreateURL(const std::string& file_name) {
73     return file_system_context_->CreateCrackedFileSystemURL(
74         kOrigin, kFileSystemType, base::FilePath().FromUTF8Unsafe(file_name));
75   }
76 
LocalPath(const char * file_name)77   base::FilePath LocalPath(const char *file_name) {
78     base::FilePath path;
79     scoped_ptr<FileSystemOperationContext> context(NewContext());
80     file_util()->GetLocalFilePath(context.get(), CreateURL(file_name), &path);
81     return path;
82   }
83 
FileExists(const char * file_name)84   bool FileExists(const char *file_name) {
85     return base::PathExists(LocalPath(file_name)) &&
86         !base::DirectoryExists(LocalPath(file_name));
87   }
88 
DirectoryExists(const char * file_name)89   bool DirectoryExists(const char *file_name) {
90     return base::DirectoryExists(LocalPath(file_name));
91   }
92 
GetSize(const char * file_name)93   int64 GetSize(const char *file_name) {
94     base::File::Info info;
95     base::GetFileInfo(LocalPath(file_name), &info);
96     return info.size;
97   }
98 
CreateFile(const char * file_name)99   base::File CreateFile(const char* file_name) {
100     int file_flags = base::File::FLAG_CREATE |
101                      base::File::FLAG_WRITE | base::File::FLAG_ASYNC;
102 
103     scoped_ptr<FileSystemOperationContext> context(NewContext());
104     return file_util()->CreateOrOpen(context.get(), CreateURL(file_name),
105                                      file_flags);
106   }
107 
EnsureFileExists(const char * file_name,bool * created)108   base::File::Error EnsureFileExists(const char* file_name,
109                                      bool* created) {
110     scoped_ptr<FileSystemOperationContext> context(NewContext());
111     return file_util()->EnsureFileExists(context.get(),
112                                          CreateURL(file_name), created);
113   }
114 
file_system_context()115   FileSystemContext* file_system_context() {
116     return file_system_context_.get();
117   }
118 
119  private:
120   base::MessageLoop message_loop_;
121   scoped_refptr<FileSystemContext> file_system_context_;
122   base::ScopedTempDir data_dir_;
123 
124   DISALLOW_COPY_AND_ASSIGN(LocalFileUtilTest);
125 };
126 
TEST_F(LocalFileUtilTest,CreateAndClose)127 TEST_F(LocalFileUtilTest, CreateAndClose) {
128   const char *file_name = "test_file";
129   base::File file = CreateFile(file_name);
130   ASSERT_TRUE(file.IsValid());
131   ASSERT_TRUE(file.created());
132 
133   EXPECT_TRUE(FileExists(file_name));
134   EXPECT_EQ(0, GetSize(file_name));
135 
136   scoped_ptr<FileSystemOperationContext> context(NewContext());
137 }
138 
139 // base::CreateSymbolicLink is only supported on POSIX.
140 #if defined(OS_POSIX)
TEST_F(LocalFileUtilTest,CreateFailForSymlink)141 TEST_F(LocalFileUtilTest, CreateFailForSymlink) {
142   // Create symlink target file.
143   const char *target_name = "symlink_target";
144   base::File target_file = CreateFile(target_name);
145   ASSERT_TRUE(target_file.IsValid());
146   ASSERT_TRUE(target_file.created());
147   base::FilePath target_path = LocalPath(target_name);
148 
149   // Create symlink where target must be real file.
150   const char *symlink_name = "symlink_file";
151   base::FilePath symlink_path = LocalPath(symlink_name);
152   ASSERT_TRUE(base::CreateSymbolicLink(target_path, symlink_path));
153   ASSERT_TRUE(FileExists(symlink_name));
154 
155   // Try to open the symlink file which should fail.
156   scoped_ptr<FileSystemOperationContext> context(NewContext());
157   FileSystemURL url = CreateURL(symlink_name);
158   int file_flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
159   base::File file = file_util()->CreateOrOpen(context.get(), url, file_flags);
160   ASSERT_FALSE(file.IsValid());
161   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details());
162 }
163 #endif
164 
TEST_F(LocalFileUtilTest,EnsureFileExists)165 TEST_F(LocalFileUtilTest, EnsureFileExists) {
166   const char *file_name = "foobar";
167   bool created;
168   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(file_name, &created));
169   ASSERT_TRUE(created);
170 
171   EXPECT_TRUE(FileExists(file_name));
172   EXPECT_EQ(0, GetSize(file_name));
173 
174   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(file_name, &created));
175   EXPECT_FALSE(created);
176 }
177 
TEST_F(LocalFileUtilTest,TouchFile)178 TEST_F(LocalFileUtilTest, TouchFile) {
179   const char *file_name = "test_file";
180   base::File file = CreateFile(file_name);
181   ASSERT_TRUE(file.IsValid());
182   ASSERT_TRUE(file.created());
183 
184   scoped_ptr<FileSystemOperationContext> context(NewContext());
185 
186   base::File::Info info;
187   ASSERT_TRUE(base::GetFileInfo(LocalPath(file_name), &info));
188   const base::Time new_accessed =
189       info.last_accessed + base::TimeDelta::FromHours(10);
190   const base::Time new_modified =
191       info.last_modified + base::TimeDelta::FromHours(5);
192 
193   EXPECT_EQ(base::File::FILE_OK,
194             file_util()->Touch(context.get(), CreateURL(file_name),
195                               new_accessed, new_modified));
196 
197   ASSERT_TRUE(base::GetFileInfo(LocalPath(file_name), &info));
198   EXPECT_EQ(new_accessed, info.last_accessed);
199   EXPECT_EQ(new_modified, info.last_modified);
200 }
201 
TEST_F(LocalFileUtilTest,TouchDirectory)202 TEST_F(LocalFileUtilTest, TouchDirectory) {
203   const char *dir_name = "test_dir";
204   scoped_ptr<FileSystemOperationContext> context(NewContext());
205   ASSERT_EQ(base::File::FILE_OK,
206             file_util()->CreateDirectory(context.get(),
207                                         CreateURL(dir_name),
208                                         false /* exclusive */,
209                                         false /* recursive */));
210 
211   base::File::Info info;
212   ASSERT_TRUE(base::GetFileInfo(LocalPath(dir_name), &info));
213   const base::Time new_accessed =
214       info.last_accessed + base::TimeDelta::FromHours(10);
215   const base::Time new_modified =
216       info.last_modified + base::TimeDelta::FromHours(5);
217 
218   EXPECT_EQ(base::File::FILE_OK,
219             file_util()->Touch(context.get(), CreateURL(dir_name),
220                               new_accessed, new_modified));
221 
222   ASSERT_TRUE(base::GetFileInfo(LocalPath(dir_name), &info));
223   EXPECT_EQ(new_accessed, info.last_accessed);
224   EXPECT_EQ(new_modified, info.last_modified);
225 }
226 
TEST_F(LocalFileUtilTest,Truncate)227 TEST_F(LocalFileUtilTest, Truncate) {
228   const char *file_name = "truncated";
229   bool created;
230   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(file_name, &created));
231   ASSERT_TRUE(created);
232 
233   scoped_ptr<FileSystemOperationContext> context;
234 
235   context.reset(NewContext());
236   ASSERT_EQ(base::File::FILE_OK,
237             file_util()->Truncate(context.get(), CreateURL(file_name), 1020));
238 
239   EXPECT_TRUE(FileExists(file_name));
240   EXPECT_EQ(1020, GetSize(file_name));
241 }
242 
TEST_F(LocalFileUtilTest,CopyFile)243 TEST_F(LocalFileUtilTest, CopyFile) {
244   const char *from_file = "fromfile";
245   const char *to_file1 = "tofile1";
246   const char *to_file2 = "tofile2";
247   bool created;
248   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(from_file, &created));
249   ASSERT_TRUE(created);
250 
251   scoped_ptr<FileSystemOperationContext> context;
252   context.reset(NewContext());
253   ASSERT_EQ(base::File::FILE_OK,
254             file_util()->Truncate(context.get(), CreateURL(from_file), 1020));
255 
256   EXPECT_TRUE(FileExists(from_file));
257   EXPECT_EQ(1020, GetSize(from_file));
258 
259   ASSERT_EQ(base::File::FILE_OK,
260             AsyncFileTestHelper::Copy(file_system_context(),
261                                       CreateURL(from_file),
262                                       CreateURL(to_file1)));
263 
264   context.reset(NewContext());
265   ASSERT_EQ(base::File::FILE_OK,
266             AsyncFileTestHelper::Copy(file_system_context(),
267                                       CreateURL(from_file),
268                                       CreateURL(to_file2)));
269 
270   EXPECT_TRUE(FileExists(from_file));
271   EXPECT_EQ(1020, GetSize(from_file));
272   EXPECT_TRUE(FileExists(to_file1));
273   EXPECT_EQ(1020, GetSize(to_file1));
274   EXPECT_TRUE(FileExists(to_file2));
275   EXPECT_EQ(1020, GetSize(to_file2));
276 }
277 
TEST_F(LocalFileUtilTest,CopyDirectory)278 TEST_F(LocalFileUtilTest, CopyDirectory) {
279   const char *from_dir = "fromdir";
280   const char *from_file = "fromdir/fromfile";
281   const char *to_dir = "todir";
282   const char *to_file = "todir/fromfile";
283   bool created;
284   scoped_ptr<FileSystemOperationContext> context;
285 
286   context.reset(NewContext());
287   ASSERT_EQ(base::File::FILE_OK,
288             file_util()->CreateDirectory(context.get(), CreateURL(from_dir),
289                                          false, false));
290   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(from_file, &created));
291   ASSERT_TRUE(created);
292 
293   context.reset(NewContext());
294   ASSERT_EQ(base::File::FILE_OK,
295             file_util()->Truncate(context.get(), CreateURL(from_file), 1020));
296 
297   EXPECT_TRUE(DirectoryExists(from_dir));
298   EXPECT_TRUE(FileExists(from_file));
299   EXPECT_EQ(1020, GetSize(from_file));
300   EXPECT_FALSE(DirectoryExists(to_dir));
301 
302   context.reset(NewContext());
303   ASSERT_EQ(base::File::FILE_OK,
304             AsyncFileTestHelper::Copy(file_system_context(),
305                                       CreateURL(from_dir), CreateURL(to_dir)));
306 
307   EXPECT_TRUE(DirectoryExists(from_dir));
308   EXPECT_TRUE(FileExists(from_file));
309   EXPECT_EQ(1020, GetSize(from_file));
310   EXPECT_TRUE(DirectoryExists(to_dir));
311   EXPECT_TRUE(FileExists(to_file));
312   EXPECT_EQ(1020, GetSize(to_file));
313 }
314 
TEST_F(LocalFileUtilTest,MoveFile)315 TEST_F(LocalFileUtilTest, MoveFile) {
316   const char *from_file = "fromfile";
317   const char *to_file = "tofile";
318   bool created;
319   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(from_file, &created));
320   ASSERT_TRUE(created);
321   scoped_ptr<FileSystemOperationContext> context;
322 
323   context.reset(NewContext());
324   ASSERT_EQ(base::File::FILE_OK,
325             file_util()->Truncate(context.get(), CreateURL(from_file), 1020));
326 
327   EXPECT_TRUE(FileExists(from_file));
328   EXPECT_EQ(1020, GetSize(from_file));
329 
330   context.reset(NewContext());
331   ASSERT_EQ(base::File::FILE_OK,
332             AsyncFileTestHelper::Move(file_system_context(),
333                                       CreateURL(from_file),
334                                       CreateURL(to_file)));
335 
336   EXPECT_FALSE(FileExists(from_file));
337   EXPECT_TRUE(FileExists(to_file));
338   EXPECT_EQ(1020, GetSize(to_file));
339 }
340 
TEST_F(LocalFileUtilTest,MoveDirectory)341 TEST_F(LocalFileUtilTest, MoveDirectory) {
342   const char *from_dir = "fromdir";
343   const char *from_file = "fromdir/fromfile";
344   const char *to_dir = "todir";
345   const char *to_file = "todir/fromfile";
346   bool created;
347   scoped_ptr<FileSystemOperationContext> context;
348 
349   context.reset(NewContext());
350   ASSERT_EQ(base::File::FILE_OK,
351             file_util()->CreateDirectory(context.get(), CreateURL(from_dir),
352                                          false, false));
353   ASSERT_EQ(base::File::FILE_OK, EnsureFileExists(from_file, &created));
354   ASSERT_TRUE(created);
355 
356   context.reset(NewContext());
357   ASSERT_EQ(base::File::FILE_OK,
358             file_util()->Truncate(context.get(), CreateURL(from_file), 1020));
359 
360   EXPECT_TRUE(DirectoryExists(from_dir));
361   EXPECT_TRUE(FileExists(from_file));
362   EXPECT_EQ(1020, GetSize(from_file));
363   EXPECT_FALSE(DirectoryExists(to_dir));
364 
365   context.reset(NewContext());
366   ASSERT_EQ(base::File::FILE_OK,
367             AsyncFileTestHelper::Move(file_system_context(),
368                                       CreateURL(from_dir),
369                                       CreateURL(to_dir)));
370 
371   EXPECT_FALSE(DirectoryExists(from_dir));
372   EXPECT_TRUE(DirectoryExists(to_dir));
373   EXPECT_TRUE(FileExists(to_file));
374   EXPECT_EQ(1020, GetSize(to_file));
375 }
376 
377 }  // namespace content
378