Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / file_manager / file_tasks_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 "chrome/browser/chromeos/file_manager/file_tasks.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/command_line.h"
11 #include "base/prefs/pref_registry_simple.h"
12 #include "base/prefs/testing_pref_service.h"
13 #include "base/values.h"
14 #include "chrome/browser/chromeos/drive/file_system_util.h"
15 #include "chrome/browser/chromeos/file_manager/app_id.h"
16 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
17 #include "chrome/browser/chromeos/settings/cros_settings.h"
18 #include "chrome/browser/chromeos/settings/device_settings_service.h"
19 #include "chrome/browser/drive/drive_app_registry.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/test_extension_system.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/test/base/testing_profile.h"
24 #include "content/public/test/test_browser_thread_bundle.h"
25 #include "extensions/browser/extension_prefs.h"
26 #include "extensions/browser/extension_system.h"
27 #include "extensions/common/extension_builder.h"
28 #include "google_apis/drive/drive_api_parser.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "url/gurl.h"
31
32 namespace file_manager {
33 namespace file_tasks {
34 namespace {
35
36 // Registers the default task preferences. Used for testing
37 // ChooseAndSetDefaultTask().
38 void RegisterDefaultTaskPreferences(TestingPrefServiceSimple* pref_service) {
39   DCHECK(pref_service);
40
41   pref_service->registry()->RegisterDictionaryPref(
42       prefs::kDefaultTasksByMimeType);
43   pref_service->registry()->RegisterDictionaryPref(
44       prefs::kDefaultTasksBySuffix);
45 }
46
47 // Updates the default task preferences per the given dictionary values. Used
48 // for testing ChooseAndSetDefaultTask.
49 void UpdateDefaultTaskPreferences(TestingPrefServiceSimple* pref_service,
50                                   const base::DictionaryValue& mime_types,
51                                   const base::DictionaryValue& suffixes) {
52   DCHECK(pref_service);
53
54   pref_service->Set(prefs::kDefaultTasksByMimeType, mime_types);
55   pref_service->Set(prefs::kDefaultTasksBySuffix, suffixes);
56 }
57
58 }  // namespace
59
60 TEST(FileManagerFileTasksTest,
61      FullTaskDescriptor_NonDriveAppWithIconAndDefault) {
62   FullTaskDescriptor full_descriptor(
63       TaskDescriptor("app-id",
64                      TASK_TYPE_FILE_BROWSER_HANDLER,
65                      "action-id"),
66       "task title",
67       GURL("http://example.com/icon.png"),
68       true /* is_default */,
69       false /* is_generic_file_handler */);
70
71   const std::string task_id =
72       TaskDescriptorToId(full_descriptor.task_descriptor());
73   EXPECT_EQ("app-id|file|action-id", task_id);
74   EXPECT_EQ("http://example.com/icon.png", full_descriptor.icon_url().spec());
75   EXPECT_EQ("task title", full_descriptor.task_title());
76   EXPECT_TRUE(full_descriptor.is_default());
77 }
78
79 TEST(FileManagerFileTasksTest,
80      FullTaskDescriptor_DriveAppWithoutIconAndNotDefault) {
81   FullTaskDescriptor full_descriptor(
82       TaskDescriptor("app-id",
83                      TASK_TYPE_DRIVE_APP,
84                      "action-id"),
85       "task title",
86       GURL(),  // No icon URL.
87       false /* is_default */,
88       false /* is_generic_file_handler */);
89
90   const std::string task_id =
91       TaskDescriptorToId(full_descriptor.task_descriptor());
92   EXPECT_EQ("app-id|drive|action-id", task_id);
93   EXPECT_TRUE(full_descriptor.icon_url().is_empty());
94   EXPECT_EQ("task title", full_descriptor.task_title());
95   EXPECT_FALSE(full_descriptor.is_default());
96 }
97
98 TEST(FileManagerFileTasksTest, MakeTaskID) {
99   EXPECT_EQ("app-id|file|action-id",
100             MakeTaskID("app-id", TASK_TYPE_FILE_BROWSER_HANDLER, "action-id"));
101   EXPECT_EQ("app-id|app|action-id",
102             MakeTaskID("app-id", TASK_TYPE_FILE_HANDLER, "action-id"));
103   EXPECT_EQ("app-id|drive|action-id",
104             MakeTaskID("app-id", TASK_TYPE_DRIVE_APP, "action-id"));
105 }
106
107 TEST(FileManagerFileTasksTest, TaskDescriptorToId) {
108   EXPECT_EQ("app-id|file|action-id",
109             TaskDescriptorToId(TaskDescriptor("app-id",
110                                               TASK_TYPE_FILE_BROWSER_HANDLER,
111                                               "action-id")));
112 }
113
114 TEST(FileManagerFileTasksTest, ParseTaskID_FileBrowserHandler) {
115   TaskDescriptor task;
116   EXPECT_TRUE(ParseTaskID("app-id|file|action-id", &task));
117   EXPECT_EQ("app-id", task.app_id);
118   EXPECT_EQ(TASK_TYPE_FILE_BROWSER_HANDLER, task.task_type);
119   EXPECT_EQ("action-id", task.action_id);
120 }
121
122 TEST(FileManagerFileTasksTest, ParseTaskID_FileHandler) {
123   TaskDescriptor task;
124   EXPECT_TRUE(ParseTaskID("app-id|app|action-id", &task));
125   EXPECT_EQ("app-id", task.app_id);
126   EXPECT_EQ(TASK_TYPE_FILE_HANDLER, task.task_type);
127   EXPECT_EQ("action-id", task.action_id);
128 }
129
130 TEST(FileManagerFileTasksTest, ParseTaskID_DriveApp) {
131   TaskDescriptor task;
132   EXPECT_TRUE(ParseTaskID("app-id|drive|action-id", &task));
133   EXPECT_EQ("app-id", task.app_id);
134   EXPECT_EQ(TASK_TYPE_DRIVE_APP, task.task_type);
135   EXPECT_EQ("action-id", task.action_id);
136 }
137
138 TEST(FileManagerFileTasksTest, ParseTaskID_Legacy) {
139   TaskDescriptor task;
140   // A legacy task ID only has two parts. The task type should be
141   // TASK_TYPE_FILE_BROWSER_HANDLER.
142   EXPECT_TRUE(ParseTaskID("app-id|action-id", &task));
143   EXPECT_EQ("app-id", task.app_id);
144   EXPECT_EQ(TASK_TYPE_FILE_BROWSER_HANDLER, task.task_type);
145   EXPECT_EQ("action-id", task.action_id);
146 }
147
148 TEST(FileManagerFileTasksTest, ParseTaskID_LegacyDrive) {
149   TaskDescriptor task;
150   // A legacy task ID only has two parts. For Drive app, the app ID is
151   // prefixed with "drive-app:".
152   EXPECT_TRUE(ParseTaskID("drive-app:app-id|action-id", &task));
153   EXPECT_EQ("app-id", task.app_id);
154   EXPECT_EQ(TASK_TYPE_DRIVE_APP, task.task_type);
155   EXPECT_EQ("action-id", task.action_id);
156 }
157
158 TEST(FileManagerFileTasksTest, ParseTaskID_Invalid) {
159   TaskDescriptor task;
160   EXPECT_FALSE(ParseTaskID("invalid", &task));
161 }
162
163 TEST(FileManagerFileTasksTest, ParseTaskID_UnknownTaskType) {
164   TaskDescriptor task;
165   EXPECT_FALSE(ParseTaskID("app-id|unknown|action-id", &task));
166 }
167
168 TEST(FileManagerFileTasksTest, FindDriveAppTasks) {
169   TestingProfile profile;
170   // For DriveAppRegistry, which checks CurrentlyOn(BrowserThread::UI).
171   content::TestBrowserThreadBundle thread_bundle;
172
173   // Foo.app can handle "text/plain" and "text/html"
174   scoped_ptr<google_apis::AppResource> foo_app(new google_apis::AppResource);
175   foo_app->set_product_id("foo_app_id");
176   foo_app->set_application_id("foo_app_id");
177   foo_app->set_name("Foo");
178   foo_app->set_object_type("foo_object_type");
179   ScopedVector<std::string> foo_mime_types;
180   foo_mime_types.push_back(new std::string("text/plain"));
181   foo_mime_types.push_back(new std::string("text/html"));
182   foo_app->set_primary_mimetypes(foo_mime_types.Pass());
183
184   // Bar.app can only handle "text/plain".
185   scoped_ptr<google_apis::AppResource> bar_app(new google_apis::AppResource);
186   bar_app->set_product_id("bar_app_id");
187   bar_app->set_application_id("bar_app_id");
188   bar_app->set_name("Bar");
189   bar_app->set_object_type("bar_object_type");
190   ScopedVector<std::string> bar_mime_types;
191   bar_mime_types.push_back(new std::string("text/plain"));
192   bar_app->set_primary_mimetypes(bar_mime_types.Pass());
193
194   // Prepare DriveAppRegistry from Foo.app and Bar.app.
195   ScopedVector<google_apis::AppResource> app_resources;
196   app_resources.push_back(foo_app.release());
197   app_resources.push_back(bar_app.release());
198   google_apis::AppList app_list;
199   app_list.set_items(app_resources.Pass());
200   drive::DriveAppRegistry drive_app_registry(NULL);
201   drive_app_registry.UpdateFromAppList(app_list);
202
203   // Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
204   PathAndMimeTypeSet path_mime_set;
205   path_mime_set.insert(
206       std::make_pair(
207           drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
208           "text/plain"));
209   std::vector<FullTaskDescriptor> tasks;
210   FindDriveAppTasks(drive_app_registry,
211                     path_mime_set,
212                     &tasks);
213   ASSERT_EQ(2U, tasks.size());
214   // Sort the app IDs, as the order is not guaranteed.
215   std::vector<std::string> app_ids;
216   app_ids.push_back(tasks[0].task_descriptor().app_id);
217   app_ids.push_back(tasks[1].task_descriptor().app_id);
218   std::sort(app_ids.begin(), app_ids.end());
219   // Confirm that both Foo.app and Bar.app are found.
220   EXPECT_EQ("bar_app_id", app_ids[0]);
221   EXPECT_EQ("foo_app_id", app_ids[1]);
222
223   // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
224   // found.
225   path_mime_set.clear();
226   path_mime_set.insert(
227       std::make_pair(
228           drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
229           "text/plain"));
230   path_mime_set.insert(
231       std::make_pair(
232           drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.html"),
233           "text/html"));
234   tasks.clear();
235   FindDriveAppTasks(drive_app_registry,
236                     path_mime_set,
237                     &tasks);
238   ASSERT_EQ(1U, tasks.size());
239   // Confirm that only Foo.app is found.
240   EXPECT_EQ("foo_app_id", tasks[0].task_descriptor().app_id);
241
242   // Add a "text/plain" file not on Drive. No tasks should be found.
243   path_mime_set.insert(
244       std::make_pair(base::FilePath::FromUTF8Unsafe("not_on_drive.txt"),
245                      "text/plain"));
246   tasks.clear();
247   FindDriveAppTasks(drive_app_registry,
248                     path_mime_set,
249                     &tasks);
250   // Confirm no tasks are found.
251   ASSERT_TRUE(tasks.empty());
252 }
253
254 // Test that the right task is chosen from multiple choices per mime types
255 // and file extensions.
256 TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_MultipleTasks) {
257   TestingPrefServiceSimple pref_service;
258   RegisterDefaultTaskPreferences(&pref_service);
259
260   // Text.app and Nice.app were found for "foo.txt".
261   TaskDescriptor text_app_task("text-app-id",
262                                TASK_TYPE_FILE_HANDLER,
263                                "action-id");
264   TaskDescriptor nice_app_task("nice-app-id",
265                                TASK_TYPE_FILE_HANDLER,
266                                "action-id");
267   std::vector<FullTaskDescriptor> tasks;
268   tasks.push_back(FullTaskDescriptor(
269       text_app_task,
270       "Text.app",
271       GURL("http://example.com/text_app.png"),
272       false /* is_default */,
273       false /* is_generic_file_handler */));
274   tasks.push_back(FullTaskDescriptor(
275       nice_app_task,
276       "Nice.app",
277       GURL("http://example.com/nice_app.png"),
278       false /* is_default */,
279       false /* is_generic_file_handler */));
280   PathAndMimeTypeSet path_mime_set;
281   path_mime_set.insert(std::make_pair(
282       base::FilePath::FromUTF8Unsafe("foo.txt"),
283       "text/plain"));
284
285   // None of them should be chosen as default, as nothing is set in the
286   // preferences.
287   ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
288   EXPECT_FALSE(tasks[0].is_default());
289   EXPECT_FALSE(tasks[1].is_default());
290
291   // Set Text.app as default for "text/plain" in the preferences.
292   base::DictionaryValue empty;
293   base::DictionaryValue mime_types;
294   mime_types.SetStringWithoutPathExpansion(
295       "text/plain",
296       TaskDescriptorToId(text_app_task));
297   UpdateDefaultTaskPreferences(&pref_service, mime_types, empty);
298
299   // Text.app should be chosen as default.
300   ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
301   EXPECT_TRUE(tasks[0].is_default());
302   EXPECT_FALSE(tasks[1].is_default());
303
304   // Change it back to non-default for testing further.
305   tasks[0].set_is_default(false);
306
307   // Clear the preferences and make sure none of them are default.
308   UpdateDefaultTaskPreferences(&pref_service, empty, empty);
309   ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
310   EXPECT_FALSE(tasks[0].is_default());
311   EXPECT_FALSE(tasks[1].is_default());
312
313   // Set Nice.app as default for ".txt" in the preferences.
314   base::DictionaryValue suffixes;
315   suffixes.SetStringWithoutPathExpansion(
316       ".txt",
317       TaskDescriptorToId(nice_app_task));
318   UpdateDefaultTaskPreferences(&pref_service, empty, suffixes);
319
320   // Now Nice.app should be chosen as default.
321   ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
322   EXPECT_FALSE(tasks[0].is_default());
323   EXPECT_TRUE(tasks[1].is_default());
324 }
325
326 // Test that Files.app's internal file browser handler is chosen as default
327 // even if nothing is set in the preferences.
328 TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_FallbackFileBrowser) {
329   TestingPrefServiceSimple pref_service;
330   RegisterDefaultTaskPreferences(&pref_service);
331
332   // Files.app's internal file browser handler was found for "foo.txt".
333   TaskDescriptor files_app_task(kFileManagerAppId,
334                                 TASK_TYPE_FILE_BROWSER_HANDLER,
335                                 "view-in-browser");
336   std::vector<FullTaskDescriptor> tasks;
337   tasks.push_back(FullTaskDescriptor(
338       files_app_task,
339       "View in browser",
340       GURL("http://example.com/some_icon.png"),
341       false /* is_default */,
342       false /* is_generic_file_handler */));
343   PathAndMimeTypeSet path_mime_set;
344   path_mime_set.insert(std::make_pair(
345       base::FilePath::FromUTF8Unsafe("foo.txt"),
346       "text/plain"));
347
348   // The internal file browser handler should be chosen as default, as it's a
349   // fallback file browser handler.
350   ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
351   EXPECT_TRUE(tasks[0].is_default());
352 }
353
354 // Test IsGenericFileHandler which returns whether a file handle info is a
355 // generic file handler or not.
356 TEST(FileManagerFileTasksTest, IsGenericFileHandler) {
357   using FileHandlerInfo = extensions::FileHandlerInfo;
358
359   // extensions: ["*"]
360   FileHandlerInfo file_handler_info_1;
361   file_handler_info_1.extensions.insert("*");
362   EXPECT_TRUE(IsGenericFileHandler(file_handler_info_1));
363
364   // extensions: ["*", "jpg"]
365   FileHandlerInfo file_handler_info_2;
366   file_handler_info_2.extensions.insert("*");
367   file_handler_info_2.extensions.insert("jpg");
368   EXPECT_TRUE(IsGenericFileHandler(file_handler_info_2));
369
370   // extensions: ["jpg"]
371   FileHandlerInfo file_handler_info_3;
372   file_handler_info_3.extensions.insert("jpg");
373   EXPECT_FALSE(IsGenericFileHandler(file_handler_info_3));
374
375   // types: ["*"]
376   FileHandlerInfo file_handler_info_4;
377   file_handler_info_4.types.insert("*");
378   EXPECT_TRUE(IsGenericFileHandler(file_handler_info_4));
379
380   // types: ["*/*"]
381   FileHandlerInfo file_handler_info_5;
382   file_handler_info_5.types.insert("*/*");
383   EXPECT_TRUE(IsGenericFileHandler(file_handler_info_5));
384
385   // types: ["image/*"]
386   FileHandlerInfo file_handler_info_6;
387   file_handler_info_6.types.insert("image/*");
388   // Partial wild card is not generic.
389   EXPECT_FALSE(IsGenericFileHandler(file_handler_info_6));
390
391   // types: ["*", "image/*"]
392   FileHandlerInfo file_handler_info_7;
393   file_handler_info_7.types.insert("*");
394   file_handler_info_7.types.insert("image/*");
395   EXPECT_TRUE(IsGenericFileHandler(file_handler_info_7));
396
397   // extensions: ["*"], types: ["image/*"]
398   FileHandlerInfo file_handler_info_8;
399   file_handler_info_8.extensions.insert("*");
400   file_handler_info_8.types.insert("image/*");
401   EXPECT_TRUE(IsGenericFileHandler(file_handler_info_8));
402 }
403
404 // Test using the test extension system, which needs lots of setup.
405 class FileManagerFileTasksComplexTest : public testing::Test {
406  protected:
407   FileManagerFileTasksComplexTest()
408       : command_line_(CommandLine::NO_PROGRAM),
409         extension_service_(NULL) {
410     extensions::TestExtensionSystem* test_extension_system =
411         static_cast<extensions::TestExtensionSystem*>(
412             extensions::ExtensionSystem::Get(&test_profile_));
413     extension_service_ = test_extension_system->CreateExtensionService(
414         &command_line_,
415         base::FilePath()  /* install_directory */,
416         false  /* autoupdate_enabled*/);
417   }
418
419   content::TestBrowserThreadBundle thread_bundle_;
420   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
421   chromeos::ScopedTestCrosSettings test_cros_settings_;
422   chromeos::ScopedTestUserManager test_user_manager_;
423   TestingProfile test_profile_;
424   CommandLine command_line_;
425   ExtensionService* extension_service_;  // Owned by test_profile_;
426 };
427
428 // The basic logic is similar to a test case for FindDriveAppTasks above.
429 TEST_F(FileManagerFileTasksComplexTest, FindFileHandlerTasks) {
430   // Random IDs generated by
431   // % ruby -le 'print (0...32).to_a.map{(?a + rand(16)).chr}.join'
432   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
433   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
434   const char kEphemeralId[] = "opoomfdlbjcbjinalcjdjfoiikdeaoel";
435
436   // Foo.app can handle "text/plain" and "text/html".
437   extensions::ExtensionBuilder foo_app;
438   foo_app.SetManifest(extensions::DictionaryBuilder()
439                       .Set("name", "Foo")
440                       .Set("version", "1.0.0")
441                       .Set("manifest_version", 2)
442                       .Set("app",
443                            extensions::DictionaryBuilder()
444                            .Set("background",
445                                 extensions::DictionaryBuilder()
446                                 .Set("scripts",
447                                      extensions::ListBuilder()
448                                      .Append("background.js"))))
449                       .Set("file_handlers",
450                            extensions::DictionaryBuilder()
451                            .Set("text",
452                                 extensions::DictionaryBuilder()
453                                 .Set("title", "Text")
454                                 .Set("types",
455                                      extensions::ListBuilder()
456                                      .Append("text/plain")
457                                      .Append("text/html")))));
458   foo_app.SetID(kFooId);
459   extension_service_->AddExtension(foo_app.Build().get());
460
461   // Bar.app can only handle "text/plain".
462   extensions::ExtensionBuilder bar_app;
463   bar_app.SetManifest(extensions::DictionaryBuilder()
464                       .Set("name", "Bar")
465                       .Set("version", "1.0.0")
466                       .Set("manifest_version", 2)
467                       .Set("app",
468                            extensions::DictionaryBuilder()
469                            .Set("background",
470                                 extensions::DictionaryBuilder()
471                                 .Set("scripts",
472                                      extensions::ListBuilder()
473                                      .Append("background.js"))))
474                       .Set("file_handlers",
475                            extensions::DictionaryBuilder()
476                            .Set("text",
477                                 extensions::DictionaryBuilder()
478                                 .Set("title", "Text")
479                                 .Set("types",
480                                      extensions::ListBuilder()
481                                      .Append("text/plain")))));
482   bar_app.SetID(kBarId);
483   extension_service_->AddExtension(bar_app.Build().get());
484
485   // Ephemeral.app is an ephemeral app that can handle "text/plain".
486   // It should not ever be found as ephemeral apps cannot be file handlers.
487   extensions::ExtensionBuilder ephemeral_app;
488   ephemeral_app.SetManifest(
489       extensions::DictionaryBuilder()
490           .Set("name", "Ephemeral")
491           .Set("version", "1.0.0")
492           .Set("manifest_version", 2)
493           .Set("app",
494                extensions::DictionaryBuilder().Set(
495                    "background",
496                    extensions::DictionaryBuilder().Set(
497                        "scripts",
498                        extensions::ListBuilder().Append("background.js"))))
499           .Set("file_handlers",
500                extensions::DictionaryBuilder().Set(
501                    "text",
502                    extensions::DictionaryBuilder().Set("title", "Text").Set(
503                        "types",
504                        extensions::ListBuilder().Append("text/plain")))));
505   ephemeral_app.SetID(kEphemeralId);
506   scoped_refptr<extensions::Extension> built_ephemeral_app(
507       ephemeral_app.Build());
508   extension_service_->AddExtension(built_ephemeral_app.get());
509   extensions::ExtensionPrefs* extension_prefs =
510       extensions::ExtensionPrefs::Get(&test_profile_);
511   extension_prefs->OnExtensionInstalled(built_ephemeral_app.get(),
512                                         extensions::Extension::ENABLED,
513                                         syncer::StringOrdinal(),
514                                         extensions::kInstallFlagIsEphemeral,
515                                         std::string());
516
517   // Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
518   PathAndMimeTypeSet path_mime_set;
519   path_mime_set.insert(
520       std::make_pair(
521           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
522               "foo.txt"),
523           "text/plain"));
524
525   std::vector<FullTaskDescriptor> tasks;
526   FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
527   ASSERT_EQ(2U, tasks.size());
528   // Sort the app IDs, as the order is not guaranteed.
529   std::vector<std::string> app_ids;
530   app_ids.push_back(tasks[0].task_descriptor().app_id);
531   app_ids.push_back(tasks[1].task_descriptor().app_id);
532   std::sort(app_ids.begin(), app_ids.end());
533   // Confirm that both Foo.app and Bar.app are found.
534   EXPECT_EQ(kFooId, app_ids[0]);
535   EXPECT_EQ(kBarId, app_ids[1]);
536
537   // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
538   // found.
539   path_mime_set.clear();
540   path_mime_set.insert(
541       std::make_pair(
542           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
543               "foo.txt"),
544           "text/plain"));
545   path_mime_set.insert(
546       std::make_pair(
547           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
548               "foo.html"),
549           "text/html"));
550   tasks.clear();
551   FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
552   ASSERT_EQ(1U, tasks.size());
553   // Confirm that only Foo.app is found.
554   EXPECT_EQ(kFooId, tasks[0].task_descriptor().app_id);
555
556   // Add an "image/png" file. No tasks should be found.
557   path_mime_set.insert(
558       std::make_pair(base::FilePath::FromUTF8Unsafe("foo.png"),
559                      "image/png"));
560   tasks.clear();
561   FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
562   // Confirm no tasks are found.
563   ASSERT_TRUE(tasks.empty());
564 }
565
566 // The basic logic is similar to a test case for FindDriveAppTasks above.
567 TEST_F(FileManagerFileTasksComplexTest, FindFileBrowserHandlerTasks) {
568   // Copied from FindFileHandlerTasks test above.
569   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
570   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
571   const char kEphemeralId[] = "opoomfdlbjcbjinalcjdjfoiikdeaoel";
572
573   // Foo.app can handle ".txt" and ".html".
574   // This one is an extension, and has "file_browser_handlers"
575   extensions::ExtensionBuilder foo_app;
576   foo_app.SetManifest(extensions::DictionaryBuilder()
577                       .Set("name", "Foo")
578                       .Set("version", "1.0.0")
579                       .Set("manifest_version", 2)
580                       .Set("file_browser_handlers",
581                            extensions::ListBuilder()
582                            .Append(extensions::DictionaryBuilder()
583                                    .Set("id", "open")
584                                    .Set("default_title", "open")
585                                    .Set("file_filters",
586                                         extensions::ListBuilder()
587                                         .Append("filesystem:*.txt")
588                                         .Append("filesystem:*.html")))));
589   foo_app.SetID(kFooId);
590   extension_service_->AddExtension(foo_app.Build().get());
591
592   // Bar.app can only handle ".txt".
593   extensions::ExtensionBuilder bar_app;
594   bar_app.SetManifest(extensions::DictionaryBuilder()
595                       .Set("name", "Bar")
596                       .Set("version", "1.0.0")
597                       .Set("manifest_version", 2)
598                       .Set("file_browser_handlers",
599                            extensions::ListBuilder()
600                            .Append(extensions::DictionaryBuilder()
601                                    .Set("id", "open")
602                                    .Set("default_title", "open")
603                                    .Set("file_filters",
604                                         extensions::ListBuilder()
605                                         .Append("filesystem:*.txt")))));
606   bar_app.SetID(kBarId);
607   extension_service_->AddExtension(bar_app.Build().get());
608
609   // Ephemeral.app is an ephemeral app that can handle ".txt".
610   // It should not ever be found as ephemeral apps cannot be file browser
611   // handlers.
612   extensions::ExtensionBuilder ephemeral_app;
613   ephemeral_app.SetManifest(
614       extensions::DictionaryBuilder()
615           .Set("name", "Ephemeral")
616           .Set("version", "1.0.0")
617           .Set("manifest_version", 2)
618           .Set("file_browser_handlers",
619                extensions::ListBuilder().Append(
620                    extensions::DictionaryBuilder()
621                        .Set("id", "open")
622                        .Set("default_title", "open")
623                        .Set("file_filters",
624                             extensions::ListBuilder().Append(
625                                 "filesystem:*.txt")))));
626   ephemeral_app.SetID(kEphemeralId);
627   scoped_refptr<extensions::Extension> built_ephemeral_app(
628       ephemeral_app.Build());
629   extension_service_->AddExtension(built_ephemeral_app.get());
630   extensions::ExtensionPrefs* extension_prefs =
631       extensions::ExtensionPrefs::Get(&test_profile_);
632   extension_prefs->OnExtensionInstalled(built_ephemeral_app.get(),
633                                         extensions::Extension::ENABLED,
634                                         syncer::StringOrdinal(),
635                                         extensions::kInstallFlagIsEphemeral,
636                                         std::string());
637
638   // Find apps for a ".txt" file. Foo.app and Bar.app should be found.
639   std::vector<GURL> file_urls;
640   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
641
642   std::vector<FullTaskDescriptor> tasks;
643   FindFileBrowserHandlerTasks(&test_profile_, file_urls, &tasks);
644   ASSERT_EQ(2U, tasks.size());
645   // Sort the app IDs, as the order is not guaranteed.
646   std::vector<std::string> app_ids;
647   app_ids.push_back(tasks[0].task_descriptor().app_id);
648   app_ids.push_back(tasks[1].task_descriptor().app_id);
649   std::sort(app_ids.begin(), app_ids.end());
650   // Confirm that both Foo.app and Bar.app are found.
651   EXPECT_EQ(kFooId, app_ids[0]);
652   EXPECT_EQ(kBarId, app_ids[1]);
653
654   // Find apps for ".txt" and ".html" files. Only Foo.app should be found.
655   file_urls.clear();
656   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
657   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.html"));
658   tasks.clear();
659   FindFileBrowserHandlerTasks(&test_profile_, file_urls, &tasks);
660   ASSERT_EQ(1U, tasks.size());
661   // Confirm that only Foo.app is found.
662   EXPECT_EQ(kFooId, tasks[0].task_descriptor().app_id);
663
664   // Add an ".png" file. No tasks should be found.
665   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.png"));
666   tasks.clear();
667   FindFileBrowserHandlerTasks(&test_profile_, file_urls, &tasks);
668   // Confirm no tasks are found.
669   ASSERT_TRUE(tasks.empty());
670 }
671
672 // Test that all kinds of apps (file handler, file browser handler, and Drive
673 // app) are returned.
674 TEST_F(FileManagerFileTasksComplexTest, FindAllTypesOfTasks) {
675   // kFooId and kBarId copied from FindFileHandlerTasks test above.
676   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
677   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
678   const char kBazId[] = "plifkpkakemokpflgbnnigcoldgcbdmc";
679
680   // Foo.app can handle "text/plain".
681   // This is a packaged app (file handler).
682   extensions::ExtensionBuilder foo_app;
683   foo_app.SetManifest(extensions::DictionaryBuilder()
684                       .Set("name", "Foo")
685                       .Set("version", "1.0.0")
686                       .Set("manifest_version", 2)
687                       .Set("app",
688                            extensions::DictionaryBuilder()
689                            .Set("background",
690                                 extensions::DictionaryBuilder()
691                                 .Set("scripts",
692                                      extensions::ListBuilder()
693                                      .Append("background.js"))))
694                       .Set("file_handlers",
695                            extensions::DictionaryBuilder()
696                            .Set("text",
697                                 extensions::DictionaryBuilder()
698                                 .Set("title", "Text")
699                                 .Set("types",
700                                      extensions::ListBuilder()
701                                      .Append("text/plain")))));
702   foo_app.SetID(kFooId);
703   extension_service_->AddExtension(foo_app.Build().get());
704
705   // Bar.app can only handle ".txt".
706   // This is an extension (file browser handler).
707   extensions::ExtensionBuilder bar_app;
708   bar_app.SetManifest(extensions::DictionaryBuilder()
709                       .Set("name", "Bar")
710                       .Set("version", "1.0.0")
711                       .Set("manifest_version", 2)
712                       .Set("file_browser_handlers",
713                            extensions::ListBuilder()
714                            .Append(extensions::DictionaryBuilder()
715                                    .Set("id", "open")
716                                    .Set("default_title", "open")
717                                    .Set("file_filters",
718                                         extensions::ListBuilder()
719                                         .Append("filesystem:*.txt")))));
720   bar_app.SetID(kBarId);
721   extension_service_->AddExtension(bar_app.Build().get());
722
723   // Baz.app can handle "text/plain".
724   // This is a Drive app.
725   scoped_ptr<google_apis::AppResource> baz_app(new google_apis::AppResource);
726   baz_app->set_product_id("baz_app_id");
727   baz_app->set_application_id(kBazId);
728   baz_app->set_name("Baz");
729   baz_app->set_object_type("baz_object_type");
730   ScopedVector<std::string> baz_mime_types;
731   baz_mime_types.push_back(new std::string("text/plain"));
732   baz_app->set_primary_mimetypes(baz_mime_types.Pass());
733   // Set up DriveAppRegistry.
734   ScopedVector<google_apis::AppResource> app_resources;
735   app_resources.push_back(baz_app.release());
736   google_apis::AppList app_list;
737   app_list.set_items(app_resources.Pass());
738   drive::DriveAppRegistry drive_app_registry(NULL);
739   drive_app_registry.UpdateFromAppList(app_list);
740
741   // Find apps for "foo.txt". All apps should be found.
742   PathAndMimeTypeSet path_mime_set;
743   std::vector<GURL> file_urls;
744   path_mime_set.insert(
745       std::make_pair(
746           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
747               "foo.txt"),
748           "text/plain"));
749   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
750
751   std::vector<FullTaskDescriptor> tasks;
752   FindAllTypesOfTasks(&test_profile_,
753                       &drive_app_registry,
754                       path_mime_set,
755                       file_urls,
756                       &tasks);
757   ASSERT_EQ(3U, tasks.size());
758
759   // Sort the app IDs, as the order is not guaranteed.
760   std::vector<std::string> app_ids;
761   app_ids.push_back(tasks[0].task_descriptor().app_id);
762   app_ids.push_back(tasks[1].task_descriptor().app_id);
763   app_ids.push_back(tasks[2].task_descriptor().app_id);
764   std::sort(app_ids.begin(), app_ids.end());
765   // Confirm that all apps are found.
766   EXPECT_EQ(kFooId, app_ids[0]);
767   EXPECT_EQ(kBarId, app_ids[1]);
768   EXPECT_EQ(kBazId, app_ids[2]);
769 }
770
771 TEST_F(FileManagerFileTasksComplexTest, FindAllTypesOfTasks_GoogleDocument) {
772   // kFooId and kBarId copied from FindFileHandlerTasks test above.
773   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
774   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
775
776   // Foo.app can handle ".gdoc" files.
777   scoped_ptr<google_apis::AppResource> foo_app(new google_apis::AppResource);
778   foo_app->set_product_id("foo_app");
779   foo_app->set_application_id(kFooId);
780   foo_app->set_name("Foo");
781   foo_app->set_object_type("foo_object_type");
782   ScopedVector<std::string> foo_extensions;
783   foo_extensions.push_back(new std::string("gdoc"));  // Not ".gdoc"
784   foo_app->set_primary_file_extensions(foo_extensions.Pass());
785
786   // Prepare DriveAppRegistry from Foo.app.
787   ScopedVector<google_apis::AppResource> app_resources;
788   app_resources.push_back(foo_app.release());
789   google_apis::AppList app_list;
790   app_list.set_items(app_resources.Pass());
791   drive::DriveAppRegistry drive_app_registry(NULL);
792   drive_app_registry.UpdateFromAppList(app_list);
793
794   // Bar.app can handle ".gdoc" files.
795   // This is an extension (file browser handler).
796   extensions::ExtensionBuilder bar_app;
797   bar_app.SetManifest(extensions::DictionaryBuilder()
798                       .Set("name", "Bar")
799                       .Set("version", "1.0.0")
800                       .Set("manifest_version", 2)
801                       .Set("file_browser_handlers",
802                            extensions::ListBuilder()
803                            .Append(extensions::DictionaryBuilder()
804                                    .Set("id", "open")
805                                    .Set("default_title", "open")
806                                    .Set("file_filters",
807                                         extensions::ListBuilder()
808                                         .Append("filesystem:*.gdoc")))));
809   bar_app.SetID(kBarId);
810   extension_service_->AddExtension(bar_app.Build().get());
811
812   // Files.app can handle ".gdoc" files.
813   // The ID "kFileManagerAppId" used here is precisely the one that identifies
814   // the Chrome OS Files.app application.
815   extensions::ExtensionBuilder files_app;
816   files_app.SetManifest(extensions::DictionaryBuilder()
817                        .Set("name", "Files")
818                        .Set("version", "1.0.0")
819                        .Set("manifest_version", 2)
820                        .Set("file_browser_handlers",
821                             extensions::ListBuilder()
822                             .Append(extensions::DictionaryBuilder()
823                                     .Set("id", "open")
824                                     .Set("default_title", "open")
825                                     .Set("file_filters",
826                                          extensions::ListBuilder()
827                                          .Append("filesystem:*.gdoc")))));
828   files_app.SetID(kFileManagerAppId);
829   extension_service_->AddExtension(files_app.Build().get());
830
831   // Find apps for a ".gdoc file". Only the built-in handler of Files.apps
832   // should be found.
833   PathAndMimeTypeSet path_mime_set;
834   std::vector<GURL> file_urls;
835   path_mime_set.insert(
836       std::make_pair(
837           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
838               "foo.gdoc"),
839           "application/vnd.google-apps.document"));
840   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.gdoc"));
841
842   std::vector<FullTaskDescriptor> tasks;
843   FindAllTypesOfTasks(&test_profile_,
844                       &drive_app_registry,
845                       path_mime_set,
846                       file_urls,
847                       &tasks);
848   ASSERT_EQ(1U, tasks.size());
849   EXPECT_EQ(kFileManagerAppId, tasks[0].task_descriptor().app_id);
850 }
851
852 TEST_F(FileManagerFileTasksComplexTest, FindFileHandlerTask_Generic) {
853   // Since we want to keep the order of the result as foo,bar,baz,qux,
854   // keep the ids in alphabetical order.
855   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
856   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
857   const char kBazId[] = "plifkpkakemokpflgbnnigcoldgcbdmc";
858   const char kQuxId[] = "pmifkpkakgkadkkhcmhgnigmmifgpaph";
859
860   // Foo app provides file handler for text/plain and all file types.
861   extensions::ExtensionBuilder foo_app;
862   foo_app.SetManifest(extensions::DictionaryBuilder()
863                       .Set("name", "Foo")
864                       .Set("version", "1.0.0")
865                       .Set("manifest_version", 2)
866                       .Set("app", extensions::DictionaryBuilder()
867                            .Set("background", extensions::DictionaryBuilder()
868                                 .Set("scripts", extensions::ListBuilder()
869                                     .Append("background.js"))))
870                       .Set("file_handlers",
871                            extensions::DictionaryBuilder()
872                            .Set("any",
873                                 extensions::DictionaryBuilder()
874                                 .Set("types", extensions::ListBuilder()
875                                      .Append("*/*")))
876                            .Set("text",
877                                 extensions::DictionaryBuilder()
878                                 .Set("types", extensions::ListBuilder()
879                                      .Append("text/plain")))));
880   foo_app.SetID(kFooId);
881   extension_service_->AddExtension(foo_app.Build().get());
882
883   // Bar app provides file handler for .txt and not provide generic file
884   // handler.
885   extensions::ExtensionBuilder bar_app;
886   bar_app.SetManifest(extensions::DictionaryBuilder()
887                       .Set("name", "Bar")
888                       .Set("version", "1.0.0")
889                       .Set("manifest_version", 2)
890                       .Set("app", extensions::DictionaryBuilder()
891                            .Set("background", extensions::DictionaryBuilder()
892                                 .Set("scripts", extensions::ListBuilder()
893                                     .Append("background.js"))))
894                       .Set("file_handlers",
895                            extensions::DictionaryBuilder()
896                            .Set("text",
897                                 extensions::DictionaryBuilder()
898                                 .Set("extensions", extensions::ListBuilder()
899                                      .Append("txt")))));
900   bar_app.SetID(kBarId);
901   extension_service_->AddExtension(bar_app.Build().get());
902
903   // Baz app provides file handler for all extensions and images.
904   extensions::ExtensionBuilder baz_app;
905   baz_app.SetManifest(extensions::DictionaryBuilder()
906                       .Set("name", "Baz")
907                       .Set("version", "1.0.0")
908                       .Set("manifest_version", 2)
909                       .Set("app", extensions::DictionaryBuilder()
910                            .Set("background", extensions::DictionaryBuilder()
911                                 .Set("scripts", extensions::ListBuilder()
912                                     .Append("background.js"))))
913                       .Set("file_handlers",
914                            extensions::DictionaryBuilder()
915                            .Set("any",
916                                 extensions::DictionaryBuilder()
917                                 .Set("extensions", extensions::ListBuilder()
918                                      .Append("*")
919                                      .Append("bar")))
920                            .Set("image",
921                                 extensions::DictionaryBuilder()
922                                 .Set("types", extensions::ListBuilder()
923                                      .Append("image/*")))));
924   baz_app.SetID(kBazId);
925   extension_service_->AddExtension(baz_app.Build().get());
926
927   // Qux app provides file handler for all types.
928   extensions::ExtensionBuilder qux_app;
929   qux_app.SetManifest(extensions::DictionaryBuilder()
930                       .Set("name", "Qux")
931                       .Set("version", "1.0.0")
932                       .Set("manifest_version", 2)
933                       .Set("app", extensions::DictionaryBuilder()
934                            .Set("background", extensions::DictionaryBuilder()
935                                 .Set("scripts", extensions::ListBuilder()
936                                     .Append("background.js"))))
937                       .Set("file_handlers",
938                            extensions::DictionaryBuilder()
939                            .Set("any",
940                                 extensions::DictionaryBuilder()
941                                 .Set("types", extensions::ListBuilder()
942                                      .Append("*")))));
943   qux_app.SetID(kQuxId);
944   extension_service_->AddExtension(qux_app.Build().get());
945
946   // Test case with .txt file
947   PathAndMimeTypeSet txt_path_mime_set;
948   txt_path_mime_set.insert(
949       std::make_pair(
950           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
951               "foo.txt"),
952           "text/plain"));
953   std::vector<FullTaskDescriptor> txt_result;
954   FindFileHandlerTasks(&test_profile_, txt_path_mime_set, &txt_result);
955   EXPECT_EQ(4U, txt_result.size());
956   // Foo app provides a handler for text/plain.
957   EXPECT_EQ("Foo", txt_result[0].task_title());
958   EXPECT_FALSE(txt_result[0].is_generic_file_handler());
959   // Bar app provides a handler for .txt.
960   EXPECT_EQ("Bar", txt_result[1].task_title());
961   EXPECT_FALSE(txt_result[1].is_generic_file_handler());
962   // Baz app provides a handler for all extensions.
963   EXPECT_EQ("Baz", txt_result[2].task_title());
964   EXPECT_TRUE(txt_result[2].is_generic_file_handler());
965   // Qux app provides a handler for all types.
966   EXPECT_EQ("Qux", txt_result[3].task_title());
967   EXPECT_TRUE(txt_result[3].is_generic_file_handler());
968
969   // Test case with .jpg file
970   PathAndMimeTypeSet jpg_path_mime_set;
971   jpg_path_mime_set.insert(
972       std::make_pair(
973           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
974               "foo.jpg"),
975           "image/jpeg"));
976   std::vector<FullTaskDescriptor> jpg_result;
977   FindFileHandlerTasks(&test_profile_, jpg_path_mime_set, &jpg_result);
978   EXPECT_EQ(3U, jpg_result.size());
979   // Foo app provides a handler for all types.
980   EXPECT_EQ("Foo", jpg_result[0].task_title());
981   EXPECT_TRUE(jpg_result[0].is_generic_file_handler());
982   // Baz app provides a handler for image/*. A partial wildcarded handler is
983   // treated as non-generic handler.
984   EXPECT_EQ("Baz", jpg_result[1].task_title());
985   EXPECT_FALSE(jpg_result[1].is_generic_file_handler());
986   // Qux app provides a handler for all types.
987   EXPECT_EQ("Qux", jpg_result[2].task_title());
988   EXPECT_TRUE(jpg_result[2].is_generic_file_handler());
989 }
990
991 }  // namespace file_tasks
992 }  // namespace file_manager.