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 "base/logging.h"
6 #include "base/metrics/histogram.h"
7 #include "base/metrics/histogram_samples.h"
8 #include "base/metrics/statistics_recorder.h"
9 #include "base/test/histogram_tester.h"
10 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
11 #include "chrome/browser/chromeos/input_method/input_method_engine.h"
12 #include "chrome/browser/chromeos/input_method/input_method_engine_interface.h"
13 #include "chrome/browser/chromeos/input_method/mock_input_method_manager.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "ui/base/ime/chromeos/extension_ime_util.h"
17 #include "ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h"
18 #include "ui/base/ime/chromeos/mock_ime_input_context_handler.h"
19 #include "ui/base/ime/text_input_flags.h"
20 #include "ui/gfx/geometry/rect.h"
24 namespace input_method
{
27 const char kTestExtensionId
[] = "mppnpdlheglhdfmldimlhpnegondlapf";
28 const char kTestExtensionId2
[] = "dmpipdbjkoajgdeppkffbjhngfckdloi";
29 const char kTestImeComponentId
[] = "test_engine_id";
37 ONCOMPOSITIONBOUNDSCHANGED
= 16U
40 void InitInputMethod() {
41 ComponentExtensionIMEManager
* comp_ime_manager
=
42 new ComponentExtensionIMEManager
;
43 MockComponentExtIMEManagerDelegate
* delegate
=
44 new MockComponentExtIMEManagerDelegate
;
46 ComponentExtensionIME ext1
;
47 ext1
.id
= kTestExtensionId
;
49 ComponentExtensionEngine ext1_engine1
;
50 ext1_engine1
.engine_id
= kTestImeComponentId
;
51 ext1_engine1
.language_codes
.push_back("en-US");
52 ext1_engine1
.layouts
.push_back("us");
53 ext1
.engines
.push_back(ext1_engine1
);
55 std::vector
<ComponentExtensionIME
> ime_list
;
56 ime_list
.push_back(ext1
);
57 delegate
->set_ime_list(ime_list
);
58 comp_ime_manager
->Initialize(
59 scoped_ptr
<ComponentExtensionIMEManagerDelegate
>(delegate
).Pass());
61 MockInputMethodManager
* manager
= new MockInputMethodManager
;
62 manager
->SetComponentExtensionIMEManager(
63 scoped_ptr
<ComponentExtensionIMEManager
>(comp_ime_manager
).Pass());
64 InitializeForTesting(manager
);
67 class TestObserver
: public InputMethodEngineInterface::Observer
{
69 TestObserver() : calls_bitmap_(NONE
) {}
70 ~TestObserver() override
{}
72 void OnActivate(const std::string
& engine_id
) override
{
73 calls_bitmap_
|= ACTIVATE
;
75 void OnDeactivated(const std::string
& engine_id
) override
{
76 calls_bitmap_
|= DEACTIVATED
;
79 const InputMethodEngineInterface::InputContext
& context
) override
{
80 calls_bitmap_
|= ONFOCUS
;
82 void OnBlur(int context_id
) override
{ calls_bitmap_
|= ONBLUR
; }
83 bool IsInterestedInKeyEvent() const override
{ return true; }
84 void OnKeyEvent(const std::string
& engine_id
,
85 const InputMethodEngineInterface::KeyboardEvent
& event
,
86 input_method::KeyEventHandle
* key_data
) override
{}
87 void OnInputContextUpdate(
88 const InputMethodEngineInterface::InputContext
& context
) override
{}
89 void OnCandidateClicked(
90 const std::string
& engine_id
,
92 InputMethodEngineInterface::MouseButtonEvent button
) override
{}
93 void OnMenuItemActivated(const std::string
& engine_id
,
94 const std::string
& menu_id
) override
{}
95 void OnSurroundingTextChanged(const std::string
& engine_id
,
96 const std::string
& text
,
99 int offset
) override
{}
100 void OnCompositionBoundsChanged(
101 const std::vector
<gfx::Rect
>& bounds
) override
{
102 calls_bitmap_
|= ONCOMPOSITIONBOUNDSCHANGED
;
104 void OnReset(const std::string
& engine_id
) override
{}
106 unsigned char GetCallsBitmapAndReset() {
107 unsigned char ret
= calls_bitmap_
;
108 calls_bitmap_
= NONE
;
113 unsigned char calls_bitmap_
;
115 DISALLOW_COPY_AND_ASSIGN(TestObserver
);
118 class InputMethodEngineTest
: public testing::Test
{
120 InputMethodEngineTest() : observer_(NULL
), input_view_("inputview.html") {
121 languages_
.push_back("en-US");
122 layouts_
.push_back("us");
124 IMEBridge::Initialize();
125 mock_ime_input_context_handler_
.reset(new MockIMEInputContextHandler());
126 IMEBridge::Get()->SetInputContextHandler(
127 mock_ime_input_context_handler_
.get());
129 ~InputMethodEngineTest() override
{
130 IMEBridge::Get()->SetInputContextHandler(NULL
);
136 void CreateEngine(bool whitelisted
) {
137 engine_
.reset(new InputMethodEngine());
138 observer_
= new TestObserver();
139 scoped_ptr
<InputMethodEngineInterface::Observer
> observer_ptr(observer_
);
140 engine_
->Initialize(observer_ptr
.Pass(),
141 whitelisted
? kTestExtensionId
: kTestExtensionId2
,
142 ProfileManager::GetActiveUserProfile());
145 void FocusIn(ui::TextInputType input_type
) {
146 IMEEngineHandlerInterface::InputContext
input_context(
147 input_type
, ui::TEXT_INPUT_MODE_DEFAULT
, ui::TEXT_INPUT_FLAG_NONE
);
148 engine_
->FocusIn(input_context
);
149 IMEBridge::Get()->SetCurrentInputContext(input_context
);
152 scoped_ptr
<InputMethodEngine
> engine_
;
154 TestObserver
* observer_
;
155 std::vector
<std::string
> languages_
;
156 std::vector
<std::string
> layouts_
;
160 scoped_ptr
<MockIMEInputContextHandler
> mock_ime_input_context_handler_
;
163 DISALLOW_COPY_AND_ASSIGN(InputMethodEngineTest
);
168 TEST_F(InputMethodEngineTest
, TestSwitching
) {
170 // Enable/disable with focus.
171 FocusIn(ui::TEXT_INPUT_TYPE_URL
);
172 EXPECT_EQ(NONE
, observer_
->GetCallsBitmapAndReset());
173 engine_
->Enable(kTestImeComponentId
);
174 EXPECT_EQ(ACTIVATE
| ONFOCUS
, observer_
->GetCallsBitmapAndReset());
176 EXPECT_EQ(DEACTIVATED
, observer_
->GetCallsBitmapAndReset());
177 // Enable/disable without focus.
179 EXPECT_EQ(NONE
, observer_
->GetCallsBitmapAndReset());
180 engine_
->Enable(kTestImeComponentId
);
181 EXPECT_EQ(ACTIVATE
| ONFOCUS
, observer_
->GetCallsBitmapAndReset());
183 EXPECT_EQ(DEACTIVATED
, observer_
->GetCallsBitmapAndReset());
184 // Focus change when enabled.
185 engine_
->Enable(kTestImeComponentId
);
186 EXPECT_EQ(ACTIVATE
| ONFOCUS
, observer_
->GetCallsBitmapAndReset());
188 EXPECT_EQ(ONBLUR
, observer_
->GetCallsBitmapAndReset());
189 // Focus change when disabled.
191 EXPECT_EQ(DEACTIVATED
, observer_
->GetCallsBitmapAndReset());
192 FocusIn(ui::TEXT_INPUT_TYPE_TEXT
);
193 EXPECT_EQ(NONE
, observer_
->GetCallsBitmapAndReset());
195 EXPECT_EQ(NONE
, observer_
->GetCallsBitmapAndReset());
198 TEST_F(InputMethodEngineTest
, TestSwitching_Password_3rd_Party
) {
200 // Enable/disable with focus.
201 FocusIn(ui::TEXT_INPUT_TYPE_PASSWORD
);
202 EXPECT_EQ(NONE
, observer_
->GetCallsBitmapAndReset());
203 engine_
->Enable(kTestImeComponentId
);
204 EXPECT_EQ(ACTIVATE
| ONFOCUS
, observer_
->GetCallsBitmapAndReset());
206 EXPECT_EQ(DEACTIVATED
, observer_
->GetCallsBitmapAndReset());
207 // Focus change when enabled.
208 engine_
->Enable(kTestImeComponentId
);
209 EXPECT_EQ(ACTIVATE
| ONFOCUS
, observer_
->GetCallsBitmapAndReset());
211 EXPECT_EQ(ONBLUR
, observer_
->GetCallsBitmapAndReset());
212 FocusIn(ui::TEXT_INPUT_TYPE_PASSWORD
);
213 EXPECT_EQ(ONFOCUS
, observer_
->GetCallsBitmapAndReset());
215 EXPECT_EQ(DEACTIVATED
, observer_
->GetCallsBitmapAndReset());
218 TEST_F(InputMethodEngineTest
, TestSwitching_Password_Whitelisted
) {
220 // Enable/disable with focus.
221 FocusIn(ui::TEXT_INPUT_TYPE_PASSWORD
);
222 EXPECT_EQ(NONE
, observer_
->GetCallsBitmapAndReset());
223 engine_
->Enable(kTestImeComponentId
);
224 EXPECT_EQ(ACTIVATE
| ONFOCUS
, observer_
->GetCallsBitmapAndReset());
226 EXPECT_EQ(DEACTIVATED
, observer_
->GetCallsBitmapAndReset());
227 // Focus change when enabled.
228 engine_
->Enable(kTestImeComponentId
);
229 EXPECT_EQ(ACTIVATE
| ONFOCUS
, observer_
->GetCallsBitmapAndReset());
231 EXPECT_EQ(ONBLUR
, observer_
->GetCallsBitmapAndReset());
232 FocusIn(ui::TEXT_INPUT_TYPE_PASSWORD
);
233 EXPECT_EQ(ONFOCUS
, observer_
->GetCallsBitmapAndReset());
235 EXPECT_EQ(DEACTIVATED
, observer_
->GetCallsBitmapAndReset());
238 TEST_F(InputMethodEngineTest
, TestHistograms
) {
240 FocusIn(ui::TEXT_INPUT_TYPE_TEXT
);
241 engine_
->Enable(kTestImeComponentId
);
242 std::vector
<InputMethodEngineInterface::SegmentInfo
> segments
;
243 int context
= engine_
->GetCotextIdForTesting();
245 base::HistogramTester histograms
;
246 engine_
->SetComposition(context
, "test", 0, 0, 0, segments
, NULL
);
247 engine_
->CommitText(context
, "input", &error
);
248 engine_
->SetComposition(context
, "test", 0, 0, 0, segments
, NULL
);
249 engine_
->CommitText(context
,
250 "\xE5\x85\xA5\xE5\x8A\x9B", // 2 UTF-8 characters
252 engine_
->SetComposition(context
, "test", 0, 0, 0, segments
, NULL
);
253 engine_
->CommitText(context
, "input\xE5\x85\xA5\xE5\x8A\x9B", &error
);
254 histograms
.ExpectTotalCount("InputMethod.CommitLength", 3);
255 histograms
.ExpectBucketCount("InputMethod.CommitLength", 5, 1);
256 histograms
.ExpectBucketCount("InputMethod.CommitLength", 2, 1);
257 histograms
.ExpectBucketCount("InputMethod.CommitLength", 7, 1);
260 TEST_F(InputMethodEngineTest
, TestCompositionBoundsChanged
) {
262 // Enable/disable with focus.
263 std::vector
<gfx::Rect
> rects
;
264 rects
.push_back(gfx::Rect());
265 engine_
->SetCompositionBounds(rects
);
266 EXPECT_EQ(ONCOMPOSITIONBOUNDSCHANGED
,
267 observer_
->GetCallsBitmapAndReset());
270 } // namespace input_method
271 } // namespace chromeos