1 // Copyright 2014 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/ui/views/apps/app_info_dialog/app_info_permissions_panel.h" 6 7 #include "apps/saved_files_service.h" 8 #include "base/callback.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/extensions/extension_service.h" 12 #include "chrome/browser/extensions/test_extension_system.h" 13 #include "chrome/grit/generated_resources.h" 14 #include "chrome/test/base/testing_profile.h" 15 #include "content/public/test/test_browser_thread_bundle.h" 16 #include "extensions/common/extension_builder.h" 17 #include "extensions/common/manifest.h" 18 #include "extensions/common/permissions/permission_set.h" 19 #include "extensions/common/permissions/permissions_data.h" 20 #include "grit/extensions_strings.h" 21 #include "testing/gmock/include/gmock/gmock-matchers.h" 22 #include "testing/gtest/include/gtest/gtest.h" 23 #include "ui/base/l10n/l10n_util.h" 24 25 namespace { 26 27 const char kTestExtensionId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 28 29 } // namespace 30 31 using base::FilePath; 32 using testing::Contains; 33 using testing::Eq; 34 35 class AppInfoPermissionsPanelTest : public testing::Test { 36 protected: 37 AppInfoPermissionsPanelTest() {} 38 39 scoped_ptr<base::DictionaryValue> ValidAppManifest() { 40 return extensions::DictionaryBuilder() 41 .Set("name", "Test App Name") 42 .Set("version", "2.0") 43 .Set("manifest_version", 2) 44 .Set("app", 45 extensions::DictionaryBuilder().Set( 46 "background", 47 extensions::DictionaryBuilder().Set( 48 "scripts", 49 extensions::ListBuilder().Append("background.js")))) 50 .Build(); 51 } 52 53 TestingProfile profile_; 54 55 // We need the UI thread in order to construct UI elements in the view. 56 content::TestBrowserThreadBundle thread_bundle_; 57 }; 58 59 // Tests that an app with no permissions is treated correctly. 60 TEST_F(AppInfoPermissionsPanelTest, NoPermissionsObtainedCorrectly) { 61 scoped_refptr<const extensions::Extension> app = 62 extensions::ExtensionBuilder() 63 .SetManifest(ValidAppManifest()) 64 .SetID(kTestExtensionId) 65 .Build(); 66 AppInfoPermissionsPanel panel(&profile_, app.get()); 67 68 EXPECT_TRUE(panel.GetActivePermissionMessages().empty()); 69 EXPECT_TRUE(panel.GetRetainedFilePaths().empty()); 70 } 71 72 // Tests that an app's required permissions are detected and converted to 73 // messages correctly. 74 TEST_F(AppInfoPermissionsPanelTest, RequiredPermissionsObtainedCorrectly) { 75 scoped_refptr<const extensions::Extension> app = 76 extensions::ExtensionBuilder() 77 .SetManifest(ValidAppManifest()) 78 .MergeManifest(extensions::DictionaryBuilder().Set( 79 "permissions", 80 extensions::ListBuilder() 81 .Append("desktopCapture") // A valid permission with a 82 // message 83 .Append("bad_perm") // An invalid permission 84 .Append("notifications") // An valid permission with 85 // no message 86 .Append("serial"))) // Another valid permission with 87 // a message 88 .SetID(kTestExtensionId) 89 .Build(); 90 AppInfoPermissionsPanel panel(&profile_, app.get()); 91 92 const std::vector<base::string16> permission_messages = 93 panel.GetActivePermissionMessages(); 94 ASSERT_EQ(2U, permission_messages.size()); 95 EXPECT_EQ( 96 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_DESKTOP_CAPTURE), 97 base::UTF16ToUTF8(permission_messages[0])); 98 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_SERIAL), 99 base::UTF16ToUTF8(permission_messages[1])); 100 } 101 102 // Tests that an app's optional permissions are detected and converted to 103 // messages correctly. 104 TEST_F(AppInfoPermissionsPanelTest, OptionalPermissionsObtainedCorrectly) { 105 scoped_refptr<const extensions::Extension> app = 106 extensions::ExtensionBuilder() 107 .SetManifest(ValidAppManifest()) 108 .MergeManifest(extensions::DictionaryBuilder().Set( 109 "optional_permissions", 110 extensions::ListBuilder() 111 .Append("clipboardRead") // A valid permission with a 112 // message 113 .Append("bad_perm") // An invalid permission 114 .Append("idle") // A valid permission with 115 // no message 116 .Append("serial"))) // Another valid permission with 117 // a message 118 .SetID(kTestExtensionId) 119 .Build(); 120 AppInfoPermissionsPanel panel(&profile_, app.get()); 121 122 // Optional permissions don't appear until they are 'activated' at runtime. 123 // TODO(sashab): Activate the optional permissions and ensure they are 124 // successfully added to the dialog. 125 EXPECT_TRUE(panel.GetActivePermissionMessages().empty()); 126 EXPECT_TRUE(panel.GetRetainedFilePaths().empty()); 127 } 128 129 // Tests that an app's retained files are detected and converted to paths 130 // correctly. 131 TEST_F(AppInfoPermissionsPanelTest, RetainedFilePermissionsObtainedCorrectly) { 132 scoped_refptr<const extensions::Extension> app = 133 extensions::ExtensionBuilder() 134 .SetManifest(ValidAppManifest()) 135 .MergeManifest(extensions::DictionaryBuilder().Set( 136 "permissions", 137 extensions::ListBuilder().Append( 138 extensions::DictionaryBuilder().Set( 139 "fileSystem", 140 extensions::ListBuilder().Append("retainEntries"))))) 141 .SetID(kTestExtensionId) 142 .Build(); 143 AppInfoPermissionsPanel panel(&profile_, app.get()); 144 apps::SavedFilesService* files_service = 145 apps::SavedFilesService::Get(&profile_); 146 files_service->RegisterFileEntry( 147 app->id(), "file_id_1", FilePath(FILE_PATH_LITERAL("file_1.ext")), false); 148 files_service->RegisterFileEntry( 149 app->id(), "file_id_2", FilePath(FILE_PATH_LITERAL("file_2.ext")), false); 150 files_service->RegisterFileEntry( 151 app->id(), "file_id_3", FilePath(FILE_PATH_LITERAL("file_3.ext")), false); 152 153 const std::vector<base::string16> permission_messages = 154 panel.GetActivePermissionMessages(); 155 ASSERT_TRUE(permission_messages.empty()); 156 157 // Since we have no guarantees on the order of retained files, make sure the 158 // list is the expected length and all required entries are present. 159 const std::vector<base::string16> retained_file_paths = 160 panel.GetRetainedFilePaths(); 161 ASSERT_EQ(3U, retained_file_paths.size()); 162 EXPECT_THAT(retained_file_paths, 163 Contains(Eq(base::UTF8ToUTF16("file_1.ext")))); 164 EXPECT_THAT(retained_file_paths, 165 Contains(Eq(base::UTF8ToUTF16("file_2.ext")))); 166 EXPECT_THAT(retained_file_paths, 167 Contains(Eq(base::UTF8ToUTF16("file_3.ext")))); 168 } 169