Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: ui/views/cocoa/bridged_native_widget_unittest.mm

Issue 329463002: MacViews: Implement text input. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase to master Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.mm ('k') | ui/views/widget/native_widget_mac.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "ui/views/cocoa/bridged_native_widget.h" 5 #import "ui/views/cocoa/bridged_native_widget.h"
6 6
7 #import <Cocoa/Cocoa.h> 7 #import <Cocoa/Cocoa.h>
8 8
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
10 #import "testing/gtest_mac.h" 12 #import "testing/gtest_mac.h"
11 #import "ui/gfx/test/ui_cocoa_test_helper.h" 13 #import "ui/gfx/test/ui_cocoa_test_helper.h"
12 #import "ui/views/cocoa/bridged_content_view.h" 14 #import "ui/views/cocoa/bridged_content_view.h"
15 #include "ui/views/controls/textfield/textfield.h"
13 #include "ui/views/ime/input_method.h" 16 #include "ui/views/ime/input_method.h"
14 #include "ui/views/view.h" 17 #include "ui/views/view.h"
15 #include "ui/views/widget/native_widget_mac.h" 18 #include "ui/views/widget/native_widget_mac.h"
16 #include "ui/views/widget/widget.h" 19 #include "ui/views/widget/widget.h"
17 #include "ui/views/widget/widget_observer.h" 20 #include "ui/views/widget/widget_observer.h"
18 21
22 using base::ASCIIToUTF16;
23 using base::SysNSStringToUTF8;
24 using base::SysNSStringToUTF16;
25 using base::SysUTF8ToNSString;
26
27 #define EXPECT_EQ_RANGE(a, b) \
28 EXPECT_EQ(a.location, b.location); \
29 EXPECT_EQ(a.length, b.length);
30
31 namespace {
32
33 // Empty range shortcut for readibility.
34 NSRange EmptyRange() {
35 return NSMakeRange(NSNotFound, 0);
36 }
37
38 } // namespace
39
19 namespace views { 40 namespace views {
20 namespace test { 41 namespace test {
21 42
22 // Provides the |parent| argument to construct a BridgedNativeWidget. 43 // Provides the |parent| argument to construct a BridgedNativeWidget.
23 class MockNativeWidgetMac : public NativeWidgetMac { 44 class MockNativeWidgetMac : public NativeWidgetMac {
24 public: 45 public:
25 MockNativeWidgetMac(Widget* delegate) : NativeWidgetMac(delegate) {} 46 MockNativeWidgetMac(Widget* delegate) : NativeWidgetMac(delegate) {}
26 47
27 // Expose a reference, so that it can be reset() independently. 48 // Expose a reference, so that it can be reset() independently.
28 scoped_ptr<BridgedNativeWidget>& bridge() { 49 scoped_ptr<BridgedNativeWidget>& bridge() {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 protected: 94 protected:
74 scoped_ptr<Widget> widget_; 95 scoped_ptr<Widget> widget_;
75 MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|. 96 MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|.
76 }; 97 };
77 98
78 class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase { 99 class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase {
79 public: 100 public:
80 BridgedNativeWidgetTest(); 101 BridgedNativeWidgetTest();
81 virtual ~BridgedNativeWidgetTest(); 102 virtual ~BridgedNativeWidgetTest();
82 103
104 // Install a textfield in the view hierarchy and make it the text input
105 // client.
106 void InstallTextField(const std::string& text);
107
108 // Returns the current text as std::string.
109 std::string GetText();
110
83 // testing::Test: 111 // testing::Test:
84 virtual void SetUp() OVERRIDE; 112 virtual void SetUp() OVERRIDE;
85 virtual void TearDown() OVERRIDE; 113 virtual void TearDown() OVERRIDE;
86 114
87 protected: 115 protected:
88 // TODO(tapted): Make this a EventCountView from widget_unittest.cc. 116 // TODO(tapted): Make this a EventCountView from widget_unittest.cc.
89 scoped_ptr<views::View> view_; 117 scoped_ptr<views::View> view_;
118 scoped_ptr<BridgedNativeWidget> bridge_;
119 BridgedContentView* ns_view_; // Weak. Owned by bridge_.
90 120
91 private: 121 private:
92 DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTest); 122 DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTest);
93 }; 123 };
94 124
95 BridgedNativeWidgetTest::BridgedNativeWidgetTest() { 125 BridgedNativeWidgetTest::BridgedNativeWidgetTest() {
96 } 126 }
97 127
98 BridgedNativeWidgetTest::~BridgedNativeWidgetTest() { 128 BridgedNativeWidgetTest::~BridgedNativeWidgetTest() {
99 } 129 }
100 130
131 void BridgedNativeWidgetTest::InstallTextField(const std::string& text) {
132 Textfield* textfield = new Textfield();
133 textfield->SetText(ASCIIToUTF16(text));
134 view_->AddChildView(textfield);
135 [ns_view_ setTextInputClient:textfield];
136 }
137
138 std::string BridgedNativeWidgetTest::GetText() {
139 NSRange range = NSMakeRange(0, NSUIntegerMax);
140 NSAttributedString* text =
141 [ns_view_ attributedSubstringForProposedRange:range actualRange:NULL];
142 return SysNSStringToUTF8([text string]);
143 }
144
101 void BridgedNativeWidgetTest::SetUp() { 145 void BridgedNativeWidgetTest::SetUp() {
102 BridgedNativeWidgetTestBase::SetUp(); 146 BridgedNativeWidgetTestBase::SetUp();
103 147
104 view_.reset(new views::View); 148 view_.reset(new views::View);
105 base::scoped_nsobject<NSWindow> window([test_window() retain]); 149 base::scoped_nsobject<NSWindow> window([test_window() retain]);
106 150
107 EXPECT_FALSE([window delegate]); 151 EXPECT_FALSE([window delegate]);
108 bridge()->Init(window, Widget::InitParams()); 152 bridge()->Init(window, Widget::InitParams());
109 153
110 // The delegate should exist before setting the root view. 154 // The delegate should exist before setting the root view.
111 EXPECT_TRUE([window delegate]); 155 EXPECT_TRUE([window delegate]);
112 bridge()->SetRootView(view_.get()); 156 bridge()->SetRootView(view_.get());
157 ns_view_ = bridge()->ns_view();
113 158
114 [test_window() makePretendKeyWindowAndSetFirstResponder:bridge()->ns_view()]; 159 [test_window() makePretendKeyWindowAndSetFirstResponder:bridge()->ns_view()];
115 } 160 }
116 161
117 void BridgedNativeWidgetTest::TearDown() { 162 void BridgedNativeWidgetTest::TearDown() {
118 view_.reset(); 163 view_.reset();
119 BridgedNativeWidgetTestBase::TearDown(); 164 BridgedNativeWidgetTestBase::TearDown();
120 } 165 }
121 166
122 // The TEST_VIEW macro expects the view it's testing to have a superview. In 167 // The TEST_VIEW macro expects the view it's testing to have a superview. In
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 // Make sure a resize actually occurs. 203 // Make sure a resize actually occurs.
159 EXPECT_NE(kTestNewWidth, view_->width()); 204 EXPECT_NE(kTestNewWidth, view_->width());
160 EXPECT_NE(kTestNewHeight, view_->height()); 205 EXPECT_NE(kTestNewHeight, view_->height());
161 206
162 [test_window() setFrame:NSMakeRect(0, 0, kTestNewWidth, kTestNewHeight) 207 [test_window() setFrame:NSMakeRect(0, 0, kTestNewWidth, kTestNewHeight)
163 display:NO]; 208 display:NO];
164 EXPECT_EQ(kTestNewWidth, view_->width()); 209 EXPECT_EQ(kTestNewWidth, view_->width());
165 EXPECT_EQ(kTestNewHeight, view_->height()); 210 EXPECT_EQ(kTestNewHeight, view_->height());
166 } 211 }
167 212
168 TEST_F(BridgedNativeWidgetTest, CreateInputMethod) { 213 TEST_F(BridgedNativeWidgetTest, CreateInputMethodShouldNotReturnNull) {
169 scoped_ptr<views::InputMethod> input_method(bridge()->CreateInputMethod()); 214 scoped_ptr<views::InputMethod> input_method(bridge()->CreateInputMethod());
170 EXPECT_TRUE(input_method); 215 EXPECT_TRUE(input_method);
171 } 216 }
172 217
173 TEST_F(BridgedNativeWidgetTest, GetHostInputMethod) { 218 TEST_F(BridgedNativeWidgetTest, GetHostInputMethodShouldNotReturnNull) {
174 EXPECT_TRUE(bridge()->GetHostInputMethod()); 219 EXPECT_TRUE(bridge()->GetHostInputMethod());
175 } 220 }
176 221
177 // A simpler test harness for testing initialization flows. 222 // A simpler test harness for testing initialization flows.
178 typedef BridgedNativeWidgetTestBase BridgedNativeWidgetInitTest; 223 typedef BridgedNativeWidgetTestBase BridgedNativeWidgetInitTest;
179 224
180 // Test that BridgedNativeWidget remains sane if Init() is never called. 225 // Test that BridgedNativeWidget remains sane if Init() is never called.
181 TEST_F(BridgedNativeWidgetInitTest, InitNotCalled) { 226 TEST_F(BridgedNativeWidgetInitTest, InitNotCalled) {
182 EXPECT_FALSE(bridge()->ns_view()); 227 EXPECT_FALSE(bridge()->ns_view());
183 EXPECT_FALSE(bridge()->ns_window()); 228 EXPECT_FALSE(bridge()->ns_window());
(...skipping 17 matching lines...) Expand all
201 246
202 EXPECT_FALSE([child_window parentWindow]); 247 EXPECT_FALSE([child_window parentWindow]);
203 bridge()->Init(child_window, params); 248 bridge()->Init(child_window, params);
204 249
205 EXPECT_EQ(1u, [[test_window() childWindows] count]); 250 EXPECT_EQ(1u, [[test_window() childWindows] count]);
206 EXPECT_EQ(test_window(), [bridge()->ns_window() parentWindow]); 251 EXPECT_EQ(test_window(), [bridge()->ns_window() parentWindow]);
207 bridge().reset(); 252 bridge().reset();
208 EXPECT_EQ(0u, [[test_window() childWindows] count]); 253 EXPECT_EQ(0u, [[test_window() childWindows] count]);
209 } 254 }
210 255
256 // Test getting complete string using text input protocol.
257 TEST_F(BridgedNativeWidgetTest, TextInput_GetCompleteString) {
258 const std::string kTestString = "foo bar baz";
259 InstallTextField(kTestString);
260
261 NSRange range = NSMakeRange(0, kTestString.size());
262 NSRange actual_range;
263 NSAttributedString* text =
264 [ns_view_ attributedSubstringForProposedRange:range
265 actualRange:&actual_range];
266 EXPECT_EQ(kTestString, SysNSStringToUTF8([text string]));
267 EXPECT_EQ_RANGE(range, actual_range);
268 }
269
270 // Test getting middle substring using text input protocol.
271 TEST_F(BridgedNativeWidgetTest, TextInput_GetMiddleSubstring) {
272 const std::string kTestString = "foo bar baz";
273 InstallTextField(kTestString);
274
275 NSRange range = NSMakeRange(4, 3);
276 NSRange actual_range;
277 NSAttributedString* text =
278 [ns_view_ attributedSubstringForProposedRange:range
279 actualRange:&actual_range];
280 EXPECT_EQ("bar", SysNSStringToUTF8([text string]));
281 EXPECT_EQ_RANGE(range, actual_range);
282 }
283
284 // Test getting ending substring using text input protocol.
285 TEST_F(BridgedNativeWidgetTest, TextInput_GetEndingSubstring) {
286 const std::string kTestString = "foo bar baz";
287 InstallTextField(kTestString);
288
289 NSRange range = NSMakeRange(8, 100);
290 NSRange actual_range;
291 NSAttributedString* text =
292 [ns_view_ attributedSubstringForProposedRange:range
293 actualRange:&actual_range];
294 EXPECT_EQ("baz", SysNSStringToUTF8([text string]));
295 EXPECT_EQ(range.location, actual_range.location);
296 EXPECT_EQ(3U, actual_range.length);
297 }
298
299 // Test getting empty substring using text input protocol.
300 TEST_F(BridgedNativeWidgetTest, TextInput_GetEmptySubstring) {
301 const std::string kTestString = "foo bar baz";
302 InstallTextField(kTestString);
303
304 NSRange range = EmptyRange();
305 NSRange actual_range;
306 NSAttributedString* text =
307 [ns_view_ attributedSubstringForProposedRange:range
308 actualRange:&actual_range];
309 EXPECT_EQ("", SysNSStringToUTF8([text string]));
310 EXPECT_EQ_RANGE(range, actual_range);
311 }
312
313 // Test inserting text using text input protocol.
314 TEST_F(BridgedNativeWidgetTest, TextInput_InsertText) {
315 const std::string kTestString = "foo";
316 InstallTextField(kTestString);
317
318 [ns_view_ insertText:SysUTF8ToNSString(kTestString)
319 replacementRange:EmptyRange()];
320 gfx::Range range(0, kTestString.size());
321 base::string16 text;
322 EXPECT_TRUE([ns_view_ textInputClient]->GetTextFromRange(range, &text));
323 EXPECT_EQ(ASCIIToUTF16(kTestString), text);
324 }
325
326 // Test replacing text using text input protocol.
327 TEST_F(BridgedNativeWidgetTest, TextInput_ReplaceText) {
328 const std::string kTestString = "foo bar";
329 InstallTextField(kTestString);
330
331 [ns_view_ insertText:@"baz" replacementRange:NSMakeRange(4, 3)];
332 EXPECT_EQ("foo baz", GetText());
333 }
334
335 // Test IME composition using text input protocol.
336 TEST_F(BridgedNativeWidgetTest, TextInput_Compose) {
337 const std::string kTestString = "foo ";
338 InstallTextField(kTestString);
339
340 EXPECT_FALSE([ns_view_ hasMarkedText]);
341 EXPECT_EQ_RANGE(EmptyRange(), [ns_view_ markedRange]);
342
343 // Start composition.
344 NSString* compositionText = @"bar";
345 NSUInteger compositionLength = [compositionText length];
346 [ns_view_ setMarkedText:compositionText
347 selectedRange:NSMakeRange(0, 2)
348 replacementRange:EmptyRange()];
349 EXPECT_TRUE([ns_view_ hasMarkedText]);
350 EXPECT_EQ_RANGE(NSMakeRange(kTestString.size(), compositionLength),
351 [ns_view_ markedRange]);
352 EXPECT_EQ_RANGE(NSMakeRange(kTestString.size(), 2), [ns_view_ selectedRange]);
353
354 // Confirm composition.
355 [ns_view_ unmarkText];
356 EXPECT_FALSE([ns_view_ hasMarkedText]);
357 EXPECT_EQ_RANGE(EmptyRange(), [ns_view_ markedRange]);
358 EXPECT_EQ("foo bar", GetText());
359 EXPECT_EQ_RANGE(NSMakeRange(GetText().size(), 0), [ns_view_ selectedRange]);
360 }
361
362 // Test moving the caret left and right using text input protocol.
363 TEST_F(BridgedNativeWidgetTest, TextInput_MoveLeftRight) {
364 InstallTextField("foo");
365 EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]);
366
367 // Move right not allowed, out of range.
368 [ns_view_ doCommandBySelector:@selector(moveRight:)];
369 EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]);
370
371 // Move left.
372 [ns_view_ doCommandBySelector:@selector(moveLeft:)];
373 EXPECT_EQ_RANGE(NSMakeRange(2, 0), [ns_view_ selectedRange]);
374
375 // Move right.
376 [ns_view_ doCommandBySelector:@selector(moveRight:)];
377 EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]);
378 }
379
380 // Test backward delete using text input protocol.
381 TEST_F(BridgedNativeWidgetTest, TextInput_DeleteBackward) {
382 InstallTextField("a");
383 EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]);
384
385 // Delete one character.
386 [ns_view_ doCommandBySelector:@selector(deleteBackward:)];
387 EXPECT_EQ("", GetText());
388 EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]);
389
390 // Try to delete again on an empty string.
391 [ns_view_ doCommandBySelector:@selector(deleteBackward:)];
392 EXPECT_EQ("", GetText());
393 EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]);
394 }
395
396 // Test forward delete using text input protocol.
397 TEST_F(BridgedNativeWidgetTest, TextInput_DeleteForward) {
398 InstallTextField("a");
399 EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]);
400
401 // At the end of the string, can't delete forward.
402 [ns_view_ doCommandBySelector:@selector(deleteForward:)];
403 EXPECT_EQ("a", GetText());
404 EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]);
405
406 // Should succeed after moving left first.
407 [ns_view_ doCommandBySelector:@selector(moveLeft:)];
408 [ns_view_ doCommandBySelector:@selector(deleteForward:)];
409 EXPECT_EQ("", GetText());
410 EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]);
411 }
412
211 } // namespace test 413 } // namespace test
212 } // namespace views 414 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/cocoa/bridged_native_widget.mm ('k') | ui/views/widget/native_widget_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698