| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ash/ime/candidate_window_view.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "ash/ime/candidate_view.h" | |
| 10 #include "base/strings/stringprintf.h" | |
| 11 #include "base/strings/utf_string_conversions.h" | |
| 12 #include "testing/gtest/include/gtest/gtest.h" | |
| 13 #include "ui/views/test/views_test_base.h" | |
| 14 #include "ui/views/widget/widget.h" | |
| 15 | |
| 16 namespace ash { | |
| 17 namespace ime { | |
| 18 | |
| 19 namespace { | |
| 20 const char* kSampleCandidate[] = { | |
| 21 "Sample Candidate 1", | |
| 22 "Sample Candidate 2", | |
| 23 "Sample Candidate 3" | |
| 24 }; | |
| 25 const char* kSampleAnnotation[] = { | |
| 26 "Sample Annotation 1", | |
| 27 "Sample Annotation 2", | |
| 28 "Sample Annotation 3" | |
| 29 }; | |
| 30 const char* kSampleDescriptionTitle[] = { | |
| 31 "Sample Description Title 1", | |
| 32 "Sample Description Title 2", | |
| 33 "Sample Description Title 3", | |
| 34 }; | |
| 35 const char* kSampleDescriptionBody[] = { | |
| 36 "Sample Description Body 1", | |
| 37 "Sample Description Body 2", | |
| 38 "Sample Description Body 3", | |
| 39 }; | |
| 40 | |
| 41 void InitCandidateWindow(size_t page_size, | |
| 42 ui::CandidateWindow* candidate_window) { | |
| 43 candidate_window->set_cursor_position(0); | |
| 44 candidate_window->set_page_size(page_size); | |
| 45 candidate_window->mutable_candidates()->clear(); | |
| 46 candidate_window->set_orientation(ui::CandidateWindow::VERTICAL); | |
| 47 } | |
| 48 | |
| 49 void InitCandidateWindowWithCandidatesFilled( | |
| 50 size_t page_size, | |
| 51 ui::CandidateWindow* candidate_window) { | |
| 52 InitCandidateWindow(page_size, candidate_window); | |
| 53 for (size_t i = 0; i < page_size; ++i) { | |
| 54 ui::CandidateWindow::Entry entry; | |
| 55 entry.value = base::UTF8ToUTF16(base::StringPrintf( | |
| 56 "value %lld", static_cast<unsigned long long>(i))); | |
| 57 entry.label = base::UTF8ToUTF16(base::StringPrintf( | |
| 58 "%lld", static_cast<unsigned long long>(i))); | |
| 59 candidate_window->mutable_candidates()->push_back(entry); | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 } // namespace | |
| 64 | |
| 65 class CandidateWindowViewTest : public views::ViewsTestBase { | |
| 66 public: | |
| 67 CandidateWindowViewTest() {} | |
| 68 ~CandidateWindowViewTest() override {} | |
| 69 | |
| 70 protected: | |
| 71 void SetUp() override { | |
| 72 views::ViewsTestBase::SetUp(); | |
| 73 candidate_window_view_ = new CandidateWindowView(GetContext()); | |
| 74 candidate_window_view_->InitWidget(); | |
| 75 } | |
| 76 | |
| 77 CandidateWindowView* candidate_window_view() { | |
| 78 return candidate_window_view_; | |
| 79 } | |
| 80 | |
| 81 int selected_candidate_index_in_page() { | |
| 82 return candidate_window_view_->selected_candidate_index_in_page_; | |
| 83 } | |
| 84 | |
| 85 size_t GetCandidatesSize() const { | |
| 86 return candidate_window_view_->candidate_views_.size(); | |
| 87 } | |
| 88 | |
| 89 CandidateView* GetCandidateAt(size_t i) { | |
| 90 return candidate_window_view_->candidate_views_[i]; | |
| 91 } | |
| 92 | |
| 93 void SelectCandidateAt(int index_in_page) { | |
| 94 candidate_window_view_->SelectCandidateAt(index_in_page); | |
| 95 } | |
| 96 | |
| 97 void MaybeInitializeCandidateViews( | |
| 98 const ui::CandidateWindow& candidate_window) { | |
| 99 candidate_window_view_->MaybeInitializeCandidateViews(candidate_window); | |
| 100 } | |
| 101 | |
| 102 void ExpectLabels(const std::string& shortcut, | |
| 103 const std::string& candidate, | |
| 104 const std::string& annotation, | |
| 105 const CandidateView* row) { | |
| 106 EXPECT_EQ(shortcut, base::UTF16ToUTF8(row->shortcut_label_->text())); | |
| 107 EXPECT_EQ(candidate, base::UTF16ToUTF8(row->candidate_label_->text())); | |
| 108 EXPECT_EQ(annotation, base::UTF16ToUTF8(row->annotation_label_->text())); | |
| 109 } | |
| 110 | |
| 111 private: | |
| 112 // owned by |parent_|. | |
| 113 CandidateWindowView* candidate_window_view_; | |
| 114 | |
| 115 DISALLOW_COPY_AND_ASSIGN(CandidateWindowViewTest); | |
| 116 }; | |
| 117 | |
| 118 TEST_F(CandidateWindowViewTest, UpdateCandidatesTest_CursorVisibility) { | |
| 119 // Visible (by default) cursor. | |
| 120 ui::CandidateWindow candidate_window; | |
| 121 const int candidate_window_size = 9; | |
| 122 InitCandidateWindowWithCandidatesFilled(candidate_window_size, | |
| 123 &candidate_window); | |
| 124 candidate_window_view()->UpdateCandidates(candidate_window); | |
| 125 EXPECT_EQ(0, selected_candidate_index_in_page()); | |
| 126 | |
| 127 // Invisible cursor. | |
| 128 candidate_window.set_is_cursor_visible(false); | |
| 129 candidate_window_view()->UpdateCandidates(candidate_window); | |
| 130 EXPECT_EQ(-1, selected_candidate_index_in_page()); | |
| 131 | |
| 132 // Move the cursor to the end. | |
| 133 candidate_window.set_cursor_position(candidate_window_size - 1); | |
| 134 candidate_window_view()->UpdateCandidates(candidate_window); | |
| 135 EXPECT_EQ(-1, selected_candidate_index_in_page()); | |
| 136 | |
| 137 // Change the cursor to visible. The cursor must be at the end. | |
| 138 candidate_window.set_is_cursor_visible(true); | |
| 139 candidate_window_view()->UpdateCandidates(candidate_window); | |
| 140 EXPECT_EQ(candidate_window_size - 1, selected_candidate_index_in_page()); | |
| 141 } | |
| 142 | |
| 143 TEST_F(CandidateWindowViewTest, SelectCandidateAtTest) { | |
| 144 // Set 9 candidates. | |
| 145 ui::CandidateWindow candidate_window_large; | |
| 146 const int candidate_window_large_size = 9; | |
| 147 InitCandidateWindowWithCandidatesFilled(candidate_window_large_size, | |
| 148 &candidate_window_large); | |
| 149 candidate_window_large.set_cursor_position(candidate_window_large_size - 1); | |
| 150 candidate_window_view()->UpdateCandidates(candidate_window_large); | |
| 151 | |
| 152 // Select the last candidate. | |
| 153 SelectCandidateAt(candidate_window_large_size - 1); | |
| 154 | |
| 155 // Reduce the number of candidates to 3. | |
| 156 ui::CandidateWindow candidate_window_small; | |
| 157 const int candidate_window_small_size = 3; | |
| 158 InitCandidateWindowWithCandidatesFilled(candidate_window_small_size, | |
| 159 &candidate_window_small); | |
| 160 candidate_window_small.set_cursor_position(candidate_window_small_size - 1); | |
| 161 // Make sure the test doesn't crash if the candidate window reduced | |
| 162 // its size. (crbug.com/174163) | |
| 163 candidate_window_view()->UpdateCandidates(candidate_window_small); | |
| 164 SelectCandidateAt(candidate_window_small_size - 1); | |
| 165 } | |
| 166 | |
| 167 TEST_F(CandidateWindowViewTest, ShortcutSettingTest) { | |
| 168 const char* kEmptyLabel = ""; | |
| 169 const char* kCustomizedLabel[] = { "a", "s", "d" }; | |
| 170 const char* kExpectedHorizontalCustomizedLabel[] = { "a.", "s.", "d." }; | |
| 171 | |
| 172 { | |
| 173 SCOPED_TRACE("candidate_views allocation test"); | |
| 174 const size_t kMaxPageSize = 16; | |
| 175 for (size_t i = 1; i < kMaxPageSize; ++i) { | |
| 176 ui::CandidateWindow candidate_window; | |
| 177 InitCandidateWindow(i, &candidate_window); | |
| 178 candidate_window_view()->UpdateCandidates(candidate_window); | |
| 179 EXPECT_EQ(i, GetCandidatesSize()); | |
| 180 } | |
| 181 } | |
| 182 { | |
| 183 SCOPED_TRACE("Empty string for each labels expects empty labels(vertical)"); | |
| 184 const size_t kPageSize = 3; | |
| 185 ui::CandidateWindow candidate_window; | |
| 186 InitCandidateWindow(kPageSize, &candidate_window); | |
| 187 | |
| 188 candidate_window.set_orientation(ui::CandidateWindow::VERTICAL); | |
| 189 for (size_t i = 0; i < kPageSize; ++i) { | |
| 190 ui::CandidateWindow::Entry entry; | |
| 191 entry.value = base::UTF8ToUTF16(kSampleCandidate[i]); | |
| 192 entry.annotation = base::UTF8ToUTF16(kSampleAnnotation[i]); | |
| 193 entry.description_title = base::UTF8ToUTF16(kSampleDescriptionTitle[i]); | |
| 194 entry.description_body = base::UTF8ToUTF16(kSampleDescriptionBody[i]); | |
| 195 entry.label = base::UTF8ToUTF16(kEmptyLabel); | |
| 196 candidate_window.mutable_candidates()->push_back(entry); | |
| 197 } | |
| 198 | |
| 199 candidate_window_view()->UpdateCandidates(candidate_window); | |
| 200 | |
| 201 ASSERT_EQ(kPageSize, GetCandidatesSize()); | |
| 202 for (size_t i = 0; i < kPageSize; ++i) { | |
| 203 ExpectLabels(kEmptyLabel, kSampleCandidate[i], kSampleAnnotation[i], | |
| 204 GetCandidateAt(i)); | |
| 205 } | |
| 206 } | |
| 207 { | |
| 208 SCOPED_TRACE( | |
| 209 "Empty string for each labels expect empty labels(horizontal)"); | |
| 210 const size_t kPageSize = 3; | |
| 211 ui::CandidateWindow candidate_window; | |
| 212 InitCandidateWindow(kPageSize, &candidate_window); | |
| 213 | |
| 214 candidate_window.set_orientation(ui::CandidateWindow::HORIZONTAL); | |
| 215 for (size_t i = 0; i < kPageSize; ++i) { | |
| 216 ui::CandidateWindow::Entry entry; | |
| 217 entry.value = base::UTF8ToUTF16(kSampleCandidate[i]); | |
| 218 entry.annotation = base::UTF8ToUTF16(kSampleAnnotation[i]); | |
| 219 entry.description_title = base::UTF8ToUTF16(kSampleDescriptionTitle[i]); | |
| 220 entry.description_body = base::UTF8ToUTF16(kSampleDescriptionBody[i]); | |
| 221 entry.label = base::UTF8ToUTF16(kEmptyLabel); | |
| 222 candidate_window.mutable_candidates()->push_back(entry); | |
| 223 } | |
| 224 | |
| 225 candidate_window_view()->UpdateCandidates(candidate_window); | |
| 226 | |
| 227 ASSERT_EQ(kPageSize, GetCandidatesSize()); | |
| 228 // Confirm actual labels not containing ".". | |
| 229 for (size_t i = 0; i < kPageSize; ++i) { | |
| 230 ExpectLabels(kEmptyLabel, kSampleCandidate[i], kSampleAnnotation[i], | |
| 231 GetCandidateAt(i)); | |
| 232 } | |
| 233 } | |
| 234 { | |
| 235 SCOPED_TRACE("Vertical customized label case"); | |
| 236 const size_t kPageSize = 3; | |
| 237 ui::CandidateWindow candidate_window; | |
| 238 InitCandidateWindow(kPageSize, &candidate_window); | |
| 239 | |
| 240 candidate_window.set_orientation(ui::CandidateWindow::VERTICAL); | |
| 241 for (size_t i = 0; i < kPageSize; ++i) { | |
| 242 ui::CandidateWindow::Entry entry; | |
| 243 entry.value = base::UTF8ToUTF16(kSampleCandidate[i]); | |
| 244 entry.annotation = base::UTF8ToUTF16(kSampleAnnotation[i]); | |
| 245 entry.description_title = base::UTF8ToUTF16(kSampleDescriptionTitle[i]); | |
| 246 entry.description_body = base::UTF8ToUTF16(kSampleDescriptionBody[i]); | |
| 247 entry.label = base::UTF8ToUTF16(kCustomizedLabel[i]); | |
| 248 candidate_window.mutable_candidates()->push_back(entry); | |
| 249 } | |
| 250 | |
| 251 candidate_window_view()->UpdateCandidates(candidate_window); | |
| 252 | |
| 253 ASSERT_EQ(kPageSize, GetCandidatesSize()); | |
| 254 // Confirm actual labels not containing ".". | |
| 255 for (size_t i = 0; i < kPageSize; ++i) { | |
| 256 ExpectLabels(kCustomizedLabel[i], | |
| 257 kSampleCandidate[i], | |
| 258 kSampleAnnotation[i], | |
| 259 GetCandidateAt(i)); | |
| 260 } | |
| 261 } | |
| 262 { | |
| 263 SCOPED_TRACE("Horizontal customized label case"); | |
| 264 const size_t kPageSize = 3; | |
| 265 ui::CandidateWindow candidate_window; | |
| 266 InitCandidateWindow(kPageSize, &candidate_window); | |
| 267 | |
| 268 candidate_window.set_orientation(ui::CandidateWindow::HORIZONTAL); | |
| 269 for (size_t i = 0; i < kPageSize; ++i) { | |
| 270 ui::CandidateWindow::Entry entry; | |
| 271 entry.value = base::UTF8ToUTF16(kSampleCandidate[i]); | |
| 272 entry.annotation = base::UTF8ToUTF16(kSampleAnnotation[i]); | |
| 273 entry.description_title = base::UTF8ToUTF16(kSampleDescriptionTitle[i]); | |
| 274 entry.description_body = base::UTF8ToUTF16(kSampleDescriptionBody[i]); | |
| 275 entry.label = base::UTF8ToUTF16(kCustomizedLabel[i]); | |
| 276 candidate_window.mutable_candidates()->push_back(entry); | |
| 277 } | |
| 278 | |
| 279 candidate_window_view()->UpdateCandidates(candidate_window); | |
| 280 | |
| 281 ASSERT_EQ(kPageSize, GetCandidatesSize()); | |
| 282 // Confirm actual labels not containing ".". | |
| 283 for (size_t i = 0; i < kPageSize; ++i) { | |
| 284 ExpectLabels(kExpectedHorizontalCustomizedLabel[i], | |
| 285 kSampleCandidate[i], | |
| 286 kSampleAnnotation[i], | |
| 287 GetCandidateAt(i)); | |
| 288 } | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 TEST_F(CandidateWindowViewTest, DoNotChangeRowHeightWithLabelSwitchTest) { | |
| 293 const size_t kPageSize = 10; | |
| 294 ui::CandidateWindow candidate_window; | |
| 295 ui::CandidateWindow no_shortcut_candidate_window; | |
| 296 | |
| 297 const base::string16 kSampleCandidate1 = base::UTF8ToUTF16( | |
| 298 "Sample String 1"); | |
| 299 const base::string16 kSampleCandidate2 = base::UTF8ToUTF16( | |
| 300 "\xE3\x81\x82"); // multi byte string. | |
| 301 const base::string16 kSampleCandidate3 = base::UTF8ToUTF16("....."); | |
| 302 | |
| 303 const base::string16 kSampleShortcut1 = base::UTF8ToUTF16("1"); | |
| 304 const base::string16 kSampleShortcut2 = base::UTF8ToUTF16("b"); | |
| 305 const base::string16 kSampleShortcut3 = base::UTF8ToUTF16("C"); | |
| 306 | |
| 307 const base::string16 kSampleAnnotation1 = base::UTF8ToUTF16( | |
| 308 "Sample Annotation 1"); | |
| 309 const base::string16 kSampleAnnotation2 = base::UTF8ToUTF16( | |
| 310 "\xE3\x81\x82"); // multi byte string. | |
| 311 const base::string16 kSampleAnnotation3 = base::UTF8ToUTF16("......"); | |
| 312 | |
| 313 // Create CandidateWindow object. | |
| 314 InitCandidateWindow(kPageSize, &candidate_window); | |
| 315 | |
| 316 candidate_window.set_cursor_position(0); | |
| 317 candidate_window.set_page_size(3); | |
| 318 candidate_window.mutable_candidates()->clear(); | |
| 319 candidate_window.set_orientation(ui::CandidateWindow::VERTICAL); | |
| 320 no_shortcut_candidate_window.CopyFrom(candidate_window); | |
| 321 | |
| 322 ui::CandidateWindow::Entry entry; | |
| 323 entry.value = kSampleCandidate1; | |
| 324 entry.annotation = kSampleAnnotation1; | |
| 325 candidate_window.mutable_candidates()->push_back(entry); | |
| 326 entry.label = kSampleShortcut1; | |
| 327 no_shortcut_candidate_window.mutable_candidates()->push_back(entry); | |
| 328 | |
| 329 entry.value = kSampleCandidate2; | |
| 330 entry.annotation = kSampleAnnotation2; | |
| 331 candidate_window.mutable_candidates()->push_back(entry); | |
| 332 entry.label = kSampleShortcut2; | |
| 333 no_shortcut_candidate_window.mutable_candidates()->push_back(entry); | |
| 334 | |
| 335 entry.value = kSampleCandidate3; | |
| 336 entry.annotation = kSampleAnnotation3; | |
| 337 candidate_window.mutable_candidates()->push_back(entry); | |
| 338 entry.label = kSampleShortcut3; | |
| 339 no_shortcut_candidate_window.mutable_candidates()->push_back(entry); | |
| 340 | |
| 341 int before_height = 0; | |
| 342 | |
| 343 // Test for shortcut mode to no-shortcut mode. | |
| 344 // Initialize with a shortcut mode candidate window. | |
| 345 MaybeInitializeCandidateViews(candidate_window); | |
| 346 ASSERT_EQ(3UL, GetCandidatesSize()); | |
| 347 // Check the selected index is invalidated. | |
| 348 EXPECT_EQ(-1, selected_candidate_index_in_page()); | |
| 349 before_height = | |
| 350 GetCandidateAt(0)->GetContentsBounds().height(); | |
| 351 // Checks all entry have same row height. | |
| 352 for (size_t i = 1; i < GetCandidatesSize(); ++i) | |
| 353 EXPECT_EQ(before_height, GetCandidateAt(i)->GetContentsBounds().height()); | |
| 354 | |
| 355 // Initialize with a no shortcut mode candidate window. | |
| 356 MaybeInitializeCandidateViews(no_shortcut_candidate_window); | |
| 357 ASSERT_EQ(3UL, GetCandidatesSize()); | |
| 358 // Check the selected index is invalidated. | |
| 359 EXPECT_EQ(-1, selected_candidate_index_in_page()); | |
| 360 EXPECT_EQ(before_height, GetCandidateAt(0)->GetContentsBounds().height()); | |
| 361 // Checks all entry have same row height. | |
| 362 for (size_t i = 1; i < GetCandidatesSize(); ++i) | |
| 363 EXPECT_EQ(before_height, GetCandidateAt(i)->GetContentsBounds().height()); | |
| 364 | |
| 365 // Test for no-shortcut mode to shortcut mode. | |
| 366 // Initialize with a no shortcut mode candidate window. | |
| 367 MaybeInitializeCandidateViews(no_shortcut_candidate_window); | |
| 368 ASSERT_EQ(3UL, GetCandidatesSize()); | |
| 369 // Check the selected index is invalidated. | |
| 370 EXPECT_EQ(-1, selected_candidate_index_in_page()); | |
| 371 before_height = GetCandidateAt(0)->GetContentsBounds().height(); | |
| 372 // Checks all entry have same row height. | |
| 373 for (size_t i = 1; i < GetCandidatesSize(); ++i) | |
| 374 EXPECT_EQ(before_height, GetCandidateAt(i)->GetContentsBounds().height()); | |
| 375 | |
| 376 // Initialize with a shortcut mode candidate window. | |
| 377 MaybeInitializeCandidateViews(candidate_window); | |
| 378 ASSERT_EQ(3UL, GetCandidatesSize()); | |
| 379 // Check the selected index is invalidated. | |
| 380 EXPECT_EQ(-1, selected_candidate_index_in_page()); | |
| 381 EXPECT_EQ(before_height, GetCandidateAt(0)->GetContentsBounds().height()); | |
| 382 // Checks all entry have same row height. | |
| 383 for (size_t i = 1; i < GetCandidatesSize(); ++i) | |
| 384 EXPECT_EQ(before_height, GetCandidateAt(i)->GetContentsBounds().height()); | |
| 385 } | |
| 386 | |
| 387 } // namespace ime | |
| 388 } // namespace ash | |
| OLD | NEW |