Chromium Code Reviews| 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 44 // Note: It does not matter which images are used here - but ButtonDecoration | 44 // Note: It does not matter which images are used here - but ButtonDecoration |
| 45 // needs _some_ images to work properly. | 45 // needs _some_ images to work properly. |
| 46 MockButtonDecoration() | 46 MockButtonDecoration() |
| 47 : ButtonDecoration(IMAGE_GRID(IDR_OMNIBOX_EV_BUBBLE), | 47 : ButtonDecoration(IMAGE_GRID(IDR_OMNIBOX_EV_BUBBLE), |
| 48 IDR_OMNIBOX_EV_BUBBLE_CENTER, | 48 IDR_OMNIBOX_EV_BUBBLE_CENTER, |
| 49 IMAGE_GRID(IDR_OMNIBOX_EV_BUBBLE), | 49 IMAGE_GRID(IDR_OMNIBOX_EV_BUBBLE), |
| 50 IDR_OMNIBOX_EV_BUBBLE_CENTER, | 50 IDR_OMNIBOX_EV_BUBBLE_CENTER, |
| 51 IMAGE_GRID(IDR_OMNIBOX_EV_BUBBLE), | 51 IMAGE_GRID(IDR_OMNIBOX_EV_BUBBLE), |
| 52 IDR_OMNIBOX_EV_BUBBLE_CENTER, | 52 IDR_OMNIBOX_EV_BUBBLE_CENTER, |
| 53 3) {} | 53 3) {} |
| 54 void Hide() { SetVisible(false); } | |
| 55 MOCK_METHOD2(OnMousePressed, bool(NSRect frame, NSPoint location)); | 54 MOCK_METHOD2(OnMousePressed, bool(NSRect frame, NSPoint location)); |
| 56 }; | 55 }; |
|
Scott Hess - ex-Googler
2015/05/08 19:38:28
Given the current code, this class seems like it i
erikchen
2015/05/08 20:02:20
Yup, removed.
| |
| 57 | 56 |
| 58 // Mock up an incrementing event number. | 57 // Mock up an incrementing event number. |
| 59 NSUInteger eventNumber = 0; | 58 NSUInteger eventNumber = 0; |
| 60 | 59 |
| 61 // Create an event of the indicated |type| at |point| within |view|. | 60 // Create an event of the indicated |type| at |point| within |view|. |
| 62 // TODO(shess): Would be nice to have a MockApplication which provided | 61 // TODO(shess): Would be nice to have a MockApplication which provided |
| 63 // nifty accessors to create these things and inject them. It could | 62 // nifty accessors to create these things and inject them. It could |
| 64 // even provide functions for "Click and drag mouse from point A to | 63 // even provide functions for "Click and drag mouse from point A to |
| 65 // point B". | 64 // point B". |
| 66 // TODO(groby): This is very similar to cocoa_testing_utils - unify. | 65 // TODO(groby): This is very similar to cocoa_testing_utils - unify. |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 163 | 162 |
| 164 virtual void TearDown() { | 163 virtual void TearDown() { |
| 165 // Clear the observer so that we don't show output for | 164 // Clear the observer so that we don't show output for |
| 166 // uninteresting messages to the mock (for instance, if |field_| has | 165 // uninteresting messages to the mock (for instance, if |field_| has |
| 167 // focus at the end of the test). | 166 // focus at the end of the test). |
| 168 [field_ setObserver:NULL]; | 167 [field_ setObserver:NULL]; |
| 169 | 168 |
| 170 AutocompleteTextFieldTest::TearDown(); | 169 AutocompleteTextFieldTest::TearDown(); |
| 171 } | 170 } |
| 172 | 171 |
| 172 // Returns the center point of the decoration. | |
| 173 NSPoint ClickLocationForDecoration(LocationBarDecoration* decoration) { | |
| 174 AutocompleteTextFieldCell* cell = [field_ cell]; | |
| 175 NSRect decoration_rect = | |
| 176 [cell frameForDecoration:decoration inFrame:[field_ bounds]]; | |
| 177 EXPECT_FALSE(NSIsEmptyRect(decoration_rect)); | |
| 178 return NSMakePoint(NSMidX(decoration_rect), NSMidY(decoration_rect)); | |
| 179 } | |
| 180 | |
| 181 void SendMouseClickToDecoration(LocationBarDecoration* decoration) { | |
| 182 NSPoint point = ClickLocationForDecoration(decoration); | |
| 183 NSEvent* downEvent = Event(field_, point, NSLeftMouseDown); | |
| 184 NSEvent* upEvent = Event(field_, point, NSLeftMouseUp); | |
| 185 | |
| 186 // Can't just use -sendEvent:, since that doesn't populate -currentEvent. | |
| 187 [NSApp postEvent:downEvent atStart:YES]; | |
| 188 [NSApp postEvent:upEvent atStart:NO]; | |
| 189 | |
| 190 NSEvent* next_event = [NSApp nextEventMatchingMask:NSAnyEventMask | |
| 191 untilDate:nil | |
| 192 inMode:NSDefaultRunLoopMode | |
| 193 dequeue:YES]; | |
| 194 [NSApp sendEvent:next_event]; | |
| 195 } | |
| 196 | |
| 173 StrictMock<MockAutocompleteTextFieldObserver> field_observer_; | 197 StrictMock<MockAutocompleteTextFieldObserver> field_observer_; |
| 174 }; | 198 }; |
| 175 | 199 |
| 176 // Test that we have the right cell class. | 200 // Test that we have the right cell class. |
| 177 TEST_F(AutocompleteTextFieldTest, CellClass) { | 201 TEST_F(AutocompleteTextFieldTest, CellClass) { |
| 178 EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]); | 202 EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]); |
| 179 } | 203 } |
| 180 | 204 |
| 181 // Test that becoming first responder sets things up correctly. | 205 // Test that becoming first responder sets things up correctly. |
| 182 TEST_F(AutocompleteTextFieldTest, FirstResponder) { | 206 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])); | 611 EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange])); |
| 588 | 612 |
| 589 // Generate another click on the decoration. | 613 // Generate another click on the decoration. |
| 590 downEvent = Event(field_, location, NSLeftMouseDown, 1); | 614 downEvent = Event(field_, location, NSLeftMouseDown, 1); |
| 591 upEvent = Event(field_, location, NSLeftMouseUp, 1); | 615 upEvent = Event(field_, location, NSLeftMouseUp, 1); |
| 592 [NSApp postEvent:upEvent atStart:YES]; | 616 [NSApp postEvent:upEvent atStart:YES]; |
| 593 EXPECT_CALL(mock_left_decoration_, OnMousePressed(_, _)) | 617 EXPECT_CALL(mock_left_decoration_, OnMousePressed(_, _)) |
| 594 .WillOnce(Return(true)); | 618 .WillOnce(Return(true)); |
| 595 [field_ mouseDown:downEvent]; | 619 [field_ mouseDown:downEvent]; |
| 596 | 620 |
| 621 // The text field should no longer be first responder. | |
| 597 // The selection should not have changed. | 622 // The selection should not have changed. |
| 598 EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange])); | 623 EXPECT_FALSE([base::mac::ObjCCast<NSView>([[field_ window] firstResponder]) |
| 624 isDescendantOf:field_]); | |
| 599 | 625 |
| 600 // TODO(shess): Test that mouse drags are initiated if the next | 626 // 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. | 627 // 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 | 628 // IDEA: mock decoration to return a pasteboard which a mock |
| 603 // AutocompleteTextField notes in -dragImage:*. | 629 // AutocompleteTextField notes in -dragImage:*. |
| 604 } | 630 } |
| 605 | 631 |
| 606 // Clicking a decoration should call decoration's OnMousePressed. | 632 // Clicking a decoration should call decoration's OnMousePressed. |
| 607 TEST_F(AutocompleteTextFieldTest, RightDecorationMouseDown) { | 633 TEST_F(AutocompleteTextFieldTest, RightDecorationMouseDown) { |
| 608 // At this point, not focussed. | 634 // At this point, not focussed. |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 782 ofView:field_]; | 808 ofView:field_]; |
| 783 EXPECT_FALSE([[field_ cell] showsFirstResponder]); | 809 EXPECT_FALSE([[field_ cell] showsFirstResponder]); |
| 784 EXPECT_FALSE([FieldEditor() shouldDrawInsertionPoint]); | 810 EXPECT_FALSE([FieldEditor() shouldDrawInsertionPoint]); |
| 785 | 811 |
| 786 [[field_ cell] setHideFocusState:NO | 812 [[field_ cell] setHideFocusState:NO |
| 787 ofView:field_]; | 813 ofView:field_]; |
| 788 EXPECT_TRUE([[field_ cell] showsFirstResponder]); | 814 EXPECT_TRUE([[field_ cell] showsFirstResponder]); |
| 789 EXPECT_TRUE([FieldEditor() shouldDrawInsertionPoint]); | 815 EXPECT_TRUE([FieldEditor() shouldDrawInsertionPoint]); |
| 790 } | 816 } |
| 791 | 817 |
| 792 // Verify that OnSetFocus for button decorations is only sent after the | 818 // Verify that clicking decorations defocuses the omnibox. |
| 793 // decoration is picked as the target for the subsequent -mouseDown:. Otherwise | 819 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]; | 820 AutocompleteTextFieldCell* cell = [field_ cell]; |
| 801 [cell addLeftDecoration:&mock_button]; | |
| 802 | 821 |
| 803 // Ensure button is hidden when OnSetFocus() is called. | 822 // Set up a non-interactive decoration. |
| 804 EXPECT_CALL(field_observer_, OnSetFocus(false)).WillOnce( | 823 MockDecoration noninteractive_decoration; |
| 805 testing::InvokeWithoutArgs(&mock_button, &MockButtonDecoration::Hide)); | 824 noninteractive_decoration.SetVisible(true); |
| 825 EXPECT_CALL(noninteractive_decoration, AcceptsMousePress()) | |
| 826 .WillRepeatedly(testing::Return(false)); | |
| 827 [cell addLeftDecoration:&noninteractive_decoration]; | |
| 806 | 828 |
| 807 // Ignore incidental calls. | 829 // Set up an interactive decoration. |
| 830 MockButtonDecoration interactive_decoration; | |
| 831 interactive_decoration.SetVisible(true); | |
| 832 [cell addLeftDecoration:&interactive_decoration]; | |
| 833 EXPECT_CALL(interactive_decoration, OnMousePressed(_, _)) | |
| 834 .WillOnce(testing::Return(true)); | |
| 835 | |
| 836 // Ignore incidental calls. The exact frequency of these calls doesn't | |
| 837 // matter, as they auxiliary to the behavior being tested. | |
|
Scott Hess - ex-Googler
2015/05/08 19:38:28
probably "they are auxiliary"
erikchen
2015/05/08 20:02:21
Done.
| |
| 808 EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(_)) | 838 EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(_)) |
| 809 .WillRepeatedly(testing::Return(NSMakeRange(0, 0))); | 839 .WillRepeatedly(testing::Return(NSMakeRange(0, 0))); |
| 810 EXPECT_CALL(field_observer_, OnMouseDown(_)); | 840 EXPECT_CALL(field_observer_, OnMouseDown(_)).Times(testing::AnyNumber()); |
| 811 | 841 EXPECT_CALL(field_observer_, OnSetFocus(false)).Times(testing::AnyNumber()); |
| 812 // Still expect an OnMousePressed on the button. | 842 EXPECT_CALL(field_observer_, OnKillFocus()).Times(testing::AnyNumber()); |
| 813 EXPECT_CALL(mock_button, OnMousePressed(_, _)) | 843 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 | 844 |
| 823 // Ensure the field is currently not first responder. | 845 // Ensure the field is currently not first responder. |
| 824 [test_window() makePretendKeyWindowAndSetFirstResponder:nil]; | 846 [test_window() makePretendKeyWindowAndSetFirstResponder:nil]; |
| 825 EXPECT_NSNE([[field_ window] firstResponder], field_); | 847 EXPECT_FALSE([base::mac::ObjCCast<NSView>([[field_ window] firstResponder]) |
| 848 isDescendantOf:field_]); | |
| 826 | 849 |
| 827 // Execute button click event sequence. | 850 SendMouseClickToDecoration(&noninteractive_decoration); |
| 828 NSEvent* downEvent = Event(field_, click_location, NSLeftMouseDown); | 851 EXPECT_TRUE([base::mac::ObjCCast<NSView>([[field_ window] firstResponder]) |
| 829 NSEvent* upEvent = Event(field_, click_location, NSLeftMouseUp); | 852 isDescendantOf:field_]); |
| 830 | 853 |
| 831 // Can't just use -sendEvent:, since that doesn't populate -currentEvent. | 854 SendMouseClickToDecoration(&interactive_decoration); |
| 832 [NSApp postEvent:downEvent atStart:YES]; | 855 EXPECT_FALSE([base::mac::ObjCCast<NSView>([[field_ window] firstResponder]) |
| 833 [NSApp postEvent:upEvent atStart:NO]; | 856 isDescendantOf:field_]); |
|
Scott Hess - ex-Googler
2015/05/08 19:38:28
This ties in with the comment in the implementatio
erikchen
2015/05/08 20:02:20
See my response to the earlier comment.
| |
| 834 NSEvent* next_event = [NSApp nextEventMatchingMask:NSAnyEventMask | |
| 835 untilDate:nil | |
| 836 inMode:NSDefaultRunLoopMode | |
| 837 dequeue:YES]; | |
| 838 [NSApp sendEvent:next_event]; | |
| 839 | 857 |
| 840 // Expectations check that both OnSetFocus and OnMouseDown were called. | 858 SendMouseClickToDecoration(&noninteractive_decoration); |
| 841 // Additionally, ensure button is hidden and field is firstResponder. | 859 EXPECT_TRUE([base::mac::ObjCCast<NSView>([[field_ window] firstResponder]) |
| 842 EXPECT_FALSE(mock_button.IsVisible()); | 860 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 } | 861 } |
| 848 | 862 |
| 849 TEST_F(AutocompleteTextFieldObserverTest, SendsEditingMessages) { | 863 TEST_F(AutocompleteTextFieldObserverTest, SendsEditingMessages) { |
| 850 // Many of these methods try to change the selection. | 864 // Many of these methods try to change the selection. |
| 851 EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>())) | 865 EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>())) |
| 852 .WillRepeatedly(ReturnArg<0>()); | 866 .WillRepeatedly(ReturnArg<0>()); |
| 853 | 867 |
| 854 EXPECT_CALL(field_observer_, OnSetFocus(false)); | 868 EXPECT_CALL(field_observer_, OnSetFocus(false)); |
| 855 // Becoming first responder doesn't begin editing. | 869 // Becoming first responder doesn't begin editing. |
| 856 [test_window() makePretendKeyWindowAndSetFirstResponder:field_]; | 870 [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]); | 909 base::scoped_nsobject<AutocompleteTextField> pin([field_ retain]); |
| 896 [field_ removeFromSuperview]; | 910 [field_ removeFromSuperview]; |
| 897 [test_window() resignKeyWindow]; | 911 [test_window() resignKeyWindow]; |
| 898 | 912 |
| 899 [[test_window() contentView] addSubview:field_]; | 913 [[test_window() contentView] addSubview:field_]; |
| 900 EXPECT_CALL(field_observer_, ClosePopup()); | 914 EXPECT_CALL(field_observer_, ClosePopup()); |
| 901 [test_window() resignKeyWindow]; | 915 [test_window() resignKeyWindow]; |
| 902 } | 916 } |
| 903 | 917 |
| 904 } // namespace | 918 } // namespace |
| OLD | NEW |