1// Copyright 2014 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 "content/shell/renderer/test_runner/mock_web_speech_recognizer.h"
6
7#include "base/logging.h"
8#include "content/shell/renderer/test_runner/web_test_delegate.h"
9#include "third_party/WebKit/public/web/WebSpeechRecognitionResult.h"
10#include "third_party/WebKit/public/web/WebSpeechRecognizerClient.h"
11
12namespace content {
13
14namespace {
15
16// Task class for calling a client function that does not take any parameters.
17typedef void (blink::WebSpeechRecognizerClient::*ClientFunctionPointer)(
18    const blink::WebSpeechRecognitionHandle&);
19class ClientCallTask : public MockWebSpeechRecognizer::Task {
20 public:
21  ClientCallTask(MockWebSpeechRecognizer* mock, ClientFunctionPointer function)
22      : MockWebSpeechRecognizer::Task(mock), function_(function) {}
23
24  virtual ~ClientCallTask() {}
25
26  virtual void run() OVERRIDE {
27    (recognizer_->Client()->*function_)(recognizer_->Handle());
28  }
29
30 private:
31  ClientFunctionPointer function_;
32
33  DISALLOW_COPY_AND_ASSIGN(ClientCallTask);
34};
35
36// Task for delivering a result event.
37class ResultTask : public MockWebSpeechRecognizer::Task {
38 public:
39  ResultTask(MockWebSpeechRecognizer* mock,
40             const blink::WebString transcript,
41             float confidence)
42      : MockWebSpeechRecognizer::Task(mock),
43        transcript_(transcript),
44        confidence_(confidence) {}
45
46  virtual ~ResultTask() {}
47
48  virtual void run() OVERRIDE {
49    blink::WebVector<blink::WebString> transcripts(static_cast<size_t>(1));
50    blink::WebVector<float> confidences(static_cast<size_t>(1));
51    transcripts[0] = transcript_;
52    confidences[0] = confidence_;
53    blink::WebVector<blink::WebSpeechRecognitionResult> final_results(
54        static_cast<size_t>(1));
55    blink::WebVector<blink::WebSpeechRecognitionResult> interim_results;
56    final_results[0].assign(transcripts, confidences, true);
57
58    recognizer_->Client()->didReceiveResults(
59        recognizer_->Handle(), final_results, interim_results);
60  }
61
62 private:
63  blink::WebString transcript_;
64  float confidence_;
65
66  DISALLOW_COPY_AND_ASSIGN(ResultTask);
67};
68
69// Task for delivering a nomatch event.
70class NoMatchTask : public MockWebSpeechRecognizer::Task {
71 public:
72  NoMatchTask(MockWebSpeechRecognizer* mock)
73      : MockWebSpeechRecognizer::Task(mock) {}
74
75  virtual ~NoMatchTask() {}
76
77  virtual void run() OVERRIDE {
78    recognizer_->Client()->didReceiveNoMatch(
79        recognizer_->Handle(), blink::WebSpeechRecognitionResult());
80  }
81
82 private:
83  DISALLOW_COPY_AND_ASSIGN(NoMatchTask);
84};
85
86// Task for delivering an error event.
87class ErrorTask : public MockWebSpeechRecognizer::Task {
88 public:
89  ErrorTask(MockWebSpeechRecognizer* mock,
90            blink::WebSpeechRecognizerClient::ErrorCode code,
91            const blink::WebString& message)
92      : MockWebSpeechRecognizer::Task(mock), code_(code), message_(message) {}
93
94  virtual ~ErrorTask() {}
95
96  virtual void run() OVERRIDE {
97    recognizer_->Client()->didReceiveError(
98        recognizer_->Handle(), message_, code_);
99  }
100
101 private:
102  blink::WebSpeechRecognizerClient::ErrorCode code_;
103  blink::WebString message_;
104
105  DISALLOW_COPY_AND_ASSIGN(ErrorTask);
106};
107
108}  // namespace
109
110MockWebSpeechRecognizer::MockWebSpeechRecognizer()
111    : was_aborted_(false), task_queue_running_(false), delegate_(0) {
112}
113
114MockWebSpeechRecognizer::~MockWebSpeechRecognizer() {
115  ClearTaskQueue();
116}
117
118void MockWebSpeechRecognizer::SetDelegate(WebTestDelegate* delegate) {
119  delegate_ = delegate;
120}
121
122void MockWebSpeechRecognizer::start(
123    const blink::WebSpeechRecognitionHandle& handle,
124    const blink::WebSpeechRecognitionParams& params,
125    blink::WebSpeechRecognizerClient* client) {
126  was_aborted_ = false;
127  handle_ = handle;
128  client_ = client;
129
130  task_queue_.push_back(
131      new ClientCallTask(this, &blink::WebSpeechRecognizerClient::didStart));
132  task_queue_.push_back(new ClientCallTask(
133      this, &blink::WebSpeechRecognizerClient::didStartAudio));
134  task_queue_.push_back(new ClientCallTask(
135      this, &blink::WebSpeechRecognizerClient::didStartSound));
136
137  if (!mock_transcripts_.empty()) {
138    DCHECK_EQ(mock_transcripts_.size(), mock_confidences_.size());
139
140    for (size_t i = 0; i < mock_transcripts_.size(); ++i)
141      task_queue_.push_back(
142          new ResultTask(this, mock_transcripts_[i], mock_confidences_[i]));
143
144    mock_transcripts_.clear();
145    mock_confidences_.clear();
146  } else
147    task_queue_.push_back(new NoMatchTask(this));
148
149  task_queue_.push_back(
150      new ClientCallTask(this, &blink::WebSpeechRecognizerClient::didEndSound));
151  task_queue_.push_back(
152      new ClientCallTask(this, &blink::WebSpeechRecognizerClient::didEndAudio));
153  task_queue_.push_back(
154      new ClientCallTask(this, &blink::WebSpeechRecognizerClient::didEnd));
155
156  StartTaskQueue();
157}
158
159void MockWebSpeechRecognizer::stop(
160    const blink::WebSpeechRecognitionHandle& handle,
161    blink::WebSpeechRecognizerClient* client) {
162  handle_ = handle;
163  client_ = client;
164
165  // FIXME: Implement.
166  NOTREACHED();
167}
168
169void MockWebSpeechRecognizer::abort(
170    const blink::WebSpeechRecognitionHandle& handle,
171    blink::WebSpeechRecognizerClient* client) {
172  handle_ = handle;
173  client_ = client;
174
175  ClearTaskQueue();
176  was_aborted_ = true;
177  task_queue_.push_back(
178      new ClientCallTask(this, &blink::WebSpeechRecognizerClient::didEnd));
179  StartTaskQueue();
180}
181
182void MockWebSpeechRecognizer::AddMockResult(const blink::WebString& transcript,
183                                            float confidence) {
184  mock_transcripts_.push_back(transcript);
185  mock_confidences_.push_back(confidence);
186}
187
188void MockWebSpeechRecognizer::SetError(const blink::WebString& error,
189                                       const blink::WebString& message) {
190  blink::WebSpeechRecognizerClient::ErrorCode code;
191  if (error == "OtherError")
192    code = blink::WebSpeechRecognizerClient::OtherError;
193  else if (error == "NoSpeechError")
194    code = blink::WebSpeechRecognizerClient::NoSpeechError;
195  else if (error == "AbortedError")
196    code = blink::WebSpeechRecognizerClient::AbortedError;
197  else if (error == "AudioCaptureError")
198    code = blink::WebSpeechRecognizerClient::AudioCaptureError;
199  else if (error == "NetworkError")
200    code = blink::WebSpeechRecognizerClient::NetworkError;
201  else if (error == "NotAllowedError")
202    code = blink::WebSpeechRecognizerClient::NotAllowedError;
203  else if (error == "ServiceNotAllowedError")
204    code = blink::WebSpeechRecognizerClient::ServiceNotAllowedError;
205  else if (error == "BadGrammarError")
206    code = blink::WebSpeechRecognizerClient::BadGrammarError;
207  else if (error == "LanguageNotSupportedError")
208    code = blink::WebSpeechRecognizerClient::LanguageNotSupportedError;
209  else
210    return;
211
212  ClearTaskQueue();
213  task_queue_.push_back(new ErrorTask(this, code, message));
214  task_queue_.push_back(
215      new ClientCallTask(this, &blink::WebSpeechRecognizerClient::didEnd));
216  StartTaskQueue();
217}
218
219void MockWebSpeechRecognizer::StartTaskQueue() {
220  if (task_queue_running_)
221    return;
222  delegate_->PostTask(new StepTask(this));
223  task_queue_running_ = true;
224}
225
226void MockWebSpeechRecognizer::ClearTaskQueue() {
227  while (!task_queue_.empty()) {
228    delete task_queue_.front();
229    task_queue_.pop_front();
230  }
231  task_queue_running_ = false;
232}
233
234void MockWebSpeechRecognizer::StepTask::RunIfValid() {
235  if (object_->task_queue_.empty()) {
236    object_->task_queue_running_ = false;
237    return;
238  }
239
240  Task* task = object_->task_queue_.front();
241  object_->task_queue_.pop_front();
242  task->run();
243  delete task;
244
245  if (object_->task_queue_.empty()) {
246    object_->task_queue_running_ = false;
247    return;
248  }
249
250  object_->delegate_->PostTask(new StepTask(object_));
251}
252
253}  // namespace content
254