toolbar_controller_unittest.mm revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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. 4 5#import <Cocoa/Cocoa.h> 6 7#import "base/mac/scoped_nsobject.h" 8#include "base/prefs/pref_service.h" 9#include "chrome/app/chrome_command_ids.h" 10#include "chrome/browser/command_updater.h" 11#include "chrome/browser/ui/browser.h" 12#include "chrome/browser/ui/browser_command_controller.h" 13#include "chrome/browser/ui/browser_commands.h" 14#include "chrome/browser/ui/cocoa/cocoa_profile_test.h" 15#import "chrome/browser/ui/cocoa/gradient_button_cell.h" 16#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" 17#import "chrome/browser/ui/cocoa/view_resizer_pong.h" 18#include "chrome/common/pref_names.h" 19#include "chrome/test/base/testing_profile.h" 20#include "testing/gtest/include/gtest/gtest.h" 21#include "testing/platform_test.h" 22 23// An NSView that fakes out hitTest:. 24@interface HitView : NSView { 25 id hitTestReturn_; 26} 27@end 28 29@implementation HitView 30 31- (void)setHitTestReturn:(id)rtn { 32 hitTestReturn_ = rtn; 33} 34 35- (NSView *)hitTest:(NSPoint)aPoint { 36 return hitTestReturn_; 37} 38 39@end 40 41 42namespace { 43 44class ToolbarControllerTest : public CocoaProfileTest { 45 public: 46 47 // Indexes that match the ordering returned by the private ToolbarController 48 // |-toolbarViews| method. 49 enum { 50 kBackIndex, kForwardIndex, kReloadIndex, kHomeIndex, 51 kWrenchIndex, kLocationIndex, kBrowserActionContainerViewIndex 52 }; 53 54 virtual void SetUp() OVERRIDE { 55 CocoaProfileTest::SetUp(); 56 ASSERT_TRUE(browser()); 57 58 CommandUpdater* updater = 59 browser()->command_controller()->command_updater(); 60 // The default state for the commands is true, set a couple to false to 61 // ensure they get picked up correct on initialization 62 updater->UpdateCommandEnabled(IDC_BACK, false); 63 updater->UpdateCommandEnabled(IDC_FORWARD, false); 64 resizeDelegate_.reset([[ViewResizerPong alloc] init]); 65 bar_.reset( 66 [[ToolbarController alloc] 67 initWithCommands:browser()->command_controller()->command_updater() 68 profile:profile() 69 browser:browser() 70 resizeDelegate:resizeDelegate_.get()]); 71 EXPECT_TRUE([bar_ view]); 72 NSView* parent = [test_window() contentView]; 73 [parent addSubview:[bar_ view]]; 74 } 75 76 virtual void TearDown() OVERRIDE { 77 bar_.reset(); // browser() must outlive the ToolbarController. 78 CocoaProfileTest::TearDown(); 79 } 80 81 // Make sure the enabled state of the view is the same as the corresponding 82 // command in the updater. The views are in the declaration order of outlets. 83 void CompareState(CommandUpdater* updater, NSArray* views) { 84 EXPECT_EQ(updater->IsCommandEnabled(IDC_BACK), 85 [[views objectAtIndex:kBackIndex] isEnabled] ? true : false); 86 EXPECT_EQ(updater->IsCommandEnabled(IDC_FORWARD), 87 [[views objectAtIndex:kForwardIndex] isEnabled] ? true : false); 88 EXPECT_EQ(updater->IsCommandEnabled(IDC_RELOAD), 89 [[views objectAtIndex:kReloadIndex] isEnabled] ? true : false); 90 EXPECT_EQ(updater->IsCommandEnabled(IDC_HOME), 91 [[views objectAtIndex:kHomeIndex] isEnabled] ? true : false); 92 } 93 94 base::scoped_nsobject<ViewResizerPong> resizeDelegate_; 95 base::scoped_nsobject<ToolbarController> bar_; 96}; 97 98TEST_VIEW(ToolbarControllerTest, [bar_ view]) 99 100// Test the initial state that everything is sync'd up 101TEST_F(ToolbarControllerTest, InitialState) { 102 CommandUpdater* updater = browser()->command_controller()->command_updater(); 103 CompareState(updater, [bar_ toolbarViews]); 104} 105 106// Make sure a "titlebar only" toolbar with location bar works. 107TEST_F(ToolbarControllerTest, TitlebarOnly) { 108 NSView* view = [bar_ view]; 109 110 [bar_ setHasToolbar:NO hasLocationBar:YES]; 111 EXPECT_NE(view, [bar_ view]); 112 113 // Simulate a popup going fullscreen and back by performing the reparenting 114 // that happens during fullscreen transitions 115 NSView* superview = [view superview]; 116 [view removeFromSuperview]; 117 [superview addSubview:view]; 118 119 [bar_ setHasToolbar:YES hasLocationBar:YES]; 120 EXPECT_EQ(view, [bar_ view]); 121 122 // Leave it off to make sure that's fine 123 [bar_ setHasToolbar:NO hasLocationBar:YES]; 124} 125 126// Make sure it works in the completely undecorated case. 127TEST_F(ToolbarControllerTest, NoLocationBar) { 128 NSView* view = [bar_ view]; 129 130 [bar_ setHasToolbar:NO hasLocationBar:NO]; 131 EXPECT_NE(view, [bar_ view]); 132 EXPECT_TRUE([[bar_ view] isHidden]); 133 134 // Simulate a popup going fullscreen and back by performing the reparenting 135 // that happens during fullscreen transitions 136 NSView* superview = [view superview]; 137 [view removeFromSuperview]; 138 [superview addSubview:view]; 139} 140 141// Make some changes to the enabled state of a few of the buttons and ensure 142// that we're still in sync. 143TEST_F(ToolbarControllerTest, UpdateEnabledState) { 144 EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_BACK)); 145 EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_FORWARD)); 146 chrome::UpdateCommandEnabled(browser(), IDC_BACK, true); 147 chrome::UpdateCommandEnabled(browser(), IDC_FORWARD, true); 148 CommandUpdater* updater = browser()->command_controller()->command_updater(); 149 CompareState(updater, [bar_ toolbarViews]); 150} 151 152// Focus the location bar and make sure that it's the first responder. 153TEST_F(ToolbarControllerTest, FocusLocation) { 154 NSWindow* window = test_window(); 155 [window makeFirstResponder:[window contentView]]; 156 EXPECT_EQ([window firstResponder], [window contentView]); 157 [bar_ focusLocationBar:YES]; 158 EXPECT_NE([window firstResponder], [window contentView]); 159 NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex]; 160 EXPECT_EQ([window firstResponder], [(id)locationBar currentEditor]); 161} 162 163TEST_F(ToolbarControllerTest, LoadingState) { 164 // In its initial state, the reload button has a tag of 165 // IDC_RELOAD. When loading, it should be IDC_STOP. 166 NSButton* reload = [[bar_ toolbarViews] objectAtIndex:kReloadIndex]; 167 EXPECT_EQ([reload tag], IDC_RELOAD); 168 [bar_ setIsLoading:YES force:YES]; 169 EXPECT_EQ([reload tag], IDC_STOP); 170 [bar_ setIsLoading:NO force:YES]; 171 EXPECT_EQ([reload tag], IDC_RELOAD); 172} 173 174// Check that toggling the state of the home button changes the visible 175// state of the home button and moves the other items accordingly. 176TEST_F(ToolbarControllerTest, ToggleHome) { 177 PrefService* prefs = profile()->GetPrefs(); 178 bool showHome = prefs->GetBoolean(prefs::kShowHomeButton); 179 NSView* homeButton = [[bar_ toolbarViews] objectAtIndex:kHomeIndex]; 180 EXPECT_EQ(showHome, ![homeButton isHidden]); 181 182 NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex]; 183 NSRect originalLocationBarFrame = [locationBar frame]; 184 185 // Toggle the pref and make sure the button changed state and the other 186 // views moved. 187 prefs->SetBoolean(prefs::kShowHomeButton, !showHome); 188 EXPECT_EQ(showHome, [homeButton isHidden]); 189 EXPECT_NE(NSMinX(originalLocationBarFrame), NSMinX([locationBar frame])); 190 EXPECT_NE(NSWidth(originalLocationBarFrame), NSWidth([locationBar frame])); 191} 192 193// Ensure that we don't toggle the buttons when we have a strip marked as not 194// having the full toolbar. Also ensure that the location bar doesn't change 195// size. 196TEST_F(ToolbarControllerTest, DontToggleWhenNoToolbar) { 197 [bar_ setHasToolbar:NO hasLocationBar:YES]; 198 NSView* homeButton = [[bar_ toolbarViews] objectAtIndex:kHomeIndex]; 199 NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex]; 200 NSRect locationBarFrame = [locationBar frame]; 201 EXPECT_EQ([homeButton isHidden], YES); 202 [bar_ showOptionalHomeButton]; 203 EXPECT_EQ([homeButton isHidden], YES); 204 NSRect newLocationBarFrame = [locationBar frame]; 205 EXPECT_TRUE(NSEqualRects(locationBarFrame, newLocationBarFrame)); 206 newLocationBarFrame = [locationBar frame]; 207 EXPECT_TRUE(NSEqualRects(locationBarFrame, newLocationBarFrame)); 208} 209 210TEST_F(ToolbarControllerTest, BookmarkBubblePoint) { 211 const NSPoint starPoint = [bar_ bookmarkBubblePoint]; 212 const NSRect barFrame = 213 [[bar_ view] convertRect:[[bar_ view] bounds] toView:nil]; 214 215 // Make sure the star is completely inside the location bar. 216 EXPECT_TRUE(NSPointInRect(starPoint, barFrame)); 217} 218 219TEST_F(ToolbarControllerTest, HoverButtonForEvent) { 220 base::scoped_nsobject<HitView> view( 221 [[HitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]); 222 [bar_ setView:view]; 223 NSEvent* event = [NSEvent mouseEventWithType:NSMouseMoved 224 location:NSMakePoint(10,10) 225 modifierFlags:0 226 timestamp:0 227 windowNumber:0 228 context:nil 229 eventNumber:0 230 clickCount:0 231 pressure:0.0]; 232 233 // NOT a match. 234 [view setHitTestReturn:bar_.get()]; 235 EXPECT_FALSE([bar_ hoverButtonForEvent:event]); 236 237 // Not yet... 238 base::scoped_nsobject<NSButton> button([[NSButton alloc] init]); 239 [view setHitTestReturn:button]; 240 EXPECT_FALSE([bar_ hoverButtonForEvent:event]); 241 242 // Now! 243 base::scoped_nsobject<GradientButtonCell> cell( 244 [[GradientButtonCell alloc] init]); 245 [button setCell:cell.get()]; 246 EXPECT_TRUE([bar_ hoverButtonForEvent:nil]); 247} 248 249} // namespace 250