| // Copyright (c) 2012 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. |
| |
| #import <Cocoa/Cocoa.h> |
| |
| #include "base/basictypes.h" |
| #include "base/command_line.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/path_service.h" |
| #include "base/values.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/test_extension_system.h" |
| #import "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/cocoa/cocoa_profile_test.h" |
| #import "chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.h" |
| #import "chrome/browser/ui/cocoa/info_bubble_window.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "extensions/common/extension.h" |
| #include "extensions/common/manifest_constants.h" |
| #import "third_party/ocmock/OCMock/OCMock.h" |
| #include "third_party/ocmock/gtest_support.h" |
| #include "ui/gfx/codec/png_codec.h" |
| |
| using extensions::Extension; |
| |
| // ExtensionInstalledBubbleController with removePageActionPreview overridden |
| // to a no-op, because pageActions are not yet hooked up in the test browser. |
| @interface ExtensionInstalledBubbleControllerForTest : |
| ExtensionInstalledBubbleController { |
| } |
| |
| // Do nothing, because browser window is not set up with page actions |
| // for unit testing. |
| - (void)removePageActionPreview; |
| |
| @end |
| |
| @implementation ExtensionInstalledBubbleControllerForTest |
| |
| - (void)removePageActionPreview { } |
| |
| @end |
| |
| namespace keys = extensions::manifest_keys; |
| |
| class ExtensionInstalledBubbleControllerTest : public CocoaProfileTest { |
| |
| public: |
| virtual void SetUp() { |
| CocoaProfileTest::SetUp(); |
| ASSERT_TRUE(browser()); |
| window_ = browser()->window()->GetNativeWindow(); |
| icon_ = LoadTestIcon(); |
| CommandLine command_line(CommandLine::NO_PROGRAM); |
| extension_service_ = static_cast<extensions::TestExtensionSystem*>( |
| extensions::ExtensionSystem::Get(profile()))->CreateExtensionService( |
| &command_line, base::FilePath(), false); |
| } |
| |
| // Load test icon from extension test directory. |
| SkBitmap LoadTestIcon() { |
| base::FilePath path; |
| PathService::Get(chrome::DIR_TEST_DATA, &path); |
| path = path.AppendASCII("extensions").AppendASCII("icon1.png"); |
| |
| std::string file_contents; |
| base::ReadFileToString(path, &file_contents); |
| const unsigned char* data = |
| reinterpret_cast<const unsigned char*>(file_contents.data()); |
| |
| SkBitmap bitmap; |
| gfx::PNGCodec::Decode(data, file_contents.length(), &bitmap); |
| return bitmap; |
| } |
| |
| // Create a skeletal framework of either page action or browser action |
| // type. This extension only needs to have a type and a name to initialize |
| // the ExtensionInstalledBubble for unit testing. |
| scoped_refptr<Extension> CreateExtension( |
| extension_installed_bubble::ExtensionType type) { |
| base::FilePath path; |
| PathService::Get(chrome::DIR_TEST_DATA, &path); |
| path = path.AppendASCII("extensions").AppendASCII("dummy"); |
| |
| base::DictionaryValue extension_input_value; |
| extension_input_value.SetString(keys::kVersion, "1.0.0.0"); |
| if (type == extension_installed_bubble::kPageAction) { |
| extension_input_value.SetString(keys::kName, "page action extension"); |
| base::DictionaryValue* action = new base::DictionaryValue; |
| action->SetString(keys::kPageActionId, "ExtensionActionId"); |
| action->SetString(keys::kPageActionDefaultTitle, "ExtensionActionTitle"); |
| action->SetString(keys::kPageActionDefaultIcon, "image1.png"); |
| extension_input_value.Set(keys::kPageAction, action); |
| } else if (type == extension_installed_bubble::kBrowserAction) { |
| extension_input_value.SetString(keys::kName, "browser action extension"); |
| base::DictionaryValue* browser_action = new base::DictionaryValue; |
| // An empty dictionary is enough to create a Browser Action. |
| extension_input_value.Set(keys::kBrowserAction, browser_action); |
| } else if (type == extension_installed_bubble::kApp) { |
| extension_input_value.SetString(keys::kName, "test app"); |
| extension_input_value.SetString(keys::kLaunchWebURL, |
| "http://www.example.com"); |
| } |
| |
| std::string error; |
| scoped_refptr<Extension> extension = |
| Extension::Create(path, extensions::Manifest::INVALID_LOCATION, |
| extension_input_value, Extension::NO_FLAGS, &error); |
| extension_service_->AddExtension(extension.get()); |
| return extension; |
| } |
| |
| // Required to initialize the extension installed bubble. |
| NSWindow* window_; // weak, owned by CocoaProfileTest. |
| |
| ExtensionService* extension_service_; |
| |
| // Skeleton extension to be tested; reinitialized for each test. |
| scoped_refptr<Extension> extension_; |
| |
| // The icon_ to be loaded into the bubble window. |
| SkBitmap icon_; |
| }; |
| |
| // Confirm that window sizes are set correctly for a page action extension. |
| TEST_F(ExtensionInstalledBubbleControllerTest, PageActionTest) { |
| extension_ = CreateExtension(extension_installed_bubble::kPageAction); |
| ExtensionInstalledBubbleControllerForTest* controller = |
| [[ExtensionInstalledBubbleControllerForTest alloc] |
| initWithParentWindow:window_ |
| extension:extension_.get() |
| bundle:NULL |
| browser:browser() |
| icon:icon_]; |
| EXPECT_TRUE(controller); |
| |
| // Initialize window without having to calculate tabstrip locations. |
| [controller initializeWindow]; |
| EXPECT_TRUE([controller window]); |
| |
| int height = [controller calculateWindowHeight]; |
| // Height should equal the vertical padding + height of all messages. |
| int correctHeight = 2 * extension_installed_bubble::kOuterVerticalMargin + |
| 2 * extension_installed_bubble::kInnerVerticalMargin + |
| NSHeight([controller headingFrame]) + |
| NSHeight([controller frameOfHowToUse]) + |
| NSHeight([controller frameOfHowToManage]); |
| if ([controller showSyncPromo]) { |
| correctHeight += NSHeight([controller frameOfSigninPromo]) + |
| extension_installed_bubble::kInnerVerticalMargin; |
| } |
| EXPECT_EQ(height, correctHeight); |
| [controller setMessageFrames:height]; |
| |
| NSRect msg1Frame = [controller headingFrame]; |
| NSRect msg2Frame = [controller frameOfHowToUse]; |
| NSRect msg3Frame = [controller frameOfHowToManage]; |
| NSRect msg4Frame = [controller frameOfSigninPromo]; |
| |
| int next_y = extension_installed_bubble::kOuterVerticalMargin; |
| if ([controller showSyncPromo]) { |
| // Bottom message should be kOuterVerticalMargin pixels above window edge. |
| EXPECT_EQ(next_y, NSMinY(msg4Frame)); |
| next_y = NSMinY(msg4Frame) + NSHeight(msg4Frame) + |
| extension_installed_bubble::kInnerVerticalMargin; |
| } |
| |
| // HowToManage frame should be kInnerVerticalMargin pixels above sync promo, |
| // unless sync promo is hidden, then kOuterVerticalMargin pixels above. |
| EXPECT_EQ(next_y, NSMinY(msg3Frame)); |
| |
| // Page action message should be kInnerVerticalMargin pixels above bottom msg. |
| EXPECT_EQ(NSMinY(msg3Frame) + NSHeight(msg3Frame) + |
| extension_installed_bubble::kInnerVerticalMargin, |
| NSMinY(msg2Frame)); |
| |
| // Top message should be kInnerVerticalMargin pixels above Page action msg. |
| EXPECT_EQ(NSMinY(msg2Frame) + NSHeight(msg2Frame) + |
| extension_installed_bubble::kInnerVerticalMargin, |
| NSMinY(msg1Frame)); |
| |
| [controller setPageActionPreviewShowing:NO]; |
| [controller close]; |
| } |
| |
| TEST_F(ExtensionInstalledBubbleControllerTest, BrowserActionTest) { |
| extension_ = CreateExtension(extension_installed_bubble::kBrowserAction); |
| ExtensionInstalledBubbleControllerForTest* controller = |
| [[ExtensionInstalledBubbleControllerForTest alloc] |
| initWithParentWindow:window_ |
| extension:extension_.get() |
| bundle:NULL |
| browser:browser() |
| icon:icon_]; |
| EXPECT_TRUE(controller); |
| |
| // Initialize window without having to calculate tabstrip locations. |
| [controller initializeWindow]; |
| EXPECT_TRUE([controller window]); |
| |
| int height = [controller calculateWindowHeight]; |
| // Height should equal the vertical padding + height of all messages. |
| int correctHeight = 2 * extension_installed_bubble::kOuterVerticalMargin + |
| 2 * extension_installed_bubble::kInnerVerticalMargin + |
| NSHeight([controller headingFrame]) + |
| NSHeight([controller frameOfHowToUse]) + |
| NSHeight([controller frameOfHowToManage]); |
| if ([controller showSyncPromo]) { |
| correctHeight += NSHeight([controller frameOfSigninPromo]) + |
| extension_installed_bubble::kInnerVerticalMargin; |
| } |
| EXPECT_EQ(height, correctHeight); |
| [controller setMessageFrames:height]; |
| |
| NSRect msg1Frame = [controller headingFrame]; |
| NSRect msg2Frame = [controller frameOfHowToUse]; |
| NSRect msg3Frame = [controller frameOfHowToManage]; |
| NSRect msg4Frame = [controller frameOfSigninPromo]; |
| |
| int next_y = extension_installed_bubble::kOuterVerticalMargin; |
| if ([controller showSyncPromo]) { |
| // Bottom message should be kOuterVerticalMargin pixels above window edge. |
| EXPECT_EQ(next_y, NSMinY(msg4Frame)); |
| next_y = NSMinY(msg4Frame) + NSHeight(msg4Frame) + |
| extension_installed_bubble::kInnerVerticalMargin; |
| } |
| |
| // HowToManage frame should be kInnerVerticalMargin pixels above sync promo, |
| // unless sync promo is hidden, then kOuterVerticalMargin pixels above. |
| EXPECT_EQ(next_y, NSMinY(msg3Frame)); |
| |
| // Browser action message should be kInnerVerticalMargin pixels above bottom |
| // msg. |
| EXPECT_EQ(NSMinY(msg3Frame) + NSHeight(msg3Frame) + |
| extension_installed_bubble::kInnerVerticalMargin, |
| NSMinY(msg2Frame)); |
| |
| // Top message should be kInnerVerticalMargin pixels above Browser action msg. |
| EXPECT_EQ(NSMinY(msg2Frame) + NSHeight(msg2Frame) + |
| extension_installed_bubble::kInnerVerticalMargin, |
| NSMinY(msg1Frame)); |
| |
| [controller close]; |
| } |
| |
| TEST_F(ExtensionInstalledBubbleControllerTest, ParentClose) { |
| extension_ = CreateExtension(extension_installed_bubble::kBrowserAction); |
| ExtensionInstalledBubbleControllerForTest* controller = |
| [[ExtensionInstalledBubbleControllerForTest alloc] |
| initWithParentWindow:window_ |
| extension:extension_.get() |
| bundle:NULL |
| browser:browser() |
| icon:icon_]; |
| EXPECT_TRUE(controller); |
| |
| // Bring up the window and disable close animation. |
| [controller showWindow:nil]; |
| NSWindow* bubbleWindow = [controller window]; |
| ASSERT_TRUE([bubbleWindow isKindOfClass:[InfoBubbleWindow class]]); |
| [static_cast<InfoBubbleWindow*>(bubbleWindow) |
| setAllowedAnimations:info_bubble::kAnimateNone]; |
| |
| // Observe whether the bubble window closes. |
| NSString* notification = NSWindowWillCloseNotification; |
| id observer = [OCMockObject observerMock]; |
| [[observer expect] notificationWithName:notification object:bubbleWindow]; |
| [[NSNotificationCenter defaultCenter] |
| addMockObserver:observer name:notification object:bubbleWindow]; |
| |
| // The bubble window goes from visible to not-visible. |
| EXPECT_TRUE([bubbleWindow isVisible]); |
| [window_ close]; |
| EXPECT_FALSE([bubbleWindow isVisible]); |
| |
| [[NSNotificationCenter defaultCenter] removeObserver:observer]; |
| |
| // Check that the appropriate notification was received. |
| EXPECT_OCMOCK_VERIFY(observer); |
| } |
| |
| TEST_F(ExtensionInstalledBubbleControllerTest, AppTest) { |
| extension_ = CreateExtension(extension_installed_bubble::kApp); |
| ExtensionInstalledBubbleControllerForTest* controller = |
| [[ExtensionInstalledBubbleControllerForTest alloc] |
| initWithParentWindow:window_ |
| extension:extension_.get() |
| bundle:NULL |
| browser:browser() |
| icon:icon_]; |
| EXPECT_TRUE(controller); |
| [controller initializeWindow]; |
| EXPECT_TRUE([controller window]); |
| |
| int height = [controller calculateWindowHeight]; |
| |
| // Make sure there is always enough room for the icon and margin. |
| int minHeight = extension_installed_bubble::kIconSize + |
| (2 * extension_installed_bubble::kOuterVerticalMargin); |
| EXPECT_GT(height, minHeight); |
| |
| // Make sure the "show me" link is visible. |
| EXPECT_FALSE([[controller appInstalledShortcutLink] isHidden]); |
| |
| [controller close]; |
| } |
| |