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.
5 #import <Cocoa/Cocoa.h>
7 #include "base/mac/scoped_nsobject.h"
8 #include "base/strings/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 "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "testing/platform_test.h"
21 #import "third_party/ocmock/OCMock/OCMock.h"
22 #include "third_party/ocmock/gtest_support.h"
24 using ::testing::Return;
25 using ::testing::StrictMock;
30 // Width of the field so that we don't have to ask |field_| for it all
32 const CGFloat kWidth(300.0);
34 class MockDecoration : public LocationBarDecoration {
36 virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
38 MOCK_METHOD2(DrawInFrame, void(NSRect frame, NSView* control_view));
39 MOCK_METHOD0(GetToolTip, NSString*());
42 class AutocompleteTextFieldCellTest : public CocoaTest {
44 AutocompleteTextFieldCellTest() {
45 // Make sure this is wide enough to play games with the cell
47 const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
49 base::scoped_nsobject<NSTextField> view(
50 [[NSTextField alloc] initWithFrame:frame]);
53 base::scoped_nsobject<AutocompleteTextFieldCell> cell(
54 [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]);
55 [cell setEditable:YES];
56 [cell setBordered:YES];
58 [cell clearDecorations];
59 mock_left_decoration_.SetVisible(false);
60 [cell addLeftDecoration:&mock_left_decoration_];
61 mock_right_decoration0_.SetVisible(false);
62 mock_right_decoration1_.SetVisible(false);
63 [cell addRightDecoration:&mock_right_decoration0_];
64 [cell addRightDecoration:&mock_right_decoration1_];
66 [view_ setCell:cell.get()];
68 [[test_window() contentView] addSubview:view_];
72 MockDecoration mock_left_decoration_;
73 MockDecoration mock_right_decoration0_;
74 MockDecoration mock_right_decoration1_;
77 // Basic view tests (AddRemove, Display).
78 TEST_VIEW(AutocompleteTextFieldCellTest, view_);
80 // Test drawing, mostly to ensure nothing leaks or crashes.
81 // Flaky, disabled. Bug http://crbug.com/49522
82 TEST_F(AutocompleteTextFieldCellTest, DISABLED_FocusedDisplay) {
85 // Test focused drawing.
86 [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
88 [test_window() clearPretendKeyWindowAndFirstResponder];
90 // Test display of various cell configurations.
91 AutocompleteTextFieldCell* cell =
92 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
94 // Load available decorations and try drawing. To make sure that
95 // they are actually drawn, check that |GetWidthForSpace()| doesn't
96 // indicate that they should be omitted.
97 const CGFloat kVeryWide = 1000.0;
99 SelectedKeywordDecoration selected_keyword_decoration;
100 selected_keyword_decoration.SetVisible(true);
101 selected_keyword_decoration.SetKeyword(base::ASCIIToUTF16("Google"), false);
102 [cell addLeftDecoration:&selected_keyword_decoration];
103 EXPECT_NE(selected_keyword_decoration.GetWidthForSpace(kVeryWide),
104 LocationBarDecoration::kOmittedWidth);
106 // TODO(shess): This really wants a |LocationBarViewMac|, but only a
107 // few methods reference it, so this works well enough. But
108 // something better would be nice.
109 LocationIconDecoration location_icon_decoration(NULL);
110 location_icon_decoration.SetVisible(true);
111 location_icon_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
112 [cell addLeftDecoration:&location_icon_decoration];
113 EXPECT_NE(location_icon_decoration.GetWidthForSpace(kVeryWide),
114 LocationBarDecoration::kOmittedWidth);
116 EVBubbleDecoration ev_bubble_decoration(&location_icon_decoration);
117 ev_bubble_decoration.SetVisible(true);
118 ev_bubble_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
119 ev_bubble_decoration.SetLabel(@"Application");
120 [cell addLeftDecoration:&ev_bubble_decoration];
121 EXPECT_NE(ev_bubble_decoration.GetWidthForSpace(kVeryWide),
122 LocationBarDecoration::kOmittedWidth);
124 StarDecoration star_decoration(NULL);
125 star_decoration.SetVisible(true);
126 [cell addRightDecoration:&star_decoration];
127 EXPECT_NE(star_decoration.GetWidthForSpace(kVeryWide),
128 LocationBarDecoration::kOmittedWidth);
130 KeywordHintDecoration keyword_hint_decoration;
131 keyword_hint_decoration.SetVisible(true);
132 keyword_hint_decoration.SetKeyword(base::ASCIIToUTF16("google"), false);
133 [cell addRightDecoration:&keyword_hint_decoration];
134 EXPECT_NE(keyword_hint_decoration.GetWidthForSpace(kVeryWide),
135 LocationBarDecoration::kOmittedWidth);
137 // Make sure we're actually calling |DrawInFrame()|.
138 StrictMock<MockDecoration> mock_decoration;
139 mock_decoration.SetVisible(true);
140 [cell addLeftDecoration:&mock_decoration];
141 EXPECT_CALL(mock_decoration, DrawInFrame(_, _));
142 EXPECT_NE(mock_decoration.GetWidthForSpace(kVeryWide),
143 LocationBarDecoration::kOmittedWidth);
147 [cell clearDecorations];
150 TEST_F(AutocompleteTextFieldCellTest, TextFrame) {
151 AutocompleteTextFieldCell* cell =
152 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
153 const NSRect bounds([view_ bounds]);
156 // The cursor frame should stay the same throughout.
157 const NSRect cursorFrame([cell textCursorFrameForFrame:bounds]);
158 EXPECT_TRUE(NSEqualRects(cursorFrame, bounds));
160 // At default settings, everything goes to the text area.
161 textFrame = [cell textFrameForFrame:bounds];
162 EXPECT_FALSE(NSIsEmptyRect(textFrame));
163 EXPECT_TRUE(NSContainsRect(bounds, textFrame));
164 EXPECT_EQ(NSMinX(bounds), NSMinX(textFrame));
165 EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
166 EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
168 // Decoration on the left takes up space.
169 mock_left_decoration_.SetVisible(true);
170 textFrame = [cell textFrameForFrame:bounds];
171 EXPECT_FALSE(NSIsEmptyRect(textFrame));
172 EXPECT_TRUE(NSContainsRect(bounds, textFrame));
173 EXPECT_GT(NSMinX(textFrame), NSMinX(bounds));
174 EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
177 // The editor frame should be slightly inset from the text frame.
178 TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) {
179 AutocompleteTextFieldCell* cell =
180 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
181 const NSRect bounds([view_ bounds]);
182 NSRect textFrame, drawingRect;
184 textFrame = [cell textFrameForFrame:bounds];
185 drawingRect = [cell drawingRectForBounds:bounds];
186 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
187 EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
189 // Save the starting frame for after clear.
190 const NSRect originalDrawingRect = drawingRect;
192 mock_left_decoration_.SetVisible(true);
193 textFrame = [cell textFrameForFrame:bounds];
194 drawingRect = [cell drawingRectForBounds:bounds];
195 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
196 EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
198 mock_right_decoration0_.SetVisible(true);
199 textFrame = [cell textFrameForFrame:bounds];
200 drawingRect = [cell drawingRectForBounds:bounds];
201 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
202 EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
204 mock_left_decoration_.SetVisible(false);
205 mock_right_decoration0_.SetVisible(false);
206 drawingRect = [cell drawingRectForBounds:bounds];
207 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
208 EXPECT_TRUE(NSEqualRects(drawingRect, originalDrawingRect));
211 // Test that left decorations are at the correct edge of the cell.
212 TEST_F(AutocompleteTextFieldCellTest, LeftDecorationFrame) {
213 AutocompleteTextFieldCell* cell =
214 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
215 const NSRect bounds = [view_ bounds];
217 mock_left_decoration_.SetVisible(true);
218 const NSRect decorationRect =
219 [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
220 EXPECT_FALSE(NSIsEmptyRect(decorationRect));
221 EXPECT_TRUE(NSContainsRect(bounds, decorationRect));
223 // Decoration should be left of |drawingRect|.
224 const NSRect drawingRect = [cell drawingRectForBounds:bounds];
225 EXPECT_GT(NSMinX(drawingRect), NSMinX(decorationRect));
227 // Decoration should be left of |textFrame|.
228 const NSRect textFrame = [cell textFrameForFrame:bounds];
229 EXPECT_GT(NSMinX(textFrame), NSMinX(decorationRect));
232 // Test that right decorations are at the correct edge of the cell.
233 TEST_F(AutocompleteTextFieldCellTest, RightDecorationFrame) {
234 AutocompleteTextFieldCell* cell =
235 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
236 const NSRect bounds = [view_ bounds];
238 mock_right_decoration0_.SetVisible(true);
239 mock_right_decoration1_.SetVisible(true);
241 const NSRect decoration0Rect =
242 [cell frameForDecoration:&mock_right_decoration0_ inFrame:bounds];
243 EXPECT_FALSE(NSIsEmptyRect(decoration0Rect));
244 EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect));
246 // Right-side decorations are ordered from rightmost to leftmost.
247 // Outer decoration (0) to right of inner decoration (1).
248 const NSRect decoration1Rect =
249 [cell frameForDecoration:&mock_right_decoration1_ inFrame:bounds];
250 EXPECT_FALSE(NSIsEmptyRect(decoration1Rect));
251 EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect));
252 EXPECT_LT(NSMinX(decoration1Rect), NSMinX(decoration0Rect));
254 // Decoration should be right of |drawingRect|.
255 const NSRect drawingRect = [cell drawingRectForBounds:bounds];
256 EXPECT_LT(NSMinX(drawingRect), NSMinX(decoration1Rect));
258 // Decoration should be right of |textFrame|.
259 const NSRect textFrame = [cell textFrameForFrame:bounds];
260 EXPECT_LT(NSMinX(textFrame), NSMinX(decoration1Rect));
263 // Verify -[AutocompleteTextFieldCell updateToolTipsInRect:ofView:].
264 TEST_F(AutocompleteTextFieldCellTest, UpdateToolTips) {
265 NSString* tooltip = @"tooltip";
267 // Left decoration returns a tooltip, make sure it is called at
269 mock_left_decoration_.SetVisible(true);
270 EXPECT_CALL(mock_left_decoration_, GetToolTip())
271 .WillOnce(Return(tooltip))
272 .WillRepeatedly(Return(tooltip));
274 // Right decoration returns no tooltip, make sure it is called at
276 mock_right_decoration0_.SetVisible(true);
277 EXPECT_CALL(mock_right_decoration0_, GetToolTip())
278 .WillOnce(Return((NSString*)nil))
279 .WillRepeatedly(Return((NSString*)nil));
281 AutocompleteTextFieldCell* cell =
282 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
283 const NSRect bounds = [view_ bounds];
284 const NSRect leftDecorationRect =
285 [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
287 // |controlView| gets the tooltip for the left decoration.
288 id controlView = [OCMockObject mockForClass:[AutocompleteTextField class]];
289 [[controlView expect] addToolTip:tooltip forRect:leftDecorationRect];
291 [cell updateToolTipsInRect:bounds ofView:controlView];
293 EXPECT_OCMOCK_VERIFY(controlView);