| OLD | NEW |
| 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 | 18 |
| 19 using base::ASCIIToUTF16; |
| 20 using base::SysNSStringToUTF8; |
| 21 using base::SysNSStringToUTF16; |
| 22 using base::SysUTF8ToNSString; |
| 23 |
| 24 #define EXPECT_EQ_RANGE(a, b) \ |
| 25 EXPECT_EQ(a.location, b.location); \ |
| 26 EXPECT_EQ(a.length, b.length); |
| 27 |
| 28 namespace { |
| 29 |
| 30 // Empty range shortcut for readibility. |
| 31 NSRange EmptyRange() { |
| 32 return NSMakeRange(NSNotFound, 0); |
| 33 } |
| 34 |
| 35 } // namespace |
| 36 |
| 16 namespace views { | 37 namespace views { |
| 17 | 38 |
| 18 class BridgedNativeWidgetTest : public ui::CocoaTest { | 39 class BridgedNativeWidgetTest : public ui::CocoaTest { |
| 19 public: | 40 public: |
| 20 BridgedNativeWidgetTest(); | 41 BridgedNativeWidgetTest(); |
| 21 virtual ~BridgedNativeWidgetTest(); | 42 virtual ~BridgedNativeWidgetTest(); |
| 22 | 43 |
| 44 // Install a textfield in the view hierarchy and make it the text input |
| 45 // client. |
| 46 void InstallTextField(const std::string& text); |
| 47 |
| 48 // Returns the current text as std::string. |
| 49 std::string GetText(); |
| 50 |
| 23 // testing::Test: | 51 // testing::Test: |
| 24 virtual void SetUp() OVERRIDE; | 52 virtual void SetUp() OVERRIDE; |
| 25 virtual void TearDown() OVERRIDE; | 53 virtual void TearDown() OVERRIDE; |
| 26 | 54 |
| 27 protected: | 55 protected: |
| 28 // TODO(tapted): Make this a EventCountView from widget_unittest.cc. | 56 // TODO(tapted): Make this a EventCountView from widget_unittest.cc. |
| 29 scoped_ptr<views::View> view_; | 57 scoped_ptr<views::View> view_; |
| 30 scoped_ptr<BridgedNativeWidget> bridge_; | 58 scoped_ptr<BridgedNativeWidget> bridge_; |
| 59 BridgedContentView* ns_view_; // Weak. Owned by bridge_. |
| 31 | 60 |
| 32 private: | 61 private: |
| 33 DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTest); | 62 DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetTest); |
| 34 }; | 63 }; |
| 35 | 64 |
| 36 BridgedNativeWidgetTest::BridgedNativeWidgetTest() { | 65 BridgedNativeWidgetTest::BridgedNativeWidgetTest() { |
| 37 } | 66 } |
| 38 | 67 |
| 39 BridgedNativeWidgetTest::~BridgedNativeWidgetTest() { | 68 BridgedNativeWidgetTest::~BridgedNativeWidgetTest() { |
| 40 } | 69 } |
| 41 | 70 |
| 71 void BridgedNativeWidgetTest::InstallTextField(const std::string& text) { |
| 72 Textfield* textfield = new Textfield(); |
| 73 textfield->SetText(ASCIIToUTF16(text)); |
| 74 view_->AddChildView(textfield); |
| 75 [ns_view_ setTextInputClient:textfield]; |
| 76 } |
| 77 |
| 78 std::string BridgedNativeWidgetTest::GetText() { |
| 79 NSRange range = NSMakeRange(0, NSUIntegerMax); |
| 80 NSAttributedString* text = |
| 81 [ns_view_ attributedSubstringForProposedRange:range actualRange:NULL]; |
| 82 return SysNSStringToUTF8([text string]); |
| 83 } |
| 84 |
| 42 void BridgedNativeWidgetTest::SetUp() { | 85 void BridgedNativeWidgetTest::SetUp() { |
| 43 ui::CocoaTest::SetUp(); | 86 ui::CocoaTest::SetUp(); |
| 44 | 87 |
| 45 view_.reset(new views::View); | 88 view_.reset(new views::View); |
| 46 bridge_.reset(new BridgedNativeWidget); | 89 bridge_.reset(new BridgedNativeWidget); |
| 47 base::scoped_nsobject<NSWindow> window([test_window() retain]); | 90 base::scoped_nsobject<NSWindow> window([test_window() retain]); |
| 48 bridge_->Init(window); | 91 bridge_->Init(window); |
| 49 bridge_->SetRootView(view_.get()); | 92 bridge_->SetRootView(view_.get()); |
| 93 ns_view_ = bridge_->ns_view(); |
| 50 | 94 |
| 51 [test_window() makePretendKeyWindowAndSetFirstResponder:bridge_->ns_view()]; | 95 [test_window() makePretendKeyWindowAndSetFirstResponder:bridge_->ns_view()]; |
| 52 } | 96 } |
| 53 | 97 |
| 54 void BridgedNativeWidgetTest::TearDown() { | 98 void BridgedNativeWidgetTest::TearDown() { |
| 55 [test_window() clearPretendKeyWindowAndFirstResponder]; | 99 [test_window() clearPretendKeyWindowAndFirstResponder]; |
| 56 | 100 |
| 57 bridge_.reset(); | 101 bridge_.reset(); |
| 58 view_.reset(); | 102 view_.reset(); |
| 59 | 103 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 // Make sure a resize actually occurs. | 142 // Make sure a resize actually occurs. |
| 99 EXPECT_NE(kTestNewWidth, view_->width()); | 143 EXPECT_NE(kTestNewWidth, view_->width()); |
| 100 EXPECT_NE(kTestNewHeight, view_->height()); | 144 EXPECT_NE(kTestNewHeight, view_->height()); |
| 101 | 145 |
| 102 [test_window() setFrame:NSMakeRect(0, 0, kTestNewWidth, kTestNewHeight) | 146 [test_window() setFrame:NSMakeRect(0, 0, kTestNewWidth, kTestNewHeight) |
| 103 display:NO]; | 147 display:NO]; |
| 104 EXPECT_EQ(kTestNewWidth, view_->width()); | 148 EXPECT_EQ(kTestNewWidth, view_->width()); |
| 105 EXPECT_EQ(kTestNewHeight, view_->height()); | 149 EXPECT_EQ(kTestNewHeight, view_->height()); |
| 106 } | 150 } |
| 107 | 151 |
| 108 TEST_F(BridgedNativeWidgetTest, CreateInputMethod) { | 152 TEST_F(BridgedNativeWidgetTest, CreateInputMethodShouldNotReturnNull) { |
| 109 scoped_ptr<views::InputMethod> input_method(bridge_->CreateInputMethod()); | 153 scoped_ptr<views::InputMethod> input_method(bridge_->CreateInputMethod()); |
| 110 EXPECT_TRUE(input_method); | 154 EXPECT_TRUE(input_method); |
| 111 } | 155 } |
| 112 | 156 |
| 113 TEST_F(BridgedNativeWidgetTest, GetHostInputMethod) { | 157 TEST_F(BridgedNativeWidgetTest, GetHostInputMethodShouldNotReturnNull) { |
| 114 EXPECT_TRUE(bridge_->GetHostInputMethod()); | 158 EXPECT_TRUE(bridge_->GetHostInputMethod()); |
| 115 } | 159 } |
| 116 | 160 |
| 161 // Test getting complete string using text input protocol. |
| 162 TEST_F(BridgedNativeWidgetTest, TextInput_GetCompleteString) { |
| 163 const std::string kTestString = "foo bar baz"; |
| 164 InstallTextField(kTestString); |
| 165 |
| 166 NSRange range = NSMakeRange(0, kTestString.size()); |
| 167 NSRange actual_range; |
| 168 NSAttributedString* text = |
| 169 [ns_view_ attributedSubstringForProposedRange:range |
| 170 actualRange:&actual_range]; |
| 171 EXPECT_EQ(kTestString, SysNSStringToUTF8([text string])); |
| 172 EXPECT_EQ_RANGE(range, actual_range); |
| 173 } |
| 174 |
| 175 // Test getting middle substring using text input protocol. |
| 176 TEST_F(BridgedNativeWidgetTest, TextInput_GetMiddleSubstring) { |
| 177 const std::string kTestString = "foo bar baz"; |
| 178 InstallTextField(kTestString); |
| 179 |
| 180 NSRange range = NSMakeRange(4, 3); |
| 181 NSRange actual_range; |
| 182 NSAttributedString* text = |
| 183 [ns_view_ attributedSubstringForProposedRange:range |
| 184 actualRange:&actual_range]; |
| 185 EXPECT_EQ("bar", SysNSStringToUTF8([text string])); |
| 186 EXPECT_EQ_RANGE(range, actual_range); |
| 187 } |
| 188 |
| 189 // Test getting ending substring using text input protocol. |
| 190 TEST_F(BridgedNativeWidgetTest, TextInput_GetEndingSubstring) { |
| 191 const std::string kTestString = "foo bar baz"; |
| 192 InstallTextField(kTestString); |
| 193 |
| 194 NSRange range = NSMakeRange(8, 100); |
| 195 NSRange actual_range; |
| 196 NSAttributedString* text = |
| 197 [ns_view_ attributedSubstringForProposedRange:range |
| 198 actualRange:&actual_range]; |
| 199 EXPECT_EQ("baz", SysNSStringToUTF8([text string])); |
| 200 EXPECT_EQ(range.location, actual_range.location); |
| 201 EXPECT_EQ(3U, actual_range.length); |
| 202 } |
| 203 |
| 204 // Test getting empty substring using text input protocol. |
| 205 TEST_F(BridgedNativeWidgetTest, TextInput_GetEmptySubstring) { |
| 206 const std::string kTestString = "foo bar baz"; |
| 207 InstallTextField(kTestString); |
| 208 |
| 209 NSRange range = EmptyRange(); |
| 210 NSRange actual_range; |
| 211 NSAttributedString* text = |
| 212 [ns_view_ attributedSubstringForProposedRange:range |
| 213 actualRange:&actual_range]; |
| 214 EXPECT_EQ("", SysNSStringToUTF8([text string])); |
| 215 EXPECT_EQ_RANGE(range, actual_range); |
| 216 } |
| 217 |
| 218 // Test inserting text using text input protocol. |
| 219 TEST_F(BridgedNativeWidgetTest, TextInput_InsertText) { |
| 220 const std::string kTestString = "foo"; |
| 221 InstallTextField(kTestString); |
| 222 |
| 223 [ns_view_ insertText:SysUTF8ToNSString(kTestString) |
| 224 replacementRange:EmptyRange()]; |
| 225 gfx::Range range(0, kTestString.size()); |
| 226 base::string16 text; |
| 227 EXPECT_TRUE([ns_view_ textInputClient]->GetTextFromRange(range, &text)); |
| 228 EXPECT_EQ(ASCIIToUTF16(kTestString), text); |
| 229 } |
| 230 |
| 231 // Test replacing text using text input protocol. |
| 232 TEST_F(BridgedNativeWidgetTest, TextInput_ReplaceText) { |
| 233 const std::string kTestString = "foo bar"; |
| 234 InstallTextField(kTestString); |
| 235 |
| 236 [ns_view_ insertText:@"baz" replacementRange:NSMakeRange(4, 3)]; |
| 237 EXPECT_EQ("foo baz", GetText()); |
| 238 } |
| 239 |
| 240 // Test IME composition using text input protocol. |
| 241 TEST_F(BridgedNativeWidgetTest, TextInput_Compose) { |
| 242 const std::string kTestString = "foo "; |
| 243 InstallTextField(kTestString); |
| 244 |
| 245 EXPECT_FALSE([ns_view_ hasMarkedText]); |
| 246 EXPECT_EQ_RANGE(EmptyRange(), [ns_view_ markedRange]); |
| 247 |
| 248 // Start composition. |
| 249 NSString* compositionText = @"bar"; |
| 250 NSUInteger compositionLength = [compositionText length]; |
| 251 [ns_view_ setMarkedText:compositionText |
| 252 selectedRange:NSMakeRange(0, 2) |
| 253 replacementRange:EmptyRange()]; |
| 254 EXPECT_TRUE([ns_view_ hasMarkedText]); |
| 255 EXPECT_EQ_RANGE(NSMakeRange(kTestString.size(), compositionLength), |
| 256 [ns_view_ markedRange]); |
| 257 EXPECT_EQ_RANGE(NSMakeRange(kTestString.size(), 2), [ns_view_ selectedRange]); |
| 258 |
| 259 // Confirm composition. |
| 260 [ns_view_ unmarkText]; |
| 261 EXPECT_FALSE([ns_view_ hasMarkedText]); |
| 262 EXPECT_EQ_RANGE(EmptyRange(), [ns_view_ markedRange]); |
| 263 EXPECT_EQ("foo bar", GetText()); |
| 264 EXPECT_EQ_RANGE(NSMakeRange(GetText().size(), 0), [ns_view_ selectedRange]); |
| 265 } |
| 266 |
| 267 // Test moving the caret left and right using text input protocol. |
| 268 TEST_F(BridgedNativeWidgetTest, TextInput_MoveLeftRight) { |
| 269 InstallTextField("foo"); |
| 270 EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]); |
| 271 |
| 272 // Move right not allowed, out of range. |
| 273 [ns_view_ doCommandBySelector:@selector(moveRight:)]; |
| 274 EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]); |
| 275 |
| 276 // Move left. |
| 277 [ns_view_ doCommandBySelector:@selector(moveLeft:)]; |
| 278 EXPECT_EQ_RANGE(NSMakeRange(2, 0), [ns_view_ selectedRange]); |
| 279 |
| 280 // Move right. |
| 281 [ns_view_ doCommandBySelector:@selector(moveRight:)]; |
| 282 EXPECT_EQ_RANGE(NSMakeRange(3, 0), [ns_view_ selectedRange]); |
| 283 } |
| 284 |
| 285 // Test backward delete using text input protocol. |
| 286 TEST_F(BridgedNativeWidgetTest, TextInput_DeleteBackward) { |
| 287 InstallTextField("a"); |
| 288 EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]); |
| 289 |
| 290 // Delete one character. |
| 291 [ns_view_ doCommandBySelector:@selector(deleteBackward:)]; |
| 292 EXPECT_EQ("", GetText()); |
| 293 EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]); |
| 294 |
| 295 // Try to delete again on an empty string. |
| 296 [ns_view_ doCommandBySelector:@selector(deleteBackward:)]; |
| 297 EXPECT_EQ("", GetText()); |
| 298 EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]); |
| 299 } |
| 300 |
| 301 // Test forward delete using text input protocol. |
| 302 TEST_F(BridgedNativeWidgetTest, TextInput_DeleteForward) { |
| 303 InstallTextField("a"); |
| 304 EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]); |
| 305 |
| 306 // At the end of the string, can't delete forward. |
| 307 [ns_view_ doCommandBySelector:@selector(deleteForward:)]; |
| 308 EXPECT_EQ("a", GetText()); |
| 309 EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]); |
| 310 |
| 311 // Should succeed after moving left first. |
| 312 [ns_view_ doCommandBySelector:@selector(moveLeft:)]; |
| 313 [ns_view_ doCommandBySelector:@selector(deleteForward:)]; |
| 314 EXPECT_EQ("", GetText()); |
| 315 EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]); |
| 316 } |
| 317 |
| 117 } // namespace views | 318 } // namespace views |
| OLD | NEW |