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.
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"
26 using content::AsyncFileTestHelper
;
27 using storage::AsyncFileUtilAdapter
;
28 using storage::FileSystemContext
;
29 using storage::FileSystemOperationContext
;
30 using storage::FileSystemURL
;
31 using storage::LocalFileUtil
;
37 const GURL
kOrigin("http://foo/");
38 const storage::FileSystemType kFileSystemType
= storage::kFileSystemTypeTest
;
42 class LocalFileUtilTest
: public testing::Test
{
44 LocalFileUtilTest() {}
46 void SetUp() override
{
47 ASSERT_TRUE(data_dir_
.CreateUniqueTempDir());
48 file_system_context_
= CreateFileSystemContextForTesting(
49 NULL
, data_dir_
.path());
52 void TearDown() override
{
53 file_system_context_
= NULL
;
54 base::RunLoop().RunUntilIdle();
58 FileSystemOperationContext
* NewContext() {
59 FileSystemOperationContext
* context
=
60 new FileSystemOperationContext(file_system_context_
.get());
61 context
->set_update_observers(
62 *file_system_context_
->GetUpdateObservers(kFileSystemType
));
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());
72 FileSystemURL
CreateURL(const std::string
& file_name
) {
73 return file_system_context_
->CreateCrackedFileSystemURL(
74 kOrigin
, kFileSystemType
, base::FilePath().FromUTF8Unsafe(file_name
));
77 base::FilePath
LocalPath(const char *file_name
) {
79 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
80 file_util()->GetLocalFilePath(context
.get(), CreateURL(file_name
), &path
);
84 bool FileExists(const char *file_name
) {
85 return base::PathExists(LocalPath(file_name
)) &&
86 !base::DirectoryExists(LocalPath(file_name
));
89 bool DirectoryExists(const char *file_name
) {
90 return base::DirectoryExists(LocalPath(file_name
));
93 int64
GetSize(const char *file_name
) {
94 base::File::Info info
;
95 base::GetFileInfo(LocalPath(file_name
), &info
);
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
;
103 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
104 return file_util()->CreateOrOpen(context
.get(), CreateURL(file_name
),
108 base::File::Error
EnsureFileExists(const char* file_name
,
110 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
111 return file_util()->EnsureFileExists(context
.get(),
112 CreateURL(file_name
), created
);
115 FileSystemContext
* file_system_context() {
116 return file_system_context_
.get();
120 base::MessageLoop message_loop_
;
121 scoped_refptr
<FileSystemContext
> file_system_context_
;
122 base::ScopedTempDir data_dir_
;
124 DISALLOW_COPY_AND_ASSIGN(LocalFileUtilTest
);
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());
133 EXPECT_TRUE(FileExists(file_name
));
134 EXPECT_EQ(0, GetSize(file_name
));
136 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
139 // base::CreateSymbolicLink is only supported on POSIX.
140 #if defined(OS_POSIX)
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
);
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
));
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());
165 TEST_F(LocalFileUtilTest
, EnsureFileExists
) {
166 const char *file_name
= "foobar";
168 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(file_name
, &created
));
169 ASSERT_TRUE(created
);
171 EXPECT_TRUE(FileExists(file_name
));
172 EXPECT_EQ(0, GetSize(file_name
));
174 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(file_name
, &created
));
175 EXPECT_FALSE(created
);
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());
184 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
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);
193 EXPECT_EQ(base::File::FILE_OK
,
194 file_util()->Touch(context
.get(), CreateURL(file_name
),
195 new_accessed
, new_modified
));
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
);
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(),
208 false /* exclusive */,
209 false /* recursive */));
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);
218 EXPECT_EQ(base::File::FILE_OK
,
219 file_util()->Touch(context
.get(), CreateURL(dir_name
),
220 new_accessed
, new_modified
));
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
);
227 TEST_F(LocalFileUtilTest
, Truncate
) {
228 const char *file_name
= "truncated";
230 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(file_name
, &created
));
231 ASSERT_TRUE(created
);
233 scoped_ptr
<FileSystemOperationContext
> context
;
235 context
.reset(NewContext());
236 ASSERT_EQ(base::File::FILE_OK
,
237 file_util()->Truncate(context
.get(), CreateURL(file_name
), 1020));
239 EXPECT_TRUE(FileExists(file_name
));
240 EXPECT_EQ(1020, GetSize(file_name
));
243 TEST_F(LocalFileUtilTest
, CopyFile
) {
244 const char *from_file
= "fromfile";
245 const char *to_file1
= "tofile1";
246 const char *to_file2
= "tofile2";
248 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(from_file
, &created
));
249 ASSERT_TRUE(created
);
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));
256 EXPECT_TRUE(FileExists(from_file
));
257 EXPECT_EQ(1020, GetSize(from_file
));
259 ASSERT_EQ(base::File::FILE_OK
,
260 AsyncFileTestHelper::Copy(file_system_context(),
261 CreateURL(from_file
),
262 CreateURL(to_file1
)));
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
)));
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
));
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";
284 scoped_ptr
<FileSystemOperationContext
> context
;
286 context
.reset(NewContext());
287 ASSERT_EQ(base::File::FILE_OK
,
288 file_util()->CreateDirectory(context
.get(), CreateURL(from_dir
),
290 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(from_file
, &created
));
291 ASSERT_TRUE(created
);
293 context
.reset(NewContext());
294 ASSERT_EQ(base::File::FILE_OK
,
295 file_util()->Truncate(context
.get(), CreateURL(from_file
), 1020));
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
));
302 context
.reset(NewContext());
303 ASSERT_EQ(base::File::FILE_OK
,
304 AsyncFileTestHelper::Copy(file_system_context(),
305 CreateURL(from_dir
), CreateURL(to_dir
)));
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
));
315 TEST_F(LocalFileUtilTest
, MoveFile
) {
316 const char *from_file
= "fromfile";
317 const char *to_file
= "tofile";
319 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(from_file
, &created
));
320 ASSERT_TRUE(created
);
321 scoped_ptr
<FileSystemOperationContext
> context
;
323 context
.reset(NewContext());
324 ASSERT_EQ(base::File::FILE_OK
,
325 file_util()->Truncate(context
.get(), CreateURL(from_file
), 1020));
327 EXPECT_TRUE(FileExists(from_file
));
328 EXPECT_EQ(1020, GetSize(from_file
));
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
)));
336 EXPECT_FALSE(FileExists(from_file
));
337 EXPECT_TRUE(FileExists(to_file
));
338 EXPECT_EQ(1020, GetSize(to_file
));
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";
347 scoped_ptr
<FileSystemOperationContext
> context
;
349 context
.reset(NewContext());
350 ASSERT_EQ(base::File::FILE_OK
,
351 file_util()->CreateDirectory(context
.get(), CreateURL(from_dir
),
353 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(from_file
, &created
));
354 ASSERT_TRUE(created
);
356 context
.reset(NewContext());
357 ASSERT_EQ(base::File::FILE_OK
,
358 file_util()->Truncate(context
.get(), CreateURL(from_file
), 1020));
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
));
365 context
.reset(NewContext());
366 ASSERT_EQ(base::File::FILE_OK
,
367 AsyncFileTestHelper::Move(file_system_context(),
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
));
377 } // namespace content