- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / fileapi / recursive_operation_delegate_unittest.cc
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 "webkit/browser/fileapi/recursive_operation_delegate.h"
6
7 #include <vector>
8
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/run_loop.h"
16 #include "content/public/test/sandbox_file_system_test_helper.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "webkit/browser/fileapi/file_system_file_util.h"
19 #include "webkit/browser/fileapi/file_system_operation.h"
20 #include "webkit/browser/fileapi/file_system_operation_runner.h"
21
22 namespace fileapi {
23 namespace {
24
25 class LoggingRecursiveOperation : public RecursiveOperationDelegate {
26  public:
27   struct LogEntry {
28     enum Type {
29       PROCESS_FILE,
30       PROCESS_DIRECTORY,
31       POST_PROCESS_DIRECTORY
32     };
33     Type type;
34     FileSystemURL url;
35   };
36
37   LoggingRecursiveOperation(FileSystemContext* file_system_context,
38                             const FileSystemURL& root,
39                             const StatusCallback& callback)
40       : RecursiveOperationDelegate(file_system_context),
41         root_(root),
42         callback_(callback),
43         weak_factory_(this) {
44   }
45   virtual ~LoggingRecursiveOperation() {}
46
47   const std::vector<LogEntry>& log_entries() const { return log_entries_; }
48
49   // RecursiveOperationDelegate overrides.
50   virtual void Run() OVERRIDE {
51     NOTREACHED();
52   }
53
54   virtual void RunRecursively() OVERRIDE {
55     StartRecursiveOperation(root_, callback_);
56   }
57
58   virtual void ProcessFile(const FileSystemURL& url,
59                            const StatusCallback& callback) OVERRIDE {
60     RecordLogEntry(LogEntry::PROCESS_FILE, url);
61     operation_runner()->GetMetadata(
62         url,
63         base::Bind(&LoggingRecursiveOperation::DidGetMetadata,
64                    weak_factory_.GetWeakPtr(), callback));
65   }
66
67   virtual void ProcessDirectory(const FileSystemURL& url,
68                                 const StatusCallback& callback) OVERRIDE {
69     RecordLogEntry(LogEntry::PROCESS_DIRECTORY, url);
70     callback.Run(base::PLATFORM_FILE_OK);
71   }
72
73   virtual void PostProcessDirectory(const FileSystemURL& url,
74                                     const StatusCallback& callback) OVERRIDE {
75     RecordLogEntry(LogEntry::POST_PROCESS_DIRECTORY, url);
76     callback.Run(base::PLATFORM_FILE_OK);
77   }
78
79  private:
80   void RecordLogEntry(LogEntry::Type type, const FileSystemURL& url) {
81     LogEntry entry;
82     entry.type = type;
83     entry.url = url;
84     log_entries_.push_back(entry);
85   }
86
87   void DidGetMetadata(const StatusCallback& callback,
88                       base::PlatformFileError result,
89                       const base::PlatformFileInfo& file_info) {
90     if (result != base::PLATFORM_FILE_OK) {
91       callback.Run(result);
92       return;
93     }
94
95     callback.Run(file_info.is_directory ?
96                  base::PLATFORM_FILE_ERROR_NOT_A_FILE :
97                  base::PLATFORM_FILE_OK);
98   }
99
100   FileSystemURL root_;
101   StatusCallback callback_;
102   std::vector<LogEntry> log_entries_;
103
104   base::WeakPtrFactory<LoggingRecursiveOperation> weak_factory_;
105   DISALLOW_COPY_AND_ASSIGN(LoggingRecursiveOperation);
106 };
107
108 void ReportStatus(base::PlatformFileError* out_error,
109                   base::PlatformFileError error) {
110   DCHECK(out_error);
111   *out_error = error;
112 }
113
114 // To test the Cancel() during operation, calls Cancel() of |operation|
115 // after |counter| times message posting.
116 void CallCancelLater(RecursiveOperationDelegate* operation, int counter) {
117   if (counter > 0) {
118     base::MessageLoopProxy::current()->PostTask(
119         FROM_HERE,
120         base::Bind(&CallCancelLater, base::Unretained(operation), counter - 1));
121     return;
122   }
123
124   operation->Cancel();
125 }
126
127 }  // namespace
128
129 class RecursiveOperationDelegateTest : public testing::Test {
130  protected:
131   virtual void SetUp() OVERRIDE {
132     EXPECT_TRUE(base_.CreateUniqueTempDir());
133     sandbox_file_system_.SetUp(base_.path().AppendASCII("filesystem"));
134   }
135
136   virtual void TearDown() OVERRIDE {
137     sandbox_file_system_.TearDown();
138   }
139
140   scoped_ptr<FileSystemOperationContext> NewContext() {
141     FileSystemOperationContext* context =
142         sandbox_file_system_.NewOperationContext();
143     // Grant enough quota for all test cases.
144     context->set_allowed_bytes_growth(1000000);
145     return make_scoped_ptr(context);
146   }
147
148   FileSystemFileUtil* file_util() {
149     return sandbox_file_system_.file_util();
150   }
151
152   FileSystemURL URLForPath(const std::string& path) const {
153     return sandbox_file_system_.CreateURLFromUTF8(path);
154   }
155
156   FileSystemURL CreateFile(const std::string& path) {
157     FileSystemURL url = URLForPath(path);
158     bool created = false;
159     EXPECT_EQ(base::PLATFORM_FILE_OK,
160               file_util()->EnsureFileExists(NewContext().get(),
161                                             url, &created));
162     EXPECT_TRUE(created);
163     return url;
164   }
165
166   FileSystemURL CreateDirectory(const std::string& path) {
167     FileSystemURL url = URLForPath(path);
168     EXPECT_EQ(base::PLATFORM_FILE_OK,
169               file_util()->CreateDirectory(NewContext().get(), url,
170                                            false /* exclusive */, true));
171     return url;
172   }
173
174  private:
175   base::MessageLoop message_loop_;
176
177   // Common temp base for nondestructive uses.
178   base::ScopedTempDir base_;
179   SandboxFileSystemTestHelper sandbox_file_system_;
180 };
181
182 TEST_F(RecursiveOperationDelegateTest, RootIsFile) {
183   FileSystemURL src_file(CreateFile("src"));
184
185   base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
186   scoped_ptr<FileSystemOperationContext> context = NewContext();
187   scoped_ptr<LoggingRecursiveOperation> operation(
188       new LoggingRecursiveOperation(
189           context->file_system_context(), src_file,
190           base::Bind(&ReportStatus, &error)));
191   operation->RunRecursively();
192   base::RunLoop().RunUntilIdle();
193   ASSERT_EQ(base::PLATFORM_FILE_OK, error);
194
195   const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
196       operation->log_entries();
197   ASSERT_EQ(1U, log_entries.size());
198   const LoggingRecursiveOperation::LogEntry& entry = log_entries[0];
199   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, entry.type);
200   EXPECT_EQ(src_file, entry.url);
201 }
202
203 TEST_F(RecursiveOperationDelegateTest, RootIsDirectory) {
204   FileSystemURL src_root(CreateDirectory("src"));
205   FileSystemURL src_dir1(CreateDirectory("src/dir1"));
206   FileSystemURL src_file1(CreateFile("src/file1"));
207   FileSystemURL src_file2(CreateFile("src/dir1/file2"));
208   FileSystemURL src_file3(CreateFile("src/dir1/file3"));
209
210   base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
211   scoped_ptr<FileSystemOperationContext> context = NewContext();
212   scoped_ptr<LoggingRecursiveOperation> operation(
213       new LoggingRecursiveOperation(
214           context->file_system_context(), src_root,
215           base::Bind(&ReportStatus, &error)));
216   operation->RunRecursively();
217   base::RunLoop().RunUntilIdle();
218   ASSERT_EQ(base::PLATFORM_FILE_OK, error);
219
220   const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
221       operation->log_entries();
222   ASSERT_EQ(8U, log_entries.size());
223
224   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
225             log_entries[0].type);
226   EXPECT_EQ(src_root, log_entries[0].url);
227
228   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
229             log_entries[1].type);
230   EXPECT_EQ(src_root, log_entries[1].url);
231
232   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
233             log_entries[2].type);
234   EXPECT_EQ(src_file1, log_entries[2].url);
235
236   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
237             log_entries[3].type);
238   EXPECT_EQ(src_dir1, log_entries[3].url);
239
240   // The order of src/dir1/file2 and src/dir1/file3 depends on the file system
241   // implementation (can be swapped).
242   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
243             log_entries[4].type);
244   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
245             log_entries[5].type);
246   EXPECT_TRUE((src_file2 == log_entries[4].url &&
247                src_file3 == log_entries[5].url) ||
248               (src_file3 == log_entries[4].url &&
249                src_file2 == log_entries[5].url));
250
251   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
252             log_entries[6].type);
253   EXPECT_EQ(src_dir1, log_entries[6].url);
254
255   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
256             log_entries[7].type);
257   EXPECT_EQ(src_root, log_entries[7].url);
258 }
259
260 TEST_F(RecursiveOperationDelegateTest, Cancel) {
261   FileSystemURL src_root(CreateDirectory("src"));
262   FileSystemURL src_dir1(CreateDirectory("src/dir1"));
263   FileSystemURL src_file1(CreateFile("src/file1"));
264   FileSystemURL src_file2(CreateFile("src/dir1/file2"));
265
266   base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
267   scoped_ptr<FileSystemOperationContext> context = NewContext();
268   scoped_ptr<LoggingRecursiveOperation> operation(
269       new LoggingRecursiveOperation(
270           context->file_system_context(), src_root,
271           base::Bind(&ReportStatus, &error)));
272   operation->RunRecursively();
273
274   // Invoke Cancel(), after 5 times message posting.
275   CallCancelLater(operation.get(), 5);
276   base::RunLoop().RunUntilIdle();
277   ASSERT_EQ(base::PLATFORM_FILE_ERROR_ABORT, error);
278 }
279
280 }  // namespace fileapi