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 "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 "third_party/ocmock/gtest_support.h"
24 #include "ui/base/resource/resource_bundle.h"
26 using ::testing::Return;
27 using ::testing::StrictMock;
32 // Width of the field so that we don't have to ask |field_| for it all
34 const CGFloat kWidth(300.0);
36 class MockDecoration : public LocationBarDecoration {
38 virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
40 MOCK_METHOD2(DrawInFrame, void(NSRect frame, NSView* control_view));
41 MOCK_METHOD0(GetToolTip, NSString*());
44 class AutocompleteTextFieldCellTest : public CocoaTest {
46 AutocompleteTextFieldCellTest() {
47 // Make sure this is wide enough to play games with the cell
49 const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
51 base::scoped_nsobject<NSTextField> view(
52 [[NSTextField alloc] initWithFrame:frame]);
55 base::scoped_nsobject<AutocompleteTextFieldCell> cell(
56 [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]);
57 [cell setEditable:YES];
58 [cell setBordered:YES];
60 [cell clearDecorations];
61 mock_left_decoration_.SetVisible(false);
62 [cell addLeftDecoration:&mock_left_decoration_];
63 mock_right_decoration0_.SetVisible(false);
64 mock_right_decoration1_.SetVisible(false);
65 [cell addRightDecoration:&mock_right_decoration0_];
66 [cell addRightDecoration:&mock_right_decoration1_];
68 [view_ setCell:cell.get()];
70 [[test_window() contentView] addSubview:view_];
74 MockDecoration mock_left_decoration_;
75 MockDecoration mock_right_decoration0_;
76 MockDecoration mock_right_decoration1_;
79 // Basic view tests (AddRemove, Display).
80 TEST_VIEW(AutocompleteTextFieldCellTest, view_);
82 // Test drawing, mostly to ensure nothing leaks or crashes.
83 // Flaky, disabled. Bug http://crbug.com/49522
84 TEST_F(AutocompleteTextFieldCellTest, DISABLED_FocusedDisplay) {
87 // Test focused drawing.
88 [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
90 [test_window() clearPretendKeyWindowAndFirstResponder];
92 // Test display of various cell configurations.
93 AutocompleteTextFieldCell* cell =
94 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
96 // Load available decorations and try drawing. To make sure that
97 // they are actually drawn, check that |GetWidthForSpace()| doesn't
98 // indicate that they should be omitted.
99 const CGFloat kVeryWide = 1000.0;
101 SelectedKeywordDecoration selected_keyword_decoration;
102 selected_keyword_decoration.SetVisible(true);
103 selected_keyword_decoration.SetKeyword(base::ASCIIToUTF16("Google"), false);
104 [cell addLeftDecoration:&selected_keyword_decoration];
105 EXPECT_NE(selected_keyword_decoration.GetWidthForSpace(kVeryWide),
106 LocationBarDecoration::kOmittedWidth);
108 // TODO(shess): This really wants a |LocationBarViewMac|, but only a
109 // few methods reference it, so this works well enough. But
110 // something better would be nice.
111 LocationIconDecoration location_icon_decoration(NULL);
112 location_icon_decoration.SetVisible(true);
113 location_icon_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
114 [cell addLeftDecoration:&location_icon_decoration];
115 EXPECT_NE(location_icon_decoration.GetWidthForSpace(kVeryWide),
116 LocationBarDecoration::kOmittedWidth);
118 EVBubbleDecoration ev_bubble_decoration(&location_icon_decoration);
119 ev_bubble_decoration.SetVisible(true);
120 ev_bubble_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
121 ev_bubble_decoration.SetLabel(@"Application");
122 [cell addLeftDecoration:&ev_bubble_decoration];
123 EXPECT_NE(ev_bubble_decoration.GetWidthForSpace(kVeryWide),
124 LocationBarDecoration::kOmittedWidth);
126 StarDecoration star_decoration(NULL);
127 star_decoration.SetVisible(true);
128 [cell addRightDecoration:&star_decoration];
129 EXPECT_NE(star_decoration.GetWidthForSpace(kVeryWide),
130 LocationBarDecoration::kOmittedWidth);
132 KeywordHintDecoration keyword_hint_decoration;
133 keyword_hint_decoration.SetVisible(true);
134 keyword_hint_decoration.SetKeyword(base::ASCIIToUTF16("google"), false);
135 [cell addRightDecoration:&keyword_hint_decoration];
136 EXPECT_NE(keyword_hint_decoration.GetWidthForSpace(kVeryWide),
137 LocationBarDecoration::kOmittedWidth);
139 // Make sure we're actually calling |DrawInFrame()|.
140 StrictMock<MockDecoration> mock_decoration;
141 mock_decoration.SetVisible(true);
142 [cell addLeftDecoration:&mock_decoration];
143 EXPECT_CALL(mock_decoration, DrawInFrame(_, _));
144 EXPECT_NE(mock_decoration.GetWidthForSpace(kVeryWide),
145 LocationBarDecoration::kOmittedWidth);
149 [cell clearDecorations];
152 TEST_F(AutocompleteTextFieldCellTest, TextFrame) {
153 AutocompleteTextFieldCell* cell =
154 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
155 const NSRect bounds([view_ bounds]);
158 // The cursor frame should stay the same throughout.
159 const NSRect cursorFrame([cell textCursorFrameForFrame:bounds]);
160 EXPECT_TRUE(NSEqualRects(cursorFrame, bounds));
162 // At default settings, everything goes to the text area.
163 textFrame = [cell textFrameForFrame:bounds];
164 EXPECT_FALSE(NSIsEmptyRect(textFrame));
165 EXPECT_TRUE(NSContainsRect(bounds, textFrame));
166 EXPECT_EQ(NSMinX(bounds), NSMinX(textFrame));
167 EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
168 EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
170 // Decoration on the left takes up space.
171 mock_left_decoration_.SetVisible(true);
172 textFrame = [cell textFrameForFrame:bounds];
173 EXPECT_FALSE(NSIsEmptyRect(textFrame));
174 EXPECT_TRUE(NSContainsRect(bounds, textFrame));
175 EXPECT_GT(NSMinX(textFrame), NSMinX(bounds));
176 EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
179 // The editor frame should be slightly inset from the text frame.
180 TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) {
181 AutocompleteTextFieldCell* cell =
182 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
183 const NSRect bounds([view_ bounds]);
184 NSRect textFrame, drawingRect;
186 textFrame = [cell textFrameForFrame:bounds];
187 drawingRect = [cell drawingRectForBounds:bounds];
188 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
189 EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
191 // Save the starting frame for after clear.
192 const NSRect originalDrawingRect = drawingRect;
194 mock_left_decoration_.SetVisible(true);
195 textFrame = [cell textFrameForFrame:bounds];
196 drawingRect = [cell drawingRectForBounds:bounds];
197 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
198 EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
200 mock_right_decoration0_.SetVisible(true);
201 textFrame = [cell textFrameForFrame:bounds];
202 drawingRect = [cell drawingRectForBounds:bounds];
203 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
204 EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
206 mock_left_decoration_.SetVisible(false);
207 mock_right_decoration0_.SetVisible(false);
208 drawingRect = [cell drawingRectForBounds:bounds];
209 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
210 EXPECT_TRUE(NSEqualRects(drawingRect, originalDrawingRect));
213 // Test that left decorations are at the correct edge of the cell.
214 TEST_F(AutocompleteTextFieldCellTest, LeftDecorationFrame) {
215 AutocompleteTextFieldCell* cell =
216 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
217 const NSRect bounds = [view_ bounds];
219 mock_left_decoration_.SetVisible(true);
220 const NSRect decorationRect =
221 [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
222 EXPECT_FALSE(NSIsEmptyRect(decorationRect));
223 EXPECT_TRUE(NSContainsRect(bounds, decorationRect));
225 // Decoration should be left of |drawingRect|.
226 const NSRect drawingRect = [cell drawingRectForBounds:bounds];
227 EXPECT_GT(NSMinX(drawingRect), NSMinX(decorationRect));
229 // Decoration should be left of |textFrame|.
230 const NSRect textFrame = [cell textFrameForFrame:bounds];
231 EXPECT_GT(NSMinX(textFrame), NSMinX(decorationRect));
234 // Test that right decorations are at the correct edge of the cell.
235 TEST_F(AutocompleteTextFieldCellTest, RightDecorationFrame) {
236 AutocompleteTextFieldCell* cell =
237 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
238 const NSRect bounds = [view_ bounds];
240 mock_right_decoration0_.SetVisible(true);
241 mock_right_decoration1_.SetVisible(true);
243 const NSRect decoration0Rect =
244 [cell frameForDecoration:&mock_right_decoration0_ inFrame:bounds];
245 EXPECT_FALSE(NSIsEmptyRect(decoration0Rect));
246 EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect));
248 // Right-side decorations are ordered from rightmost to leftmost.
249 // Outer decoration (0) to right of inner decoration (1).
250 const NSRect decoration1Rect =
251 [cell frameForDecoration:&mock_right_decoration1_ inFrame:bounds];
252 EXPECT_FALSE(NSIsEmptyRect(decoration1Rect));
253 EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect));
254 EXPECT_LT(NSMinX(decoration1Rect), NSMinX(decoration0Rect));
256 // Decoration should be right of |drawingRect|.
257 const NSRect drawingRect = [cell drawingRectForBounds:bounds];
258 EXPECT_LT(NSMinX(drawingRect), NSMinX(decoration1Rect));
260 // Decoration should be right of |textFrame|.
261 const NSRect textFrame = [cell textFrameForFrame:bounds];
262 EXPECT_LT(NSMinX(textFrame), NSMinX(decoration1Rect));
265 // Verify -[AutocompleteTextFieldCell updateToolTipsInRect:ofView:].
266 TEST_F(AutocompleteTextFieldCellTest, UpdateToolTips) {
267 NSString* tooltip = @"tooltip";
269 // Left decoration returns a tooltip, make sure it is called at
271 mock_left_decoration_.SetVisible(true);
272 EXPECT_CALL(mock_left_decoration_, GetToolTip())
273 .WillOnce(Return(tooltip))
274 .WillRepeatedly(Return(tooltip));
276 // Right decoration returns no tooltip, make sure it is called at
278 mock_right_decoration0_.SetVisible(true);
279 EXPECT_CALL(mock_right_decoration0_, GetToolTip())
280 .WillOnce(Return((NSString*)nil))
281 .WillRepeatedly(Return((NSString*)nil));
283 AutocompleteTextFieldCell* cell =
284 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
285 const NSRect bounds = [view_ bounds];
286 const NSRect leftDecorationRect =
287 [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
289 // |controlView| gets the tooltip for the left decoration.
290 id controlView = [OCMockObject mockForClass:[AutocompleteTextField class]];
291 [[controlView expect] addToolTip:tooltip forRect:leftDecorationRect];
293 [cell updateToolTipsInRect:bounds ofView:controlView];
295 EXPECT_OCMOCK_VERIFY(controlView);