Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / location_bar / autocomplete_text_field_unittest.mm
blob6d138011b2687a550b13f28c65cb701d7d1a5b86
1 // Copyright (c) 2012 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 <ApplicationServices/ApplicationServices.h>
6 #import <Cocoa/Cocoa.h>
8 #include "base/mac/foundation_util.h"
9 #include "base/mac/scoped_nsobject.h"
10 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
11 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
12 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
13 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
14 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
15 #import "chrome/browser/ui/cocoa/location_bar/button_decoration.h"
16 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
17 #include "grit/theme_resources.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"
23 using ::testing::A;
24 using ::testing::InSequence;
25 using ::testing::Return;
26 using ::testing::ReturnArg;
27 using ::testing::StrictMock;
28 using ::testing::_;
30 namespace {
32 class MockDecoration : public LocationBarDecoration {
33  public:
34   virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
36   virtual void DrawInFrame(NSRect frame, NSView* control_view) { ; }
37   MOCK_METHOD0(AcceptsMousePress, bool());
38   MOCK_METHOD2(OnMousePressed, bool(NSRect frame, NSPoint location));
39   MOCK_METHOD0(GetMenu, NSMenu*());
42 class MockButtonDecoration : public ButtonDecoration {
43  public:
44   // Note: It does not matter which images are used here - but ButtonDecoration
45   // needs _some_ images to work properly.
46   MockButtonDecoration()
47       : ButtonDecoration(IMAGE_GRID(IDR_OMNIBOX_EV_BUBBLE),
48                          IDR_OMNIBOX_EV_BUBBLE_CENTER,
49                          IMAGE_GRID(IDR_OMNIBOX_EV_BUBBLE),
50                          IDR_OMNIBOX_EV_BUBBLE_CENTER,
51                          IMAGE_GRID(IDR_OMNIBOX_EV_BUBBLE),
52                          IDR_OMNIBOX_EV_BUBBLE_CENTER,
53                          3) {}
54   void Hide() { SetVisible(false); }
55   MOCK_METHOD2(OnMousePressed, bool(NSRect frame, NSPoint location));
58 // Mock up an incrementing event number.
59 NSUInteger eventNumber = 0;
61 // Create an event of the indicated |type| at |point| within |view|.
62 // TODO(shess): Would be nice to have a MockApplication which provided
63 // nifty accessors to create these things and inject them.  It could
64 // even provide functions for "Click and drag mouse from point A to
65 // point B".
66 // TODO(groby): This is very similar to cocoa_testing_utils - unify.
67 NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type,
68                const NSUInteger clickCount) {
69   NSWindow* window([view window]);
70   const NSPoint locationInWindow([view convertPoint:point toView:nil]);
71   const NSPoint location([window convertBaseToScreen:locationInWindow]);
72   return [NSEvent mouseEventWithType:type
73                             location:location
74                        modifierFlags:0
75                            timestamp:0
76                         windowNumber:[window windowNumber]
77                              context:nil
78                          eventNumber:eventNumber++
79                           clickCount:clickCount
80                             pressure:0.0];
82 NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type) {
83   return Event(view, point, type, 1);
86 // Width of the field so that we don't have to ask |field_| for it all
87 // the time.
88 static const CGFloat kWidth(300.0);
90 class AutocompleteTextFieldTest : public CocoaTest {
91  public:
92   AutocompleteTextFieldTest() {
93     // Make sure this is wide enough to play games with the cell
94     // decorations.
95     NSRect frame = NSMakeRect(0, 0, kWidth, 30);
96     base::scoped_nsobject<AutocompleteTextField> field(
97         [[AutocompleteTextField alloc] initWithFrame:frame]);
98     field_ = field.get();
99     [field_ setStringValue:@"Test test"];
100     [[test_window() contentView] addSubview:field_];
102     AutocompleteTextFieldCell* cell = [field_ cell];
103     [cell clearDecorations];
105     mock_left_decoration_.SetVisible(false);
106     [cell addLeftDecoration:&mock_left_decoration_];
108     mock_right_decoration_.SetVisible(false);
109     [cell addRightDecoration:&mock_right_decoration_];
111     window_delegate_.reset(
112         [[AutocompleteTextFieldWindowTestDelegate alloc] init]);
113     [test_window() setDelegate:window_delegate_.get()];
114   }
116   NSEvent* KeyDownEventWithFlags(NSUInteger flags) {
117     return [NSEvent keyEventWithType:NSKeyDown
118                             location:NSZeroPoint
119                        modifierFlags:flags
120                            timestamp:0.0
121                         windowNumber:[test_window() windowNumber]
122                              context:nil
123                           characters:@"a"
124          charactersIgnoringModifiers:@"a"
125                            isARepeat:NO
126                              keyCode:'a'];
127   }
129   // Helper to return the field-editor frame being used w/in |field_|.
130   NSRect EditorFrame() {
131     EXPECT_TRUE([field_ currentEditor]);
132     EXPECT_EQ([[field_ subviews] count], 1U);
133     if ([[field_ subviews] count] > 0) {
134       return [[[field_ subviews] objectAtIndex:0] frame];
135     } else {
136       // Return something which won't work so the caller can soldier
137       // on.
138       return NSZeroRect;
139     }
140   }
142   AutocompleteTextFieldEditor* FieldEditor() {
143     return base::mac::ObjCCastStrict<AutocompleteTextFieldEditor>(
144         [field_ currentEditor]);
145   }
147   AutocompleteTextField* field_;
148   MockDecoration mock_left_decoration_;
149   MockDecoration mock_right_decoration_;
150   base::scoped_nsobject<AutocompleteTextFieldWindowTestDelegate>
151       window_delegate_;
154 TEST_VIEW(AutocompleteTextFieldTest, field_);
156 // Base class for testing AutocompleteTextFieldObserver messages.
157 class AutocompleteTextFieldObserverTest : public AutocompleteTextFieldTest {
158  public:
159   virtual void SetUp() {
160     AutocompleteTextFieldTest::SetUp();
161     [field_ setObserver:&field_observer_];
162   }
164   virtual void TearDown() {
165     // Clear the observer so that we don't show output for
166     // uninteresting messages to the mock (for instance, if |field_| has
167     // focus at the end of the test).
168     [field_ setObserver:NULL];
170     AutocompleteTextFieldTest::TearDown();
171   }
173   StrictMock<MockAutocompleteTextFieldObserver> field_observer_;
176 // Test that we have the right cell class.
177 TEST_F(AutocompleteTextFieldTest, CellClass) {
178   EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]);
181 // Test that becoming first responder sets things up correctly.
182 TEST_F(AutocompleteTextFieldTest, FirstResponder) {
183   EXPECT_EQ(nil, [field_ currentEditor]);
184   EXPECT_EQ([[field_ subviews] count], 0U);
185   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
186   EXPECT_FALSE(nil == [field_ currentEditor]);
187   EXPECT_EQ([[field_ subviews] count], 1U);
188   EXPECT_TRUE([[field_ currentEditor] isDescendantOf:field_]);
190   // Check that the window delegate is providing the right editor.
191   Class c = [AutocompleteTextFieldEditor class];
192   EXPECT_TRUE([[field_ currentEditor] isKindOfClass:c]);
195 TEST_F(AutocompleteTextFieldTest, AvailableDecorationWidth) {
196   // A fudge factor to account for how much space the border takes up.
197   // The test shouldn't be too dependent on the field's internals, but
198   // it also shouldn't let deranged cases fall through the cracks
199   // (like nothing available with no text, or everything available
200   // with some text).
201   const CGFloat kBorderWidth = 20.0;
203   // With no contents, almost the entire width is available for
204   // decorations.
205   [field_ setStringValue:@""];
206   CGFloat availableWidth = [field_ availableDecorationWidth];
207   EXPECT_LE(availableWidth, kWidth);
208   EXPECT_GT(availableWidth, kWidth - kBorderWidth);
210   // With minor contents, most of the remaining width is available for
211   // decorations.
212   NSDictionary* attributes =
213       [NSDictionary dictionaryWithObject:[field_ font]
214                                   forKey:NSFontAttributeName];
215   NSString* string = @"Hello world";
216   const NSSize size([string sizeWithAttributes:attributes]);
217   [field_ setStringValue:string];
218   availableWidth = [field_ availableDecorationWidth];
219   EXPECT_LE(availableWidth, kWidth - size.width);
220   EXPECT_GT(availableWidth, kWidth - size.width - kBorderWidth);
222   // With huge contents, nothing at all is left for decorations.
223   string = @"A long string which is surely wider than field_ can hold.";
224   [field_ setStringValue:string];
225   availableWidth = [field_ availableDecorationWidth];
226   EXPECT_LT(availableWidth, 0.0);
229 // Test drawing, mostly to ensure nothing leaks or crashes.
230 TEST_F(AutocompleteTextFieldTest, Display) {
231   [field_ display];
233   // Test focussed drawing.
234   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
235   [field_ display];
238 // Test setting gray text, mostly to ensure nothing leaks or crashes.
239 TEST_F(AutocompleteTextFieldTest, GrayText) {
240   [field_ display];
241   EXPECT_FALSE([field_ needsDisplay]);
242   [field_ setGrayTextAutocompletion:@"foo" textColor:[NSColor redColor]];
243   EXPECT_TRUE([field_ needsDisplay]);
244   [field_ display];
247 TEST_F(AutocompleteTextFieldObserverTest, FlagsChanged) {
248   InSequence dummy;  // Call mock in exactly the order specified.
250   // Test without Control key down, but some other modifier down.
251   EXPECT_CALL(field_observer_, OnControlKeyChanged(false));
252   [field_ flagsChanged:KeyDownEventWithFlags(NSShiftKeyMask)];
254   // Test with Control key down.
255   EXPECT_CALL(field_observer_, OnControlKeyChanged(true));
256   [field_ flagsChanged:KeyDownEventWithFlags(NSControlKeyMask)];
259 // This test is here rather than in the editor's tests because the
260 // field catches -flagsChanged: because it's on the responder chain,
261 // the field editor doesn't implement it.
262 TEST_F(AutocompleteTextFieldObserverTest, FieldEditorFlagsChanged) {
263   // Many of these methods try to change the selection.
264   EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
265       .WillRepeatedly(ReturnArg<0>());
267   InSequence dummy;  // Call mock in exactly the order specified.
268   EXPECT_CALL(field_observer_, OnSetFocus(false));
269   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
270   NSResponder* firstResponder = [[field_ window] firstResponder];
271   EXPECT_EQ(firstResponder, [field_ currentEditor]);
273   // Test without Control key down, but some other modifier down.
274   EXPECT_CALL(field_observer_, OnControlKeyChanged(false));
275   [firstResponder flagsChanged:KeyDownEventWithFlags(NSShiftKeyMask)];
277   // Test with Control key down.
278   EXPECT_CALL(field_observer_, OnControlKeyChanged(true));
279   [firstResponder flagsChanged:KeyDownEventWithFlags(NSControlKeyMask)];
282 // Frame size changes are propagated to |observer_|.
283 TEST_F(AutocompleteTextFieldObserverTest, FrameChanged) {
284   EXPECT_CALL(field_observer_, OnFrameChanged());
285   NSRect frame = [field_ frame];
286   frame.size.width += 10.0;
287   [field_ setFrame:frame];
290 // Test that the field editor gets the same bounds when focus is
291 // delivered by the standard focusing machinery, or by
292 // -resetFieldEditorFrameIfNeeded.
293 TEST_F(AutocompleteTextFieldTest, ResetFieldEditorBase) {
294   // Capture the editor frame resulting from the standard focus
295   // machinery.
296   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
297   const NSRect baseEditorFrame = EditorFrame();
299   // A decoration should result in a strictly smaller editor frame.
300   mock_left_decoration_.SetVisible(true);
301   [field_ resetFieldEditorFrameIfNeeded];
302   EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
303   EXPECT_TRUE(NSContainsRect(baseEditorFrame, EditorFrame()));
305   // Removing the decoration and using -resetFieldEditorFrameIfNeeded
306   // should result in the same frame as the standard focus machinery.
307   mock_left_decoration_.SetVisible(false);
308   [field_ resetFieldEditorFrameIfNeeded];
309   EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
312 // Test that the field editor gets the same bounds when focus is
313 // delivered by the standard focusing machinery, or by
314 // -resetFieldEditorFrameIfNeeded, this time with a decoration
315 // pre-loaded.
316 TEST_F(AutocompleteTextFieldTest, ResetFieldEditorWithDecoration) {
317   AutocompleteTextFieldCell* cell = [field_ cell];
319   // Make sure decoration isn't already visible, then make it visible.
320   EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
321                                              inFrame:[field_ bounds]]));
322   mock_left_decoration_.SetVisible(true);
323   EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
324                                               inFrame:[field_ bounds]]));
326   // Capture the editor frame resulting from the standard focus
327   // machinery.
329   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
330   const NSRect baseEditorFrame = EditorFrame();
332   // When the decoration is not visible the frame should be strictly larger.
333   mock_left_decoration_.SetVisible(false);
334   EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
335                                              inFrame:[field_ bounds]]));
336   [field_ resetFieldEditorFrameIfNeeded];
337   EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
338   EXPECT_TRUE(NSContainsRect(EditorFrame(), baseEditorFrame));
340   // When the decoration is visible, -resetFieldEditorFrameIfNeeded
341   // should result in the same frame as the standard focus machinery.
342   mock_left_decoration_.SetVisible(true);
343   EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
344                                               inFrame:[field_ bounds]]));
346   [field_ resetFieldEditorFrameIfNeeded];
347   EXPECT_TRUE(NSEqualRects(baseEditorFrame, EditorFrame()));
350 // Test that resetting the field editor bounds does not cause untoward
351 // messages to the field's observer.
352 TEST_F(AutocompleteTextFieldObserverTest, ResetFieldEditorContinuesEditing) {
353   // Many of these methods try to change the selection.
354   EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
355       .WillRepeatedly(ReturnArg<0>());
357   EXPECT_CALL(field_observer_, OnSetFocus(false));
358   // Becoming first responder doesn't begin editing.
359   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
360   const NSRect baseEditorFrame = EditorFrame();
361   NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
362   EXPECT_TRUE(nil != editor);
364   // This should begin editing and indicate a change.
365   EXPECT_CALL(field_observer_, OnDidBeginEditing());
366   EXPECT_CALL(field_observer_, OnBeforeChange());
367   EXPECT_CALL(field_observer_, OnDidChange());
368   [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
369   [editor didChangeText];
371   // No messages to |field_observer_| when the frame actually changes.
372   mock_left_decoration_.SetVisible(true);
373   [field_ resetFieldEditorFrameIfNeeded];
374   EXPECT_FALSE(NSEqualRects(baseEditorFrame, EditorFrame()));
377 // Clicking in a right-hand decoration which does not handle the mouse
378 // puts the caret rightmost.
379 TEST_F(AutocompleteTextFieldTest, ClickRightDecorationPutsCaretRightmost) {
380   // Decoration does not handle the mouse event, so the cell should
381   // process it.  Called at least once.
382   EXPECT_CALL(mock_right_decoration_, AcceptsMousePress())
383       .WillOnce(Return(false))
384       .WillRepeatedly(Return(false));
386   // Set the decoration before becoming responder.
387   EXPECT_FALSE([field_ currentEditor]);
388   mock_right_decoration_.SetVisible(true);
390   // Make first responder should select all.
391   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
392   EXPECT_TRUE([field_ currentEditor]);
393   const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
394   EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
396   // Generate a click on the decoration.
397   AutocompleteTextFieldCell* cell = [field_ cell];
398   const NSRect bounds = [field_ bounds];
399   const NSRect iconFrame =
400       [cell frameForDecoration:&mock_right_decoration_ inFrame:bounds];
401   const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
402   NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
403   NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
404   [NSApp postEvent:upEvent atStart:YES];
405   [field_ mouseDown:downEvent];
407   // Selection should be a right-hand-side caret.
408   EXPECT_TRUE(NSEqualRanges(NSMakeRange([[field_ stringValue] length], 0),
409                             [[field_ currentEditor] selectedRange]));
412 // Clicking in a left-side decoration which doesn't handle the event
413 // puts the selection in the leftmost position.
414 TEST_F(AutocompleteTextFieldTest, ClickLeftDecorationPutsCaretLeftmost) {
415   // Decoration does not handle the mouse event, so the cell should
416   // process it.  Called at least once.
417   EXPECT_CALL(mock_left_decoration_, AcceptsMousePress())
418       .WillOnce(Return(false))
419       .WillRepeatedly(Return(false));
421   // Set the decoration before becoming responder.
422   EXPECT_FALSE([field_ currentEditor]);
423   mock_left_decoration_.SetVisible(true);
425   // Make first responder should select all.
426   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
427   EXPECT_TRUE([field_ currentEditor]);
428   const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
429   EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
431   // Generate a click on the decoration.
432   AutocompleteTextFieldCell* cell = [field_ cell];
433   const NSRect bounds = [field_ bounds];
434   const NSRect iconFrame =
435       [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
436   const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
437   NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
438   NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
439   [NSApp postEvent:upEvent atStart:YES];
440   [field_ mouseDown:downEvent];
442   // Selection should be a left-hand-side caret.
443   EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, 0),
444                             [[field_ currentEditor] selectedRange]));
447 // Clicks not in the text area or the cell's decorations fall through
448 // to the editor.
449 TEST_F(AutocompleteTextFieldTest, ClickBorderSelectsAll) {
450   // Can't rely on the window machinery to make us first responder,
451   // here.
452   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
453   EXPECT_TRUE([field_ currentEditor]);
455   const NSPoint point(NSMakePoint(20.0, 1.0));
456   NSEvent* downEvent(Event(field_, point, NSLeftMouseDown));
457   NSEvent* upEvent(Event(field_, point, NSLeftMouseUp));
458   [NSApp postEvent:upEvent atStart:YES];
459   [field_ mouseDown:downEvent];
461   // Clicking in the narrow border area around a Cocoa NSTextField
462   // does a select-all.  Regardless of whether this is a good call, it
463   // works as a test that things get passed down to the editor.
464   const NSRange selectedRange([[field_ currentEditor] selectedRange]);
465   EXPECT_EQ(selectedRange.location, 0U);
466   EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
469 // Single-click with no drag should setup a field editor and
470 // select all.
471 TEST_F(AutocompleteTextFieldTest, ClickSelectsAll) {
472   EXPECT_FALSE([field_ currentEditor]);
474   const NSPoint point = NSMakePoint(20.0, NSMidY([field_ bounds]));
475   NSEvent* downEvent(Event(field_, point, NSLeftMouseDown));
476   NSEvent* upEvent(Event(field_, point, NSLeftMouseUp));
477   [NSApp postEvent:upEvent atStart:YES];
478   [field_ mouseDown:downEvent];
479   EXPECT_TRUE([field_ currentEditor]);
480   const NSRange selectedRange([[field_ currentEditor] selectedRange]);
481   EXPECT_EQ(selectedRange.location, 0U);
482   EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
485 // Click-drag selects text, not select all.
486 TEST_F(AutocompleteTextFieldTest, ClickDragSelectsText) {
487   EXPECT_FALSE([field_ currentEditor]);
489   NSEvent* downEvent(Event(field_, NSMakePoint(20.0, 5.0), NSLeftMouseDown));
490   NSEvent* upEvent(Event(field_, NSMakePoint(0.0, 5.0), NSLeftMouseUp));
491   [NSApp postEvent:upEvent atStart:YES];
492   [field_ mouseDown:downEvent];
493   EXPECT_TRUE([field_ currentEditor]);
495   // Expect this to have selected a prefix of the content.  Mostly
496   // just don't want the select-all behavior.
497   const NSRange selectedRange([[field_ currentEditor] selectedRange]);
498   EXPECT_EQ(selectedRange.location, 0U);
499   EXPECT_LT(selectedRange.length, [[field_ stringValue] length]);
502 // TODO(shess): Test that click/pause/click allows cursor placement.
503 // In this case the first click goes to the field, but the second
504 // click goes to the field editor, so the current testing pattern
505 // can't work.  What really needs to happen is to push through the
506 // NSWindow event machinery so that we can say "two independent clicks
507 // at the same location have the right effect".  Once that is done, it
508 // might make sense to revise the other tests to use the same
509 // machinery.
511 // Double-click selects word, not select all.
512 TEST_F(AutocompleteTextFieldTest, DoubleClickSelectsWord) {
513   EXPECT_FALSE([field_ currentEditor]);
515   const NSPoint point = NSMakePoint(20.0, NSMidY([field_ bounds]));
516   NSEvent* downEvent(Event(field_, point, NSLeftMouseDown, 1));
517   NSEvent* upEvent(Event(field_, point, NSLeftMouseUp, 1));
518   NSEvent* downEvent2(Event(field_, point, NSLeftMouseDown, 2));
519   NSEvent* upEvent2(Event(field_, point, NSLeftMouseUp, 2));
520   [NSApp postEvent:upEvent atStart:YES];
521   [field_ mouseDown:downEvent];
522   [NSApp postEvent:upEvent2 atStart:YES];
523   [field_ mouseDown:downEvent2];
524   EXPECT_TRUE([field_ currentEditor]);
526   // Selected the first word.
527   const NSRange selectedRange([[field_ currentEditor] selectedRange]);
528   const NSRange spaceRange([[field_ stringValue] rangeOfString:@" "]);
529   EXPECT_GT(spaceRange.location, 0U);
530   EXPECT_LT(spaceRange.length, [[field_ stringValue] length]);
531   EXPECT_EQ(selectedRange.location, 0U);
532   EXPECT_EQ(selectedRange.length, spaceRange.location);
535 TEST_F(AutocompleteTextFieldTest, TripleClickSelectsAll) {
536   EXPECT_FALSE([field_ currentEditor]);
538   const NSPoint point(NSMakePoint(20.0, 5.0));
539   NSEvent* downEvent(Event(field_, point, NSLeftMouseDown, 1));
540   NSEvent* upEvent(Event(field_, point, NSLeftMouseUp, 1));
541   NSEvent* downEvent2(Event(field_, point, NSLeftMouseDown, 2));
542   NSEvent* upEvent2(Event(field_, point, NSLeftMouseUp, 2));
543   NSEvent* downEvent3(Event(field_, point, NSLeftMouseDown, 3));
544   NSEvent* upEvent3(Event(field_, point, NSLeftMouseUp, 3));
545   [NSApp postEvent:upEvent atStart:YES];
546   [field_ mouseDown:downEvent];
547   [NSApp postEvent:upEvent2 atStart:YES];
548   [field_ mouseDown:downEvent2];
549   [NSApp postEvent:upEvent3 atStart:YES];
550   [field_ mouseDown:downEvent3];
551   EXPECT_TRUE([field_ currentEditor]);
553   // Selected the first word.
554   const NSRange selectedRange([[field_ currentEditor] selectedRange]);
555   EXPECT_EQ(selectedRange.location, 0U);
556   EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
559 // Clicking a decoration should call decoration's OnMousePressed.
560 TEST_F(AutocompleteTextFieldTest, LeftDecorationMouseDown) {
561   // At this point, not focussed.
562   EXPECT_FALSE([field_ currentEditor]);
564   mock_left_decoration_.SetVisible(true);
565   EXPECT_CALL(mock_left_decoration_, AcceptsMousePress())
566       .WillRepeatedly(Return(true));
568   AutocompleteTextFieldCell* cell = [field_ cell];
569   const NSRect iconFrame =
570       [cell frameForDecoration:&mock_left_decoration_ inFrame:[field_ bounds]];
571   const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
572   NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1);
573   NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1);
575   // Since decorations can be dragged, the mouse-press is sent on
576   // mouse-up.
577   [NSApp postEvent:upEvent atStart:YES];
579   EXPECT_CALL(mock_left_decoration_, OnMousePressed(_, _))
580       .WillOnce(Return(true));
581   [field_ mouseDown:downEvent];
583   // Focus the field and test that handled clicks don't affect selection.
584   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
585   EXPECT_TRUE([field_ currentEditor]);
586   const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
587   EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
589   // Generate another click on the decoration.
590   downEvent = Event(field_, location, NSLeftMouseDown, 1);
591   upEvent = Event(field_, location, NSLeftMouseUp, 1);
592   [NSApp postEvent:upEvent atStart:YES];
593   EXPECT_CALL(mock_left_decoration_, OnMousePressed(_, _))
594       .WillOnce(Return(true));
595   [field_ mouseDown:downEvent];
597   // The selection should not have changed.
598   EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
600   // TODO(shess): Test that mouse drags are initiated if the next
601   // event is a drag, or if the mouse-up takes too long to arrive.
602   // IDEA: mock decoration to return a pasteboard which a mock
603   // AutocompleteTextField notes in -dragImage:*.
606 // Clicking a decoration should call decoration's OnMousePressed.
607 TEST_F(AutocompleteTextFieldTest, RightDecorationMouseDown) {
608   // At this point, not focussed.
609   EXPECT_FALSE([field_ currentEditor]);
611   mock_right_decoration_.SetVisible(true);
612   EXPECT_CALL(mock_right_decoration_, AcceptsMousePress())
613       .WillRepeatedly(Return(true));
615   AutocompleteTextFieldCell* cell = [field_ cell];
616   const NSRect bounds = [field_ bounds];
617   const NSRect iconFrame =
618       [cell frameForDecoration:&mock_right_decoration_ inFrame:bounds];
619   const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
620   NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1);
621   NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1);
623   // Since decorations can be dragged, the mouse-press is sent on
624   // mouse-up.
625   [NSApp postEvent:upEvent atStart:YES];
627   EXPECT_CALL(mock_right_decoration_, OnMousePressed(_, _))
628       .WillOnce(Return(true));
629   [field_ mouseDown:downEvent];
632 // Test that page action menus are properly returned.
633 // TODO(shess): Really, this should test that things are forwarded to
634 // the cell, and the cell tests should test that the right things are
635 // selected.  It's easier to mock the event here, though.  This code's
636 // event-mockers might be worth promoting to |cocoa_test_event_utils.h| or
637 // |cocoa_test_helper.h|.
638 TEST_F(AutocompleteTextFieldTest, DecorationMenu) {
639   AutocompleteTextFieldCell* cell = [field_ cell];
640   const NSRect bounds([field_ bounds]);
642   const CGFloat edge = NSHeight(bounds) - 4.0;
643   const NSSize size = NSMakeSize(edge, edge);
644   base::scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:size]);
646   base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
648   mock_left_decoration_.SetVisible(true);
649   mock_right_decoration_.SetVisible(true);
651   // The item with a menu returns it.
652   NSRect actionFrame = [cell frameForDecoration:&mock_right_decoration_
653                                         inFrame:bounds];
654   NSPoint location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame));
655   NSEvent* event = Event(field_, location, NSRightMouseDown, 1);
657   // Check that the decoration is called, and the field returns the
658   // menu.
659   EXPECT_CALL(mock_right_decoration_, GetMenu())
660       .WillOnce(Return(menu.get()));
661   NSMenu *decorationMenu = [field_ decorationMenuForEvent:event];
662   EXPECT_EQ(decorationMenu, menu);
664   // The item without a menu returns nil.
665   EXPECT_CALL(mock_left_decoration_, GetMenu())
666       .WillOnce(Return(static_cast<NSMenu*>(nil)));
667   actionFrame = [cell frameForDecoration:&mock_left_decoration_
668                                  inFrame:bounds];
669   location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame));
670   event = Event(field_, location, NSRightMouseDown, 1);
671   EXPECT_FALSE([field_ decorationMenuForEvent:event]);
673   // Something not in an action returns nil.
674   location = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
675   event = Event(field_, location, NSRightMouseDown, 1);
676   EXPECT_FALSE([field_ decorationMenuForEvent:event]);
679 // Verify that -setAttributedStringValue: works as expected when
680 // focussed or when not focussed.  Our code mostly depends on about
681 // whether -stringValue works right.
682 TEST_F(AutocompleteTextFieldTest, SetAttributedStringBaseline) {
683   EXPECT_EQ(nil, [field_ currentEditor]);
685   // So that we can set rich text.
686   [field_ setAllowsEditingTextAttributes:YES];
688   // Set an attribute different from the field's default so we can
689   // tell we got the same string out as we put in.
690   NSFont* font = [NSFont fontWithDescriptor:[[field_ font] fontDescriptor]
691                                        size:[[field_ font] pointSize] + 2];
692   NSDictionary* attributes =
693       [NSDictionary dictionaryWithObject:font
694                                   forKey:NSFontAttributeName];
695   NSString* const kString = @"This is a test";
696   base::scoped_nsobject<NSAttributedString> attributedString(
697       [[NSAttributedString alloc] initWithString:kString
698                                       attributes:attributes]);
700   // Check that what we get back looks like what we put in.
701   EXPECT_NSNE(kString, [field_ stringValue]);
702   [field_ setAttributedStringValue:attributedString];
703   EXPECT_TRUE([[field_ attributedStringValue]
704                 isEqualToAttributedString:attributedString]);
705   EXPECT_NSEQ(kString, [field_ stringValue]);
707   // Try that again with focus.
708   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
710   EXPECT_TRUE([field_ currentEditor]);
712   // Check that what we get back looks like what we put in.
713   [field_ setStringValue:@""];
714   EXPECT_NSNE(kString, [field_ stringValue]);
715   [field_ setAttributedStringValue:attributedString];
716   EXPECT_TRUE([[field_ attributedStringValue]
717                 isEqualToAttributedString:attributedString]);
718   EXPECT_NSEQ(kString, [field_ stringValue]);
721 // -setAttributedStringValue: shouldn't reset the undo state if things
722 // are being editted.
723 TEST_F(AutocompleteTextFieldTest, SetAttributedStringUndo) {
724   NSColor* redColor = [NSColor redColor];
725   NSDictionary* attributes =
726       [NSDictionary dictionaryWithObject:redColor
727                                   forKey:NSForegroundColorAttributeName];
728   NSString* const kString = @"This is a test";
729   base::scoped_nsobject<NSAttributedString> attributedString(
730       [[NSAttributedString alloc] initWithString:kString
731                                       attributes:attributes]);
732   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
733   EXPECT_TRUE([field_ currentEditor]);
734   NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
735   NSUndoManager* undoManager = [editor undoManager];
736   EXPECT_TRUE(undoManager);
738   // Nothing to undo, yet.
739   EXPECT_FALSE([undoManager canUndo]);
741   // Starting an editing action creates an undoable item.
742   [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
743   [editor didChangeText];
744   EXPECT_TRUE([undoManager canUndo]);
746   // -setStringValue: resets the editor's undo chain.
747   [field_ setStringValue:kString];
748   EXPECT_FALSE([undoManager canUndo]);
750   // Verify that -setAttributedStringValue: does not reset the
751   // editor's undo chain.
752   [field_ setStringValue:@""];
753   [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
754   [editor didChangeText];
755   EXPECT_TRUE([undoManager canUndo]);
756   [field_ setAttributedStringValue:attributedString];
757   EXPECT_TRUE([undoManager canUndo]);
759   // Verify that calling -clearUndoChain clears the undo chain.
760   [field_ clearUndoChain];
761   EXPECT_FALSE([undoManager canUndo]);
764 TEST_F(AutocompleteTextFieldTest, EditorGetsCorrectUndoManager) {
765   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
767   NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
768   EXPECT_TRUE(editor);
769   EXPECT_EQ([field_ undoManagerForTextView:editor], [editor undoManager]);
772 // Verify that hideFocusState correctly hides the focus ring and insertion
773 // pointer.
774 TEST_F(AutocompleteTextFieldTest, HideFocusState) {
775   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
776   [[field_ cell] setShowsFirstResponder:YES];
778   EXPECT_TRUE([[field_ cell] showsFirstResponder]);
779   EXPECT_TRUE([FieldEditor() shouldDrawInsertionPoint]);
781   [[field_ cell] setHideFocusState:YES
782                             ofView:field_];
783   EXPECT_FALSE([[field_ cell] showsFirstResponder]);
784   EXPECT_FALSE([FieldEditor() shouldDrawInsertionPoint]);
786   [[field_ cell] setHideFocusState:NO
787                             ofView:field_];
788   EXPECT_TRUE([[field_ cell] showsFirstResponder]);
789   EXPECT_TRUE([FieldEditor() shouldDrawInsertionPoint]);
792 // Verify that OnSetFocus for button decorations is only sent after the
793 // decoration is picked as the target for the subsequent -mouseDown:. Otherwise
794 // hiding a ButtonDecoration in OnSetFocus will prevent a call to
795 // OnMousePressed, since it is already hidden at the time of mouseDown.
796 TEST_F(AutocompleteTextFieldObserverTest, ButtonDecorationFocus) {
797   // Add the mock button.
798   MockButtonDecoration mock_button;
799   mock_button.SetVisible(true);
800   AutocompleteTextFieldCell* cell = [field_ cell];
801   [cell addLeftDecoration:&mock_button];
803   // Ensure button is hidden when OnSetFocus() is called.
804   EXPECT_CALL(field_observer_, OnSetFocus(false)).WillOnce(
805       testing::InvokeWithoutArgs(&mock_button, &MockButtonDecoration::Hide));
807   // Ignore incidental calls.
808   EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(_))
809       .WillRepeatedly(testing::Return(NSMakeRange(0, 0)));
810   EXPECT_CALL(field_observer_, OnMouseDown(_));
812   // Still expect an OnMousePressed on the button.
813   EXPECT_CALL(mock_button, OnMousePressed(_, _))
814       .WillOnce(testing::Return(true));
816   // Get click point for button decoration.
817   NSRect button_rect =
818       [cell frameForDecoration:&mock_button inFrame:[field_ bounds]];
819   EXPECT_FALSE(NSIsEmptyRect(button_rect));
820   NSPoint click_location =
821       NSMakePoint(NSMidX(button_rect), NSMidY(button_rect));
823   // Ensure the field is currently not first responder.
824   [test_window() makePretendKeyWindowAndSetFirstResponder:nil];
825   EXPECT_NSNE([[field_ window] firstResponder], field_);
827   // Execute button click event sequence.
828   NSEvent* downEvent = Event(field_, click_location, NSLeftMouseDown);
829   NSEvent* upEvent = Event(field_, click_location, NSLeftMouseUp);
831   // Can't just use -sendEvent:, since that doesn't populate -currentEvent.
832   [NSApp postEvent:downEvent atStart:YES];
833   [NSApp postEvent:upEvent atStart:NO];
834   NSEvent* next_event = [NSApp nextEventMatchingMask:NSAnyEventMask
835                                            untilDate:nil
836                                               inMode:NSDefaultRunLoopMode
837                                              dequeue:YES];
838   [NSApp sendEvent:next_event];
840   // Expectations check that both OnSetFocus and OnMouseDown were called.
841   // Additionally, ensure button is hidden and field is firstResponder.
842   EXPECT_FALSE(mock_button.IsVisible());
843   EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
844                                              inFrame:[field_ bounds]]));
845   EXPECT_TRUE([base::mac::ObjCCastStrict<NSView>(
846       [[field_ window] firstResponder]) isDescendantOf:field_]);
849 TEST_F(AutocompleteTextFieldObserverTest, SendsEditingMessages) {
850   // Many of these methods try to change the selection.
851   EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
852       .WillRepeatedly(ReturnArg<0>());
854   EXPECT_CALL(field_observer_, OnSetFocus(false));
855   // Becoming first responder doesn't begin editing.
856   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
857   NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
858   EXPECT_TRUE(nil != editor);
860   // This should begin editing and indicate a change.
861   EXPECT_CALL(field_observer_, OnDidBeginEditing());
862   EXPECT_CALL(field_observer_, OnBeforeChange());
863   EXPECT_CALL(field_observer_, OnDidChange());
864   [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
865   [editor didChangeText];
867   // Further changes don't send the begin message.
868   EXPECT_CALL(field_observer_, OnBeforeChange());
869   EXPECT_CALL(field_observer_, OnDidChange());
870   [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
871   [editor didChangeText];
873   // -doCommandBySelector: should forward to observer via |field_|.
874   // TODO(shess): Test with a fake arrow-key event?
875   const SEL cmd = @selector(moveDown:);
876   EXPECT_CALL(field_observer_, OnDoCommandBySelector(cmd))
877       .WillOnce(Return(true));
878   [editor doCommandBySelector:cmd];
880   // Finished with the changes.
881   EXPECT_CALL(field_observer_, OnKillFocus());
882   EXPECT_CALL(field_observer_, OnDidEndEditing());
883   [test_window() clearPretendKeyWindowAndFirstResponder];
886 // Test that the resign-key notification is forwarded right, and that
887 // the notification is registered and unregistered when the view moves
888 // in and out of the window.
889 // TODO(shess): Should this test the key window for realz?  That would
890 // be really annoying to whoever is running the tests.
891 TEST_F(AutocompleteTextFieldObserverTest, ClosePopupOnResignKey) {
892   EXPECT_CALL(field_observer_, ClosePopup());
893   [test_window() resignKeyWindow];
895   base::scoped_nsobject<AutocompleteTextField> pin([field_ retain]);
896   [field_ removeFromSuperview];
897   [test_window() resignKeyWindow];
899   [[test_window() contentView] addSubview:field_];
900   EXPECT_CALL(field_observer_, ClosePopup());
901   [test_window() resignKeyWindow];
904 }  // namespace