| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 <Cocoa/Cocoa.h> | 5 #import <Cocoa/Cocoa.h> |
| 6 | 6 |
| 7 #include "base/scoped_nsobject.h" | 7 #include "base/scoped_nsobject.h" |
| 8 #import "chrome/browser/cocoa/autocomplete_text_field.h" | 8 #import "chrome/browser/cocoa/autocomplete_text_field.h" |
| 9 #import "chrome/browser/cocoa/autocomplete_text_field_cell.h" | 9 #import "chrome/browser/cocoa/autocomplete_text_field_cell.h" |
| 10 #import "chrome/browser/cocoa/autocomplete_text_field_editor.h" | 10 #import "chrome/browser/cocoa/autocomplete_text_field_editor.h" |
| 11 #import "chrome/browser/cocoa/cocoa_test_helper.h" | 11 #import "chrome/browser/cocoa/cocoa_test_helper.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 | 13 |
| 14 @interface AutocompleteTextFieldTestDelegate : NSObject { | 14 @interface AutocompleteTextFieldTestDelegate : NSObject { |
| 15 BOOL textShouldPaste_; | 15 BOOL textShouldPaste_; |
| 16 BOOL receivedTextShouldPaste_; | 16 BOOL receivedTextShouldPaste_; |
| 17 BOOL receivedFlagsChanged_; | 17 BOOL receivedFlagsChanged_; |
| 18 BOOL receivedControlTextDidBeginEditing_; |
| 19 BOOL receivedControlTextShouldEndEditing_; |
| 18 } | 20 } |
| 19 - initWithTextShouldPaste:(BOOL)flag; | 21 - initWithTextShouldPaste:(BOOL)flag; |
| 20 - (BOOL)receivedTextShouldPaste; | 22 - (BOOL)receivedTextShouldPaste; |
| 21 - (BOOL)receivedFlagsChanged; | 23 - (BOOL)receivedFlagsChanged; |
| 24 - (BOOL)receivedControlTextDidBeginEditing; |
| 25 - (BOOL)receivedControlTextShouldEndEditing; |
| 26 @end |
| 27 |
| 28 @interface AutocompleteTextFieldWindowTestDelegate : NSObject { |
| 29 scoped_nsobject<AutocompleteTextFieldEditor> editor_; |
| 30 } |
| 31 - (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject; |
| 22 @end | 32 @end |
| 23 | 33 |
| 24 namespace { | 34 namespace { |
| 25 | 35 |
| 26 class AutocompleteTextFieldTest : public testing::Test { | 36 class AutocompleteTextFieldTest : public testing::Test { |
| 27 public: | 37 public: |
| 28 AutocompleteTextFieldTest() { | 38 AutocompleteTextFieldTest() { |
| 29 NSRect frame = NSMakeRect(0, 0, 50, 30); | 39 // Make sure this is wide enough to play games with the cell |
| 40 // decorations. |
| 41 NSRect frame = NSMakeRect(0, 0, 300, 30); |
| 30 field_.reset([[AutocompleteTextField alloc] initWithFrame:frame]); | 42 field_.reset([[AutocompleteTextField alloc] initWithFrame:frame]); |
| 31 [field_ setStringValue:@"Testing"]; | 43 [field_ setStringValue:@"Testing"]; |
| 32 [cocoa_helper_.contentView() addSubview:field_.get()]; | 44 [cocoa_helper_.contentView() addSubview:field_.get()]; |
| 45 |
| 46 window_delegate_.reset( |
| 47 [[AutocompleteTextFieldWindowTestDelegate alloc] init]); |
| 48 [cocoa_helper_.window() setDelegate:window_delegate_]; |
| 33 } | 49 } |
| 34 | 50 |
| 35 CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... | 51 CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... |
| 36 scoped_nsobject<AutocompleteTextField> field_; | 52 scoped_nsobject<AutocompleteTextField> field_; |
| 53 scoped_nsobject<AutocompleteTextFieldWindowTestDelegate> window_delegate_; |
| 37 }; | 54 }; |
| 38 | 55 |
| 39 // Test that we have the right cell class. | 56 // Test that we have the right cell class. |
| 40 TEST_F(AutocompleteTextFieldTest, CellClass) { | 57 TEST_F(AutocompleteTextFieldTest, CellClass) { |
| 41 EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]); | 58 EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]); |
| 42 } | 59 } |
| 43 | 60 |
| 44 // Test adding/removing from the view hierarchy, mostly to ensure nothing | 61 // Test adding/removing from the view hierarchy, mostly to ensure nothing |
| 45 // leaks or crashes. | 62 // leaks or crashes. |
| 46 TEST_F(AutocompleteTextFieldTest, AddRemove) { | 63 TEST_F(AutocompleteTextFieldTest, AddRemove) { |
| 47 EXPECT_EQ(cocoa_helper_.contentView(), [field_ superview]); | 64 EXPECT_EQ(cocoa_helper_.contentView(), [field_ superview]); |
| 48 [field_.get() removeFromSuperview]; | 65 [field_.get() removeFromSuperview]; |
| 49 EXPECT_FALSE([field_ superview]); | 66 EXPECT_FALSE([field_ superview]); |
| 50 } | 67 } |
| 51 | 68 |
| 69 // Test that we get the same cell from -cell and |
| 70 // -autocompleteTextFieldCell. |
| 71 TEST_F(AutocompleteTextFieldTest, Cell) { |
| 72 AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; |
| 73 EXPECT_EQ(cell, [field_ cell]); |
| 74 EXPECT_TRUE(cell != nil); |
| 75 } |
| 76 |
| 52 // Test drawing, mostly to ensure nothing leaks or crashes. | 77 // Test drawing, mostly to ensure nothing leaks or crashes. |
| 53 TEST_F(AutocompleteTextFieldTest, Display) { | 78 TEST_F(AutocompleteTextFieldTest, Display) { |
| 54 [field_ display]; | 79 [field_ display]; |
| 80 |
| 81 // Test display of various cell configurations. |
| 82 AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; |
| 83 |
| 84 [cell setSearchHintString:@"Type to search"]; |
| 85 [field_ display]; |
| 86 |
| 87 NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"]; |
| 88 [cell setKeywordHintPrefix:@"prefix" image:image suffix:@"suffix"]; |
| 89 [field_ display]; |
| 90 |
| 91 [cell setKeywordString:@"Search Engine:"]; |
| 92 [field_ display]; |
| 93 |
| 94 [cell clearKeywordAndHint]; |
| 95 [field_ display]; |
| 55 } | 96 } |
| 56 | 97 |
| 57 // Test that -textShouldPaste: properly queries the delegate. | 98 // Test that -textShouldPaste: properly queries the delegate. |
| 58 TEST_F(AutocompleteTextFieldTest, TextShouldPaste) { | 99 TEST_F(AutocompleteTextFieldTest, TextShouldPaste) { |
| 59 EXPECT_TRUE(![field_ delegate]); | 100 EXPECT_TRUE(![field_ delegate]); |
| 60 EXPECT_TRUE([field_ textShouldPaste:nil]); | 101 EXPECT_TRUE([field_ textShouldPaste:nil]); |
| 61 | 102 |
| 62 scoped_nsobject<AutocompleteTextFieldTestDelegate> shouldPaste( | 103 scoped_nsobject<AutocompleteTextFieldTestDelegate> shouldPaste( |
| 63 [[AutocompleteTextFieldTestDelegate alloc] initWithTextShouldPaste:YES]); | 104 [[AutocompleteTextFieldTestDelegate alloc] initWithTextShouldPaste:YES]); |
| 64 [field_ setDelegate:shouldPaste]; | 105 [field_ setDelegate:shouldPaste]; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 [[field_ cell] editWithFrame:[field_ bounds] | 149 [[field_ cell] editWithFrame:[field_ bounds] |
| 109 inView:field_ | 150 inView:field_ |
| 110 editor:editor | 151 editor:editor |
| 111 delegate:[field_ delegate] | 152 delegate:[field_ delegate] |
| 112 event:nil]; | 153 event:nil]; |
| 113 EXPECT_FALSE([delegate receivedFlagsChanged]); | 154 EXPECT_FALSE([delegate receivedFlagsChanged]); |
| 114 [editor flagsChanged:nil]; | 155 [editor flagsChanged:nil]; |
| 115 EXPECT_TRUE([delegate receivedFlagsChanged]); | 156 EXPECT_TRUE([delegate receivedFlagsChanged]); |
| 116 } | 157 } |
| 117 | 158 |
| 159 // Test that the field editor is reset correctly when search keyword |
| 160 // or hints change. |
| 161 TEST_F(AutocompleteTextFieldTest, ResetFieldEditor) { |
| 162 EXPECT_EQ(nil, [field_ currentEditor]); |
| 163 EXPECT_EQ([[field_ subviews] count], 0U); |
| 164 [[field_ window] makeFirstResponder:field_]; |
| 165 EXPECT_FALSE(nil == [field_ currentEditor]); |
| 166 EXPECT_EQ([[field_ subviews] count], 1U); |
| 167 |
| 168 // Check that the window delegate is working right. |
| 169 { |
| 170 Class c = [AutocompleteTextFieldEditor class]; |
| 171 EXPECT_TRUE([[field_ currentEditor] isKindOfClass:c]); |
| 172 } |
| 173 |
| 174 // The field editor may not be an immediate subview of |field_|, it |
| 175 // may be a subview of a clipping view (for purposes of scrolling). |
| 176 // So just look at the immediate subview. |
| 177 EXPECT_EQ([[field_ subviews] count], 1U); |
| 178 const NSRect baseEditorFrame([[[field_ subviews] objectAtIndex:0] frame]); |
| 179 |
| 180 AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; |
| 181 EXPECT_FALSE([cell fieldEditorNeedsReset]); |
| 182 |
| 183 // Asking the cell to add a search hint should leave the field |
| 184 // editor alone until -resetFieldEditorFrameIfNeeded is called. |
| 185 // Then the field editor should be moved to a smaller region with |
| 186 // the same left-hand side. |
| 187 [cell setSearchHintString:@"Type to search"]; |
| 188 EXPECT_TRUE([cell fieldEditorNeedsReset]); |
| 189 NSRect r = [[[field_ subviews] objectAtIndex:0] frame]; |
| 190 EXPECT_TRUE(NSEqualRects(r, baseEditorFrame)); |
| 191 [field_ resetFieldEditorFrameIfNeeded]; |
| 192 r = [[[field_ subviews] objectAtIndex:0] frame]; |
| 193 EXPECT_FALSE([cell fieldEditorNeedsReset]); |
| 194 EXPECT_FALSE(NSEqualRects(r, baseEditorFrame)); |
| 195 EXPECT_TRUE(NSContainsRect(baseEditorFrame, r)); |
| 196 EXPECT_EQ(NSMinX(r), NSMinX(baseEditorFrame)); |
| 197 EXPECT_LT(NSWidth(r), NSWidth(baseEditorFrame)); |
| 198 |
| 199 // Save the search-hint editor frame for later. |
| 200 const NSRect searchHintEditorFrame(r); |
| 201 |
| 202 // Asking the cell to change to keyword mode should leave the field |
| 203 // editor alone until -resetFieldEditorFrameIfNeeded is called. |
| 204 // Then the field editor should be moved to a smaller region with |
| 205 // the same right-hand side. |
| 206 [cell setKeywordString:@"Search Engine:"]; |
| 207 EXPECT_TRUE([cell fieldEditorNeedsReset]); |
| 208 r = [[[field_ subviews] objectAtIndex:0] frame]; |
| 209 EXPECT_TRUE(NSEqualRects(r, searchHintEditorFrame)); |
| 210 [field_ resetFieldEditorFrameIfNeeded]; |
| 211 r = [[[field_ subviews] objectAtIndex:0] frame]; |
| 212 EXPECT_FALSE([cell fieldEditorNeedsReset]); |
| 213 EXPECT_FALSE(NSEqualRects(r, baseEditorFrame)); |
| 214 EXPECT_FALSE(NSEqualRects(r, searchHintEditorFrame)); |
| 215 EXPECT_TRUE(NSContainsRect(baseEditorFrame, r)); |
| 216 EXPECT_EQ(NSMaxX(r), NSMaxX(baseEditorFrame)); |
| 217 EXPECT_LT(NSWidth(r), NSWidth(baseEditorFrame)); |
| 218 |
| 219 // Asking the cell to clear everything should leave the field editor |
| 220 // alone until -resetFieldEditorFrameIfNeeded is called. Then the |
| 221 // field editor should be back to baseEditorFrame. |
| 222 [cell clearKeywordAndHint]; |
| 223 EXPECT_TRUE([cell fieldEditorNeedsReset]); |
| 224 [field_ resetFieldEditorFrameIfNeeded]; |
| 225 r = [[[field_ subviews] objectAtIndex:0] frame]; |
| 226 EXPECT_FALSE([cell fieldEditorNeedsReset]); |
| 227 EXPECT_TRUE(NSEqualRects(r, baseEditorFrame)); |
| 228 } |
| 229 |
| 230 // Test that the field editor is reset correctly when search keyword |
| 231 // or hints change. |
| 232 TEST_F(AutocompleteTextFieldTest, ResetFieldEditorBlocksEndEditing) { |
| 233 [[field_ window] makeFirstResponder:field_]; |
| 234 |
| 235 // First, test that -makeFirstResponder: sends |
| 236 // -controlTextDidBeginEditing: and -control:textShouldEndEditing at |
| 237 // the expected times. |
| 238 { |
| 239 scoped_nsobject<AutocompleteTextFieldTestDelegate> delegate( |
| 240 [[AutocompleteTextFieldTestDelegate alloc] initWithTextShouldPaste:NO]); |
| 241 EXPECT_FALSE([delegate receivedControlTextDidBeginEditing]); |
| 242 EXPECT_FALSE([delegate receivedControlTextShouldEndEditing]); |
| 243 |
| 244 [field_ setDelegate:delegate]; |
| 245 [[field_ window] makeFirstResponder:field_]; |
| 246 NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]); |
| 247 EXPECT_TRUE(nil != editor); |
| 248 EXPECT_FALSE([delegate receivedControlTextDidBeginEditing]); |
| 249 EXPECT_FALSE([delegate receivedControlTextShouldEndEditing]); |
| 250 |
| 251 // This should start the begin/end editing state. |
| 252 [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""]; |
| 253 EXPECT_TRUE([delegate receivedControlTextDidBeginEditing]); |
| 254 EXPECT_FALSE([delegate receivedControlTextShouldEndEditing]); |
| 255 |
| 256 // This should send the end-editing message. |
| 257 [[field_ window] makeFirstResponder:field_]; |
| 258 EXPECT_TRUE([delegate receivedControlTextShouldEndEditing]); |
| 259 [field_ setDelegate:nil]; |
| 260 } |
| 261 |
| 262 // Then test that -resetFieldEditorFrameIfNeeded manages without |
| 263 // sending that message. |
| 264 { |
| 265 scoped_nsobject<AutocompleteTextFieldTestDelegate> delegate( |
| 266 [[AutocompleteTextFieldTestDelegate alloc] initWithTextShouldPaste:NO]); |
| 267 [field_ setDelegate:delegate]; |
| 268 EXPECT_FALSE([delegate receivedControlTextDidBeginEditing]); |
| 269 EXPECT_FALSE([delegate receivedControlTextShouldEndEditing]); |
| 270 |
| 271 AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; |
| 272 EXPECT_FALSE([cell fieldEditorNeedsReset]); |
| 273 [cell setSearchHintString:@"Type to search"]; |
| 274 EXPECT_TRUE([cell fieldEditorNeedsReset]); |
| 275 EXPECT_FALSE([delegate receivedControlTextShouldEndEditing]); |
| 276 [field_ resetFieldEditorFrameIfNeeded]; |
| 277 EXPECT_FALSE([delegate receivedControlTextShouldEndEditing]); |
| 278 EXPECT_TRUE([delegate receivedControlTextDidBeginEditing]); |
| 279 } |
| 280 } |
| 281 |
| 118 } // namespace | 282 } // namespace |
| 119 | 283 |
| 120 @implementation AutocompleteTextFieldTestDelegate | 284 @implementation AutocompleteTextFieldTestDelegate |
| 121 | 285 |
| 122 - initWithTextShouldPaste:(BOOL)flag { | 286 - initWithTextShouldPaste:(BOOL)flag { |
| 123 self = [super init]; | 287 self = [super init]; |
| 124 if (self) { | 288 if (self) { |
| 125 textShouldPaste_ = flag; | 289 textShouldPaste_ = flag; |
| 126 receivedTextShouldPaste_ = NO; | 290 receivedTextShouldPaste_ = NO; |
| 127 receivedFlagsChanged_ = NO; | 291 receivedFlagsChanged_ = NO; |
| 292 receivedControlTextDidBeginEditing_ = NO; |
| 293 receivedControlTextShouldEndEditing_ = NO; |
| 128 } | 294 } |
| 129 return self; | 295 return self; |
| 130 } | 296 } |
| 131 | 297 |
| 132 - (BOOL)receivedTextShouldPaste { | 298 - (BOOL)receivedTextShouldPaste { |
| 133 return receivedTextShouldPaste_; | 299 return receivedTextShouldPaste_; |
| 134 } | 300 } |
| 135 | 301 |
| 136 - (BOOL)receivedFlagsChanged { | 302 - (BOOL)receivedFlagsChanged { |
| 137 return receivedFlagsChanged_; | 303 return receivedFlagsChanged_; |
| 138 } | 304 } |
| 139 | 305 |
| 306 - (BOOL)receivedControlTextDidBeginEditing { |
| 307 return receivedControlTextDidBeginEditing_; |
| 308 } |
| 309 |
| 310 - (BOOL)receivedControlTextShouldEndEditing { |
| 311 return receivedControlTextShouldEndEditing_; |
| 312 } |
| 313 |
| 140 - (BOOL)control:(NSControl*)control textShouldPaste:(NSText*)fieldEditor { | 314 - (BOOL)control:(NSControl*)control textShouldPaste:(NSText*)fieldEditor { |
| 141 receivedTextShouldPaste_ = YES; | 315 receivedTextShouldPaste_ = YES; |
| 142 return textShouldPaste_; | 316 return textShouldPaste_; |
| 143 } | 317 } |
| 144 | 318 |
| 145 - (void)control:(id)control flagsChanged:(NSEvent*)theEvent { | 319 - (void)control:(id)control flagsChanged:(NSEvent*)theEvent { |
| 146 receivedFlagsChanged_ = YES; | 320 receivedFlagsChanged_ = YES; |
| 147 } | 321 } |
| 148 | 322 |
| 323 - (void)controlTextDidBeginEditing:(NSNotification*)aNotification { |
| 324 receivedControlTextDidBeginEditing_ = YES; |
| 325 } |
| 326 |
| 327 - (BOOL)control:(NSControl*)control textShouldEndEditing:(NSText*)fieldEditor { |
| 328 receivedControlTextShouldEndEditing_ = YES; |
| 329 return YES; |
| 330 } |
| 331 |
| 149 @end | 332 @end |
| 333 |
| 334 @implementation AutocompleteTextFieldWindowTestDelegate |
| 335 |
| 336 - (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject { |
| 337 EXPECT_TRUE([anObject isKindOfClass:[AutocompleteTextField class]]); |
| 338 |
| 339 if (editor_ == nil) { |
| 340 editor_.reset([[AutocompleteTextFieldEditor alloc] init]); |
| 341 } |
| 342 EXPECT_TRUE(editor_ != nil); |
| 343 |
| 344 // This needs to be called every time, otherwise notifications |
| 345 // aren't sent correctly. |
| 346 [editor_ setFieldEditor:YES]; |
| 347 return editor_; |
| 348 } |
| 349 |
| 350 @end |
| OLD | NEW |