- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / media_galleries / fileapi / native_media_file_util_unittest.cc
1 // Copyright (c) 2012 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 #include <string>
7
8 #include "base/bind.h"
9 #include "base/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/format_macros.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
17 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
18 #include "content/public/test/test_browser_thread.h"
19 #include "content/public/test/test_file_system_options.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "webkit/browser/fileapi/external_mount_points.h"
22 #include "webkit/browser/fileapi/file_system_backend.h"
23 #include "webkit/browser/fileapi/file_system_context.h"
24 #include "webkit/browser/fileapi/file_system_operation_runner.h"
25 #include "webkit/browser/fileapi/file_system_url.h"
26 #include "webkit/browser/fileapi/isolated_context.h"
27 #include "webkit/browser/fileapi/native_file_util.h"
28 #include "webkit/browser/quota/mock_special_storage_policy.h"
29
30 #define FPL(x) FILE_PATH_LITERAL(x)
31
32 using fileapi::FileSystemOperation;
33 using fileapi::FileSystemURL;
34
35 namespace {
36
37 typedef FileSystemOperation::FileEntryList FileEntryList;
38
39 struct FilteringTestCase {
40   const base::FilePath::CharType* path;
41   bool is_directory;
42   bool visible;
43   bool media_file;
44   const char* content;
45 };
46
47 const FilteringTestCase kFilteringTestCases[] = {
48   // Directory should always be visible.
49   { FPL("hoge"), true, true, false, NULL },
50   { FPL("fuga.jpg"), true, true, false, NULL },
51   { FPL("piyo.txt"), true, true, false, NULL },
52   { FPL("moga.cod"), true, true, false, NULL },
53
54   // File should be visible if it's a supported media file.
55   // File without extension.
56   { FPL("foo"), false, false, false, "abc" },
57   // Supported media file.
58   { FPL("bar.jpg"), false, true, true, "\xFF\xD8\xFF" },
59   // Unsupported masquerading file.
60   { FPL("sna.jpg"), false, true, false, "abc" },
61   // Non-media file.
62   { FPL("baz.txt"), false, false, false, "abc" },
63   // Unsupported media file.
64   { FPL("foobar.cod"), false, false, false, "abc" },
65 };
66
67 void ExpectEqHelper(const std::string& test_name,
68                     base::PlatformFileError expected,
69                     base::PlatformFileError actual) {
70   EXPECT_EQ(expected, actual) << test_name;
71 }
72
73 void ExpectMetadataEqHelper(const std::string& test_name,
74                             base::PlatformFileError expected,
75                             bool expected_is_directory,
76                             base::PlatformFileError actual,
77                             const base::PlatformFileInfo& file_info) {
78   EXPECT_EQ(expected, actual) << test_name;
79   if (actual == base::PLATFORM_FILE_OK)
80     EXPECT_EQ(expected_is_directory, file_info.is_directory) << test_name;
81 }
82
83 void DidReadDirectory(std::set<base::FilePath::StringType>* content,
84                       bool* completed,
85                       base::PlatformFileError error,
86                       const FileEntryList& file_list,
87                       bool has_more) {
88   EXPECT_TRUE(!*completed);
89   *completed = !has_more;
90   for (FileEntryList::const_iterator itr = file_list.begin();
91        itr != file_list.end(); ++itr)
92     EXPECT_TRUE(content->insert(itr->name).second);
93 }
94
95 void PopulateDirectoryWithTestCases(const base::FilePath& dir,
96                                     const FilteringTestCase* test_cases,
97                                     size_t n) {
98   for (size_t i = 0; i < n; ++i) {
99     base::FilePath path = dir.Append(test_cases[i].path);
100     if (test_cases[i].is_directory) {
101       ASSERT_TRUE(file_util::CreateDirectory(path));
102     } else {
103       ASSERT_TRUE(test_cases[i].content != NULL);
104       int len = strlen(test_cases[i].content);
105       ASSERT_EQ(len, file_util::WriteFile(path, test_cases[i].content, len));
106     }
107   }
108 }
109
110 }  // namespace
111
112 class NativeMediaFileUtilTest : public testing::Test {
113  public:
114   NativeMediaFileUtilTest()
115       : io_thread_(content::BrowserThread::IO, &message_loop_) {
116   }
117
118   virtual void SetUp() {
119     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
120     ASSERT_TRUE(file_util::CreateDirectory(root_path()));
121
122     scoped_refptr<quota::SpecialStoragePolicy> storage_policy =
123         new quota::MockSpecialStoragePolicy();
124
125     ScopedVector<fileapi::FileSystemBackend> additional_providers;
126     additional_providers.push_back(new MediaFileSystemBackend(
127         data_dir_.path(), base::MessageLoopProxy::current().get()));
128
129     file_system_context_ = new fileapi::FileSystemContext(
130         base::MessageLoopProxy::current().get(),
131         base::MessageLoopProxy::current().get(),
132         fileapi::ExternalMountPoints::CreateRefCounted().get(),
133         storage_policy.get(),
134         NULL,
135         additional_providers.Pass(),
136         data_dir_.path(),
137         fileapi::CreateAllowFileAccessOptions());
138
139     filesystem_id_ = isolated_context()->RegisterFileSystemForPath(
140         fileapi::kFileSystemTypeNativeMedia, root_path(), NULL);
141
142     isolated_context()->AddReference(filesystem_id_);
143   }
144
145   virtual void TearDown() {
146     isolated_context()->RemoveReference(filesystem_id_);
147     file_system_context_ = NULL;
148   }
149
150  protected:
151   fileapi::FileSystemContext* file_system_context() {
152     return file_system_context_.get();
153   }
154
155   FileSystemURL CreateURL(const base::FilePath::CharType* test_case_path) {
156     return file_system_context_->CreateCrackedFileSystemURL(
157         origin(),
158         fileapi::kFileSystemTypeIsolated,
159         GetVirtualPath(test_case_path));
160   }
161
162   fileapi::IsolatedContext* isolated_context() {
163     return fileapi::IsolatedContext::GetInstance();
164   }
165
166   base::FilePath root_path() {
167     return data_dir_.path().Append(FPL("Media Directory"));
168   }
169
170   base::FilePath GetVirtualPath(
171       const base::FilePath::CharType* test_case_path) {
172     return base::FilePath::FromUTF8Unsafe(filesystem_id_).
173                Append(FPL("Media Directory")).
174                Append(base::FilePath(test_case_path));
175   }
176
177   GURL origin() {
178     return GURL("http://example.com");
179   }
180
181   fileapi::FileSystemType type() {
182     return fileapi::kFileSystemTypeNativeMedia;
183   }
184
185   fileapi::FileSystemOperationRunner* operation_runner() {
186     return file_system_context_->operation_runner();
187   }
188
189  private:
190   base::MessageLoop message_loop_;
191   content::TestBrowserThread io_thread_;
192
193   base::ScopedTempDir data_dir_;
194   scoped_refptr<fileapi::FileSystemContext> file_system_context_;
195
196   std::string filesystem_id_;
197
198   DISALLOW_COPY_AND_ASSIGN(NativeMediaFileUtilTest);
199 };
200
201 TEST_F(NativeMediaFileUtilTest, DirectoryExistsAndFileExistsFiltering) {
202   PopulateDirectoryWithTestCases(root_path(),
203                                  kFilteringTestCases,
204                                  arraysize(kFilteringTestCases));
205
206   for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
207     FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
208
209     base::PlatformFileError expectation =
210         kFilteringTestCases[i].visible ?
211         base::PLATFORM_FILE_OK :
212         base::PLATFORM_FILE_ERROR_NOT_FOUND;
213
214     std::string test_name =
215         base::StringPrintf("DirectoryExistsAndFileExistsFiltering %" PRIuS, i);
216     if (kFilteringTestCases[i].is_directory) {
217       operation_runner()->DirectoryExists(
218           url, base::Bind(&ExpectEqHelper, test_name, expectation));
219     } else {
220       operation_runner()->FileExists(
221           url, base::Bind(&ExpectEqHelper, test_name, expectation));
222     }
223     base::MessageLoop::current()->RunUntilIdle();
224   }
225 }
226
227 TEST_F(NativeMediaFileUtilTest, ReadDirectoryFiltering) {
228   PopulateDirectoryWithTestCases(root_path(),
229                                  kFilteringTestCases,
230                                  arraysize(kFilteringTestCases));
231
232   std::set<base::FilePath::StringType> content;
233   FileSystemURL url = CreateURL(FPL(""));
234   bool completed = false;
235   operation_runner()->ReadDirectory(
236       url, base::Bind(&DidReadDirectory, &content, &completed));
237   base::MessageLoop::current()->RunUntilIdle();
238   EXPECT_TRUE(completed);
239   EXPECT_EQ(6u, content.size());
240
241   for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
242     base::FilePath::StringType name =
243         base::FilePath(kFilteringTestCases[i].path).BaseName().value();
244     std::set<base::FilePath::StringType>::const_iterator found =
245         content.find(name);
246     EXPECT_EQ(kFilteringTestCases[i].visible, found != content.end());
247   }
248 }
249
250 TEST_F(NativeMediaFileUtilTest, CreateDirectoryFiltering) {
251   // Run the loop twice. The second loop attempts to create directories that are
252   // pre-existing. Though the result should be the same.
253   for (int loop_count = 0; loop_count < 2; ++loop_count) {
254     for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
255       if (kFilteringTestCases[i].is_directory) {
256         FileSystemURL root_url = CreateURL(FPL(""));
257         FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
258
259         std::string test_name = base::StringPrintf(
260             "CreateFileAndCreateDirectoryFiltering run %d, test %" PRIuS,
261             loop_count, i);
262         base::PlatformFileError expectation =
263             kFilteringTestCases[i].visible ?
264             base::PLATFORM_FILE_OK :
265             base::PLATFORM_FILE_ERROR_SECURITY;
266         operation_runner()->CreateDirectory(
267             url, false, false,
268             base::Bind(&ExpectEqHelper, test_name, expectation));
269       }
270       base::MessageLoop::current()->RunUntilIdle();
271     }
272   }
273 }
274
275 TEST_F(NativeMediaFileUtilTest, CopySourceFiltering) {
276   base::FilePath dest_path = root_path().AppendASCII("dest");
277   FileSystemURL dest_url = CreateURL(FPL("dest"));
278
279   // Run the loop twice. The first run has no source files. The second run does.
280   for (int loop_count = 0; loop_count < 2; ++loop_count) {
281     if (loop_count == 1) {
282       PopulateDirectoryWithTestCases(root_path(),
283                                      kFilteringTestCases,
284                                      arraysize(kFilteringTestCases));
285     }
286     for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
287       // Always start with an empty destination directory.
288       // Copying to a non-empty destination directory is an invalid operation.
289       ASSERT_TRUE(base::DeleteFile(dest_path, true));
290       ASSERT_TRUE(file_util::CreateDirectory(dest_path));
291
292       FileSystemURL root_url = CreateURL(FPL(""));
293       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
294
295       std::string test_name = base::StringPrintf(
296           "CopySourceFiltering run %d test %" PRIuS, loop_count, i);
297       base::PlatformFileError expectation = base::PLATFORM_FILE_OK;
298       if (loop_count == 0 || !kFilteringTestCases[i].visible) {
299         // If the source does not exist or is not visible.
300         expectation = base::PLATFORM_FILE_ERROR_NOT_FOUND;
301       } else if (!kFilteringTestCases[i].is_directory) {
302         // Cannot copy a visible file to a directory.
303         expectation = base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
304       }
305       operation_runner()->Copy(
306           url, dest_url,
307           fileapi::FileSystemOperation::OPTION_NONE,
308           fileapi::FileSystemOperationRunner::CopyProgressCallback(),
309           base::Bind(&ExpectEqHelper, test_name, expectation));
310       base::MessageLoop::current()->RunUntilIdle();
311     }
312   }
313 }
314
315 TEST_F(NativeMediaFileUtilTest, CopyDestFiltering) {
316   // Run the loop twice. The first run has no destination files.
317   // The second run does.
318   for (int loop_count = 0; loop_count < 2; ++loop_count) {
319     if (loop_count == 1) {
320       // Reset the test directory between the two loops to remove old
321       // directories and create new ones that should pre-exist.
322       ASSERT_TRUE(base::DeleteFile(root_path(), true));
323       ASSERT_TRUE(file_util::CreateDirectory(root_path()));
324       PopulateDirectoryWithTestCases(root_path(),
325                                      kFilteringTestCases,
326                                      arraysize(kFilteringTestCases));
327     }
328
329     // Always create a dummy source data file.
330     base::FilePath src_path = root_path().AppendASCII("foo.jpg");
331     FileSystemURL src_url = CreateURL(FPL("foo.jpg"));
332     static const char kDummyData[] = "dummy";
333     ASSERT_TRUE(file_util::WriteFile(src_path, kDummyData, strlen(kDummyData)));
334
335     for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
336       if (loop_count == 0 && kFilteringTestCases[i].is_directory) {
337         // These directories do not exist in this case, so Copy() will not
338         // treat them as directories. Thus invalidating these test cases.
339         continue;
340       }
341       FileSystemURL root_url = CreateURL(FPL(""));
342       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
343
344       std::string test_name = base::StringPrintf(
345           "CopyDestFiltering run %d test %" PRIuS, loop_count, i);
346       base::PlatformFileError expectation;
347       if (loop_count == 0) {
348         // The destination path is a file here. The directory case has been
349         // handled above.
350         // If the destination path does not exist and is not visible, then
351         // creating it would be a security violation.
352         expectation =
353             kFilteringTestCases[i].visible ?
354             base::PLATFORM_FILE_OK :
355             base::PLATFORM_FILE_ERROR_SECURITY;
356       } else {
357         if (!kFilteringTestCases[i].visible) {
358           // If the destination path exist and is not visible, then to the copy
359           // operation, it looks like the file needs to be created, which is a
360           // security violation.
361           expectation = base::PLATFORM_FILE_ERROR_SECURITY;
362         } else if (kFilteringTestCases[i].is_directory) {
363           // Cannot copy a file to a directory.
364           expectation = base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
365         } else {
366           // Copying from a file to a visible file that exists is ok.
367           expectation = base::PLATFORM_FILE_OK;
368         }
369       }
370       operation_runner()->Copy(
371           src_url, url,
372           fileapi::FileSystemOperation::OPTION_NONE,
373           fileapi::FileSystemOperationRunner::CopyProgressCallback(),
374           base::Bind(&ExpectEqHelper, test_name, expectation));
375       base::MessageLoop::current()->RunUntilIdle();
376     }
377   }
378 }
379
380 TEST_F(NativeMediaFileUtilTest, MoveSourceFiltering) {
381   base::FilePath dest_path = root_path().AppendASCII("dest");
382   FileSystemURL dest_url = CreateURL(FPL("dest"));
383
384   // Run the loop twice. The first run has no source files. The second run does.
385   for (int loop_count = 0; loop_count < 2; ++loop_count) {
386     if (loop_count == 1) {
387       PopulateDirectoryWithTestCases(root_path(),
388                                      kFilteringTestCases,
389                                      arraysize(kFilteringTestCases));
390     }
391     for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
392       // Always start with an empty destination directory.
393       // Moving to a non-empty destination directory is an invalid operation.
394       ASSERT_TRUE(base::DeleteFile(dest_path, true));
395       ASSERT_TRUE(file_util::CreateDirectory(dest_path));
396
397       FileSystemURL root_url = CreateURL(FPL(""));
398       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
399
400       std::string test_name = base::StringPrintf(
401           "MoveSourceFiltering run %d test %" PRIuS, loop_count, i);
402       base::PlatformFileError expectation = base::PLATFORM_FILE_OK;
403       if (loop_count == 0 || !kFilteringTestCases[i].visible) {
404         // If the source does not exist or is not visible.
405         expectation = base::PLATFORM_FILE_ERROR_NOT_FOUND;
406       } else if (!kFilteringTestCases[i].is_directory) {
407         // Cannot move a visible file to a directory.
408         expectation = base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
409       }
410       operation_runner()->Move(
411           url, dest_url, fileapi::FileSystemOperation::OPTION_NONE,
412           base::Bind(&ExpectEqHelper, test_name, expectation));
413       base::MessageLoop::current()->RunUntilIdle();
414     }
415   }
416 }
417
418 TEST_F(NativeMediaFileUtilTest, MoveDestFiltering) {
419   // Run the loop twice. The first run has no destination files.
420   // The second run does.
421   for (int loop_count = 0; loop_count < 2; ++loop_count) {
422     if (loop_count == 1) {
423       // Reset the test directory between the two loops to remove old
424       // directories and create new ones that should pre-exist.
425       ASSERT_TRUE(base::DeleteFile(root_path(), true));
426       ASSERT_TRUE(file_util::CreateDirectory(root_path()));
427       PopulateDirectoryWithTestCases(root_path(),
428                                      kFilteringTestCases,
429                                      arraysize(kFilteringTestCases));
430     }
431
432     for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
433       if (loop_count == 0 && kFilteringTestCases[i].is_directory) {
434         // These directories do not exist in this case, so Copy() will not
435         // treat them as directories. Thus invalidating these test cases.
436         continue;
437       }
438
439       // Create the source file for every test case because it might get moved.
440       base::FilePath src_path = root_path().AppendASCII("foo.jpg");
441       FileSystemURL src_url = CreateURL(FPL("foo.jpg"));
442       static const char kDummyData[] = "dummy";
443       ASSERT_TRUE(
444           file_util::WriteFile(src_path, kDummyData, strlen(kDummyData)));
445
446       FileSystemURL root_url = CreateURL(FPL(""));
447       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
448
449       std::string test_name = base::StringPrintf(
450           "MoveDestFiltering run %d test %" PRIuS, loop_count, i);
451       base::PlatformFileError expectation;
452       if (loop_count == 0) {
453         // The destination path is a file here. The directory case has been
454         // handled above.
455         // If the destination path does not exist and is not visible, then
456         // creating it would be a security violation.
457         expectation =
458             kFilteringTestCases[i].visible ?
459             base::PLATFORM_FILE_OK :
460             base::PLATFORM_FILE_ERROR_SECURITY;
461       } else {
462         if (!kFilteringTestCases[i].visible) {
463           // If the destination path exist and is not visible, then to the move
464           // operation, it looks like the file needs to be created, which is a
465           // security violation.
466           expectation = base::PLATFORM_FILE_ERROR_SECURITY;
467         } else if (kFilteringTestCases[i].is_directory) {
468           // Cannot move a file to a directory.
469           expectation = base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
470         } else {
471           // Moving from a file to a visible file that exists is ok.
472           expectation = base::PLATFORM_FILE_OK;
473         }
474       }
475       operation_runner()->Move(
476           src_url, url, fileapi::FileSystemOperation::OPTION_NONE,
477           base::Bind(&ExpectEqHelper, test_name, expectation));
478       base::MessageLoop::current()->RunUntilIdle();
479     }
480   }
481 }
482
483 TEST_F(NativeMediaFileUtilTest, GetMetadataFiltering) {
484   // Run the loop twice. The first run has no files. The second run does.
485   for (int loop_count = 0; loop_count < 2; ++loop_count) {
486     if (loop_count == 1) {
487       PopulateDirectoryWithTestCases(root_path(),
488                                      kFilteringTestCases,
489                                      arraysize(kFilteringTestCases));
490     }
491     for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
492       FileSystemURL root_url = CreateURL(FPL(""));
493       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
494
495       std::string test_name = base::StringPrintf(
496           "GetMetadataFiltering run %d test %" PRIuS, loop_count, i);
497       base::PlatformFileError expectation = base::PLATFORM_FILE_OK;
498       if (loop_count == 0 || !kFilteringTestCases[i].visible) {
499         // Cannot get metadata from files that do not exist or are not visible.
500         expectation = base::PLATFORM_FILE_ERROR_NOT_FOUND;
501       }
502       operation_runner()->GetMetadata(
503           url,
504           base::Bind(&ExpectMetadataEqHelper,
505                      test_name,
506                      expectation,
507                      kFilteringTestCases[i].is_directory));
508       base::MessageLoop::current()->RunUntilIdle();
509     }
510   }
511 }
512
513 void CreateSnapshotCallback(base::PlatformFileError* error,
514     base::PlatformFileError result, const base::PlatformFileInfo&,
515     const base::FilePath&,
516     const scoped_refptr<webkit_blob::ShareableFileReference>&) {
517   *error = result;
518 }
519
520 TEST_F(NativeMediaFileUtilTest, CreateSnapshot) {
521   PopulateDirectoryWithTestCases(root_path(),
522                                  kFilteringTestCases,
523                                  arraysize(kFilteringTestCases));
524   for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
525     if (kFilteringTestCases[i].is_directory ||
526         !kFilteringTestCases[i].visible) {
527       continue;
528     }
529     FileSystemURL root_url = CreateURL(FPL(""));
530     FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
531     base::PlatformFileError expected_error, error;
532     if (kFilteringTestCases[i].media_file)
533       expected_error = base::PLATFORM_FILE_OK;
534     else
535       expected_error = base::PLATFORM_FILE_ERROR_SECURITY;
536     error = base::PLATFORM_FILE_ERROR_FAILED;
537     operation_runner()->CreateSnapshotFile(url,
538         base::Bind(CreateSnapshotCallback, &error));
539     base::MessageLoop::current()->RunUntilIdle();
540     ASSERT_EQ(expected_error, error);
541   }
542 }