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 #import "testing/gtest_mac.h"
21 #include "testing/platform_test.h"
22 #import "third_party/ocmock/OCMock/OCMock.h"
23 #include "third_party/ocmock/gtest_support.h"
25 using ::testing::Return;
26 using ::testing::StrictMock;
31 // Width of the field so that we don't have to ask |field_| for it all
33 const CGFloat kWidth(300.0);
35 class MockDecoration : public LocationBarDecoration {
37 virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
39 MOCK_METHOD2(DrawInFrame, void(NSRect frame, NSView* control_view));
40 MOCK_METHOD0(GetToolTip, NSString*());
43 class AutocompleteTextFieldCellTest : public CocoaTest {
45 AutocompleteTextFieldCellTest() {
46 // Make sure this is wide enough to play games with the cell
48 const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
50 base::scoped_nsobject<NSTextField> view(
51 [[NSTextField alloc] initWithFrame:frame]);
54 base::scoped_nsobject<AutocompleteTextFieldCell> cell(
55 [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]);
56 [cell setEditable:YES];
57 [cell setBordered:YES];
59 [cell clearDecorations];
60 mock_left_decoration_.SetVisible(false);
61 [cell addLeftDecoration:&mock_left_decoration_];
62 mock_right_decoration0_.SetVisible(false);
63 mock_right_decoration1_.SetVisible(false);
64 [cell addRightDecoration:&mock_right_decoration0_];
65 [cell addRightDecoration:&mock_right_decoration1_];
67 [view_ setCell:cell.get()];
69 [[test_window() contentView] addSubview:view_];
73 MockDecoration mock_left_decoration_;
74 MockDecoration mock_right_decoration0_;
75 MockDecoration mock_right_decoration1_;
78 // Basic view tests (AddRemove, Display).
79 TEST_VIEW(AutocompleteTextFieldCellTest, view_);
81 // Test drawing, mostly to ensure nothing leaks or crashes.
82 // Flaky, disabled. Bug http://crbug.com/49522
83 TEST_F(AutocompleteTextFieldCellTest, DISABLED_FocusedDisplay) {
86 // Test focused drawing.
87 [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
89 [test_window() clearPretendKeyWindowAndFirstResponder];
91 // Test display of various cell configurations.
92 AutocompleteTextFieldCell* cell =
93 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
95 // Load available decorations and try drawing. To make sure that
96 // they are actually drawn, check that |GetWidthForSpace()| doesn't
97 // indicate that they should be omitted.
98 const CGFloat kVeryWide = 1000.0;
100 SelectedKeywordDecoration selected_keyword_decoration;
101 selected_keyword_decoration.SetVisible(true);
102 selected_keyword_decoration.SetKeyword(base::ASCIIToUTF16("Google"), false);
103 [cell addLeftDecoration:&selected_keyword_decoration];
104 EXPECT_NE(selected_keyword_decoration.GetWidthForSpace(kVeryWide),
105 LocationBarDecoration::kOmittedWidth);
107 // TODO(shess): This really wants a |LocationBarViewMac|, but only a
108 // few methods reference it, so this works well enough. But
109 // something better would be nice.
110 LocationIconDecoration location_icon_decoration(NULL);
111 location_icon_decoration.SetVisible(true);
112 location_icon_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
113 [cell addLeftDecoration:&location_icon_decoration];
114 EXPECT_NE(location_icon_decoration.GetWidthForSpace(kVeryWide),
115 LocationBarDecoration::kOmittedWidth);
117 EVBubbleDecoration ev_bubble_decoration(&location_icon_decoration);
118 ev_bubble_decoration.SetVisible(true);
119 ev_bubble_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
120 ev_bubble_decoration.SetLabel(@"Application");
121 [cell addLeftDecoration:&ev_bubble_decoration];
122 EXPECT_NE(ev_bubble_decoration.GetWidthForSpace(kVeryWide),
123 LocationBarDecoration::kOmittedWidth);
125 StarDecoration star_decoration(NULL);
126 star_decoration.SetVisible(true);
127 [cell addRightDecoration:&star_decoration];
128 EXPECT_NE(star_decoration.GetWidthForSpace(kVeryWide),
129 LocationBarDecoration::kOmittedWidth);
131 KeywordHintDecoration keyword_hint_decoration;
132 keyword_hint_decoration.SetVisible(true);
133 keyword_hint_decoration.SetKeyword(base::ASCIIToUTF16("google"), false);
134 [cell addRightDecoration:&keyword_hint_decoration];
135 EXPECT_NE(keyword_hint_decoration.GetWidthForSpace(kVeryWide),
136 LocationBarDecoration::kOmittedWidth);
138 // Make sure we're actually calling |DrawInFrame()|.
139 StrictMock<MockDecoration> mock_decoration;
140 mock_decoration.SetVisible(true);
141 [cell addLeftDecoration:&mock_decoration];
142 EXPECT_CALL(mock_decoration, DrawInFrame(_, _));
143 EXPECT_NE(mock_decoration.GetWidthForSpace(kVeryWide),
144 LocationBarDecoration::kOmittedWidth);
148 [cell clearDecorations];
151 TEST_F(AutocompleteTextFieldCellTest, TextFrame) {
152 AutocompleteTextFieldCell* cell =
153 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
154 const NSRect bounds([view_ bounds]);
157 // The cursor frame should stay the same throughout.
158 const NSRect cursorFrame([cell textCursorFrameForFrame:bounds]);
159 EXPECT_NSEQ(cursorFrame, bounds);
161 // At default settings, everything goes to the text area.
162 textFrame = [cell textFrameForFrame:bounds];
163 EXPECT_FALSE(NSIsEmptyRect(textFrame));
164 EXPECT_TRUE(NSContainsRect(bounds, textFrame));
165 EXPECT_EQ(NSMinX(bounds), NSMinX(textFrame));
166 EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
167 EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
169 // Decoration on the left takes up space.
170 mock_left_decoration_.SetVisible(true);
171 textFrame = [cell textFrameForFrame:bounds];
172 EXPECT_FALSE(NSIsEmptyRect(textFrame));
173 EXPECT_TRUE(NSContainsRect(bounds, textFrame));
174 EXPECT_GT(NSMinX(textFrame), NSMinX(bounds));
175 EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
178 // The editor frame should be slightly inset from the text frame.
179 TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) {
180 AutocompleteTextFieldCell* cell =
181 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
182 const NSRect bounds([view_ bounds]);
183 NSRect textFrame, drawingRect;
185 textFrame = [cell textFrameForFrame:bounds];
186 drawingRect = [cell drawingRectForBounds:bounds];
187 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
188 EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
190 // Save the starting frame for after clear.
191 const NSRect originalDrawingRect = drawingRect;
193 mock_left_decoration_.SetVisible(true);
194 textFrame = [cell textFrameForFrame:bounds];
195 drawingRect = [cell drawingRectForBounds:bounds];
196 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
197 EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
199 mock_right_decoration0_.SetVisible(true);
200 textFrame = [cell textFrameForFrame:bounds];
201 drawingRect = [cell drawingRectForBounds:bounds];
202 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
203 EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
205 mock_left_decoration_.SetVisible(false);
206 mock_right_decoration0_.SetVisible(false);
207 drawingRect = [cell drawingRectForBounds:bounds];
208 EXPECT_FALSE(NSIsEmptyRect(drawingRect));
209 EXPECT_NSEQ(drawingRect, originalDrawingRect);
212 // Test that left decorations are at the correct edge of the cell.
213 TEST_F(AutocompleteTextFieldCellTest, LeftDecorationFrame) {
214 AutocompleteTextFieldCell* cell =
215 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
216 const NSRect bounds = [view_ bounds];
218 mock_left_decoration_.SetVisible(true);
219 const NSRect decorationRect =
220 [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
221 EXPECT_FALSE(NSIsEmptyRect(decorationRect));
222 EXPECT_TRUE(NSContainsRect(bounds, decorationRect));
224 // Decoration should be left of |drawingRect|.
225 const NSRect drawingRect = [cell drawingRectForBounds:bounds];
226 EXPECT_GT(NSMinX(drawingRect), NSMinX(decorationRect));
228 // Decoration should be left of |textFrame|.
229 const NSRect textFrame = [cell textFrameForFrame:bounds];
230 EXPECT_GT(NSMinX(textFrame), NSMinX(decorationRect));
233 // Test that right decorations are at the correct edge of the cell.
234 TEST_F(AutocompleteTextFieldCellTest, RightDecorationFrame) {
235 AutocompleteTextFieldCell* cell =
236 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
237 const NSRect bounds = [view_ bounds];
239 mock_right_decoration0_.SetVisible(true);
240 mock_right_decoration1_.SetVisible(true);
242 const NSRect decoration0Rect =
243 [cell frameForDecoration:&mock_right_decoration0_ inFrame:bounds];
244 EXPECT_FALSE(NSIsEmptyRect(decoration0Rect));
245 EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect));
247 // Right-side decorations are ordered from rightmost to leftmost.
248 // Outer decoration (0) to right of inner decoration (1).
249 const NSRect decoration1Rect =
250 [cell frameForDecoration:&mock_right_decoration1_ inFrame:bounds];
251 EXPECT_FALSE(NSIsEmptyRect(decoration1Rect));
252 EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect));
253 EXPECT_LT(NSMinX(decoration1Rect), NSMinX(decoration0Rect));
255 // Decoration should be right of |drawingRect|.
256 const NSRect drawingRect = [cell drawingRectForBounds:bounds];
257 EXPECT_LT(NSMinX(drawingRect), NSMinX(decoration1Rect));
259 // Decoration should be right of |textFrame|.
260 const NSRect textFrame = [cell textFrameForFrame:bounds];
261 EXPECT_LT(NSMinX(textFrame), NSMinX(decoration1Rect));
264 // Verify -[AutocompleteTextFieldCell updateToolTipsInRect:ofView:].
265 TEST_F(AutocompleteTextFieldCellTest, UpdateToolTips) {
266 NSString* tooltip = @"tooltip";
268 // Left decoration returns a tooltip, make sure it is called at
270 mock_left_decoration_.SetVisible(true);
271 EXPECT_CALL(mock_left_decoration_, GetToolTip())
272 .WillOnce(Return(tooltip))
273 .WillRepeatedly(Return(tooltip));
275 // Right decoration returns no tooltip, make sure it is called at
277 mock_right_decoration0_.SetVisible(true);
278 EXPECT_CALL(mock_right_decoration0_, GetToolTip())
279 .WillOnce(Return((NSString*)nil))
280 .WillRepeatedly(Return((NSString*)nil));
282 AutocompleteTextFieldCell* cell =
283 static_cast<AutocompleteTextFieldCell*>([view_ cell]);
284 const NSRect bounds = [view_ bounds];
285 const NSRect leftDecorationRect =
286 [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
288 // |controlView| gets the tooltip for the left decoration.
289 id controlView = [OCMockObject mockForClass:[AutocompleteTextField class]];
290 [[controlView expect] addToolTip:tooltip forRect:leftDecorationRect];
292 [cell updateToolTipsInRect:bounds ofView:controlView];
294 EXPECT_OCMOCK_VERIFY(controlView);