| Index: chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
|
| diff --git a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b435caa9bb0e54edd78161a2daa3cb801842462b
|
| --- /dev/null
|
| +++ b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
|
| @@ -0,0 +1,405 @@
|
| +// Copyright (c) 2013 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/command_line.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "chrome/browser/extensions/dev_mode_bubble_controller.h"
|
| +#include "chrome/browser/extensions/extension_function_test_utils.h"
|
| +#include "chrome/browser/extensions/extension_message_bubble.h"
|
| +#include "chrome/browser/extensions/extension_service.h"
|
| +#include "chrome/browser/extensions/suspicious_extension_bubble_controller.h"
|
| +#include "chrome/browser/extensions/test_extension_system.h"
|
| +#include "chrome/test/base/testing_profile.h"
|
| +#include "content/public/test/test_browser_thread_bundle.h"
|
| +#include "extensions/common/extension.h"
|
| +
|
| +namespace extensions {
|
| +
|
| +class TestController {
|
| + public:
|
| + TestController()
|
| + : action_button_callback_count_(0),
|
| + dismiss_button_callback_count_(0),
|
| + link_click_callback_count_(0) {
|
| + }
|
| +
|
| + // Returns how often the dismiss button has been called.
|
| + size_t action_click_count() {
|
| + return action_button_callback_count_;
|
| + }
|
| +
|
| + // Returns how often the dismiss button has been called.
|
| + size_t dismiss_click_count() {
|
| + return dismiss_button_callback_count_;
|
| + }
|
| +
|
| + // Returns how often the link has been clicked.
|
| + size_t link_click_count() {
|
| + return link_click_callback_count_;
|
| + }
|
| +
|
| + protected:
|
| + size_t action_button_callback_count_;
|
| + size_t dismiss_button_callback_count_;
|
| + size_t link_click_callback_count_;
|
| +};
|
| +
|
| +// A test class for the SuspiciousExtensionBubbleController.
|
| +class TestSuspiciousExtensionBubbleController
|
| + : public SuspiciousExtensionBubbleController,
|
| + public TestController {
|
| + public:
|
| + explicit TestSuspiciousExtensionBubbleController(Profile* profile)
|
| + : SuspiciousExtensionBubbleController(profile) {
|
| + }
|
| +
|
| + // Callbacks from bubble.
|
| + virtual void OnBubbleAction() OVERRIDE {
|
| + // This bubble offers no user action so this should never get called.
|
| + NOTREACHED();
|
| + }
|
| +
|
| + virtual void OnBubbleDismiss() OVERRIDE {
|
| + ++dismiss_button_callback_count_;
|
| + SuspiciousExtensionBubbleController::OnBubbleDismiss();
|
| + }
|
| + virtual void OnLinkClicked() OVERRIDE {
|
| + ++link_click_callback_count_;
|
| + SuspiciousExtensionBubbleController::OnLinkClicked();
|
| + }
|
| +};
|
| +
|
| +// A test class for the DevModeBubbleController.
|
| +class TestDevModeBubbleController
|
| + : public DevModeBubbleController,
|
| + public TestController {
|
| + public:
|
| + explicit TestDevModeBubbleController(Profile* profile)
|
| + : DevModeBubbleController(profile) {
|
| + }
|
| +
|
| + // Callbacks from bubble.
|
| + // Callbacks from bubble.
|
| + virtual void OnBubbleAction() OVERRIDE {
|
| + ++action_button_callback_count_;
|
| + DevModeBubbleController::OnBubbleAction();
|
| + }
|
| +
|
| + virtual void OnBubbleDismiss() OVERRIDE {
|
| + ++dismiss_button_callback_count_;
|
| + DevModeBubbleController::OnBubbleDismiss();
|
| + }
|
| + virtual void OnLinkClicked() OVERRIDE {
|
| + ++link_click_callback_count_;
|
| + DevModeBubbleController::OnLinkClicked();
|
| + }
|
| +};
|
| +
|
| +// A fake bubble used for testing the controller. Takes an action that specifies
|
| +// what should happen when the bubble is "shown" (the bubble is actually not
|
| +// shown, the corresponding action is taken immediately).
|
| +class FakeExtensionMessageBubble : public ExtensionMessageBubble {
|
| + public:
|
| + enum ExtensionBubbleAction {
|
| + BUBBLE_ACTION_CLICK_ACTION_BUTTON = 0,
|
| + BUBBLE_ACTION_CLICK_DISMISS_BUTTON,
|
| + BUBBLE_ACTION_CLICK_LINK
|
| + };
|
| +
|
| + FakeExtensionMessageBubble() {}
|
| +
|
| + void set_action_on_show(ExtensionBubbleAction action) {
|
| + action_ = action;
|
| + }
|
| +
|
| + virtual void Show() OVERRIDE {
|
| + if (action_ == BUBBLE_ACTION_CLICK_ACTION_BUTTON)
|
| + action_callback_.Run();
|
| + else if (action_ == BUBBLE_ACTION_CLICK_DISMISS_BUTTON)
|
| + dismiss_callback_.Run();
|
| + else if (action_ == BUBBLE_ACTION_CLICK_LINK)
|
| + link_callback_.Run();
|
| + }
|
| +
|
| + virtual void OnActionButtonClicked(const base::Closure& callback) OVERRIDE {
|
| + action_callback_ = callback;
|
| + }
|
| +
|
| + virtual void OnDismissButtonClicked(const base::Closure& callback) OVERRIDE {
|
| + dismiss_callback_ = callback;
|
| + }
|
| +
|
| + virtual void OnLinkClicked(const base::Closure& callback) OVERRIDE {
|
| + link_callback_ = callback;
|
| + }
|
| +
|
| + private:
|
| + ExtensionBubbleAction action_;
|
| +
|
| + base::Closure action_callback_;
|
| + base::Closure dismiss_callback_;
|
| + base::Closure link_callback_;
|
| +};
|
| +
|
| +class ExtensionMessageBubbleTest : public testing::Test {
|
| + public:
|
| + ExtensionMessageBubbleTest() {
|
| + // The two lines of magical incantation required to get the extension
|
| + // service to work inside a unit test and access the extension prefs.
|
| + thread_bundle_.reset(new content::TestBrowserThreadBundle);
|
| + profile_.reset(new TestingProfile);
|
| +
|
| + static_cast<TestExtensionSystem*>(
|
| + ExtensionSystem::Get(profile_.get()))->CreateExtensionService(
|
| + CommandLine::ForCurrentProcess(),
|
| + base::FilePath(),
|
| + false);
|
| + service_ = profile_->GetExtensionService();
|
| + service_->Init();
|
| +
|
| + std::string basic_extension =
|
| + "{\"name\": \"Extension #\","
|
| + "\"version\": \"1.0\","
|
| + "\"manifest_version\": 2}";
|
| + std::string basic_extension_with_action =
|
| + "{\"name\": \"Extension #\","
|
| + "\"version\": \"1.0\","
|
| + "\"browser_action\": {"
|
| + " \"default_title\": \"Default title\""
|
| + "},"
|
| + "\"manifest_version\": 2}";
|
| +
|
| + std::string extension_data;
|
| + ReplaceChars(basic_extension_with_action, "#", "1", &extension_data);
|
| + scoped_refptr<Extension> my_test_extension1(
|
| + CreateExtension(
|
| + Manifest::COMMAND_LINE,
|
| + extension_data,
|
| + "Autogenerated 1"));
|
| +
|
| + ReplaceChars(basic_extension, "#", "2", &extension_data);
|
| + scoped_refptr<Extension> my_test_extension2(
|
| + CreateExtension(
|
| + Manifest::UNPACKED,
|
| + extension_data,
|
| + "Autogenerated 2"));
|
| +
|
| + ReplaceChars(basic_extension, "#", "3", &extension_data);
|
| + scoped_refptr<Extension> regular_extension(
|
| + CreateExtension(
|
| + Manifest::EXTERNAL_POLICY,
|
| + extension_data,
|
| + "Autogenerated 3"));
|
| +
|
| + extension_id1_ = my_test_extension1->id();
|
| + extension_id2_ = my_test_extension2->id();
|
| + extension_id3_ = regular_extension->id();
|
| +
|
| + service_->AddExtension(regular_extension);
|
| + service_->AddExtension(my_test_extension1);
|
| + service_->AddExtension(my_test_extension2);
|
| + }
|
| + virtual ~ExtensionMessageBubbleTest() {}
|
| + virtual void SetUp() {
|
| + command_line_.reset(new CommandLine(CommandLine::NO_PROGRAM));
|
| + }
|
| + scoped_ptr<CommandLine> command_line_;
|
| +
|
| + protected:
|
| + scoped_refptr<Extension> CreateExtension(
|
| + Manifest::Location location,
|
| + const std::string& data,
|
| + const std::string& id) {
|
| + scoped_ptr<base::DictionaryValue> parsed_manifest(
|
| + extension_function_test_utils::ParseDictionary(data));
|
| + return extension_function_test_utils::CreateExtension(
|
| + location,
|
| + parsed_manifest.get(),
|
| + id);
|
| + }
|
| +
|
| + scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_;
|
| + scoped_ptr<TestingProfile> profile_;
|
| + ExtensionService* service_;
|
| + std::string extension_id1_;
|
| + std::string extension_id2_;
|
| + std::string extension_id3_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleTest);
|
| +};
|
| +
|
| +// The feature this is meant to test is only implemented on Windows.
|
| +#if defined(OS_WIN)
|
| +#define MAYBE_SuspiciousExtensionControllerTest SuspiciousExtensionControllerTest
|
| +#else
|
| +#define MAYBE_SuspiciousExtensionControllerTest DISABLED_SuspiciousExtensionControllerTest
|
| +#endif
|
| +
|
| +TEST_F(ExtensionMessageBubbleTest, MAYBE_SuspiciousExtensionControllerTest) {
|
| + // The test base class adds three extensions, and we control two of them in
|
| + // this test (ids are: extension_id1_ and extension_id2_).
|
| + scoped_ptr<TestSuspiciousExtensionBubbleController> controller(
|
| + new TestSuspiciousExtensionBubbleController(profile_.get()));
|
| + FakeExtensionMessageBubble bubble;
|
| + bubble.set_action_on_show(
|
| + FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON);
|
| +
|
| + // Validate that we don't have a suppress value for the extensions.
|
| + ExtensionPrefs* prefs = service_->extension_prefs();
|
| + EXPECT_FALSE(prefs->HasWipeoutBeenAcknowledged(extension_id1_));
|
| + EXPECT_FALSE(prefs->HasWipeoutBeenAcknowledged(extension_id2_));
|
| +
|
| + EXPECT_FALSE(controller->HasExtensionList());
|
| + std::vector<string16> suspicious_extensions = controller->GetExtensionList();
|
| + EXPECT_EQ(0U, suspicious_extensions.size());
|
| + EXPECT_EQ(0U, controller->link_click_count());
|
| + EXPECT_EQ(0U, controller->dismiss_click_count());
|
| +
|
| + // Now disable an extension, specifying the wipeout flag.
|
| + service_->DisableExtension(extension_id1_,
|
| + Extension::DISABLE_NOT_VERIFIED);
|
| +
|
| + EXPECT_FALSE(prefs->HasWipeoutBeenAcknowledged(extension_id1_));
|
| + EXPECT_FALSE(prefs->HasWipeoutBeenAcknowledged(extension_id2_));
|
| + controller.reset(new TestSuspiciousExtensionBubbleController(profile_.get()));
|
| + EXPECT_TRUE(controller->HasExtensionList());
|
| + suspicious_extensions = controller->GetExtensionList();
|
| + ASSERT_EQ(1U, suspicious_extensions.size());
|
| + EXPECT_TRUE(ASCIIToUTF16("Extension 1") == suspicious_extensions[0]);
|
| + controller->Show(&bubble); // Simulate showing the bubble.
|
| + EXPECT_EQ(0U, controller->link_click_count());
|
| + EXPECT_EQ(1U, controller->dismiss_click_count());
|
| + // Now the acknowledge flag should be set only for the first extension.
|
| + EXPECT_TRUE(prefs->HasWipeoutBeenAcknowledged(extension_id1_));
|
| + EXPECT_FALSE(prefs->HasWipeoutBeenAcknowledged(extension_id2_));
|
| + // Clear the flag.
|
| + prefs->SetWipeoutAcknowledged(extension_id1_, false);
|
| + EXPECT_FALSE(prefs->HasWipeoutBeenAcknowledged(extension_id1_));
|
| +
|
| + // Now disable the other extension and exercise the link click code path.
|
| + service_->DisableExtension(extension_id2_,
|
| + Extension::DISABLE_NOT_VERIFIED);
|
| +
|
| + bubble.set_action_on_show(
|
| + FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK);
|
| + controller.reset(new TestSuspiciousExtensionBubbleController(profile_.get()));
|
| + EXPECT_TRUE(controller->HasExtensionList());
|
| + suspicious_extensions = controller->GetExtensionList();
|
| + ASSERT_EQ(2U, suspicious_extensions.size());
|
| + EXPECT_TRUE(ASCIIToUTF16("Extension 1") == suspicious_extensions[1]);
|
| + EXPECT_TRUE(ASCIIToUTF16("Extension 2") == suspicious_extensions[0]);
|
| + controller->Show(&bubble); // Simulate showing the bubble.
|
| + EXPECT_EQ(1U, controller->link_click_count());
|
| + EXPECT_EQ(0U, controller->dismiss_click_count());
|
| + EXPECT_TRUE(prefs->HasWipeoutBeenAcknowledged(extension_id1_));
|
| +}
|
| +
|
| +// The feature this is meant to test is only implemented on Windows.
|
| +#if defined(OS_WIN)
|
| +#define MAYBE_DevModeControllerTest DevModeControllerTest
|
| +#else
|
| +#define MAYBE_DevModeControllerTest DISABLED_DevModeControllerTest
|
| +#endif
|
| +
|
| +TEST_F(ExtensionMessageBubbleTest, MAYBE_DevModeControllerTest) {
|
| + // The test base class adds three extensions, and we control two of them in
|
| + // this test (ids are: extension_id1_ and extension_id2_). Extension 1 is a
|
| + // regular extension, Extension 2 is UNPACKED so it counts as a DevMode
|
| + // extension.
|
| + scoped_ptr<TestDevModeBubbleController> controller(
|
| + new TestDevModeBubbleController(profile_.get()));
|
| +
|
| + // Validate that we don't have a suppress value for the two extensions.
|
| + ExtensionPrefs* prefs = service_->extension_prefs();
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id1_));
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id2_));
|
| +
|
| + // The list will contain one enabled unpacked extension.
|
| + EXPECT_TRUE(controller->HasExtensionList());
|
| + std::vector<string16> dev_mode_extensions = controller->GetExtensionList();
|
| + ASSERT_EQ(2U, dev_mode_extensions.size());
|
| + EXPECT_TRUE(ASCIIToUTF16("Extension 2") == dev_mode_extensions[0]);
|
| + EXPECT_TRUE(ASCIIToUTF16("Extension 1") == dev_mode_extensions[1]);
|
| + EXPECT_EQ(0U, controller->link_click_count());
|
| + EXPECT_EQ(0U, controller->dismiss_click_count());
|
| + EXPECT_EQ(0U, controller->action_click_count());
|
| +
|
| + // Simulate showing the bubble.
|
| + FakeExtensionMessageBubble bubble;
|
| + bubble.set_action_on_show(
|
| + FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON);
|
| + controller->Show(&bubble);
|
| + EXPECT_EQ(0U, controller->link_click_count());
|
| + EXPECT_EQ(0U, controller->action_click_count());
|
| + EXPECT_EQ(1U, controller->dismiss_click_count());
|
| + // The user dismissed, so we should have ack'ed the extension shown in bubble.
|
| + EXPECT_TRUE(prefs->HasDevModeBeenAcknowledged(extension_id1_));
|
| + EXPECT_TRUE(prefs->HasDevModeBeenAcknowledged(extension_id2_));
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id3_));
|
| + EXPECT_TRUE(service_->GetExtensionById(extension_id1_, false) != NULL);
|
| + EXPECT_TRUE(service_->GetExtensionById(extension_id2_, false) != NULL);
|
| +
|
| + // Clear the flags.
|
| + prefs->SetDevModeAcknowledged(extension_id1_, false);
|
| + prefs->SetDevModeAcknowledged(extension_id2_, false);
|
| +
|
| + // Do it again, but now press different button (Disable).
|
| + bubble.set_action_on_show(
|
| + FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_ACTION_BUTTON);
|
| + controller.reset(new TestDevModeBubbleController(profile_.get()));
|
| + EXPECT_TRUE(controller->HasExtensionList());
|
| + dev_mode_extensions = controller->GetExtensionList();
|
| + EXPECT_EQ(2U, dev_mode_extensions.size());
|
| + controller->Show(&bubble); // Simulate showing the bubble.
|
| + EXPECT_EQ(0U, controller->link_click_count());
|
| + EXPECT_EQ(1U, controller->action_click_count());
|
| + EXPECT_EQ(0U, controller->dismiss_click_count());
|
| + // No extension should be acknowledged (since we want to warn again when they
|
| + // become re-enabled).
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id1_));
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id2_));
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id3_));
|
| + EXPECT_TRUE(service_->GetExtensionById(extension_id1_, false) == NULL);
|
| + EXPECT_TRUE(service_->GetExtensionById(extension_id2_, false) == NULL);
|
| +
|
| + // Re-enable the extensions (disabled by the action button above).
|
| + service_->EnableExtension(extension_id1_);
|
| + service_->EnableExtension(extension_id2_);
|
| +
|
| + // Show the dialog a third time, but now press the learn more link.
|
| + bubble.set_action_on_show(
|
| + FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK);
|
| + controller.reset(new TestDevModeBubbleController(profile_.get()));
|
| + EXPECT_TRUE(controller->HasExtensionList());
|
| + dev_mode_extensions = controller->GetExtensionList();
|
| + EXPECT_EQ(2U, dev_mode_extensions.size());
|
| + controller->Show(&bubble); // Simulate showing the bubble.
|
| + EXPECT_EQ(1U, controller->link_click_count());
|
| + EXPECT_EQ(0U, controller->action_click_count());
|
| + EXPECT_EQ(0U, controller->dismiss_click_count());
|
| + // No extension should be acknowledged (we should show the bubble again on
|
| + // next startup).
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id1_));
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id2_));
|
| + EXPECT_TRUE(service_->GetExtensionById(extension_id1_, false) != NULL);
|
| + EXPECT_TRUE(service_->GetExtensionById(extension_id2_, false) != NULL);
|
| +
|
| + // Now disable the unpacked extension.
|
| + service_->DisableExtension(extension_id1_, Extension::DISABLE_USER_ACTION);
|
| + service_->DisableExtension(extension_id2_, Extension::DISABLE_USER_ACTION);
|
| +
|
| + // We should find no extension and none should be acknowledged.
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id1_));
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id2_));
|
| +
|
| + controller.reset(new TestDevModeBubbleController(profile_.get()));
|
| + EXPECT_FALSE(controller->HasExtensionList());
|
| + dev_mode_extensions = controller->GetExtensionList();
|
| + EXPECT_EQ(0U, dev_mode_extensions.size());
|
| + EXPECT_FALSE(prefs->HasDevModeBeenAcknowledged(extension_id2_));
|
| +}
|
| +
|
| +} // namespace extensions
|
|
|