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.
4
5#include "base/command_line.h"
6#include "base/files/file_path.h"
7#include "base/memory/scoped_ptr.h"
8#include "base/message_loop/message_loop.h"
9#include "base/strings/string_number_conversions.h"
10#include "base/strings/utf_string_conversions.h"
11#include "content/browser/renderer_host/render_view_host_impl.h"
12#include "content/browser/web_contents/web_contents_impl.h"
13#include "content/public/browser/notification_types.h"
14#include "content/public/browser/web_contents.h"
15#include "content/public/common/content_switches.h"
16#include "content/public/common/speech_recognition_error.h"
17#include "content/public/common/speech_recognition_result.h"
18#include "content/public/common/url_constants.h"
19#include "content/public/test/fake_speech_recognition_manager.h"
20#include "content/public/test/test_utils.h"
21#include "content/shell/shell.h"
22#include "content/test/content_browser_test.h"
23#include "content/test/content_browser_test_utils.h"
24#include "third_party/WebKit/public/web/WebInputEvent.h"
25
26namespace content {
27
28class SpeechRecognitionBrowserTest : public ContentBrowserTest {
29 public:
30  // ContentBrowserTest methods
31  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
32    EXPECT_TRUE(!command_line->HasSwitch(switches::kDisableSpeechInput));
33  }
34
35 protected:
36  void LoadAndStartSpeechRecognitionTest(const char* filename) {
37    // The test page calculates the speech button's coordinate in the page on
38    // load & sets that coordinate in the URL fragment. We send mouse down & up
39    // events at that coordinate to trigger speech recognition.
40    GURL test_url = GetTestUrl("speech", filename);
41    NavigateToURL(shell(), test_url);
42
43    WebKit::WebMouseEvent mouse_event;
44    mouse_event.type = WebKit::WebInputEvent::MouseDown;
45    mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
46    mouse_event.x = 0;
47    mouse_event.y = 0;
48    mouse_event.clickCount = 1;
49    WebContents* web_contents = shell()->web_contents();
50
51    WindowedNotificationObserver observer(
52        NOTIFICATION_LOAD_STOP,
53        Source<NavigationController>(&web_contents->GetController()));
54    web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
55    mouse_event.type = WebKit::WebInputEvent::MouseUp;
56    web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
57    fake_speech_recognition_manager_.WaitForRecognitionStarted();
58
59    // We should wait for a navigation event, raised by the test page JS code
60    // upon the onwebkitspeechchange event, in all cases except when the
61    // speech response is inhibited.
62    if (fake_speech_recognition_manager_.should_send_fake_response())
63      observer.Wait();
64  }
65
66  void RunSpeechRecognitionTest(const char* filename) {
67    // The fake speech input manager would receive the speech input
68    // request and return the test string as recognition result. The test page
69    // then sets the URL fragment as 'pass' if it received the expected string.
70    LoadAndStartSpeechRecognitionTest(filename);
71
72    EXPECT_EQ("pass", shell()->web_contents()->GetURL().ref());
73  }
74
75  // ContentBrowserTest methods.
76  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
77    fake_speech_recognition_manager_.set_should_send_fake_response(true);
78    speech_recognition_manager_ = &fake_speech_recognition_manager_;
79
80    // Inject the fake manager factory so that the test result is returned to
81    // the web page.
82    SpeechRecognitionManager::SetManagerForTests(speech_recognition_manager_);
83  }
84
85  virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
86    speech_recognition_manager_ = NULL;
87  }
88
89  FakeSpeechRecognitionManager fake_speech_recognition_manager_;
90
91  // This is used by the static |fakeManager|, and it is a pointer rather than a
92  // direct instance per the style guide.
93  static SpeechRecognitionManager* speech_recognition_manager_;
94};
95
96SpeechRecognitionManager*
97    SpeechRecognitionBrowserTest::speech_recognition_manager_ = NULL;
98
99// TODO(satish): Once this flakiness has been fixed, add a second test here to
100// check for sending many clicks in succession to the speech button and verify
101// that it doesn't cause any crash but works as expected. This should act as the
102// test for http://crbug.com/59173
103//
104// TODO(satish): Similar to above, once this flakiness has been fixed add
105// another test here to check that when speech recognition is in progress and
106// a renderer crashes, we get a call to
107// SpeechRecognitionManager::CancelAllRequestsWithDelegate.
108IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, TestBasicRecognition) {
109  RunSpeechRecognitionTest("basic_recognition.html");
110  EXPECT_TRUE(fake_speech_recognition_manager_.grammar().empty());
111}
112
113IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, GrammarAttribute) {
114  RunSpeechRecognitionTest("grammar_attribute.html");
115  EXPECT_EQ("http://example.com/grammar.xml",
116            fake_speech_recognition_manager_.grammar());
117}
118
119// Flaky on Linux, Windows and Mac http://crbug.com/140765.
120IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, DISABLED_TestCancelAll) {
121  // The test checks that the cancel-all callback gets issued when a session
122  // is pending, so don't send a fake response.
123  // We are not expecting a navigation event being raised from the JS of the
124  // test page JavaScript in this case.
125  fake_speech_recognition_manager_.set_should_send_fake_response(false);
126
127  LoadAndStartSpeechRecognitionTest("basic_recognition.html");
128
129  // Make the renderer crash. This should trigger
130  // InputTagSpeechDispatcherHost to cancel all pending sessions.
131  NavigateToURL(shell(), GURL(kChromeUICrashURL));
132
133  EXPECT_TRUE(fake_speech_recognition_manager_.did_cancel_all());
134}
135
136}  // namespace content
137