Home | History | Annotate | Download | only in location_bar
      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 #include "base/memory/scoped_nsobject.h"
      8 #include "base/utf_string_conversions.h"
      9 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
     10 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
     11 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
     12 #import "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h"
     13 #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
     14 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
     15 #import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
     16 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
     17 #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
     18 #include "grit/theme_resources.h"
     19 #include "testing/gmock/include/gmock/gmock.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 #include "testing/platform_test.h"
     22 #import "third_party/ocmock/OCMock/OCMock.h"
     23 #include "ui/base/resource/resource_bundle.h"
     24 
     25 using ::testing::Return;
     26 using ::testing::StrictMock;
     27 using ::testing::_;
     28 
     29 namespace {
     30 
     31 // Width of the field so that we don't have to ask |field_| for it all
     32 // the time.
     33 const CGFloat kWidth(300.0);
     34 
     35 // A narrow width for tests which test things that don't fit.
     36 const CGFloat kNarrowWidth(5.0);
     37 
     38 class MockDecoration : public LocationBarDecoration {
     39  public:
     40   virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
     41 
     42   MOCK_METHOD2(DrawInFrame, void(NSRect frame, NSView* control_view));
     43   MOCK_METHOD0(GetToolTip, NSString*());
     44 };
     45 
     46 class AutocompleteTextFieldCellTest : public CocoaTest {
     47  public:
     48   AutocompleteTextFieldCellTest() {
     49     // Make sure this is wide enough to play games with the cell
     50     // decorations.
     51     const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
     52 
     53     scoped_nsobject<NSTextField> view(
     54         [[NSTextField alloc] initWithFrame:frame]);
     55     view_ = view.get();
     56 
     57     scoped_nsobject<AutocompleteTextFieldCell> cell(
     58         [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]);
     59     [cell setEditable:YES];
     60     [cell setBordered:YES];
     61 
     62     [cell clearDecorations];
     63     mock_left_decoration_.SetVisible(false);
     64     [cell addLeftDecoration:&mock_left_decoration_];
     65     mock_right_decoration0_.SetVisible(false);
     66     mock_right_decoration1_.SetVisible(false);
     67     [cell addRightDecoration:&mock_right_decoration0_];
     68     [cell addRightDecoration:&mock_right_decoration1_];
     69 
     70     [view_ setCell:cell.get()];
     71 
     72     [[test_window() contentView] addSubview:view_];
     73   }
     74 
     75   NSTextField* view_;
     76   MockDecoration mock_left_decoration_;
     77   MockDecoration mock_right_decoration0_;
     78   MockDecoration mock_right_decoration1_;
     79 };
     80 
     81 // Basic view tests (AddRemove, Display).
     82 TEST_VIEW(AutocompleteTextFieldCellTest, view_);
     83 
     84 // Test drawing, mostly to ensure nothing leaks or crashes.
     85 // Flaky, disabled. Bug http://crbug.com/49522
     86 TEST_F(AutocompleteTextFieldCellTest, DISABLED_FocusedDisplay) {
     87   [view_ display];
     88 
     89   // Test focused drawing.
     90   [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
     91   [view_ display];
     92   [test_window() clearPretendKeyWindowAndFirstResponder];
     93 
     94   // Test display of various cell configurations.
     95   AutocompleteTextFieldCell* cell =
     96       static_cast<AutocompleteTextFieldCell*>([view_ cell]);
     97 
     98   // Load available decorations and try drawing.  To make sure that
     99   // they are actually drawn, check that |GetWidthForSpace()| doesn't
    100   // indicate that they should be omitted.
    101   const CGFloat kVeryWide = 1000.0;
    102 
    103   SelectedKeywordDecoration selected_keyword_decoration([view_ font]);
    104   selected_keyword_decoration.SetVisible(true);
    105   selected_keyword_decoration.SetKeyword(ASCIIToUTF16("Google"), false);
    106   [cell addLeftDecoration:&selected_keyword_decoration];
    107   EXPECT_NE(selected_keyword_decoration.GetWidthForSpace(kVeryWide),
    108             LocationBarDecoration::kOmittedWidth);
    109 
    110   // TODO(shess): This really wants a |LocationBarViewMac|, but only a
    111   // few methods reference it, so this works well enough.  But
    112   // something better would be nice.
    113   LocationIconDecoration location_icon_decoration(NULL);
    114   location_icon_decoration.SetVisible(true);
    115   location_icon_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
    116   [cell addLeftDecoration:&location_icon_decoration];
    117   EXPECT_NE(location_icon_decoration.GetWidthForSpace(kVeryWide),
    118             LocationBarDecoration::kOmittedWidth);
    119 
    120   EVBubbleDecoration ev_bubble_decoration(&location_icon_decoration,
    121                                           [view_ font]);
    122   ev_bubble_decoration.SetVisible(true);
    123   ev_bubble_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
    124   ev_bubble_decoration.SetLabel(@"Application");
    125   [cell addLeftDecoration:&ev_bubble_decoration];
    126   EXPECT_NE(ev_bubble_decoration.GetWidthForSpace(kVeryWide),
    127             LocationBarDecoration::kOmittedWidth);
    128 
    129   StarDecoration star_decoration(NULL);
    130   star_decoration.SetVisible(true);
    131   [cell addRightDecoration:&star_decoration];
    132   EXPECT_NE(star_decoration.GetWidthForSpace(kVeryWide),
    133             LocationBarDecoration::kOmittedWidth);
    134 
    135   KeywordHintDecoration keyword_hint_decoration([view_ font]);
    136   keyword_hint_decoration.SetVisible(true);
    137   keyword_hint_decoration.SetKeyword(ASCIIToUTF16("google"), false);
    138   [cell addRightDecoration:&keyword_hint_decoration];
    139   EXPECT_NE(keyword_hint_decoration.GetWidthForSpace(kVeryWide),
    140             LocationBarDecoration::kOmittedWidth);
    141 
    142   // Make sure we're actually calling |DrawInFrame()|.
    143   StrictMock<MockDecoration> mock_decoration;
    144   mock_decoration.SetVisible(true);
    145   [cell addLeftDecoration:&mock_decoration];
    146   EXPECT_CALL(mock_decoration, DrawInFrame(_, _));
    147   EXPECT_NE(mock_decoration.GetWidthForSpace(kVeryWide),
    148             LocationBarDecoration::kOmittedWidth);
    149 
    150   [view_ display];
    151 
    152   [cell clearDecorations];
    153 }
    154 
    155 TEST_F(AutocompleteTextFieldCellTest, TextFrame) {
    156   AutocompleteTextFieldCell* cell =
    157       static_cast<AutocompleteTextFieldCell*>([view_ cell]);
    158   const NSRect bounds([view_ bounds]);
    159   NSRect textFrame;
    160 
    161   // The cursor frame should stay the same throughout.
    162   const NSRect cursorFrame([cell textCursorFrameForFrame:bounds]);
    163   EXPECT_TRUE(NSEqualRects(cursorFrame, bounds));
    164 
    165   // At default settings, everything goes to the text area.
    166   textFrame = [cell textFrameForFrame:bounds];
    167   EXPECT_FALSE(NSIsEmptyRect(textFrame));
    168   EXPECT_TRUE(NSContainsRect(bounds, textFrame));
    169   EXPECT_EQ(NSMinX(bounds), NSMinX(textFrame));
    170   EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
    171   EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
    172 
    173   // Decoration on the left takes up space.
    174   mock_left_decoration_.SetVisible(true);
    175   textFrame = [cell textFrameForFrame:bounds];
    176   EXPECT_FALSE(NSIsEmptyRect(textFrame));
    177   EXPECT_TRUE(NSContainsRect(bounds, textFrame));
    178   EXPECT_GT(NSMinX(textFrame), NSMinX(bounds));
    179   EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
    180 }
    181 
    182 // The editor frame should be slightly inset from the text frame.
    183 TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) {
    184   AutocompleteTextFieldCell* cell =
    185       static_cast<AutocompleteTextFieldCell*>([view_ cell]);
    186   const NSRect bounds([view_ bounds]);
    187   NSRect textFrame, drawingRect;
    188 
    189   textFrame = [cell textFrameForFrame:bounds];
    190   drawingRect = [cell drawingRectForBounds:bounds];
    191   EXPECT_FALSE(NSIsEmptyRect(drawingRect));
    192   EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
    193 
    194   // Save the starting frame for after clear.
    195   const NSRect originalDrawingRect = drawingRect;
    196 
    197   mock_left_decoration_.SetVisible(true);
    198   textFrame = [cell textFrameForFrame:bounds];
    199   drawingRect = [cell drawingRectForBounds:bounds];
    200   EXPECT_FALSE(NSIsEmptyRect(drawingRect));
    201   EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
    202 
    203   mock_right_decoration0_.SetVisible(true);
    204   textFrame = [cell textFrameForFrame:bounds];
    205   drawingRect = [cell drawingRectForBounds:bounds];
    206   EXPECT_FALSE(NSIsEmptyRect(drawingRect));
    207   EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
    208 
    209   mock_left_decoration_.SetVisible(false);
    210   mock_right_decoration0_.SetVisible(false);
    211   drawingRect = [cell drawingRectForBounds:bounds];
    212   EXPECT_FALSE(NSIsEmptyRect(drawingRect));
    213   EXPECT_TRUE(NSEqualRects(drawingRect, originalDrawingRect));
    214 }
    215 
    216 // Test that left decorations are at the correct edge of the cell.
    217 TEST_F(AutocompleteTextFieldCellTest, LeftDecorationFrame) {
    218   AutocompleteTextFieldCell* cell =
    219       static_cast<AutocompleteTextFieldCell*>([view_ cell]);
    220   const NSRect bounds = [view_ bounds];
    221 
    222   mock_left_decoration_.SetVisible(true);
    223   const NSRect decorationRect =
    224       [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
    225   EXPECT_FALSE(NSIsEmptyRect(decorationRect));
    226   EXPECT_TRUE(NSContainsRect(bounds, decorationRect));
    227 
    228   // Decoration should be left of |drawingRect|.
    229   const NSRect drawingRect = [cell drawingRectForBounds:bounds];
    230   EXPECT_GT(NSMinX(drawingRect), NSMinX(decorationRect));
    231 
    232   // Decoration should be left of |textFrame|.
    233   const NSRect textFrame = [cell textFrameForFrame:bounds];
    234   EXPECT_GT(NSMinX(textFrame), NSMinX(decorationRect));
    235 }
    236 
    237 // Test that right decorations are at the correct edge of the cell.
    238 TEST_F(AutocompleteTextFieldCellTest, RightDecorationFrame) {
    239   AutocompleteTextFieldCell* cell =
    240       static_cast<AutocompleteTextFieldCell*>([view_ cell]);
    241   const NSRect bounds = [view_ bounds];
    242 
    243   mock_right_decoration0_.SetVisible(true);
    244   mock_right_decoration1_.SetVisible(true);
    245 
    246   const NSRect decoration0Rect =
    247       [cell frameForDecoration:&mock_right_decoration0_ inFrame:bounds];
    248   EXPECT_FALSE(NSIsEmptyRect(decoration0Rect));
    249   EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect));
    250 
    251   // Right-side decorations are ordered from rightmost to leftmost.
    252   // Outer decoration (0) to right of inner decoration (1).
    253   const NSRect decoration1Rect =
    254       [cell frameForDecoration:&mock_right_decoration1_ inFrame:bounds];
    255   EXPECT_FALSE(NSIsEmptyRect(decoration1Rect));
    256   EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect));
    257   EXPECT_LT(NSMinX(decoration1Rect), NSMinX(decoration0Rect));
    258 
    259   // Decoration should be right of |drawingRect|.
    260   const NSRect drawingRect = [cell drawingRectForBounds:bounds];
    261   EXPECT_LT(NSMinX(drawingRect), NSMinX(decoration1Rect));
    262 
    263   // Decoration should be right of |textFrame|.
    264   const NSRect textFrame = [cell textFrameForFrame:bounds];
    265   EXPECT_LT(NSMinX(textFrame), NSMinX(decoration1Rect));
    266 }
    267 
    268 // Verify -[AutocompleteTextFieldCell updateToolTipsInRect:ofView:].
    269 TEST_F(AutocompleteTextFieldCellTest, UpdateToolTips) {
    270   NSString* tooltip = @"tooltip";
    271 
    272   // Left decoration returns a tooltip, make sure it is called at
    273   // least once.
    274   mock_left_decoration_.SetVisible(true);
    275   EXPECT_CALL(mock_left_decoration_, GetToolTip())
    276       .WillOnce(Return(tooltip))
    277       .WillRepeatedly(Return(tooltip));
    278 
    279   // Right decoration returns no tooltip, make sure it is called at
    280   // least once.
    281   mock_right_decoration0_.SetVisible(true);
    282   EXPECT_CALL(mock_right_decoration0_, GetToolTip())
    283       .WillOnce(Return((NSString*)nil))
    284       .WillRepeatedly(Return((NSString*)nil));
    285 
    286   AutocompleteTextFieldCell* cell =
    287       static_cast<AutocompleteTextFieldCell*>([view_ cell]);
    288   const NSRect bounds = [view_ bounds];
    289   const NSRect leftDecorationRect =
    290       [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
    291 
    292   // |controlView| gets the tooltip for the left decoration.
    293   id controlView = [OCMockObject mockForClass:[AutocompleteTextField class]];
    294   [[controlView expect] addToolTip:tooltip forRect:leftDecorationRect];
    295 
    296   [cell updateToolTipsInRect:bounds ofView:controlView];
    297 
    298   [controlView verify];
    299 }
    300 
    301 }  // namespace
    302