blob: 59b99589e2e5d1404e017ec502d8987fdf86e06e [file] [log] [blame] [edit]
// Copyright (c) 2012 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 "base/bind.h"
#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/speech/speech_input_extension_api.h"
#include "chrome/browser/speech/speech_input_extension_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/speech_recognition_event_listener.h"
#include "content/public/common/speech_recognition_error.h"
#include "content/public/common/speech_recognition_result.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::BrowserThread;
namespace net {
class URLRequestContextGetter;
}
namespace {
const int kSessionIDForTests = 0;
}
// Mock class used to test the extension speech input API.
class SpeechInputExtensionApiTest : public ExtensionApiTest,
public SpeechInputExtensionInterface {
public:
SpeechInputExtensionApiTest();
virtual ~SpeechInputExtensionApiTest();
void SetRecordingDevicesAvailable(bool available) {
recording_devices_available_ = available;
}
void SetRecognitionError(content::SpeechRecognitionErrorCode error) {
next_error_ = error;
}
void SetRecognitionResult(const content::SpeechRecognitionResult& result) {
next_result_ = result;
}
void SetRecognitionDelay(int result_delay_ms) {
result_delay_ms_ = result_delay_ms;
}
// Used as delay when the corresponding call should not be dispatched.
static const int kDontDispatchCall = -1;
// InProcessBrowserTest methods.
virtual void SetUpOnMainThread() OVERRIDE {
manager_ = SpeechInputExtensionManager::GetForProfile(browser()->profile());
}
// ExtensionApiTest methods.
virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
ExtensionApiTest::SetUpCommandLine(command_line);
command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
}
// SpeechInputExtensionInterface methods.
virtual bool HasAudioInputDevices() OVERRIDE {
return recording_devices_available_;
}
virtual bool IsCapturingAudio() OVERRIDE {
// Only the mock recognizer is supposed to be recording during testing.
return HasValidRecognizer();
}
virtual bool HasValidRecognizer() OVERRIDE {
return recognizer_is_valid_;
}
virtual void StartRecording(
content::SpeechRecognitionEventListener* listener,
net::URLRequestContextGetter* context_getter,
const std::string& extension_name,
const std::string& language,
const std::string& grammar,
bool filter_profanities,
int render_process_id) OVERRIDE;
virtual void StopRecording(bool recognition_failed) OVERRIDE;
SpeechInputExtensionManager* GetManager() {
return manager_.get();
}
// Auxiliary class used to hook the API manager into the test during its
// lifetime. Required since browser() is not available during the set up
// or tear down callbacks, or during the test class construction.
class AutoManagerHook {
public:
explicit AutoManagerHook(SpeechInputExtensionApiTest* test)
: test_(test) {
test_->GetManager()->SetSpeechInputExtensionInterface(test_);
}
~AutoManagerHook() {
test_->GetManager()->SetSpeechInputExtensionInterface(NULL);
}
private:
SpeechInputExtensionApiTest* test_;
};
private:
void ProvideResults();
bool recording_devices_available_;
bool recognizer_is_valid_;
content::SpeechRecognitionErrorCode next_error_;
content::SpeechRecognitionResult next_result_;
int result_delay_ms_;
scoped_refptr<SpeechInputExtensionManager> manager_;
};
SpeechInputExtensionApiTest::SpeechInputExtensionApiTest()
: recording_devices_available_(true),
recognizer_is_valid_(false),
next_error_(content::SPEECH_RECOGNITION_ERROR_NONE),
result_delay_ms_(0) {
}
SpeechInputExtensionApiTest::~SpeechInputExtensionApiTest() {
}
void SpeechInputExtensionApiTest::StartRecording(
content::SpeechRecognitionEventListener* listener,
net::URLRequestContextGetter* context_getter,
const std::string& extension_name,
const std::string& language,
const std::string& grammar,
bool filter_profanities,
int render_process_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
recognizer_is_valid_ = true;
// Notify that recording started.
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&SpeechInputExtensionManager::OnAudioStart,
GetManager(),
kSessionIDForTests),
base::TimeDelta());
// Notify sound start in the input device.
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&SpeechInputExtensionManager::OnSoundStart,
GetManager(),
kSessionIDForTests),
base::TimeDelta());
if (result_delay_ms_ != kDontDispatchCall) {
// Dispatch the recognition results.
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&SpeechInputExtensionApiTest::ProvideResults, this),
base::TimeDelta::FromMilliseconds(result_delay_ms_));
}
}
void SpeechInputExtensionApiTest::StopRecording(bool recognition_failed) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
recognizer_is_valid_ = false;
}
void SpeechInputExtensionApiTest::ProvideResults() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (next_error_ != content::SPEECH_RECOGNITION_ERROR_NONE) {
GetManager()->OnRecognitionError(
kSessionIDForTests, content::SpeechRecognitionError(next_error_));
return;
}
GetManager()->OnSoundEnd(kSessionIDForTests);
GetManager()->OnAudioEnd(kSessionIDForTests);
GetManager()->OnRecognitionResult(kSessionIDForTests, next_result_);
GetManager()->OnRecognitionEnd(kSessionIDForTests);
}
// Every test should leave the manager in the idle state when finished.
IN_PROC_BROWSER_TEST_F(SpeechInputExtensionApiTest, StartStopTest) {
AutoManagerHook hook(this);
SetRecognitionDelay(kDontDispatchCall);
ASSERT_TRUE(RunExtensionTest("speech_input/start_stop")) << message_;
}
IN_PROC_BROWSER_TEST_F(SpeechInputExtensionApiTest, NoDevicesAvailable) {
AutoManagerHook hook(this);
SetRecordingDevicesAvailable(false);
ASSERT_TRUE(RunExtensionTest("speech_input/start_error")) << message_;
}
IN_PROC_BROWSER_TEST_F(SpeechInputExtensionApiTest, RecognitionSuccessful) {
AutoManagerHook hook(this);
content::SpeechRecognitionResult result;
result.hypotheses.push_back(
content::SpeechRecognitionHypothesis(
UTF8ToUTF16("this is a test"), 0.99));
SetRecognitionResult(result);
ASSERT_TRUE(RunExtensionTest("speech_input/recognition")) << message_;
}
IN_PROC_BROWSER_TEST_F(SpeechInputExtensionApiTest, RecognitionError) {
AutoManagerHook hook(this);
SetRecognitionError(content::SPEECH_RECOGNITION_ERROR_NETWORK);
ASSERT_TRUE(RunExtensionTest("speech_input/recognition_error")) << message_;
}