| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import <Cocoa/Cocoa.h> |
| |
| #include "base/mac/scoped_nsobject.h" |
| #include "base/strings/utf_string_conversions.h" |
| #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" |
| #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h" |
| #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h" |
| #import "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h" |
| #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h" |
| #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h" |
| #import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h" |
| #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h" |
| #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h" |
| #include "grit/theme_resources.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/platform_test.h" |
| #import "third_party/ocmock/OCMock/OCMock.h" |
| #include "third_party/ocmock/gtest_support.h" |
| #include "ui/base/resource/resource_bundle.h" |
| |
| using ::testing::Return; |
| using ::testing::StrictMock; |
| using ::testing::_; |
| |
| namespace { |
| |
| // Width of the field so that we don't have to ask |field_| for it all |
| // the time. |
| const CGFloat kWidth(300.0); |
| |
| // A narrow width for tests which test things that don't fit. |
| const CGFloat kNarrowWidth(5.0); |
| |
| class MockDecoration : public LocationBarDecoration { |
| public: |
| virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; } |
| |
| MOCK_METHOD2(DrawInFrame, void(NSRect frame, NSView* control_view)); |
| MOCK_METHOD0(GetToolTip, NSString*()); |
| }; |
| |
| class AutocompleteTextFieldCellTest : public CocoaTest { |
| public: |
| AutocompleteTextFieldCellTest() { |
| // Make sure this is wide enough to play games with the cell |
| // decorations. |
| const NSRect frame = NSMakeRect(0, 0, kWidth, 30); |
| |
| base::scoped_nsobject<NSTextField> view( |
| [[NSTextField alloc] initWithFrame:frame]); |
| view_ = view.get(); |
| |
| base::scoped_nsobject<AutocompleteTextFieldCell> cell( |
| [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]); |
| [cell setEditable:YES]; |
| [cell setBordered:YES]; |
| |
| [cell clearDecorations]; |
| mock_left_decoration_.SetVisible(false); |
| [cell addLeftDecoration:&mock_left_decoration_]; |
| mock_right_decoration0_.SetVisible(false); |
| mock_right_decoration1_.SetVisible(false); |
| [cell addRightDecoration:&mock_right_decoration0_]; |
| [cell addRightDecoration:&mock_right_decoration1_]; |
| |
| [view_ setCell:cell.get()]; |
| |
| [[test_window() contentView] addSubview:view_]; |
| } |
| |
| NSTextField* view_; |
| MockDecoration mock_left_decoration_; |
| MockDecoration mock_right_decoration0_; |
| MockDecoration mock_right_decoration1_; |
| }; |
| |
| // Basic view tests (AddRemove, Display). |
| TEST_VIEW(AutocompleteTextFieldCellTest, view_); |
| |
| // Test drawing, mostly to ensure nothing leaks or crashes. |
| // Flaky, disabled. Bug http://crbug.com/49522 |
| TEST_F(AutocompleteTextFieldCellTest, DISABLED_FocusedDisplay) { |
| [view_ display]; |
| |
| // Test focused drawing. |
| [test_window() makePretendKeyWindowAndSetFirstResponder:view_]; |
| [view_ display]; |
| [test_window() clearPretendKeyWindowAndFirstResponder]; |
| |
| // Test display of various cell configurations. |
| AutocompleteTextFieldCell* cell = |
| static_cast<AutocompleteTextFieldCell*>([view_ cell]); |
| |
| // Load available decorations and try drawing. To make sure that |
| // they are actually drawn, check that |GetWidthForSpace()| doesn't |
| // indicate that they should be omitted. |
| const CGFloat kVeryWide = 1000.0; |
| |
| SelectedKeywordDecoration selected_keyword_decoration; |
| selected_keyword_decoration.SetVisible(true); |
| selected_keyword_decoration.SetKeyword(ASCIIToUTF16("Google"), false); |
| [cell addLeftDecoration:&selected_keyword_decoration]; |
| EXPECT_NE(selected_keyword_decoration.GetWidthForSpace(kVeryWide), |
| LocationBarDecoration::kOmittedWidth); |
| |
| // TODO(shess): This really wants a |LocationBarViewMac|, but only a |
| // few methods reference it, so this works well enough. But |
| // something better would be nice. |
| LocationIconDecoration location_icon_decoration(NULL); |
| location_icon_decoration.SetVisible(true); |
| location_icon_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]); |
| [cell addLeftDecoration:&location_icon_decoration]; |
| EXPECT_NE(location_icon_decoration.GetWidthForSpace(kVeryWide), |
| LocationBarDecoration::kOmittedWidth); |
| |
| EVBubbleDecoration ev_bubble_decoration(&location_icon_decoration); |
| ev_bubble_decoration.SetVisible(true); |
| ev_bubble_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]); |
| ev_bubble_decoration.SetLabel(@"Application"); |
| [cell addLeftDecoration:&ev_bubble_decoration]; |
| EXPECT_NE(ev_bubble_decoration.GetWidthForSpace(kVeryWide), |
| LocationBarDecoration::kOmittedWidth); |
| |
| StarDecoration star_decoration(NULL); |
| star_decoration.SetVisible(true); |
| [cell addRightDecoration:&star_decoration]; |
| EXPECT_NE(star_decoration.GetWidthForSpace(kVeryWide), |
| LocationBarDecoration::kOmittedWidth); |
| |
| KeywordHintDecoration keyword_hint_decoration; |
| keyword_hint_decoration.SetVisible(true); |
| keyword_hint_decoration.SetKeyword(ASCIIToUTF16("google"), false); |
| [cell addRightDecoration:&keyword_hint_decoration]; |
| EXPECT_NE(keyword_hint_decoration.GetWidthForSpace(kVeryWide), |
| LocationBarDecoration::kOmittedWidth); |
| |
| // Make sure we're actually calling |DrawInFrame()|. |
| StrictMock<MockDecoration> mock_decoration; |
| mock_decoration.SetVisible(true); |
| [cell addLeftDecoration:&mock_decoration]; |
| EXPECT_CALL(mock_decoration, DrawInFrame(_, _)); |
| EXPECT_NE(mock_decoration.GetWidthForSpace(kVeryWide), |
| LocationBarDecoration::kOmittedWidth); |
| |
| [view_ display]; |
| |
| [cell clearDecorations]; |
| } |
| |
| TEST_F(AutocompleteTextFieldCellTest, TextFrame) { |
| AutocompleteTextFieldCell* cell = |
| static_cast<AutocompleteTextFieldCell*>([view_ cell]); |
| const NSRect bounds([view_ bounds]); |
| NSRect textFrame; |
| |
| // The cursor frame should stay the same throughout. |
| const NSRect cursorFrame([cell textCursorFrameForFrame:bounds]); |
| EXPECT_TRUE(NSEqualRects(cursorFrame, bounds)); |
| |
| // At default settings, everything goes to the text area. |
| textFrame = [cell textFrameForFrame:bounds]; |
| EXPECT_FALSE(NSIsEmptyRect(textFrame)); |
| EXPECT_TRUE(NSContainsRect(bounds, textFrame)); |
| EXPECT_EQ(NSMinX(bounds), NSMinX(textFrame)); |
| EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame)); |
| EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame)); |
| |
| // Decoration on the left takes up space. |
| mock_left_decoration_.SetVisible(true); |
| textFrame = [cell textFrameForFrame:bounds]; |
| EXPECT_FALSE(NSIsEmptyRect(textFrame)); |
| EXPECT_TRUE(NSContainsRect(bounds, textFrame)); |
| EXPECT_GT(NSMinX(textFrame), NSMinX(bounds)); |
| EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame)); |
| } |
| |
| // The editor frame should be slightly inset from the text frame. |
| TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) { |
| AutocompleteTextFieldCell* cell = |
| static_cast<AutocompleteTextFieldCell*>([view_ cell]); |
| const NSRect bounds([view_ bounds]); |
| NSRect textFrame, drawingRect; |
| |
| textFrame = [cell textFrameForFrame:bounds]; |
| drawingRect = [cell drawingRectForBounds:bounds]; |
| EXPECT_FALSE(NSIsEmptyRect(drawingRect)); |
| EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1))); |
| |
| // Save the starting frame for after clear. |
| const NSRect originalDrawingRect = drawingRect; |
| |
| mock_left_decoration_.SetVisible(true); |
| textFrame = [cell textFrameForFrame:bounds]; |
| drawingRect = [cell drawingRectForBounds:bounds]; |
| EXPECT_FALSE(NSIsEmptyRect(drawingRect)); |
| EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect)); |
| |
| mock_right_decoration0_.SetVisible(true); |
| textFrame = [cell textFrameForFrame:bounds]; |
| drawingRect = [cell drawingRectForBounds:bounds]; |
| EXPECT_FALSE(NSIsEmptyRect(drawingRect)); |
| EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect)); |
| |
| mock_left_decoration_.SetVisible(false); |
| mock_right_decoration0_.SetVisible(false); |
| drawingRect = [cell drawingRectForBounds:bounds]; |
| EXPECT_FALSE(NSIsEmptyRect(drawingRect)); |
| EXPECT_TRUE(NSEqualRects(drawingRect, originalDrawingRect)); |
| } |
| |
| // Test that left decorations are at the correct edge of the cell. |
| TEST_F(AutocompleteTextFieldCellTest, LeftDecorationFrame) { |
| AutocompleteTextFieldCell* cell = |
| static_cast<AutocompleteTextFieldCell*>([view_ cell]); |
| const NSRect bounds = [view_ bounds]; |
| |
| mock_left_decoration_.SetVisible(true); |
| const NSRect decorationRect = |
| [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds]; |
| EXPECT_FALSE(NSIsEmptyRect(decorationRect)); |
| EXPECT_TRUE(NSContainsRect(bounds, decorationRect)); |
| |
| // Decoration should be left of |drawingRect|. |
| const NSRect drawingRect = [cell drawingRectForBounds:bounds]; |
| EXPECT_GT(NSMinX(drawingRect), NSMinX(decorationRect)); |
| |
| // Decoration should be left of |textFrame|. |
| const NSRect textFrame = [cell textFrameForFrame:bounds]; |
| EXPECT_GT(NSMinX(textFrame), NSMinX(decorationRect)); |
| } |
| |
| // Test that right decorations are at the correct edge of the cell. |
| TEST_F(AutocompleteTextFieldCellTest, RightDecorationFrame) { |
| AutocompleteTextFieldCell* cell = |
| static_cast<AutocompleteTextFieldCell*>([view_ cell]); |
| const NSRect bounds = [view_ bounds]; |
| |
| mock_right_decoration0_.SetVisible(true); |
| mock_right_decoration1_.SetVisible(true); |
| |
| const NSRect decoration0Rect = |
| [cell frameForDecoration:&mock_right_decoration0_ inFrame:bounds]; |
| EXPECT_FALSE(NSIsEmptyRect(decoration0Rect)); |
| EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect)); |
| |
| // Right-side decorations are ordered from rightmost to leftmost. |
| // Outer decoration (0) to right of inner decoration (1). |
| const NSRect decoration1Rect = |
| [cell frameForDecoration:&mock_right_decoration1_ inFrame:bounds]; |
| EXPECT_FALSE(NSIsEmptyRect(decoration1Rect)); |
| EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect)); |
| EXPECT_LT(NSMinX(decoration1Rect), NSMinX(decoration0Rect)); |
| |
| // Decoration should be right of |drawingRect|. |
| const NSRect drawingRect = [cell drawingRectForBounds:bounds]; |
| EXPECT_LT(NSMinX(drawingRect), NSMinX(decoration1Rect)); |
| |
| // Decoration should be right of |textFrame|. |
| const NSRect textFrame = [cell textFrameForFrame:bounds]; |
| EXPECT_LT(NSMinX(textFrame), NSMinX(decoration1Rect)); |
| } |
| |
| // Verify -[AutocompleteTextFieldCell updateToolTipsInRect:ofView:]. |
| TEST_F(AutocompleteTextFieldCellTest, UpdateToolTips) { |
| NSString* tooltip = @"tooltip"; |
| |
| // Left decoration returns a tooltip, make sure it is called at |
| // least once. |
| mock_left_decoration_.SetVisible(true); |
| EXPECT_CALL(mock_left_decoration_, GetToolTip()) |
| .WillOnce(Return(tooltip)) |
| .WillRepeatedly(Return(tooltip)); |
| |
| // Right decoration returns no tooltip, make sure it is called at |
| // least once. |
| mock_right_decoration0_.SetVisible(true); |
| EXPECT_CALL(mock_right_decoration0_, GetToolTip()) |
| .WillOnce(Return((NSString*)nil)) |
| .WillRepeatedly(Return((NSString*)nil)); |
| |
| AutocompleteTextFieldCell* cell = |
| static_cast<AutocompleteTextFieldCell*>([view_ cell]); |
| const NSRect bounds = [view_ bounds]; |
| const NSRect leftDecorationRect = |
| [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds]; |
| |
| // |controlView| gets the tooltip for the left decoration. |
| id controlView = [OCMockObject mockForClass:[AutocompleteTextField class]]; |
| [[controlView expect] addToolTip:tooltip forRect:leftDecorationRect]; |
| |
| [cell updateToolTipsInRect:bounds ofView:controlView]; |
| |
| EXPECT_OCMOCK_VERIFY(controlView); |
| } |
| |
| } // namespace |