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