Home | History | Annotate | Download | only in file_manager
      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/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_system.h"
     26 #include "extensions/common/extension_builder.h"
     27 #include "google_apis/drive/drive_api_parser.h"
     28 #include "testing/gtest/include/gtest/gtest.h"
     29 #include "url/gurl.h"
     30 
     31 namespace file_manager {
     32 namespace file_tasks {
     33 namespace {
     34 
     35 // Registers the default task preferences. Used for testing
     36 // ChooseAndSetDefaultTask().
     37 void RegisterDefaultTaskPreferences(TestingPrefServiceSimple* pref_service) {
     38   DCHECK(pref_service);
     39 
     40   pref_service->registry()->RegisterDictionaryPref(
     41       prefs::kDefaultTasksByMimeType);
     42   pref_service->registry()->RegisterDictionaryPref(
     43       prefs::kDefaultTasksBySuffix);
     44 }
     45 
     46 // Updates the default task preferences per the given dictionary values. Used
     47 // for testing ChooseAndSetDefaultTask.
     48 void UpdateDefaultTaskPreferences(TestingPrefServiceSimple* pref_service,
     49                                   const base::DictionaryValue& mime_types,
     50                                   const base::DictionaryValue& suffixes) {
     51   DCHECK(pref_service);
     52 
     53   pref_service->Set(prefs::kDefaultTasksByMimeType, mime_types);
     54   pref_service->Set(prefs::kDefaultTasksBySuffix, suffixes);
     55 }
     56 
     57 }  // namespace
     58 
     59 TEST(FileManagerFileTasksTest,
     60      FullTaskDescriptor_NonDriveAppWithIconAndDefault) {
     61   FullTaskDescriptor full_descriptor(
     62       TaskDescriptor("app-id",
     63                      TASK_TYPE_FILE_BROWSER_HANDLER,
     64                      "action-id"),
     65       "task title",
     66       GURL("http://example.com/icon.png"),
     67       true /* is_default */);
     68 
     69   const std::string task_id =
     70       TaskDescriptorToId(full_descriptor.task_descriptor());
     71   EXPECT_EQ("app-id|file|action-id", task_id);
     72   EXPECT_EQ("http://example.com/icon.png", full_descriptor.icon_url().spec());
     73   EXPECT_EQ("task title", full_descriptor.task_title());
     74   EXPECT_TRUE(full_descriptor.is_default());
     75 }
     76 
     77 TEST(FileManagerFileTasksTest,
     78      FullTaskDescriptor_DriveAppWithoutIconAndNotDefault) {
     79   FullTaskDescriptor full_descriptor(
     80       TaskDescriptor("app-id",
     81                      TASK_TYPE_DRIVE_APP,
     82                      "action-id"),
     83       "task title",
     84       GURL(),  // No icon URL.
     85       false /* is_default */);
     86 
     87   const std::string task_id =
     88       TaskDescriptorToId(full_descriptor.task_descriptor());
     89   EXPECT_EQ("app-id|drive|action-id", task_id);
     90   EXPECT_TRUE(full_descriptor.icon_url().is_empty());
     91   EXPECT_EQ("task title", full_descriptor.task_title());
     92   EXPECT_FALSE(full_descriptor.is_default());
     93 }
     94 
     95 TEST(FileManagerFileTasksTest, MakeTaskID) {
     96   EXPECT_EQ("app-id|file|action-id",
     97             MakeTaskID("app-id", TASK_TYPE_FILE_BROWSER_HANDLER, "action-id"));
     98   EXPECT_EQ("app-id|app|action-id",
     99             MakeTaskID("app-id", TASK_TYPE_FILE_HANDLER, "action-id"));
    100   EXPECT_EQ("app-id|drive|action-id",
    101             MakeTaskID("app-id", TASK_TYPE_DRIVE_APP, "action-id"));
    102 }
    103 
    104 TEST(FileManagerFileTasksTest, MakeDriveAppTaskId) {
    105   EXPECT_EQ("app-id|drive|open-with", MakeDriveAppTaskId("app-id"));
    106 }
    107 
    108 TEST(FileManagerFileTasksTest, TaskDescriptorToId) {
    109   EXPECT_EQ("app-id|file|action-id",
    110             TaskDescriptorToId(TaskDescriptor("app-id",
    111                                               TASK_TYPE_FILE_BROWSER_HANDLER,
    112                                               "action-id")));
    113 }
    114 
    115 TEST(FileManagerFileTasksTest, ParseTaskID_FileBrowserHandler) {
    116   TaskDescriptor task;
    117   EXPECT_TRUE(ParseTaskID("app-id|file|action-id", &task));
    118   EXPECT_EQ("app-id", task.app_id);
    119   EXPECT_EQ(TASK_TYPE_FILE_BROWSER_HANDLER, task.task_type);
    120   EXPECT_EQ("action-id", task.action_id);
    121 }
    122 
    123 TEST(FileManagerFileTasksTest, ParseTaskID_FileHandler) {
    124   TaskDescriptor task;
    125   EXPECT_TRUE(ParseTaskID("app-id|app|action-id", &task));
    126   EXPECT_EQ("app-id", task.app_id);
    127   EXPECT_EQ(TASK_TYPE_FILE_HANDLER, task.task_type);
    128   EXPECT_EQ("action-id", task.action_id);
    129 }
    130 
    131 TEST(FileManagerFileTasksTest, ParseTaskID_DriveApp) {
    132   TaskDescriptor task;
    133   EXPECT_TRUE(ParseTaskID("app-id|drive|action-id", &task));
    134   EXPECT_EQ("app-id", task.app_id);
    135   EXPECT_EQ(TASK_TYPE_DRIVE_APP, task.task_type);
    136   EXPECT_EQ("action-id", task.action_id);
    137 }
    138 
    139 TEST(FileManagerFileTasksTest, ParseTaskID_Legacy) {
    140   TaskDescriptor task;
    141   // A legacy task ID only has two parts. The task type should be
    142   // TASK_TYPE_FILE_BROWSER_HANDLER.
    143   EXPECT_TRUE(ParseTaskID("app-id|action-id", &task));
    144   EXPECT_EQ("app-id", task.app_id);
    145   EXPECT_EQ(TASK_TYPE_FILE_BROWSER_HANDLER, task.task_type);
    146   EXPECT_EQ("action-id", task.action_id);
    147 }
    148 
    149 TEST(FileManagerFileTasksTest, ParseTaskID_LegacyDrive) {
    150   TaskDescriptor task;
    151   // A legacy task ID only has two parts. For Drive app, the app ID is
    152   // prefixed with "drive-app:".
    153   EXPECT_TRUE(ParseTaskID("drive-app:app-id|action-id", &task));
    154   EXPECT_EQ("app-id", task.app_id);
    155   EXPECT_EQ(TASK_TYPE_DRIVE_APP, task.task_type);
    156   EXPECT_EQ("action-id", task.action_id);
    157 }
    158 
    159 TEST(FileManagerFileTasksTest, ParseTaskID_Invalid) {
    160   TaskDescriptor task;
    161   EXPECT_FALSE(ParseTaskID("invalid", &task));
    162 }
    163 
    164 TEST(FileManagerFileTasksTest, ParseTaskID_UnknownTaskType) {
    165   TaskDescriptor task;
    166   EXPECT_FALSE(ParseTaskID("app-id|unknown|action-id", &task));
    167 }
    168 
    169 TEST(FileManagerFileTasksTest, FindDriveAppTasks) {
    170   TestingProfile profile;
    171   // For DriveAppRegistry, which checks CurrentlyOn(BrowserThread::UI).
    172   content::TestBrowserThreadBundle thread_bundle;
    173 
    174   // Foo.app can handle "text/plain" and "text/html"
    175   scoped_ptr<google_apis::AppResource> foo_app(new google_apis::AppResource);
    176   foo_app->set_product_id("foo_app_id");
    177   foo_app->set_application_id("foo_app_id");
    178   foo_app->set_name("Foo");
    179   foo_app->set_object_type("foo_object_type");
    180   ScopedVector<std::string> foo_mime_types;
    181   foo_mime_types.push_back(new std::string("text/plain"));
    182   foo_mime_types.push_back(new std::string("text/html"));
    183   foo_app->set_primary_mimetypes(foo_mime_types.Pass());
    184 
    185   // Bar.app can only handle "text/plain".
    186   scoped_ptr<google_apis::AppResource> bar_app(new google_apis::AppResource);
    187   bar_app->set_product_id("bar_app_id");
    188   bar_app->set_application_id("bar_app_id");
    189   bar_app->set_name("Bar");
    190   bar_app->set_object_type("bar_object_type");
    191   ScopedVector<std::string> bar_mime_types;
    192   bar_mime_types.push_back(new std::string("text/plain"));
    193   bar_app->set_primary_mimetypes(bar_mime_types.Pass());
    194 
    195   // Prepare DriveAppRegistry from Foo.app and Bar.app.
    196   ScopedVector<google_apis::AppResource> app_resources;
    197   app_resources.push_back(foo_app.release());
    198   app_resources.push_back(bar_app.release());
    199   google_apis::AppList app_list;
    200   app_list.set_items(app_resources.Pass());
    201   drive::DriveAppRegistry drive_app_registry(NULL);
    202   drive_app_registry.UpdateFromAppList(app_list);
    203 
    204   // Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
    205   PathAndMimeTypeSet path_mime_set;
    206   path_mime_set.insert(
    207       std::make_pair(
    208           drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
    209           "text/plain"));
    210   std::vector<FullTaskDescriptor> tasks;
    211   FindDriveAppTasks(drive_app_registry,
    212                     path_mime_set,
    213                     &tasks);
    214   ASSERT_EQ(2U, tasks.size());
    215   // Sort the app IDs, as the order is not guaranteed.
    216   std::vector<std::string> app_ids;
    217   app_ids.push_back(tasks[0].task_descriptor().app_id);
    218   app_ids.push_back(tasks[1].task_descriptor().app_id);
    219   std::sort(app_ids.begin(), app_ids.end());
    220   // Confirm that both Foo.app and Bar.app are found.
    221   EXPECT_EQ("bar_app_id", app_ids[0]);
    222   EXPECT_EQ("foo_app_id", app_ids[1]);
    223 
    224   // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
    225   // found.
    226   path_mime_set.clear();
    227   path_mime_set.insert(
    228       std::make_pair(
    229           drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
    230           "text/plain"));
    231   path_mime_set.insert(
    232       std::make_pair(
    233           drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.html"),
    234           "text/html"));
    235   tasks.clear();
    236   FindDriveAppTasks(drive_app_registry,
    237                     path_mime_set,
    238                     &tasks);
    239   ASSERT_EQ(1U, tasks.size());
    240   // Confirm that only Foo.app is found.
    241   EXPECT_EQ("foo_app_id", tasks[0].task_descriptor().app_id);
    242 
    243   // Add a "text/plain" file not on Drive. No tasks should be found.
    244   path_mime_set.insert(
    245       std::make_pair(base::FilePath::FromUTF8Unsafe("not_on_drive.txt"),
    246                      "text/plain"));
    247   tasks.clear();
    248   FindDriveAppTasks(drive_app_registry,
    249                     path_mime_set,
    250                     &tasks);
    251   // Confirm no tasks are found.
    252   ASSERT_TRUE(tasks.empty());
    253 }
    254 
    255 // Test that the right task is chosen from multiple choices per mime types
    256 // and file extensions.
    257 TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_MultipleTasks) {
    258   TestingPrefServiceSimple pref_service;
    259   RegisterDefaultTaskPreferences(&pref_service);
    260 
    261   // Text.app and Nice.app were found for "foo.txt".
    262   TaskDescriptor text_app_task("text-app-id",
    263                                TASK_TYPE_FILE_HANDLER,
    264                                "action-id");
    265   TaskDescriptor nice_app_task("nice-app-id",
    266                                TASK_TYPE_FILE_HANDLER,
    267                                "action-id");
    268   std::vector<FullTaskDescriptor> tasks;
    269   tasks.push_back(FullTaskDescriptor(
    270       text_app_task,
    271       "Text.app",
    272       GURL("http://example.com/text_app.png"),
    273       false /* is_default */));
    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   PathAndMimeTypeSet path_mime_set;
    280   path_mime_set.insert(std::make_pair(
    281       base::FilePath::FromUTF8Unsafe("foo.txt"),
    282       "text/plain"));
    283 
    284   // None of them should be chosen as default, as nothing is set in the
    285   // preferences.
    286   ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
    287   EXPECT_FALSE(tasks[0].is_default());
    288   EXPECT_FALSE(tasks[1].is_default());
    289 
    290   // Set Text.app as default for "text/plain" in the preferences.
    291   base::DictionaryValue empty;
    292   base::DictionaryValue mime_types;
    293   mime_types.SetStringWithoutPathExpansion(
    294       "text/plain",
    295       TaskDescriptorToId(text_app_task));
    296   UpdateDefaultTaskPreferences(&pref_service, mime_types, empty);
    297 
    298   // Text.app should be chosen as default.
    299   ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
    300   EXPECT_TRUE(tasks[0].is_default());
    301   EXPECT_FALSE(tasks[1].is_default());
    302 
    303   // Change it back to non-default for testing further.
    304   tasks[0].set_is_default(false);
    305 
    306   // Clear the preferences and make sure none of them are default.
    307   UpdateDefaultTaskPreferences(&pref_service, empty, empty);
    308   ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
    309   EXPECT_FALSE(tasks[0].is_default());
    310   EXPECT_FALSE(tasks[1].is_default());
    311 
    312   // Set Nice.app as default for ".txt" in the preferences.
    313   base::DictionaryValue suffixes;
    314   suffixes.SetStringWithoutPathExpansion(
    315       ".txt",
    316       TaskDescriptorToId(nice_app_task));
    317   UpdateDefaultTaskPreferences(&pref_service, empty, suffixes);
    318 
    319   // Now Nice.app should be chosen as default.
    320   ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
    321   EXPECT_FALSE(tasks[0].is_default());
    322   EXPECT_TRUE(tasks[1].is_default());
    323 }
    324 
    325 // Test that Files.app's internal file browser handler is chosen as default
    326 // even if nothing is set in the preferences.
    327 TEST(FileManagerFileTasksTest, ChooseAndSetDefaultTask_FallbackFileBrowser) {
    328   TestingPrefServiceSimple pref_service;
    329   RegisterDefaultTaskPreferences(&pref_service);
    330 
    331   // Files.app's internal file browser handler was found for "foo.txt".
    332   TaskDescriptor files_app_task(kFileManagerAppId,
    333                                 TASK_TYPE_FILE_BROWSER_HANDLER,
    334                                 "view-in-browser");
    335   std::vector<FullTaskDescriptor> tasks;
    336   tasks.push_back(FullTaskDescriptor(
    337       files_app_task,
    338       "View in browser",
    339       GURL("http://example.com/some_icon.png"),
    340       false /* is_default */));
    341   PathAndMimeTypeSet path_mime_set;
    342   path_mime_set.insert(std::make_pair(
    343       base::FilePath::FromUTF8Unsafe("foo.txt"),
    344       "text/plain"));
    345 
    346   // The internal file browser handler should be chosen as default, as it's a
    347   // fallback file browser handler.
    348   ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
    349   EXPECT_TRUE(tasks[0].is_default());
    350 }
    351 
    352 // Test using the test extension system, which needs lots of setup.
    353 class FileManagerFileTasksComplexTest : public testing::Test {
    354  protected:
    355   FileManagerFileTasksComplexTest()
    356       : command_line_(CommandLine::NO_PROGRAM),
    357         extension_service_(NULL) {
    358     extensions::TestExtensionSystem* test_extension_system =
    359         static_cast<extensions::TestExtensionSystem*>(
    360             extensions::ExtensionSystem::Get(&test_profile_));
    361     extension_service_ = test_extension_system->CreateExtensionService(
    362         &command_line_,
    363         base::FilePath()  /* install_directory */,
    364         false  /* autoupdate_enabled*/);
    365   }
    366 
    367   content::TestBrowserThreadBundle thread_bundle_;
    368   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
    369   chromeos::ScopedTestCrosSettings test_cros_settings_;
    370   chromeos::ScopedTestUserManager test_user_manager_;
    371   TestingProfile test_profile_;
    372   CommandLine command_line_;
    373   ExtensionService* extension_service_;  // Owned by test_profile_;
    374 };
    375 
    376 // The basic logic is similar to a test case for FindDriveAppTasks above.
    377 TEST_F(FileManagerFileTasksComplexTest, FindFileHandlerTasks) {
    378   // Random IDs generated by
    379   // % ruby -le 'print (0...32).to_a.map{(?a + rand(16)).chr}.join'
    380   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
    381   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
    382 
    383   // Foo.app can handle "text/plain" and "text/html".
    384   extensions::ExtensionBuilder foo_app;
    385   foo_app.SetManifest(extensions::DictionaryBuilder()
    386                       .Set("name", "Foo")
    387                       .Set("version", "1.0.0")
    388                       .Set("manifest_version", 2)
    389                       .Set("app",
    390                            extensions::DictionaryBuilder()
    391                            .Set("background",
    392                                 extensions::DictionaryBuilder()
    393                                 .Set("scripts",
    394                                      extensions::ListBuilder()
    395                                      .Append("background.js"))))
    396                       .Set("file_handlers",
    397                            extensions::DictionaryBuilder()
    398                            .Set("text",
    399                                 extensions::DictionaryBuilder()
    400                                 .Set("title", "Text")
    401                                 .Set("types",
    402                                      extensions::ListBuilder()
    403                                      .Append("text/plain")
    404                                      .Append("text/html")))));
    405   foo_app.SetID(kFooId);
    406   extension_service_->AddExtension(foo_app.Build().get());
    407 
    408   // Bar.app can only handle "text/plain".
    409   extensions::ExtensionBuilder bar_app;
    410   bar_app.SetManifest(extensions::DictionaryBuilder()
    411                       .Set("name", "Bar")
    412                       .Set("version", "1.0.0")
    413                       .Set("manifest_version", 2)
    414                       .Set("app",
    415                            extensions::DictionaryBuilder()
    416                            .Set("background",
    417                                 extensions::DictionaryBuilder()
    418                                 .Set("scripts",
    419                                      extensions::ListBuilder()
    420                                      .Append("background.js"))))
    421                       .Set("file_handlers",
    422                            extensions::DictionaryBuilder()
    423                            .Set("text",
    424                                 extensions::DictionaryBuilder()
    425                                 .Set("title", "Text")
    426                                 .Set("types",
    427                                      extensions::ListBuilder()
    428                                      .Append("text/plain")))));
    429   bar_app.SetID(kBarId);
    430   extension_service_->AddExtension(bar_app.Build().get());
    431 
    432   // Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
    433   PathAndMimeTypeSet path_mime_set;
    434   path_mime_set.insert(
    435       std::make_pair(
    436           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
    437               "foo.txt"),
    438           "text/plain"));
    439 
    440   std::vector<FullTaskDescriptor> tasks;
    441   FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
    442   ASSERT_EQ(2U, tasks.size());
    443   // Sort the app IDs, as the order is not guaranteed.
    444   std::vector<std::string> app_ids;
    445   app_ids.push_back(tasks[0].task_descriptor().app_id);
    446   app_ids.push_back(tasks[1].task_descriptor().app_id);
    447   std::sort(app_ids.begin(), app_ids.end());
    448   // Confirm that both Foo.app and Bar.app are found.
    449   EXPECT_EQ(kFooId, app_ids[0]);
    450   EXPECT_EQ(kBarId, app_ids[1]);
    451 
    452   // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
    453   // found.
    454   path_mime_set.clear();
    455   path_mime_set.insert(
    456       std::make_pair(
    457           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
    458               "foo.txt"),
    459           "text/plain"));
    460   path_mime_set.insert(
    461       std::make_pair(
    462           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
    463               "foo.html"),
    464           "text/html"));
    465   tasks.clear();
    466   FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
    467   ASSERT_EQ(1U, tasks.size());
    468   // Confirm that only Foo.app is found.
    469   EXPECT_EQ(kFooId, tasks[0].task_descriptor().app_id);
    470 
    471   // Add an "image/png" file. No tasks should be found.
    472   path_mime_set.insert(
    473       std::make_pair(base::FilePath::FromUTF8Unsafe("foo.png"),
    474                      "image/png"));
    475   tasks.clear();
    476   FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
    477   // Confirm no tasks are found.
    478   ASSERT_TRUE(tasks.empty());
    479 }
    480 
    481 // The basic logic is similar to a test case for FindDriveAppTasks above.
    482 TEST_F(FileManagerFileTasksComplexTest, FindFileBrowserHandlerTasks) {
    483   // Copied from FindFileHandlerTasks test above.
    484   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
    485   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
    486 
    487   // Foo.app can handle ".txt" and ".html".
    488   // This one is an extension, and has "file_browser_handlers"
    489   extensions::ExtensionBuilder foo_app;
    490   foo_app.SetManifest(extensions::DictionaryBuilder()
    491                       .Set("name", "Foo")
    492                       .Set("version", "1.0.0")
    493                       .Set("manifest_version", 2)
    494                       .Set("file_browser_handlers",
    495                            extensions::ListBuilder()
    496                            .Append(extensions::DictionaryBuilder()
    497                                    .Set("id", "open")
    498                                    .Set("default_title", "open")
    499                                    .Set("file_filters",
    500                                         extensions::ListBuilder()
    501                                         .Append("filesystem:*.txt")
    502                                         .Append("filesystem:*.html")))));
    503   foo_app.SetID(kFooId);
    504   extension_service_->AddExtension(foo_app.Build().get());
    505 
    506   // Bar.app can only handle ".txt".
    507   extensions::ExtensionBuilder bar_app;
    508   bar_app.SetManifest(extensions::DictionaryBuilder()
    509                       .Set("name", "Bar")
    510                       .Set("version", "1.0.0")
    511                       .Set("manifest_version", 2)
    512                       .Set("file_browser_handlers",
    513                            extensions::ListBuilder()
    514                            .Append(extensions::DictionaryBuilder()
    515                                    .Set("id", "open")
    516                                    .Set("default_title", "open")
    517                                    .Set("file_filters",
    518                                         extensions::ListBuilder()
    519                                         .Append("filesystem:*.txt")))));
    520   bar_app.SetID(kBarId);
    521   extension_service_->AddExtension(bar_app.Build().get());
    522 
    523   // Find apps for a ".txt" file. Foo.app and Bar.app should be found.
    524   std::vector<GURL> file_urls;
    525   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
    526 
    527   std::vector<FullTaskDescriptor> tasks;
    528   FindFileBrowserHandlerTasks(&test_profile_, file_urls, &tasks);
    529   ASSERT_EQ(2U, tasks.size());
    530   // Sort the app IDs, as the order is not guaranteed.
    531   std::vector<std::string> app_ids;
    532   app_ids.push_back(tasks[0].task_descriptor().app_id);
    533   app_ids.push_back(tasks[1].task_descriptor().app_id);
    534   std::sort(app_ids.begin(), app_ids.end());
    535   // Confirm that both Foo.app and Bar.app are found.
    536   EXPECT_EQ(kFooId, app_ids[0]);
    537   EXPECT_EQ(kBarId, app_ids[1]);
    538 
    539   // Find apps for ".txt" and ".html" files. Only Foo.app should be found.
    540   file_urls.clear();
    541   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
    542   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.html"));
    543   tasks.clear();
    544   FindFileBrowserHandlerTasks(&test_profile_, file_urls, &tasks);
    545   ASSERT_EQ(1U, tasks.size());
    546   // Confirm that only Foo.app is found.
    547   EXPECT_EQ(kFooId, tasks[0].task_descriptor().app_id);
    548 
    549   // Add an ".png" file. No tasks should be found.
    550   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.png"));
    551   tasks.clear();
    552   FindFileBrowserHandlerTasks(&test_profile_, file_urls, &tasks);
    553   // Confirm no tasks are found.
    554   ASSERT_TRUE(tasks.empty());
    555 }
    556 
    557 // Test that all kinds of apps (file handler, file browser handler, and Drive
    558 // app) are returned.
    559 TEST_F(FileManagerFileTasksComplexTest, FindAllTypesOfTasks) {
    560   // kFooId and kBarId copied from FindFileHandlerTasks test above.
    561   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
    562   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
    563   const char kBazId[] = "plifkpkakemokpflgbnnigcoldgcbdmc";
    564 
    565   // Foo.app can handle "text/plain".
    566   // This is a packaged app (file handler).
    567   extensions::ExtensionBuilder foo_app;
    568   foo_app.SetManifest(extensions::DictionaryBuilder()
    569                       .Set("name", "Foo")
    570                       .Set("version", "1.0.0")
    571                       .Set("manifest_version", 2)
    572                       .Set("app",
    573                            extensions::DictionaryBuilder()
    574                            .Set("background",
    575                                 extensions::DictionaryBuilder()
    576                                 .Set("scripts",
    577                                      extensions::ListBuilder()
    578                                      .Append("background.js"))))
    579                       .Set("file_handlers",
    580                            extensions::DictionaryBuilder()
    581                            .Set("text",
    582                                 extensions::DictionaryBuilder()
    583                                 .Set("title", "Text")
    584                                 .Set("types",
    585                                      extensions::ListBuilder()
    586                                      .Append("text/plain")))));
    587   foo_app.SetID(kFooId);
    588   extension_service_->AddExtension(foo_app.Build().get());
    589 
    590   // Bar.app can only handle ".txt".
    591   // This is an extension (file browser handler).
    592   extensions::ExtensionBuilder bar_app;
    593   bar_app.SetManifest(extensions::DictionaryBuilder()
    594                       .Set("name", "Bar")
    595                       .Set("version", "1.0.0")
    596                       .Set("manifest_version", 2)
    597                       .Set("file_browser_handlers",
    598                            extensions::ListBuilder()
    599                            .Append(extensions::DictionaryBuilder()
    600                                    .Set("id", "open")
    601                                    .Set("default_title", "open")
    602                                    .Set("file_filters",
    603                                         extensions::ListBuilder()
    604                                         .Append("filesystem:*.txt")))));
    605   bar_app.SetID(kBarId);
    606   extension_service_->AddExtension(bar_app.Build().get());
    607 
    608   // Baz.app can handle "text/plain".
    609   // This is a Drive app.
    610   scoped_ptr<google_apis::AppResource> baz_app(new google_apis::AppResource);
    611   baz_app->set_product_id("baz_app_id");
    612   baz_app->set_application_id(kBazId);
    613   baz_app->set_name("Baz");
    614   baz_app->set_object_type("baz_object_type");
    615   ScopedVector<std::string> baz_mime_types;
    616   baz_mime_types.push_back(new std::string("text/plain"));
    617   baz_app->set_primary_mimetypes(baz_mime_types.Pass());
    618   // Set up DriveAppRegistry.
    619   ScopedVector<google_apis::AppResource> app_resources;
    620   app_resources.push_back(baz_app.release());
    621   google_apis::AppList app_list;
    622   app_list.set_items(app_resources.Pass());
    623   drive::DriveAppRegistry drive_app_registry(NULL);
    624   drive_app_registry.UpdateFromAppList(app_list);
    625 
    626   // Find apps for "foo.txt". All apps should be found.
    627   PathAndMimeTypeSet path_mime_set;
    628   std::vector<GURL> file_urls;
    629   path_mime_set.insert(
    630       std::make_pair(
    631           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
    632               "foo.txt"),
    633           "text/plain"));
    634   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
    635 
    636   std::vector<FullTaskDescriptor> tasks;
    637   FindAllTypesOfTasks(&test_profile_,
    638                       &drive_app_registry,
    639                       path_mime_set,
    640                       file_urls,
    641                       &tasks);
    642   ASSERT_EQ(3U, tasks.size());
    643 
    644   // Sort the app IDs, as the order is not guaranteed.
    645   std::vector<std::string> app_ids;
    646   app_ids.push_back(tasks[0].task_descriptor().app_id);
    647   app_ids.push_back(tasks[1].task_descriptor().app_id);
    648   app_ids.push_back(tasks[2].task_descriptor().app_id);
    649   std::sort(app_ids.begin(), app_ids.end());
    650   // Confirm that all apps are found.
    651   EXPECT_EQ(kFooId, app_ids[0]);
    652   EXPECT_EQ(kBarId, app_ids[1]);
    653   EXPECT_EQ(kBazId, app_ids[2]);
    654 }
    655 
    656 TEST_F(FileManagerFileTasksComplexTest, FindAllTypesOfTasks_GoogleDocument) {
    657   // kFooId and kBarId copied from FindFileHandlerTasks test above.
    658   const char kFooId[] = "hhgbjpmdppecanaaogonaigmmifgpaph";
    659   const char kBarId[] = "odlhccgofgkadkkhcmhgnhgahonahoca";
    660 
    661   // Foo.app can handle ".gdoc" files.
    662   scoped_ptr<google_apis::AppResource> foo_app(new google_apis::AppResource);
    663   foo_app->set_product_id("foo_app");
    664   foo_app->set_application_id(kFooId);
    665   foo_app->set_name("Foo");
    666   foo_app->set_object_type("foo_object_type");
    667   ScopedVector<std::string> foo_extensions;
    668   foo_extensions.push_back(new std::string("gdoc"));  // Not ".gdoc"
    669   foo_app->set_primary_file_extensions(foo_extensions.Pass());
    670 
    671   // Prepare DriveAppRegistry from Foo.app.
    672   ScopedVector<google_apis::AppResource> app_resources;
    673   app_resources.push_back(foo_app.release());
    674   google_apis::AppList app_list;
    675   app_list.set_items(app_resources.Pass());
    676   drive::DriveAppRegistry drive_app_registry(NULL);
    677   drive_app_registry.UpdateFromAppList(app_list);
    678 
    679   // Bar.app can handle ".gdoc" files.
    680   // This is an extension (file browser handler).
    681   extensions::ExtensionBuilder bar_app;
    682   bar_app.SetManifest(extensions::DictionaryBuilder()
    683                       .Set("name", "Bar")
    684                       .Set("version", "1.0.0")
    685                       .Set("manifest_version", 2)
    686                       .Set("file_browser_handlers",
    687                            extensions::ListBuilder()
    688                            .Append(extensions::DictionaryBuilder()
    689                                    .Set("id", "open")
    690                                    .Set("default_title", "open")
    691                                    .Set("file_filters",
    692                                         extensions::ListBuilder()
    693                                         .Append("filesystem:*.gdoc")))));
    694   bar_app.SetID(kBarId);
    695   extension_service_->AddExtension(bar_app.Build().get());
    696 
    697   // Files.app can handle ".gdoc" files.
    698   // The ID "kFileManagerAppId" used here is precisely the one that identifies
    699   // the Chrome OS Files.app application.
    700   extensions::ExtensionBuilder files_app;
    701   files_app.SetManifest(extensions::DictionaryBuilder()
    702                        .Set("name", "Files")
    703                        .Set("version", "1.0.0")
    704                        .Set("manifest_version", 2)
    705                        .Set("file_browser_handlers",
    706                             extensions::ListBuilder()
    707                             .Append(extensions::DictionaryBuilder()
    708                                     .Set("id", "open")
    709                                     .Set("default_title", "open")
    710                                     .Set("file_filters",
    711                                          extensions::ListBuilder()
    712                                          .Append("filesystem:*.gdoc")))));
    713   files_app.SetID(kFileManagerAppId);
    714   extension_service_->AddExtension(files_app.Build().get());
    715 
    716   // Find apps for a ".gdoc file". Only the built-in handler of Files.apps
    717   // should be found.
    718   PathAndMimeTypeSet path_mime_set;
    719   std::vector<GURL> file_urls;
    720   path_mime_set.insert(
    721       std::make_pair(
    722           drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
    723               "foo.gdoc"),
    724           "application/vnd.google-apps.document"));
    725   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.gdoc"));
    726 
    727   std::vector<FullTaskDescriptor> tasks;
    728   FindAllTypesOfTasks(&test_profile_,
    729                       &drive_app_registry,
    730                       path_mime_set,
    731                       file_urls,
    732                       &tasks);
    733   ASSERT_EQ(1U, tasks.size());
    734   EXPECT_EQ(kFileManagerAppId, tasks[0].task_descriptor().app_id);
    735 }
    736 
    737 }  // namespace file_tasks
    738 }  // namespace file_manager.
    739