| // Copyright 2019 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 "ash/components/quick_answers/quick_answers_client.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "ash/components/quick_answers/quick_answers_model.h" |
| #include "ash/components/quick_answers/test/test_helpers.h" |
| #include "ash/components/quick_answers/utils/quick_answers_utils.h" |
| #include "ash/constants/ash_features.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/task_environment.h" |
| #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace chromeos { |
| namespace quick_answers { |
| |
| namespace { |
| |
| class TestResultLoader : public ResultLoader { |
| public: |
| TestResultLoader(network::mojom::URLLoaderFactory* url_loader_factory, |
| ResultLoaderDelegate* delegate) |
| : ResultLoader(url_loader_factory, delegate) {} |
| // ResultLoader: |
| void BuildRequest(const PreprocessedOutput& preprocessed_output, |
| BuildRequestCallback callback) const override { |
| return std::move(callback).Run(std::make_unique<network::ResourceRequest>(), |
| std::string()); |
| } |
| void ProcessResponse(const PreprocessedOutput& preprocessed_output, |
| std::unique_ptr<std::string> response_body, |
| ResponseParserCallback complete_callback) override {} |
| }; |
| |
| class MockResultLoader : public TestResultLoader { |
| public: |
| MockResultLoader(network::mojom::URLLoaderFactory* url_loader_factory, |
| ResultLoaderDelegate* delegate) |
| : TestResultLoader(url_loader_factory, delegate) {} |
| |
| MockResultLoader(const MockResultLoader&) = delete; |
| MockResultLoader& operator=(const MockResultLoader&) = delete; |
| |
| // TestResultLoader: |
| MOCK_METHOD1(Fetch, void(const PreprocessedOutput&)); |
| }; |
| |
| MATCHER_P(QuickAnswersRequestWithOutputEqual, quick_answers_request, "") { |
| return ( |
| arg.selected_text == quick_answers_request.selected_text && |
| arg.preprocessed_output.intent_info.intent_type == |
| quick_answers_request.preprocessed_output.intent_info.intent_type && |
| arg.preprocessed_output.intent_info.intent_text == |
| quick_answers_request.preprocessed_output.intent_info.intent_text && |
| arg.preprocessed_output.query == |
| quick_answers_request.preprocessed_output.query); |
| } |
| |
| class MockIntentGenerator : public IntentGenerator { |
| public: |
| explicit MockIntentGenerator(IntentGeneratorCallback complete_callback) |
| : IntentGenerator(std::move(complete_callback)) {} |
| |
| MockIntentGenerator(const MockIntentGenerator&) = delete; |
| MockIntentGenerator& operator=(const MockIntentGenerator&) = delete; |
| |
| // IntentGenerator: |
| MOCK_METHOD1(GenerateIntent, void(const QuickAnswersRequest&)); |
| }; |
| |
| } // namespace |
| |
| class QuickAnswersClientTest : public testing::Test { |
| public: |
| QuickAnswersClientTest() = default; |
| |
| QuickAnswersClientTest(const QuickAnswersClientTest&) = delete; |
| QuickAnswersClientTest& operator=(const QuickAnswersClientTest&) = delete; |
| |
| // Testing::Test: |
| void SetUp() override { |
| mock_delegate_ = std::make_unique<MockQuickAnswersDelegate>(); |
| |
| client_ = std::make_unique<QuickAnswersClient>(&test_url_loader_factory_, |
| mock_delegate_.get()); |
| |
| result_loader_factory_callback_ = base::BindRepeating( |
| &QuickAnswersClientTest::CreateResultLoader, base::Unretained(this)); |
| |
| intent_generator_factory_callback_ = base::BindRepeating( |
| &QuickAnswersClientTest::CreateIntentGenerator, base::Unretained(this)); |
| |
| mock_intent_generator_ = std::make_unique<MockIntentGenerator>( |
| base::BindOnce(&QuickAnswersClientTest::IntentGeneratorTestCallback, |
| base::Unretained(this))); |
| } |
| |
| void TearDown() override { |
| QuickAnswersClient::SetResultLoaderFactoryForTesting(nullptr); |
| QuickAnswersClient::SetIntentGeneratorFactoryForTesting(nullptr); |
| client_.reset(); |
| } |
| |
| void IntentGeneratorTestCallback(const IntentInfo& intent_info) {} |
| |
| protected: |
| std::unique_ptr<ResultLoader> CreateResultLoader() { |
| return std::move(mock_result_loader_); |
| } |
| |
| std::unique_ptr<IntentGenerator> CreateIntentGenerator() { |
| return std::move(mock_intent_generator_); |
| } |
| |
| std::unique_ptr<QuickAnswersClient> client_; |
| std::unique_ptr<MockQuickAnswersDelegate> mock_delegate_; |
| std::unique_ptr<MockResultLoader> mock_result_loader_; |
| std::unique_ptr<MockIntentGenerator> mock_intent_generator_; |
| base::test::SingleThreadTaskEnvironment task_environment_; |
| network::TestURLLoaderFactory test_url_loader_factory_; |
| QuickAnswersClient::ResultLoaderFactoryCallback |
| result_loader_factory_callback_; |
| QuickAnswersClient::IntentGeneratorFactoryCallback |
| intent_generator_factory_callback_; |
| IntentGenerator::IntentGeneratorCallback intent_generator_callback_; |
| }; |
| |
| TEST_F(QuickAnswersClientTest, NetworkError) { |
| // Verify that OnNetworkError is called. |
| EXPECT_CALL(*mock_delegate_, OnNetworkError()); |
| EXPECT_CALL(*mock_delegate_, OnQuickAnswerReceived(::testing::_)).Times(0); |
| |
| client_->OnNetworkError(); |
| } |
| |
| TEST_F(QuickAnswersClientTest, SendRequest) { |
| std::unique_ptr<QuickAnswersRequest> quick_answers_request = |
| std::make_unique<QuickAnswersRequest>(); |
| quick_answers_request->selected_text = "sel"; |
| |
| // Verify that |GenerateIntent| is called. |
| EXPECT_CALL(*mock_intent_generator_, |
| GenerateIntent(QuickAnswersRequestEqual(*quick_answers_request))); |
| QuickAnswersClient::SetIntentGeneratorFactoryForTesting( |
| &intent_generator_factory_callback_); |
| |
| mock_result_loader_ = |
| std::make_unique<MockResultLoader>(&test_url_loader_factory_, nullptr); |
| EXPECT_CALL(*mock_result_loader_, |
| Fetch(PreprocessedOutputEqual(PreprocessRequest( |
| IntentInfo("sel", IntentType::kDictionary))))); |
| QuickAnswersClient::SetResultLoaderFactoryForTesting( |
| &result_loader_factory_callback_); |
| |
| client_->SendRequest(*quick_answers_request); |
| client_->IntentGeneratorCallback(*quick_answers_request, /*skip_fetch=*/false, |
| IntentInfo("sel", IntentType::kDictionary)); |
| |
| std::unique_ptr<QuickAnswer> quick_answer = std::make_unique<QuickAnswer>(); |
| quick_answer->first_answer_row.push_back( |
| std::make_unique<QuickAnswerResultText>("answer")); |
| EXPECT_CALL(*mock_delegate_, |
| OnQuickAnswerReceived(QuickAnswerEqual(&(*quick_answer)))); |
| client_->OnQuickAnswerReceived(std::move(quick_answer)); |
| } |
| |
| TEST_F(QuickAnswersClientTest, SendRequestForPreprocessing) { |
| std::unique_ptr<QuickAnswersRequest> quick_answers_request = |
| std::make_unique<QuickAnswersRequest>(); |
| quick_answers_request->selected_text = "sel"; |
| |
| // Verify that |GenerateIntent| is called. |
| EXPECT_CALL(*mock_intent_generator_, |
| GenerateIntent(QuickAnswersRequestEqual(*quick_answers_request))); |
| QuickAnswersClient::SetIntentGeneratorFactoryForTesting( |
| &intent_generator_factory_callback_); |
| |
| mock_result_loader_ = |
| std::make_unique<MockResultLoader>(&test_url_loader_factory_, nullptr); |
| EXPECT_CALL(*mock_result_loader_, Fetch(::testing::_)).Times(0); |
| QuickAnswersClient::SetResultLoaderFactoryForTesting( |
| &result_loader_factory_callback_); |
| |
| client_->SendRequestForPreprocessing(*quick_answers_request); |
| } |
| |
| TEST_F(QuickAnswersClientTest, FetchQuickAnswers) { |
| std::unique_ptr<QuickAnswersRequest> quick_answers_request = |
| std::make_unique<QuickAnswersRequest>(); |
| quick_answers_request->preprocessed_output.query = "Define sel"; |
| |
| mock_result_loader_ = |
| std::make_unique<MockResultLoader>(&test_url_loader_factory_, nullptr); |
| EXPECT_CALL(*mock_result_loader_, |
| Fetch(PreprocessedOutputEqual( |
| quick_answers_request->preprocessed_output))); |
| QuickAnswersClient::SetResultLoaderFactoryForTesting( |
| &result_loader_factory_callback_); |
| |
| client_->FetchQuickAnswers(*quick_answers_request); |
| } |
| |
| TEST_F(QuickAnswersClientTest, PreprocessDefinitionIntent) { |
| std::unique_ptr<QuickAnswersRequest> quick_answers_request = |
| std::make_unique<QuickAnswersRequest>(); |
| quick_answers_request->selected_text = "unfathomable"; |
| |
| // Verify that |OnRequestPreprocessFinished| is called. |
| std::unique_ptr<QuickAnswersRequest> processed_request = |
| std::make_unique<QuickAnswersRequest>(); |
| processed_request->selected_text = "unfathomable"; |
| PreprocessedOutput expected_processed_output; |
| expected_processed_output.intent_info.intent_text = "unfathomable"; |
| expected_processed_output.query = "Define unfathomable"; |
| expected_processed_output.intent_info.intent_type = IntentType::kDictionary; |
| processed_request->preprocessed_output = expected_processed_output; |
| EXPECT_CALL(*mock_delegate_, |
| OnRequestPreprocessFinished( |
| QuickAnswersRequestWithOutputEqual(*processed_request))); |
| |
| client_->IntentGeneratorCallback( |
| *quick_answers_request, /*skip_fetch=*/false, |
| IntentInfo("unfathomable", IntentType::kDictionary)); |
| } |
| |
| TEST_F(QuickAnswersClientTest, PreprocessTranslationIntent) { |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndDisableFeature( |
| chromeos::features::kQuickAnswersTranslationCloudAPI); |
| std::unique_ptr<QuickAnswersRequest> quick_answers_request = |
| std::make_unique<QuickAnswersRequest>(); |
| quick_answers_request->selected_text = "sel"; |
| |
| // Verify that |OnRequestPreprocessFinished| is called. |
| std::unique_ptr<QuickAnswersRequest> processed_request = |
| std::make_unique<QuickAnswersRequest>(); |
| processed_request->selected_text = "sel"; |
| PreprocessedOutput expected_processed_output; |
| expected_processed_output.intent_info.intent_text = "intent text"; |
| expected_processed_output.query = "Translate:intent text"; |
| expected_processed_output.intent_info.intent_type = IntentType::kTranslation; |
| processed_request->preprocessed_output = expected_processed_output; |
| EXPECT_CALL(*mock_delegate_, |
| OnRequestPreprocessFinished( |
| QuickAnswersRequestWithOutputEqual(*processed_request))); |
| |
| client_->IntentGeneratorCallback( |
| *quick_answers_request, /*skip_fetch=*/false, |
| IntentInfo("intent text", IntentType::kTranslation)); |
| } |
| |
| TEST_F(QuickAnswersClientTest, PreprocessUnitConversionIntent) { |
| std::unique_ptr<QuickAnswersRequest> quick_answers_request = |
| std::make_unique<QuickAnswersRequest>(); |
| quick_answers_request->selected_text = "20ft"; |
| |
| // Verify that |OnRequestPreprocessFinished| is called. |
| std::unique_ptr<QuickAnswersRequest> processed_request = |
| std::make_unique<QuickAnswersRequest>(); |
| processed_request->selected_text = "20ft"; |
| PreprocessedOutput expected_processed_output; |
| expected_processed_output.intent_info.intent_text = "20ft"; |
| expected_processed_output.query = "Convert:20ft"; |
| expected_processed_output.intent_info.intent_type = IntentType::kUnit; |
| processed_request->preprocessed_output = expected_processed_output; |
| EXPECT_CALL(*mock_delegate_, |
| OnRequestPreprocessFinished( |
| QuickAnswersRequestWithOutputEqual(*processed_request))); |
| |
| client_->IntentGeneratorCallback(*quick_answers_request, /*skip_fetch=*/false, |
| IntentInfo("20ft", IntentType::kUnit)); |
| } |
| |
| } // namespace quick_answers |
| } // namespace chromeos |