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 "chrome/browser/chromeos/file_manager/file_tasks.h"
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"
32 namespace file_manager {
33 namespace file_tasks {
36 // Registers the default task preferences. Used for testing
37 // ChooseAndSetDefaultTask().
38 void RegisterDefaultTaskPreferences(TestingPrefServiceSimple* pref_service) {
41 pref_service->registry()->RegisterDictionaryPref(
42 prefs::kDefaultTasksByMimeType);
43 pref_service->registry()->RegisterDictionaryPref(
44 prefs::kDefaultTasksBySuffix);
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) {
54 pref_service->Set(prefs::kDefaultTasksByMimeType, mime_types);
55 pref_service->Set(prefs::kDefaultTasksBySuffix, suffixes);
60 TEST(FileManagerFileTasksTest,
61 FullTaskDescriptor_NonDriveAppWithIconAndDefault) {
62 FullTaskDescriptor full_descriptor(
63 TaskDescriptor("app-id",
64 TASK_TYPE_FILE_BROWSER_HANDLER,
67 GURL("http://example.com/icon.png"),
68 true /* is_default */,
69 false /* is_generic_file_handler */);
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());
79 TEST(FileManagerFileTasksTest,
80 FullTaskDescriptor_DriveAppWithoutIconAndNotDefault) {
81 FullTaskDescriptor full_descriptor(
82 TaskDescriptor("app-id",
86 GURL(), // No icon URL.
87 false /* is_default */,
88 false /* is_generic_file_handler */);
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());
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"));
107 TEST(FileManagerFileTasksTest, TaskDescriptorToId) {
108 EXPECT_EQ("app-id|file|action-id",
109 TaskDescriptorToId(TaskDescriptor("app-id",
110 TASK_TYPE_FILE_BROWSER_HANDLER,
114 TEST(FileManagerFileTasksTest, ParseTaskID_FileBrowserHandler) {
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);
122 TEST(FileManagerFileTasksTest, ParseTaskID_FileHandler) {
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);
130 TEST(FileManagerFileTasksTest, ParseTaskID_DriveApp) {
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);
138 TEST(FileManagerFileTasksTest, ParseTaskID_Legacy) {
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);
148 TEST(FileManagerFileTasksTest, ParseTaskID_LegacyDrive) {
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);
158 TEST(FileManagerFileTasksTest, ParseTaskID_Invalid) {
160 EXPECT_FALSE(ParseTaskID("invalid", &task));
163 TEST(FileManagerFileTasksTest, ParseTaskID_UnknownTaskType) {
165 EXPECT_FALSE(ParseTaskID("app-id|unknown|action-id", &task));
168 TEST(FileManagerFileTasksTest, FindDriveAppTasks) {
169 TestingProfile profile;
170 // For DriveAppRegistry, which checks CurrentlyOn(BrowserThread::UI).
171 content::TestBrowserThreadBundle thread_bundle;
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());
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());
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);
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(
207 drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
209 std::vector<FullTaskDescriptor> tasks;
210 FindDriveAppTasks(drive_app_registry,
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]);
223 // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
225 path_mime_set.clear();
226 path_mime_set.insert(
228 drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
230 path_mime_set.insert(
232 drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.html"),
235 FindDriveAppTasks(drive_app_registry,
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);
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"),
247 FindDriveAppTasks(drive_app_registry,
250 // Confirm no tasks are found.
251 ASSERT_TRUE(tasks.empty());
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);
260 // Text.app and Nice.app were found for "foo.txt".
261 TaskDescriptor text_app_task("text-app-id",
262 TASK_TYPE_FILE_HANDLER,
264 TaskDescriptor nice_app_task("nice-app-id",
265 TASK_TYPE_FILE_HANDLER,
267 std::vector<FullTaskDescriptor> tasks;
268 tasks.push_back(FullTaskDescriptor(
271 GURL("http://example.com/text_app.png"),
272 false /* is_default */,
273 false /* is_generic_file_handler */));
274 tasks.push_back(FullTaskDescriptor(
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"),
285 // None of them should be chosen as default, as nothing is set in the
287 ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
288 EXPECT_FALSE(tasks[0].is_default());
289 EXPECT_FALSE(tasks[1].is_default());
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(
296 TaskDescriptorToId(text_app_task));
297 UpdateDefaultTaskPreferences(&pref_service, mime_types, empty);
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());
304 // Change it back to non-default for testing further.
305 tasks[0].set_is_default(false);
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());
313 // Set Nice.app as default for ".txt" in the preferences.
314 base::DictionaryValue suffixes;
315 suffixes.SetStringWithoutPathExpansion(
317 TaskDescriptorToId(nice_app_task));
318 UpdateDefaultTaskPreferences(&pref_service, empty, suffixes);
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());
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);
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,
336 std::vector<FullTaskDescriptor> tasks;
337 tasks.push_back(FullTaskDescriptor(
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"),
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());
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;
360 FileHandlerInfo file_handler_info_1;
361 file_handler_info_1.extensions.insert("*");
362 EXPECT_TRUE(IsGenericFileHandler(file_handler_info_1));
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));
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));
376 FileHandlerInfo file_handler_info_4;
377 file_handler_info_4.types.insert("*");
378 EXPECT_TRUE(IsGenericFileHandler(file_handler_info_4));
381 FileHandlerInfo file_handler_info_5;
382 file_handler_info_5.types.insert("*/*");
383 EXPECT_TRUE(IsGenericFileHandler(file_handler_info_5));
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));
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));
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));
404 // Test using the test extension system, which needs lots of setup.
405 class FileManagerFileTasksComplexTest : public testing::Test {
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(
415 base::FilePath() /* install_directory */,
416 false /* autoupdate_enabled*/);
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_;
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";
436 // Foo.app can handle "text/plain" and "text/html".
437 extensions::ExtensionBuilder foo_app;
438 foo_app.SetManifest(extensions::DictionaryBuilder()
440 .Set("version", "1.0.0")
441 .Set("manifest_version", 2)
443 extensions::DictionaryBuilder()
445 extensions::DictionaryBuilder()
447 extensions::ListBuilder()
448 .Append("background.js"))))
449 .Set("file_handlers",
450 extensions::DictionaryBuilder()
452 extensions::DictionaryBuilder()
453 .Set("title", "Text")
455 extensions::ListBuilder()
456 .Append("text/plain")
457 .Append("text/html")))));
458 foo_app.SetID(kFooId);
459 extension_service_->AddExtension(foo_app.Build().get());
461 // Bar.app can only handle "text/plain".
462 extensions::ExtensionBuilder bar_app;
463 bar_app.SetManifest(extensions::DictionaryBuilder()
465 .Set("version", "1.0.0")
466 .Set("manifest_version", 2)
468 extensions::DictionaryBuilder()
470 extensions::DictionaryBuilder()
472 extensions::ListBuilder()
473 .Append("background.js"))))
474 .Set("file_handlers",
475 extensions::DictionaryBuilder()
477 extensions::DictionaryBuilder()
478 .Set("title", "Text")
480 extensions::ListBuilder()
481 .Append("text/plain")))));
482 bar_app.SetID(kBarId);
483 extension_service_->AddExtension(bar_app.Build().get());
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)
494 extensions::DictionaryBuilder().Set(
496 extensions::DictionaryBuilder().Set(
498 extensions::ListBuilder().Append("background.js"))))
499 .Set("file_handlers",
500 extensions::DictionaryBuilder().Set(
502 extensions::DictionaryBuilder().Set("title", "Text").Set(
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,
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(
521 drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
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]);
537 // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
539 path_mime_set.clear();
540 path_mime_set.insert(
542 drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
545 path_mime_set.insert(
547 drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
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);
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"),
561 FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
562 // Confirm no tasks are found.
563 ASSERT_TRUE(tasks.empty());
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";
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()
578 .Set("version", "1.0.0")
579 .Set("manifest_version", 2)
580 .Set("file_browser_handlers",
581 extensions::ListBuilder()
582 .Append(extensions::DictionaryBuilder()
584 .Set("default_title", "open")
586 extensions::ListBuilder()
587 .Append("filesystem:*.txt")
588 .Append("filesystem:*.html")))));
589 foo_app.SetID(kFooId);
590 extension_service_->AddExtension(foo_app.Build().get());
592 // Bar.app can only handle ".txt".
593 extensions::ExtensionBuilder bar_app;
594 bar_app.SetManifest(extensions::DictionaryBuilder()
596 .Set("version", "1.0.0")
597 .Set("manifest_version", 2)
598 .Set("file_browser_handlers",
599 extensions::ListBuilder()
600 .Append(extensions::DictionaryBuilder()
602 .Set("default_title", "open")
604 extensions::ListBuilder()
605 .Append("filesystem:*.txt")))));
606 bar_app.SetID(kBarId);
607 extension_service_->AddExtension(bar_app.Build().get());
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
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()
622 .Set("default_title", "open")
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,
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"));
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]);
654 // Find apps for ".txt" and ".html" files. Only Foo.app should be found.
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"));
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);
664 // Add an ".png" file. No tasks should be found.
665 file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.png"));
667 FindFileBrowserHandlerTasks(&test_profile_, file_urls, &tasks);
668 // Confirm no tasks are found.
669 ASSERT_TRUE(tasks.empty());
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";
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()
685 .Set("version", "1.0.0")
686 .Set("manifest_version", 2)
688 extensions::DictionaryBuilder()
690 extensions::DictionaryBuilder()
692 extensions::ListBuilder()
693 .Append("background.js"))))
694 .Set("file_handlers",
695 extensions::DictionaryBuilder()
697 extensions::DictionaryBuilder()
698 .Set("title", "Text")
700 extensions::ListBuilder()
701 .Append("text/plain")))));
702 foo_app.SetID(kFooId);
703 extension_service_->AddExtension(foo_app.Build().get());
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()
710 .Set("version", "1.0.0")
711 .Set("manifest_version", 2)
712 .Set("file_browser_handlers",
713 extensions::ListBuilder()
714 .Append(extensions::DictionaryBuilder()
716 .Set("default_title", "open")
718 extensions::ListBuilder()
719 .Append("filesystem:*.txt")))));
720 bar_app.SetID(kBarId);
721 extension_service_->AddExtension(bar_app.Build().get());
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);
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(
746 drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
749 file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
751 std::vector<FullTaskDescriptor> tasks;
752 FindAllTypesOfTasks(&test_profile_,
757 ASSERT_EQ(3U, tasks.size());
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]);
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";
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());
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);
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()
799 .Set("version", "1.0.0")
800 .Set("manifest_version", 2)
801 .Set("file_browser_handlers",
802 extensions::ListBuilder()
803 .Append(extensions::DictionaryBuilder()
805 .Set("default_title", "open")
807 extensions::ListBuilder()
808 .Append("filesystem:*.gdoc")))));
809 bar_app.SetID(kBarId);
810 extension_service_->AddExtension(bar_app.Build().get());
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()
824 .Set("default_title", "open")
826 extensions::ListBuilder()
827 .Append("filesystem:*.gdoc")))));
828 files_app.SetID(kFileManagerAppId);
829 extension_service_->AddExtension(files_app.Build().get());
831 // Find apps for a ".gdoc file". Only the built-in handler of Files.apps
833 PathAndMimeTypeSet path_mime_set;
834 std::vector<GURL> file_urls;
835 path_mime_set.insert(
837 drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
839 "application/vnd.google-apps.document"));
840 file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.gdoc"));
842 std::vector<FullTaskDescriptor> tasks;
843 FindAllTypesOfTasks(&test_profile_,
848 ASSERT_EQ(1U, tasks.size());
849 EXPECT_EQ(kFileManagerAppId, tasks[0].task_descriptor().app_id);
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";
860 // Foo app provides file handler for text/plain and all file types.
861 extensions::ExtensionBuilder foo_app;
862 foo_app.SetManifest(extensions::DictionaryBuilder()
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()
873 extensions::DictionaryBuilder()
874 .Set("types", extensions::ListBuilder()
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());
883 // Bar app provides file handler for .txt and not provide generic file
885 extensions::ExtensionBuilder bar_app;
886 bar_app.SetManifest(extensions::DictionaryBuilder()
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()
897 extensions::DictionaryBuilder()
898 .Set("extensions", extensions::ListBuilder()
900 bar_app.SetID(kBarId);
901 extension_service_->AddExtension(bar_app.Build().get());
903 // Baz app provides file handler for all extensions and images.
904 extensions::ExtensionBuilder baz_app;
905 baz_app.SetManifest(extensions::DictionaryBuilder()
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()
916 extensions::DictionaryBuilder()
917 .Set("extensions", extensions::ListBuilder()
921 extensions::DictionaryBuilder()
922 .Set("types", extensions::ListBuilder()
923 .Append("image/*")))));
924 baz_app.SetID(kBazId);
925 extension_service_->AddExtension(baz_app.Build().get());
927 // Qux app provides file handler for all types.
928 extensions::ExtensionBuilder qux_app;
929 qux_app.SetManifest(extensions::DictionaryBuilder()
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()
940 extensions::DictionaryBuilder()
941 .Set("types", extensions::ListBuilder()
943 qux_app.SetID(kQuxId);
944 extension_service_->AddExtension(qux_app.Build().get());
946 // Test case with .txt file
947 PathAndMimeTypeSet txt_path_mime_set;
948 txt_path_mime_set.insert(
950 drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
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());
969 // Test case with .jpg file
970 PathAndMimeTypeSet jpg_path_mime_set;
971 jpg_path_mime_set.insert(
973 drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
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());
991 } // namespace file_tasks
992 } // namespace file_manager.