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_(base::CommandLine::NO_PROGRAM
), extension_service_(NULL
) {
409 extensions::TestExtensionSystem
* test_extension_system
=
410 static_cast<extensions::TestExtensionSystem
*>(
411 extensions::ExtensionSystem::Get(&test_profile_
));
412 extension_service_
= test_extension_system
->CreateExtensionService(
414 base::FilePath() /* install_directory */,
415 false /* autoupdate_enabled*/);
418 content::TestBrowserThreadBundle thread_bundle_
;
419 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_
;
420 chromeos::ScopedTestCrosSettings test_cros_settings_
;
421 chromeos::ScopedTestUserManager test_user_manager_
;
422 TestingProfile test_profile_
;
423 base::CommandLine command_line_
;
424 ExtensionService
* extension_service_
; // Owned by test_profile_;
427 // The basic logic is similar to a test case for FindDriveAppTasks above.
428 TEST_F(FileManagerFileTasksComplexTest
, FindFileHandlerTasks
) {
429 // Random IDs generated by
430 // % ruby -le 'print (0...32).to_a.map{(?a + rand(16)).chr}.join'
431 const char kFooId
[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
432 const char kBarId
[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
433 const char kEphemeralId
[] = "opoomfdlbjcbjinalcjdjfoiikdeaoel";
435 // Foo.app can handle "text/plain" and "text/html".
436 extensions::ExtensionBuilder foo_app
;
437 foo_app
.SetManifest(extensions::DictionaryBuilder()
439 .Set("version", "1.0.0")
440 .Set("manifest_version", 2)
442 extensions::DictionaryBuilder()
444 extensions::DictionaryBuilder()
446 extensions::ListBuilder()
447 .Append("background.js"))))
448 .Set("file_handlers",
449 extensions::DictionaryBuilder()
451 extensions::DictionaryBuilder()
452 .Set("title", "Text")
454 extensions::ListBuilder()
455 .Append("text/plain")
456 .Append("text/html")))));
457 foo_app
.SetID(kFooId
);
458 extension_service_
->AddExtension(foo_app
.Build().get());
460 // Bar.app can only handle "text/plain".
461 extensions::ExtensionBuilder bar_app
;
462 bar_app
.SetManifest(extensions::DictionaryBuilder()
464 .Set("version", "1.0.0")
465 .Set("manifest_version", 2)
467 extensions::DictionaryBuilder()
469 extensions::DictionaryBuilder()
471 extensions::ListBuilder()
472 .Append("background.js"))))
473 .Set("file_handlers",
474 extensions::DictionaryBuilder()
476 extensions::DictionaryBuilder()
477 .Set("title", "Text")
479 extensions::ListBuilder()
480 .Append("text/plain")))));
481 bar_app
.SetID(kBarId
);
482 extension_service_
->AddExtension(bar_app
.Build().get());
484 // Ephemeral.app is an ephemeral app that can handle "text/plain".
485 // It should not ever be found as ephemeral apps cannot be file handlers.
486 extensions::ExtensionBuilder ephemeral_app
;
487 ephemeral_app
.SetManifest(
488 extensions::DictionaryBuilder()
489 .Set("name", "Ephemeral")
490 .Set("version", "1.0.0")
491 .Set("manifest_version", 2)
493 extensions::DictionaryBuilder().Set(
495 extensions::DictionaryBuilder().Set(
497 extensions::ListBuilder().Append("background.js"))))
498 .Set("file_handlers",
499 extensions::DictionaryBuilder().Set(
501 extensions::DictionaryBuilder().Set("title", "Text").Set(
503 extensions::ListBuilder().Append("text/plain")))));
504 ephemeral_app
.SetID(kEphemeralId
);
505 scoped_refptr
<extensions::Extension
> built_ephemeral_app(
506 ephemeral_app
.Build());
507 extension_service_
->AddExtension(built_ephemeral_app
.get());
508 extensions::ExtensionPrefs
* extension_prefs
=
509 extensions::ExtensionPrefs::Get(&test_profile_
);
510 extension_prefs
->OnExtensionInstalled(built_ephemeral_app
.get(),
511 extensions::Extension::ENABLED
,
512 syncer::StringOrdinal(),
513 extensions::kInstallFlagIsEphemeral
,
516 // Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
517 PathAndMimeTypeSet path_mime_set
;
518 path_mime_set
.insert(
520 drive::util::GetDriveMountPointPath(&test_profile_
).AppendASCII(
524 std::vector
<FullTaskDescriptor
> tasks
;
525 FindFileHandlerTasks(&test_profile_
, path_mime_set
, &tasks
);
526 ASSERT_EQ(2U, tasks
.size());
527 // Sort the app IDs, as the order is not guaranteed.
528 std::vector
<std::string
> app_ids
;
529 app_ids
.push_back(tasks
[0].task_descriptor().app_id
);
530 app_ids
.push_back(tasks
[1].task_descriptor().app_id
);
531 std::sort(app_ids
.begin(), app_ids
.end());
532 // Confirm that both Foo.app and Bar.app are found.
533 EXPECT_EQ(kFooId
, app_ids
[0]);
534 EXPECT_EQ(kBarId
, app_ids
[1]);
536 // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
538 path_mime_set
.clear();
539 path_mime_set
.insert(
541 drive::util::GetDriveMountPointPath(&test_profile_
).AppendASCII(
544 path_mime_set
.insert(
546 drive::util::GetDriveMountPointPath(&test_profile_
).AppendASCII(
550 FindFileHandlerTasks(&test_profile_
, path_mime_set
, &tasks
);
551 ASSERT_EQ(1U, tasks
.size());
552 // Confirm that only Foo.app is found.
553 EXPECT_EQ(kFooId
, tasks
[0].task_descriptor().app_id
);
555 // Add an "image/png" file. No tasks should be found.
556 path_mime_set
.insert(
557 std::make_pair(base::FilePath::FromUTF8Unsafe("foo.png"),
560 FindFileHandlerTasks(&test_profile_
, path_mime_set
, &tasks
);
561 // Confirm no tasks are found.
562 ASSERT_TRUE(tasks
.empty());
565 // The basic logic is similar to a test case for FindDriveAppTasks above.
566 TEST_F(FileManagerFileTasksComplexTest
, FindFileBrowserHandlerTasks
) {
567 // Copied from FindFileHandlerTasks test above.
568 const char kFooId
[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
569 const char kBarId
[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
570 const char kEphemeralId
[] = "opoomfdlbjcbjinalcjdjfoiikdeaoel";
572 // Foo.app can handle ".txt" and ".html".
573 // This one is an extension, and has "file_browser_handlers"
574 extensions::ExtensionBuilder foo_app
;
576 extensions::DictionaryBuilder()
578 .Set("version", "1.0.0")
579 .Set("manifest_version", 2)
581 extensions::ListBuilder().Append("fileBrowserHandler"))
583 "file_browser_handlers",
584 extensions::ListBuilder().Append(
585 extensions::DictionaryBuilder()
587 .Set("default_title", "open")
588 .Set("file_filters", extensions::ListBuilder()
589 .Append("filesystem:*.txt")
590 .Append("filesystem:*.html")))));
591 foo_app
.SetID(kFooId
);
592 extension_service_
->AddExtension(foo_app
.Build().get());
594 // Bar.app can only handle ".txt".
595 extensions::ExtensionBuilder bar_app
;
597 extensions::DictionaryBuilder()
599 .Set("version", "1.0.0")
600 .Set("manifest_version", 2)
602 extensions::ListBuilder().Append("fileBrowserHandler"))
603 .Set("file_browser_handlers",
604 extensions::ListBuilder().Append(
605 extensions::DictionaryBuilder()
607 .Set("default_title", "open")
608 .Set("file_filters", extensions::ListBuilder().Append(
609 "filesystem:*.txt")))));
610 bar_app
.SetID(kBarId
);
611 extension_service_
->AddExtension(bar_app
.Build().get());
613 // Ephemeral.app is an ephemeral app that can handle ".txt".
614 // It should not ever be found as ephemeral apps cannot be file browser
616 extensions::ExtensionBuilder ephemeral_app
;
617 ephemeral_app
.SetManifest(
618 extensions::DictionaryBuilder()
619 .Set("name", "Ephemeral")
620 .Set("version", "1.0.0")
621 .Set("manifest_version", 2)
623 extensions::ListBuilder().Append("fileBrowserHandler"))
624 .Set("file_browser_handlers",
625 extensions::ListBuilder().Append(
626 extensions::DictionaryBuilder()
628 .Set("default_title", "open")
629 .Set("file_filters", extensions::ListBuilder().Append(
630 "filesystem:*.txt")))));
631 ephemeral_app
.SetID(kEphemeralId
);
632 scoped_refptr
<extensions::Extension
> built_ephemeral_app(
633 ephemeral_app
.Build());
634 extension_service_
->AddExtension(built_ephemeral_app
.get());
635 extensions::ExtensionPrefs
* extension_prefs
=
636 extensions::ExtensionPrefs::Get(&test_profile_
);
637 extension_prefs
->OnExtensionInstalled(built_ephemeral_app
.get(),
638 extensions::Extension::ENABLED
,
639 syncer::StringOrdinal(),
640 extensions::kInstallFlagIsEphemeral
,
643 // Find apps for a ".txt" file. Foo.app and Bar.app should be found.
644 std::vector
<GURL
> file_urls
;
645 file_urls
.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
647 std::vector
<FullTaskDescriptor
> tasks
;
648 FindFileBrowserHandlerTasks(&test_profile_
, file_urls
, &tasks
);
649 ASSERT_EQ(2U, tasks
.size());
650 // Sort the app IDs, as the order is not guaranteed.
651 std::vector
<std::string
> app_ids
;
652 app_ids
.push_back(tasks
[0].task_descriptor().app_id
);
653 app_ids
.push_back(tasks
[1].task_descriptor().app_id
);
654 std::sort(app_ids
.begin(), app_ids
.end());
655 // Confirm that both Foo.app and Bar.app are found.
656 EXPECT_EQ(kFooId
, app_ids
[0]);
657 EXPECT_EQ(kBarId
, app_ids
[1]);
659 // Find apps for ".txt" and ".html" files. Only Foo.app should be found.
661 file_urls
.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
662 file_urls
.push_back(GURL("filesystem:chrome-extension://id/dir/foo.html"));
664 FindFileBrowserHandlerTasks(&test_profile_
, file_urls
, &tasks
);
665 ASSERT_EQ(1U, tasks
.size());
666 // Confirm that only Foo.app is found.
667 EXPECT_EQ(kFooId
, tasks
[0].task_descriptor().app_id
);
669 // Add an ".png" file. No tasks should be found.
670 file_urls
.push_back(GURL("filesystem:chrome-extension://id/dir/foo.png"));
672 FindFileBrowserHandlerTasks(&test_profile_
, file_urls
, &tasks
);
673 // Confirm no tasks are found.
674 ASSERT_TRUE(tasks
.empty());
677 // Test that all kinds of apps (file handler, file browser handler, and Drive
678 // app) are returned.
679 TEST_F(FileManagerFileTasksComplexTest
, FindAllTypesOfTasks
) {
680 // kFooId and kBarId copied from FindFileHandlerTasks test above.
681 const char kFooId
[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
682 const char kBarId
[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
683 const char kBazId
[] = "plifkpkakemokpflgbnnigcoldgcbdmc";
685 // Foo.app can handle "text/plain".
686 // This is a packaged app (file handler).
687 extensions::ExtensionBuilder foo_app
;
688 foo_app
.SetManifest(extensions::DictionaryBuilder()
690 .Set("version", "1.0.0")
691 .Set("manifest_version", 2)
693 extensions::DictionaryBuilder()
695 extensions::DictionaryBuilder()
697 extensions::ListBuilder()
698 .Append("background.js"))))
699 .Set("file_handlers",
700 extensions::DictionaryBuilder()
702 extensions::DictionaryBuilder()
703 .Set("title", "Text")
705 extensions::ListBuilder()
706 .Append("text/plain")))));
707 foo_app
.SetID(kFooId
);
708 extension_service_
->AddExtension(foo_app
.Build().get());
710 // Bar.app can only handle ".txt".
711 // This is an extension (file browser handler).
712 extensions::ExtensionBuilder bar_app
;
714 extensions::DictionaryBuilder()
716 .Set("version", "1.0.0")
717 .Set("manifest_version", 2)
719 extensions::ListBuilder().Append("fileBrowserHandler"))
720 .Set("file_browser_handlers",
721 extensions::ListBuilder().Append(
722 extensions::DictionaryBuilder()
724 .Set("default_title", "open")
725 .Set("file_filters", extensions::ListBuilder().Append(
726 "filesystem:*.txt")))));
727 bar_app
.SetID(kBarId
);
728 extension_service_
->AddExtension(bar_app
.Build().get());
730 // Baz.app can handle "text/plain".
731 // This is a Drive app.
732 scoped_ptr
<google_apis::AppResource
> baz_app(new google_apis::AppResource
);
733 baz_app
->set_product_id("baz_app_id");
734 baz_app
->set_application_id(kBazId
);
735 baz_app
->set_name("Baz");
736 baz_app
->set_object_type("baz_object_type");
737 ScopedVector
<std::string
> baz_mime_types
;
738 baz_mime_types
.push_back(new std::string("text/plain"));
739 baz_app
->set_primary_mimetypes(baz_mime_types
.Pass());
740 // Set up DriveAppRegistry.
741 ScopedVector
<google_apis::AppResource
> app_resources
;
742 app_resources
.push_back(baz_app
.release());
743 google_apis::AppList app_list
;
744 app_list
.set_items(app_resources
.Pass());
745 drive::DriveAppRegistry
drive_app_registry(NULL
);
746 drive_app_registry
.UpdateFromAppList(app_list
);
748 // Find apps for "foo.txt". All apps should be found.
749 PathAndMimeTypeSet path_mime_set
;
750 std::vector
<GURL
> file_urls
;
751 path_mime_set
.insert(
753 drive::util::GetDriveMountPointPath(&test_profile_
).AppendASCII(
756 file_urls
.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
758 std::vector
<FullTaskDescriptor
> tasks
;
759 FindAllTypesOfTasks(&test_profile_
,
764 ASSERT_EQ(3U, tasks
.size());
766 // Sort the app IDs, as the order is not guaranteed.
767 std::vector
<std::string
> app_ids
;
768 app_ids
.push_back(tasks
[0].task_descriptor().app_id
);
769 app_ids
.push_back(tasks
[1].task_descriptor().app_id
);
770 app_ids
.push_back(tasks
[2].task_descriptor().app_id
);
771 std::sort(app_ids
.begin(), app_ids
.end());
772 // Confirm that all apps are found.
773 EXPECT_EQ(kFooId
, app_ids
[0]);
774 EXPECT_EQ(kBarId
, app_ids
[1]);
775 EXPECT_EQ(kBazId
, app_ids
[2]);
778 TEST_F(FileManagerFileTasksComplexTest
, FindAllTypesOfTasks_GoogleDocument
) {
779 // kFooId and kBarId copied from FindFileHandlerTasks test above.
780 const char kFooId
[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
781 const char kBarId
[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
783 // Foo.app can handle ".gdoc" files.
784 scoped_ptr
<google_apis::AppResource
> foo_app(new google_apis::AppResource
);
785 foo_app
->set_product_id("foo_app");
786 foo_app
->set_application_id(kFooId
);
787 foo_app
->set_name("Foo");
788 foo_app
->set_object_type("foo_object_type");
789 ScopedVector
<std::string
> foo_extensions
;
790 foo_extensions
.push_back(new std::string("gdoc")); // Not ".gdoc"
791 foo_app
->set_primary_file_extensions(foo_extensions
.Pass());
793 // Prepare DriveAppRegistry from Foo.app.
794 ScopedVector
<google_apis::AppResource
> app_resources
;
795 app_resources
.push_back(foo_app
.release());
796 google_apis::AppList app_list
;
797 app_list
.set_items(app_resources
.Pass());
798 drive::DriveAppRegistry
drive_app_registry(NULL
);
799 drive_app_registry
.UpdateFromAppList(app_list
);
801 // Bar.app can handle ".gdoc" files.
802 // This is an extension (file browser handler).
803 extensions::ExtensionBuilder bar_app
;
805 extensions::DictionaryBuilder()
807 .Set("version", "1.0.0")
808 .Set("manifest_version", 2)
810 extensions::ListBuilder().Append("fileBrowserHandler"))
811 .Set("file_browser_handlers",
812 extensions::ListBuilder().Append(
813 extensions::DictionaryBuilder()
815 .Set("default_title", "open")
816 .Set("file_filters", extensions::ListBuilder().Append(
817 "filesystem:*.gdoc")))));
818 bar_app
.SetID(kBarId
);
819 extension_service_
->AddExtension(bar_app
.Build().get());
821 // Files.app can handle ".gdoc" files.
822 // The ID "kFileManagerAppId" used here is precisely the one that identifies
823 // the Chrome OS Files.app application.
824 extensions::ExtensionBuilder files_app
;
825 files_app
.SetManifest(
826 extensions::DictionaryBuilder()
827 .Set("name", "Files")
828 .Set("version", "1.0.0")
829 .Set("manifest_version", 2)
831 extensions::ListBuilder().Append("fileBrowserHandler"))
832 .Set("file_browser_handlers",
833 extensions::ListBuilder().Append(
834 extensions::DictionaryBuilder()
836 .Set("default_title", "open")
837 .Set("file_filters", extensions::ListBuilder().Append(
838 "filesystem:*.gdoc")))));
839 files_app
.SetID(kFileManagerAppId
);
840 extension_service_
->AddExtension(files_app
.Build().get());
842 // Find apps for a ".gdoc file". Only the built-in handler of Files.apps
844 PathAndMimeTypeSet path_mime_set
;
845 std::vector
<GURL
> file_urls
;
846 path_mime_set
.insert(
848 drive::util::GetDriveMountPointPath(&test_profile_
).AppendASCII(
850 "application/vnd.google-apps.document"));
851 file_urls
.push_back(GURL("filesystem:chrome-extension://id/dir/foo.gdoc"));
853 std::vector
<FullTaskDescriptor
> tasks
;
854 FindAllTypesOfTasks(&test_profile_
,
859 ASSERT_EQ(1U, tasks
.size());
860 EXPECT_EQ(kFileManagerAppId
, tasks
[0].task_descriptor().app_id
);
863 TEST_F(FileManagerFileTasksComplexTest
, FindFileHandlerTask_Generic
) {
864 // Since we want to keep the order of the result as foo,bar,baz,qux,
865 // keep the ids in alphabetical order.
866 const char kFooId
[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
867 const char kBarId
[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
868 const char kBazId
[] = "plifkpkakemokpflgbnnigcoldgcbdmc";
869 const char kQuxId
[] = "pmifkpkakgkadkkhcmhgnigmmifgpaph";
871 // Foo app provides file handler for text/plain and all file types.
872 extensions::ExtensionBuilder foo_app
;
873 foo_app
.SetManifest(extensions::DictionaryBuilder()
875 .Set("version", "1.0.0")
876 .Set("manifest_version", 2)
877 .Set("app", extensions::DictionaryBuilder()
878 .Set("background", extensions::DictionaryBuilder()
879 .Set("scripts", extensions::ListBuilder()
880 .Append("background.js"))))
881 .Set("file_handlers",
882 extensions::DictionaryBuilder()
884 extensions::DictionaryBuilder()
885 .Set("types", extensions::ListBuilder()
888 extensions::DictionaryBuilder()
889 .Set("types", extensions::ListBuilder()
890 .Append("text/plain")))));
891 foo_app
.SetID(kFooId
);
892 extension_service_
->AddExtension(foo_app
.Build().get());
894 // Bar app provides file handler for .txt and not provide generic file
896 extensions::ExtensionBuilder bar_app
;
897 bar_app
.SetManifest(extensions::DictionaryBuilder()
899 .Set("version", "1.0.0")
900 .Set("manifest_version", 2)
901 .Set("app", extensions::DictionaryBuilder()
902 .Set("background", extensions::DictionaryBuilder()
903 .Set("scripts", extensions::ListBuilder()
904 .Append("background.js"))))
905 .Set("file_handlers",
906 extensions::DictionaryBuilder()
908 extensions::DictionaryBuilder()
909 .Set("extensions", extensions::ListBuilder()
911 bar_app
.SetID(kBarId
);
912 extension_service_
->AddExtension(bar_app
.Build().get());
914 // Baz app provides file handler for all extensions and images.
915 extensions::ExtensionBuilder baz_app
;
916 baz_app
.SetManifest(extensions::DictionaryBuilder()
918 .Set("version", "1.0.0")
919 .Set("manifest_version", 2)
920 .Set("app", extensions::DictionaryBuilder()
921 .Set("background", extensions::DictionaryBuilder()
922 .Set("scripts", extensions::ListBuilder()
923 .Append("background.js"))))
924 .Set("file_handlers",
925 extensions::DictionaryBuilder()
927 extensions::DictionaryBuilder()
928 .Set("extensions", extensions::ListBuilder()
932 extensions::DictionaryBuilder()
933 .Set("types", extensions::ListBuilder()
934 .Append("image/*")))));
935 baz_app
.SetID(kBazId
);
936 extension_service_
->AddExtension(baz_app
.Build().get());
938 // Qux app provides file handler for all types.
939 extensions::ExtensionBuilder qux_app
;
940 qux_app
.SetManifest(extensions::DictionaryBuilder()
942 .Set("version", "1.0.0")
943 .Set("manifest_version", 2)
944 .Set("app", extensions::DictionaryBuilder()
945 .Set("background", extensions::DictionaryBuilder()
946 .Set("scripts", extensions::ListBuilder()
947 .Append("background.js"))))
948 .Set("file_handlers",
949 extensions::DictionaryBuilder()
951 extensions::DictionaryBuilder()
952 .Set("types", extensions::ListBuilder()
954 qux_app
.SetID(kQuxId
);
955 extension_service_
->AddExtension(qux_app
.Build().get());
957 // Test case with .txt file
958 PathAndMimeTypeSet txt_path_mime_set
;
959 txt_path_mime_set
.insert(
961 drive::util::GetDriveMountPointPath(&test_profile_
).AppendASCII(
964 std::vector
<FullTaskDescriptor
> txt_result
;
965 FindFileHandlerTasks(&test_profile_
, txt_path_mime_set
, &txt_result
);
966 EXPECT_EQ(4U, txt_result
.size());
967 // Foo app provides a handler for text/plain.
968 EXPECT_EQ("Foo", txt_result
[0].task_title());
969 EXPECT_FALSE(txt_result
[0].is_generic_file_handler());
970 // Bar app provides a handler for .txt.
971 EXPECT_EQ("Bar", txt_result
[1].task_title());
972 EXPECT_FALSE(txt_result
[1].is_generic_file_handler());
973 // Baz app provides a handler for all extensions.
974 EXPECT_EQ("Baz", txt_result
[2].task_title());
975 EXPECT_TRUE(txt_result
[2].is_generic_file_handler());
976 // Qux app provides a handler for all types.
977 EXPECT_EQ("Qux", txt_result
[3].task_title());
978 EXPECT_TRUE(txt_result
[3].is_generic_file_handler());
980 // Test case with .jpg file
981 PathAndMimeTypeSet jpg_path_mime_set
;
982 jpg_path_mime_set
.insert(
984 drive::util::GetDriveMountPointPath(&test_profile_
).AppendASCII(
987 std::vector
<FullTaskDescriptor
> jpg_result
;
988 FindFileHandlerTasks(&test_profile_
, jpg_path_mime_set
, &jpg_result
);
989 EXPECT_EQ(3U, jpg_result
.size());
990 // Foo app provides a handler for all types.
991 EXPECT_EQ("Foo", jpg_result
[0].task_title());
992 EXPECT_TRUE(jpg_result
[0].is_generic_file_handler());
993 // Baz app provides a handler for image/*. A partial wildcarded handler is
994 // treated as non-generic handler.
995 EXPECT_EQ("Baz", jpg_result
[1].task_title());
996 EXPECT_FALSE(jpg_result
[1].is_generic_file_handler());
997 // Qux app provides a handler for all types.
998 EXPECT_EQ("Qux", jpg_result
[2].task_title());
999 EXPECT_TRUE(jpg_result
[2].is_generic_file_handler());
1002 } // namespace file_tasks
1003 } // namespace file_manager.