| // 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 |