1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "base/command_line.h"
7 #include "base/message_loop.h"
8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/extensions/extension_apitest.h"
10 #include "chrome/browser/speech/speech_input_extension_api.h"
11 #include "chrome/browser/speech/speech_input_extension_manager.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/common/chrome_notification_types.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "content/public/browser/speech_recognition_event_listener.h"
16 #include "content/public/common/speech_recognition_error.h"
17 #include "content/public/common/speech_recognition_result.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 using content::BrowserThread
;
23 class URLRequestContextGetter
;
27 const int kSessionIDForTests
= 0;
30 // Mock class used to test the extension speech input API.
31 class SpeechInputExtensionApiTest
: public ExtensionApiTest
,
32 public SpeechInputExtensionInterface
{
34 SpeechInputExtensionApiTest();
35 virtual ~SpeechInputExtensionApiTest();
37 void SetRecordingDevicesAvailable(bool available
) {
38 recording_devices_available_
= available
;
41 void SetRecognitionError(content::SpeechRecognitionErrorCode error
) {
45 void SetRecognitionResult(const content::SpeechRecognitionResult
& result
) {
46 next_result_
= result
;
49 void SetRecognitionDelay(int result_delay_ms
) {
50 result_delay_ms_
= result_delay_ms
;
53 // Used as delay when the corresponding call should not be dispatched.
54 static const int kDontDispatchCall
= -1;
56 // InProcessBrowserTest methods.
57 virtual void SetUpOnMainThread() OVERRIDE
{
58 manager_
= SpeechInputExtensionManager::GetForProfile(browser()->profile());
61 // ExtensionApiTest methods.
62 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
63 ExtensionApiTest::SetUpCommandLine(command_line
);
64 command_line
->AppendSwitch(switches::kEnableExperimentalExtensionApis
);
67 // SpeechInputExtensionInterface methods.
68 virtual bool HasAudioInputDevices() OVERRIDE
{
69 return recording_devices_available_
;
72 virtual bool IsCapturingAudio() OVERRIDE
{
73 // Only the mock recognizer is supposed to be recording during testing.
74 return HasValidRecognizer();
77 virtual bool HasValidRecognizer() OVERRIDE
{
78 return recognizer_is_valid_
;
81 virtual void StartRecording(
82 content::SpeechRecognitionEventListener
* listener
,
83 net::URLRequestContextGetter
* context_getter
,
84 const std::string
& extension_name
,
85 const std::string
& language
,
86 const std::string
& grammar
,
87 bool filter_profanities
,
88 int render_process_id
) OVERRIDE
;
90 virtual void StopRecording(bool recognition_failed
) OVERRIDE
;
92 SpeechInputExtensionManager
* GetManager() {
93 return manager_
.get();
96 // Auxiliary class used to hook the API manager into the test during its
97 // lifetime. Required since browser() is not available during the set up
98 // or tear down callbacks, or during the test class construction.
99 class AutoManagerHook
{
101 explicit AutoManagerHook(SpeechInputExtensionApiTest
* test
)
103 test_
->GetManager()->SetSpeechInputExtensionInterface(test_
);
107 test_
->GetManager()->SetSpeechInputExtensionInterface(NULL
);
111 SpeechInputExtensionApiTest
* test_
;
115 void ProvideResults();
117 bool recording_devices_available_
;
118 bool recognizer_is_valid_
;
119 content::SpeechRecognitionErrorCode next_error_
;
120 content::SpeechRecognitionResult next_result_
;
121 int result_delay_ms_
;
123 scoped_refptr
<SpeechInputExtensionManager
> manager_
;
126 SpeechInputExtensionApiTest::SpeechInputExtensionApiTest()
127 : recording_devices_available_(true),
128 recognizer_is_valid_(false),
129 next_error_(content::SPEECH_RECOGNITION_ERROR_NONE
),
130 result_delay_ms_(0) {
133 SpeechInputExtensionApiTest::~SpeechInputExtensionApiTest() {
136 void SpeechInputExtensionApiTest::StartRecording(
137 content::SpeechRecognitionEventListener
* listener
,
138 net::URLRequestContextGetter
* context_getter
,
139 const std::string
& extension_name
,
140 const std::string
& language
,
141 const std::string
& grammar
,
142 bool filter_profanities
,
143 int render_process_id
) {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
145 recognizer_is_valid_
= true;
147 // Notify that recording started.
148 MessageLoop::current()->PostDelayedTask(
150 base::Bind(&SpeechInputExtensionManager::OnAudioStart
,
155 // Notify sound start in the input device.
156 MessageLoop::current()->PostDelayedTask(
158 base::Bind(&SpeechInputExtensionManager::OnSoundStart
,
163 if (result_delay_ms_
!= kDontDispatchCall
) {
164 // Dispatch the recognition results.
165 MessageLoop::current()->PostDelayedTask(
167 base::Bind(&SpeechInputExtensionApiTest::ProvideResults
, this),
168 base::TimeDelta::FromMilliseconds(result_delay_ms_
));
172 void SpeechInputExtensionApiTest::StopRecording(bool recognition_failed
) {
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
174 recognizer_is_valid_
= false;
177 void SpeechInputExtensionApiTest::ProvideResults() {
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
180 if (next_error_
!= content::SPEECH_RECOGNITION_ERROR_NONE
) {
181 GetManager()->OnRecognitionError(
182 kSessionIDForTests
, content::SpeechRecognitionError(next_error_
));
186 GetManager()->OnSoundEnd(kSessionIDForTests
);
187 GetManager()->OnAudioEnd(kSessionIDForTests
);
188 content::SpeechRecognitionResults results
;
189 results
.push_back(next_result_
);
190 GetManager()->OnRecognitionResults(kSessionIDForTests
, results
);
191 GetManager()->OnRecognitionEnd(kSessionIDForTests
);
194 // Every test should leave the manager in the idle state when finished.
195 IN_PROC_BROWSER_TEST_F(SpeechInputExtensionApiTest
, StartStopTest
) {
196 AutoManagerHook
hook(this);
198 SetRecognitionDelay(kDontDispatchCall
);
199 ASSERT_TRUE(RunExtensionTest("speech_input/start_stop")) << message_
;
202 IN_PROC_BROWSER_TEST_F(SpeechInputExtensionApiTest
, NoDevicesAvailable
) {
203 AutoManagerHook
hook(this);
205 SetRecordingDevicesAvailable(false);
206 ASSERT_TRUE(RunExtensionTest("speech_input/start_error")) << message_
;
209 IN_PROC_BROWSER_TEST_F(SpeechInputExtensionApiTest
, RecognitionSuccessful
) {
210 AutoManagerHook
hook(this);
212 content::SpeechRecognitionResult result
;
213 result
.hypotheses
.push_back(
214 content::SpeechRecognitionHypothesis(
215 UTF8ToUTF16("this is a test"), 0.99));
216 SetRecognitionResult(result
);
217 ASSERT_TRUE(RunExtensionTest("speech_input/recognition")) << message_
;
220 IN_PROC_BROWSER_TEST_F(SpeechInputExtensionApiTest
, RecognitionError
) {
221 AutoManagerHook
hook(this);
223 SetRecognitionError(content::SPEECH_RECOGNITION_ERROR_NETWORK
);
224 ASSERT_TRUE(RunExtensionTest("speech_input/recognition_error")) << message_
;