Chromium Code Reviews| Index: views/controls/textfield/textfield_views_model_unittest.cc |
| =================================================================== |
| --- views/controls/textfield/textfield_views_model_unittest.cc (revision 100008) |
| +++ views/controls/textfield/textfield_views_model_unittest.cc (working copy) |
| @@ -2,6 +2,8 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| +#include <vector> |
| + |
| #include "base/auto_reset.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/message_loop.h" |
| @@ -17,6 +19,19 @@ |
| #include "views/test/views_test_base.h" |
| #include "views/views_delegate.h" |
| +namespace { |
| + |
| +struct WordAndCursor { |
| + const wchar_t* word; |
|
msw
2011/09/14 02:43:48
Data members belong below the ctor.
xji
2011/09/15 23:38:13
Done.
|
| + size_t cursor; |
| + WordAndCursor(const wchar_t* w, size_t c) |
| + : word(w), |
| + cursor(c) { |
| + } |
| +}; |
| + |
| +} // namespace |
| + |
| namespace views { |
| class TextfieldViewsModelTest : public ViewsTestBase, |
| @@ -83,8 +98,121 @@ |
| // but backspace should work. |
| EXPECT_TRUE(model.Backspace()); |
| EXPECT_STR_EQ("HELLORL", model.GetText()); |
| + |
| + model.MoveCursorTo(gfx::SelectionModel(5)); |
| + model.ReplaceText(ASCIIToUTF16(" WOR")); |
| + EXPECT_STR_EQ("HELLO WORL", model.GetText()); |
| } |
| +TEST_F(TextfieldViewsModelTest, EditString_SimpleRTL) { |
| + TextfieldViewsModel model(NULL); |
| + // Append two strings. |
| + model.Append(WideToUTF16(L"\x05d0\x05d1\x05d2")); |
| + EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2"), model.GetText()); |
| + model.Append(WideToUTF16(L"\x05e0\x05e1\x05e2")); |
| + EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2\x05e0\x05e1\x05e2"), |
| + model.GetText()); |
| + |
| + // Insert 0x05f0. |
| + model.MoveCursorTo(gfx::SelectionModel(1U)); |
| + model.InsertChar(0x05f0); |
| + EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05d1\x05d2\x05e0\x05e1\x05e2"), |
| + model.GetText()); |
| + |
| + // Replace "\x05d1" with "\x05f1". |
| + model.ReplaceChar(0x05f1); |
| + EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05d2\x05e0\x05e1\x05e2"), |
| + model.GetText()); |
| + |
| + // Delete and backspace. |
| + EXPECT_EQ(3U, model.GetCursorPosition()); |
| + EXPECT_TRUE(model.Delete()); |
| + EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05e0\x05e1\x05e2"), |
| + model.GetText()); |
| + EXPECT_TRUE(model.Backspace()); |
| + EXPECT_EQ(2U, model.GetCursorPosition()); |
| + EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05e0\x05e1\x05e2"), model.GetText()); |
| +} |
| + |
| +TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) { |
| + TextfieldViewsModel model(NULL); |
| + // Append two Hindi strings. |
| + model.Append(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915")); |
| + EXPECT_EQ(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"), |
| + model.GetText()); |
| + model.Append(WideToUTF16(L"\x0915\x094d\x092e\x094d")); |
| + EXPECT_EQ(WideToUTF16( |
| + L"\x0915\x093f\x0915\x094d\x0915\x0915\x094d\x092e\x094d"), |
| + model.GetText()); |
| + |
| + // Check it is not able to place cursor in middle of a grapheme. |
| + model.MoveCursorTo(gfx::SelectionModel(1U)); |
| + EXPECT_EQ(0U, model.GetCursorPosition()); |
| + |
| + model.MoveCursorTo(gfx::SelectionModel(2U)); |
| + EXPECT_EQ(2U, model.GetCursorPosition()); |
| + model.InsertChar('a'); |
| + EXPECT_EQ(WideToUTF16( |
| + L"\x0915\x093f\x0061\x0915\x094d\x0915\x0915\x094d\x092e\x094d"), |
| + model.GetText()); |
| + |
| + // ReplaceChar will replace the whole grapheme. |
| + model.ReplaceChar('b'); |
| + EXPECT_EQ(WideToUTF16( |
| + L"\x0915\x093f\x0061\x0062\x0915\x0915\x094d\x092e\x094d"), |
| + model.GetText()); |
| + EXPECT_EQ(4U, model.GetCursorPosition()); |
| + |
| + // Delete should delete the whole grapheme. |
| + model.MoveCursorTo(gfx::SelectionModel(0U)); |
| + EXPECT_TRUE(model.Delete()); |
| + EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e\x094d"), |
| + model.GetText()); |
| + model.MoveCursorTo(gfx::SelectionModel(model.GetText().length())); |
| + EXPECT_TRUE(model.Backspace()); |
| + EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e"), |
| + model.GetText()); |
| + |
| + // Test cursor position and deletion for Hindi Virama. |
| + model.SetText(WideToUTF16(L"\x0D38\x0D4D\x0D15\x0D16\x0D2E")); |
| + model.MoveCursorTo(gfx::SelectionModel(0)); |
| + EXPECT_EQ(0U, model.GetCursorPosition()); |
| + |
| + model.MoveCursorTo(gfx::SelectionModel(1)); |
| + EXPECT_EQ(0U, model.GetCursorPosition()); |
| + |
| + model.MoveCursorTo(gfx::SelectionModel(2)); |
| + EXPECT_EQ(2U, model.GetCursorPosition()); |
| + |
| + model.MoveCursorTo(gfx::SelectionModel(3)); |
| + EXPECT_EQ(3U, model.GetCursorPosition()); |
| + |
| + model.MoveCursorTo(gfx::SelectionModel(2)); |
| + |
| + EXPECT_TRUE(model.Backspace()); |
| + EXPECT_EQ(WideToUTF16(L"\x0D38\x0D15\x0D16\x0D2E"), model.GetText()); |
| + |
| + // Test Delete/Backspace on Hebrew with non-spacing marks. |
| + model.SetText(WideToUTF16(L"\x05d5\x05b7\x05D9\x05B0\x05D4\x05B4\x05D9")); |
| + model.MoveCursorTo(gfx::SelectionModel(0)); |
| + EXPECT_TRUE(model.Delete()); |
| + EXPECT_TRUE(model.Delete()); |
| + EXPECT_TRUE(model.Delete()); |
| + EXPECT_TRUE(model.Delete()); |
| + EXPECT_EQ(WideToUTF16(L""), model.GetText()); |
| + |
| + // The first 2 characters are not strong directionality characters. |
| + model.SetText(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9\x05BC")); |
| +#if defined(OS_WIN) |
| + model.MoveCursorRight(gfx::LINE_BREAK, false); |
| +#else |
| + model.MoveCursorLeft(gfx::LINE_BREAK, false); |
| +#endif |
| + EXPECT_TRUE(model.Backspace()); |
| + EXPECT_EQ(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"), |
| + model.GetText()); |
| +} |
| + |
| TEST_F(TextfieldViewsModelTest, EmptyString) { |
| TextfieldViewsModel model(NULL); |
| EXPECT_EQ(string16(), model.GetText()); |
| @@ -143,6 +271,88 @@ |
| EXPECT_EQ(5U, model.GetCursorPosition()); |
| } |
| +TEST_F(TextfieldViewsModelTest, Selection_BidiWithNonSpacingMarks) { |
| + // Selection is a logical operation. And it should work with the arrow |
| + // keys doing visual movements, while the selection is logical between |
| + // the (logical) start and end points. Selection is simply defined as |
| + // the portion of text between the logical positions of the start and end |
| + // caret positions. |
| + TextfieldViewsModel model(NULL); |
| + model.Append(WideToUTF16( |
| + L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8"L"def")); |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, false); |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, false); |
| + |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(2U, model.render_text()->GetSelectionStart()); |
| + EXPECT_EQ(3U, model.GetCursorPosition()); |
| + EXPECT_EQ(WideToUTF16(L"c"), model.GetSelectedText()); |
| + |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(2U, model.render_text()->GetSelectionStart()); |
| + EXPECT_EQ(7U, model.GetCursorPosition()); |
| + EXPECT_EQ(WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8"), |
| + model.GetSelectedText()); |
| + |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(2U, model.render_text()->GetSelectionStart()); |
| + EXPECT_EQ(3U, model.GetCursorPosition()); |
| + EXPECT_EQ(WideToUTF16(L"c"), model.GetSelectedText()); |
| + |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(2U, model.render_text()->GetSelectionStart()); |
| + EXPECT_EQ(10U, model.GetCursorPosition()); |
| + EXPECT_EQ(WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8"L"d"), |
| + model.GetSelectedText()); |
| + |
| + model.ClearSelection(); |
| + EXPECT_EQ(string16(), model.GetSelectedText()); |
| + model.SelectAll(); |
| + EXPECT_EQ(WideToUTF16(L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8"L"def"), |
| + model.GetSelectedText()); |
| + |
| + // In case of "aBc", this test shows how to select "aB" or "Bc", assume 'B' is |
| + // an RTL character. |
| + model.SetText(WideToUTF16(L"a\x05E9"L"b")); |
| + model.MoveCursorTo(gfx::SelectionModel(0)); |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(WideToUTF16(L"a"), model.GetSelectedText()); |
| + |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(WideToUTF16(L"a"), model.GetSelectedText()); |
| + |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(WideToUTF16(L"a\x05E9"L"b"), model.GetSelectedText()); |
| + |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, false); |
| + EXPECT_EQ(3U, model.GetCursorPosition()); |
| + model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(WideToUTF16(L"b"), model.GetSelectedText()); |
| + |
| + model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(WideToUTF16(L"b"), model.GetSelectedText()); |
| + |
| + model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(WideToUTF16(L"a\x05E9"L"b"), model.GetSelectedText()); |
| + |
| + model.MoveCursorLeft(gfx::LINE_BREAK, false); |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); |
| + model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(WideToUTF16(L"a\x05E9"), model.GetSelectedText()); |
| + |
| + model.MoveCursorRight(gfx::LINE_BREAK, false); |
| + model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); |
| + model.MoveCursorLeft(gfx::CHARACTER_BREAK, true); |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, true); |
| + EXPECT_EQ(WideToUTF16(L"\x05E9"L"b"), model.GetSelectedText()); |
| + |
| + model.ClearSelection(); |
| + EXPECT_EQ(string16(), model.GetSelectedText()); |
| + model.SelectAll(); |
| + EXPECT_EQ(WideToUTF16(L"a\x05E9"L"b"), model.GetSelectedText()); |
| +} |
| + |
| TEST_F(TextfieldViewsModelTest, SelectionAndEdit) { |
| TextfieldViewsModel model(NULL); |
| model.Append(ASCIIToUTF16("HELLO")); |
| @@ -314,8 +524,8 @@ |
| } |
| void SelectWordTestVerifier(TextfieldViewsModel &model, |
| - const std::string &expected_selected_string, size_t expected_cursor_pos) { |
| - EXPECT_STR_EQ(expected_selected_string, model.GetSelectedText()); |
| + const string16 &expected_selected_string, size_t expected_cursor_pos) { |
| + EXPECT_EQ(expected_selected_string, model.GetSelectedText()); |
| EXPECT_EQ(expected_cursor_pos, model.GetCursorPosition()); |
| } |
| @@ -326,40 +536,70 @@ |
| // Test when cursor is at the beginning. |
| model.MoveCursorLeft(gfx::LINE_BREAK, false); |
| model.SelectWord(); |
| - SelectWordTestVerifier(model, " ", 2U); |
| + SelectWordTestVerifier(model, ASCIIToUTF16(" "), 2U); |
| // Test when cursor is at the beginning of a word. |
| gfx::SelectionModel selection(2U); |
| model.MoveCursorTo(selection); |
| model.SelectWord(); |
| - SelectWordTestVerifier(model, "HELLO", 7U); |
| + SelectWordTestVerifier(model, ASCIIToUTF16("HELLO"), 7U); |
| // Test when cursor is at the end of a word. |
| selection = gfx::SelectionModel(15U); |
| model.MoveCursorTo(selection); |
| model.SelectWord(); |
| - SelectWordTestVerifier(model, "WO", 15U); |
| + SelectWordTestVerifier(model, ASCIIToUTF16(" "), 20U); |
| - // Test when cursor is somewhere in a non-alph-numeric fragment. |
| + // Test when cursor is somewhere in a non-alpha-numeric fragment. |
| for (size_t cursor_pos = 8; cursor_pos < 13U; cursor_pos++) { |
| selection = gfx::SelectionModel(cursor_pos); |
| model.MoveCursorTo(selection); |
| model.SelectWord(); |
| - SelectWordTestVerifier(model, " !! ", 13U); |
| + SelectWordTestVerifier(model, ASCIIToUTF16(" !! "), 13U); |
| } |
| // Test when cursor is somewhere in a whitespace fragment. |
| selection = gfx::SelectionModel(17U); |
| model.MoveCursorTo(selection); |
| model.SelectWord(); |
| - SelectWordTestVerifier(model, " ", 20U); |
| + SelectWordTestVerifier(model, ASCIIToUTF16(" "), 20U); |
| // Test when cursor is at the end. |
| model.MoveCursorRight(gfx::LINE_BREAK, false); |
| model.SelectWord(); |
| - SelectWordTestVerifier(model, " ", 24U); |
| + SelectWordTestVerifier(model, ASCIIToUTF16(" "), 24U); |
| } |
| +TEST_F(TextfieldViewsModelTest, SelectWordTest_MixScripts) { |
| + TextfieldViewsModel model(NULL); |
| + std::vector<WordAndCursor> word_and_cursor; |
| + word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2)); |
| + word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2)); |
| + word_and_cursor.push_back(WordAndCursor(L"\x05d1\x05d2", 5)); |
| + word_and_cursor.push_back(WordAndCursor(L"\x05d1\x05d2", 5)); |
| + word_and_cursor.push_back(WordAndCursor(L" ", 3)); |
| + word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2)); |
| + word_and_cursor.push_back(WordAndCursor(L"\x0915\x094d\x0915", 9)); |
| + word_and_cursor.push_back(WordAndCursor(L"\x0915\x094d\x0915", 9)); |
| + word_and_cursor.push_back(WordAndCursor(L" ", 10)); |
| + word_and_cursor.push_back(WordAndCursor(L"\x4E2D\x56FD", 12)); |
| + word_and_cursor.push_back(WordAndCursor(L"\x4E2D\x56FD", 12)); |
| + word_and_cursor.push_back(WordAndCursor(L"\x82B1", 13)); |
| + word_and_cursor.push_back(WordAndCursor(L"\x5929", 14)); |
| + |
| + // The text consists of Ascii, Hebrew, Hindi with Virama sign, and Chinese. |
| + model.SetText(WideToUTF16(L"a\x05d0 \x05d1\x05d2 \x0915\x094d\x0915 " |
| + L"\x4E2D\x56FD\x82B1\x5929")); |
| + for (size_t i = 0; i < word_and_cursor.size(); ++i) { |
| + model.MoveCursorLeft(gfx::LINE_BREAK, false); |
| + for (size_t j = 0; j < i; ++j) |
| + model.MoveCursorRight(gfx::CHARACTER_BREAK, false); |
| + model.SelectWord(); |
| + SelectWordTestVerifier(model, WideToUTF16(word_and_cursor[i].word), |
| + word_and_cursor[i].cursor); |
| + } |
| +} |
| + |
| TEST_F(TextfieldViewsModelTest, RangeTest) { |
| TextfieldViewsModel model(NULL); |
| model.Append(ASCIIToUTF16("HELLO WORLD")); |