Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / extensions / api / file_system / file_system_api_unittest.cc
blob9a01de9b0bdbc5837a38932f9cb7051a2d3a7d5a
1 // Copyright (c) 2012 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/extensions/api/file_system/file_system_api.h"
7 #include <vector>
9 #include "base/files/file_path.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/shell_dialogs/select_file_dialog.h"
17 #if defined(OS_CHROMEOS)
18 #include "base/memory/ref_counted.h"
19 #include "base/memory/weak_ptr.h"
20 #include "base/prefs/testing_pref_service.h"
21 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
22 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
23 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
24 #include "chrome/test/base/testing_browser_process.h"
25 #include "content/public/test/test_browser_thread_bundle.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/extension_builder.h"
28 #include "extensions/common/manifest.h"
29 #include "extensions/common/test_util.h"
30 #include "extensions/common/value_builder.h"
31 #endif
33 using extensions::FileSystemChooseEntryFunction;
34 using extensions::api::file_system::AcceptOption;
36 #if defined(OS_CHROMEOS)
37 using extensions::file_system_api::ConsentProvider;
38 using file_manager::Volume;
39 #endif
41 namespace extensions {
42 namespace {
44 void CheckExtensions(const std::vector<base::FilePath::StringType>& expected,
45 const std::vector<base::FilePath::StringType>& actual) {
46 EXPECT_EQ(expected.size(), actual.size());
47 if (expected.size() != actual.size())
48 return;
50 for (size_t i = 0; i < expected.size(); ++i) {
51 EXPECT_EQ(expected[i], actual[i]);
55 AcceptOption* BuildAcceptOption(const std::string& description,
56 const std::string& mime_types,
57 const std::string& extensions) {
58 AcceptOption* option = new AcceptOption();
60 if (!description.empty())
61 option->description.reset(new std::string(description));
63 if (!mime_types.empty()) {
64 option->mime_types.reset(new std::vector<std::string>());
65 base::SplitString(mime_types, ',', option->mime_types.get());
68 if (!extensions.empty()) {
69 option->extensions.reset(new std::vector<std::string>());
70 base::SplitString(extensions, ',', option->extensions.get());
73 return option;
76 #if defined(OS_WIN)
77 #define ToStringType base::UTF8ToWide
78 #else
79 #define ToStringType
80 #endif
82 #if defined(OS_CHROMEOS)
83 class TestingConsentProviderDelegate
84 : public ConsentProvider::DelegateInterface {
85 public:
86 TestingConsentProviderDelegate()
87 : show_dialog_counter_(0),
88 show_notification_counter_(0),
89 dialog_button_(ui::DIALOG_BUTTON_NONE),
90 is_auto_launched_(false) {}
92 ~TestingConsentProviderDelegate() {}
94 // Sets a fake dialog response.
95 void SetDialogButton(ui::DialogButton button) { dialog_button_ = button; }
97 // Sets a fake result of detection the auto launch kiosk mode.
98 void SetIsAutoLaunched(bool is_auto_launched) {
99 is_auto_launched_ = is_auto_launched;
102 // Sets a whitelisted components list with a single id.
103 void SetComponentWhitelist(const std::string& extension_id) {
104 whitelisted_component_id_ = extension_id;
107 int show_dialog_counter() const { return show_dialog_counter_; }
108 int show_notification_counter() const { return show_notification_counter_; }
110 private:
111 // ConsentProvider::DelegateInterface overrides:
112 void ShowDialog(
113 const extensions::Extension& extension,
114 const base::WeakPtr<Volume>& volume,
115 bool writable,
116 const ConsentProvider::ShowDialogCallback& callback) override {
117 ++show_dialog_counter_;
118 callback.Run(dialog_button_);
121 void ShowNotification(const extensions::Extension& extension,
122 const base::WeakPtr<Volume>& volume,
123 bool writable) override {
124 ++show_notification_counter_;
127 bool IsAutoLaunched(const extensions::Extension& extension) override {
128 return is_auto_launched_;
131 bool IsWhitelistedComponent(const extensions::Extension& extension) override {
132 return whitelisted_component_id_.compare(extension.id()) == 0;
135 int show_dialog_counter_;
136 int show_notification_counter_;
137 ui::DialogButton dialog_button_;
138 bool is_auto_launched_;
139 std::string whitelisted_component_id_;
141 DISALLOW_COPY_AND_ASSIGN(TestingConsentProviderDelegate);
144 // Rewrites result of a consent request from |result| to |log|.
145 void OnConsentReceived(ConsentProvider::Consent* log,
146 const ConsentProvider::Consent result) {
147 *log = result;
149 #endif
151 } // namespace
153 #if defined(OS_CHROMEOS)
154 class FileSystemApiConsentProviderTest : public testing::Test {
155 public:
156 FileSystemApiConsentProviderTest() {}
158 void SetUp() override {
159 testing_pref_service_.reset(new TestingPrefServiceSimple);
160 TestingBrowserProcess::GetGlobal()->SetLocalState(
161 testing_pref_service_.get());
162 user_manager_ = new chromeos::FakeChromeUserManager;
163 scoped_user_manager_enabler_.reset(
164 new chromeos::ScopedUserManagerEnabler(user_manager_));
167 void TearDown() override {
168 scoped_user_manager_enabler_.reset();
169 user_manager_ = nullptr;
170 testing_pref_service_.reset();
171 TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
174 protected:
175 base::WeakPtr<Volume> volume_;
176 scoped_ptr<TestingPrefServiceSimple> testing_pref_service_;
177 chromeos::FakeChromeUserManager*
178 user_manager_; // Owned by the scope enabler.
179 scoped_ptr<chromeos::ScopedUserManagerEnabler> scoped_user_manager_enabler_;
180 content::TestBrowserThreadBundle thread_bundle_;
182 #endif
184 TEST(FileSystemApiUnitTest, FileSystemChooseEntryFunctionFileTypeInfoTest) {
185 // AcceptsAllTypes is ignored when no other extensions are available.
186 ui::SelectFileDialog::FileTypeInfo file_type_info;
187 bool acceptsAllTypes = false;
188 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info,
189 base::FilePath::StringType(), NULL, &acceptsAllTypes);
190 EXPECT_TRUE(file_type_info.include_all_files);
191 EXPECT_TRUE(file_type_info.extensions.empty());
193 // Test grouping of multiple types.
194 file_type_info = ui::SelectFileDialog::FileTypeInfo();
195 std::vector<linked_ptr<AcceptOption> > options;
196 options.push_back(linked_ptr<AcceptOption>(BuildAcceptOption(
197 std::string(), "application/x-chrome-extension", "jso")));
198 acceptsAllTypes = false;
199 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info,
200 base::FilePath::StringType(), &options, &acceptsAllTypes);
201 EXPECT_FALSE(file_type_info.include_all_files);
202 ASSERT_EQ(file_type_info.extensions.size(), (size_t) 1);
203 EXPECT_TRUE(file_type_info.extension_description_overrides[0].empty()) <<
204 "No override must be specified for boring accept types";
205 // Note here (and below) that the expectedTypes are sorted, because we use a
206 // set internally to generate the output: thus, the output is sorted.
207 std::vector<base::FilePath::StringType> expectedTypes;
208 expectedTypes.push_back(ToStringType("crx"));
209 expectedTypes.push_back(ToStringType("jso"));
210 CheckExtensions(expectedTypes, file_type_info.extensions[0]);
212 // Test that not satisfying the extension will force all types.
213 file_type_info = ui::SelectFileDialog::FileTypeInfo();
214 options.clear();
215 options.push_back(linked_ptr<AcceptOption>(BuildAcceptOption(
216 std::string(), std::string(), "unrelated")));
217 acceptsAllTypes = false;
218 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info,
219 ToStringType(".jso"), &options, &acceptsAllTypes);
220 EXPECT_TRUE(file_type_info.include_all_files);
222 // Test multiple list entries, all containing their own types.
223 file_type_info = ui::SelectFileDialog::FileTypeInfo();
224 options.clear();
225 options.push_back(linked_ptr<AcceptOption>(
226 BuildAcceptOption(std::string(), std::string(), "jso,js")));
227 options.push_back(linked_ptr<AcceptOption>(
228 BuildAcceptOption(std::string(), std::string(), "cpp,cc")));
229 acceptsAllTypes = false;
230 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info,
231 base::FilePath::StringType(), &options, &acceptsAllTypes);
232 ASSERT_EQ(file_type_info.extensions.size(), options.size());
234 expectedTypes.clear();
235 expectedTypes.push_back(ToStringType("js"));
236 expectedTypes.push_back(ToStringType("jso"));
237 CheckExtensions(expectedTypes, file_type_info.extensions[0]);
239 expectedTypes.clear();
240 expectedTypes.push_back(ToStringType("cc"));
241 expectedTypes.push_back(ToStringType("cpp"));
242 CheckExtensions(expectedTypes, file_type_info.extensions[1]);
244 // Test accept type that causes description override.
245 file_type_info = ui::SelectFileDialog::FileTypeInfo();
246 options.clear();
247 options.push_back(linked_ptr<AcceptOption>(
248 BuildAcceptOption(std::string(), "image/*", "html")));
249 acceptsAllTypes = false;
250 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info,
251 base::FilePath::StringType(), &options, &acceptsAllTypes);
252 ASSERT_EQ(file_type_info.extension_description_overrides.size(), (size_t) 1);
253 EXPECT_FALSE(file_type_info.extension_description_overrides[0].empty()) <<
254 "Accept type \"image/*\" must generate description override";
256 // Test multiple accept types that cause description override causes us to
257 // still present the default.
258 file_type_info = ui::SelectFileDialog::FileTypeInfo();
259 options.clear();
260 options.push_back(linked_ptr<AcceptOption>(BuildAcceptOption(
261 std::string(), "image/*,audio/*,video/*", std::string())));
262 acceptsAllTypes = false;
263 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info,
264 base::FilePath::StringType(), &options, &acceptsAllTypes);
265 ASSERT_EQ(file_type_info.extension_description_overrides.size(), (size_t) 1);
266 EXPECT_TRUE(file_type_info.extension_description_overrides[0].empty());
268 // Test explicit description override.
269 file_type_info = ui::SelectFileDialog::FileTypeInfo();
270 options.clear();
271 options.push_back(linked_ptr<AcceptOption>(
272 BuildAcceptOption("File Types 101", "image/jpeg", std::string())));
273 acceptsAllTypes = false;
274 FileSystemChooseEntryFunction::BuildFileTypeInfo(&file_type_info,
275 base::FilePath::StringType(), &options, &acceptsAllTypes);
276 EXPECT_EQ(file_type_info.extension_description_overrides[0],
277 base::UTF8ToUTF16("File Types 101"));
280 TEST(FileSystemApiUnitTest, FileSystemChooseEntryFunctionSuggestionTest) {
281 std::string opt_name;
282 base::FilePath suggested_name;
283 base::FilePath::StringType suggested_extension;
285 opt_name = std::string("normal_path.txt");
286 FileSystemChooseEntryFunction::BuildSuggestion(&opt_name, &suggested_name,
287 &suggested_extension);
288 EXPECT_FALSE(suggested_name.IsAbsolute());
289 EXPECT_EQ(suggested_name.MaybeAsASCII(), "normal_path.txt");
290 EXPECT_EQ(suggested_extension, ToStringType("txt"));
292 // We should provide just the basename, i.e., "path".
293 opt_name = std::string("/a/bad/path");
294 FileSystemChooseEntryFunction::BuildSuggestion(&opt_name, &suggested_name,
295 &suggested_extension);
296 EXPECT_FALSE(suggested_name.IsAbsolute());
297 EXPECT_EQ(suggested_name.MaybeAsASCII(), "path");
298 EXPECT_TRUE(suggested_extension.empty());
300 #if !defined(OS_WIN)
301 // TODO(thorogood): Fix this test on Windows.
302 // Filter out absolute paths with no basename.
303 opt_name = std::string("/");
304 FileSystemChooseEntryFunction::BuildSuggestion(&opt_name, &suggested_name,
305 &suggested_extension);
306 EXPECT_FALSE(suggested_name.IsAbsolute());
307 EXPECT_TRUE(suggested_name.MaybeAsASCII().empty());
308 EXPECT_TRUE(suggested_extension.empty());
309 #endif
312 #if defined(OS_CHROMEOS)
313 TEST_F(FileSystemApiConsentProviderTest, ForNonKioskApps) {
314 // Component apps are not granted unless they are whitelisted.
316 scoped_refptr<Extension> component_extension(
317 test_util::BuildApp(ExtensionBuilder().SetLocation(Manifest::COMPONENT))
318 .Build());
319 TestingConsentProviderDelegate delegate;
320 ConsentProvider provider(&delegate);
321 EXPECT_FALSE(provider.IsGrantable(*component_extension));
324 // Whitelitsed component apps are instantly granted access without asking
325 // user.
327 scoped_refptr<Extension> whitelisted_component_extension(
328 test_util::BuildApp(ExtensionBuilder().SetLocation(Manifest::COMPONENT))
329 .Build());
330 TestingConsentProviderDelegate delegate;
331 delegate.SetComponentWhitelist(whitelisted_component_extension->id());
332 ConsentProvider provider(&delegate);
333 EXPECT_TRUE(provider.IsGrantable(*whitelisted_component_extension));
335 ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
336 provider.RequestConsent(*whitelisted_component_extension.get(), volume_,
337 true /* writable */,
338 base::Bind(&OnConsentReceived, &result));
339 base::RunLoop().RunUntilIdle();
341 EXPECT_EQ(0, delegate.show_dialog_counter());
342 EXPECT_EQ(0, delegate.show_notification_counter());
343 EXPECT_EQ(ConsentProvider::CONSENT_GRANTED, result);
346 // Non-component apps in non-kiosk mode will be rejected instantly, without
347 // asking for user consent.
349 scoped_refptr<Extension> non_component_extension(
350 test_util::CreateEmptyExtension());
351 TestingConsentProviderDelegate delegate;
352 ConsentProvider provider(&delegate);
353 EXPECT_FALSE(provider.IsGrantable(*non_component_extension));
357 TEST_F(FileSystemApiConsentProviderTest, ForKioskApps) {
358 // Non-component apps in auto-launch kiosk mode will be granted access
359 // instantly without asking for user consent, but with a notification.
361 scoped_refptr<Extension> auto_launch_kiosk_app(
362 test_util::BuildApp(ExtensionBuilder().Pass())
363 .MergeManifest(DictionaryBuilder()
364 .SetBoolean("kiosk_enabled", true)
365 .SetBoolean("kiosk_only", true))
366 .Build());
367 user_manager_->AddKioskAppUser(auto_launch_kiosk_app->id());
368 user_manager_->LoginUser(auto_launch_kiosk_app->id());
370 TestingConsentProviderDelegate delegate;
371 delegate.SetIsAutoLaunched(true);
372 ConsentProvider provider(&delegate);
373 EXPECT_TRUE(provider.IsGrantable(*auto_launch_kiosk_app));
375 ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
376 provider.RequestConsent(*auto_launch_kiosk_app.get(), volume_,
377 true /* writable */,
378 base::Bind(&OnConsentReceived, &result));
379 base::RunLoop().RunUntilIdle();
381 EXPECT_EQ(0, delegate.show_dialog_counter());
382 EXPECT_EQ(1, delegate.show_notification_counter());
383 EXPECT_EQ(ConsentProvider::CONSENT_GRANTED, result);
386 // Non-component apps in manual-launch kiosk mode will be granted access after
387 // receiving approval from the user.
388 scoped_refptr<Extension> manual_launch_kiosk_app(
389 test_util::BuildApp(ExtensionBuilder().Pass())
390 .MergeManifest(DictionaryBuilder()
391 .SetBoolean("kiosk_enabled", true)
392 .SetBoolean("kiosk_only", true))
393 .Build());
394 user_manager_->KioskAppLoggedIn(manual_launch_kiosk_app->id());
396 TestingConsentProviderDelegate delegate;
397 delegate.SetDialogButton(ui::DIALOG_BUTTON_OK);
398 ConsentProvider provider(&delegate);
399 EXPECT_TRUE(provider.IsGrantable(*manual_launch_kiosk_app));
401 ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
402 provider.RequestConsent(*manual_launch_kiosk_app.get(), volume_,
403 true /* writable */,
404 base::Bind(&OnConsentReceived, &result));
405 base::RunLoop().RunUntilIdle();
407 EXPECT_EQ(1, delegate.show_dialog_counter());
408 EXPECT_EQ(0, delegate.show_notification_counter());
409 EXPECT_EQ(ConsentProvider::CONSENT_GRANTED, result);
412 // Non-component apps in manual-launch kiosk mode will be rejected access
413 // after rejecting by a user.
415 TestingConsentProviderDelegate delegate;
416 ConsentProvider provider(&delegate);
417 delegate.SetDialogButton(ui::DIALOG_BUTTON_CANCEL);
418 EXPECT_TRUE(provider.IsGrantable(*manual_launch_kiosk_app));
420 ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
421 provider.RequestConsent(*manual_launch_kiosk_app.get(), volume_,
422 true /* writable */,
423 base::Bind(&OnConsentReceived, &result));
424 base::RunLoop().RunUntilIdle();
426 EXPECT_EQ(1, delegate.show_dialog_counter());
427 EXPECT_EQ(0, delegate.show_notification_counter());
428 EXPECT_EQ(ConsentProvider::CONSENT_REJECTED, result);
431 #endif
433 } // namespace extensions