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/run_loop.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "content/public/test/async_file_test_helper.h"
15 #include "content/public/test/test_file_system_context.h"
16 #include "storage/browser/fileapi/async_file_util_adapter.h"
17 #include "storage/browser/fileapi/file_system_context.h"
18 #include "storage/browser/fileapi/file_system_file_util.h"
19 #include "storage/browser/fileapi/file_system_operation_context.h"
20 #include "storage/browser/fileapi/local_file_util.h"
21 #include "storage/browser/fileapi/native_file_util.h"
22 #include "storage/common/fileapi/file_system_types.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 using content::AsyncFileTestHelper
;
26 using storage::AsyncFileUtilAdapter
;
27 using storage::FileSystemContext
;
28 using storage::FileSystemOperationContext
;
29 using storage::FileSystemURL
;
30 using storage::LocalFileUtil
;
36 const GURL
kOrigin("http://foo/");
37 const storage::FileSystemType kFileSystemType
= storage::kFileSystemTypeTest
;
41 class LocalFileUtilTest
: public testing::Test
{
43 LocalFileUtilTest() {}
45 void SetUp() override
{
46 ASSERT_TRUE(data_dir_
.CreateUniqueTempDir());
47 file_system_context_
= CreateFileSystemContextForTesting(
48 NULL
, data_dir_
.path());
51 void TearDown() override
{
52 file_system_context_
= NULL
;
53 base::RunLoop().RunUntilIdle();
57 FileSystemOperationContext
* NewContext() {
58 FileSystemOperationContext
* context
=
59 new FileSystemOperationContext(file_system_context_
.get());
60 context
->set_update_observers(
61 *file_system_context_
->GetUpdateObservers(kFileSystemType
));
65 LocalFileUtil
* file_util() {
66 AsyncFileUtilAdapter
* adapter
= static_cast<AsyncFileUtilAdapter
*>(
67 file_system_context_
->GetAsyncFileUtil(kFileSystemType
));
68 return static_cast<LocalFileUtil
*>(adapter
->sync_file_util());
71 FileSystemURL
CreateURL(const std::string
& file_name
) {
72 return file_system_context_
->CreateCrackedFileSystemURL(
73 kOrigin
, kFileSystemType
, base::FilePath().FromUTF8Unsafe(file_name
));
76 base::FilePath
LocalPath(const char *file_name
) {
78 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
79 file_util()->GetLocalFilePath(context
.get(), CreateURL(file_name
), &path
);
83 bool FileExists(const char *file_name
) {
84 return base::PathExists(LocalPath(file_name
)) &&
85 !base::DirectoryExists(LocalPath(file_name
));
88 bool DirectoryExists(const char *file_name
) {
89 return base::DirectoryExists(LocalPath(file_name
));
92 int64
GetSize(const char *file_name
) {
93 base::File::Info info
;
94 base::GetFileInfo(LocalPath(file_name
), &info
);
98 base::File
CreateFile(const char* file_name
) {
99 int file_flags
= base::File::FLAG_CREATE
|
100 base::File::FLAG_WRITE
| base::File::FLAG_ASYNC
;
102 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
103 return file_util()->CreateOrOpen(context
.get(), CreateURL(file_name
),
107 base::File::Error
EnsureFileExists(const char* file_name
,
109 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
110 return file_util()->EnsureFileExists(context
.get(),
111 CreateURL(file_name
), created
);
114 FileSystemContext
* file_system_context() {
115 return file_system_context_
.get();
119 base::MessageLoop message_loop_
;
120 scoped_refptr
<FileSystemContext
> file_system_context_
;
121 base::ScopedTempDir data_dir_
;
123 DISALLOW_COPY_AND_ASSIGN(LocalFileUtilTest
);
126 TEST_F(LocalFileUtilTest
, CreateAndClose
) {
127 const char *file_name
= "test_file";
128 base::File file
= CreateFile(file_name
);
129 ASSERT_TRUE(file
.IsValid());
130 ASSERT_TRUE(file
.created());
132 EXPECT_TRUE(FileExists(file_name
));
133 EXPECT_EQ(0, GetSize(file_name
));
135 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
138 // base::CreateSymbolicLink is only supported on POSIX.
139 #if defined(OS_POSIX)
140 TEST_F(LocalFileUtilTest
, CreateFailForSymlink
) {
141 // Create symlink target file.
142 const char *target_name
= "symlink_target";
143 base::File target_file
= CreateFile(target_name
);
144 ASSERT_TRUE(target_file
.IsValid());
145 ASSERT_TRUE(target_file
.created());
146 base::FilePath target_path
= LocalPath(target_name
);
148 // Create symlink where target must be real file.
149 const char *symlink_name
= "symlink_file";
150 base::FilePath symlink_path
= LocalPath(symlink_name
);
151 ASSERT_TRUE(base::CreateSymbolicLink(target_path
, symlink_path
));
152 ASSERT_TRUE(FileExists(symlink_name
));
154 // Try to open the symlink file which should fail.
155 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
156 FileSystemURL url
= CreateURL(symlink_name
);
157 int file_flags
= base::File::FLAG_OPEN
| base::File::FLAG_READ
;
158 base::File file
= file_util()->CreateOrOpen(context
.get(), url
, file_flags
);
159 ASSERT_FALSE(file
.IsValid());
160 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND
, file
.error_details());
164 TEST_F(LocalFileUtilTest
, EnsureFileExists
) {
165 const char *file_name
= "foobar";
167 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(file_name
, &created
));
168 ASSERT_TRUE(created
);
170 EXPECT_TRUE(FileExists(file_name
));
171 EXPECT_EQ(0, GetSize(file_name
));
173 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(file_name
, &created
));
174 EXPECT_FALSE(created
);
177 TEST_F(LocalFileUtilTest
, TouchFile
) {
178 const char *file_name
= "test_file";
179 base::File file
= CreateFile(file_name
);
180 ASSERT_TRUE(file
.IsValid());
181 ASSERT_TRUE(file
.created());
183 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
185 base::File::Info info
;
186 ASSERT_TRUE(base::GetFileInfo(LocalPath(file_name
), &info
));
187 const base::Time new_accessed
=
188 info
.last_accessed
+ base::TimeDelta::FromHours(10);
189 const base::Time new_modified
=
190 info
.last_modified
+ base::TimeDelta::FromHours(5);
192 EXPECT_EQ(base::File::FILE_OK
,
193 file_util()->Touch(context
.get(), CreateURL(file_name
),
194 new_accessed
, new_modified
));
196 ASSERT_TRUE(base::GetFileInfo(LocalPath(file_name
), &info
));
197 EXPECT_EQ(new_accessed
, info
.last_accessed
);
198 EXPECT_EQ(new_modified
, info
.last_modified
);
201 TEST_F(LocalFileUtilTest
, TouchDirectory
) {
202 const char *dir_name
= "test_dir";
203 scoped_ptr
<FileSystemOperationContext
> context(NewContext());
204 ASSERT_EQ(base::File::FILE_OK
,
205 file_util()->CreateDirectory(context
.get(),
207 false /* exclusive */,
208 false /* recursive */));
210 base::File::Info info
;
211 ASSERT_TRUE(base::GetFileInfo(LocalPath(dir_name
), &info
));
212 const base::Time new_accessed
=
213 info
.last_accessed
+ base::TimeDelta::FromHours(10);
214 const base::Time new_modified
=
215 info
.last_modified
+ base::TimeDelta::FromHours(5);
217 EXPECT_EQ(base::File::FILE_OK
,
218 file_util()->Touch(context
.get(), CreateURL(dir_name
),
219 new_accessed
, new_modified
));
221 ASSERT_TRUE(base::GetFileInfo(LocalPath(dir_name
), &info
));
222 EXPECT_EQ(new_accessed
, info
.last_accessed
);
223 EXPECT_EQ(new_modified
, info
.last_modified
);
226 TEST_F(LocalFileUtilTest
, Truncate
) {
227 const char *file_name
= "truncated";
229 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(file_name
, &created
));
230 ASSERT_TRUE(created
);
232 scoped_ptr
<FileSystemOperationContext
> context
;
234 context
.reset(NewContext());
235 ASSERT_EQ(base::File::FILE_OK
,
236 file_util()->Truncate(context
.get(), CreateURL(file_name
), 1020));
238 EXPECT_TRUE(FileExists(file_name
));
239 EXPECT_EQ(1020, GetSize(file_name
));
242 TEST_F(LocalFileUtilTest
, CopyFile
) {
243 const char *from_file
= "fromfile";
244 const char *to_file1
= "tofile1";
245 const char *to_file2
= "tofile2";
247 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(from_file
, &created
));
248 ASSERT_TRUE(created
);
250 scoped_ptr
<FileSystemOperationContext
> context
;
251 context
.reset(NewContext());
252 ASSERT_EQ(base::File::FILE_OK
,
253 file_util()->Truncate(context
.get(), CreateURL(from_file
), 1020));
255 EXPECT_TRUE(FileExists(from_file
));
256 EXPECT_EQ(1020, GetSize(from_file
));
258 ASSERT_EQ(base::File::FILE_OK
,
259 AsyncFileTestHelper::Copy(file_system_context(),
260 CreateURL(from_file
),
261 CreateURL(to_file1
)));
263 context
.reset(NewContext());
264 ASSERT_EQ(base::File::FILE_OK
,
265 AsyncFileTestHelper::Copy(file_system_context(),
266 CreateURL(from_file
),
267 CreateURL(to_file2
)));
269 EXPECT_TRUE(FileExists(from_file
));
270 EXPECT_EQ(1020, GetSize(from_file
));
271 EXPECT_TRUE(FileExists(to_file1
));
272 EXPECT_EQ(1020, GetSize(to_file1
));
273 EXPECT_TRUE(FileExists(to_file2
));
274 EXPECT_EQ(1020, GetSize(to_file2
));
277 TEST_F(LocalFileUtilTest
, CopyDirectory
) {
278 const char *from_dir
= "fromdir";
279 const char *from_file
= "fromdir/fromfile";
280 const char *to_dir
= "todir";
281 const char *to_file
= "todir/fromfile";
283 scoped_ptr
<FileSystemOperationContext
> context
;
285 context
.reset(NewContext());
286 ASSERT_EQ(base::File::FILE_OK
,
287 file_util()->CreateDirectory(context
.get(), CreateURL(from_dir
),
289 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(from_file
, &created
));
290 ASSERT_TRUE(created
);
292 context
.reset(NewContext());
293 ASSERT_EQ(base::File::FILE_OK
,
294 file_util()->Truncate(context
.get(), CreateURL(from_file
), 1020));
296 EXPECT_TRUE(DirectoryExists(from_dir
));
297 EXPECT_TRUE(FileExists(from_file
));
298 EXPECT_EQ(1020, GetSize(from_file
));
299 EXPECT_FALSE(DirectoryExists(to_dir
));
301 context
.reset(NewContext());
302 ASSERT_EQ(base::File::FILE_OK
,
303 AsyncFileTestHelper::Copy(file_system_context(),
304 CreateURL(from_dir
), CreateURL(to_dir
)));
306 EXPECT_TRUE(DirectoryExists(from_dir
));
307 EXPECT_TRUE(FileExists(from_file
));
308 EXPECT_EQ(1020, GetSize(from_file
));
309 EXPECT_TRUE(DirectoryExists(to_dir
));
310 EXPECT_TRUE(FileExists(to_file
));
311 EXPECT_EQ(1020, GetSize(to_file
));
314 TEST_F(LocalFileUtilTest
, MoveFile
) {
315 const char *from_file
= "fromfile";
316 const char *to_file
= "tofile";
318 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(from_file
, &created
));
319 ASSERT_TRUE(created
);
320 scoped_ptr
<FileSystemOperationContext
> context
;
322 context
.reset(NewContext());
323 ASSERT_EQ(base::File::FILE_OK
,
324 file_util()->Truncate(context
.get(), CreateURL(from_file
), 1020));
326 EXPECT_TRUE(FileExists(from_file
));
327 EXPECT_EQ(1020, GetSize(from_file
));
329 context
.reset(NewContext());
330 ASSERT_EQ(base::File::FILE_OK
,
331 AsyncFileTestHelper::Move(file_system_context(),
332 CreateURL(from_file
),
333 CreateURL(to_file
)));
335 EXPECT_FALSE(FileExists(from_file
));
336 EXPECT_TRUE(FileExists(to_file
));
337 EXPECT_EQ(1020, GetSize(to_file
));
340 TEST_F(LocalFileUtilTest
, MoveDirectory
) {
341 const char *from_dir
= "fromdir";
342 const char *from_file
= "fromdir/fromfile";
343 const char *to_dir
= "todir";
344 const char *to_file
= "todir/fromfile";
346 scoped_ptr
<FileSystemOperationContext
> context
;
348 context
.reset(NewContext());
349 ASSERT_EQ(base::File::FILE_OK
,
350 file_util()->CreateDirectory(context
.get(), CreateURL(from_dir
),
352 ASSERT_EQ(base::File::FILE_OK
, EnsureFileExists(from_file
, &created
));
353 ASSERT_TRUE(created
);
355 context
.reset(NewContext());
356 ASSERT_EQ(base::File::FILE_OK
,
357 file_util()->Truncate(context
.get(), CreateURL(from_file
), 1020));
359 EXPECT_TRUE(DirectoryExists(from_dir
));
360 EXPECT_TRUE(FileExists(from_file
));
361 EXPECT_EQ(1020, GetSize(from_file
));
362 EXPECT_FALSE(DirectoryExists(to_dir
));
364 context
.reset(NewContext());
365 ASSERT_EQ(base::File::FILE_OK
,
366 AsyncFileTestHelper::Move(file_system_context(),
370 EXPECT_FALSE(DirectoryExists(from_dir
));
371 EXPECT_TRUE(DirectoryExists(to_dir
));
372 EXPECT_TRUE(FileExists(to_file
));
373 EXPECT_EQ(1020, GetSize(to_file
));
376 } // namespace content