summaryrefslogtreecommitdiffstats
path: root/content/browser/speech/speech_recognition_browsertest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/speech/speech_recognition_browsertest.cc')
-rw-r--r--content/browser/speech/speech_recognition_browsertest.cc254
1 files changed, 254 insertions, 0 deletions
diff --git a/content/browser/speech/speech_recognition_browsertest.cc b/content/browser/speech/speech_recognition_browsertest.cc
new file mode 100644
index 0000000..0b56226
--- /dev/null
+++ b/content/browser/speech/speech_recognition_browsertest.cc
@@ -0,0 +1,254 @@
+// 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/file_path.h"
+#include "base/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/speech/input_tag_speech_dispatcher_host.h"
+#include "content/browser/speech/speech_recognition_manager_impl.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/speech_recognition_result.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
+
+using content::NavigationController;
+using content::WebContents;
+
+namespace speech {
+class FakeSpeechRecognitionManager;
+}
+
+namespace speech {
+
+const char kTestResult[] = "Pictures of the moon";
+
+class FakeSpeechRecognitionManager : public SpeechRecognitionManagerImpl {
+ public:
+ FakeSpeechRecognitionManager()
+ : caller_id_(0),
+ delegate_(NULL),
+ did_cancel_all_(false),
+ should_send_fake_response_(true),
+ recognition_started_event_(false, false) {
+ }
+
+ std::string grammar() {
+ return grammar_;
+ }
+
+ bool did_cancel_all() {
+ return did_cancel_all_;
+ }
+
+ void set_should_send_fake_response(bool send) {
+ should_send_fake_response_ = send;
+ }
+
+ bool should_send_fake_response() {
+ return should_send_fake_response_;
+ }
+
+ base::WaitableEvent& recognition_started_event() {
+ return recognition_started_event_;
+ }
+
+ // SpeechRecognitionManager methods.
+ virtual void StartRecognition(
+ InputTagSpeechDispatcherHost* delegate,
+ int caller_id,
+ int render_process_id,
+ int render_view_id,
+ const gfx::Rect& element_rect,
+ const std::string& language,
+ const std::string& grammar,
+ const std::string& origin_url,
+ net::URLRequestContextGetter* context_getter,
+ content::SpeechRecognitionPreferences* recognition_prefs) OVERRIDE {
+ VLOG(1) << "StartRecognition invoked.";
+ EXPECT_EQ(0, caller_id_);
+ EXPECT_EQ(NULL, delegate_);
+ caller_id_ = caller_id;
+ delegate_ = delegate;
+ grammar_ = grammar;
+ if (should_send_fake_response_) {
+ // Give the fake result in a short while.
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &FakeSpeechRecognitionManager::SetFakeRecognitionResult,
+ // This class does not need to be refcounted (typically done by
+ // PostTask) since it will outlive the test and gets released only
+ // when the test shuts down. Disabling refcounting here saves a bit
+ // of unnecessary code and the factory method can return a plain
+ // pointer below as required by the real code.
+ base::Unretained(this)));
+ }
+ recognition_started_event_.Signal();
+ }
+ virtual void CancelRecognition(int caller_id) OVERRIDE {
+ VLOG(1) << "CancelRecognition invoked.";
+ EXPECT_EQ(caller_id_, caller_id);
+ caller_id_ = 0;
+ delegate_ = NULL;
+ }
+ virtual void StopRecording(int caller_id) OVERRIDE {
+ VLOG(1) << "StopRecording invoked.";
+ EXPECT_EQ(caller_id_, caller_id);
+ // Nothing to do here since we aren't really recording.
+ }
+ virtual void CancelAllRequestsWithDelegate(
+ InputTagSpeechDispatcherHost* delegate) OVERRIDE {
+ VLOG(1) << "CancelAllRequestsWithDelegate invoked.";
+ // delegate_ is set to NULL if a fake result was received (see below), so
+ // check that delegate_ matches the incoming parameter only when there is
+ // no fake result sent.
+ EXPECT_TRUE(should_send_fake_response_ || delegate_ == delegate);
+ did_cancel_all_ = true;
+ }
+
+ private:
+ void SetFakeRecognitionResult() {
+ if (caller_id_) { // Do a check in case we were cancelled..
+ VLOG(1) << "Setting fake recognition result.";
+ delegate_->DidCompleteRecording(caller_id_);
+ content::SpeechRecognitionResult results;
+ results.hypotheses.push_back(content::SpeechRecognitionHypothesis(
+ ASCIIToUTF16(kTestResult), 1.0));
+ delegate_->SetRecognitionResult(caller_id_, results);
+ delegate_->DidCompleteRecognition(caller_id_);
+ caller_id_ = 0;
+ delegate_ = NULL;
+ VLOG(1) << "Finished setting fake recognition result.";
+ }
+ }
+
+ int caller_id_;
+ InputTagSpeechDispatcherHost* delegate_;
+ std::string grammar_;
+ bool did_cancel_all_;
+ bool should_send_fake_response_;
+ base::WaitableEvent recognition_started_event_;
+};
+
+class SpeechRecognitionBrowserTest : public InProcessBrowserTest {
+ public:
+ // InProcessBrowserTest methods
+ virtual void SetUpCommandLine(CommandLine* command_line) {
+ EXPECT_TRUE(!command_line->HasSwitch(switches::kDisableSpeechInput));
+ }
+
+ GURL testUrl(const FilePath::CharType* filename) {
+ const FilePath kTestDir(FILE_PATH_LITERAL("speech"));
+ return ui_test_utils::GetTestUrl(kTestDir, FilePath(filename));
+ }
+
+ protected:
+ void LoadAndStartSpeechRecognitionTest(const FilePath::CharType* filename) {
+ // The test page calculates the speech button's coordinate in the page on
+ // load & sets that coordinate in the URL fragment. We send mouse down & up
+ // events at that coordinate to trigger speech recognition.
+ GURL test_url = testUrl(filename);
+ ui_test_utils::NavigateToURL(browser(), test_url);
+
+ WebKit::WebMouseEvent mouse_event;
+ mouse_event.type = WebKit::WebInputEvent::MouseDown;
+ mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
+ mouse_event.x = 0;
+ mouse_event.y = 0;
+ mouse_event.clickCount = 1;
+ WebContents* web_contents = browser()->GetSelectedWebContents();
+
+ ui_test_utils::WindowedNotificationObserver observer(
+ content::NOTIFICATION_LOAD_STOP,
+ content::Source<NavigationController>(&web_contents->GetController()));
+ web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+ mouse_event.type = WebKit::WebInputEvent::MouseUp;
+ web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
+ fake_speech_recognition_manager_.recognition_started_event().Wait();
+
+ // We should wait for a navigation event, raised by the test page JS code
+ // upon the onwebkitspeechchange event, in all cases except when the
+ // speech response is inhibited.
+ if (fake_speech_recognition_manager_.should_send_fake_response())
+ observer.Wait();
+ }
+
+ void RunSpeechRecognitionTest(const FilePath::CharType* filename) {
+ // The fake speech input manager would receive the speech input
+ // request and return the test string as recognition result. The test page
+ // then sets the URL fragment as 'pass' if it received the expected string.
+ LoadAndStartSpeechRecognitionTest(filename);
+
+ EXPECT_EQ("pass", browser()->GetSelectedWebContents()->GetURL().ref());
+ }
+
+ // InProcessBrowserTest methods.
+ virtual void SetUpInProcessBrowserTestFixture() {
+ fake_speech_recognition_manager_.set_should_send_fake_response(true);
+ speech_recognition_manager_ = &fake_speech_recognition_manager_;
+
+ // Inject the fake manager factory so that the test result is returned to
+ // the web page.
+ InputTagSpeechDispatcherHost::set_manager(speech_recognition_manager_);
+ }
+
+ virtual void TearDownInProcessBrowserTestFixture() {
+ speech_recognition_manager_ = NULL;
+ }
+
+ FakeSpeechRecognitionManager fake_speech_recognition_manager_;
+
+ // This is used by the static |fakeManager|, and it is a pointer rather than a
+ // direct instance per the style guide.
+ static SpeechRecognitionManagerImpl* speech_recognition_manager_;
+};
+
+SpeechRecognitionManagerImpl*
+ SpeechRecognitionBrowserTest::speech_recognition_manager_ = NULL;
+
+// TODO(satish): Once this flakiness has been fixed, add a second test here to
+// check for sending many clicks in succession to the speech button and verify
+// that it doesn't cause any crash but works as expected. This should act as the
+// test for http://crbug.com/59173
+//
+// TODO(satish): Similar to above, once this flakiness has been fixed add
+// another test here to check that when speech recognition is in progress and
+// a renderer crashes, we get a call to
+// SpeechRecognitionManager::CancelAllRequestsWithDelegate.
+IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, TestBasicRecognition) {
+ RunSpeechRecognitionTest(FILE_PATH_LITERAL("basic_recognition.html"));
+ EXPECT_TRUE(fake_speech_recognition_manager_.grammar().empty());
+}
+
+IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, GrammarAttribute) {
+ RunSpeechRecognitionTest(FILE_PATH_LITERAL("grammar_attribute.html"));
+ EXPECT_EQ("http://example.com/grammar.xml",
+ fake_speech_recognition_manager_.grammar());
+}
+
+IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, TestCancelAll) {
+ // The test checks that the cancel-all callback gets issued when a session
+ // is pending, so don't send a fake response.
+ // We are not expecting a navigation event being raised from the JS of the
+ // test page JavaScript in this case.
+ fake_speech_recognition_manager_.set_should_send_fake_response(false);
+
+ LoadAndStartSpeechRecognitionTest(
+ FILE_PATH_LITERAL("basic_recognition.html"));
+
+ // Make the renderer crash. This should trigger
+ // InputTagSpeechDispatcherHost to cancel all pending sessions.
+ GURL test_url("about:crash");
+ ui_test_utils::NavigateToURL(browser(), test_url);
+
+ EXPECT_TRUE(fake_speech_recognition_manager_.did_cancel_all());
+}
+
+} // namespace speech