blob: f14fb226562d6a08744cda7d1d2b741d6ef8e59e [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/input_method/candidate_window_view.h"
#include <string>
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chromeos/input_method/candidate_view.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
namespace chromeos {
namespace input_method {
namespace {
const char* kSampleCandidate[] = {
"Sample Candidate 1",
"Sample Candidate 2",
"Sample Candidate 3"
};
const char* kSampleAnnotation[] = {
"Sample Annotation 1",
"Sample Annotation 2",
"Sample Annotation 3"
};
const char* kSampleDescriptionTitle[] = {
"Sample Description Title 1",
"Sample Description Title 2",
"Sample Description Title 3",
};
const char* kSampleDescriptionBody[] = {
"Sample Description Body 1",
"Sample Description Body 2",
"Sample Description Body 3",
};
void InitIBusLookupTable(size_t page_size,
IBusLookupTable* table) {
table->set_cursor_position(0);
table->set_page_size(page_size);
table->mutable_candidates()->clear();
table->set_orientation(IBusLookupTable::VERTICAL);
}
void InitIBusLookupTableWithCandidatesFilled(size_t page_size,
IBusLookupTable* table) {
InitIBusLookupTable(page_size, table);
for (size_t i = 0; i < page_size; ++i) {
IBusLookupTable::Entry entry;
entry.value = base::StringPrintf("value %lld",
static_cast<unsigned long long>(i));
entry.label = base::StringPrintf("%lld",
static_cast<unsigned long long>(i));
table->mutable_candidates()->push_back(entry);
}
}
} // namespace
class CandidateWindowViewTest : public views::ViewsTestBase {
protected:
void ExpectLabels(const std::string& shortcut,
const std::string& candidate,
const std::string& annotation,
const CandidateView* row) {
EXPECT_EQ(shortcut, UTF16ToUTF8(row->shortcut_label_->text()));
EXPECT_EQ(candidate, UTF16ToUTF8(row->candidate_label_->text()));
EXPECT_EQ(annotation, UTF16ToUTF8(row->annotation_label_->text()));
}
};
TEST_F(CandidateWindowViewTest, UpdateCandidatesTest_CursorVisibility) {
views::Widget* widget = new views::Widget;
views::Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
widget->Init(params);
CandidateWindowView candidate_window_view(widget);
candidate_window_view.Init();
// Visible (by default) cursor.
IBusLookupTable table;
const int table_size = 9;
InitIBusLookupTableWithCandidatesFilled(table_size, &table);
candidate_window_view.UpdateCandidates(table);
EXPECT_EQ(0, candidate_window_view.selected_candidate_index_in_page_);
// Invisible cursor.
table.set_is_cursor_visible(false);
candidate_window_view.UpdateCandidates(table);
EXPECT_EQ(-1, candidate_window_view.selected_candidate_index_in_page_);
// Move the cursor to the end.
table.set_cursor_position(table_size - 1);
candidate_window_view.UpdateCandidates(table);
EXPECT_EQ(-1, candidate_window_view.selected_candidate_index_in_page_);
// Change the cursor to visible. The cursor must be at the end.
table.set_is_cursor_visible(true);
candidate_window_view.UpdateCandidates(table);
EXPECT_EQ(table_size - 1,
candidate_window_view.selected_candidate_index_in_page_);
}
TEST_F(CandidateWindowViewTest, SelectCandidateAtTest) {
views::Widget* widget = new views::Widget;
views::Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
widget->Init(params);
CandidateWindowView candidate_window_view(widget);
candidate_window_view.Init();
// Set 9 candidates.
IBusLookupTable table_large;
const int table_large_size = 9;
InitIBusLookupTableWithCandidatesFilled(table_large_size, &table_large);
table_large.set_cursor_position(table_large_size - 1);
candidate_window_view.UpdateCandidates(table_large);
// Select the last candidate.
candidate_window_view.SelectCandidateAt(table_large_size - 1);
// Reduce the number of candidates to 3.
IBusLookupTable table_small;
const int table_small_size = 3;
InitIBusLookupTableWithCandidatesFilled(table_small_size, &table_small);
table_small.set_cursor_position(table_small_size - 1);
// Make sure the test doesn't crash if the candidate table reduced its size.
// (crbug.com/174163)
candidate_window_view.UpdateCandidates(table_small);
candidate_window_view.SelectCandidateAt(table_small_size - 1);
}
TEST_F(CandidateWindowViewTest, ShortcutSettingTest) {
const char* kEmptyLabel = "";
const char* kCustomizedLabel[] = { "a", "s", "d" };
const char* kExpectedHorizontalCustomizedLabel[] = { "a.", "s.", "d." };
views::Widget* widget = new views::Widget;
views::Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
widget->Init(params);
CandidateWindowView candidate_window_view(widget);
candidate_window_view.Init();
{
SCOPED_TRACE("candidate_views allocation test");
const size_t kMaxPageSize = 16;
for (size_t i = 1; i < kMaxPageSize; ++i) {
IBusLookupTable table;
InitIBusLookupTable(i, &table);
candidate_window_view.UpdateCandidates(table);
EXPECT_EQ(i, candidate_window_view.candidate_views_.size());
}
}
{
SCOPED_TRACE("Empty string for each labels expects empty labels(vertical)");
const size_t kPageSize = 3;
IBusLookupTable table;
InitIBusLookupTable(kPageSize, &table);
table.set_orientation(IBusLookupTable::VERTICAL);
for (size_t i = 0; i < kPageSize; ++i) {
IBusLookupTable::Entry entry;
entry.value = kSampleCandidate[i];
entry.annotation = kSampleAnnotation[i];
entry.description_title = kSampleDescriptionTitle[i];
entry.description_body = kSampleDescriptionBody[i];
entry.label = kEmptyLabel;
table.mutable_candidates()->push_back(entry);
}
candidate_window_view.UpdateCandidates(table);
ASSERT_EQ(kPageSize, candidate_window_view.candidate_views_.size());
for (size_t i = 0; i < kPageSize; ++i) {
ExpectLabels(kEmptyLabel, kSampleCandidate[i], kSampleAnnotation[i],
candidate_window_view.candidate_views_[i]);
}
}
{
SCOPED_TRACE(
"Empty string for each labels expect empty labels(horizontal)");
const size_t kPageSize = 3;
IBusLookupTable table;
InitIBusLookupTable(kPageSize, &table);
table.set_orientation(IBusLookupTable::HORIZONTAL);
for (size_t i = 0; i < kPageSize; ++i) {
IBusLookupTable::Entry entry;
entry.value = kSampleCandidate[i];
entry.annotation = kSampleAnnotation[i];
entry.description_title = kSampleDescriptionTitle[i];
entry.description_body = kSampleDescriptionBody[i];
entry.label = kEmptyLabel;
table.mutable_candidates()->push_back(entry);
}
candidate_window_view.UpdateCandidates(table);
ASSERT_EQ(kPageSize, candidate_window_view.candidate_views_.size());
// Confirm actual labels not containing ".".
for (size_t i = 0; i < kPageSize; ++i) {
ExpectLabels(kEmptyLabel, kSampleCandidate[i], kSampleAnnotation[i],
candidate_window_view.candidate_views_[i]);
}
}
{
SCOPED_TRACE("Vertical customized label case");
const size_t kPageSize = 3;
IBusLookupTable table;
InitIBusLookupTable(kPageSize, &table);
table.set_orientation(IBusLookupTable::VERTICAL);
for (size_t i = 0; i < kPageSize; ++i) {
IBusLookupTable::Entry entry;
entry.value = kSampleCandidate[i];
entry.annotation = kSampleAnnotation[i];
entry.description_title = kSampleDescriptionTitle[i];
entry.description_body = kSampleDescriptionBody[i];
entry.label = kCustomizedLabel[i];
table.mutable_candidates()->push_back(entry);
}
candidate_window_view.UpdateCandidates(table);
ASSERT_EQ(kPageSize, candidate_window_view.candidate_views_.size());
// Confirm actual labels not containing ".".
for (size_t i = 0; i < kPageSize; ++i) {
ExpectLabels(kCustomizedLabel[i],
kSampleCandidate[i],
kSampleAnnotation[i],
candidate_window_view.candidate_views_[i]);
}
}
{
SCOPED_TRACE("Horizontal customized label case");
const size_t kPageSize = 3;
IBusLookupTable table;
InitIBusLookupTable(kPageSize, &table);
table.set_orientation(IBusLookupTable::HORIZONTAL);
for (size_t i = 0; i < kPageSize; ++i) {
IBusLookupTable::Entry entry;
entry.value = kSampleCandidate[i];
entry.annotation = kSampleAnnotation[i];
entry.description_title = kSampleDescriptionTitle[i];
entry.description_body = kSampleDescriptionBody[i];
entry.label = kCustomizedLabel[i];
table.mutable_candidates()->push_back(entry);
}
candidate_window_view.UpdateCandidates(table);
ASSERT_EQ(kPageSize, candidate_window_view.candidate_views_.size());
// Confirm actual labels not containing ".".
for (size_t i = 0; i < kPageSize; ++i) {
ExpectLabels(kExpectedHorizontalCustomizedLabel[i],
kSampleCandidate[i],
kSampleAnnotation[i],
candidate_window_view.candidate_views_[i]);
}
}
// We should call CloseNow method, otherwise this test will leak memory.
widget->CloseNow();
}
TEST_F(CandidateWindowViewTest, DoNotChangeRowHeightWithLabelSwitchTest) {
const size_t kPageSize = 10;
IBusLookupTable table;
IBusLookupTable no_shortcut_table;
const char kSampleCandidate1[] = "Sample String 1";
const char kSampleCandidate2[] = "\xE3\x81\x82"; // multi byte string.
const char kSampleCandidate3[] = ".....";
const char kSampleShortcut1[] = "1";
const char kSampleShortcut2[] = "b";
const char kSampleShortcut3[] = "C";
const char kSampleAnnotation1[] = "Sample Annotation 1";
const char kSampleAnnotation2[] = "\xE3\x81\x82"; // multi byte string.
const char kSampleAnnotation3[] = "......";
// For testing, we have to prepare empty widget.
// We should NOT manually free widget by default, otherwise double free will
// be occurred. So, we should instantiate widget class with "new" operation.
views::Widget* widget = new views::Widget;
views::Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
widget->Init(params);
CandidateWindowView candidate_window_view(widget);
candidate_window_view.Init();
// Create LookupTable object.
InitIBusLookupTable(kPageSize, &table);
table.set_cursor_position(0);
table.set_page_size(3);
table.mutable_candidates()->clear();
table.set_orientation(IBusLookupTable::VERTICAL);
no_shortcut_table.CopyFrom(table);
IBusLookupTable::Entry entry;
entry.value = kSampleCandidate1;
entry.annotation = kSampleAnnotation1;
table.mutable_candidates()->push_back(entry);
entry.label = kSampleShortcut1;
no_shortcut_table.mutable_candidates()->push_back(entry);
entry.value = kSampleCandidate2;
entry.annotation = kSampleAnnotation2;
table.mutable_candidates()->push_back(entry);
entry.label = kSampleShortcut2;
no_shortcut_table.mutable_candidates()->push_back(entry);
entry.value = kSampleCandidate3;
entry.annotation = kSampleAnnotation3;
table.mutable_candidates()->push_back(entry);
entry.label = kSampleShortcut3;
no_shortcut_table.mutable_candidates()->push_back(entry);
int before_height = 0;
// Test for shortcut mode to no-shortcut mode.
// Initialize with a shortcut mode lookup table.
candidate_window_view.MaybeInitializeCandidateViews(table);
ASSERT_EQ(3UL, candidate_window_view.candidate_views_.size());
// Check the selected index is invalidated.
EXPECT_EQ(-1, candidate_window_view.selected_candidate_index_in_page_);
before_height =
candidate_window_view.candidate_views_[0]->GetContentsBounds().height();
// Checks all entry have same row height.
for (size_t i = 1; i < candidate_window_view.candidate_views_.size(); ++i) {
const CandidateView* view = candidate_window_view.candidate_views_[i];
EXPECT_EQ(before_height, view->GetContentsBounds().height());
}
// Initialize with a no shortcut mode lookup table.
candidate_window_view.MaybeInitializeCandidateViews(no_shortcut_table);
ASSERT_EQ(3UL, candidate_window_view.candidate_views_.size());
// Check the selected index is invalidated.
EXPECT_EQ(-1, candidate_window_view.selected_candidate_index_in_page_);
EXPECT_EQ(before_height,
candidate_window_view.candidate_views_[0]->GetContentsBounds()
.height());
// Checks all entry have same row height.
for (size_t i = 1; i < candidate_window_view.candidate_views_.size(); ++i) {
const CandidateView* view = candidate_window_view.candidate_views_[i];
EXPECT_EQ(before_height, view->GetContentsBounds().height());
}
// Test for no-shortcut mode to shortcut mode.
// Initialize with a no shortcut mode lookup table.
candidate_window_view.MaybeInitializeCandidateViews(no_shortcut_table);
ASSERT_EQ(3UL, candidate_window_view.candidate_views_.size());
// Check the selected index is invalidated.
EXPECT_EQ(-1, candidate_window_view.selected_candidate_index_in_page_);
before_height =
candidate_window_view.candidate_views_[0]->GetContentsBounds().height();
// Checks all entry have same row height.
for (size_t i = 1; i < candidate_window_view.candidate_views_.size(); ++i) {
const CandidateView* view = candidate_window_view.candidate_views_[i];
EXPECT_EQ(before_height, view->GetContentsBounds().height());
}
// Initialize with a shortcut mode lookup table.
candidate_window_view.MaybeInitializeCandidateViews(table);
ASSERT_EQ(3UL, candidate_window_view.candidate_views_.size());
// Check the selected index is invalidated.
EXPECT_EQ(-1, candidate_window_view.selected_candidate_index_in_page_);
EXPECT_EQ(before_height,
candidate_window_view.candidate_views_[0]->GetContentsBounds()
.height());
// Checks all entry have same row height.
for (size_t i = 1; i < candidate_window_view.candidate_views_.size(); ++i) {
const CandidateView* view = candidate_window_view.candidate_views_[i];
EXPECT_EQ(before_height, view->GetContentsBounds().height());
}
// We should call CloseNow method, otherwise this test will leak memory.
widget->CloseNow();
}
} // namespace input_method
} // namespace chromeos