• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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