| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos/services/ime/ime_service.h" |
| |
| #include "base/bind.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/task_environment.h" |
| #include "chromeos/services/ime/public/mojom/input_engine.mojom.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "mojo/public/cpp/bindings/receiver.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using testing::_; |
| |
| namespace chromeos { |
| namespace ime { |
| |
| namespace { |
| |
| const char kInvalidImeSpec[] = "ime_spec_never_support"; |
| const std::vector<uint8_t> extra{0x66, 0x77, 0x88}; |
| |
| void ConnectCallback(bool* success, bool result) { |
| *success = result; |
| } |
| |
| void TestProcessKeypressForRulebasedCallback( |
| mojom::KeypressResponseForRulebased* res_out, |
| mojom::KeypressResponseForRulebasedPtr response) { |
| res_out->result = response->result; |
| res_out->operations = std::vector<mojom::OperationForRulebasedPtr>(0); |
| for (int i = 0; i < (int)response->operations.size(); i++) { |
| res_out->operations.push_back(std::move(response->operations[i])); |
| } |
| } |
| void TestGetRulebasedKeypressCountForTestingCallback(int32_t* res_out, |
| int32_t response) { |
| *res_out = response; |
| } |
| |
| class TestClientChannel : mojom::InputChannel { |
| public: |
| TestClientChannel() : receiver_(this) {} |
| |
| mojo::PendingRemote<mojom::InputChannel> CreatePendingRemote() { |
| return receiver_.BindNewPipeAndPassRemote(); |
| } |
| |
| // mojom::InputChannel implementation. |
| MOCK_METHOD2(ProcessText, void(const std::string&, ProcessTextCallback)); |
| MOCK_METHOD2(ProcessMessage, |
| void(const std::vector<uint8_t>& message, |
| ProcessMessageCallback)); |
| MOCK_METHOD2(ProcessKeypressForRulebased, |
| void(const mojom::KeypressInfoForRulebasedPtr message, |
| ProcessKeypressForRulebasedCallback)); |
| MOCK_METHOD0(ResetForRulebased, void()); |
| MOCK_METHOD1(GetRulebasedKeypressCountForTesting, |
| void(GetRulebasedKeypressCountForTestingCallback)); |
| |
| private: |
| mojo::Receiver<mojom::InputChannel> receiver_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestClientChannel); |
| }; |
| |
| class ImeServiceTest : public testing::Test { |
| public: |
| ImeServiceTest() : service_(remote_service_.BindNewPipeAndPassReceiver()) {} |
| ~ImeServiceTest() override = default; |
| |
| MOCK_METHOD1(SentTextCallback, void(const std::string&)); |
| MOCK_METHOD1(SentMessageCallback, void(const std::vector<uint8_t>&)); |
| |
| protected: |
| void SetUp() override { |
| remote_service_->BindInputEngineManager( |
| remote_manager_.BindNewPipeAndPassReceiver()); |
| } |
| |
| mojo::Remote<mojom::ImeService> remote_service_; |
| mojo::Remote<mojom::InputEngineManager> remote_manager_; |
| |
| private: |
| base::test::TaskEnvironment task_environment_; |
| ImeService service_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ImeServiceTest); |
| }; |
| |
| } // namespace |
| |
| // Tests that the service is instantiated and it will return false when |
| // activating an IME engine with an invalid IME spec. |
| TEST_F(ImeServiceTest, ConnectInvalidImeEngine) { |
| bool success = true; |
| TestClientChannel test_channel; |
| mojo::Remote<mojom::InputChannel> remote_engine; |
| |
| remote_manager_->ConnectToImeEngine( |
| kInvalidImeSpec, remote_engine.BindNewPipeAndPassReceiver(), |
| test_channel.CreatePendingRemote(), extra, |
| base::BindOnce(&ConnectCallback, &success)); |
| remote_manager_.FlushForTesting(); |
| EXPECT_FALSE(success); |
| } |
| |
| TEST_F(ImeServiceTest, MultipleClientsRulebased) { |
| bool success = false; |
| TestClientChannel test_channel_1; |
| TestClientChannel test_channel_2; |
| mojo::Remote<mojom::InputChannel> remote_engine_1; |
| mojo::Remote<mojom::InputChannel> remote_engine_2; |
| |
| remote_manager_->ConnectToImeEngine( |
| "m17n:ar", remote_engine_1.BindNewPipeAndPassReceiver(), |
| test_channel_1.CreatePendingRemote(), extra, |
| base::BindOnce(&ConnectCallback, &success)); |
| remote_manager_.FlushForTesting(); |
| |
| remote_manager_->ConnectToImeEngine( |
| "m17n:ar", remote_engine_2.BindNewPipeAndPassReceiver(), |
| test_channel_2.CreatePendingRemote(), extra, |
| base::BindOnce(&ConnectCallback, &success)); |
| remote_manager_.FlushForTesting(); |
| |
| mojom::KeypressResponseForRulebased response; |
| mojom::KeypressInfoForRulebasedPtr keypress_info = |
| mojom::KeypressInfoForRulebased::New("keydown", "KeyA", true, false, |
| false, false, false); |
| remote_engine_1->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "KeyA", true, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| remote_engine_1.FlushForTesting(); |
| |
| remote_engine_2->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "KeyA", true, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| remote_engine_2.FlushForTesting(); |
| |
| int32_t count; |
| remote_engine_1->GetRulebasedKeypressCountForTesting( |
| base::BindOnce(&TestGetRulebasedKeypressCountForTestingCallback, &count)); |
| remote_engine_1.FlushForTesting(); |
| EXPECT_EQ(1, count); |
| |
| remote_engine_2->GetRulebasedKeypressCountForTesting( |
| base::BindOnce(&TestGetRulebasedKeypressCountForTestingCallback, &count)); |
| remote_engine_2.FlushForTesting(); |
| EXPECT_EQ(1, count); |
| } |
| |
| // Tests that the rule-based Arabic keyboard can work correctly. |
| TEST_F(ImeServiceTest, RuleBasedArabic) { |
| bool success = false; |
| TestClientChannel test_channel; |
| mojo::Remote<mojom::InputChannel> to_engine_remote; |
| |
| remote_manager_->ConnectToImeEngine( |
| "m17n:ar", to_engine_remote.BindNewPipeAndPassReceiver(), |
| test_channel.CreatePendingRemote(), extra, |
| base::BindOnce(&ConnectCallback, &success)); |
| remote_manager_.FlushForTesting(); |
| EXPECT_TRUE(success); |
| |
| // Test Shift+KeyA. |
| mojom::KeypressResponseForRulebased response; |
| to_engine_remote->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "KeyA", true, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| to_engine_remote.FlushForTesting(); |
| |
| EXPECT_EQ(response.result, true); |
| std::vector<mojom::OperationForRulebasedPtr> expected_operations; |
| expected_operations.push_back({mojom::OperationForRulebased::New( |
| mojom::OperationMethodForRulebased::COMMIT_TEXT, "\u0650")}); |
| EXPECT_EQ(response.operations.size(), expected_operations.size()); |
| EXPECT_EQ(response.operations, expected_operations); |
| |
| // Test KeyB |
| to_engine_remote->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "KeyB", false, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| to_engine_remote.FlushForTesting(); |
| EXPECT_EQ(response.result, true); |
| expected_operations = std::vector<mojom::OperationForRulebasedPtr>(0); |
| expected_operations.push_back({mojom::OperationForRulebased::New( |
| mojom::OperationMethodForRulebased::COMMIT_TEXT, "\u0644\u0627")}); |
| EXPECT_EQ(response.operations.size(), expected_operations.size()); |
| EXPECT_EQ(response.operations, expected_operations); |
| |
| // Test unhandled key. |
| to_engine_remote->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "Enter", false, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| to_engine_remote.FlushForTesting(); |
| EXPECT_EQ(response.result, false); |
| |
| // Test keyup. |
| to_engine_remote->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keyup", "Enter", false, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| to_engine_remote.FlushForTesting(); |
| EXPECT_EQ(response.result, false); |
| |
| // TODO(keithlee) Test reset function |
| to_engine_remote->ResetForRulebased(); |
| |
| // Test invalid request. |
| to_engine_remote->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "", false, false, false, |
| false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| to_engine_remote.FlushForTesting(); |
| EXPECT_EQ(response.result, false); |
| } |
| |
| // Tests that the rule-based DevaPhone keyboard can work correctly. |
| TEST_F(ImeServiceTest, RuleBasedDevaPhone) { |
| bool success = false; |
| TestClientChannel test_channel; |
| mojo::Remote<mojom::InputChannel> to_engine_remote; |
| |
| remote_manager_->ConnectToImeEngine( |
| "m17n:deva_phone", to_engine_remote.BindNewPipeAndPassReceiver(), |
| test_channel.CreatePendingRemote(), extra, |
| base::BindOnce(&ConnectCallback, &success)); |
| remote_manager_.FlushForTesting(); |
| EXPECT_TRUE(success); |
| |
| mojom::KeypressResponseForRulebased response; |
| std::vector<mojom::OperationForRulebasedPtr> expected_operations; |
| |
| // Test KeyN. |
| to_engine_remote->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "KeyN", false, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| to_engine_remote.FlushForTesting(); |
| |
| EXPECT_EQ(response.result, true); |
| expected_operations = std::vector<mojom::OperationForRulebasedPtr>(0); |
| expected_operations.push_back({mojom::OperationForRulebased::New( |
| mojom::OperationMethodForRulebased::SET_COMPOSITION, "\u0928")}); |
| EXPECT_EQ(response.operations.size(), expected_operations.size()); |
| EXPECT_EQ(response.operations, expected_operations); |
| |
| // Backspace. |
| to_engine_remote->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "Backspace", false, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| to_engine_remote.FlushForTesting(); |
| |
| EXPECT_EQ(response.result, true); |
| expected_operations = std::vector<mojom::OperationForRulebasedPtr>(0); |
| expected_operations.push_back({mojom::OperationForRulebased::New( |
| mojom::OperationMethodForRulebased::SET_COMPOSITION, "")}); |
| EXPECT_EQ(response.operations.size(), expected_operations.size()); |
| EXPECT_EQ(response.operations, expected_operations); |
| |
| // KeyN + KeyC. |
| to_engine_remote->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "KeyN", false, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| to_engine_remote->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "KeyC", false, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| to_engine_remote.FlushForTesting(); |
| |
| EXPECT_EQ(response.result, true); |
| expected_operations = std::vector<mojom::OperationForRulebasedPtr>(0); |
| expected_operations.push_back({mojom::OperationForRulebased::New( |
| mojom::OperationMethodForRulebased::SET_COMPOSITION, |
| "\u091e\u094d\u091a")}); |
| EXPECT_EQ(response.operations.size(), expected_operations.size()); |
| EXPECT_EQ(response.operations, expected_operations); |
| |
| // Space. |
| to_engine_remote->ProcessKeypressForRulebased( |
| mojom::KeypressInfoForRulebased::New("keydown", "Space", false, false, |
| false, false, false), |
| base::BindOnce(&TestProcessKeypressForRulebasedCallback, &response)); |
| to_engine_remote.FlushForTesting(); |
| |
| EXPECT_EQ(response.result, true); |
| expected_operations = std::vector<mojom::OperationForRulebasedPtr>(0); |
| expected_operations.push_back({mojom::OperationForRulebased::New( |
| mojom::OperationMethodForRulebased::COMMIT_TEXT, "\u091e\u094d\u091a ")}); |
| EXPECT_EQ(response.operations.size(), expected_operations.size()); |
| EXPECT_EQ(response.operations, expected_operations); |
| } |
| |
| } // namespace ime |
| } // namespace chromeos |