1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <vector> 6 7 #include "base/auto_reset.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/strings/string16.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "ui/base/clipboard/clipboard.h" 14 #include "ui/base/clipboard/scoped_clipboard_writer.h" 15 #include "ui/gfx/range/range.h" 16 #include "ui/gfx/render_text.h" 17 #include "ui/views/controls/textfield/textfield.h" 18 #include "ui/views/controls/textfield/textfield_views_model.h" 19 #include "ui/views/test/test_views_delegate.h" 20 #include "ui/views/test/views_test_base.h" 21 22 #if defined(OS_WIN) 23 #include "base/win/windows_version.h" 24 #endif 25 26 #define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16) 27 28 namespace { 29 30 struct WordAndCursor { 31 WordAndCursor(const wchar_t* w, size_t c) : word(w), cursor(c) {} 32 33 const wchar_t* word; 34 size_t cursor; 35 }; 36 37 void MoveCursorTo(views::TextfieldViewsModel& model, size_t pos) { 38 model.MoveCursorTo(gfx::SelectionModel(pos, gfx::CURSOR_FORWARD)); 39 } 40 41 } // namespace 42 43 namespace views { 44 45 class TextfieldViewsModelTest : public ViewsTestBase, 46 public TextfieldViewsModel::Delegate { 47 public: 48 TextfieldViewsModelTest() 49 : ViewsTestBase(), 50 composition_text_confirmed_or_cleared_(false) { 51 } 52 53 virtual void OnCompositionTextConfirmedOrCleared() OVERRIDE { 54 composition_text_confirmed_or_cleared_ = true; 55 } 56 57 protected: 58 void ResetModel(TextfieldViewsModel* model) const { 59 model->SetText(string16()); 60 model->ClearEditHistory(); 61 } 62 63 bool composition_text_confirmed_or_cleared_; 64 65 private: 66 DISALLOW_COPY_AND_ASSIGN(TextfieldViewsModelTest); 67 }; 68 69 TEST_F(TextfieldViewsModelTest, EditString) { 70 TextfieldViewsModel model(NULL); 71 // append two strings 72 model.Append(ASCIIToUTF16("HILL")); 73 EXPECT_STR_EQ("HILL", model.GetText()); 74 model.Append(ASCIIToUTF16("WORLD")); 75 EXPECT_STR_EQ("HILLWORLD", model.GetText()); 76 77 // Insert "E" to make hello 78 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 79 model.InsertChar('E'); 80 EXPECT_STR_EQ("HEILLWORLD", model.GetText()); 81 // Replace "I" with "L" 82 model.ReplaceChar('L'); 83 EXPECT_STR_EQ("HELLLWORLD", model.GetText()); 84 model.ReplaceChar('L'); 85 model.ReplaceChar('O'); 86 EXPECT_STR_EQ("HELLOWORLD", model.GetText()); 87 88 // Delete 6th char "W", then delete 5th char O" 89 EXPECT_EQ(5U, model.GetCursorPosition()); 90 EXPECT_TRUE(model.Delete()); 91 EXPECT_STR_EQ("HELLOORLD", model.GetText()); 92 EXPECT_TRUE(model.Backspace()); 93 EXPECT_EQ(4U, model.GetCursorPosition()); 94 EXPECT_STR_EQ("HELLORLD", model.GetText()); 95 96 // Move the cursor to start. backspace should fail. 97 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); 98 EXPECT_FALSE(model.Backspace()); 99 EXPECT_STR_EQ("HELLORLD", model.GetText()); 100 // Move the cursor to the end. delete should fail. 101 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 102 EXPECT_FALSE(model.Delete()); 103 EXPECT_STR_EQ("HELLORLD", model.GetText()); 104 // but backspace should work. 105 EXPECT_TRUE(model.Backspace()); 106 EXPECT_STR_EQ("HELLORL", model.GetText()); 107 108 MoveCursorTo(model, 5); 109 model.ReplaceText(ASCIIToUTF16(" WOR")); 110 EXPECT_STR_EQ("HELLO WORL", model.GetText()); 111 } 112 113 TEST_F(TextfieldViewsModelTest, EditString_SimpleRTL) { 114 TextfieldViewsModel model(NULL); 115 // Append two strings. 116 model.Append(WideToUTF16(L"\x05d0\x05d1\x05d2")); 117 EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2"), model.GetText()); 118 model.Append(WideToUTF16(L"\x05e0\x05e1\x05e2")); 119 EXPECT_EQ(WideToUTF16(L"\x05d0\x05d1\x05d2\x05e0\x05e1\x05e2"), 120 model.GetText()); 121 122 // Insert 0x05f0. 123 MoveCursorTo(model, 1); 124 model.InsertChar(0x05f0); 125 EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05d1\x05d2\x05e0\x05e1\x05e2"), 126 model.GetText()); 127 128 // Replace "\x05d1" with "\x05f1". 129 model.ReplaceChar(0x05f1); 130 EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05d2\x05e0\x05e1\x05e2"), 131 model.GetText()); 132 133 // Delete and backspace. 134 EXPECT_EQ(3U, model.GetCursorPosition()); 135 EXPECT_TRUE(model.Delete()); 136 EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x5f1\x05e0\x05e1\x05e2"), 137 model.GetText()); 138 EXPECT_TRUE(model.Backspace()); 139 EXPECT_EQ(2U, model.GetCursorPosition()); 140 EXPECT_EQ(WideToUTF16(L"\x05d0\x05f0\x05e0\x05e1\x05e2"), model.GetText()); 141 } 142 143 TEST_F(TextfieldViewsModelTest, EditString_ComplexScript) { 144 // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete 145 // font support for some scripts - http://crbug.com/106450 146 bool on_windows_xp = false; 147 #if defined(OS_WIN) 148 on_windows_xp = base::win::GetVersion() < base::win::VERSION_VISTA; 149 #endif 150 151 TextfieldViewsModel model(NULL); 152 153 // Append two Hindi strings. 154 model.Append(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915")); 155 EXPECT_EQ(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"), 156 model.GetText()); 157 model.Append(WideToUTF16(L"\x0915\x094d\x092e\x094d")); 158 EXPECT_EQ(WideToUTF16( 159 L"\x0915\x093f\x0915\x094d\x0915\x0915\x094d\x092e\x094d"), 160 model.GetText()); 161 162 // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete 163 // font support for some scripts - http://crbug.com/106450 164 if (!on_windows_xp) { 165 // Check it is not able to place cursor in middle of a grapheme. 166 MoveCursorTo(model, 1); 167 EXPECT_EQ(0U, model.GetCursorPosition()); 168 169 MoveCursorTo(model, 2); 170 EXPECT_EQ(2U, model.GetCursorPosition()); 171 model.InsertChar('a'); 172 EXPECT_EQ(WideToUTF16( 173 L"\x0915\x093f\x0061\x0915\x094d\x0915\x0915\x094d\x092e\x094d"), 174 model.GetText()); 175 176 // ReplaceChar will replace the whole grapheme. 177 model.ReplaceChar('b'); 178 // TODO(xji): temporarily disable in platform Win since the complex script 179 // characters turned into empty square due to font regression. So, not able 180 // to test 2 characters belong to the same grapheme. 181 #if defined(OS_LINUX) 182 EXPECT_EQ(WideToUTF16( 183 L"\x0915\x093f\x0061\x0062\x0915\x0915\x094d\x092e\x094d"), 184 model.GetText()); 185 #endif 186 EXPECT_EQ(4U, model.GetCursorPosition()); 187 } 188 189 // Delete should delete the whole grapheme. 190 MoveCursorTo(model, 0); 191 // TODO(xji): temporarily disable in platform Win since the complex script 192 // characters turned into empty square due to font regression. So, not able 193 // to test 2 characters belong to the same grapheme. 194 #if defined(OS_LINUX) 195 EXPECT_TRUE(model.Delete()); 196 EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e\x094d"), 197 model.GetText()); 198 MoveCursorTo(model, model.GetText().length()); 199 EXPECT_EQ(model.GetText().length(), model.GetCursorPosition()); 200 EXPECT_TRUE(model.Backspace()); 201 EXPECT_EQ(WideToUTF16(L"\x0061\x0062\x0915\x0915\x094d\x092e"), 202 model.GetText()); 203 #endif 204 205 // Test cursor position and deletion for Hindi Virama. 206 model.SetText(WideToUTF16(L"\x0D38\x0D4D\x0D15\x0D16\x0D2E")); 207 MoveCursorTo(model, 0); 208 EXPECT_EQ(0U, model.GetCursorPosition()); 209 210 // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete 211 // font support for some scripts - http://crbug.com/106450 212 if (!on_windows_xp) { 213 MoveCursorTo(model, 1); 214 EXPECT_EQ(0U, model.GetCursorPosition()); 215 MoveCursorTo(model, 3); 216 EXPECT_EQ(3U, model.GetCursorPosition()); 217 } 218 219 // TODO(asvitkine): Temporarily disable the following check on Windows. It 220 // seems Windows treats "\x0D38\x0D4D\x0D15" as a single grapheme. 221 #if !defined(OS_WIN) 222 MoveCursorTo(model, 2); 223 EXPECT_EQ(2U, model.GetCursorPosition()); 224 EXPECT_TRUE(model.Backspace()); 225 EXPECT_EQ(WideToUTF16(L"\x0D38\x0D15\x0D16\x0D2E"), model.GetText()); 226 #endif 227 228 model.SetText(WideToUTF16(L"\x05d5\x05b7\x05D9\x05B0\x05D4\x05B4\x05D9")); 229 MoveCursorTo(model, 0); 230 EXPECT_TRUE(model.Delete()); 231 EXPECT_TRUE(model.Delete()); 232 EXPECT_TRUE(model.Delete()); 233 EXPECT_TRUE(model.Delete()); 234 EXPECT_EQ(WideToUTF16(L""), model.GetText()); 235 236 // The first 2 characters are not strong directionality characters. 237 model.SetText(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9\x05BC")); 238 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); 239 EXPECT_TRUE(model.Backspace()); 240 EXPECT_EQ(WideToUTF16(L"\x002C\x0020\x05D1\x05BC\x05B7\x05E9"), 241 model.GetText()); 242 } 243 244 TEST_F(TextfieldViewsModelTest, EmptyString) { 245 TextfieldViewsModel model(NULL); 246 EXPECT_EQ(string16(), model.GetText()); 247 EXPECT_EQ(string16(), model.GetSelectedText()); 248 249 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 250 EXPECT_EQ(0U, model.GetCursorPosition()); 251 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 252 EXPECT_EQ(0U, model.GetCursorPosition()); 253 254 EXPECT_EQ(string16(), model.GetSelectedText()); 255 256 EXPECT_FALSE(model.Delete()); 257 EXPECT_FALSE(model.Backspace()); 258 } 259 260 TEST_F(TextfieldViewsModelTest, Selection) { 261 TextfieldViewsModel model(NULL); 262 model.Append(ASCIIToUTF16("HELLO")); 263 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 264 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 265 EXPECT_STR_EQ("E", model.GetSelectedText()); 266 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 267 EXPECT_STR_EQ("EL", model.GetSelectedText()); 268 269 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true); 270 EXPECT_STR_EQ("H", model.GetSelectedText()); 271 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, true); 272 EXPECT_STR_EQ("ELLO", model.GetSelectedText()); 273 model.ClearSelection(); 274 EXPECT_EQ(string16(), model.GetSelectedText()); 275 276 // SelectAll(false) selects towards the end. 277 model.SelectAll(false); 278 EXPECT_STR_EQ("HELLO", model.GetSelectedText()); 279 EXPECT_EQ(gfx::Range(0, 5), model.render_text()->selection()); 280 281 // SelectAll(true) selects towards the beginning. 282 model.SelectAll(true); 283 EXPECT_STR_EQ("HELLO", model.GetSelectedText()); 284 EXPECT_EQ(gfx::Range(5, 0), model.render_text()->selection()); 285 286 // Select and move cursor. 287 model.SelectRange(gfx::Range(1U, 3U)); 288 EXPECT_STR_EQ("EL", model.GetSelectedText()); 289 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); 290 EXPECT_EQ(1U, model.GetCursorPosition()); 291 model.SelectRange(gfx::Range(1U, 3U)); 292 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 293 EXPECT_EQ(3U, model.GetCursorPosition()); 294 295 // Select all and move cursor. 296 model.SelectAll(false); 297 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); 298 EXPECT_EQ(0U, model.GetCursorPosition()); 299 model.SelectAll(false); 300 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 301 EXPECT_EQ(5U, model.GetCursorPosition()); 302 } 303 304 TEST_F(TextfieldViewsModelTest, Selection_BidiWithNonSpacingMarks) { 305 // Selection is a logical operation. And it should work with the arrow 306 // keys doing visual movements, while the selection is logical between 307 // the (logical) start and end points. Selection is simply defined as 308 // the portion of text between the logical positions of the start and end 309 // caret positions. 310 TextfieldViewsModel model(NULL); 311 // TODO(xji): temporarily disable in platform Win since the complex script 312 // characters turned into empty square due to font regression. So, not able 313 // to test 2 characters belong to the same grapheme. 314 #if defined(OS_LINUX) 315 model.Append(WideToUTF16( 316 L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"def")); 317 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 318 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 319 320 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 321 EXPECT_EQ(gfx::Range(2, 3), model.render_text()->selection()); 322 EXPECT_EQ(WideToUTF16(L"c"), model.GetSelectedText()); 323 324 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 325 EXPECT_EQ(gfx::Range(2, 7), model.render_text()->selection()); 326 EXPECT_EQ(WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8"), 327 model.GetSelectedText()); 328 329 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 330 EXPECT_EQ(gfx::Range(2, 3), model.render_text()->selection()); 331 EXPECT_EQ(WideToUTF16(L"c"), model.GetSelectedText()); 332 333 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 334 EXPECT_EQ(gfx::Range(2, 10), model.render_text()->selection()); 335 EXPECT_EQ(WideToUTF16(L"c\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"d"), 336 model.GetSelectedText()); 337 338 model.ClearSelection(); 339 EXPECT_EQ(string16(), model.GetSelectedText()); 340 model.SelectAll(false); 341 EXPECT_EQ(WideToUTF16(L"abc\x05E9\x05BC\x05C1\x05B8\x05E0\x05B8" L"def"), 342 model.GetSelectedText()); 343 #endif 344 345 // In case of "aBc", this test shows how to select "aB" or "Bc", assume 'B' is 346 // an RTL character. 347 model.SetText(WideToUTF16(L"a\x05E9" L"b")); 348 MoveCursorTo(model, 0); 349 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 350 EXPECT_EQ(WideToUTF16(L"a"), model.GetSelectedText()); 351 352 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 353 EXPECT_EQ(WideToUTF16(L"a"), model.GetSelectedText()); 354 355 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 356 EXPECT_EQ(WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText()); 357 358 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 359 EXPECT_EQ(3U, model.GetCursorPosition()); 360 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 361 EXPECT_EQ(WideToUTF16(L"b"), model.GetSelectedText()); 362 363 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 364 EXPECT_EQ(WideToUTF16(L"b"), model.GetSelectedText()); 365 366 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 367 EXPECT_EQ(WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText()); 368 369 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); 370 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 371 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 372 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 373 EXPECT_EQ(WideToUTF16(L"a\x05E9"), model.GetSelectedText()); 374 375 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 376 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 377 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 378 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 379 EXPECT_EQ(WideToUTF16(L"\x05E9" L"b"), model.GetSelectedText()); 380 381 model.ClearSelection(); 382 EXPECT_EQ(string16(), model.GetSelectedText()); 383 model.SelectAll(false); 384 EXPECT_EQ(WideToUTF16(L"a\x05E9" L"b"), model.GetSelectedText()); 385 } 386 387 TEST_F(TextfieldViewsModelTest, SelectionAndEdit) { 388 TextfieldViewsModel model(NULL); 389 model.Append(ASCIIToUTF16("HELLO")); 390 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 391 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 392 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "EL" 393 EXPECT_TRUE(model.Backspace()); 394 EXPECT_STR_EQ("HLO", model.GetText()); 395 396 model.Append(ASCIIToUTF16("ILL")); 397 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 398 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "LO" 399 EXPECT_TRUE(model.Delete()); 400 EXPECT_STR_EQ("HILL", model.GetText()); 401 EXPECT_EQ(1U, model.GetCursorPosition()); 402 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "I" 403 model.InsertChar('E'); 404 EXPECT_STR_EQ("HELL", model.GetText()); 405 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); 406 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); // "H" 407 model.ReplaceChar('B'); 408 EXPECT_STR_EQ("BELL", model.GetText()); 409 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 410 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 411 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); // "ELL" 412 model.ReplaceChar('E'); 413 EXPECT_STR_EQ("BEE", model.GetText()); 414 } 415 416 TEST_F(TextfieldViewsModelTest, Word) { 417 TextfieldViewsModel model(NULL); 418 model.Append( 419 ASCIIToUTF16("The answer to Life, the Universe, and Everything")); 420 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); 421 EXPECT_EQ(3U, model.GetCursorPosition()); 422 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); 423 EXPECT_EQ(10U, model.GetCursorPosition()); 424 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); 425 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); 426 EXPECT_EQ(18U, model.GetCursorPosition()); 427 428 // Should passes the non word char ',' 429 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); 430 EXPECT_EQ(23U, model.GetCursorPosition()); 431 EXPECT_STR_EQ(", the", model.GetSelectedText()); 432 433 // Move to the end. 434 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); 435 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); 436 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); 437 EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText()); 438 // Should be safe to go next word at the end. 439 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); 440 EXPECT_STR_EQ(", the Universe, and Everything", model.GetSelectedText()); 441 model.InsertChar('2'); 442 EXPECT_EQ(19U, model.GetCursorPosition()); 443 444 // Now backwards. 445 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); // leave 2. 446 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); 447 EXPECT_EQ(14U, model.GetCursorPosition()); 448 EXPECT_STR_EQ("Life", model.GetSelectedText()); 449 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); 450 EXPECT_STR_EQ("to Life", model.GetSelectedText()); 451 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); 452 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); 453 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); // Now at start. 454 EXPECT_STR_EQ("The answer to Life", model.GetSelectedText()); 455 // Should be safe to go to the previous word at the beginning. 456 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); 457 EXPECT_STR_EQ("The answer to Life", model.GetSelectedText()); 458 model.ReplaceChar('4'); 459 EXPECT_EQ(string16(), model.GetSelectedText()); 460 EXPECT_STR_EQ("42", model.GetText()); 461 } 462 463 TEST_F(TextfieldViewsModelTest, SetText) { 464 TextfieldViewsModel model(NULL); 465 model.Append(ASCIIToUTF16("HELLO")); 466 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 467 model.SetText(ASCIIToUTF16("GOODBYE")); 468 EXPECT_STR_EQ("GOODBYE", model.GetText()); 469 // SetText move the cursor to the end of the new text. 470 EXPECT_EQ(7U, model.GetCursorPosition()); 471 model.SelectAll(false); 472 EXPECT_STR_EQ("GOODBYE", model.GetSelectedText()); 473 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 474 EXPECT_EQ(7U, model.GetCursorPosition()); 475 476 model.SetText(ASCIIToUTF16("BYE")); 477 // Setting shorter string moves the cursor to the end of the new string. 478 EXPECT_EQ(3U, model.GetCursorPosition()); 479 EXPECT_EQ(string16(), model.GetSelectedText()); 480 model.SetText(string16()); 481 EXPECT_EQ(0U, model.GetCursorPosition()); 482 } 483 484 TEST_F(TextfieldViewsModelTest, Clipboard) { 485 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); 486 const string16 initial_clipboard_text = ASCIIToUTF16("initial text"); 487 ui::ScopedClipboardWriter(clipboard, ui::CLIPBOARD_TYPE_COPY_PASTE). 488 WriteText(initial_clipboard_text); 489 490 string16 clipboard_text; 491 TextfieldViewsModel model(NULL); 492 model.Append(ASCIIToUTF16("HELLO WORLD")); 493 494 // Cut with an empty selection should do nothing. 495 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 496 EXPECT_FALSE(model.Cut()); 497 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); 498 EXPECT_EQ(initial_clipboard_text, clipboard_text); 499 EXPECT_STR_EQ("HELLO WORLD", model.GetText()); 500 EXPECT_EQ(11U, model.GetCursorPosition()); 501 502 // Copy with an empty selection should do nothing. 503 model.Copy(); 504 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); 505 EXPECT_EQ(initial_clipboard_text, clipboard_text); 506 EXPECT_STR_EQ("HELLO WORLD", model.GetText()); 507 EXPECT_EQ(11U, model.GetCursorPosition()); 508 509 // Cut on obscured (password) text should do nothing. 510 model.render_text()->SetObscured(true); 511 model.SelectAll(false); 512 EXPECT_FALSE(model.Cut()); 513 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); 514 EXPECT_EQ(initial_clipboard_text, clipboard_text); 515 EXPECT_STR_EQ("HELLO WORLD", model.GetText()); 516 EXPECT_STR_EQ("HELLO WORLD", model.GetSelectedText()); 517 518 // Copy on obscured text should do nothing. 519 model.SelectAll(false); 520 EXPECT_FALSE(model.Copy()); 521 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); 522 EXPECT_EQ(initial_clipboard_text, clipboard_text); 523 EXPECT_STR_EQ("HELLO WORLD", model.GetText()); 524 EXPECT_STR_EQ("HELLO WORLD", model.GetSelectedText()); 525 526 // Cut with non-empty selection. 527 model.render_text()->SetObscured(false); 528 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 529 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); 530 EXPECT_TRUE(model.Cut()); 531 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); 532 EXPECT_STR_EQ("WORLD", clipboard_text); 533 EXPECT_STR_EQ("HELLO ", model.GetText()); 534 EXPECT_EQ(6U, model.GetCursorPosition()); 535 536 // Copy with non-empty selection. 537 model.SelectAll(false); 538 EXPECT_TRUE(model.Copy()); 539 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &clipboard_text); 540 EXPECT_STR_EQ("HELLO ", clipboard_text); 541 EXPECT_STR_EQ("HELLO ", model.GetText()); 542 EXPECT_EQ(6U, model.GetCursorPosition()); 543 544 // Test that paste works regardless of the obscured bit. 545 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 546 EXPECT_TRUE(model.Paste()); 547 EXPECT_STR_EQ("HELLO HELLO ", model.GetText()); 548 EXPECT_EQ(12U, model.GetCursorPosition()); 549 model.render_text()->SetObscured(true); 550 EXPECT_TRUE(model.Paste()); 551 EXPECT_STR_EQ("HELLO HELLO HELLO ", model.GetText()); 552 EXPECT_EQ(18U, model.GetCursorPosition()); 553 } 554 555 static void SelectWordTestVerifier(const TextfieldViewsModel& model, 556 const string16 &expected_selected_string, size_t expected_cursor_pos) { 557 EXPECT_EQ(expected_selected_string, model.GetSelectedText()); 558 EXPECT_EQ(expected_cursor_pos, model.GetCursorPosition()); 559 } 560 561 TEST_F(TextfieldViewsModelTest, SelectWordTest) { 562 TextfieldViewsModel model(NULL); 563 model.Append(ASCIIToUTF16(" HELLO !! WO RLD ")); 564 565 // Test when cursor is at the beginning. 566 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); 567 model.SelectWord(); 568 SelectWordTestVerifier(model, ASCIIToUTF16(" "), 2U); 569 570 // Test when cursor is at the beginning of a word. 571 MoveCursorTo(model, 2); 572 model.SelectWord(); 573 SelectWordTestVerifier(model, ASCIIToUTF16("HELLO"), 7U); 574 575 // Test when cursor is at the end of a word. 576 MoveCursorTo(model, 15); 577 model.SelectWord(); 578 SelectWordTestVerifier(model, ASCIIToUTF16(" "), 20U); 579 580 // Test when cursor is somewhere in a non-alpha-numeric fragment. 581 for (size_t cursor_pos = 8; cursor_pos < 13U; cursor_pos++) { 582 MoveCursorTo(model, cursor_pos); 583 model.SelectWord(); 584 SelectWordTestVerifier(model, ASCIIToUTF16(" !! "), 13U); 585 } 586 587 // Test when cursor is somewhere in a whitespace fragment. 588 MoveCursorTo(model, 17); 589 model.SelectWord(); 590 SelectWordTestVerifier(model, ASCIIToUTF16(" "), 20U); 591 592 // Test when cursor is at the end. 593 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 594 model.SelectWord(); 595 SelectWordTestVerifier(model, ASCIIToUTF16(" "), 24U); 596 } 597 598 // TODO(xji): temporarily disable in platform Win since the complex script 599 // characters and Chinese characters are turned into empty square due to font 600 // regression. 601 #if defined(OS_LINUX) 602 TEST_F(TextfieldViewsModelTest, SelectWordTest_MixScripts) { 603 TextfieldViewsModel model(NULL); 604 std::vector<WordAndCursor> word_and_cursor; 605 word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2)); 606 word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2)); 607 word_and_cursor.push_back(WordAndCursor(L"\x05d1\x05d2", 5)); 608 word_and_cursor.push_back(WordAndCursor(L"\x05d1\x05d2", 5)); 609 word_and_cursor.push_back(WordAndCursor(L" ", 3)); 610 word_and_cursor.push_back(WordAndCursor(L"a\x05d0", 2)); 611 word_and_cursor.push_back(WordAndCursor(L"\x0915\x094d\x0915", 9)); 612 word_and_cursor.push_back(WordAndCursor(L"\x0915\x094d\x0915", 9)); 613 word_and_cursor.push_back(WordAndCursor(L" ", 10)); 614 word_and_cursor.push_back(WordAndCursor(L"\x4E2D\x56FD", 12)); 615 word_and_cursor.push_back(WordAndCursor(L"\x4E2D\x56FD", 12)); 616 word_and_cursor.push_back(WordAndCursor(L"\x82B1", 13)); 617 word_and_cursor.push_back(WordAndCursor(L"\x5929", 14)); 618 619 // The text consists of Ascii, Hebrew, Hindi with Virama sign, and Chinese. 620 model.SetText(WideToUTF16(L"a\x05d0 \x05d1\x05d2 \x0915\x094d\x0915 " 621 L"\x4E2D\x56FD\x82B1\x5929")); 622 for (size_t i = 0; i < word_and_cursor.size(); ++i) { 623 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); 624 for (size_t j = 0; j < i; ++j) 625 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 626 model.SelectWord(); 627 SelectWordTestVerifier(model, WideToUTF16(word_and_cursor[i].word), 628 word_and_cursor[i].cursor); 629 } 630 } 631 #endif 632 633 TEST_F(TextfieldViewsModelTest, RangeTest) { 634 TextfieldViewsModel model(NULL); 635 model.Append(ASCIIToUTF16("HELLO WORLD")); 636 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); 637 gfx::Range range = model.render_text()->selection(); 638 EXPECT_TRUE(range.is_empty()); 639 EXPECT_EQ(0U, range.start()); 640 EXPECT_EQ(0U, range.end()); 641 642 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); 643 range = model.render_text()->selection(); 644 EXPECT_FALSE(range.is_empty()); 645 EXPECT_FALSE(range.is_reversed()); 646 EXPECT_EQ(0U, range.start()); 647 EXPECT_EQ(5U, range.end()); 648 649 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 650 range = model.render_text()->selection(); 651 EXPECT_FALSE(range.is_empty()); 652 EXPECT_EQ(0U, range.start()); 653 EXPECT_EQ(4U, range.end()); 654 655 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); 656 range = model.render_text()->selection(); 657 EXPECT_TRUE(range.is_empty()); 658 EXPECT_EQ(0U, range.start()); 659 EXPECT_EQ(0U, range.end()); 660 661 // now from the end. 662 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 663 range = model.render_text()->selection(); 664 EXPECT_TRUE(range.is_empty()); 665 EXPECT_EQ(11U, range.start()); 666 EXPECT_EQ(11U, range.end()); 667 668 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); 669 range = model.render_text()->selection(); 670 EXPECT_FALSE(range.is_empty()); 671 EXPECT_TRUE(range.is_reversed()); 672 EXPECT_EQ(11U, range.start()); 673 EXPECT_EQ(6U, range.end()); 674 675 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 676 range = model.render_text()->selection(); 677 EXPECT_FALSE(range.is_empty()); 678 EXPECT_TRUE(range.is_reversed()); 679 EXPECT_EQ(11U, range.start()); 680 EXPECT_EQ(7U, range.end()); 681 682 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); 683 range = model.render_text()->selection(); 684 EXPECT_TRUE(range.is_empty()); 685 EXPECT_EQ(11U, range.start()); 686 EXPECT_EQ(11U, range.end()); 687 688 // Select All 689 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true); 690 range = model.render_text()->selection(); 691 EXPECT_FALSE(range.is_empty()); 692 EXPECT_TRUE(range.is_reversed()); 693 EXPECT_EQ(11U, range.start()); 694 EXPECT_EQ(0U, range.end()); 695 } 696 697 TEST_F(TextfieldViewsModelTest, SelectRangeTest) { 698 TextfieldViewsModel model(NULL); 699 model.Append(ASCIIToUTF16("HELLO WORLD")); 700 gfx::Range range(0, 6); 701 EXPECT_FALSE(range.is_reversed()); 702 model.SelectRange(range); 703 EXPECT_STR_EQ("HELLO ", model.GetSelectedText()); 704 705 range = gfx::Range(6, 1); 706 EXPECT_TRUE(range.is_reversed()); 707 model.SelectRange(range); 708 EXPECT_STR_EQ("ELLO ", model.GetSelectedText()); 709 710 range = gfx::Range(2, 1000); 711 EXPECT_FALSE(range.is_reversed()); 712 model.SelectRange(range); 713 EXPECT_STR_EQ("LLO WORLD", model.GetSelectedText()); 714 715 range = gfx::Range(1000, 3); 716 EXPECT_TRUE(range.is_reversed()); 717 model.SelectRange(range); 718 EXPECT_STR_EQ("LO WORLD", model.GetSelectedText()); 719 720 range = gfx::Range(0, 0); 721 EXPECT_TRUE(range.is_empty()); 722 model.SelectRange(range); 723 EXPECT_TRUE(model.GetSelectedText().empty()); 724 725 range = gfx::Range(3, 3); 726 EXPECT_TRUE(range.is_empty()); 727 model.SelectRange(range); 728 EXPECT_TRUE(model.GetSelectedText().empty()); 729 730 range = gfx::Range(1000, 100); 731 EXPECT_FALSE(range.is_empty()); 732 model.SelectRange(range); 733 EXPECT_TRUE(model.GetSelectedText().empty()); 734 735 range = gfx::Range(1000, 1000); 736 EXPECT_TRUE(range.is_empty()); 737 model.SelectRange(range); 738 EXPECT_TRUE(model.GetSelectedText().empty()); 739 } 740 741 TEST_F(TextfieldViewsModelTest, SelectionTest) { 742 TextfieldViewsModel model(NULL); 743 model.Append(ASCIIToUTF16("HELLO WORLD")); 744 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); 745 gfx::Range selection = model.render_text()->selection(); 746 EXPECT_EQ(gfx::Range(0), selection); 747 748 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); 749 selection = model.render_text()->selection(); 750 EXPECT_EQ(gfx::Range(0, 5), selection); 751 752 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 753 selection = model.render_text()->selection(); 754 EXPECT_EQ(gfx::Range(0, 4), selection); 755 756 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); 757 selection = model.render_text()->selection(); 758 EXPECT_EQ(gfx::Range(0), selection); 759 760 // now from the end. 761 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 762 selection = model.render_text()->selection(); 763 EXPECT_EQ(gfx::Range(11), selection); 764 765 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, true); 766 selection = model.render_text()->selection(); 767 EXPECT_EQ(gfx::Range(11, 6), selection); 768 769 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, true); 770 selection = model.render_text()->selection(); 771 EXPECT_EQ(gfx::Range(11, 7), selection); 772 773 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, true); 774 selection = model.render_text()->selection(); 775 EXPECT_EQ(gfx::Range(11), selection); 776 777 // Select All 778 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true); 779 selection = model.render_text()->selection(); 780 EXPECT_EQ(gfx::Range(11, 0), selection); 781 } 782 783 TEST_F(TextfieldViewsModelTest, SelectSelectionModelTest) { 784 TextfieldViewsModel model(NULL); 785 model.Append(ASCIIToUTF16("HELLO WORLD")); 786 model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(0, 6), 787 gfx::CURSOR_BACKWARD)); 788 EXPECT_STR_EQ("HELLO ", model.GetSelectedText()); 789 790 model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(6, 1), 791 gfx::CURSOR_FORWARD)); 792 EXPECT_STR_EQ("ELLO ", model.GetSelectedText()); 793 794 model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(2, 1000), 795 gfx::CURSOR_BACKWARD)); 796 EXPECT_STR_EQ("LLO WORLD", model.GetSelectedText()); 797 798 model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(1000, 3), 799 gfx::CURSOR_FORWARD)); 800 EXPECT_STR_EQ("LO WORLD", model.GetSelectedText()); 801 802 model.SelectSelectionModel(gfx::SelectionModel(0, gfx::CURSOR_FORWARD)); 803 EXPECT_TRUE(model.GetSelectedText().empty()); 804 805 model.SelectSelectionModel(gfx::SelectionModel(3, gfx::CURSOR_FORWARD)); 806 EXPECT_TRUE(model.GetSelectedText().empty()); 807 808 model.SelectSelectionModel(gfx::SelectionModel(gfx::Range(1000, 100), 809 gfx::CURSOR_FORWARD)); 810 EXPECT_TRUE(model.GetSelectedText().empty()); 811 812 model.SelectSelectionModel(gfx::SelectionModel(1000, gfx::CURSOR_BACKWARD)); 813 EXPECT_TRUE(model.GetSelectedText().empty()); 814 } 815 816 TEST_F(TextfieldViewsModelTest, CompositionTextTest) { 817 TextfieldViewsModel model(this); 818 model.Append(ASCIIToUTF16("1234590")); 819 model.SelectRange(gfx::Range(5, 5)); 820 EXPECT_FALSE(model.HasSelection()); 821 EXPECT_EQ(5U, model.GetCursorPosition()); 822 823 gfx::Range range; 824 model.GetTextRange(&range); 825 EXPECT_EQ(gfx::Range(0, 7), range); 826 827 ui::CompositionText composition; 828 composition.text = ASCIIToUTF16("678"); 829 composition.underlines.push_back(ui::CompositionUnderline(0, 3, 0, false)); 830 831 // Cursor should be at the end of composition when characters are just typed. 832 composition.selection = gfx::Range(3, 3); 833 model.SetCompositionText(composition); 834 EXPECT_TRUE(model.HasCompositionText()); 835 EXPECT_FALSE(model.HasSelection()); 836 837 // Cancel composition 838 model.CancelCompositionText(); 839 composition_text_confirmed_or_cleared_ = false; 840 841 // Restart composition with targeting "67" in "678". 842 composition.selection = gfx::Range(0, 2); 843 composition.underlines.clear(); 844 composition.underlines.push_back(ui::CompositionUnderline(0, 2, 0, true)); 845 composition.underlines.push_back(ui::CompositionUnderline(2, 3, 0, false)); 846 model.SetCompositionText(composition); 847 EXPECT_TRUE(model.HasCompositionText()); 848 EXPECT_TRUE(model.HasSelection()); 849 EXPECT_EQ(gfx::Range(5, 7), model.render_text()->selection()); 850 851 model.GetTextRange(&range); 852 EXPECT_EQ(10U, range.end()); 853 EXPECT_STR_EQ("1234567890", model.GetText()); 854 855 model.GetCompositionTextRange(&range); 856 EXPECT_EQ(gfx::Range(5, 8), range); 857 // composition text 858 EXPECT_STR_EQ("456", model.GetTextFromRange(gfx::Range(3, 6))); 859 EXPECT_EQ(gfx::Range(5, 7), model.render_text()->selection()); 860 861 EXPECT_FALSE(composition_text_confirmed_or_cleared_); 862 model.CancelCompositionText(); 863 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 864 composition_text_confirmed_or_cleared_ = false; 865 EXPECT_FALSE(model.HasCompositionText()); 866 EXPECT_FALSE(model.HasSelection()); 867 EXPECT_EQ(5U, model.GetCursorPosition()); 868 869 model.SetCompositionText(composition); 870 EXPECT_STR_EQ("1234567890", model.GetText()); 871 EXPECT_TRUE(model.SetText(ASCIIToUTF16("1234567890"))); 872 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 873 composition_text_confirmed_or_cleared_ = false; 874 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 875 876 model.SetCompositionText(composition); 877 EXPECT_STR_EQ("1234567890678", model.GetText()); 878 879 model.InsertText(UTF8ToUTF16("-")); 880 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 881 composition_text_confirmed_or_cleared_ = false; 882 EXPECT_STR_EQ("1234567890-", model.GetText()); 883 EXPECT_FALSE(model.HasCompositionText()); 884 EXPECT_FALSE(model.HasSelection()); 885 886 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, true); 887 EXPECT_STR_EQ("-", model.GetSelectedText()); 888 model.SetCompositionText(composition); 889 EXPECT_STR_EQ("1234567890678", model.GetText()); 890 891 model.ReplaceText(UTF8ToUTF16("-")); 892 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 893 composition_text_confirmed_or_cleared_ = false; 894 EXPECT_STR_EQ("1234567890-", model.GetText()); 895 EXPECT_FALSE(model.HasCompositionText()); 896 EXPECT_FALSE(model.HasSelection()); 897 898 model.SetCompositionText(composition); 899 model.Append(UTF8ToUTF16("-")); 900 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 901 composition_text_confirmed_or_cleared_ = false; 902 EXPECT_STR_EQ("1234567890-678-", model.GetText()); 903 904 model.SetCompositionText(composition); 905 model.Delete(); 906 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 907 composition_text_confirmed_or_cleared_ = false; 908 EXPECT_STR_EQ("1234567890-678-", model.GetText()); 909 910 model.SetCompositionText(composition); 911 model.Backspace(); 912 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 913 composition_text_confirmed_or_cleared_ = false; 914 EXPECT_STR_EQ("1234567890-678-", model.GetText()); 915 916 model.SetText(string16()); 917 model.SetCompositionText(composition); 918 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); 919 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 920 composition_text_confirmed_or_cleared_ = false; 921 EXPECT_STR_EQ("678", model.GetText()); 922 EXPECT_EQ(2U, model.GetCursorPosition()); 923 924 model.SetCompositionText(composition); 925 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 926 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 927 composition_text_confirmed_or_cleared_ = false; 928 EXPECT_STR_EQ("676788", model.GetText()); 929 EXPECT_EQ(6U, model.GetCursorPosition()); 930 931 model.SetCompositionText(composition); 932 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_LEFT, false); 933 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 934 composition_text_confirmed_or_cleared_ = false; 935 EXPECT_STR_EQ("676788678", model.GetText()); 936 937 model.SetText(string16()); 938 model.SetCompositionText(composition); 939 model.MoveCursor(gfx::WORD_BREAK, gfx::CURSOR_RIGHT, false); 940 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 941 composition_text_confirmed_or_cleared_ = false; 942 943 model.SetCompositionText(composition); 944 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, true); 945 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 946 composition_text_confirmed_or_cleared_ = false; 947 EXPECT_STR_EQ("678678", model.GetText()); 948 949 model.SetCompositionText(composition); 950 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 951 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 952 composition_text_confirmed_or_cleared_ = false; 953 EXPECT_STR_EQ("678", model.GetText()); 954 955 model.SetCompositionText(composition); 956 gfx::SelectionModel sel( 957 gfx::Range(model.render_text()->selection().start(), 0), 958 gfx::CURSOR_FORWARD); 959 model.MoveCursorTo(sel); 960 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 961 composition_text_confirmed_or_cleared_ = false; 962 EXPECT_STR_EQ("678678", model.GetText()); 963 964 model.SetCompositionText(composition); 965 model.SelectRange(gfx::Range(0, 3)); 966 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 967 composition_text_confirmed_or_cleared_ = false; 968 EXPECT_STR_EQ("678", model.GetText()); 969 970 model.SetCompositionText(composition); 971 model.SelectAll(false); 972 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 973 composition_text_confirmed_or_cleared_ = false; 974 EXPECT_STR_EQ("678", model.GetText()); 975 976 model.SetCompositionText(composition); 977 model.SelectWord(); 978 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 979 composition_text_confirmed_or_cleared_ = false; 980 EXPECT_STR_EQ("678", model.GetText()); 981 982 model.SetCompositionText(composition); 983 model.ClearSelection(); 984 EXPECT_TRUE(composition_text_confirmed_or_cleared_); 985 composition_text_confirmed_or_cleared_ = false; 986 987 model.SetCompositionText(composition); 988 EXPECT_FALSE(model.Cut()); 989 EXPECT_FALSE(composition_text_confirmed_or_cleared_); 990 } 991 992 TEST_F(TextfieldViewsModelTest, UndoRedo_BasicTest) { 993 TextfieldViewsModel model(NULL); 994 model.InsertChar('a'); 995 EXPECT_FALSE(model.Redo()); // nothing to redo 996 EXPECT_TRUE(model.Undo()); 997 EXPECT_STR_EQ("", model.GetText()); 998 EXPECT_TRUE(model.Redo()); 999 EXPECT_STR_EQ("a", model.GetText()); 1000 1001 // Continuous inserts are treated as one edit. 1002 model.InsertChar('b'); 1003 model.InsertChar('c'); 1004 EXPECT_STR_EQ("abc", model.GetText()); 1005 EXPECT_TRUE(model.Undo()); 1006 EXPECT_STR_EQ("a", model.GetText()); 1007 EXPECT_EQ(1U, model.GetCursorPosition()); 1008 EXPECT_TRUE(model.Undo()); 1009 EXPECT_STR_EQ("", model.GetText()); 1010 EXPECT_EQ(0U, model.GetCursorPosition()); 1011 1012 // Undoing further shouldn't change the text. 1013 EXPECT_FALSE(model.Undo()); 1014 EXPECT_STR_EQ("", model.GetText()); 1015 EXPECT_FALSE(model.Undo()); 1016 EXPECT_STR_EQ("", model.GetText()); 1017 EXPECT_EQ(0U, model.GetCursorPosition()); 1018 1019 // Redoing to the latest text. 1020 EXPECT_TRUE(model.Redo()); 1021 EXPECT_STR_EQ("a", model.GetText()); 1022 EXPECT_EQ(1U, model.GetCursorPosition()); 1023 EXPECT_TRUE(model.Redo()); 1024 EXPECT_STR_EQ("abc", model.GetText()); 1025 EXPECT_EQ(3U, model.GetCursorPosition()); 1026 1027 // Backspace =============================== 1028 EXPECT_TRUE(model.Backspace()); 1029 EXPECT_STR_EQ("ab", model.GetText()); 1030 EXPECT_TRUE(model.Undo()); 1031 EXPECT_STR_EQ("abc", model.GetText()); 1032 EXPECT_EQ(3U, model.GetCursorPosition()); 1033 EXPECT_TRUE(model.Redo()); 1034 EXPECT_STR_EQ("ab", model.GetText()); 1035 EXPECT_EQ(2U, model.GetCursorPosition()); 1036 // Continous backspaces are treated as one edit. 1037 EXPECT_TRUE(model.Backspace()); 1038 EXPECT_TRUE(model.Backspace()); 1039 EXPECT_STR_EQ("", model.GetText()); 1040 // Extra backspace shouldn't affect the history. 1041 EXPECT_FALSE(model.Backspace()); 1042 EXPECT_TRUE(model.Undo()); 1043 EXPECT_STR_EQ("ab", model.GetText()); 1044 EXPECT_EQ(2U, model.GetCursorPosition()); 1045 EXPECT_TRUE(model.Undo()); 1046 EXPECT_STR_EQ("abc", model.GetText()); 1047 EXPECT_EQ(3U, model.GetCursorPosition()); 1048 EXPECT_TRUE(model.Undo()); 1049 EXPECT_STR_EQ("a", model.GetText()); 1050 EXPECT_EQ(1U, model.GetCursorPosition()); 1051 1052 // Clear history 1053 model.ClearEditHistory(); 1054 EXPECT_FALSE(model.Undo()); 1055 EXPECT_FALSE(model.Redo()); 1056 EXPECT_STR_EQ("a", model.GetText()); 1057 EXPECT_EQ(1U, model.GetCursorPosition()); 1058 1059 // Delete =============================== 1060 model.SetText(ASCIIToUTF16("ABCDE")); 1061 model.ClearEditHistory(); 1062 MoveCursorTo(model, 2); 1063 EXPECT_TRUE(model.Delete()); 1064 EXPECT_STR_EQ("ABDE", model.GetText()); 1065 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); 1066 EXPECT_TRUE(model.Delete()); 1067 EXPECT_STR_EQ("BDE", model.GetText()); 1068 EXPECT_TRUE(model.Undo()); 1069 EXPECT_STR_EQ("ABDE", model.GetText()); 1070 EXPECT_EQ(0U, model.GetCursorPosition()); 1071 EXPECT_TRUE(model.Undo()); 1072 EXPECT_STR_EQ("ABCDE", model.GetText()); 1073 EXPECT_EQ(2U, model.GetCursorPosition()); 1074 EXPECT_TRUE(model.Redo()); 1075 EXPECT_STR_EQ("ABDE", model.GetText()); 1076 EXPECT_EQ(2U, model.GetCursorPosition()); 1077 // Continous deletes are treated as one edit. 1078 EXPECT_TRUE(model.Delete()); 1079 EXPECT_TRUE(model.Delete()); 1080 EXPECT_STR_EQ("AB", model.GetText()); 1081 EXPECT_TRUE(model.Undo()); 1082 EXPECT_STR_EQ("ABDE", model.GetText()); 1083 EXPECT_EQ(2U, model.GetCursorPosition()); 1084 EXPECT_TRUE(model.Redo()); 1085 EXPECT_STR_EQ("AB", model.GetText()); 1086 EXPECT_EQ(2U, model.GetCursorPosition()); 1087 } 1088 1089 TEST_F(TextfieldViewsModelTest, UndoRedo_SetText) { 1090 // This is to test the undo/redo behavior of omnibox. 1091 TextfieldViewsModel model(NULL); 1092 model.InsertChar('w'); 1093 EXPECT_STR_EQ("w", model.GetText()); 1094 EXPECT_EQ(1U, model.GetCursorPosition()); 1095 model.SetText(ASCIIToUTF16("www.google.com")); 1096 EXPECT_EQ(14U, model.GetCursorPosition()); 1097 EXPECT_STR_EQ("www.google.com", model.GetText()); 1098 model.SelectRange(gfx::Range(14, 1)); 1099 model.InsertChar('w'); 1100 EXPECT_STR_EQ("ww", model.GetText()); 1101 model.SetText(ASCIIToUTF16("www.google.com")); 1102 model.SelectRange(gfx::Range(14, 2)); 1103 model.InsertChar('w'); 1104 EXPECT_STR_EQ("www", model.GetText()); 1105 model.SetText(ASCIIToUTF16("www.google.com")); 1106 model.SelectRange(gfx::Range(14, 3)); 1107 model.InsertChar('.'); 1108 EXPECT_STR_EQ("www.", model.GetText()); 1109 model.SetText(ASCIIToUTF16("www.google.com")); 1110 model.SelectRange(gfx::Range(14, 4)); 1111 model.InsertChar('y'); 1112 EXPECT_STR_EQ("www.y", model.GetText()); 1113 model.SetText(ASCIIToUTF16("www.youtube.com")); 1114 EXPECT_STR_EQ("www.youtube.com", model.GetText()); 1115 EXPECT_EQ(15U, model.GetCursorPosition()); 1116 1117 EXPECT_TRUE(model.Undo()); 1118 EXPECT_STR_EQ("www.google.com", model.GetText()); 1119 EXPECT_EQ(4U, model.GetCursorPosition()); 1120 EXPECT_TRUE(model.Undo()); 1121 EXPECT_STR_EQ("www.google.com", model.GetText()); 1122 EXPECT_EQ(3U, model.GetCursorPosition()); 1123 EXPECT_TRUE(model.Undo()); 1124 EXPECT_STR_EQ("www.google.com", model.GetText()); 1125 EXPECT_EQ(2U, model.GetCursorPosition()); 1126 EXPECT_TRUE(model.Undo()); 1127 EXPECT_STR_EQ("www.google.com", model.GetText()); 1128 EXPECT_EQ(1U, model.GetCursorPosition()); 1129 EXPECT_TRUE(model.Undo()); 1130 EXPECT_STR_EQ("", model.GetText()); 1131 EXPECT_EQ(0U, model.GetCursorPosition()); 1132 EXPECT_FALSE(model.Undo()); 1133 EXPECT_TRUE(model.Redo()); 1134 EXPECT_STR_EQ("www.google.com", model.GetText()); 1135 EXPECT_EQ(1U, model.GetCursorPosition()); 1136 EXPECT_TRUE(model.Redo()); 1137 EXPECT_STR_EQ("www.google.com", model.GetText()); 1138 EXPECT_EQ(2U, model.GetCursorPosition()); 1139 EXPECT_TRUE(model.Redo()); 1140 EXPECT_STR_EQ("www.google.com", model.GetText()); 1141 EXPECT_EQ(3U, model.GetCursorPosition()); 1142 EXPECT_TRUE(model.Redo()); 1143 EXPECT_STR_EQ("www.google.com", model.GetText()); 1144 EXPECT_EQ(4U, model.GetCursorPosition()); 1145 EXPECT_TRUE(model.Redo()); 1146 EXPECT_STR_EQ("www.youtube.com", model.GetText()); 1147 EXPECT_EQ(5U, model.GetCursorPosition()); 1148 EXPECT_FALSE(model.Redo()); 1149 } 1150 1151 TEST_F(TextfieldViewsModelTest, UndoRedo_BackspaceThenSetText) { 1152 // This is to test the undo/redo behavior of omnibox. 1153 TextfieldViewsModel model(NULL); 1154 model.InsertChar('w'); 1155 EXPECT_STR_EQ("w", model.GetText()); 1156 EXPECT_EQ(1U, model.GetCursorPosition()); 1157 model.SetText(ASCIIToUTF16("www.google.com")); 1158 EXPECT_EQ(14U, model.GetCursorPosition()); 1159 EXPECT_STR_EQ("www.google.com", model.GetText()); 1160 model.SetText(ASCIIToUTF16("www.google.com")); // Confirm the text. 1161 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 1162 EXPECT_EQ(14U, model.GetCursorPosition()); 1163 EXPECT_TRUE(model.Backspace()); 1164 EXPECT_TRUE(model.Backspace()); 1165 EXPECT_STR_EQ("www.google.c", model.GetText()); 1166 // Autocomplete sets the text 1167 model.SetText(ASCIIToUTF16("www.google.com/search=www.google.c")); 1168 EXPECT_STR_EQ("www.google.com/search=www.google.c", model.GetText()); 1169 EXPECT_TRUE(model.Undo()); 1170 EXPECT_STR_EQ("www.google.c", model.GetText()); 1171 EXPECT_TRUE(model.Undo()); 1172 EXPECT_STR_EQ("www.google.com", model.GetText()); 1173 } 1174 1175 TEST_F(TextfieldViewsModelTest, UndoRedo_CutCopyPasteTest) { 1176 TextfieldViewsModel model(NULL); 1177 model.SetText(ASCIIToUTF16("ABCDE")); 1178 EXPECT_FALSE(model.Redo()); // nothing to redo 1179 // Cut 1180 model.SelectRange(gfx::Range(1, 3)); 1181 model.Cut(); 1182 EXPECT_STR_EQ("ADE", model.GetText()); 1183 EXPECT_EQ(1U, model.GetCursorPosition()); 1184 EXPECT_TRUE(model.Undo()); 1185 EXPECT_STR_EQ("ABCDE", model.GetText()); 1186 EXPECT_EQ(3U, model.GetCursorPosition()); 1187 EXPECT_TRUE(model.Undo()); 1188 EXPECT_STR_EQ("", model.GetText()); 1189 EXPECT_EQ(0U, model.GetCursorPosition()); 1190 EXPECT_FALSE(model.Undo()); // no more undo 1191 EXPECT_STR_EQ("", model.GetText()); 1192 EXPECT_TRUE(model.Redo()); 1193 EXPECT_STR_EQ("ABCDE", model.GetText()); 1194 EXPECT_EQ(5U, model.GetCursorPosition()); 1195 EXPECT_TRUE(model.Redo()); 1196 EXPECT_STR_EQ("ADE", model.GetText()); 1197 EXPECT_EQ(1U, model.GetCursorPosition()); 1198 EXPECT_FALSE(model.Redo()); // no more redo 1199 EXPECT_STR_EQ("ADE", model.GetText()); 1200 1201 model.Paste(); 1202 model.Paste(); 1203 model.Paste(); 1204 EXPECT_STR_EQ("ABCBCBCDE", model.GetText()); 1205 EXPECT_EQ(7U, model.GetCursorPosition()); 1206 EXPECT_TRUE(model.Undo()); 1207 EXPECT_STR_EQ("ABCBCDE", model.GetText()); 1208 EXPECT_EQ(5U, model.GetCursorPosition()); 1209 EXPECT_TRUE(model.Undo()); 1210 EXPECT_STR_EQ("ABCDE", model.GetText()); 1211 EXPECT_EQ(3U, model.GetCursorPosition()); 1212 EXPECT_TRUE(model.Undo()); 1213 EXPECT_STR_EQ("ADE", model.GetText()); 1214 EXPECT_EQ(1U, model.GetCursorPosition()); 1215 EXPECT_TRUE(model.Undo()); 1216 EXPECT_STR_EQ("ABCDE", model.GetText()); 1217 EXPECT_EQ(3U, model.GetCursorPosition()); 1218 EXPECT_TRUE(model.Undo()); 1219 EXPECT_STR_EQ("", model.GetText()); 1220 EXPECT_EQ(0U, model.GetCursorPosition()); 1221 EXPECT_FALSE(model.Undo()); 1222 EXPECT_STR_EQ("", model.GetText()); 1223 EXPECT_TRUE(model.Redo()); 1224 EXPECT_STR_EQ("ABCDE", model.GetText()); // Redoing SetText 1225 EXPECT_EQ(5U, model.GetCursorPosition()); 1226 1227 // Redo 1228 EXPECT_TRUE(model.Redo()); 1229 EXPECT_STR_EQ("ADE", model.GetText()); 1230 EXPECT_EQ(1U, model.GetCursorPosition()); 1231 EXPECT_TRUE(model.Redo()); 1232 EXPECT_STR_EQ("ABCDE", model.GetText()); 1233 EXPECT_EQ(3U, model.GetCursorPosition()); 1234 EXPECT_TRUE(model.Redo()); 1235 EXPECT_STR_EQ("ABCBCDE", model.GetText()); 1236 EXPECT_EQ(5U, model.GetCursorPosition()); 1237 EXPECT_TRUE(model.Redo()); 1238 EXPECT_STR_EQ("ABCBCBCDE", model.GetText()); 1239 EXPECT_EQ(7U, model.GetCursorPosition()); 1240 EXPECT_FALSE(model.Redo()); 1241 1242 // with SelectRange 1243 model.SelectRange(gfx::Range(1, 3)); 1244 EXPECT_TRUE(model.Cut()); 1245 EXPECT_STR_EQ("ABCBCDE", model.GetText()); 1246 EXPECT_EQ(1U, model.GetCursorPosition()); 1247 model.SelectRange(gfx::Range(1, 1)); 1248 EXPECT_FALSE(model.Cut()); 1249 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 1250 EXPECT_TRUE(model.Paste()); 1251 EXPECT_STR_EQ("ABCBCDEBC", model.GetText()); 1252 EXPECT_EQ(9U, model.GetCursorPosition()); 1253 EXPECT_TRUE(model.Undo()); 1254 EXPECT_STR_EQ("ABCBCDE", model.GetText()); 1255 EXPECT_EQ(7U, model.GetCursorPosition()); 1256 // empty cut shouldn't create an edit. 1257 EXPECT_TRUE(model.Undo()); 1258 EXPECT_STR_EQ("ABCBCBCDE", model.GetText()); 1259 EXPECT_EQ(3U, model.GetCursorPosition()); 1260 1261 // Copy 1262 ResetModel(&model); 1263 model.SetText(ASCIIToUTF16("12345")); 1264 EXPECT_STR_EQ("12345", model.GetText()); 1265 EXPECT_EQ(5U, model.GetCursorPosition()); 1266 model.SelectRange(gfx::Range(1, 3)); 1267 model.Copy(); // Copy "23" 1268 EXPECT_STR_EQ("12345", model.GetText()); 1269 EXPECT_EQ(3U, model.GetCursorPosition()); 1270 model.Paste(); // Paste "23" into "23". 1271 EXPECT_STR_EQ("12345", model.GetText()); 1272 EXPECT_EQ(3U, model.GetCursorPosition()); 1273 model.Paste(); 1274 EXPECT_STR_EQ("1232345", model.GetText()); 1275 EXPECT_EQ(5U, model.GetCursorPosition()); 1276 EXPECT_TRUE(model.Undo()); 1277 EXPECT_STR_EQ("12345", model.GetText()); 1278 EXPECT_EQ(3U, model.GetCursorPosition()); 1279 // TODO(oshima): We need to change the return type from bool to enum. 1280 EXPECT_FALSE(model.Undo()); // No text change. 1281 EXPECT_STR_EQ("12345", model.GetText()); 1282 EXPECT_EQ(3U, model.GetCursorPosition()); 1283 EXPECT_TRUE(model.Undo()); 1284 EXPECT_STR_EQ("", model.GetText()); 1285 EXPECT_FALSE(model.Undo()); 1286 // Redo 1287 EXPECT_TRUE(model.Redo()); 1288 EXPECT_STR_EQ("12345", model.GetText()); 1289 EXPECT_EQ(5U, model.GetCursorPosition()); 1290 EXPECT_TRUE(model.Redo()); 1291 EXPECT_STR_EQ("12345", model.GetText()); // For 1st paste 1292 EXPECT_EQ(3U, model.GetCursorPosition()); 1293 EXPECT_TRUE(model.Redo()); 1294 EXPECT_STR_EQ("1232345", model.GetText()); 1295 EXPECT_EQ(5U, model.GetCursorPosition()); 1296 EXPECT_FALSE(model.Redo()); 1297 EXPECT_STR_EQ("1232345", model.GetText()); 1298 1299 // Test using SelectRange 1300 model.SelectRange(gfx::Range(1, 3)); 1301 model.Copy(); 1302 EXPECT_STR_EQ("1232345", model.GetText()); 1303 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 1304 EXPECT_TRUE(model.Paste()); 1305 EXPECT_STR_EQ("123234523", model.GetText()); 1306 EXPECT_EQ(9U, model.GetCursorPosition()); 1307 EXPECT_TRUE(model.Undo()); 1308 EXPECT_STR_EQ("1232345", model.GetText()); 1309 EXPECT_EQ(7U, model.GetCursorPosition()); 1310 } 1311 1312 TEST_F(TextfieldViewsModelTest, UndoRedo_CursorTest) { 1313 TextfieldViewsModel model(NULL); 1314 model.InsertChar('a'); 1315 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_LEFT, false); 1316 model.MoveCursor(gfx::CHARACTER_BREAK, gfx::CURSOR_RIGHT, false); 1317 model.InsertChar('b'); 1318 // Moving the cursor shouldn't create a new edit. 1319 EXPECT_STR_EQ("ab", model.GetText()); 1320 EXPECT_FALSE(model.Redo()); 1321 EXPECT_TRUE(model.Undo()); 1322 EXPECT_STR_EQ("", model.GetText()); 1323 EXPECT_FALSE(model.Undo()); 1324 EXPECT_STR_EQ("", model.GetText()); 1325 EXPECT_TRUE(model.Redo()); 1326 EXPECT_STR_EQ("ab", model.GetText()); 1327 EXPECT_EQ(2U, model.GetCursorPosition()); 1328 EXPECT_FALSE(model.Redo()); 1329 } 1330 1331 void RunInsertReplaceTest(TextfieldViewsModel& model) { 1332 const bool reverse = model.render_text()->selection().is_reversed(); 1333 model.InsertChar('1'); 1334 model.InsertChar('2'); 1335 model.InsertChar('3'); 1336 EXPECT_STR_EQ("a123d", model.GetText()); 1337 EXPECT_EQ(4U, model.GetCursorPosition()); 1338 EXPECT_TRUE(model.Undo()); 1339 EXPECT_STR_EQ("abcd", model.GetText()); 1340 EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition()); 1341 EXPECT_TRUE(model.Undo()); 1342 EXPECT_STR_EQ("", model.GetText()); 1343 EXPECT_EQ(0U, model.GetCursorPosition()); 1344 EXPECT_FALSE(model.Undo()); 1345 EXPECT_TRUE(model.Redo()); 1346 EXPECT_STR_EQ("abcd", model.GetText()); 1347 EXPECT_EQ(4U, model.GetCursorPosition()); // By SetText 1348 EXPECT_TRUE(model.Redo()); 1349 EXPECT_STR_EQ("a123d", model.GetText()); 1350 EXPECT_EQ(4U, model.GetCursorPosition()); 1351 EXPECT_FALSE(model.Redo()); 1352 } 1353 1354 void RunOverwriteReplaceTest(TextfieldViewsModel& model) { 1355 const bool reverse = model.render_text()->selection().is_reversed(); 1356 model.ReplaceChar('1'); 1357 model.ReplaceChar('2'); 1358 model.ReplaceChar('3'); 1359 model.ReplaceChar('4'); 1360 EXPECT_STR_EQ("a1234", model.GetText()); 1361 EXPECT_EQ(5U, model.GetCursorPosition()); 1362 EXPECT_TRUE(model.Undo()); 1363 EXPECT_STR_EQ("abcd", model.GetText()); 1364 EXPECT_EQ(reverse ? 1U : 3U, model.GetCursorPosition()); 1365 EXPECT_TRUE(model.Undo()); 1366 EXPECT_STR_EQ("", model.GetText()); 1367 EXPECT_EQ(0U, model.GetCursorPosition()); 1368 EXPECT_FALSE(model.Undo()); 1369 EXPECT_TRUE(model.Redo()); 1370 EXPECT_STR_EQ("abcd", model.GetText()); 1371 EXPECT_EQ(4U, model.GetCursorPosition()); 1372 EXPECT_TRUE(model.Redo()); 1373 EXPECT_STR_EQ("a1234", model.GetText()); 1374 EXPECT_EQ(5U, model.GetCursorPosition()); 1375 EXPECT_FALSE(model.Redo()); 1376 } 1377 1378 TEST_F(TextfieldViewsModelTest, UndoRedo_ReplaceTest) { 1379 // By Cursor 1380 { 1381 SCOPED_TRACE("forward & insert by cursor"); 1382 TextfieldViewsModel model(NULL); 1383 model.SetText(ASCIIToUTF16("abcd")); 1384 model.SelectRange(gfx::Range(1, 3)); 1385 RunInsertReplaceTest(model); 1386 } 1387 { 1388 SCOPED_TRACE("backward & insert by cursor"); 1389 TextfieldViewsModel model(NULL); 1390 model.SetText(ASCIIToUTF16("abcd")); 1391 model.SelectRange(gfx::Range(3, 1)); 1392 RunInsertReplaceTest(model); 1393 } 1394 { 1395 SCOPED_TRACE("forward & overwrite by cursor"); 1396 TextfieldViewsModel model(NULL); 1397 model.SetText(ASCIIToUTF16("abcd")); 1398 model.SelectRange(gfx::Range(1, 3)); 1399 RunOverwriteReplaceTest(model); 1400 } 1401 { 1402 SCOPED_TRACE("backward & overwrite by cursor"); 1403 TextfieldViewsModel model(NULL); 1404 model.SetText(ASCIIToUTF16("abcd")); 1405 model.SelectRange(gfx::Range(3, 1)); 1406 RunOverwriteReplaceTest(model); 1407 } 1408 // By SelectRange API 1409 { 1410 SCOPED_TRACE("forward & insert by SelectRange"); 1411 TextfieldViewsModel model(NULL); 1412 model.SetText(ASCIIToUTF16("abcd")); 1413 model.SelectRange(gfx::Range(1, 3)); 1414 RunInsertReplaceTest(model); 1415 } 1416 { 1417 SCOPED_TRACE("backward & insert by SelectRange"); 1418 TextfieldViewsModel model(NULL); 1419 model.SetText(ASCIIToUTF16("abcd")); 1420 model.SelectRange(gfx::Range(3, 1)); 1421 RunInsertReplaceTest(model); 1422 } 1423 { 1424 SCOPED_TRACE("forward & overwrite by SelectRange"); 1425 TextfieldViewsModel model(NULL); 1426 model.SetText(ASCIIToUTF16("abcd")); 1427 model.SelectRange(gfx::Range(1, 3)); 1428 RunOverwriteReplaceTest(model); 1429 } 1430 { 1431 SCOPED_TRACE("backward & overwrite by SelectRange"); 1432 TextfieldViewsModel model(NULL); 1433 model.SetText(ASCIIToUTF16("abcd")); 1434 model.SelectRange(gfx::Range(3, 1)); 1435 RunOverwriteReplaceTest(model); 1436 } 1437 } 1438 1439 TEST_F(TextfieldViewsModelTest, UndoRedo_CompositionText) { 1440 TextfieldViewsModel model(NULL); 1441 1442 ui::CompositionText composition; 1443 composition.text = ASCIIToUTF16("abc"); 1444 composition.underlines.push_back(ui::CompositionUnderline(0, 3, 0, false)); 1445 composition.selection = gfx::Range(2, 3); 1446 1447 model.SetText(ASCIIToUTF16("ABCDE")); 1448 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 1449 model.InsertChar('x'); 1450 EXPECT_STR_EQ("ABCDEx", model.GetText()); 1451 EXPECT_TRUE(model.Undo()); // set composition should forget undone edit. 1452 model.SetCompositionText(composition); 1453 EXPECT_TRUE(model.HasCompositionText()); 1454 EXPECT_TRUE(model.HasSelection()); 1455 EXPECT_STR_EQ("ABCDEabc", model.GetText()); 1456 1457 // Accepting composition 1458 model.ConfirmCompositionText(); 1459 EXPECT_STR_EQ("ABCDEabc", model.GetText()); 1460 EXPECT_TRUE(model.Undo()); 1461 EXPECT_STR_EQ("ABCDE", model.GetText()); 1462 EXPECT_TRUE(model.Undo()); 1463 EXPECT_STR_EQ("", model.GetText()); 1464 EXPECT_TRUE(model.Redo()); 1465 EXPECT_STR_EQ("ABCDE", model.GetText()); 1466 EXPECT_TRUE(model.Redo()); 1467 EXPECT_STR_EQ("ABCDEabc", model.GetText()); 1468 EXPECT_FALSE(model.Redo()); 1469 1470 // Canceling composition 1471 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_LEFT, false); 1472 model.SetCompositionText(composition); 1473 EXPECT_STR_EQ("abcABCDEabc", model.GetText()); 1474 model.CancelCompositionText(); 1475 EXPECT_STR_EQ("ABCDEabc", model.GetText()); 1476 EXPECT_FALSE(model.Redo()); 1477 EXPECT_STR_EQ("ABCDEabc", model.GetText()); 1478 EXPECT_TRUE(model.Undo()); 1479 EXPECT_STR_EQ("ABCDE", model.GetText()); 1480 EXPECT_TRUE(model.Redo()); 1481 EXPECT_STR_EQ("ABCDEabc", model.GetText()); 1482 EXPECT_FALSE(model.Redo()); 1483 1484 // SetText with the same text as the result. 1485 ResetModel(&model); 1486 model.SetText(ASCIIToUTF16("ABCDE")); 1487 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 1488 model.SetCompositionText(composition); 1489 EXPECT_STR_EQ("ABCDEabc", model.GetText()); 1490 model.SetText(ASCIIToUTF16("ABCDEabc")); 1491 EXPECT_STR_EQ("ABCDEabc", model.GetText()); 1492 EXPECT_TRUE(model.Undo()); 1493 EXPECT_STR_EQ("ABCDE", model.GetText()); 1494 EXPECT_TRUE(model.Redo()); 1495 EXPECT_STR_EQ("ABCDEabc", model.GetText()); 1496 EXPECT_FALSE(model.Redo()); 1497 1498 // SetText with the different text than the result should not 1499 // remember composition text. 1500 ResetModel(&model); 1501 model.SetText(ASCIIToUTF16("ABCDE")); 1502 model.MoveCursor(gfx::LINE_BREAK, gfx::CURSOR_RIGHT, false); 1503 model.SetCompositionText(composition); 1504 EXPECT_STR_EQ("ABCDEabc", model.GetText()); 1505 model.SetText(ASCIIToUTF16("1234")); 1506 EXPECT_STR_EQ("1234", model.GetText()); 1507 EXPECT_TRUE(model.Undo()); 1508 EXPECT_STR_EQ("ABCDE", model.GetText()); 1509 EXPECT_TRUE(model.Redo()); 1510 EXPECT_STR_EQ("1234", model.GetText()); 1511 EXPECT_FALSE(model.Redo()); 1512 1513 // TODO(oshima): We need MockInputMethod to test the behavior with IME. 1514 } 1515 1516 } // namespace views 1517