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
31namespace file_manager {
32namespace file_tasks {
33namespace {
34
35// Registers the default task preferences. Used for testing
36// ChooseAndSetDefaultTask().
37void 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.
48void 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
59TEST(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
77TEST(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
95TEST(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
104TEST(FileManagerFileTasksTest, MakeDriveAppTaskId) {
105  EXPECT_EQ("app-id|drive|open-with", MakeDriveAppTaskId("app-id"));
106}
107
108TEST(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
115TEST(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
123TEST(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
131TEST(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
139TEST(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
149TEST(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
159TEST(FileManagerFileTasksTest, ParseTaskID_Invalid) {
160  TaskDescriptor task;
161  EXPECT_FALSE(ParseTaskID("invalid", &task));
162}
163
164TEST(FileManagerFileTasksTest, ParseTaskID_UnknownTaskType) {
165  TaskDescriptor task;
166  EXPECT_FALSE(ParseTaskID("app-id|unknown|action-id", &task));
167}
168
169TEST(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.
257TEST(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.
327TEST(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.
353class 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.
377TEST_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.
482TEST_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.
559TEST_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
656TEST_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