blob: 8c5d6b1d59d75dbf33b49fc1963b1e2a92ba71a4 [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 "client/client.h"
#include <map>
#include <string>
#include "base/logging.h"
#include "base/number_util.h"
#include "base/port.h"
#include "base/util.h"
#include "base/version.h"
#include "ipc/ipc_mock.h"
#include "session/commands.pb.h"
#include "testing/base/public/gunit.h"
namespace mozc {
namespace client {
namespace {
const char kPrecedingText[] = "preceding_text";
const char kFollowingText[] = "following_text";
const bool kSuppressSuggestion = true;
const string UpdateVersion(int diff) {
vector<string> tokens;
Util::SplitStringUsing(Version::GetMozcVersion(), ".", &tokens);
EXPECT_EQ(tokens.size(), 4);
char buf[64];
snprintf(buf, sizeof(buf), "%d", NumberUtil::SimpleAtoi(tokens[3]) + diff);
tokens[3] = buf;
string output;
Util::JoinStrings(tokens, ".", &output);
return output;
}
} // namespace
class TestServerLauncher : public ServerLauncherInterface {
public:
explicit TestServerLauncher(IPCClientFactoryMock *factory)
: factory_(factory),
start_server_result_(false),
start_server_called_(false),
force_terminate_server_result_(false),
force_terminate_server_called_(false),
server_protocol_version_(IPC_PROTOCOL_VERSION) {}
virtual void Ready() {}
virtual void Wait() {}
virtual void Error() {}
virtual bool StartServer(ClientInterface *client) {
if (!response_.empty()) {
factory_->SetMockResponse(response_);
}
if (!product_version_after_start_server_.empty()) {
factory_->SetServerProductVersion(product_version_after_start_server_);
}
factory_->SetServerProtocolVersion(server_protocol_version_);
start_server_called_ = true;
return start_server_result_;
}
virtual bool ForceTerminateServer(const string &name) {
force_terminate_server_called_ = true;
return force_terminate_server_result_;
}
virtual bool WaitServer(uint32 pid) {
return true;
}
virtual void OnFatal(ServerLauncherInterface::ServerErrorType type) {
LOG(ERROR) << static_cast<int>(type);
error_map_[static_cast<int>(type)]++;
}
int error_count(ServerLauncherInterface::ServerErrorType type) {
return error_map_[static_cast<int>(type)];
}
bool start_server_called() const {
return start_server_called_;
}
void set_start_server_called(bool start_server_called) {
start_server_called_ = start_server_called;
}
bool force_terminate_server_called() const {
return force_terminate_server_called_;
}
void set_force_terminate_server_called(bool force_terminate_server_called) {
force_terminate_server_called_ = force_terminate_server_called;
}
void set_server_program(const string &server_path) {
}
virtual const string &server_program() const {
static const string path;
return path;
}
void set_restricted(bool restricted) {}
void set_suppress_error_dialog(bool suppress) {}
void set_start_server_result(const bool result) {
start_server_result_ = result;
}
void set_force_terminate_server_result(const bool result) {
force_terminate_server_result_ = result;
}
void set_server_protocol_version(uint32 server_protocol_version) {
server_protocol_version_ = server_protocol_version;
}
void set_mock_after_start_server(const commands::Output &mock_output) {
mock_output.SerializeToString(&response_);
}
void set_product_version_after_start_server(const string &version) {
product_version_after_start_server_ = version;
}
private:
IPCClientFactoryMock *factory_;
bool start_server_result_;
bool start_server_called_;
bool force_terminate_server_result_;
bool force_terminate_server_called_;
uint32 server_protocol_version_;
string response_;
string product_version_after_start_server_;
map<int, int> error_map_;
};
class ClientTest : public testing::Test {
protected:
ClientTest() : version_diff_(0) {}
virtual void SetUp() {
client_factory_.reset(new IPCClientFactoryMock);
client_.reset(new Client);
client_->SetIPCClientFactory(client_factory_.get());
server_launcher_ = new TestServerLauncher(client_factory_.get());
client_->SetServerLauncher(server_launcher_);
}
virtual void TearDown() {
client_.reset();
client_factory_.reset();
}
void SetMockOutput(const commands::Output &mock_output) {
string response;
mock_output.SerializeToString(&response);
client_factory_->SetMockResponse(response);
}
void GetGeneratedInput(commands::Input *input) {
input->ParseFromString(client_factory_->GetGeneratedRequest());
if (input->type() != commands::Input::CREATE_SESSION) {
ASSERT_TRUE(input->has_id());
}
}
void SetupProductVersion(int version_diff) {
version_diff_ = version_diff;
}
bool SetupConnection(const int id) {
client_factory_->SetConnection(true);
client_factory_->SetResult(true);
if (version_diff_ == 0) {
client_factory_->SetServerProductVersion(Version::GetMozcVersion());
} else {
client_factory_->SetServerProductVersion(UpdateVersion(version_diff_));
}
server_launcher_->set_start_server_result(true);
// TODO(komatsu): Due to the limitation of the testing mock,
// EnsureConnection should be explicitly called before calling
// SendKey. Fix the testing mock.
commands::Output mock_output;
mock_output.set_id(id);
SetMockOutput(mock_output);
return client_->EnsureConnection();
}
scoped_ptr<IPCClientFactoryMock> client_factory_;
scoped_ptr<Client> client_;
TestServerLauncher *server_launcher_;
int version_diff_;
private:
DISALLOW_COPY_AND_ASSIGN(ClientTest);
};
TEST_F(ClientTest, ConnectionError) {
client_factory_->SetConnection(false);
server_launcher_->set_start_server_result(false);
EXPECT_FALSE(client_->EnsureConnection());
commands::KeyEvent key;
commands::Output output;
EXPECT_FALSE(client_->SendKey(key, &output));
key.Clear();
output.Clear();
EXPECT_FALSE(client_->TestSendKey(key, &output));
commands::SessionCommand command;
output.Clear();
EXPECT_FALSE(client_->SendCommand(command, &output));
}
TEST_F(ClientTest, SendKey) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
commands::Output mock_output;
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
commands::Input input;
GetGeneratedInput(&input);
EXPECT_EQ(mock_id, input.id());
EXPECT_EQ(commands::Input::SEND_KEY, input.type());
}
TEST_F(ClientTest, SendKeyWithContext) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
commands::Context context;
context.set_preceding_text(kPrecedingText);
context.set_following_text(kFollowingText);
context.set_suppress_suggestion(kSuppressSuggestion);
commands::Output mock_output;
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->SendKeyWithContext(key_event, context, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
commands::Input input;
GetGeneratedInput(&input);
EXPECT_EQ(mock_id, input.id());
EXPECT_EQ(commands::Input::SEND_KEY, input.type());
EXPECT_EQ(kPrecedingText, input.context().preceding_text());
EXPECT_EQ(kFollowingText, input.context().following_text());
EXPECT_EQ(kSuppressSuggestion, input.context().suppress_suggestion());
}
TEST_F(ClientTest, TestSendKey) {
const int mock_id = 512;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
commands::Output mock_output;
mock_output.Clear();
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->TestSendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
commands::Input input;
GetGeneratedInput(&input);
EXPECT_EQ(mock_id, input.id());
EXPECT_EQ(commands::Input::TEST_SEND_KEY, input.type());
}
TEST_F(ClientTest, TestSendKeyWithContext) {
const int mock_id = 512;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
commands::Context context;
context.set_preceding_text(kPrecedingText);
context.set_following_text(kFollowingText);
context.set_suppress_suggestion(kSuppressSuggestion);
commands::Output mock_output;
mock_output.Clear();
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->TestSendKeyWithContext(key_event, context, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
commands::Input input;
GetGeneratedInput(&input);
EXPECT_EQ(mock_id, input.id());
EXPECT_EQ(commands::Input::TEST_SEND_KEY, input.type());
EXPECT_EQ(kPrecedingText, input.context().preceding_text());
EXPECT_EQ(kFollowingText, input.context().following_text());
EXPECT_EQ(kSuppressSuggestion, input.context().suppress_suggestion());
}
TEST_F(ClientTest, SendCommand) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::SessionCommand session_command;
session_command.set_type(commands::SessionCommand::SUBMIT);
commands::Output mock_output;
mock_output.Clear();
mock_output.set_id(mock_id);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->SendCommand(session_command, &output));
commands::Input input;
GetGeneratedInput(&input);
EXPECT_EQ(mock_id, input.id());
EXPECT_EQ(commands::Input::SEND_COMMAND, input.type());
}
TEST_F(ClientTest, SendCommandWithContext) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::SessionCommand session_command;
session_command.set_type(commands::SessionCommand::SUBMIT);
commands::Context context;
context.set_preceding_text(kPrecedingText);
context.set_following_text(kFollowingText);
context.set_suppress_suggestion(kSuppressSuggestion);
commands::Output mock_output;
mock_output.Clear();
mock_output.set_id(mock_id);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->SendCommandWithContext(session_command,
context,
&output));
commands::Input input;
GetGeneratedInput(&input);
EXPECT_EQ(mock_id, input.id());
EXPECT_EQ(commands::Input::SEND_COMMAND, input.type());
EXPECT_EQ(kPrecedingText, input.context().preceding_text());
EXPECT_EQ(kFollowingText, input.context().following_text());
EXPECT_EQ(kSuppressSuggestion, input.context().suppress_suggestion());
}
TEST_F(ClientTest, SetConfig) {
const int mock_id = 0;
EXPECT_TRUE(SetupConnection(mock_id));
config::Config config;
EXPECT_TRUE(client_->SetConfig(config));
}
TEST_F(ClientTest, GetConfig) {
const int mock_id = 0;
EXPECT_TRUE(SetupConnection(mock_id));
commands::Output mock_output;
mock_output.set_id(mock_id);
mock_output.mutable_config()->set_verbose_level(2);
mock_output.mutable_config()->set_incognito_mode(true);
SetMockOutput(mock_output);
config::Config config;
EXPECT_TRUE(client_->GetConfig(&config));
EXPECT_EQ(2, config.verbose_level());
EXPECT_EQ(true, config.incognito_mode());
}
TEST_F(ClientTest, EnableCascadingWindow) {
const int mock_id = 0;
EXPECT_TRUE(SetupConnection(mock_id));
commands::Output mock_output;
mock_output.set_id(mock_id);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->EnsureConnection());
client_->NoOperation();
commands::Input input;
GetGeneratedInput(&input);
EXPECT_FALSE(input.has_config());
client_->EnableCascadingWindow(false);
client_->NoOperation();
GetGeneratedInput(&input);
ASSERT_TRUE(input.has_config());
ASSERT_TRUE(input.config().has_use_cascading_window());
EXPECT_FALSE(input.config().use_cascading_window());
client_->EnableCascadingWindow(true);
client_->NoOperation();
GetGeneratedInput(&input);
ASSERT_TRUE(input.has_config());
ASSERT_TRUE(input.config().has_use_cascading_window());
EXPECT_TRUE(input.config().use_cascading_window());
client_->NoOperation();
GetGeneratedInput(&input);
ASSERT_TRUE(input.has_config());
EXPECT_TRUE(input.config().has_use_cascading_window());
}
TEST_F(ClientTest, VersionMismatch) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
commands::Output mock_output;
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
SetMockOutput(mock_output);
// Suddenly, connects to a different server
client_factory_->SetServerProtocolVersion(IPC_PROTOCOL_VERSION + 1);
commands::Output output;
EXPECT_FALSE(client_->SendKey(key_event, &output));
EXPECT_FALSE(client_->EnsureConnection());
EXPECT_EQ(1, server_launcher_->error_count
(ServerLauncherInterface::SERVER_VERSION_MISMATCH));
}
TEST_F(ClientTest, ProtocolUpdate) {
server_launcher_->set_start_server_result(true);
const int mock_id = 0;
EXPECT_TRUE(SetupConnection(mock_id));
commands::Output mock_output;
mock_output.set_id(mock_id);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->EnsureConnection());
server_launcher_->set_force_terminate_server_called(false);
server_launcher_->set_force_terminate_server_result(true);
server_launcher_->set_start_server_called(false);
// Now connecting to an old server
client_factory_->SetServerProtocolVersion(IPC_PROTOCOL_VERSION - 1);
// after start server, protocol version becomes the same
server_launcher_->set_server_protocol_version(IPC_PROTOCOL_VERSION);
EXPECT_TRUE(client_->EnsureSession());
EXPECT_TRUE(server_launcher_->start_server_called());
EXPECT_TRUE(server_launcher_->force_terminate_server_called());
}
TEST_F(ClientTest, ProtocolUpdateFailSameBinary) {
server_launcher_->set_start_server_result(true);
const int mock_id = 0;
EXPECT_TRUE(SetupConnection(mock_id));
commands::Output mock_output;
mock_output.set_id(mock_id);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->EnsureConnection());
server_launcher_->set_force_terminate_server_called(false);
server_launcher_->set_force_terminate_server_result(true);
server_launcher_->set_start_server_called(false);
EXPECT_FALSE(server_launcher_->start_server_called());
// version is updated after restart the server
client_factory_->SetServerProtocolVersion(IPC_PROTOCOL_VERSION - 1);
// even after server reboot, protocol version is old
server_launcher_->set_server_protocol_version(IPC_PROTOCOL_VERSION - 1);
server_launcher_->set_mock_after_start_server(mock_output);
EXPECT_FALSE(client_->EnsureSession());
EXPECT_TRUE(server_launcher_->start_server_called());
EXPECT_TRUE(server_launcher_->force_terminate_server_called());
EXPECT_FALSE(client_->EnsureConnection());
EXPECT_EQ(1, server_launcher_->error_count
(ServerLauncherInterface::SERVER_BROKEN_MESSAGE));
}
TEST_F(ClientTest, ProtocolUpdateFailOnTerminate) {
server_launcher_->set_start_server_result(true);
const int mock_id = 0;
EXPECT_TRUE(SetupConnection(mock_id));
commands::Output mock_output;
mock_output.set_id(mock_id);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->EnsureConnection());
server_launcher_->set_force_terminate_server_called(false);
server_launcher_->set_force_terminate_server_result(false);
server_launcher_->set_start_server_called(false);
EXPECT_FALSE(server_launcher_->start_server_called());
// version is updated after restart the server
client_factory_->SetServerProtocolVersion(IPC_PROTOCOL_VERSION - 1);
// even after server reboot, protocol version is old
server_launcher_->set_server_protocol_version(IPC_PROTOCOL_VERSION);
server_launcher_->set_mock_after_start_server(mock_output);
EXPECT_FALSE(client_->EnsureSession());
EXPECT_FALSE(server_launcher_->start_server_called());
EXPECT_TRUE(server_launcher_->force_terminate_server_called());
EXPECT_FALSE(client_->EnsureConnection());
EXPECT_EQ(1, server_launcher_->error_count
(ServerLauncherInterface::SERVER_BROKEN_MESSAGE));
}
TEST_F(ClientTest, ServerUpdate) {
SetupProductVersion(-1); // old version
server_launcher_->set_start_server_result(true);
const int mock_id = 0;
EXPECT_TRUE(SetupConnection(mock_id));
LOG(ERROR) << Version::GetMozcVersion();
commands::Output mock_output;
mock_output.set_id(mock_id);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->EnsureConnection());
server_launcher_->set_start_server_called(false);
EXPECT_FALSE(server_launcher_->start_server_called());
// version is updated after restart the server
server_launcher_->set_product_version_after_start_server(
Version::GetMozcVersion());
EXPECT_TRUE(client_->EnsureSession());
EXPECT_TRUE(server_launcher_->start_server_called());
}
TEST_F(ClientTest, ServerUpdateToNewer) {
SetupProductVersion(1); // new version
server_launcher_->set_start_server_result(true);
const int mock_id = 0;
EXPECT_TRUE(SetupConnection(mock_id));
LOG(ERROR) << Version::GetMozcVersion();
commands::Output mock_output;
mock_output.set_id(mock_id);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->EnsureConnection());
server_launcher_->set_start_server_called(false);
EXPECT_TRUE(client_->EnsureSession());
EXPECT_FALSE(server_launcher_->start_server_called());
}
TEST_F(ClientTest, ServerUpdateFail) {
SetupProductVersion(-1); // old
server_launcher_->set_start_server_result(true);
const int mock_id = 0;
EXPECT_TRUE(SetupConnection(mock_id));
commands::Output mock_output;
mock_output.set_id(mock_id);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->EnsureConnection());
server_launcher_->set_start_server_called(false);
EXPECT_FALSE(server_launcher_->start_server_called());
// version is not updated after restart the server
server_launcher_->set_mock_after_start_server(mock_output);
EXPECT_FALSE(client_->EnsureSession());
EXPECT_TRUE(server_launcher_->start_server_called());
EXPECT_FALSE(client_->EnsureConnection());
EXPECT_EQ(1, server_launcher_->error_count
(ServerLauncherInterface::SERVER_BROKEN_MESSAGE));
}
TEST_F(ClientTest, TranslateProtoBufToMozcToolArgTest) {
commands::Output output;
string mode = "";
// If no value is set, we expect to return false
EXPECT_FALSE(client::Client::TranslateProtoBufToMozcToolArg(output, &mode));
EXPECT_EQ("", mode);
// If NO_TOOL is set, we expect to return false
output.set_launch_tool_mode(commands::Output::NO_TOOL);
EXPECT_FALSE(client::Client::TranslateProtoBufToMozcToolArg(output, &mode));
EXPECT_EQ("", mode);
output.set_launch_tool_mode(commands::Output::CONFIG_DIALOG);
EXPECT_TRUE(client::Client::TranslateProtoBufToMozcToolArg(output, &mode));
EXPECT_EQ("config_dialog", mode);
output.set_launch_tool_mode(commands::Output::DICTIONARY_TOOL);
EXPECT_TRUE(client::Client::TranslateProtoBufToMozcToolArg(output, &mode));
EXPECT_EQ("dictionary_tool", mode);
output.set_launch_tool_mode(commands::Output::WORD_REGISTER_DIALOG);
EXPECT_TRUE(client::Client::TranslateProtoBufToMozcToolArg(output, &mode));
EXPECT_EQ("word_register_dialog", mode);
}
class SessionPlaybackTestServerLauncher : public ServerLauncherInterface {
public:
explicit SessionPlaybackTestServerLauncher(IPCClientFactoryMock *factory)
: factory_(factory),
start_server_result_(false),
start_server_called_(false),
force_terminate_server_result_(false),
force_terminate_server_called_(false),
server_protocol_version_(IPC_PROTOCOL_VERSION) {}
virtual void Ready() {}
virtual void Wait() {}
virtual void Error() {}
virtual bool StartServer(ClientInterface *client) {
if (!response_.empty()) {
factory_->SetMockResponse(response_);
}
if (!product_version_after_start_server_.empty()) {
factory_->SetServerProductVersion(product_version_after_start_server_);
}
factory_->SetServerProtocolVersion(server_protocol_version_);
start_server_called_ = true;
return start_server_result_;
}
virtual bool ForceTerminateServer(const string &name) {
force_terminate_server_called_ = true;
return force_terminate_server_result_;
}
virtual bool WaitServer(uint32 pid) {
return true;
}
virtual void OnFatal(ServerLauncherInterface::ServerErrorType type) {
}
void set_server_program(const string &server_path) {}
void set_restricted(bool restricted) {}
void set_suppress_error_dialog(bool suppress) {}
void set_start_server_result(const bool result) {
start_server_result_ = result;
}
virtual const string &server_program() const {
static const string path;
return path;
}
private:
IPCClientFactoryMock *factory_;
bool start_server_result_;
bool start_server_called_;
bool force_terminate_server_result_;
bool force_terminate_server_called_;
uint32 server_protocol_version_;
string response_;
string product_version_after_start_server_;
map<int, int> error_map_;
};
class SessionPlaybackTest : public testing::Test {
protected:
SessionPlaybackTest() {}
virtual ~SessionPlaybackTest() {}
virtual void SetUp() {
ipc_client_factory_.reset(new IPCClientFactoryMock);
ipc_client_.reset(reinterpret_cast<IPCClientMock *>(
ipc_client_factory_->NewClient("")));
client_.reset(new Client);
client_->SetIPCClientFactory(ipc_client_factory_.get());
server_launcher_ = new SessionPlaybackTestServerLauncher(
ipc_client_factory_.get());
client_->SetServerLauncher(server_launcher_);
}
virtual void TearDown() {
client_.reset();
ipc_client_factory_.reset();
}
bool SetupConnection(const int id) {
ipc_client_factory_->SetConnection(true);
ipc_client_factory_->SetResult(true);
ipc_client_factory_->SetServerProductVersion(Version::GetMozcVersion());
server_launcher_->set_start_server_result(true);
// TODO(komatsu): Due to the limitation of the testing mock,
// EnsureConnection should be explicitly called before calling
// SendKey. Fix the testing mock.
commands::Output mock_output;
mock_output.set_id(id);
SetMockOutput(mock_output);
return client_->EnsureConnection();
}
void SetMockOutput(const commands::Output &mock_output) {
string response;
mock_output.SerializeToString(&response);
ipc_client_factory_->SetMockResponse(response);
}
scoped_ptr<IPCClientFactoryMock> ipc_client_factory_;
scoped_ptr<IPCClientMock> ipc_client_;
scoped_ptr<Client> client_;
SessionPlaybackTestServerLauncher *server_launcher_;
private:
DISALLOW_COPY_AND_ASSIGN(SessionPlaybackTest);
};
// b/2797557
TEST_F(SessionPlaybackTest, PushAndResetHistoryWithNoModeTest) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
commands::Output mock_output;
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
vector<commands::Input> history;
client_->GetHistoryInputs(&history);
EXPECT_EQ(1, history.size());
mock_output.Clear();
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
mock_output.mutable_result()->set_type(commands::Result::STRING);
mock_output.mutable_result()->set_value("output");
EXPECT_FALSE(mock_output.has_mode());
SetMockOutput(mock_output);
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
// history should be reset.
client_->GetHistoryInputs(&history);
EXPECT_EQ(0, history.size());
}
// b/2797557
TEST_F(SessionPlaybackTest, PushAndResetHistoryWithModeTest) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
key_event.set_mode(commands::HIRAGANA);
key_event.set_activated(true);
commands::Output mock_output;
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
mock_output.set_mode(commands::HIRAGANA);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
EXPECT_TRUE(output.has_mode());
EXPECT_EQ(commands::HIRAGANA, output.mode());
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
EXPECT_TRUE(output.has_mode());
EXPECT_EQ(commands::HIRAGANA, output.mode());
vector<commands::Input> history;
client_->GetHistoryInputs(&history);
EXPECT_EQ(2, history.size());
mock_output.Clear();
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
mock_output.mutable_result()->set_type(commands::Result::STRING);
mock_output.mutable_result()->set_value("output");
SetMockOutput(mock_output);
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
client_->GetHistoryInputs(&history);
#ifdef OS_MACOSX
// history is reset, but initializer should be added because the last mode
// is not DIRECT.
// TODO(team): fix b/10250883 to remove this special treatment.
EXPECT_EQ(1, history.size());
// Implicit IMEOn key must be added. See b/2797557 and b/>10250883.
EXPECT_EQ(commands::Input::SEND_KEY, history[0].type());
EXPECT_EQ(commands::KeyEvent::ON, history[0].key().special_key());
EXPECT_EQ(commands::HIRAGANA, history[0].key().mode());
#else
// history is reset, but initializer is not required.
EXPECT_EQ(0, history.size());
#endif
}
// b/2797557
TEST_F(SessionPlaybackTest, PushAndResetHistoryWithDirectTest) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
commands::Output mock_output;
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
mock_output.set_mode(commands::DIRECT);
SetMockOutput(mock_output);
commands::Output output;
// Send key twice
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
EXPECT_TRUE(output.has_mode());
EXPECT_EQ(commands::DIRECT, output.mode());
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
EXPECT_TRUE(output.has_mode());
EXPECT_EQ(commands::DIRECT, output.mode());
vector<commands::Input> history;
client_->GetHistoryInputs(&history);
EXPECT_EQ(2, history.size());
mock_output.Clear();
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
mock_output.mutable_result()->set_type(commands::Result::STRING);
mock_output.mutable_result()->set_value("output");
SetMockOutput(mock_output);
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
// history is reset, and initializer should not be added.
client_->GetHistoryInputs(&history);
EXPECT_EQ(0, history.size());
}
TEST_F(SessionPlaybackTest, PlaybackHistoryTest) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
// On Windows, mode initializer should be added if the output contains mode.
commands::Output mock_output;
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
vector<commands::Input> history;
client_->GetHistoryInputs(&history);
EXPECT_EQ(2, history.size());
// Invalid id
const int new_id = 456;
mock_output.set_id(new_id);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->SendKey(key_event, &output));
#ifndef DEBUG
// PlaybackHistory and push history
client_->GetHistoryInputs(&history);
EXPECT_EQ(3, history.size());
#else
// PlaybackHistory, dump history(including reset), and add last input
client_->GetHistoryInputs(&history);
EXPECT_EQ(1, history.size());
#endif
}
// b/2797557
TEST_F(SessionPlaybackTest, SetModeInitializerTest) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
commands::Output mock_output;
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
mock_output.set_mode(commands::HIRAGANA);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
mock_output.set_mode(commands::DIRECT);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
EXPECT_TRUE(output.has_mode());
EXPECT_EQ(commands::DIRECT, output.mode());
mock_output.set_mode(commands::FULL_KATAKANA);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
EXPECT_TRUE(output.has_mode());
EXPECT_EQ(commands::FULL_KATAKANA, output.mode());
vector<commands::Input> history;
client_->GetHistoryInputs(&history);
EXPECT_EQ(3, history.size());
mock_output.Clear();
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
mock_output.mutable_result()->set_type(commands::Result::STRING);
mock_output.mutable_result()->set_value("output");
SetMockOutput(mock_output);
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
client_->GetHistoryInputs(&history);
#ifdef OS_MACOSX
// history is reset, but initializer should be added.
// TODO(team): fix b/10250883 to remove this special treatment.
EXPECT_EQ(1, history.size());
EXPECT_EQ(commands::Input::SEND_KEY, history[0].type());
EXPECT_EQ(commands::KeyEvent::ON, history[0].key().special_key());
EXPECT_EQ(commands::FULL_KATAKANA, history[0].key().mode());
#else
// history is reset, but initializer is not required.
EXPECT_EQ(0, history.size());
#endif
}
TEST_F(SessionPlaybackTest, ConsumedTest) {
const int mock_id = 123;
EXPECT_TRUE(SetupConnection(mock_id));
commands::KeyEvent key_event;
key_event.set_special_key(commands::KeyEvent::ENTER);
commands::Output mock_output;
mock_output.set_id(mock_id);
mock_output.set_consumed(true);
SetMockOutput(mock_output);
commands::Output output;
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
vector<commands::Input> history;
client_->GetHistoryInputs(&history);
EXPECT_EQ(2, history.size());
mock_output.set_consumed(false);
SetMockOutput(mock_output);
EXPECT_TRUE(client_->SendKey(key_event, &output));
EXPECT_EQ(mock_output.consumed(), output.consumed());
// Do not push unconsumed input
client_->GetHistoryInputs(&history);
EXPECT_EQ(2, history.size());
}
} // namespace client
} // namespace mozc