summaryrefslogtreecommitdiffstats
path: root/content/browser/speech/speech_input_browsertest.cc
blob: eae9b234a3b080bd48abcadb105d83f4f7ee7bd2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
// Copyright (c) 2011 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/command_line.h"
#include "base/file_path.h"
#include "base/string_number_conversions.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.h"
#include "content/browser/speech/speech_input_dispatcher_host.h"
#include "content/browser/speech/speech_input_manager.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/content_switches.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"

namespace speech_input {
class FakeSpeechInputManager;
}

// 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.
DISABLE_RUNNABLE_METHOD_REFCOUNT(speech_input::FakeSpeechInputManager);

namespace speech_input {

const char* kTestResult = "Pictures of the moon";

class FakeSpeechInputManager : public SpeechInputManager {
 public:
  FakeSpeechInputManager()
      : caller_id_(0),
        delegate_(NULL),
        did_cancel_all_(false),
        send_fake_response_(true) {
  }

  std::string grammar() {
    return grammar_;
  }

  bool did_cancel_all() {
    return did_cancel_all_;
  }

  void set_send_fake_response(bool send) {
    send_fake_response_ = send;
  }

  // SpeechInputManager methods.
  virtual void StartRecognition(Delegate* 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,
                                SpeechInputPreferences* speech_input_prefs) {
    VLOG(1) << "StartRecognition invoked.";
    EXPECT_EQ(0, caller_id_);
    EXPECT_EQ(NULL, delegate_);
    caller_id_ = caller_id;
    delegate_ = delegate;
    grammar_ = grammar;
    if (send_fake_response_) {
      // Give the fake result in a short while.
      MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
          &FakeSpeechInputManager::SetFakeRecognitionResult));
    }
  }
  virtual void CancelRecognition(int caller_id) {
    VLOG(1) << "CancelRecognition invoked.";
    EXPECT_EQ(caller_id_, caller_id);
    caller_id_ = 0;
    delegate_ = NULL;
  }
  virtual void StopRecording(int caller_id) {
    VLOG(1) << "StopRecording invoked.";
    EXPECT_EQ(caller_id_, caller_id);
    // Nothing to do here since we aren't really recording.
  }
  virtual void CancelAllRequestsWithDelegate(Delegate* delegate) {
    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(send_fake_response_ || delegate_ == delegate);
    did_cancel_all_ = true;
  }

 protected:
  virtual void GetRequestInfo(bool* can_report_metrics,
                              std::string* request_info) {}
  virtual void ShowRecognitionRequested(int caller_id,
                                        int render_process_id,
                                        int render_view_id,
                                        const gfx::Rect& element_rect) {}
  virtual void ShowWarmUp(int caller_id) {}
  virtual void ShowRecognizing(int caller_id) {}
  virtual void ShowRecording(int caller_id)  {}
  virtual void ShowInputVolume(int caller_id,
                               float volume,
                               float noise_volume) {}
  virtual void ShowNoMicError(int caller_id) {}
  virtual void ShowRecognizerError(int caller_id,
                                   SpeechRecognizer::ErrorCode error) {}
  virtual void DoClose(int caller_id) {}

 private:
  void SetFakeRecognitionResult() {
    if (caller_id_) {  // Do a check in case we were cancelled..
      VLOG(1) << "Setting fake recognition result.";
      delegate_->DidCompleteRecording(caller_id_);
      SpeechInputResultArray results;
      results.push_back(SpeechInputResultItem(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_;
  Delegate* delegate_;
  std::string grammar_;
  bool did_cancel_all_;
  bool send_fake_response_;
};

class SpeechInputBrowserTest : 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 LoadAndStartSpeechInputTest(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;
    TabContents* tab_contents = browser()->GetSelectedTabContents();
    ui_test_utils::WindowedNotificationObserver observer(
        content::NOTIFICATION_LOAD_STOP,
        Source<NavigationController>(&tab_contents->controller()));
    tab_contents->render_view_host()->ForwardMouseEvent(mouse_event);
    mouse_event.type = WebKit::WebInputEvent::MouseUp;
    tab_contents->render_view_host()->ForwardMouseEvent(mouse_event);
    observer.Wait();
  }

  void RunSpeechInputTest(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.
    LoadAndStartSpeechInputTest(filename);

    EXPECT_EQ("pass", browser()->GetSelectedTabContents()->GetURL().ref());
  }

  // InProcessBrowserTest methods.
  virtual void SetUpInProcessBrowserTestFixture() {
    fake_speech_input_manager_.set_send_fake_response(true);
    speech_input_manager_ = &fake_speech_input_manager_;

    // Inject the fake manager factory so that the test result is returned to
    // the web page.
    SpeechInputDispatcherHost::set_manager(speech_input_manager_);
  }

  virtual void TearDownInProcessBrowserTestFixture() {
    speech_input_manager_ = NULL;
  }

  FakeSpeechInputManager fake_speech_input_manager_;

  // This is used by the static |fakeManager|, and it is a pointer rather than a
  // direct instance per the style guide.
  static SpeechInputManager* speech_input_manager_;
};

SpeechInputManager* SpeechInputBrowserTest::speech_input_manager_ = NULL;

// Marked as DISABLED due to http://crbug.com/51337
//
// 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
// SpeechInputManager::CancelAllRequestsWithDelegate.
//
// Marked as DISABLED due to http://crbug.com/71227
#if defined(GOOGLE_CHROME_BUILD)
#define MAYBE_TestBasicRecognition DISABLED_TestBasicRecognition
#else
#define MAYBE_TestBasicRecognition TestBasicRecognition
#endif
IN_PROC_BROWSER_TEST_F(SpeechInputBrowserTest, MAYBE_TestBasicRecognition) {
  RunSpeechInputTest(FILE_PATH_LITERAL("basic_recognition.html"));
  EXPECT_TRUE(fake_speech_input_manager_.grammar().empty());
}

// Marked as FLAKY due to http://crbug.com/51337
// Marked as DISALBED due to http://crbug.com/71227
#if defined(GOOGLE_CHROME_BUILD)
#define MAYBE_GrammarAttribute DISABLED_GrammarAttribute
#else
#define MAYBE_GrammarAttribute GrammarAttribute
#endif
IN_PROC_BROWSER_TEST_F(SpeechInputBrowserTest, MAYBE_GrammarAttribute) {
  RunSpeechInputTest(FILE_PATH_LITERAL("grammar_attribute.html"));
  EXPECT_EQ("http://example.com/grammar.xml",
            fake_speech_input_manager_.grammar());
}

// Marked as DISABLED due to http://crbug.com/71227
IN_PROC_BROWSER_TEST_F(SpeechInputBrowserTest, DISABLED_TestCancelAll) {
  // The test checks that the cancel-all callback gets issued when a session
  // is pending, so don't send a fake response.
  fake_speech_input_manager_.set_send_fake_response(false);

  LoadAndStartSpeechInputTest(FILE_PATH_LITERAL("basic_recognition.html"));

  // Make the renderer crash. This should trigger SpeechInputDispatcherHost to
  // cancel all pending sessions.
  GURL test_url("about:crash");
  ui_test_utils::NavigateToURL(browser(), test_url);

  EXPECT_TRUE(fake_speech_input_manager_.did_cancel_all());
}

}  // namespace speech_input