Home | History | Annotate | Download | only in toolbar
      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 
     38 namespace {
     39 
     40 class 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 
     87 TEST_VIEW(ToolbarControllerTest, [bar_ view])
     88 
     89 // Test the initial state that everything is sync'd up
     90 TEST_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.
     96 TEST_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.
    116 TEST_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.
    132 TEST_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.
    142 TEST_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 
    152 TEST_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.
    165 TEST_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.
    185 TEST_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 
    199 TEST_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 
    208 TEST_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