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 "chrome/browser/chromeos/input_method/input_method_configuration.h"
10 #include "chrome/browser/chromeos/input_method/input_method_engine.h"
11 #include "chrome/browser/chromeos/input_method/input_method_engine_interface.h"
12 #include "chrome/browser/chromeos/input_method/mock_input_method_manager.h"
13 #include "chromeos/ime/extension_ime_util.h"
14 #include "chromeos/ime/mock_component_extension_ime_manager_delegate.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "ui/base/ime/chromeos/mock_ime_input_context_handler.h"
20 namespace input_method {
23 const char kTestExtensionId[] = "mppnpdlheglhdfmldimlhpnegondlapf";
24 const char kTestExtensionId2[] = "dmpipdbjkoajgdeppkffbjhngfckdloi";
25 const char kTestImeEngineId[] = "test_engine_id";
27 const char* kHistogramNames[] = {
28 "InputMethod.Enable.test_engine_id", "InputMethod.Commit.test_engine_id",
29 "InputMethod.CommitCharacter.test_engine_id",
32 scoped_ptr<base::HistogramSamples> GetHistogramSamples(
33 const char* histogram_name) {
34 base::HistogramBase* histogram =
35 base::StatisticsRecorder::FindHistogram(histogram_name);
36 EXPECT_NE(static_cast<base::HistogramBase*>(NULL), histogram);
37 return histogram->SnapshotSamples().Pass();
48 void InitInputMethod() {
49 ComponentExtensionIMEManager* comp_ime_manager =
50 new ComponentExtensionIMEManager;
51 MockComponentExtIMEManagerDelegate* delegate =
52 new MockComponentExtIMEManagerDelegate;
54 ComponentExtensionIME ext1;
55 ext1.id = kTestExtensionId;
57 ComponentExtensionEngine ext1_engine1;
58 ext1_engine1.engine_id = kTestImeEngineId;
59 ext1_engine1.language_codes.push_back("en-US");
60 ext1_engine1.layouts.push_back("us");
61 ext1.engines.push_back(ext1_engine1);
63 std::vector<ComponentExtensionIME> ime_list;
64 ime_list.push_back(ext1);
65 delegate->set_ime_list(ime_list);
66 comp_ime_manager->Initialize(
67 scoped_ptr<ComponentExtensionIMEManagerDelegate>(delegate).Pass());
69 MockInputMethodManager* manager = new MockInputMethodManager;
70 manager->SetComponentExtensionIMEManager(
71 scoped_ptr<ComponentExtensionIMEManager>(comp_ime_manager).Pass());
72 InitializeForTesting(manager);
75 class TestObserver : public InputMethodEngineInterface::Observer {
77 TestObserver() : calls_bitmap_(NONE) {}
78 virtual ~TestObserver() {}
80 virtual void OnActivate(const std::string& engine_id) OVERRIDE {
81 calls_bitmap_ |= ACTIVATE;
83 virtual void OnDeactivated(const std::string& engine_id) OVERRIDE {
84 calls_bitmap_ |= DEACTIVATED;
87 const InputMethodEngineInterface::InputContext& context) OVERRIDE {
88 calls_bitmap_ |= ONFOCUS;
90 virtual void OnBlur(int context_id) OVERRIDE {
91 calls_bitmap_ |= ONBLUR;
93 virtual void OnKeyEvent(
94 const std::string& engine_id,
95 const InputMethodEngineInterface::KeyboardEvent& event,
96 input_method::KeyEventHandle* key_data) OVERRIDE {}
97 virtual void OnInputContextUpdate(
98 const InputMethodEngineInterface::InputContext& context) OVERRIDE {}
99 virtual void OnCandidateClicked(
100 const std::string& engine_id,
102 InputMethodEngineInterface::MouseButtonEvent button) OVERRIDE {}
103 virtual void OnMenuItemActivated(
104 const std::string& engine_id,
105 const std::string& menu_id) OVERRIDE {}
106 virtual void OnSurroundingTextChanged(
107 const std::string& engine_id,
108 const std::string& text,
110 int anchor_pos) OVERRIDE {}
111 virtual void OnReset(const std::string& engine_id) OVERRIDE {}
113 unsigned char GetCallsBitmapAndReset() {
114 unsigned char ret = calls_bitmap_;
115 calls_bitmap_ = NONE;
120 unsigned char calls_bitmap_;
122 DISALLOW_COPY_AND_ASSIGN(TestObserver);
125 class InputMethodEngineTest : public testing::Test {
127 InputMethodEngineTest() : observer_(NULL), input_view_("inputview.html") {
128 languages_.push_back("en-US");
129 layouts_.push_back("us");
131 IMEBridge::Initialize();
132 mock_ime_input_context_handler_.reset(new MockIMEInputContextHandler());
133 IMEBridge::Get()->SetInputContextHandler(
134 mock_ime_input_context_handler_.get());
136 base::StatisticsRecorder::Initialize();
138 for (size_t i = 0; i < arraysize(kHistogramNames); i++) {
139 base::Histogram::FactoryGet(
140 kHistogramNames[i], 0, 1000000, 50, base::HistogramBase::kNoFlags)
142 initial_histogram_samples_[i] =
143 GetHistogramSamples(kHistogramNames[i]).Pass();
144 initial_histogram_samples_map_[kHistogramNames[i]] =
145 initial_histogram_samples_[i].get();
148 virtual ~InputMethodEngineTest() {
149 IMEBridge::Get()->SetInputContextHandler(NULL);
155 scoped_ptr<base::HistogramSamples> GetHistogramSamplesDelta(
156 const char* histogram_name) {
157 scoped_ptr<base::HistogramSamples> delta_samples(
158 GetHistogramSamples(histogram_name));
159 delta_samples->Subtract(*initial_histogram_samples_map_[histogram_name]);
161 return delta_samples.Pass();
164 void ExpectNewSample(const char* histogram_name,
165 base::HistogramBase::Sample sample,
168 scoped_ptr<base::HistogramSamples> delta_samples(
169 GetHistogramSamplesDelta(histogram_name));
170 EXPECT_EQ(total_count, delta_samples->TotalCount());
171 EXPECT_EQ(sample_count, delta_samples->GetCount(sample));
174 void CreateEngine(bool whitelisted) {
175 engine_.reset(new InputMethodEngine());
176 observer_ = new TestObserver();
177 scoped_ptr<InputMethodEngineInterface::Observer> observer_ptr(observer_);
178 engine_->Initialize(observer_ptr.Pass(),
180 whitelisted ? kTestExtensionId : kTestExtensionId2,
188 void FocusIn(ui::TextInputType input_type) {
189 IMEEngineHandlerInterface::InputContext input_context(
190 input_type, ui::TEXT_INPUT_MODE_DEFAULT);
191 engine_->FocusIn(input_context);
192 IMEBridge::Get()->SetCurrentTextInputType(input_type);
195 scoped_ptr<InputMethodEngine> engine_;
197 TestObserver* observer_;
198 std::vector<std::string> languages_;
199 std::vector<std::string> layouts_;
203 scoped_ptr<base::HistogramSamples>
204 initial_histogram_samples_[arraysize(kHistogramNames)];
205 std::map<std::string, base::HistogramSamples*> initial_histogram_samples_map_;
207 scoped_ptr<MockIMEInputContextHandler> mock_ime_input_context_handler_;
210 DISALLOW_COPY_AND_ASSIGN(InputMethodEngineTest);
215 TEST_F(InputMethodEngineTest, TestSwitching) {
217 // Enable/disable with focus.
218 FocusIn(ui::TEXT_INPUT_TYPE_URL);
219 EXPECT_EQ(NONE, observer_->GetCallsBitmapAndReset());
221 EXPECT_EQ(ACTIVATE | ONFOCUS, observer_->GetCallsBitmapAndReset());
223 EXPECT_EQ(DEACTIVATED, observer_->GetCallsBitmapAndReset());
224 // Enable/disable without focus.
226 EXPECT_EQ(NONE, observer_->GetCallsBitmapAndReset());
228 EXPECT_EQ(ACTIVATE | ONFOCUS, observer_->GetCallsBitmapAndReset());
230 EXPECT_EQ(DEACTIVATED, observer_->GetCallsBitmapAndReset());
231 // Focus change when enabled.
233 EXPECT_EQ(ACTIVATE | ONFOCUS, observer_->GetCallsBitmapAndReset());
235 EXPECT_EQ(ONBLUR, observer_->GetCallsBitmapAndReset());
236 // Focus change when disabled.
238 EXPECT_EQ(DEACTIVATED, observer_->GetCallsBitmapAndReset());
239 FocusIn(ui::TEXT_INPUT_TYPE_TEXT);
240 EXPECT_EQ(NONE, observer_->GetCallsBitmapAndReset());
242 EXPECT_EQ(NONE, observer_->GetCallsBitmapAndReset());
245 TEST_F(InputMethodEngineTest, TestSwitching_Password_3rd_Party) {
247 // Enable/disable with focus.
248 FocusIn(ui::TEXT_INPUT_TYPE_PASSWORD);
249 EXPECT_EQ(NONE, observer_->GetCallsBitmapAndReset());
251 EXPECT_EQ(ACTIVATE, observer_->GetCallsBitmapAndReset());
253 EXPECT_EQ(DEACTIVATED, observer_->GetCallsBitmapAndReset());
254 // Focus change when enabled.
256 EXPECT_EQ(ACTIVATE, observer_->GetCallsBitmapAndReset());
258 EXPECT_EQ(NONE, observer_->GetCallsBitmapAndReset());
259 FocusIn(ui::TEXT_INPUT_TYPE_PASSWORD);
260 EXPECT_EQ(NONE, observer_->GetCallsBitmapAndReset());
262 EXPECT_EQ(DEACTIVATED, observer_->GetCallsBitmapAndReset());
265 TEST_F(InputMethodEngineTest, TestSwitching_Password_Whitelisted) {
267 // Enable/disable with focus.
268 FocusIn(ui::TEXT_INPUT_TYPE_PASSWORD);
269 EXPECT_EQ(NONE, observer_->GetCallsBitmapAndReset());
271 EXPECT_EQ(ACTIVATE | ONFOCUS, observer_->GetCallsBitmapAndReset());
273 EXPECT_EQ(DEACTIVATED, observer_->GetCallsBitmapAndReset());
274 // Focus change when enabled.
276 EXPECT_EQ(ACTIVATE | ONFOCUS, observer_->GetCallsBitmapAndReset());
278 EXPECT_EQ(ONBLUR, observer_->GetCallsBitmapAndReset());
279 FocusIn(ui::TEXT_INPUT_TYPE_PASSWORD);
280 EXPECT_EQ(ONFOCUS, observer_->GetCallsBitmapAndReset());
282 EXPECT_EQ(DEACTIVATED, observer_->GetCallsBitmapAndReset());
285 TEST_F(InputMethodEngineTest, TestHistograms) {
287 FocusIn(ui::TEXT_INPUT_TYPE_TEXT);
290 ExpectNewSample("InputMethod.Enable.test_engine_id", 1, 1, 1);
291 engine_->CommitText(1, "input", &error);
292 engine_->CommitText(1, "入力", &error);
293 engine_->CommitText(1, "input入力", &error);
294 ExpectNewSample("InputMethod.Commit.test_engine_id", 1, 3, 3);
295 ExpectNewSample("InputMethod.CommitCharacter.test_engine_id", 5, 3, 1);
296 ExpectNewSample("InputMethod.CommitCharacter.test_engine_id", 2, 3, 1);
297 ExpectNewSample("InputMethod.CommitCharacter.test_engine_id", 7, 3, 1);
300 } // namespace input_method
301 } // namespace chromeos