| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/speech/speech_recognition_test_helper.h" |
| |
| #include "ash/constants/ash_features.h" |
| #include "base/functional/bind.h" |
| #include "base/run_loop.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/speech/cros_speech_recognition_service_factory.h" |
| #include "chrome/browser/speech/fake_speech_recognition_service.h" |
| #include "chrome/browser/speech/fake_speech_recognizer.h" |
| #include "chrome/browser/speech/speech_recognition_constants.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| #include "components/soda/soda_installer.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/test/fake_speech_recognition_manager.h" |
| #include "media/mojo/mojom/speech_recognition.mojom.h" |
| |
| SpeechRecognitionTestHelper::SpeechRecognitionTestHelper( |
| speech::SpeechRecognitionType type, |
| media::mojom::RecognizerClientType client_type) |
| : feature_under_test_(client_type), type_(type) {} |
| SpeechRecognitionTestHelper::~SpeechRecognitionTestHelper() = default; |
| |
| void SpeechRecognitionTestHelper::SetUp(Profile* profile) { |
| if (type_ == speech::SpeechRecognitionType::kNetwork) |
| SetUpNetworkRecognition(); |
| else |
| SetUpOnDeviceRecognition(profile); |
| } |
| |
| void SpeechRecognitionTestHelper::SetUpNetworkRecognition() { |
| fake_speech_recognition_manager_ = |
| std::make_unique<content::FakeSpeechRecognitionManager>(); |
| fake_speech_recognition_manager_->set_should_send_fake_response(false); |
| content::SpeechRecognitionManager::SetManagerForTesting( |
| fake_speech_recognition_manager_.get()); |
| } |
| |
| void SpeechRecognitionTestHelper::SetUpOnDeviceRecognition(Profile* profile) { |
| // Fake that SODA is installed so SpeechRecognitionPrivate uses |
| // OnDeviceSpeechRecognizer. |
| speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting( |
| speech::LanguageCode::kEnUs); |
| speech::SodaInstaller::GetInstance()->NotifySodaInstalledForTesting(); |
| CrosSpeechRecognitionServiceFactory::GetInstanceForTest() |
| ->SetTestingFactoryAndUse( |
| profile, |
| base::BindRepeating(&SpeechRecognitionTestHelper:: |
| CreateTestOnDeviceSpeechRecognitionService, |
| base::Unretained(this))); |
| } |
| |
| void SpeechRecognitionTestHelper::OnRecognizerBound( |
| speech::FakeSpeechRecognizer* bound_recognizer) { |
| if (bound_recognizer->recognition_options()->recognizer_client_type == |
| feature_under_test_) { |
| fake_recognizer_ = bound_recognizer->GetWeakPtr(); |
| } |
| } |
| |
| std::unique_ptr<KeyedService> |
| SpeechRecognitionTestHelper::CreateTestOnDeviceSpeechRecognitionService( |
| content::BrowserContext* context) { |
| std::unique_ptr<speech::FakeSpeechRecognitionService> fake_service = |
| std::make_unique<speech::FakeSpeechRecognitionService>(); |
| fake_service_ = fake_service.get(); |
| fake_service_->AddObserver(this); |
| return std::move(fake_service); |
| } |
| |
| void SpeechRecognitionTestHelper::WaitForRecognitionStarted() { |
| // In the case of OnDevice recognition tests the fake_recognizer_ will not |
| // exist until events have propagated to the point that a recognition client |
| // impl is instantiated. So here we will wait for events to propagate in case |
| // the fake_recognizer_ needs to be instantiated. |
| base::RunLoop().RunUntilIdle(); |
| |
| // Only wait for recognition to start if it hasn't been started yet. |
| if (type_ == speech::SpeechRecognitionType::kNetwork && |
| !fake_speech_recognition_manager_->is_recognizing()) { |
| fake_speech_recognition_manager_->WaitForRecognitionStarted(); |
| } else if (type_ == speech::SpeechRecognitionType::kOnDevice && |
| fake_recognizer_ && !fake_recognizer_->is_capturing_audio()) { |
| fake_recognizer_->WaitForRecognitionStarted(); |
| } |
| |
| // Wait for any subsequent events to propagate. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void SpeechRecognitionTestHelper::WaitForRecognitionStopped() { |
| // Only wait for recognition to stop if it hasn't been stopped yet. |
| if (type_ == speech::SpeechRecognitionType::kNetwork && |
| fake_speech_recognition_manager_->is_recognizing()) { |
| fake_speech_recognition_manager_->WaitForRecognitionEnded(); |
| } |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void SpeechRecognitionTestHelper::SendInterimResultAndWait( |
| const std::string& transcript) { |
| SendFakeSpeechResultAndWait(transcript, /*is_final=*/false); |
| } |
| |
| void SpeechRecognitionTestHelper::SendFinalResultAndWait( |
| const std::string& transcript) { |
| SendFakeSpeechResultAndWait(transcript, /*is_final=*/true); |
| } |
| |
| void SpeechRecognitionTestHelper::SendFakeSpeechResultAndWait( |
| const std::string& transcript, |
| bool is_final) { |
| base::RunLoop loop; |
| if (type_ == speech::SpeechRecognitionType::kNetwork) { |
| fake_speech_recognition_manager_->SetFakeResult(transcript, is_final); |
| fake_speech_recognition_manager_->SendFakeResponse( |
| false /* end recognition */, loop.QuitClosure()); |
| loop.Run(); |
| } else { |
| CHECK(fake_recognizer_->is_capturing_audio()); |
| fake_recognizer_->SendSpeechRecognitionResult( |
| media::SpeechRecognitionResult(transcript, is_final)); |
| loop.RunUntilIdle(); |
| } |
| } |
| |
| void SpeechRecognitionTestHelper::SendErrorAndWait() { |
| base::RunLoop loop; |
| if (type_ == speech::SpeechRecognitionType::kNetwork) { |
| fake_speech_recognition_manager_->SendFakeError(loop.QuitClosure()); |
| loop.Run(); |
| } else { |
| CHECK(fake_recognizer_); |
| fake_recognizer_->SendSpeechRecognitionError(); |
| loop.RunUntilIdle(); |
| } |
| } |
| |
| std::vector<base::test::FeatureRef> |
| SpeechRecognitionTestHelper::GetEnabledFeatures() { |
| std::vector<base::test::FeatureRef> features; |
| if (type_ == speech::SpeechRecognitionType::kOnDevice) |
| features.push_back(ash::features::kOnDeviceSpeechRecognition); |
| return features; |
| } |
| |
| std::vector<base::test::FeatureRef> |
| SpeechRecognitionTestHelper::GetDisabledFeatures() { |
| std::vector<base::test::FeatureRef> features; |
| if (type_ == speech::SpeechRecognitionType::kNetwork) |
| features.push_back(ash::features::kOnDeviceSpeechRecognition); |
| return features; |
| } |