autocomplete_text_field_cell_unittest.mm revision ddb351dbec246cf1fab5ec20d2d5520909041de1
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
25using ::testing::Return;
26using ::testing::StrictMock;
27using ::testing::_;
28
29namespace {
30
31// Width of the field so that we don't have to ask |field_| for it all
32// the time.
33const CGFloat kWidth(300.0);
34
35// A narrow width for tests which test things that don't fit.
36const CGFloat kNarrowWidth(5.0);
37
38class 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
46class 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).
82TEST_VIEW(AutocompleteTextFieldCellTest, view_);
83
84// Test drawing, mostly to ensure nothing leaks or crashes.
85// Flaky, disabled. Bug http://crbug.com/49522
86TEST_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
155TEST_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.
183TEST_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.
217TEST_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.
238TEST_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:].
269TEST_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