OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import <ApplicationServices/ApplicationServices.h> | 5 #import <ApplicationServices/ApplicationServices.h> |
6 #import <Cocoa/Cocoa.h> | 6 #import <Cocoa/Cocoa.h> |
7 | 7 |
8 #include "base/mac/foundation_util.h" | 8 #include "base/mac/foundation_util.h" |
9 #include "base/mac/scoped_nsobject.h" | 9 #include "base/mac/scoped_nsobject.h" |
10 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" | 10 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" |
(...skipping 21 matching lines...) Expand all Loading... | |
32 class MockDecoration : public LocationBarDecoration { | 32 class MockDecoration : public LocationBarDecoration { |
33 public: | 33 public: |
34 virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; } | 34 virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; } |
35 | 35 |
36 virtual void DrawInFrame(NSRect frame, NSView* control_view) { ; } | 36 virtual void DrawInFrame(NSRect frame, NSView* control_view) { ; } |
37 MOCK_METHOD0(AcceptsMousePress, bool()); | 37 MOCK_METHOD0(AcceptsMousePress, bool()); |
38 MOCK_METHOD2(OnMousePressed, bool(NSRect frame, NSPoint location)); | 38 MOCK_METHOD2(OnMousePressed, bool(NSRect frame, NSPoint location)); |
39 MOCK_METHOD0(GetMenu, NSMenu*()); | 39 MOCK_METHOD0(GetMenu, NSMenu*()); |
40 }; | 40 }; |
41 | 41 |
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)); | |
56 }; | |
57 | |
58 // Mock up an incrementing event number. | 42 // Mock up an incrementing event number. |
59 NSUInteger eventNumber = 0; | 43 NSUInteger eventNumber = 0; |
60 | 44 |
61 // Create an event of the indicated |type| at |point| within |view|. | 45 // Create an event of the indicated |type| at |point| within |view|. |
62 // TODO(shess): Would be nice to have a MockApplication which provided | 46 // TODO(shess): Would be nice to have a MockApplication which provided |
63 // nifty accessors to create these things and inject them. It could | 47 // nifty accessors to create these things and inject them. It could |
64 // even provide functions for "Click and drag mouse from point A to | 48 // even provide functions for "Click and drag mouse from point A to |
65 // point B". | 49 // point B". |
66 // TODO(groby): This is very similar to cocoa_testing_utils - unify. | 50 // TODO(groby): This is very similar to cocoa_testing_utils - unify. |
67 NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type, | 51 NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type, |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
163 | 147 |
164 virtual void TearDown() { | 148 virtual void TearDown() { |
165 // Clear the observer so that we don't show output for | 149 // Clear the observer so that we don't show output for |
166 // uninteresting messages to the mock (for instance, if |field_| has | 150 // uninteresting messages to the mock (for instance, if |field_| has |
167 // focus at the end of the test). | 151 // focus at the end of the test). |
168 [field_ setObserver:NULL]; | 152 [field_ setObserver:NULL]; |
169 | 153 |
170 AutocompleteTextFieldTest::TearDown(); | 154 AutocompleteTextFieldTest::TearDown(); |
171 } | 155 } |
172 | 156 |
157 // Returns the center point of the decoration. | |
158 NSPoint ClickLocationForDecoration(LocationBarDecoration* decoration) { | |
159 AutocompleteTextFieldCell* cell = [field_ cell]; | |
160 NSRect decoration_rect = | |
161 [cell frameForDecoration:decoration inFrame:[field_ bounds]]; | |
162 EXPECT_FALSE(NSIsEmptyRect(decoration_rect)); | |
163 return NSMakePoint(NSMidX(decoration_rect), NSMidY(decoration_rect)); | |
164 } | |
165 | |
166 void SendMouseClickToDecoration(LocationBarDecoration* decoration) { | |
167 NSPoint point = ClickLocationForDecoration(decoration); | |
168 NSEvent* downEvent = Event(field_, point, NSLeftMouseDown); | |
169 NSEvent* upEvent = Event(field_, point, NSLeftMouseUp); | |
170 | |
171 // Can't just use -sendEvent:, since that doesn't populate -currentEvent. | |
172 [NSApp postEvent:downEvent atStart:YES]; | |
173 [NSApp postEvent:upEvent atStart:NO]; | |
174 | |
175 NSEvent* next_event = [NSApp nextEventMatchingMask:NSAnyEventMask | |
176 untilDate:nil | |
177 inMode:NSDefaultRunLoopMode | |
178 dequeue:YES]; | |
179 [NSApp sendEvent:next_event]; | |
180 } | |
181 | |
173 StrictMock<MockAutocompleteTextFieldObserver> field_observer_; | 182 StrictMock<MockAutocompleteTextFieldObserver> field_observer_; |
174 }; | 183 }; |
175 | 184 |
176 // Test that we have the right cell class. | 185 // Test that we have the right cell class. |
177 TEST_F(AutocompleteTextFieldTest, CellClass) { | 186 TEST_F(AutocompleteTextFieldTest, CellClass) { |
178 EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]); | 187 EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]); |
179 } | 188 } |
180 | 189 |
181 // Test that becoming first responder sets things up correctly. | 190 // Test that becoming first responder sets things up correctly. |
182 TEST_F(AutocompleteTextFieldTest, FirstResponder) { | 191 TEST_F(AutocompleteTextFieldTest, FirstResponder) { |
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
587 EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange])); | 596 EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange])); |
588 | 597 |
589 // Generate another click on the decoration. | 598 // Generate another click on the decoration. |
590 downEvent = Event(field_, location, NSLeftMouseDown, 1); | 599 downEvent = Event(field_, location, NSLeftMouseDown, 1); |
591 upEvent = Event(field_, location, NSLeftMouseUp, 1); | 600 upEvent = Event(field_, location, NSLeftMouseUp, 1); |
592 [NSApp postEvent:upEvent atStart:YES]; | 601 [NSApp postEvent:upEvent atStart:YES]; |
593 EXPECT_CALL(mock_left_decoration_, OnMousePressed(_, _)) | 602 EXPECT_CALL(mock_left_decoration_, OnMousePressed(_, _)) |
594 .WillOnce(Return(true)); | 603 .WillOnce(Return(true)); |
595 [field_ mouseDown:downEvent]; | 604 [field_ mouseDown:downEvent]; |
596 | 605 |
606 // The text field should no longer be first responder. | |
597 // The selection should not have changed. | 607 // The selection should not have changed. |
Scott Hess - ex-Googler
2015/05/08 20:34:29
Without first responder the selection is ill-defin
erikchen
2015/05/09 01:09:38
Fixed.
| |
598 EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange])); | 608 EXPECT_FALSE([base::mac::ObjCCast<NSView>([[field_ window] firstResponder]) |
609 isDescendantOf:field_]); | |
599 | 610 |
600 // TODO(shess): Test that mouse drags are initiated if the next | 611 // 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. | 612 // 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 | 613 // IDEA: mock decoration to return a pasteboard which a mock |
603 // AutocompleteTextField notes in -dragImage:*. | 614 // AutocompleteTextField notes in -dragImage:*. |
604 } | 615 } |
605 | 616 |
606 // Clicking a decoration should call decoration's OnMousePressed. | 617 // Clicking a decoration should call decoration's OnMousePressed. |
607 TEST_F(AutocompleteTextFieldTest, RightDecorationMouseDown) { | 618 TEST_F(AutocompleteTextFieldTest, RightDecorationMouseDown) { |
608 // At this point, not focussed. | 619 // At this point, not focussed. |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
782 ofView:field_]; | 793 ofView:field_]; |
783 EXPECT_FALSE([[field_ cell] showsFirstResponder]); | 794 EXPECT_FALSE([[field_ cell] showsFirstResponder]); |
784 EXPECT_FALSE([FieldEditor() shouldDrawInsertionPoint]); | 795 EXPECT_FALSE([FieldEditor() shouldDrawInsertionPoint]); |
785 | 796 |
786 [[field_ cell] setHideFocusState:NO | 797 [[field_ cell] setHideFocusState:NO |
787 ofView:field_]; | 798 ofView:field_]; |
788 EXPECT_TRUE([[field_ cell] showsFirstResponder]); | 799 EXPECT_TRUE([[field_ cell] showsFirstResponder]); |
789 EXPECT_TRUE([FieldEditor() shouldDrawInsertionPoint]); | 800 EXPECT_TRUE([FieldEditor() shouldDrawInsertionPoint]); |
790 } | 801 } |
791 | 802 |
792 // Verify that OnSetFocus for button decorations is only sent after the | 803 // Verify that clicking decorations defocuses the omnibox. |
793 // decoration is picked as the target for the subsequent -mouseDown:. Otherwise | 804 TEST_F(AutocompleteTextFieldObserverTest, ClickingDecorationDefocusesOmnibox) { |
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]; | 805 AutocompleteTextFieldCell* cell = [field_ cell]; |
801 [cell addLeftDecoration:&mock_button]; | |
802 | 806 |
803 // Ensure button is hidden when OnSetFocus() is called. | 807 // Set up a non-interactive decoration. |
804 EXPECT_CALL(field_observer_, OnSetFocus(false)).WillOnce( | 808 MockDecoration noninteractive_decoration; |
805 testing::InvokeWithoutArgs(&mock_button, &MockButtonDecoration::Hide)); | 809 noninteractive_decoration.SetVisible(true); |
810 EXPECT_CALL(noninteractive_decoration, AcceptsMousePress()) | |
811 .WillRepeatedly(testing::Return(false)); | |
812 [cell addLeftDecoration:&noninteractive_decoration]; | |
806 | 813 |
807 // Ignore incidental calls. | 814 // Set up an interactive decoration. |
815 MockDecoration interactive_decoration; | |
816 EXPECT_CALL(interactive_decoration, AcceptsMousePress()) | |
817 .WillRepeatedly(testing::Return(true)); | |
818 interactive_decoration.SetVisible(true); | |
819 [cell addLeftDecoration:&interactive_decoration]; | |
820 EXPECT_CALL(interactive_decoration, OnMousePressed(_, _)) | |
821 .WillOnce(testing::Return(true)); | |
822 | |
823 // Ignore incidental calls. The exact frequency of these calls doesn't matter | |
824 // as they auxiliary. | |
Scott Hess - ex-Googler
2015/05/08 20:34:29
I think it still needs an "are" in there somewhere
erikchen
2015/05/09 01:09:37
Yup, fixed.
| |
808 EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(_)) | 825 EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(_)) |
809 .WillRepeatedly(testing::Return(NSMakeRange(0, 0))); | 826 .WillRepeatedly(testing::Return(NSMakeRange(0, 0))); |
810 EXPECT_CALL(field_observer_, OnMouseDown(_)); | 827 EXPECT_CALL(field_observer_, OnMouseDown(_)).Times(testing::AnyNumber()); |
811 | 828 EXPECT_CALL(field_observer_, OnSetFocus(false)).Times(testing::AnyNumber()); |
812 // Still expect an OnMousePressed on the button. | 829 EXPECT_CALL(field_observer_, OnKillFocus()).Times(testing::AnyNumber()); |
813 EXPECT_CALL(mock_button, OnMousePressed(_, _)) | 830 EXPECT_CALL(field_observer_, OnDidEndEditing()).Times(testing::AnyNumber()); |
814 .WillOnce(testing::Return(true)); | |
815 | |
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)); | |
822 | 831 |
823 // Ensure the field is currently not first responder. | 832 // Ensure the field is currently not first responder. |
824 [test_window() makePretendKeyWindowAndSetFirstResponder:nil]; | 833 [test_window() makePretendKeyWindowAndSetFirstResponder:nil]; |
825 EXPECT_NSNE([[field_ window] firstResponder], field_); | 834 EXPECT_FALSE([base::mac::ObjCCast<NSView>([[field_ window] firstResponder]) |
835 isDescendantOf:field_]); | |
826 | 836 |
827 // Execute button click event sequence. | 837 SendMouseClickToDecoration(&noninteractive_decoration); |
828 NSEvent* downEvent = Event(field_, click_location, NSLeftMouseDown); | 838 EXPECT_TRUE([base::mac::ObjCCast<NSView>([[field_ window] firstResponder]) |
829 NSEvent* upEvent = Event(field_, click_location, NSLeftMouseUp); | 839 isDescendantOf:field_]); |
830 | 840 |
831 // Can't just use -sendEvent:, since that doesn't populate -currentEvent. | 841 SendMouseClickToDecoration(&interactive_decoration); |
832 [NSApp postEvent:downEvent atStart:YES]; | 842 EXPECT_FALSE([base::mac::ObjCCast<NSView>([[field_ window] firstResponder]) |
833 [NSApp postEvent:upEvent atStart:NO]; | 843 isDescendantOf:field_]); |
834 NSEvent* next_event = [NSApp nextEventMatchingMask:NSAnyEventMask | |
835 untilDate:nil | |
836 inMode:NSDefaultRunLoopMode | |
837 dequeue:YES]; | |
838 [NSApp sendEvent:next_event]; | |
839 | 844 |
840 // Expectations check that both OnSetFocus and OnMouseDown were called. | 845 SendMouseClickToDecoration(&noninteractive_decoration); |
841 // Additionally, ensure button is hidden and field is firstResponder. | 846 EXPECT_TRUE([base::mac::ObjCCast<NSView>([[field_ window] firstResponder]) |
842 EXPECT_FALSE(mock_button.IsVisible()); | 847 isDescendantOf:field_]); |
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_]); | |
847 } | 848 } |
848 | 849 |
849 TEST_F(AutocompleteTextFieldObserverTest, SendsEditingMessages) { | 850 TEST_F(AutocompleteTextFieldObserverTest, SendsEditingMessages) { |
850 // Many of these methods try to change the selection. | 851 // Many of these methods try to change the selection. |
851 EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>())) | 852 EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>())) |
852 .WillRepeatedly(ReturnArg<0>()); | 853 .WillRepeatedly(ReturnArg<0>()); |
853 | 854 |
854 EXPECT_CALL(field_observer_, OnSetFocus(false)); | 855 EXPECT_CALL(field_observer_, OnSetFocus(false)); |
855 // Becoming first responder doesn't begin editing. | 856 // Becoming first responder doesn't begin editing. |
856 [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; | 857 [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
895 base::scoped_nsobject<AutocompleteTextField> pin([field_ retain]); | 896 base::scoped_nsobject<AutocompleteTextField> pin([field_ retain]); |
896 [field_ removeFromSuperview]; | 897 [field_ removeFromSuperview]; |
897 [test_window() resignKeyWindow]; | 898 [test_window() resignKeyWindow]; |
898 | 899 |
899 [[test_window() contentView] addSubview:field_]; | 900 [[test_window() contentView] addSubview:field_]; |
900 EXPECT_CALL(field_observer_, ClosePopup()); | 901 EXPECT_CALL(field_observer_, ClosePopup()); |
901 [test_window() resignKeyWindow]; | 902 [test_window() resignKeyWindow]; |
902 } | 903 } |
903 | 904 |
904 } // namespace | 905 } // namespace |
OLD | NEW |