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.
5 #include "ui/chromeos/ime/candidate_window_view.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/chromeos/ime/candidate_view.h"
13 #include "ui/views/test/views_test_base.h"
14 #include "ui/views/widget/widget.h"
20 const char* kSampleCandidate
[] = {
25 const char* kSampleAnnotation
[] = {
26 "Sample Annotation 1",
27 "Sample Annotation 2",
30 const char* kSampleDescriptionTitle
[] = {
31 "Sample Description Title 1",
32 "Sample Description Title 2",
33 "Sample Description Title 3",
35 const char* kSampleDescriptionBody
[] = {
36 "Sample Description Body 1",
37 "Sample Description Body 2",
38 "Sample Description Body 3",
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
);
49 void InitCandidateWindowWithCandidatesFilled(
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
);
65 class CandidateWindowViewTest
: public views::ViewsTestBase
{
67 CandidateWindowViewTest() {}
68 ~CandidateWindowViewTest() override
{}
71 void SetUp() override
{
72 views::ViewsTestBase::SetUp();
73 candidate_window_view_
= new CandidateWindowView(GetContext());
74 candidate_window_view_
->InitWidget();
77 void TearDown() override
{
78 candidate_window_view_
->GetWidget()->CloseNow();
79 views::ViewsTestBase::TearDown();
82 CandidateWindowView
* candidate_window_view() {
83 return candidate_window_view_
;
86 int selected_candidate_index_in_page() {
87 return candidate_window_view_
->selected_candidate_index_in_page_
;
90 size_t GetCandidatesSize() const {
91 return candidate_window_view_
->candidate_views_
.size();
94 CandidateView
* GetCandidateAt(size_t i
) {
95 return candidate_window_view_
->candidate_views_
[i
];
98 void SelectCandidateAt(int index_in_page
) {
99 candidate_window_view_
->SelectCandidateAt(index_in_page
);
102 void MaybeInitializeCandidateViews(
103 const ui::CandidateWindow
& candidate_window
) {
104 candidate_window_view_
->MaybeInitializeCandidateViews(candidate_window
);
107 void ExpectLabels(const std::string
& shortcut
,
108 const std::string
& candidate
,
109 const std::string
& annotation
,
110 const CandidateView
* row
) {
111 EXPECT_EQ(shortcut
, base::UTF16ToUTF8(row
->shortcut_label_
->text()));
112 EXPECT_EQ(candidate
, base::UTF16ToUTF8(row
->candidate_label_
->text()));
113 EXPECT_EQ(annotation
, base::UTF16ToUTF8(row
->annotation_label_
->text()));
117 CandidateWindowView
* candidate_window_view_
; // Owned by its Widget.
119 DISALLOW_COPY_AND_ASSIGN(CandidateWindowViewTest
);
122 TEST_F(CandidateWindowViewTest
, UpdateCandidatesTest_CursorVisibility
) {
123 // Visible (by default) cursor.
124 ui::CandidateWindow candidate_window
;
125 const int candidate_window_size
= 9;
126 InitCandidateWindowWithCandidatesFilled(candidate_window_size
,
128 candidate_window_view()->UpdateCandidates(candidate_window
);
129 EXPECT_EQ(0, selected_candidate_index_in_page());
132 candidate_window
.set_is_cursor_visible(false);
133 candidate_window_view()->UpdateCandidates(candidate_window
);
134 EXPECT_EQ(-1, selected_candidate_index_in_page());
136 // Move the cursor to the end.
137 candidate_window
.set_cursor_position(candidate_window_size
- 1);
138 candidate_window_view()->UpdateCandidates(candidate_window
);
139 EXPECT_EQ(-1, selected_candidate_index_in_page());
141 // Change the cursor to visible. The cursor must be at the end.
142 candidate_window
.set_is_cursor_visible(true);
143 candidate_window_view()->UpdateCandidates(candidate_window
);
144 EXPECT_EQ(candidate_window_size
- 1, selected_candidate_index_in_page());
147 TEST_F(CandidateWindowViewTest
, SelectCandidateAtTest
) {
149 ui::CandidateWindow candidate_window_large
;
150 const int candidate_window_large_size
= 9;
151 InitCandidateWindowWithCandidatesFilled(candidate_window_large_size
,
152 &candidate_window_large
);
153 candidate_window_large
.set_cursor_position(candidate_window_large_size
- 1);
154 candidate_window_view()->UpdateCandidates(candidate_window_large
);
156 // Select the last candidate.
157 SelectCandidateAt(candidate_window_large_size
- 1);
159 // Reduce the number of candidates to 3.
160 ui::CandidateWindow candidate_window_small
;
161 const int candidate_window_small_size
= 3;
162 InitCandidateWindowWithCandidatesFilled(candidate_window_small_size
,
163 &candidate_window_small
);
164 candidate_window_small
.set_cursor_position(candidate_window_small_size
- 1);
165 // Make sure the test doesn't crash if the candidate window reduced
166 // its size. (crbug.com/174163)
167 candidate_window_view()->UpdateCandidates(candidate_window_small
);
168 SelectCandidateAt(candidate_window_small_size
- 1);
171 TEST_F(CandidateWindowViewTest
, ShortcutSettingTest
) {
172 const char* kEmptyLabel
= "";
173 const char* kCustomizedLabel
[] = { "a", "s", "d" };
174 const char* kExpectedHorizontalCustomizedLabel
[] = { "a.", "s.", "d." };
177 SCOPED_TRACE("candidate_views allocation test");
178 const size_t kMaxPageSize
= 16;
179 for (size_t i
= 1; i
< kMaxPageSize
; ++i
) {
180 ui::CandidateWindow candidate_window
;
181 InitCandidateWindow(i
, &candidate_window
);
182 candidate_window_view()->UpdateCandidates(candidate_window
);
183 EXPECT_EQ(i
, GetCandidatesSize());
187 SCOPED_TRACE("Empty string for each labels expects empty labels(vertical)");
188 const size_t kPageSize
= 3;
189 ui::CandidateWindow candidate_window
;
190 InitCandidateWindow(kPageSize
, &candidate_window
);
192 candidate_window
.set_orientation(ui::CandidateWindow::VERTICAL
);
193 for (size_t i
= 0; i
< kPageSize
; ++i
) {
194 ui::CandidateWindow::Entry entry
;
195 entry
.value
= base::UTF8ToUTF16(kSampleCandidate
[i
]);
196 entry
.annotation
= base::UTF8ToUTF16(kSampleAnnotation
[i
]);
197 entry
.description_title
= base::UTF8ToUTF16(kSampleDescriptionTitle
[i
]);
198 entry
.description_body
= base::UTF8ToUTF16(kSampleDescriptionBody
[i
]);
199 entry
.label
= base::UTF8ToUTF16(kEmptyLabel
);
200 candidate_window
.mutable_candidates()->push_back(entry
);
203 candidate_window_view()->UpdateCandidates(candidate_window
);
205 ASSERT_EQ(kPageSize
, GetCandidatesSize());
206 for (size_t i
= 0; i
< kPageSize
; ++i
) {
207 ExpectLabels(kEmptyLabel
, kSampleCandidate
[i
], kSampleAnnotation
[i
],
213 "Empty string for each labels expect empty labels(horizontal)");
214 const size_t kPageSize
= 3;
215 ui::CandidateWindow candidate_window
;
216 InitCandidateWindow(kPageSize
, &candidate_window
);
218 candidate_window
.set_orientation(ui::CandidateWindow::HORIZONTAL
);
219 for (size_t i
= 0; i
< kPageSize
; ++i
) {
220 ui::CandidateWindow::Entry entry
;
221 entry
.value
= base::UTF8ToUTF16(kSampleCandidate
[i
]);
222 entry
.annotation
= base::UTF8ToUTF16(kSampleAnnotation
[i
]);
223 entry
.description_title
= base::UTF8ToUTF16(kSampleDescriptionTitle
[i
]);
224 entry
.description_body
= base::UTF8ToUTF16(kSampleDescriptionBody
[i
]);
225 entry
.label
= base::UTF8ToUTF16(kEmptyLabel
);
226 candidate_window
.mutable_candidates()->push_back(entry
);
229 candidate_window_view()->UpdateCandidates(candidate_window
);
231 ASSERT_EQ(kPageSize
, GetCandidatesSize());
232 // Confirm actual labels not containing ".".
233 for (size_t i
= 0; i
< kPageSize
; ++i
) {
234 ExpectLabels(kEmptyLabel
, kSampleCandidate
[i
], kSampleAnnotation
[i
],
239 SCOPED_TRACE("Vertical customized label case");
240 const size_t kPageSize
= 3;
241 ui::CandidateWindow candidate_window
;
242 InitCandidateWindow(kPageSize
, &candidate_window
);
244 candidate_window
.set_orientation(ui::CandidateWindow::VERTICAL
);
245 for (size_t i
= 0; i
< kPageSize
; ++i
) {
246 ui::CandidateWindow::Entry entry
;
247 entry
.value
= base::UTF8ToUTF16(kSampleCandidate
[i
]);
248 entry
.annotation
= base::UTF8ToUTF16(kSampleAnnotation
[i
]);
249 entry
.description_title
= base::UTF8ToUTF16(kSampleDescriptionTitle
[i
]);
250 entry
.description_body
= base::UTF8ToUTF16(kSampleDescriptionBody
[i
]);
251 entry
.label
= base::UTF8ToUTF16(kCustomizedLabel
[i
]);
252 candidate_window
.mutable_candidates()->push_back(entry
);
255 candidate_window_view()->UpdateCandidates(candidate_window
);
257 ASSERT_EQ(kPageSize
, GetCandidatesSize());
258 // Confirm actual labels not containing ".".
259 for (size_t i
= 0; i
< kPageSize
; ++i
) {
260 ExpectLabels(kCustomizedLabel
[i
],
262 kSampleAnnotation
[i
],
267 SCOPED_TRACE("Horizontal customized label case");
268 const size_t kPageSize
= 3;
269 ui::CandidateWindow candidate_window
;
270 InitCandidateWindow(kPageSize
, &candidate_window
);
272 candidate_window
.set_orientation(ui::CandidateWindow::HORIZONTAL
);
273 for (size_t i
= 0; i
< kPageSize
; ++i
) {
274 ui::CandidateWindow::Entry entry
;
275 entry
.value
= base::UTF8ToUTF16(kSampleCandidate
[i
]);
276 entry
.annotation
= base::UTF8ToUTF16(kSampleAnnotation
[i
]);
277 entry
.description_title
= base::UTF8ToUTF16(kSampleDescriptionTitle
[i
]);
278 entry
.description_body
= base::UTF8ToUTF16(kSampleDescriptionBody
[i
]);
279 entry
.label
= base::UTF8ToUTF16(kCustomizedLabel
[i
]);
280 candidate_window
.mutable_candidates()->push_back(entry
);
283 candidate_window_view()->UpdateCandidates(candidate_window
);
285 ASSERT_EQ(kPageSize
, GetCandidatesSize());
286 // Confirm actual labels not containing ".".
287 for (size_t i
= 0; i
< kPageSize
; ++i
) {
288 ExpectLabels(kExpectedHorizontalCustomizedLabel
[i
],
290 kSampleAnnotation
[i
],
296 TEST_F(CandidateWindowViewTest
, DoNotChangeRowHeightWithLabelSwitchTest
) {
297 const size_t kPageSize
= 10;
298 ui::CandidateWindow candidate_window
;
299 ui::CandidateWindow no_shortcut_candidate_window
;
301 const base::string16 kSampleCandidate1
= base::UTF8ToUTF16(
303 const base::string16 kSampleCandidate2
= base::UTF8ToUTF16(
304 "\xE3\x81\x82"); // multi byte string.
305 const base::string16 kSampleCandidate3
= base::UTF8ToUTF16(".....");
307 const base::string16 kSampleShortcut1
= base::UTF8ToUTF16("1");
308 const base::string16 kSampleShortcut2
= base::UTF8ToUTF16("b");
309 const base::string16 kSampleShortcut3
= base::UTF8ToUTF16("C");
311 const base::string16 kSampleAnnotation1
= base::UTF8ToUTF16(
312 "Sample Annotation 1");
313 const base::string16 kSampleAnnotation2
= base::UTF8ToUTF16(
314 "\xE3\x81\x82"); // multi byte string.
315 const base::string16 kSampleAnnotation3
= base::UTF8ToUTF16("......");
317 // Create CandidateWindow object.
318 InitCandidateWindow(kPageSize
, &candidate_window
);
320 candidate_window
.set_cursor_position(0);
321 candidate_window
.set_page_size(3);
322 candidate_window
.mutable_candidates()->clear();
323 candidate_window
.set_orientation(ui::CandidateWindow::VERTICAL
);
324 no_shortcut_candidate_window
.CopyFrom(candidate_window
);
326 ui::CandidateWindow::Entry entry
;
327 entry
.value
= kSampleCandidate1
;
328 entry
.annotation
= kSampleAnnotation1
;
329 candidate_window
.mutable_candidates()->push_back(entry
);
330 entry
.label
= kSampleShortcut1
;
331 no_shortcut_candidate_window
.mutable_candidates()->push_back(entry
);
333 entry
.value
= kSampleCandidate2
;
334 entry
.annotation
= kSampleAnnotation2
;
335 candidate_window
.mutable_candidates()->push_back(entry
);
336 entry
.label
= kSampleShortcut2
;
337 no_shortcut_candidate_window
.mutable_candidates()->push_back(entry
);
339 entry
.value
= kSampleCandidate3
;
340 entry
.annotation
= kSampleAnnotation3
;
341 candidate_window
.mutable_candidates()->push_back(entry
);
342 entry
.label
= kSampleShortcut3
;
343 no_shortcut_candidate_window
.mutable_candidates()->push_back(entry
);
345 int before_height
= 0;
347 // Test for shortcut mode to no-shortcut mode.
348 // Initialize with a shortcut mode candidate window.
349 MaybeInitializeCandidateViews(candidate_window
);
350 ASSERT_EQ(3UL, GetCandidatesSize());
351 // Check the selected index is invalidated.
352 EXPECT_EQ(-1, selected_candidate_index_in_page());
354 GetCandidateAt(0)->GetContentsBounds().height();
355 // Checks all entry have same row height.
356 for (size_t i
= 1; i
< GetCandidatesSize(); ++i
)
357 EXPECT_EQ(before_height
, GetCandidateAt(i
)->GetContentsBounds().height());
359 // Initialize with a no shortcut mode candidate window.
360 MaybeInitializeCandidateViews(no_shortcut_candidate_window
);
361 ASSERT_EQ(3UL, GetCandidatesSize());
362 // Check the selected index is invalidated.
363 EXPECT_EQ(-1, selected_candidate_index_in_page());
364 EXPECT_EQ(before_height
, GetCandidateAt(0)->GetContentsBounds().height());
365 // Checks all entry have same row height.
366 for (size_t i
= 1; i
< GetCandidatesSize(); ++i
)
367 EXPECT_EQ(before_height
, GetCandidateAt(i
)->GetContentsBounds().height());
369 // Test for no-shortcut mode to shortcut mode.
370 // Initialize with a no shortcut mode candidate window.
371 MaybeInitializeCandidateViews(no_shortcut_candidate_window
);
372 ASSERT_EQ(3UL, GetCandidatesSize());
373 // Check the selected index is invalidated.
374 EXPECT_EQ(-1, selected_candidate_index_in_page());
375 before_height
= GetCandidateAt(0)->GetContentsBounds().height();
376 // Checks all entry have same row height.
377 for (size_t i
= 1; i
< GetCandidatesSize(); ++i
)
378 EXPECT_EQ(before_height
, GetCandidateAt(i
)->GetContentsBounds().height());
380 // Initialize with a shortcut mode candidate window.
381 MaybeInitializeCandidateViews(candidate_window
);
382 ASSERT_EQ(3UL, GetCandidatesSize());
383 // Check the selected index is invalidated.
384 EXPECT_EQ(-1, selected_candidate_index_in_page());
385 EXPECT_EQ(before_height
, GetCandidateAt(0)->GetContentsBounds().height());
386 // Checks all entry have same row height.
387 for (size_t i
= 1; i
< GetCandidatesSize(); ++i
)
388 EXPECT_EQ(before_height
, GetCandidateAt(i
)->GetContentsBounds().height());