blob: 1c91929808b265469344109f99aa07fba5e9fb56 [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "session/session_usage_observer.h"
#include <string>
#include "base/clock_mock.h"
#include "base/logging.h"
#include "base/scheduler.h"
#include "base/scheduler_stub.h"
#include "base/system_util.h"
#include "base/util.h"
#include "config/stats_config_util.h"
#include "config/stats_config_util_mock.h"
#include "session/commands.pb.h"
#include "testing/base/public/googletest.h"
#include "testing/base/public/gunit.h"
#include "usage_stats/usage_stats.h"
#include "usage_stats/usage_stats.pb.h"
#include "usage_stats/usage_stats_testing_util.h"
using mozc::usage_stats::Stats;
using mozc::usage_stats::UsageStats;
DECLARE_string(test_tmpdir);
namespace mozc {
namespace session {
class SessionUsageObserverTest : public testing::Test {
protected:
virtual void SetUp() {
SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir);
UsageStats::ClearAllStatsForTest();
Util::SetClockHandler(NULL);
scheduler_stub_.reset(new SchedulerStub);
Scheduler::SetSchedulerHandler(scheduler_stub_.get());
stats_config_util_mock_.reset(new config::StatsConfigUtilMock);
config::StatsConfigUtil::SetHandler(stats_config_util_mock_.get());
}
virtual void TearDown() {
Util::SetClockHandler(NULL);
Scheduler::SetSchedulerHandler(NULL);
config::StatsConfigUtil::SetHandler(NULL);
UsageStats::ClearAllStatsForTest();
}
void EnsureSave() const {
// Make sure to save stats.
const uint32 kWaitngUsecForEnsureSave = 10 * 60 * 1000;
scheduler_stub_->PutClockForward(kWaitngUsecForEnsureSave);
}
void SetDoubleValueStats(
uint32 num, double total, double square_total,
Stats::DoubleValueStats *double_stats) {
DCHECK(double_stats);
double_stats->set_num(num);
double_stats->set_total(total);
double_stats->set_square_total(square_total);
}
void 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) {
event_stats->set_source_id(source_id);
SetDoubleValueStats(sx_num, sx_total, sx_square_total,
event_stats->mutable_start_x_stats());
SetDoubleValueStats(sy_num, sy_total, sy_square_total,
event_stats->mutable_start_y_stats());
SetDoubleValueStats(dx_num, dx_total, dx_square_total,
event_stats->mutable_direction_x_stats());
SetDoubleValueStats(dy_num, dy_total, dy_square_total,
event_stats->mutable_direction_y_stats());
SetDoubleValueStats(tl_num, tl_total, tl_square_total,
event_stats->mutable_time_length_stats());
}
scoped_ptr<SchedulerStub> scheduler_stub_;
scoped_ptr<config::StatsConfigUtilMock> stats_config_util_mock_;
};
TEST_F(SessionUsageObserverTest, DoNotSaveWhenDeleted) {
stats_config_util_mock_->SetEnabled(false);
scoped_ptr<SessionUsageObserver> observer(new SessionUsageObserver);
// Add command
commands::Command command;
command.mutable_input()->set_type(commands::Input::NONE);
command.mutable_input()->set_id(0);
command.mutable_output()->set_consumed(true);
for (int i = 0; i < 5; ++i) {
observer->EvalCommandHandler(command);
EXPECT_STATS_NOT_EXIST("SessionAllEvent");
}
observer.reset();
EXPECT_STATS_NOT_EXIST("SessionAllEvent");
}
TEST_F(SessionUsageObserverTest, ClientSideStatsInfolist) {
scoped_ptr<SessionUsageObserver> observer(new SessionUsageObserver);
// create session
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
command.mutable_input()->set_id(1);
command.mutable_output()->set_id(1);
observer->EvalCommandHandler(command);
}
const uint64 kSeconds = 0;
const uint32 kMicroSeconds = 0;
ClockMock clock(kSeconds, kMicroSeconds);
Util::SetClockHandler(&clock);
// prepare command
commands::Command orig_show_command, orig_hide_command;
orig_show_command.mutable_input()->set_type(commands::Input::SEND_COMMAND);
orig_show_command.mutable_input()->set_id(1);
orig_show_command.mutable_input()->mutable_command()->set_type(
commands::SessionCommand::USAGE_STATS_EVENT);
orig_show_command.mutable_input()->mutable_command()->set_usage_stats_event(
commands::SessionCommand::INFOLIST_WINDOW_SHOW);
orig_show_command.mutable_output()->set_consumed(false);
EXPECT_TRUE(orig_show_command.output().has_consumed());
EXPECT_FALSE(orig_show_command.output().consumed());
EXPECT_TRUE(orig_show_command.input().has_id());
orig_hide_command.CopyFrom(orig_show_command);
orig_hide_command.mutable_input()->mutable_command()->set_usage_stats_event(
commands::SessionCommand::INFOLIST_WINDOW_HIDE);
{ // show infolist, wait 1,100,000 usec and hide infolist.
commands::Command show_command, hide_command;
show_command.CopyFrom(orig_show_command);
hide_command.CopyFrom(orig_hide_command);
observer->EvalCommandHandler(show_command);
EXPECT_STATS_NOT_EXIST("InfolistWindowDurationMSec");
clock.PutClockForward(1, 100000);
observer->EvalCommandHandler(hide_command);
EXPECT_TIMING_STATS("InfolistWindowDurationMSec", 1100, 1, 1100, 1100);
}
{ // show infolist, wait 1,200,000 usec and hide infolist.
commands::Command show_command, hide_command;
show_command.CopyFrom(orig_show_command);
hide_command.CopyFrom(orig_hide_command);
observer->EvalCommandHandler(show_command);
clock.PutClockForward(1, 200000);
observer->EvalCommandHandler(hide_command);
EXPECT_TIMING_STATS("InfolistWindowDurationMSec", 2300, 2, 1100, 1200);
}
}
TEST_F(SessionUsageObserverTest, ClientSideStatsSoftwareKeyboardLayout) {
SessionUsageObserver observer;
// create session
commands::Command command;
command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
command.mutable_input()->set_id(1);
command.mutable_output()->set_id(1);
observer.EvalCommandHandler(command);
EXPECT_STATS_NOT_EXIST("SoftwareKeyboardLayoutLandscape");
EXPECT_STATS_NOT_EXIST("SoftwareKeyboardLayoutPortrait");
command.mutable_input()->set_type(commands::Input::SEND_COMMAND);
commands::SessionCommand *session_command =
command.mutable_input()->mutable_command();
session_command->set_type(commands::SessionCommand::USAGE_STATS_EVENT);
session_command->set_usage_stats_event(
commands::SessionCommand::SOFTWARE_KEYBOARD_LAYOUT_LANDSCAPE);
session_command->set_usage_stats_event_int_value(1);
observer.EvalCommandHandler(command);
EXPECT_INTEGER_STATS("SoftwareKeyboardLayoutLandscape", 1);
EXPECT_STATS_NOT_EXIST("SoftwareKeyboardLayoutPortrait");
session_command->set_usage_stats_event_int_value(2);
observer.EvalCommandHandler(command);
EXPECT_INTEGER_STATS("SoftwareKeyboardLayoutLandscape", 2);
EXPECT_STATS_NOT_EXIST("SoftwareKeyboardLayoutPortrait");
session_command->set_usage_stats_event(
commands::SessionCommand::SOFTWARE_KEYBOARD_LAYOUT_PORTRAIT);
session_command->set_usage_stats_event_int_value(3);
observer.EvalCommandHandler(command);
EXPECT_INTEGER_STATS("SoftwareKeyboardLayoutLandscape", 2);
EXPECT_INTEGER_STATS("SoftwareKeyboardLayoutPortrait", 3);
}
TEST_F(SessionUsageObserverTest, SubmittedCandidateRow) {
SessionUsageObserver observer;
// create session
commands::Command command;
command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
command.mutable_input()->set_id(1);
command.mutable_output()->set_id(1);
observer.EvalCommandHandler(command);
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow0");
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow1");
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow2");
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow3");
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow4");
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow5");
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow6");
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow7");
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow8");
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRow9");
EXPECT_STATS_NOT_EXIST("SubmittedCandidateRowGE10");
command.mutable_input()->set_type(commands::Input::SEND_COMMAND);
commands::SessionCommand *session_command =
command.mutable_input()->mutable_command();
session_command->set_type(commands::SessionCommand::USAGE_STATS_EVENT);
session_command->set_usage_stats_event(
commands::SessionCommand::SUBMITTED_CANDIDATE_ROW_0);
observer.EvalCommandHandler(command);
EXPECT_COUNT_STATS("SubmittedCandidateRow0", 1);
observer.EvalCommandHandler(command);
EXPECT_COUNT_STATS("SubmittedCandidateRow0", 2);
}
TEST_F(SessionUsageObserverTest, LogTouchEvent) {
scoped_ptr<SessionUsageObserver> observer(new SessionUsageObserver);
// create session
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
command.mutable_input()->set_id(1);
command.mutable_output()->set_id(1);
observer->EvalCommandHandler(command);
}
// set keyboard
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SET_REQUEST);
command.mutable_input()->set_id(1);
command.mutable_input()->mutable_request()->set_keyboard_name("KB1");
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_KEY);
command.mutable_input()->set_id(1);
commands::Input::TouchEvent *touch_event =
command.mutable_input()->add_touch_events();
touch_event->set_source_id(10);
commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
pos1->set_action(commands::Input::TOUCH_DOWN);
pos1->set_x(1);
pos1->set_y(2);
pos1->set_timestamp(0);
commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
pos2->set_action(commands::Input::TOUCH_UP);
pos2->set_x(2);
pos2->set_y(1);
pos2->set_timestamp(1500);
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_KEY);
command.mutable_input()->set_id(1);
commands::Input::TouchEvent *touch_event =
command.mutable_input()->add_touch_events();
touch_event->set_source_id(10);
commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
pos1->set_action(commands::Input::TOUCH_DOWN);
pos1->set_x(2);
pos1->set_y(2);
pos1->set_timestamp(0);
commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
pos2->set_action(commands::Input::TOUCH_MOVE);
pos2->set_x(2);
pos2->set_y(2);
pos2->set_timestamp(1000);
commands::Input::TouchPosition *pos3 = touch_event->add_stroke();
pos3->set_action(commands::Input::TOUCH_MOVE);
pos3->set_x(1);
pos3->set_y(1);
pos3->set_timestamp(2000);
observer->EvalCommandHandler(command);
}
// change keyboard
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SET_REQUEST);
command.mutable_input()->set_id(1);
command.mutable_input()->mutable_request()->set_keyboard_name("KB2");
commands::Input::TouchEvent *touch_event =
command.mutable_input()->add_touch_events();
touch_event->set_source_id(100);
commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
pos1->set_action(commands::Input::TOUCH_DOWN);
pos1->set_x(1);
pos1->set_y(1);
pos1->set_timestamp(0);
commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
pos2->set_action(commands::Input::TOUCH_UP);
pos2->set_x(1);
pos2->set_y(1);
pos2->set_timestamp(1000);
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_KEY);
command.mutable_input()->set_id(1);
commands::Input::TouchEvent *touch_event =
command.mutable_input()->add_touch_events();
touch_event->set_source_id(10);
commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
pos1->set_action(commands::Input::TOUCH_DOWN);
pos1->set_x(1);
pos1->set_y(2);
pos1->set_timestamp(0);
commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
pos2->set_action(commands::Input::TOUCH_UP);
pos2->set_x(2);
pos2->set_y(1);
pos2->set_timestamp(1500);
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_KEY);
command.mutable_input()->set_id(1);
commands::Input::TouchEvent *touch_event =
command.mutable_input()->add_touch_events();
touch_event->set_source_id(20);
commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
pos1->set_action(commands::Input::TOUCH_DOWN);
pos1->set_x(2);
pos1->set_y(2);
pos1->set_timestamp(0);
commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
pos2->set_action(commands::Input::TOUCH_UP);
pos2->set_x(1);
pos2->set_y(1);
pos2->set_timestamp(2000);
// add preedit
command.mutable_output()->mutable_preedit();
command.mutable_output()->set_consumed(true);
observer->EvalCommandHandler(command);
}
{
// send BACKSPACE
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_KEY);
command.mutable_input()->set_id(1);
command.mutable_input()->mutable_key()->set_special_key(
commands::KeyEvent::BACKSPACE);
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_KEY);
command.mutable_input()->set_id(1);
commands::Input::TouchEvent *touch_event =
command.mutable_input()->add_touch_events();
touch_event->set_source_id(30);
commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
pos1->set_action(commands::Input::TOUCH_DOWN);
pos1->set_x(2);
pos1->set_y(2);
pos1->set_timestamp(0);
commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
pos2->set_action(commands::Input::TOUCH_MOVE);
pos2->set_x(1);
pos2->set_y(1);
pos2->set_timestamp(1000);
commands::Input::TouchPosition *pos3 = touch_event->add_stroke();
pos3->set_action(commands::Input::TOUCH_UP);
pos3->set_x(1);
pos3->set_y(3);
pos3->set_timestamp(2000);
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::NONE);
command.mutable_input()->set_id(1);
observer->EvalCommandHandler(command);
}
EXPECT_STATS_NOT_EXIST("VirtualKeyboardStats");
EXPECT_STATS_NOT_EXIST("VirtualKeyboardMissStats");
EnsureSave();
{
Stats stats;
UsageStats::GetVirtualKeyboardForTest("VirtualKeyboardStats", &stats);
ASSERT_EQ(2, stats.virtual_keyboard_stats_size());
ASSERT_EQ(2, stats.virtual_keyboard_stats(0).touch_event_stats_size());
Stats::TouchEventStats expected_event_stats;
SetEventStats(10, 2, 3, 5, 2, 4, 8, 2, 0, 2, 2, -2, 2, 2, 3.5, 6.25,
&expected_event_stats);
EXPECT_EQ(
expected_event_stats.DebugString(),
stats.virtual_keyboard_stats(0).touch_event_stats(0).DebugString());
SetEventStats(100, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
&expected_event_stats);
EXPECT_EQ(
expected_event_stats.DebugString(),
stats.virtual_keyboard_stats(0).touch_event_stats(1).DebugString());
ASSERT_EQ(2, stats.virtual_keyboard_stats(1).touch_event_stats_size());
SetEventStats(10, 1, 1, 1, 1, 2, 4, 1, 1, 1, 1, -1, 1, 1, 1.5, 2.25,
&expected_event_stats);
EXPECT_EQ(
expected_event_stats.DebugString(),
stats.virtual_keyboard_stats(1).touch_event_stats(0).DebugString());
SetEventStats(30, 1, 2, 4, 1, 2, 4, 1, -1, 1, 1, 1, 1, 1, 2, 4,
&expected_event_stats);
EXPECT_EQ(
expected_event_stats.DebugString(),
stats.virtual_keyboard_stats(1).touch_event_stats(1).DebugString());
}
{
Stats stats;
UsageStats::GetVirtualKeyboardForTest("VirtualKeyboardMissStats", &stats);
ASSERT_EQ(1, stats.virtual_keyboard_stats_size());
ASSERT_EQ(1, stats.virtual_keyboard_stats(0).touch_event_stats_size());
Stats::TouchEventStats expected_event_stats;
SetEventStats(20, 1, 2, 4, 1, 2, 4, 1, -1, 1, 1, -1, 1, 1, 2, 4,
&expected_event_stats);
EXPECT_EQ(
expected_event_stats.DebugString(),
stats.virtual_keyboard_stats(0).touch_event_stats(0).DebugString());
}
}
TEST_F(SessionUsageObserverTest, LogTouchEventPasswordField) {
scoped_ptr<SessionUsageObserver> observer(new SessionUsageObserver);
// create session
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
command.mutable_input()->set_id(1);
command.mutable_output()->set_id(1);
observer->EvalCommandHandler(command);
}
// set keyboard
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SET_REQUEST);
command.mutable_input()->set_id(1);
command.mutable_input()->mutable_request()->set_keyboard_name("KB1");
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_KEY);
command.mutable_input()->set_id(1);
commands::Input::TouchEvent *touch_event =
command.mutable_input()->add_touch_events();
touch_event->set_source_id(10);
commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
pos1->set_action(commands::Input::TOUCH_DOWN);
pos1->set_x(1);
pos1->set_y(1);
pos1->set_timestamp(0);
commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
pos2->set_action(commands::Input::TOUCH_UP);
pos2->set_x(1);
pos2->set_y(1);
pos2->set_timestamp(1000);
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_KEY);
command.mutable_input()->set_id(1);
commands::Input::TouchEvent *touch_event =
command.mutable_input()->add_touch_events();
touch_event->set_source_id(20);
commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
pos1->set_action(commands::Input::TOUCH_DOWN);
pos1->set_x(1);
pos1->set_y(1);
pos1->set_timestamp(0);
commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
pos2->set_action(commands::Input::TOUCH_MOVE);
pos2->set_x(1);
pos2->set_y(1);
pos2->set_timestamp(1000);
observer->EvalCommandHandler(command);
}
{
// Changes INPUT_FIELD_TYPE to PASSWORD
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_COMMAND);
command.mutable_input()->set_id(1);
command.mutable_input()->mutable_command()->set_type(
commands::SessionCommand::SWITCH_INPUT_FIELD_TYPE);
command.mutable_input()->mutable_context()->set_input_field_type(
commands::Context::PASSWORD);
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_KEY);
command.mutable_input()->set_id(1);
commands::Input::TouchEvent *touch_event =
command.mutable_input()->add_touch_events();
touch_event->set_source_id(30);
commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
pos1->set_action(commands::Input::TOUCH_DOWN);
pos1->set_x(1);
pos1->set_y(1);
pos1->set_timestamp(0);
commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
pos2->set_action(commands::Input::TOUCH_UP);
pos2->set_x(1);
pos2->set_y(1);
pos2->set_timestamp(1000);
observer->EvalCommandHandler(command);
}
{
// Changes INPUT_FIELD_TYPE to NORMAL
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_COMMAND);
command.mutable_input()->set_id(1);
command.mutable_input()->mutable_command()->set_type(
commands::SessionCommand::SWITCH_INPUT_FIELD_TYPE);
command.mutable_input()->mutable_context()->set_input_field_type(
commands::Context::NORMAL);
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::SEND_KEY);
command.mutable_input()->set_id(1);
commands::Input::TouchEvent *touch_event =
command.mutable_input()->add_touch_events();
touch_event->set_source_id(40);
commands::Input::TouchPosition *pos1 = touch_event->add_stroke();
pos1->set_action(commands::Input::TOUCH_DOWN);
pos1->set_x(1);
pos1->set_y(1);
pos1->set_timestamp(0);
commands::Input::TouchPosition *pos2 = touch_event->add_stroke();
pos2->set_action(commands::Input::TOUCH_UP);
pos2->set_x(1);
pos2->set_y(1);
pos2->set_timestamp(1000);
observer->EvalCommandHandler(command);
}
{
commands::Command command;
command.mutable_input()->set_type(commands::Input::NONE);
command.mutable_input()->set_id(1);
observer->EvalCommandHandler(command);
}
EXPECT_STATS_NOT_EXIST("VirtualKeyboardStats");
EXPECT_STATS_NOT_EXIST("VirtualKeyboardMissStats");
EnsureSave();
{
Stats stats;
UsageStats::GetVirtualKeyboardForTest("VirtualKeyboardStats", &stats);
ASSERT_EQ(1, stats.virtual_keyboard_stats_size());
ASSERT_EQ(3, stats.virtual_keyboard_stats(0).touch_event_stats_size());
Stats::TouchEventStats expected_event_stats;
SetEventStats(10, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
&expected_event_stats);
EXPECT_EQ(
expected_event_stats.DebugString(),
stats.virtual_keyboard_stats(0).touch_event_stats(0).DebugString());
SetEventStats(20, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
&expected_event_stats);
EXPECT_EQ(
expected_event_stats.DebugString(),
stats.virtual_keyboard_stats(0).touch_event_stats(1).DebugString());
SetEventStats(40, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1,
&expected_event_stats);
EXPECT_EQ(
expected_event_stats.DebugString(),
stats.virtual_keyboard_stats(0).touch_event_stats(2).DebugString());
}
}
} // namespace session
} // namespace mozc