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 "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
7 #include "base/mac/scoped_nsobject.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/string_util.h"
10 #include "chrome/app/chrome_command_ids.h" // IDC_*
11 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
12 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
13 #include "grit/generated_resources.h"
14 #include "testing/gmock/include/gmock/gmock-matchers.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #import "testing/gtest_mac.h"
17 #include "testing/platform_test.h"
18 #import "third_party/ocmock/OCMock/OCMock.h"
19 #include "third_party/ocmock/gtest_support.h"
20 #import "third_party/ocmock/ocmock_extensions.h"
21 #import "ui/base/test/cocoa_test_event_utils.h"
23 using ::testing::Return;
24 using ::testing::ReturnArg;
25 using ::testing::StrictMock;
30 // TODO(shess): Very similar to AutocompleteTextFieldTest. Maybe
31 // those can be shared.
33 class AutocompleteTextFieldEditorTest : public CocoaTest {
35 virtual void SetUp() {
37 NSRect frame = NSMakeRect(0, 0, 50, 30);
38 base::scoped_nsobject<AutocompleteTextField> field(
39 [[AutocompleteTextField alloc] initWithFrame:frame]);
41 [field_ setStringValue:@"Testing"];
42 [[test_window() contentView] addSubview:field_];
44 // Arrange for |field_| to get the right field editor.
45 window_delegate_.reset(
46 [[AutocompleteTextFieldWindowTestDelegate alloc] init]);
47 [test_window() setDelegate:window_delegate_.get()];
49 // Get the field editor setup.
50 [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
51 editor_ = static_cast<AutocompleteTextFieldEditor*>([field_ currentEditor]);
54 EXPECT_TRUE([editor_ isKindOfClass:[AutocompleteTextFieldEditor class]]);
57 AutocompleteTextFieldEditor* editor_;
58 AutocompleteTextField* field_;
59 base::scoped_nsobject<AutocompleteTextFieldWindowTestDelegate>
63 // Disabled because it crashes sometimes. http://crbug.com/49522
64 // Can't rename DISABLED_ because the TEST_VIEW macro prepends.
65 // http://crbug.com/53621
67 TEST_VIEW(AutocompleteTextFieldEditorTest, field_);
70 // Test that control characters are stripped from insertions.
71 TEST_F(AutocompleteTextFieldEditorTest, InsertStripsControlChars) {
72 // Sets a string in the field.
73 NSString* test_string = @"astring";
74 [field_ setStringValue:test_string];
75 [editor_ selectAll:nil];
77 [editor_ insertText:@"t"];
78 EXPECT_NSEQ(@"t", [field_ stringValue]);
80 [editor_ insertText:@"h"];
81 EXPECT_NSEQ(@"th", [field_ stringValue]);
83 // TAB doesn't get inserted.
84 [editor_ insertText:[NSString stringWithFormat:@"%c", 7]];
85 EXPECT_NSEQ(@"th", [field_ stringValue]);
87 // Newline doesn't get inserted.
88 [editor_ insertText:[NSString stringWithFormat:@"%c", 12]];
89 EXPECT_NSEQ(@"th", [field_ stringValue]);
91 // Multi-character strings get through.
92 [editor_ insertText:[NSString stringWithFormat:@"i%cs%c", 8, 127]];
93 EXPECT_NSEQ(@"this", [field_ stringValue]);
95 // Attempting to insert newline when everything is selected clears
97 [editor_ selectAll:nil];
98 [editor_ insertText:[NSString stringWithFormat:@"%c", 12]];
99 EXPECT_NSEQ(@"", [field_ stringValue]);
102 // Test that |delegate| can provide page action menus.
103 TEST_F(AutocompleteTextFieldEditorTest, PageActionMenus) {
104 // The event just needs to be something the mock can recognize.
105 NSEvent* event = cocoa_test_event_utils::MouseEventAtPoint(NSZeroPoint,
109 // Trivial menu which we can recognize and which doesn't look like
110 // the default editor context menu.
111 base::scoped_nsobject<id> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
112 [menu addItemWithTitle:@"Go Fish"
113 action:@selector(goFish:)
116 // So that we don't have to mock the observer.
117 [editor_ setEditable:NO];
119 // The delegate's intercept point gets called, and results are
122 id delegate = [OCMockObject mockForClass:[AutocompleteTextField class]];
123 [[[delegate stub] andReturnBool:YES]
124 isKindOfClass:[AutocompleteTextField class]];
125 [[[delegate expect] andReturn:menu.get()] decorationMenuForEvent:event];
126 [[[delegate expect] andReturn:nil] undoManagerForTextView:editor_];
127 [editor_ setDelegate:delegate];
128 NSMenu* contextMenu = [editor_ menuForEvent:event];
129 EXPECT_OCMOCK_VERIFY(delegate);
130 [editor_ setDelegate:nil];
132 EXPECT_EQ(contextMenu, menu.get());
135 // If the delegate does not return any menu, the default menu is
138 id delegate = [OCMockObject mockForClass:[AutocompleteTextField class]];
139 [[[delegate stub] andReturnBool:YES]
140 isKindOfClass:[AutocompleteTextField class]];
141 [[[delegate expect] andReturn:nil] decorationMenuForEvent:event];
142 [[[delegate expect] andReturn:nil] undoManagerForTextView:editor_];
143 [editor_ setDelegate:delegate];
144 NSMenu* contextMenu = [editor_ menuForEvent:event];
145 EXPECT_OCMOCK_VERIFY(delegate);
146 [editor_ setDelegate:nil];
148 EXPECT_NE(contextMenu, menu.get());
149 NSArray* items = [contextMenu itemArray];
150 ASSERT_GT([items count], 0U);
151 EXPECT_EQ(@selector(cut:), [[items objectAtIndex:0] action])
152 << "action is: " << sel_getName([[items objectAtIndex:0] action]);
156 // Base class for testing AutocompleteTextFieldObserver messages.
157 class AutocompleteTextFieldEditorObserverTest
158 : public AutocompleteTextFieldEditorTest {
160 virtual void SetUp() {
161 AutocompleteTextFieldEditorTest::SetUp();
162 [field_ setObserver:&field_observer_];
165 virtual void TearDown() {
166 // Clear the observer so that we don't show output for
167 // uninteresting messages to the mock (for instance, if |field_| has
168 // focus at the end of the test).
169 [field_ setObserver:NULL];
171 AutocompleteTextFieldEditorTest::TearDown();
174 StrictMock<MockAutocompleteTextFieldObserver> field_observer_;
177 // Test that the field editor is linked in correctly.
178 TEST_F(AutocompleteTextFieldEditorTest, FirstResponder) {
179 EXPECT_EQ(editor_, [field_ currentEditor]);
180 EXPECT_TRUE([editor_ isDescendantOf:field_]);
181 EXPECT_EQ([editor_ delegate], field_);
182 EXPECT_EQ([editor_ observer], [field_ observer]);
185 // Test drawing, mostly to ensure nothing leaks or crashes.
186 TEST_F(AutocompleteTextFieldEditorTest, Display) {
191 // Test setting gray text, mostly to ensure nothing leaks or crashes.
192 TEST_F(AutocompleteTextFieldEditorTest, GrayText) {
194 EXPECT_FALSE([editor_ needsDisplay]);
195 [field_ setGrayTextAutocompletion:@"foo" textColor:[NSColor redColor]];
196 EXPECT_TRUE([editor_ needsDisplay]);
200 // Test that -paste: is correctly delegated to the observer.
201 TEST_F(AutocompleteTextFieldEditorObserverTest, Paste) {
202 EXPECT_CALL(field_observer_, OnPaste());
206 // Test that -copy: is correctly delegated to the observer.
207 TEST_F(AutocompleteTextFieldEditorObserverTest, Copy) {
208 EXPECT_CALL(field_observer_, CanCopy())
209 .WillOnce(Return(true));
210 EXPECT_CALL(field_observer_, CopyToPasteboard(A<NSPasteboard*>()))
215 // Test that -showURL: is correctly delegated to the observer.
216 TEST_F(AutocompleteTextFieldEditorObserverTest, ShowURL) {
217 EXPECT_CALL(field_observer_, ShowURL()).Times(1);
218 [editor_ showURL:nil];
221 // Test that -cut: is correctly delegated to the observer and clears
223 TEST_F(AutocompleteTextFieldEditorObserverTest, Cut) {
224 // Sets a string in the field.
225 NSString* test_string = @"astring";
226 EXPECT_CALL(field_observer_, OnDidBeginEditing());
227 EXPECT_CALL(field_observer_, OnBeforeChange());
228 EXPECT_CALL(field_observer_, OnDidChange());
229 EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
230 .WillRepeatedly(ReturnArg<0>());
231 [editor_ setString:test_string];
232 [editor_ selectAll:nil];
235 EXPECT_CALL(field_observer_, CanCopy())
236 .WillOnce(Return(true));
237 EXPECT_CALL(field_observer_, CopyToPasteboard(A<NSPasteboard*>()))
241 // Check if the field is cleared.
242 ASSERT_EQ([[editor_ textStorage] length], 0U);
245 // Test that -pasteAndGo: is correctly delegated to the observer.
246 TEST_F(AutocompleteTextFieldEditorObserverTest, PasteAndGo) {
247 EXPECT_CALL(field_observer_, OnPasteAndGo());
248 [editor_ pasteAndGo:nil];
251 // Test that the menu is constructed correctly.
252 TEST_F(AutocompleteTextFieldEditorObserverTest, Menu) {
253 EXPECT_CALL(field_observer_, GetPasteActionStringId()).
254 WillOnce(Return(IDS_PASTE_AND_GO));
255 EXPECT_CALL(field_observer_, ShouldEnableShowURL()).
256 WillOnce(Return(true));
258 NSMenu* menu = [editor_ menuForEvent:nil];
259 NSArray* items = [menu itemArray];
260 ASSERT_EQ([items count], 7U);
261 // TODO(shess): Check the titles, too?
262 NSUInteger i = 0; // Use an index to make future changes easier.
263 EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:));
264 EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:));
265 EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:));
266 EXPECT_EQ([[items objectAtIndex:i++] action], @selector(pasteAndGo:));
267 EXPECT_TRUE([[items objectAtIndex:i++] isSeparatorItem]);
268 EXPECT_EQ([[items objectAtIndex:i++] action], @selector(showURL:));
269 EXPECT_EQ([[items objectAtIndex:i] tag], IDC_EDIT_SEARCH_ENGINES);
270 EXPECT_EQ([[items objectAtIndex:i++] action], @selector(commandDispatch:));
273 // Test that the menu is constructed correctly when field isn't
275 TEST_F(AutocompleteTextFieldEditorObserverTest, CanPasteAndGoMenuNotEditable) {
276 [field_ setEditable:NO];
277 [editor_ setEditable:NO];
279 // Never call this when not editable.
280 EXPECT_CALL(field_observer_, GetPasteActionStringId()).Times(0);
282 NSMenu* menu = [editor_ menuForEvent:nil];
283 NSArray* items = [menu itemArray];
284 ASSERT_EQ([items count], 3U);
285 // TODO(shess): Check the titles, too?
286 NSUInteger i = 0; // Use an index to make future changes easier.
287 EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:));
288 EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:));
289 EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:));
292 // Test that the menu validation works as expected when CanPasteAndGo().
293 TEST_F(AutocompleteTextFieldEditorObserverTest, CanPasteAndGoValidate) {
294 EXPECT_CALL(field_observer_, GetPasteActionStringId())
295 .WillOnce(Return(IDS_PASTE_AND_GO));
296 EXPECT_CALL(field_observer_, CanPasteAndGo()).WillOnce(Return(true));
297 EXPECT_CALL(field_observer_, ShouldEnableShowURL())
298 .WillOnce(Return(false));
300 NSMenu* menu = [editor_ menuForEvent:nil];
301 NSArray* items = [menu itemArray];
302 ASSERT_EQ([items count], 6U);
303 for (NSUInteger i = 0; i < [items count]; ++i) {
304 NSMenuItem* item = [items objectAtIndex:i];
305 if ([item action] == @selector(pasteAndGo:)) {
306 EXPECT_TRUE([editor_ validateMenuItem:item]);
312 // Test that the menu validation works as expected when !CanPasteAndGo().
313 TEST_F(AutocompleteTextFieldEditorObserverTest, CannotPasteAndGoValidate) {
314 EXPECT_CALL(field_observer_, GetPasteActionStringId())
315 .WillOnce(Return(IDS_PASTE_AND_GO));
316 EXPECT_CALL(field_observer_, CanPasteAndGo()).WillOnce(Return(false));
317 EXPECT_CALL(field_observer_, ShouldEnableShowURL())
318 .WillOnce(Return(false));
320 NSMenu* menu = [editor_ menuForEvent:nil];
321 NSArray* items = [menu itemArray];
322 ASSERT_EQ([items count], 6U);
323 for (NSUInteger i = 0; i < [items count]; ++i) {
324 NSMenuItem* item = [items objectAtIndex:i];
325 if ([item action] == @selector(pasteAndGo:)) {
326 EXPECT_FALSE([editor_ validateMenuItem:item]);
332 // Test that the menu validation works as expected when ShouldEnableShowURL().
333 TEST_F(AutocompleteTextFieldEditorObserverTest, ShouldEnableShowURLValidate) {
334 EXPECT_CALL(field_observer_, GetPasteActionStringId())
335 .WillOnce(Return(IDS_PASTE_AND_GO));
336 EXPECT_CALL(field_observer_, ShouldEnableShowURL())
337 .WillRepeatedly(Return(true));
339 NSMenu* menu = [editor_ menuForEvent:nil];
340 NSArray* items = [menu itemArray];
341 ASSERT_EQ([items count], 7U);
342 for (NSUInteger i = 0; i < [items count]; ++i) {
343 NSMenuItem* item = [items objectAtIndex:i];
344 if ([item action] == @selector(showURL:)) {
345 EXPECT_TRUE([editor_ validateMenuItem:item]);