| Index: ui/views/cocoa/bridged_native_widget_unittest.mm
|
| diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm
|
| index fcc59453bb04c61438eaa0224c4c5316ac387753..80f0bd8b6da9030846417db7f7e65f5a2afac526 100644
|
| --- a/ui/views/cocoa/bridged_native_widget_unittest.mm
|
| +++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
|
| @@ -13,6 +13,7 @@
|
| #import "base/mac/sdk_forward_declarations.h"
|
| #include "base/macros.h"
|
| #include "base/message_loop/message_loop.h"
|
| +#include "base/strings/stringprintf.h"
|
| #include "base/strings/sys_string_conversions.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #import "testing/gtest_mac.h"
|
| @@ -212,12 +213,14 @@ class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase {
|
|
|
| // Install a textfield with input type |text_input_type| in the view hierarchy
|
| // and make it the text input client. Also initializes |dummy_text_view_|.
|
| - void InstallTextField(const std::string& text,
|
| + void InstallTextField(const base::string16& text,
|
| ui::TextInputType text_input_type);
|
|
|
| // Install a textfield with input type ui::TEXT_INPUT_TYPE_TEXT in the view
|
| // hierarchy and make it the text input client. Also initializes
|
| // |dummy_text_view_|.
|
| + void InstallTextField(const base::string16& text);
|
| +
|
| void InstallTextField(const std::string& text);
|
|
|
| // Returns the actual current text for |ns_view_|.
|
| @@ -238,6 +241,11 @@ class BridgedNativeWidgetTest : public BridgedNativeWidgetTestBase {
|
| // Perform command |sel| on |ns_view_| and |dummy_text_view_|.
|
| void PerformCommand(SEL sel);
|
|
|
| + // Make selection from |start| to |end| on installed textfield and
|
| + // |dummy_text_view_|. If |start| > |end|, extend selection to left from
|
| + // |start|.
|
| + void MakeSelection(int start, int end);
|
| +
|
| // testing::Test:
|
| void SetUp() override;
|
| void TearDown() override;
|
| @@ -271,11 +279,19 @@ BridgedNativeWidgetTest::BridgedNativeWidgetTest() {
|
| BridgedNativeWidgetTest::~BridgedNativeWidgetTest() {
|
| }
|
|
|
| +void BridgedNativeWidgetTest::InstallTextField(const base::string16& text) {
|
| + InstallTextField(text, ui::TEXT_INPUT_TYPE_TEXT);
|
| +}
|
| +
|
| +void BridgedNativeWidgetTest::InstallTextField(const std::string& text) {
|
| + InstallTextField(base::ASCIIToUTF16(text), ui::TEXT_INPUT_TYPE_TEXT);
|
| +}
|
| +
|
| void BridgedNativeWidgetTest::InstallTextField(
|
| - const std::string& text,
|
| + const base::string16& text,
|
| ui::TextInputType text_input_type) {
|
| Textfield* textfield = new Textfield();
|
| - textfield->SetText(ASCIIToUTF16(text));
|
| + textfield->SetText(text);
|
| textfield->SetTextInputType(text_input_type);
|
| view_->RemoveAllChildViews(true);
|
| view_->AddChildView(textfield);
|
| @@ -290,11 +306,7 @@ void BridgedNativeWidgetTest::InstallTextField(
|
|
|
| // Initialize the dummy text view.
|
| dummy_text_view_.reset([[NSTextView alloc] initWithFrame:NSZeroRect]);
|
| - [dummy_text_view_ setString:SysUTF8ToNSString(text)];
|
| -}
|
| -
|
| -void BridgedNativeWidgetTest::InstallTextField(const std::string& text) {
|
| - InstallTextField(text, ui::TEXT_INPUT_TYPE_TEXT);
|
| + [dummy_text_view_ setString:SysUTF16ToNSString(text)];
|
| }
|
|
|
| NSString* BridgedNativeWidgetTest::GetActualText() {
|
| @@ -330,6 +342,22 @@ void BridgedNativeWidgetTest::PerformCommand(SEL sel) {
|
| [dummy_text_view_ doCommandBySelector:sel];
|
| }
|
|
|
| +void BridgedNativeWidgetTest::MakeSelection(int start, int end) {
|
| + ui::TextInputClient* client = [ns_view_ textInputClient];
|
| + client->SetSelectionRange(gfx::Range(start, end));
|
| +
|
| + // NSTextView does not support specifying the selection "direction" i.e. the
|
| + // leading edge of selection. Hence we extend the selection from |start| to
|
| + // |end|.
|
| + [dummy_text_view_ setSelectedRange:NSMakeRange(start, 0)];
|
| + SEL sel = start > end ? @selector(moveBackwardAndModifySelection:)
|
| + : @selector(moveForwardAndModifySelection:);
|
| + size_t delta = std::abs(end - start);
|
| +
|
| + for (size_t i = 0; i < delta; i++)
|
| + [dummy_text_view_ doCommandBySelector:sel];
|
| +}
|
| +
|
| void BridgedNativeWidgetTest::SetUp() {
|
| BridgedNativeWidgetTestBase::SetUp();
|
|
|
| @@ -550,7 +578,7 @@ TEST_F(BridgedNativeWidgetInitTest, ShadowType) {
|
| // Ensure a nil NSTextInputContext is returned when the ui::TextInputClient is
|
| // not editable, a password field, or unset.
|
| TEST_F(BridgedNativeWidgetTest, InputContext) {
|
| - const std::string test_string = "test_str";
|
| + const base::string16 test_string = base::ASCIIToUTF16("test_str");
|
| InstallTextField(test_string, ui::TEXT_INPUT_TYPE_PASSWORD);
|
| EXPECT_FALSE([ns_view_ inputContext]);
|
| InstallTextField(test_string, ui::TEXT_INPUT_TYPE_TEXT);
|
| @@ -873,6 +901,89 @@ TEST_F(BridgedNativeWidgetTest, TextInput_DeleteToEndOfParagraph) {
|
| TestDeleteEnd(@selector(deleteToEndOfParagraph:));
|
| }
|
|
|
| +TEST_F(BridgedNativeWidgetTest, EditingCommands) {
|
| + NSArray* selectors = @[
|
| + @"moveForward:", @"moveRight:", @"moveBackward:", @"moveLeft:", @"moveUp:",
|
| + @"moveDown:", @"moveWordForward:", @"moveWordBackward:",
|
| + @"moveToBeginningOfLine:", @"moveToEndOfLine:",
|
| + @"moveToBeginningOfParagraph:", @"moveToEndOfParagraph:",
|
| + @"moveToEndOfDocument:", @"moveToBeginningOfDocument:", @"pageDown:",
|
| + @"pageUp:", @"moveBackwardAndModifySelection:",
|
| + @"moveForwardAndModifySelection:",
|
| + // @"moveWordForwardAndModifySelection:",
|
| + // @"moveWordBackwardAndModifySelection:",
|
| + @"moveUpAndModifySelection:", @"moveDownAndModifySelection:",
|
| + // @"moveToBeginningOfLineAndModifySelection:",
|
| + // @"moveToEndOfLineAndModifySelection:",
|
| + // @"moveToBeginningOfParagraphAndModifySelection:",
|
| + // @"moveToEndOfParagraphAndModifySelection:",
|
| + // @"moveToEndOfDocumentAndModifySelection:",
|
| + // @"moveToBeginningOfDocumentAndModifySelection:",
|
| + @"pageDownAndModifySelection:", @"pageUpAndModifySelection:",
|
| + // @"moveParagraphForwardAndModifySelection:",
|
| + // @"moveParagraphBackwardAndModifySelection:",
|
| + @"moveWordRight:", @"moveWordLeft:", @"moveRightAndModifySelection:",
|
| + @"moveLeftAndModifySelection:",
|
| + // @"moveWordRightAndModifySelection:",
|
| + // @"moveWordLeftAndModifySelection:",
|
| + @"moveToLeftEndOfLine:", @"moveToRightEndOfLine:",
|
| + // @"moveToLeftEndOfLineAndModifySelection:",
|
| + // @"moveToRightEndOfLineAndModifySelection:",
|
| + @"deleteForward:", @"deleteBackward:", @"deleteWordForward:",
|
| + @"deleteWordBackward:", @"deleteToBeginningOfLine:", @"deleteToEndOfLine:",
|
| + @"deleteToBeginningOfParagraph:", @"deleteToEndOfParagraph:",
|
| + @"cancelOperation:"
|
| + ];
|
| +
|
| + struct {
|
| + const std::wstring test_string;
|
| + bool rtl;
|
| + } cases[] =
|
| + {{L"abc def", false},
|
| + {L"\x0634\x0632\x0630 \x064A\x062B\x0628", true}};
|
| +
|
| + for (auto test_case : cases) {
|
| + for (NSString* selector_string in selectors) {
|
| + SEL sel = NSSelectorFromString(selector_string);
|
| + const int len = test_case.test_string.length();
|
| + for (int i = 0; i <= len; i++) {
|
| + for (int j = 0; j <= len; j++) {
|
| + SCOPED_TRACE(base::StringPrintf(
|
| + "Testing range [%d-%d] for case %s and selector %s\n", i, j,
|
| + base::WideToUTF8(test_case.test_string).c_str(),
|
| + base::SysNSStringToUTF8(selector_string).c_str()));
|
| +
|
| + InstallTextField(base::WideToUTF16(test_case.test_string));
|
| + MakeSelection(i, j);
|
| + EXPECT_EQ_RANGE_3(NSMakeRange(std::min(i, j), std::abs(i - j)),
|
| + GetExpectedSelectionRange(),
|
| + GetActualSelectionRange());
|
| +
|
| + PerformCommand(sel);
|
| + EXPECT_NSEQ(GetExpectedText(), GetActualText());
|
| +
|
| + // This is another case where NSTextView behaves a bit weirdly. Turns
|
| + // out for RTL text, move[Left/Right]AndModifySelection and
|
| + // move[Forward/Backward]AndModifySelection do not share selection
|
| + // "direction". For eg say current rtl text is "abc|". On doing
|
| + // moveForwardAndModifySelection: twice, text becomes "a|bc|". Now if
|
| + // we do moveLeftAndModifySelection, text should become "|abc|" but
|
| + // instead it becomes "a|b|c". Blink also behaves similarly to our
|
| + // implementation in this case.
|
| + if (!(test_case.rtl &&
|
| + ([selector_string
|
| + isEqualToString:@"moveRightAndModifySelection:"] ||
|
| + [selector_string
|
| + isEqualToString:@"moveLeftAndModifySelection:"]))) {
|
| + EXPECT_EQ_RANGE(GetExpectedSelectionRange(),
|
| + GetActualSelectionRange());
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| // Test firstRectForCharacterRange:actualRange for cases where query range is
|
| // empty or outside composition range.
|
| TEST_F(BridgedNativeWidgetTest, TextInput_FirstRectForCharacterRange_Caret) {
|
|
|