Index: chrome/browser/extensions/permission_messages_unittest.cc |
diff --git a/chrome/browser/extensions/permission_messages_unittest.cc b/chrome/browser/extensions/permission_messages_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5edd3bf514c47b4053cdf8650eadced1bc57e380 |
--- /dev/null |
+++ b/chrome/browser/extensions/permission_messages_unittest.cc |
@@ -0,0 +1,273 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/memory/scoped_ptr.h" |
+#include "chrome/browser/extensions/extension_service.h" |
+#include "chrome/browser/extensions/extension_service_test_base.h" |
+#include "chrome/browser/extensions/permissions_updater.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h" |
+#include "chrome/grit/generated_resources.h" |
+#include "components/crx_file/id_util.h" |
+#include "extensions/browser/extension_prefs.h" |
+#include "extensions/browser/extension_registry.h" |
+#include "extensions/common/extension_builder.h" |
+#include "extensions/common/manifest.h" |
+#include "extensions/common/manifest_handlers/permissions_parser.h" |
+#include "extensions/common/permissions/permissions_data.h" |
+#include "extensions/common/test_util.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "ui/base/l10n/l10n_util.h" |
+ |
+namespace extensions { |
+ |
+// Tests that ChromePermissionMessageProvider provides not only correct, but |
+// meaningful permission messages that coalesce correctly where appropriate. |
+// There are 3 types of permission messages that need to be tested: |
+// 1. The combined list of active permissions, displayed at install time (or |
+// when the app has been disabled automatically and needs to be re-enabled) |
+// 2. The split list of active permissions, displayed in the App Info dialog, |
+// where the optional permissions are individually revokable |
+// 3. The list of requested optional permissions, displayed in a prompt to the |
+// user when the app requests these during runtime |
+// Some of these tests are prefixed AntiTest_, since they demonstrate existing |
+// problematic functionality. These tests are prefixed with AntiTest_ and will |
+// be changed as the correct behaviour is implemented. TODOs in the test explain |
+// the currently problematic behaviour. |
+class PermissionMessagesUnittest : public ExtensionServiceTestBase { |
+ public: |
+ PermissionMessagesUnittest() |
+ : message_provider_(new ChromePermissionMessageProvider()) {} |
+ virtual ~PermissionMessagesUnittest() {} |
+ |
+ // Overridden from testing::Test: |
+ virtual void SetUp() OVERRIDE { |
+ ExtensionServiceTestBase::SetUp(); |
+ InitializeExtensionService(CreateDefaultInitParams()); |
+ InitializeProcessManager(); |
+ } |
+ |
+ protected: |
+ void CreateAndInstallAppWithPermissions(ListBuilder& required_permissions, |
+ ListBuilder& optional_permissions) { |
+ app_ = test_util::BuildApp(ExtensionBuilder().Pass()) |
+ .MergeManifest( |
+ DictionaryBuilder() |
+ .Set("permissions", required_permissions) |
+ .Set("optional_permissions", optional_permissions)) |
+ .SetID(crx_file::id_util::GenerateId("app")) |
+ .SetLocation(Manifest::INTERNAL) |
+ .Build(); |
+ service()->AddExtension(app_.get()); |
+ } |
+ |
+ void CreateAndInstallExtensionWithPermissions( |
+ ListBuilder& required_permissions, |
+ ListBuilder& optional_permissions) { |
+ app_ = test_util::BuildExtension(ExtensionBuilder().Pass()) |
+ .MergeManifest( |
+ DictionaryBuilder() |
+ .Set("permissions", required_permissions) |
+ .Set("optional_permissions", optional_permissions)) |
+ .SetID(crx_file::id_util::GenerateId("extension")) |
+ .SetLocation(Manifest::INTERNAL) |
+ .Build(); |
+ service()->AddExtension(app_.get()); |
+ } |
+ |
+ // Returns the permission messages that would display in the prompt that |
+ // requests all the optional permissions for the current |app_|. |
+ std::vector<base::string16> GetOptionalPermissionMessages() { |
+ scoped_refptr<const PermissionSet> granted_permissions = |
+ ExtensionPrefs::Get(profile())->GetGrantedPermissions(app_->id()); |
+ scoped_refptr<const PermissionSet> optional_permissions = |
+ PermissionsParser::GetOptionalPermissions(app_.get()); |
+ scoped_refptr<const PermissionSet> requested_permissions = |
+ PermissionSet::CreateDifference(optional_permissions.get(), |
+ granted_permissions.get()); |
+ return GetMessages(requested_permissions); |
+ } |
+ |
+ void GrantOptionalPermissions() { |
+ PermissionsUpdater perms_updater(profile()); |
+ perms_updater.AddPermissions( |
+ app_.get(), |
+ PermissionsParser::GetOptionalPermissions(app_.get()).get()); |
+ } |
+ |
+ std::vector<base::string16> active_permissions() { |
+ return GetMessages(app_->permissions_data()->active_permissions()); |
+ } |
+ |
+ std::vector<base::string16> withheld_permissions() { |
+ return GetMessages(app_->permissions_data()->withheld_permissions()); |
+ } |
+ |
+ std::vector<base::string16> granted_permissions() { |
+ return GetMessages( |
+ ExtensionPrefs::Get(profile())->GetGrantedPermissions(app_->id())); |
+ } |
+ |
+ std::vector<base::string16> required_permissions() { |
+ return GetMessages(PermissionsParser::GetRequiredPermissions(app_.get())); |
+ } |
+ |
+ std::vector<base::string16> optional_permissions() { |
+ return GetMessages(PermissionsParser::GetOptionalPermissions(app_.get())); |
+ } |
+ |
+ private: |
+ std::vector<base::string16> GetMessages( |
+ scoped_refptr<const PermissionSet> permissions) { |
+ return message_provider_->GetWarningMessages(permissions.get(), |
+ app_->GetType()); |
+ } |
+ |
+ scoped_ptr<ChromePermissionMessageProvider> message_provider_; |
+ scoped_refptr<const Extension> app_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(PermissionMessagesUnittest); |
+}; |
+ |
+// If an app has both the 'serial' and 'USB' permission, they should coalesce |
+// into a single permission message. |
+TEST_F(PermissionMessagesUnittest, RequiredPermissionMessagesCoalesce) { |
+ CreateAndInstallAppWithPermissions( |
+ ListBuilder().Append("serial").Append("usb").Pass(), |
+ ListBuilder().Pass()); |
+ |
+ ASSERT_EQ(1U, required_permissions().size()); |
+ EXPECT_EQ(l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_USB_SERIAL), |
+ required_permissions()[0]); |
+ |
+ ASSERT_EQ(0U, optional_permissions().size()); |
+} |
+ |
+// If an app has both the 'history' and 'tabs' permission, one should hide the |
+// other (the 'history' permission has superset permissions). |
+TEST_F(PermissionMessagesUnittest, HistoryHidesTabsMessage) { |
+ CreateAndInstallExtensionWithPermissions( |
+ ListBuilder().Append("tabs").Append("history").Pass(), |
+ ListBuilder().Pass()); |
+ |
+ ASSERT_EQ(1U, required_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), |
+ required_permissions()[0]); |
+ |
+ ASSERT_EQ(0U, optional_permissions().size()); |
+} |
+ |
+// If an app requests the 'history' permission, but already has the 'tabs' |
+// permission, only the new coalesced message is displayed. |
+TEST_F(PermissionMessagesUnittest, MixedPermissionMessagesCoalesceOnceGranted) { |
+ CreateAndInstallExtensionWithPermissions( |
+ ListBuilder().Append("tabs").Pass(), |
+ ListBuilder().Append("history").Pass()); |
+ |
+ ASSERT_EQ(1U, required_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), |
+ required_permissions()[0]); |
+ |
+ ASSERT_EQ(1U, optional_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), |
+ optional_permissions()[0]); |
+ |
+ ASSERT_EQ(1U, active_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), |
+ active_permissions()[0]); |
+ |
+ ASSERT_EQ(1U, GetOptionalPermissionMessages().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), |
+ GetOptionalPermissionMessages()[0]); |
+ |
+ GrantOptionalPermissions(); |
+ |
+ ASSERT_EQ(1U, active_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), |
+ active_permissions()[0]); |
+} |
+ |
+// AntiTest: This behavior should be changed and improved. |
+// If an app requests the 'tabs' permission but already has the 'history' |
+// permission, a prompt is displayed. However, no prompt should appear at all, |
+// since 'tabs' is a subset of 'history' and the final list of permissions are |
+// not affected by this grant. |
+TEST_F(PermissionMessagesUnittest, |
+ AntiTest_PromptCanRequestSubsetOfAlreadyGrantedPermissions) { |
+ CreateAndInstallExtensionWithPermissions( |
+ ListBuilder().Append("history").Pass(), |
+ ListBuilder().Append("tabs").Pass()); |
+ |
+ ASSERT_EQ(1U, required_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), |
+ required_permissions()[0]); |
+ |
+ ASSERT_EQ(1U, optional_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), |
+ optional_permissions()[0]); |
+ |
+ ASSERT_EQ(1U, active_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), |
+ active_permissions()[0]); |
+ |
+ // TODO(sashab): This prompt should display no permissions, since READ is a |
+ // subset permission of WRITE. |
+ ASSERT_EQ(1U, GetOptionalPermissionMessages().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), |
+ GetOptionalPermissionMessages()[0]); |
+ |
+ GrantOptionalPermissions(); |
+ |
+ ASSERT_EQ(1U, active_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), |
+ active_permissions()[0]); |
+} |
+ |
+// AntiTest: This behavior should be changed and improved. |
+// If an app requests the 'sessions' permission, nothing is displayed in the |
+// permission request prompt. However, the required permissions for the app are |
+// actually modified, so the prompt *should* display a message to prevent this |
+// permission from being granted for free. |
+TEST_F(PermissionMessagesUnittest, |
+ AntiTest_PromptCanBeEmptyButCausesChangeInPermissions) { |
+ CreateAndInstallExtensionWithPermissions( |
+ ListBuilder().Append("tabs").Pass(), |
+ ListBuilder().Append("sessions").Pass()); |
+ |
+ ASSERT_EQ(1U, required_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), |
+ required_permissions()[0]); |
+ |
+ ASSERT_EQ(0U, optional_permissions().size()); |
+ |
+ ASSERT_EQ(1U, active_permissions().size()); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), |
+ active_permissions()[0]); |
+ |
+ // TODO(sashab): This prompt should display the sessions permission message, |
+ // as well as warn the user that it can affect the existing 'tab' permission. |
+ ASSERT_EQ(0U, GetOptionalPermissionMessages().size()); |
+ |
+ GrantOptionalPermissions(); |
+ |
+ ASSERT_EQ(1U, active_permissions().size()); |
+ EXPECT_EQ(l10n_util::GetStringUTF16( |
+ IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ_AND_SESSIONS), |
+ active_permissions()[0]); |
+} |
+ |
+} // namespace extensions |