1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "session/session_usage_observer.h"
31
32 #include <memory>
33 #include <string>
34
35 #include "base/clock.h"
36 #include "base/clock_mock.h"
37 #include "base/logging.h"
38 #include "base/scheduler.h"
39 #include "base/scheduler_stub.h"
40 #include "base/system_util.h"
41 #include "base/util.h"
42 #include "config/stats_config_util.h"
43 #include "config/stats_config_util_mock.h"
44 #include "protocol/commands.pb.h"
45 #include "testing/base/public/googletest.h"
46 #include "testing/base/public/gunit.h"
47 #include "usage_stats/usage_stats.h"
48 #include "usage_stats/usage_stats.pb.h"
49 #include "usage_stats/usage_stats_testing_util.h"
50
51 using mozc::usage_stats::Stats;
52 using mozc::usage_stats::UsageStats;
53
54 DECLARE_string(test_tmpdir);
55
56 namespace mozc {
57 namespace session {
58
59 class SessionUsageObserverTest : public testing::Test {
60 protected:
SetUp()61 virtual void SetUp() {
62 SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir);
63 UsageStats::ClearAllStatsForTest();
64
65 Clock::SetClockForUnitTest(nullptr);
66
67 scheduler_stub_.reset(new SchedulerStub);
68 Scheduler::SetSchedulerHandler(scheduler_stub_.get());
69
70 stats_config_util_mock_.reset(new config::StatsConfigUtilMock);
71 config::StatsConfigUtil::SetHandler(stats_config_util_mock_.get());
72 }
73
TearDown()74 virtual void TearDown() {
75 Clock::SetClockForUnitTest(nullptr);
76 Scheduler::SetSchedulerHandler(nullptr);
77 config::StatsConfigUtil::SetHandler(nullptr);
78
79 UsageStats::ClearAllStatsForTest();
80 }
81
EnsureSave() const82 void EnsureSave() const {
83 // Make sure to save stats.
84 const uint32 kWaitngUsecForEnsureSave = 10 * 60 * 1000;
85 scheduler_stub_->PutClockForward(kWaitngUsecForEnsureSave);
86 }
87
SetDoubleValueStats(uint32 num,double total,double square_total,Stats::DoubleValueStats * double_stats)88 void SetDoubleValueStats(
89 uint32 num, double total, double square_total,
90 Stats::DoubleValueStats *double_stats) {
91 DCHECK(double_stats);
92 double_stats->set_num(num);
93 double_stats->set_total(total);
94 double_stats->set_square_total(square_total);
95 }
96
SetEventStats(uint32 source_id,uint32 sx_num,double sx_total,double sx_square_total,uint32 sy_num,double sy_total,double sy_square_total,uint32 dx_num,double dx_total,double dx_square_total,uint32 dy_num,double dy_total,double dy_square_total,uint32 tl_num,double tl_total,double tl_square_total,Stats::TouchEventStats * event_stats)97 void SetEventStats(
98 uint32 source_id,
99 uint32 sx_num, double sx_total, double sx_square_total,
100 uint32 sy_num, double sy_total, double sy_square_total,
101 uint32 dx_num, double dx_total, double dx_square_total,
102 uint32 dy_num, double dy_total, double dy_square_total,
103 uint32 tl_num, double tl_total, double tl_square_total,
104 Stats::TouchEventStats *event_stats) {
105 event_stats->set_source_id(source_id);
106 SetDoubleValueStats(sx_num, sx_total, sx_square_total,
107 event_stats->mutable_start_x_stats());
108 SetDoubleValueStats(sy_num, sy_total, sy_square_total,
109 event_stats->mutable_start_y_stats());
110 SetDoubleValueStats(dx_num, dx_total, dx_square_total,
111 event_stats->mutable_direction_x_stats());
112 SetDoubleValueStats(dy_num, dy_total, dy_square_total,
113 event_stats->mutable_direction_y_stats());
114 SetDoubleValueStats(tl_num, tl_total, tl_square_total,
115 event_stats->mutable_time_length_stats());
116 }
117
118 std::unique_ptr<SchedulerStub> scheduler_stub_;
119 std::unique_ptr<config::StatsConfigUtilMock> stats_config_util_mock_;
120 };
121
TEST_F(SessionUsageObserverTest,DoNotSaveWhenDeleted)122 TEST_F(SessionUsageObserverTest, DoNotSaveWhenDeleted) {
123 stats_config_util_mock_->SetEnabled(false);
124
125 std::unique_ptr<SessionUsageObserver> observer(new SessionUsageObserver);
126
127 // Add command
128 commands::Command command;
129 command.mutable_input()->set_type(commands::Input::NONE);
130 command.mutable_input()->set_id(0);
131 command.mutable_output()->set_consumed(true);
132 for (int i = 0; i < 5; ++i) {
133 observer->EvalCommandHandler(command);
134 EXPECT_STATS_NOT_EXIST("SessionAllEvent");
135 }
136
137 observer.reset();
138 EXPECT_STATS_NOT_EXIST("SessionAllEvent");
139 }
140
TEST_F(SessionUsageObserverTest,ClientSideStatsInfolist)141 TEST_F(SessionUsageObserverTest, ClientSideStatsInfolist) {
142 std::unique_ptr<SessionUsageObserver> observer(new SessionUsageObserver);
143
144 // create session
145 {
146 commands::Command command;
147 command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
148 command.mutable_input()->set_id(1);
149 command.mutable_output()->set_id(1);
150 observer->EvalCommandHandler(command);
151 }
152
153 const uint64 kSeconds = 0;
154 const uint32 kMicroSeconds = 0;
155 ClockMock clock(kSeconds, kMicroSeconds);
156 Clock::SetClockForUnitTest(&clock);
157
158 // prepare command
159 commands::Command orig_show_command, orig_hide_command;
160 orig_show_command.mutable_input()->set_type(commands::Input::SEND_COMMAND);
161 orig_show_command.mutable_input()->set_id(1);
162 orig_show_command.mutable_input()->mutable_command()->set_type(
163 commands::SessionCommand::USAGE_STATS_EVENT);
164 orig_show_command.mutable_input()->mutable_command()->set_usage_stats_event(
165 commands::SessionCommand::INFOLIST_WINDOW_SHOW);
166 orig_show_command.mutable_output()->set_consumed(false);
167 EXPECT_TRUE(orig_show_command.output().has_consumed());
168 EXPECT_FALSE(orig_show_command.output().consumed());
169 EXPECT_TRUE(orig_show_command.input().has_id());
170 orig_hide_command.CopyFrom(orig_show_command);
171 orig_hide_command.mutable_input()->mutable_command()->set_usage_stats_event(
172 commands::SessionCommand::INFOLIST_WINDOW_HIDE);
173
174 { // show infolist, wait 1,100,000 usec and hide infolist.
175 commands::Command show_command, hide_command;
176 show_command.CopyFrom(orig_show_command);
177 hide_command.CopyFrom(orig_hide_command);
178
179 observer->EvalCommandHandler(show_command);
180 EXPECT_STATS_NOT_EXIST("InfolistWindowDurationMSec");
181 clock.PutClockForward(1, 100000);
182 observer->EvalCommandHandler(hide_command);
183 EXPECT_TIMING_STATS("InfolistWindowDurationMSec", 1100, 1, 1100, 1100);
184 }
185
186 { // show infolist, wait 1,200,000 usec and hide infolist.
187 commands::Command show_command, hide_command;
188 show_command.CopyFrom(orig_show_command);
189 hide_command.CopyFrom(orig_hide_command);
190
191 observer->EvalCommandHandler(show_command);
192 clock.PutClockForward(1, 200000);
193 observer->EvalCommandHandler(hide_command);
194 EXPECT_TIMING_STATS("InfolistWindowDurationMSec", 2300, 2, 1100, 1200);
195 }
196 }
197
TEST_F(SessionUsageObserverTest,ClientSideStatsSoftwareKeyboardLayout)198 TEST_F(SessionUsageObserverTest, ClientSideStatsSoftwareKeyboardLayout) {
199 SessionUsageObserver observer;
200
201 // create session
202 commands::Command command;
203 command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
204 command.mutable_input()->set_id(1);
205 command.mutable_output()->set_id(1);
206 observer.EvalCommandHandler(command);
207
208 EXPECT_STATS_NOT_EXIST("SoftwareKeyboardLayoutLandscape");
209 EXPECT_STATS_NOT_EXIST("SoftwareKeyboardLayoutPortrait");
210
211 command.mutable_input()->set_type(commands::Input::SEND_COMMAND);
212 commands::SessionCommand *session_command =
213 command.mutable_input()->mutable_command();
214 session_command->set_type(commands::SessionCommand::USAGE_STATS_EVENT);
215 session_command->set_usage_stats_event(
216 commands::SessionCommand::SOFTWARE_KEYBOARD_LAYOUT_LANDSCAPE);
217 session_command->set_usage_stats_event_int_value(1);
218 observer.EvalCommandHandler(command);
219 EXPECT_INTEGER_STATS("SoftwareKeyboardLayoutLandscape", 1);
220 EXPECT_STATS_NOT_EXIST("SoftwareKeyboardLayoutPortrait");
221
222 session_command->set_usage_stats_event_int_value(2);
223 observer.EvalCommandHandler(command);
224 EXPECT_INTEGER_STATS("SoftwareKeyboardLayoutLandscape", 2);
225 EXPECT_STATS_NOT_EXIST("SoftwareKeyboardLayoutPortrait");
226
227 session_command->set_usage_stats_event(
228 commands::SessionCommand::SOFTWARE_KEYBOARD_LAYOUT_PORTRAIT);
229 session_command->set_usage_stats_event_int_value(3);
230 observer.EvalCommandHandler(command);
231 EXPECT_INTEGER_STATS("SoftwareKeyboardLayoutLandscape", 2);
232 EXPECT_INTEGER_STATS("SoftwareKeyboardLayoutPortrait", 3);
233 }
234
TEST_F(SessionUsageObserverTest,SubmittedCandidateRow)235 TEST_F(SessionUsageObserverTest, SubmittedCandidateRow) {
236 SessionUsageObserver observer;
237
238 // create session
239 commands::Command command;
240 command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
241 command.mutable_input()->set_id(1);
242 command.mutable_output()->set_id(1);
243 observer.EvalCommandHandler(command);
244
245 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow0");
246 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow1");
247 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow2");
248 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow3");
249 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow4");
250 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow5");
251 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow6");
252 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow7");
253 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow8");
254 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow9");
255 EXPECT_STATS_NOT_EXIST("SubmittedCandidateRowGE10");
256
257 command.mutable_input()->set_type(commands::Input::SEND_COMMAND);
258 commands::SessionCommand *session_command =
259 command.mutable_input()->mutable_command();
260 session_command->set_type(commands::SessionCommand::USAGE_STATS_EVENT);
261 session_command->set_usage_stats_event(
262 commands::SessionCommand::SUBMITTED_CANDIDATE_ROW_0);
263 observer.EvalCommandHandler(command);
264 EXPECT_COUNT_STATS("SubmittedCandidateRow0", 1);
265
266 observer.EvalCommandHandler(command);
267 EXPECT_COUNT_STATS("SubmittedCandidateRow0", 2);
268 }
269
TEST_F(SessionUsageObserverTest,LogTouchEvent)270 TEST_F(SessionUsageObserverTest, LogTouchEvent) {
271 std::unique_ptr<SessionUsageObserver> observer(new SessionUsageObserver);
272
273 // create session
274 {
275 commands::Command command;
276 command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
277 command.mutable_input()->set_id(1);
278 command.mutable_output()->set_id(1);
279 observer->EvalCommandHandler(command);
280 }
281 // set keyboard
282 {
283 commands::Command command;
284 command.mutable_input()->set_type(commands::Input::SET_REQUEST);
285 command.mutable_input()->set_id(1);
286 command.mutable_input()->mutable_request()->set_keyboard_name("KB1");
287 observer->EvalCommandHandler(command);
288 }
289 {
290 commands::Command command;
291 command.mutable_input()->set_type(commands::Input::SEND_KEY);
292 command.mutable_input()->set_id(1);
293 commands::Input::TouchEvent *touch_event =
294 command.mutable_input()->add_touch_events();
295 touch_event->set_source_id(10);
296 commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
297 pos1->set_action(commands::Input::TOUCH_DOWN);
298 pos1->set_x(1);
299 pos1->set_y(2);
300 pos1->set_timestamp(0);
301 commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
302 pos2->set_action(commands::Input::TOUCH_UP);
303 pos2->set_x(2);
304 pos2->set_y(1);
305 pos2->set_timestamp(1500);
306 observer->EvalCommandHandler(command);
307 }
308 {
309 commands::Command command;
310 command.mutable_input()->set_type(commands::Input::SEND_KEY);
311 command.mutable_input()->set_id(1);
312 commands::Input::TouchEvent *touch_event =
313 command.mutable_input()->add_touch_events();
314 touch_event->set_source_id(10);
315 commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
316 pos1->set_action(commands::Input::TOUCH_DOWN);
317 pos1->set_x(2);
318 pos1->set_y(2);
319 pos1->set_timestamp(0);
320 commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
321 pos2->set_action(commands::Input::TOUCH_MOVE);
322 pos2->set_x(2);
323 pos2->set_y(2);
324 pos2->set_timestamp(1000);
325 commands::Input::TouchPosition *pos3 = touch_event->add_stroke();
326 pos3->set_action(commands::Input::TOUCH_MOVE);
327 pos3->set_x(1);
328 pos3->set_y(1);
329 pos3->set_timestamp(2000);
330 observer->EvalCommandHandler(command);
331 }
332 // change keyboard
333 {
334 commands::Command command;
335 command.mutable_input()->set_type(commands::Input::SET_REQUEST);
336 command.mutable_input()->set_id(1);
337 command.mutable_input()->mutable_request()->set_keyboard_name("KB2");
338 commands::Input::TouchEvent *touch_event =
339 command.mutable_input()->add_touch_events();
340 touch_event->set_source_id(100);
341 commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
342 pos1->set_action(commands::Input::TOUCH_DOWN);
343 pos1->set_x(1);
344 pos1->set_y(1);
345 pos1->set_timestamp(0);
346 commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
347 pos2->set_action(commands::Input::TOUCH_UP);
348 pos2->set_x(1);
349 pos2->set_y(1);
350 pos2->set_timestamp(1000);
351 observer->EvalCommandHandler(command);
352 }
353 {
354 commands::Command command;
355 command.mutable_input()->set_type(commands::Input::SEND_KEY);
356 command.mutable_input()->set_id(1);
357 commands::Input::TouchEvent *touch_event =
358 command.mutable_input()->add_touch_events();
359 touch_event->set_source_id(10);
360 commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
361 pos1->set_action(commands::Input::TOUCH_DOWN);
362 pos1->set_x(1);
363 pos1->set_y(2);
364 pos1->set_timestamp(0);
365 commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
366 pos2->set_action(commands::Input::TOUCH_UP);
367 pos2->set_x(2);
368 pos2->set_y(1);
369 pos2->set_timestamp(1500);
370 observer->EvalCommandHandler(command);
371 }
372 {
373 commands::Command command;
374 command.mutable_input()->set_type(commands::Input::SEND_KEY);
375 command.mutable_input()->set_id(1);
376 commands::Input::TouchEvent *touch_event =
377 command.mutable_input()->add_touch_events();
378 touch_event->set_source_id(20);
379 commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
380 pos1->set_action(commands::Input::TOUCH_DOWN);
381 pos1->set_x(2);
382 pos1->set_y(2);
383 pos1->set_timestamp(0);
384 commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
385 pos2->set_action(commands::Input::TOUCH_UP);
386 pos2->set_x(1);
387 pos2->set_y(1);
388 pos2->set_timestamp(2000);
389
390 // add preedit
391 command.mutable_output()->mutable_preedit();
392 command.mutable_output()->set_consumed(true);
393 observer->EvalCommandHandler(command);
394 }
395 {
396 // send BACKSPACE
397 commands::Command command;
398 command.mutable_input()->set_type(commands::Input::SEND_KEY);
399 command.mutable_input()->set_id(1);
400 command.mutable_input()->mutable_key()->set_special_key(
401 commands::KeyEvent::BACKSPACE);
402 observer->EvalCommandHandler(command);
403 }
404 {
405 commands::Command command;
406 command.mutable_input()->set_type(commands::Input::SEND_KEY);
407 command.mutable_input()->set_id(1);
408 commands::Input::TouchEvent *touch_event =
409 command.mutable_input()->add_touch_events();
410 touch_event->set_source_id(30);
411 commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
412 pos1->set_action(commands::Input::TOUCH_DOWN);
413 pos1->set_x(2);
414 pos1->set_y(2);
415 pos1->set_timestamp(0);
416 commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
417 pos2->set_action(commands::Input::TOUCH_MOVE);
418 pos2->set_x(1);
419 pos2->set_y(1);
420 pos2->set_timestamp(1000);
421 commands::Input::TouchPosition *pos3 = touch_event->add_stroke();
422 pos3->set_action(commands::Input::TOUCH_UP);
423 pos3->set_x(1);
424 pos3->set_y(3);
425 pos3->set_timestamp(2000);
426 observer->EvalCommandHandler(command);
427 }
428 {
429 commands::Command command;
430 command.mutable_input()->set_type(commands::Input::NONE);
431 command.mutable_input()->set_id(1);
432 observer->EvalCommandHandler(command);
433 }
434
435 EXPECT_STATS_NOT_EXIST("VirtualKeyboardStats");
436 EXPECT_STATS_NOT_EXIST("VirtualKeyboardMissStats");
437 EnsureSave();
438
439 {
440 Stats stats;
441 UsageStats::GetVirtualKeyboardForTest("VirtualKeyboardStats", &stats);
442 ASSERT_EQ(2, stats.virtual_keyboard_stats_size());
443 ASSERT_EQ(2, stats.virtual_keyboard_stats(0).touch_event_stats_size());
444
445 Stats::TouchEventStats expected_event_stats;
446 SetEventStats(10, 2, 3, 5, 2, 4, 8, 2, 0, 2, 2, -2, 2, 2, 3.5, 6.25,
447 &expected_event_stats);
448 EXPECT_EQ(
449 expected_event_stats.DebugString(),
450 stats.virtual_keyboard_stats(0).touch_event_stats(0).DebugString());
451
452 SetEventStats(100, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
453 &expected_event_stats);
454 EXPECT_EQ(
455 expected_event_stats.DebugString(),
456 stats.virtual_keyboard_stats(0).touch_event_stats(1).DebugString());
457
458 ASSERT_EQ(2, stats.virtual_keyboard_stats(1).touch_event_stats_size());
459
460 SetEventStats(10, 1, 1, 1, 1, 2, 4, 1, 1, 1, 1, -1, 1, 1, 1.5, 2.25,
461 &expected_event_stats);
462 EXPECT_EQ(
463 expected_event_stats.DebugString(),
464 stats.virtual_keyboard_stats(1).touch_event_stats(0).DebugString());
465
466 SetEventStats(30, 1, 2, 4, 1, 2, 4, 1, -1, 1, 1, 1, 1, 1, 2, 4,
467 &expected_event_stats);
468 EXPECT_EQ(
469 expected_event_stats.DebugString(),
470 stats.virtual_keyboard_stats(1).touch_event_stats(1).DebugString());
471 }
472 {
473 Stats stats;
474 UsageStats::GetVirtualKeyboardForTest("VirtualKeyboardMissStats", &stats);
475 ASSERT_EQ(1, stats.virtual_keyboard_stats_size());
476 ASSERT_EQ(1, stats.virtual_keyboard_stats(0).touch_event_stats_size());
477 Stats::TouchEventStats expected_event_stats;
478 SetEventStats(20, 1, 2, 4, 1, 2, 4, 1, -1, 1, 1, -1, 1, 1, 2, 4,
479 &expected_event_stats);
480 EXPECT_EQ(
481 expected_event_stats.DebugString(),
482 stats.virtual_keyboard_stats(0).touch_event_stats(0).DebugString());
483 }
484 }
485
TEST_F(SessionUsageObserverTest,LogTouchEventPasswordField)486 TEST_F(SessionUsageObserverTest, LogTouchEventPasswordField) {
487 std::unique_ptr<SessionUsageObserver> observer(new SessionUsageObserver);
488
489 // create session
490 {
491 commands::Command command;
492 command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
493 command.mutable_input()->set_id(1);
494 command.mutable_output()->set_id(1);
495 observer->EvalCommandHandler(command);
496 }
497 // set keyboard
498 {
499 commands::Command command;
500 command.mutable_input()->set_type(commands::Input::SET_REQUEST);
501 command.mutable_input()->set_id(1);
502 command.mutable_input()->mutable_request()->set_keyboard_name("KB1");
503 observer->EvalCommandHandler(command);
504 }
505 {
506 commands::Command command;
507 command.mutable_input()->set_type(commands::Input::SEND_KEY);
508 command.mutable_input()->set_id(1);
509 commands::Input::TouchEvent *touch_event =
510 command.mutable_input()->add_touch_events();
511 touch_event->set_source_id(10);
512 commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
513 pos1->set_action(commands::Input::TOUCH_DOWN);
514 pos1->set_x(1);
515 pos1->set_y(1);
516 pos1->set_timestamp(0);
517 commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
518 pos2->set_action(commands::Input::TOUCH_UP);
519 pos2->set_x(1);
520 pos2->set_y(1);
521 pos2->set_timestamp(1000);
522 observer->EvalCommandHandler(command);
523 }
524 {
525 commands::Command command;
526 command.mutable_input()->set_type(commands::Input::SEND_KEY);
527 command.mutable_input()->set_id(1);
528 commands::Input::TouchEvent *touch_event =
529 command.mutable_input()->add_touch_events();
530 touch_event->set_source_id(20);
531 commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
532 pos1->set_action(commands::Input::TOUCH_DOWN);
533 pos1->set_x(1);
534 pos1->set_y(1);
535 pos1->set_timestamp(0);
536 commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
537 pos2->set_action(commands::Input::TOUCH_MOVE);
538 pos2->set_x(1);
539 pos2->set_y(1);
540 pos2->set_timestamp(1000);
541 observer->EvalCommandHandler(command);
542 }
543 {
544 // Changes INPUT_FIELD_TYPE to PASSWORD
545 commands::Command command;
546 command.mutable_input()->set_type(commands::Input::SEND_COMMAND);
547 command.mutable_input()->set_id(1);
548 command.mutable_input()->mutable_command()->set_type(
549 commands::SessionCommand::SWITCH_INPUT_FIELD_TYPE);
550 command.mutable_input()->mutable_context()->set_input_field_type(
551 commands::Context::PASSWORD);
552 observer->EvalCommandHandler(command);
553 }
554 {
555 commands::Command command;
556 command.mutable_input()->set_type(commands::Input::SEND_KEY);
557 command.mutable_input()->set_id(1);
558 commands::Input::TouchEvent *touch_event =
559 command.mutable_input()->add_touch_events();
560 touch_event->set_source_id(30);
561 commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
562 pos1->set_action(commands::Input::TOUCH_DOWN);
563 pos1->set_x(1);
564 pos1->set_y(1);
565 pos1->set_timestamp(0);
566 commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
567 pos2->set_action(commands::Input::TOUCH_UP);
568 pos2->set_x(1);
569 pos2->set_y(1);
570 pos2->set_timestamp(1000);
571 observer->EvalCommandHandler(command);
572 }
573 {
574 // Changes INPUT_FIELD_TYPE to NORMAL
575 commands::Command command;
576 command.mutable_input()->set_type(commands::Input::SEND_COMMAND);
577 command.mutable_input()->set_id(1);
578 command.mutable_input()->mutable_command()->set_type(
579 commands::SessionCommand::SWITCH_INPUT_FIELD_TYPE);
580 command.mutable_input()->mutable_context()->set_input_field_type(
581 commands::Context::NORMAL);
582 observer->EvalCommandHandler(command);
583 }
584 {
585 commands::Command command;
586 command.mutable_input()->set_type(commands::Input::SEND_KEY);
587 command.mutable_input()->set_id(1);
588 commands::Input::TouchEvent *touch_event =
589 command.mutable_input()->add_touch_events();
590 touch_event->set_source_id(40);
591 commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
592 pos1->set_action(commands::Input::TOUCH_DOWN);
593 pos1->set_x(1);
594 pos1->set_y(1);
595 pos1->set_timestamp(0);
596 commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
597 pos2->set_action(commands::Input::TOUCH_UP);
598 pos2->set_x(1);
599 pos2->set_y(1);
600 pos2->set_timestamp(1000);
601 observer->EvalCommandHandler(command);
602 }
603 {
604 commands::Command command;
605 command.mutable_input()->set_type(commands::Input::NONE);
606 command.mutable_input()->set_id(1);
607 observer->EvalCommandHandler(command);
608 }
609
610 EXPECT_STATS_NOT_EXIST("VirtualKeyboardStats");
611 EXPECT_STATS_NOT_EXIST("VirtualKeyboardMissStats");
612 EnsureSave();
613
614 {
615 Stats stats;
616 UsageStats::GetVirtualKeyboardForTest("VirtualKeyboardStats", &stats);
617 ASSERT_EQ(1, stats.virtual_keyboard_stats_size());
618 ASSERT_EQ(3, stats.virtual_keyboard_stats(0).touch_event_stats_size());
619
620 Stats::TouchEventStats expected_event_stats;
621 SetEventStats(10, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
622 &expected_event_stats);
623 EXPECT_EQ(
624 expected_event_stats.DebugString(),
625 stats.virtual_keyboard_stats(0).touch_event_stats(0).DebugString());
626 SetEventStats(20, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
627 &expected_event_stats);
628 EXPECT_EQ(
629 expected_event_stats.DebugString(),
630 stats.virtual_keyboard_stats(0).touch_event_stats(1).DebugString());
631 SetEventStats(40, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
632 &expected_event_stats);
633 EXPECT_EQ(
634 expected_event_stats.DebugString(),
635 stats.virtual_keyboard_stats(0).touch_event_stats(2).DebugString());
636 }
637 }
638
639 } // namespace session
640 } // namespace mozc
641