Add ICU message format support
[chromium-blink-merge.git] / content / browser / fileapi / recursive_operation_delegate_unittest.cc
bloba99a5575a2d88d50d89a3c8c419935a1aed37b7d
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.
5 #include "storage/browser/fileapi/recursive_operation_delegate.h"
7 #include <vector>
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/location.h"
14 #include "base/run_loop.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "content/public/test/sandbox_file_system_test_helper.h"
18 #include "storage/browser/fileapi/file_system_file_util.h"
19 #include "storage/browser/fileapi/file_system_operation.h"
20 #include "storage/browser/fileapi/file_system_operation_runner.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using storage::FileSystemContext;
24 using storage::FileSystemOperationContext;
25 using storage::FileSystemURL;
27 namespace content {
28 namespace {
30 class LoggingRecursiveOperation : public storage::RecursiveOperationDelegate {
31 public:
32 struct LogEntry {
33 enum Type {
34 PROCESS_FILE,
35 PROCESS_DIRECTORY,
36 POST_PROCESS_DIRECTORY
38 Type type;
39 FileSystemURL url;
42 LoggingRecursiveOperation(FileSystemContext* file_system_context,
43 const FileSystemURL& root,
44 const StatusCallback& callback)
45 : storage::RecursiveOperationDelegate(file_system_context),
46 root_(root),
47 callback_(callback),
48 weak_factory_(this) {}
49 ~LoggingRecursiveOperation() override {}
51 const std::vector<LogEntry>& log_entries() const { return log_entries_; }
53 // RecursiveOperationDelegate overrides.
54 void Run() override { NOTREACHED(); }
56 void RunRecursively() override {
57 StartRecursiveOperation(
58 root_, storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT, callback_);
61 void RunRecursivelyWithIgnoringError() {
62 StartRecursiveOperation(
63 root_, storage::FileSystemOperation::ERROR_BEHAVIOR_SKIP, callback_);
66 void ProcessFile(const FileSystemURL& url,
67 const StatusCallback& callback) override {
68 RecordLogEntry(LogEntry::PROCESS_FILE, url);
70 if (error_url_.is_valid() && error_url_ == url) {
71 callback.Run(base::File::FILE_ERROR_FAILED);
72 return;
75 operation_runner()->GetMetadata(
76 url,
77 base::Bind(&LoggingRecursiveOperation::DidGetMetadata,
78 weak_factory_.GetWeakPtr(), callback));
81 void ProcessDirectory(const FileSystemURL& url,
82 const StatusCallback& callback) override {
83 RecordLogEntry(LogEntry::PROCESS_DIRECTORY, url);
84 callback.Run(base::File::FILE_OK);
87 void PostProcessDirectory(const FileSystemURL& url,
88 const StatusCallback& callback) override {
89 RecordLogEntry(LogEntry::POST_PROCESS_DIRECTORY, url);
90 callback.Run(base::File::FILE_OK);
93 void SetEntryToFail(const FileSystemURL& url) { error_url_ = url; }
95 private:
96 void RecordLogEntry(LogEntry::Type type, const FileSystemURL& url) {
97 LogEntry entry;
98 entry.type = type;
99 entry.url = url;
100 log_entries_.push_back(entry);
103 void DidGetMetadata(const StatusCallback& callback,
104 base::File::Error result,
105 const base::File::Info& file_info) {
106 if (result != base::File::FILE_OK) {
107 callback.Run(result);
108 return;
111 callback.Run(file_info.is_directory ?
112 base::File::FILE_ERROR_NOT_A_FILE :
113 base::File::FILE_OK);
116 FileSystemURL root_;
117 StatusCallback callback_;
118 std::vector<LogEntry> log_entries_;
119 FileSystemURL error_url_;
121 base::WeakPtrFactory<LoggingRecursiveOperation> weak_factory_;
122 DISALLOW_COPY_AND_ASSIGN(LoggingRecursiveOperation);
125 void ReportStatus(base::File::Error* out_error,
126 base::File::Error error) {
127 DCHECK(out_error);
128 *out_error = error;
131 // To test the Cancel() during operation, calls Cancel() of |operation|
132 // after |counter| times message posting.
133 void CallCancelLater(storage::RecursiveOperationDelegate* operation,
134 int counter) {
135 if (counter > 0) {
136 base::ThreadTaskRunnerHandle::Get()->PostTask(
137 FROM_HERE,
138 base::Bind(&CallCancelLater, base::Unretained(operation), counter - 1));
139 return;
142 operation->Cancel();
145 } // namespace
147 class RecursiveOperationDelegateTest : public testing::Test {
148 protected:
149 void SetUp() override {
150 EXPECT_TRUE(base_.CreateUniqueTempDir());
151 sandbox_file_system_.SetUp(base_.path().AppendASCII("filesystem"));
154 void TearDown() override { sandbox_file_system_.TearDown(); }
156 scoped_ptr<FileSystemOperationContext> NewContext() {
157 FileSystemOperationContext* context =
158 sandbox_file_system_.NewOperationContext();
159 // Grant enough quota for all test cases.
160 context->set_allowed_bytes_growth(1000000);
161 return make_scoped_ptr(context);
164 storage::FileSystemFileUtil* file_util() {
165 return sandbox_file_system_.file_util();
168 FileSystemURL URLForPath(const std::string& path) const {
169 return sandbox_file_system_.CreateURLFromUTF8(path);
172 FileSystemURL CreateFile(const std::string& path) {
173 FileSystemURL url = URLForPath(path);
174 bool created = false;
175 EXPECT_EQ(base::File::FILE_OK,
176 file_util()->EnsureFileExists(NewContext().get(),
177 url, &created));
178 EXPECT_TRUE(created);
179 return url;
182 FileSystemURL CreateDirectory(const std::string& path) {
183 FileSystemURL url = URLForPath(path);
184 EXPECT_EQ(base::File::FILE_OK,
185 file_util()->CreateDirectory(NewContext().get(), url,
186 false /* exclusive */, true));
187 return url;
190 private:
191 base::MessageLoop message_loop_;
193 // Common temp base for nondestructive uses.
194 base::ScopedTempDir base_;
195 SandboxFileSystemTestHelper sandbox_file_system_;
198 TEST_F(RecursiveOperationDelegateTest, RootIsFile) {
199 FileSystemURL src_file(CreateFile("src"));
201 base::File::Error error = base::File::FILE_ERROR_FAILED;
202 scoped_ptr<FileSystemOperationContext> context = NewContext();
203 scoped_ptr<LoggingRecursiveOperation> operation(
204 new LoggingRecursiveOperation(
205 context->file_system_context(), src_file,
206 base::Bind(&ReportStatus, &error)));
207 operation->RunRecursively();
208 base::RunLoop().RunUntilIdle();
209 ASSERT_EQ(base::File::FILE_OK, error);
211 const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
212 operation->log_entries();
213 ASSERT_EQ(1U, log_entries.size());
214 const LoggingRecursiveOperation::LogEntry& entry = log_entries[0];
215 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, entry.type);
216 EXPECT_EQ(src_file, entry.url);
219 TEST_F(RecursiveOperationDelegateTest, RootIsDirectory) {
220 FileSystemURL src_root(CreateDirectory("src"));
221 FileSystemURL src_dir1(CreateDirectory("src/dir1"));
222 FileSystemURL src_file1(CreateFile("src/file1"));
223 FileSystemURL src_file2(CreateFile("src/dir1/file2"));
224 FileSystemURL src_file3(CreateFile("src/dir1/file3"));
226 base::File::Error error = base::File::FILE_ERROR_FAILED;
227 scoped_ptr<FileSystemOperationContext> context = NewContext();
228 scoped_ptr<LoggingRecursiveOperation> operation(
229 new LoggingRecursiveOperation(
230 context->file_system_context(), src_root,
231 base::Bind(&ReportStatus, &error)));
232 operation->RunRecursively();
233 base::RunLoop().RunUntilIdle();
234 ASSERT_EQ(base::File::FILE_OK, error);
236 const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
237 operation->log_entries();
238 ASSERT_EQ(8U, log_entries.size());
240 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
241 log_entries[0].type);
242 EXPECT_EQ(src_root, log_entries[0].url);
244 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
245 log_entries[1].type);
246 EXPECT_EQ(src_root, log_entries[1].url);
248 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
249 log_entries[2].type);
250 EXPECT_EQ(src_file1, log_entries[2].url);
252 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
253 log_entries[3].type);
254 EXPECT_EQ(src_dir1, log_entries[3].url);
256 // The order of src/dir1/file2 and src/dir1/file3 depends on the file system
257 // implementation (can be swapped).
258 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
259 log_entries[4].type);
260 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
261 log_entries[5].type);
262 EXPECT_TRUE((src_file2 == log_entries[4].url &&
263 src_file3 == log_entries[5].url) ||
264 (src_file3 == log_entries[4].url &&
265 src_file2 == log_entries[5].url));
267 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
268 log_entries[6].type);
269 EXPECT_EQ(src_dir1, log_entries[6].url);
271 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
272 log_entries[7].type);
273 EXPECT_EQ(src_root, log_entries[7].url);
276 TEST_F(RecursiveOperationDelegateTest, Cancel) {
277 FileSystemURL src_root(CreateDirectory("src"));
278 FileSystemURL src_dir1(CreateDirectory("src/dir1"));
279 FileSystemURL src_file1(CreateFile("src/file1"));
280 FileSystemURL src_file2(CreateFile("src/dir1/file2"));
282 base::File::Error error = base::File::FILE_ERROR_FAILED;
283 scoped_ptr<FileSystemOperationContext> context = NewContext();
284 scoped_ptr<LoggingRecursiveOperation> operation(
285 new LoggingRecursiveOperation(
286 context->file_system_context(), src_root,
287 base::Bind(&ReportStatus, &error)));
288 operation->RunRecursively();
290 // Invoke Cancel(), after 5 times message posting.
291 CallCancelLater(operation.get(), 5);
292 base::RunLoop().RunUntilIdle();
293 ASSERT_EQ(base::File::FILE_ERROR_ABORT, error);
296 TEST_F(RecursiveOperationDelegateTest, AbortWithError) {
297 FileSystemURL src_root(CreateDirectory("src"));
298 FileSystemURL src_dir1(CreateDirectory("src/dir1"));
299 FileSystemURL src_file1(CreateFile("src/file1"));
300 FileSystemURL src_file2(CreateFile("src/dir1/file2"));
301 FileSystemURL src_file3(CreateFile("src/dir1/file3"));
303 base::File::Error error = base::File::FILE_ERROR_FAILED;
304 scoped_ptr<FileSystemOperationContext> context = NewContext();
305 scoped_ptr<LoggingRecursiveOperation> operation(
306 new LoggingRecursiveOperation(context->file_system_context(), src_root,
307 base::Bind(&ReportStatus, &error)));
308 operation->SetEntryToFail(src_file1);
309 operation->RunRecursively();
310 base::RunLoop().RunUntilIdle();
312 ASSERT_EQ(base::File::FILE_ERROR_FAILED, error);
314 // Confirm that operation has been aborted in the middle.
315 const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
316 operation->log_entries();
317 ASSERT_EQ(3U, log_entries.size());
319 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
320 log_entries[0].type);
321 EXPECT_EQ(src_root, log_entries[0].url);
323 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
324 log_entries[1].type);
325 EXPECT_EQ(src_root, log_entries[1].url);
327 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
328 log_entries[2].type);
329 EXPECT_EQ(src_file1, log_entries[2].url);
332 TEST_F(RecursiveOperationDelegateTest, ContinueWithError) {
333 FileSystemURL src_root(CreateDirectory("src"));
334 FileSystemURL src_dir1(CreateDirectory("src/dir1"));
335 FileSystemURL src_file1(CreateFile("src/file1"));
336 FileSystemURL src_file2(CreateFile("src/dir1/file2"));
337 FileSystemURL src_file3(CreateFile("src/dir1/file3"));
339 base::File::Error error = base::File::FILE_ERROR_FAILED;
340 scoped_ptr<FileSystemOperationContext> context = NewContext();
341 scoped_ptr<LoggingRecursiveOperation> operation(
342 new LoggingRecursiveOperation(context->file_system_context(), src_root,
343 base::Bind(&ReportStatus, &error)));
344 operation->SetEntryToFail(src_file1);
345 operation->RunRecursivelyWithIgnoringError();
346 base::RunLoop().RunUntilIdle();
348 // Error code should be base::File::FILE_ERROR_FAILED.
349 ASSERT_EQ(base::File::FILE_ERROR_FAILED, error);
351 // Confirm that operation continues after the error.
352 const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
353 operation->log_entries();
354 ASSERT_EQ(8U, log_entries.size());
356 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
357 log_entries[0].type);
358 EXPECT_EQ(src_root, log_entries[0].url);
360 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
361 log_entries[1].type);
362 EXPECT_EQ(src_root, log_entries[1].url);
364 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
365 log_entries[2].type);
366 EXPECT_EQ(src_file1, log_entries[2].url);
368 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
369 log_entries[3].type);
370 EXPECT_EQ(src_dir1, log_entries[3].url);
372 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
373 log_entries[4].type);
374 EXPECT_EQ(src_file3, log_entries[4].url);
376 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
377 log_entries[5].type);
378 EXPECT_EQ(src_file2, log_entries[5].url);
380 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
381 log_entries[6].type);
382 EXPECT_EQ(src_dir1, log_entries[6].url);
384 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
385 log_entries[7].type);
386 EXPECT_EQ(src_root, log_entries[7].url);
389 } // namespace content