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