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 "chrome/browser/chromeos/input_method/ui/candidate_view.h"
6 
7 #include <stddef.h>
8 
9 #include "base/check.h"
10 #include "base/stl_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "ui/aura/window.h"
13 #include "ui/events/test/event_generator.h"
14 #include "ui/gfx/geometry/insets.h"
15 #include "ui/views/controls/button/button.h"
16 #include "ui/views/layout/box_layout.h"
17 #include "ui/views/layout/fill_layout.h"
18 #include "ui/views/test/views_test_base.h"
19 #include "ui/views/widget/widget_delegate.h"
20 
21 namespace ui {
22 namespace ime {
23 namespace {
24 
25 const char* const kDummyCandidates[] = {
26     "candidate1",
27     "candidate2",
28     "candidate3",
29 };
30 
31 }  // namespace
32 
33 class CandidateViewTest : public views::ViewsTestBase {
34  public:
35   CandidateViewTest() = default;
36   ~CandidateViewTest() override = default;
37 
SetUp()38   void SetUp() override {
39     views::ViewsTestBase::SetUp();
40 
41     views::Widget::InitParams init_params(
42         CreateParams(views::Widget::InitParams::TYPE_WINDOW));
43 
44     init_params.delegate = new views::WidgetDelegateView();
45 
46     container_ = init_params.delegate->GetContentsView();
47     container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
48         views::BoxLayout::Orientation::kVertical));
49     for (size_t i = 0; i < base::size(kDummyCandidates); ++i) {
50       CandidateView* candidate = new CandidateView(
51           views::Button::PressedCallback(), ui::CandidateWindow::VERTICAL);
52       ui::CandidateWindow::Entry entry;
53       entry.value = base::UTF8ToUTF16(kDummyCandidates[i]);
54       candidate->SetEntry(entry);
55       container_->AddChildView(candidate);
56     }
57 
58     widget_ = new views::Widget();
59     widget_->Init(std::move(init_params));
60     widget_->Show();
61 
62     aura::Window* native_window = widget_->GetNativeWindow();
63     event_generator_ = std::make_unique<ui::test::EventGenerator>(
64         native_window->GetRootWindow(), native_window);
65   }
66 
TearDown()67   void TearDown() override {
68     widget_->Close();
69 
70     views::ViewsTestBase::TearDown();
71   }
72 
73  protected:
GetCandidateAt(size_t index)74   CandidateView* GetCandidateAt(size_t index) {
75     return static_cast<CandidateView*>(container_->children()[index]);
76   }
77 
GetHighlightedCount() const78   size_t GetHighlightedCount() const {
79     const auto& children = container_->children();
80     return std::count_if(
81         children.cbegin(), children.cend(),
82         [](const views::View* v) { return !!v->background(); });
83   }
84 
GetHighlightedIndex() const85   int GetHighlightedIndex() const {
86     const auto& children = container_->children();
87     const auto it =
88         std::find_if(children.cbegin(), children.cend(),
89                      [](const views::View* v) { return !!v->background(); });
90     return (it == children.cend()) ? -1 : std::distance(children.cbegin(), it);
91   }
92 
event_generator()93   ui::test::EventGenerator* event_generator() { return event_generator_.get(); }
94 
95  private:
96   views::Widget* widget_ = nullptr;
97   views::View* container_ = nullptr;
98   std::unique_ptr<ui::test::EventGenerator> event_generator_;
99 
100   DISALLOW_COPY_AND_ASSIGN(CandidateViewTest);
101 };
102 
TEST_F(CandidateViewTest,MouseHovers)103 TEST_F(CandidateViewTest, MouseHovers) {
104   GetCandidateAt(0)->SetHighlighted(true);
105 
106   EXPECT_EQ(1u, GetHighlightedCount());
107   EXPECT_EQ(0, GetHighlightedIndex());
108 
109   // Mouse hover shouldn't change the background.
110   event_generator()->MoveMouseTo(
111       GetCandidateAt(0)->GetBoundsInScreen().CenterPoint());
112   EXPECT_EQ(1u, GetHighlightedCount());
113   EXPECT_EQ(0, GetHighlightedIndex());
114 
115   // Mouse hover shouldn't change the background.
116   event_generator()->MoveMouseTo(
117       GetCandidateAt(1)->GetBoundsInScreen().CenterPoint());
118   EXPECT_EQ(1u, GetHighlightedCount());
119   EXPECT_EQ(0, GetHighlightedIndex());
120 
121   // Mouse hover shouldn't change the background.
122   event_generator()->MoveMouseTo(
123       GetCandidateAt(2)->GetBoundsInScreen().CenterPoint());
124   EXPECT_EQ(1u, GetHighlightedCount());
125   EXPECT_EQ(0, GetHighlightedIndex());
126 }
127 
TEST_F(CandidateViewTest,MouseClick)128 TEST_F(CandidateViewTest, MouseClick) {
129   bool clicked = false;
130   CandidateView* view = GetCandidateAt(1);
131   view->SetCallback(
132       base::BindRepeating([](bool* clicked) { *clicked = true; }, &clicked));
133   event_generator()->MoveMouseTo(view->GetBoundsInScreen().CenterPoint());
134   event_generator()->ClickLeftButton();
135   EXPECT_TRUE(clicked);
136 }
137 
TEST_F(CandidateViewTest,ClickAndMove)138 TEST_F(CandidateViewTest, ClickAndMove) {
139   GetCandidateAt(0)->SetHighlighted(true);
140 
141   EXPECT_EQ(1u, GetHighlightedCount());
142   EXPECT_EQ(0, GetHighlightedIndex());
143 
144   bool clicked = false;
145   CandidateView* view = GetCandidateAt(1);
146   view->SetCallback(
147       base::BindRepeating([](bool* clicked) { *clicked = true; }, &clicked));
148   event_generator()->MoveMouseTo(
149       GetCandidateAt(2)->GetBoundsInScreen().CenterPoint());
150   event_generator()->PressLeftButton();
151   EXPECT_EQ(1u, GetHighlightedCount());
152   EXPECT_EQ(2, GetHighlightedIndex());
153 
154   // Highlight follows the drag.
155   event_generator()->MoveMouseTo(view->GetBoundsInScreen().CenterPoint());
156   EXPECT_EQ(1u, GetHighlightedCount());
157   EXPECT_EQ(1, GetHighlightedIndex());
158 
159   event_generator()->MoveMouseTo(
160       GetCandidateAt(0)->GetBoundsInScreen().CenterPoint());
161   EXPECT_EQ(1u, GetHighlightedCount());
162   EXPECT_EQ(0, GetHighlightedIndex());
163 
164   event_generator()->MoveMouseTo(view->GetBoundsInScreen().CenterPoint());
165   EXPECT_EQ(1u, GetHighlightedCount());
166   EXPECT_EQ(1, GetHighlightedIndex());
167 
168   EXPECT_FALSE(clicked);
169   event_generator()->ReleaseLeftButton();
170   EXPECT_TRUE(clicked);
171 }
172 
173 }  // namespace ime
174 }  // namespace ui
175