1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "MockWebSpeechRecognizer.h"
27
28#include "public/testing/WebTestDelegate.h"
29#include "public/web/WebSpeechRecognitionResult.h"
30#include "public/web/WebSpeechRecognizerClient.h"
31
32using namespace blink;
33using namespace std;
34
35namespace WebTestRunner {
36
37namespace {
38
39// Task class for calling a client function that does not take any parameters.
40typedef void (WebSpeechRecognizerClient::*ClientFunctionPointer)(const WebSpeechRecognitionHandle&);
41class ClientCallTask : public MockWebSpeechRecognizer::Task {
42public:
43    ClientCallTask(MockWebSpeechRecognizer* mock, ClientFunctionPointer function)
44        : MockWebSpeechRecognizer::Task(mock)
45        , m_function(function)
46    {
47    }
48
49    virtual void run() OVERRIDE { (m_recognizer->client()->*m_function)(m_recognizer->handle()); }
50
51private:
52    ClientFunctionPointer m_function;
53};
54
55// Task for delivering a result event.
56class ResultTask : public MockWebSpeechRecognizer::Task {
57public:
58    ResultTask(MockWebSpeechRecognizer* mock, const WebString transcript, float confidence)
59        : MockWebSpeechRecognizer::Task(mock)
60        , m_transcript(transcript)
61        , m_confidence(confidence)
62    {
63    }
64
65    virtual void run() OVERRIDE
66    {
67        WebVector<WebString> transcripts(static_cast<size_t>(1));
68        WebVector<float> confidences(static_cast<size_t>(1));
69        transcripts[0] = m_transcript;
70        confidences[0] = m_confidence;
71        WebVector<WebSpeechRecognitionResult> finalResults(static_cast<size_t>(1));
72        WebVector<WebSpeechRecognitionResult> interimResults;
73        finalResults[0].assign(transcripts, confidences, true);
74
75        m_recognizer->client()->didReceiveResults(m_recognizer->handle(), finalResults, interimResults);
76    }
77
78private:
79    WebString m_transcript;
80    float m_confidence;
81};
82
83// Task for delivering a nomatch event.
84class NoMatchTask : public MockWebSpeechRecognizer::Task {
85public:
86    NoMatchTask(MockWebSpeechRecognizer* mock) : MockWebSpeechRecognizer::Task(mock) { }
87    virtual void run() OVERRIDE { m_recognizer->client()->didReceiveNoMatch(m_recognizer->handle(), WebSpeechRecognitionResult()); }
88};
89
90// Task for delivering an error event.
91class ErrorTask : public MockWebSpeechRecognizer::Task {
92public:
93    ErrorTask(MockWebSpeechRecognizer* mock, WebSpeechRecognizerClient::ErrorCode code, const WebString& message)
94        : MockWebSpeechRecognizer::Task(mock)
95        , m_code(code)
96        , m_message(message)
97    {
98    }
99
100    virtual void run() OVERRIDE { m_recognizer->client()->didReceiveError(m_recognizer->handle(), m_message, m_code); }
101
102private:
103    WebSpeechRecognizerClient::ErrorCode m_code;
104    WebString m_message;
105};
106
107} // namespace
108
109MockWebSpeechRecognizer::MockWebSpeechRecognizer()
110    : m_wasAborted(false)
111    , m_taskQueueRunning(false)
112    , m_delegate(0)
113{
114}
115
116MockWebSpeechRecognizer::~MockWebSpeechRecognizer()
117{
118    clearTaskQueue();
119}
120
121void MockWebSpeechRecognizer::setDelegate(WebTestDelegate* delegate)
122{
123    m_delegate = delegate;
124}
125
126void MockWebSpeechRecognizer::start(const WebSpeechRecognitionHandle& handle, const WebSpeechRecognitionParams& params, WebSpeechRecognizerClient* client)
127{
128    m_wasAborted = false;
129    m_handle = handle;
130    m_client = client;
131
132    m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didStart));
133    m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didStartAudio));
134    m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didStartSound));
135
136    if (!m_mockTranscripts.empty()) {
137        BLINK_ASSERT(m_mockTranscripts.size() == m_mockConfidences.size());
138
139        for (size_t i = 0; i < m_mockTranscripts.size(); ++i)
140            m_taskQueue.push_back(new ResultTask(this, m_mockTranscripts[i], m_mockConfidences[i]));
141
142        m_mockTranscripts.clear();
143        m_mockConfidences.clear();
144    } else
145        m_taskQueue.push_back(new NoMatchTask(this));
146
147    m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didEndSound));
148    m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didEndAudio));
149    m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didEnd));
150
151    startTaskQueue();
152}
153
154void MockWebSpeechRecognizer::stop(const WebSpeechRecognitionHandle& handle, WebSpeechRecognizerClient* client)
155{
156    m_handle = handle;
157    m_client = client;
158
159    // FIXME: Implement.
160    BLINK_ASSERT_NOT_REACHED();
161}
162
163void MockWebSpeechRecognizer::abort(const WebSpeechRecognitionHandle& handle, WebSpeechRecognizerClient* client)
164{
165    m_handle = handle;
166    m_client = client;
167
168    clearTaskQueue();
169    m_wasAborted = true;
170    m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didEnd));
171    startTaskQueue();
172}
173
174void MockWebSpeechRecognizer::addMockResult(const WebString& transcript, float confidence)
175{
176    m_mockTranscripts.push_back(transcript);
177    m_mockConfidences.push_back(confidence);
178}
179
180void MockWebSpeechRecognizer::setError(const WebString& error, const WebString& message)
181{
182    WebSpeechRecognizerClient::ErrorCode code;
183    if (error == "OtherError")
184        code = WebSpeechRecognizerClient::OtherError;
185    else if (error == "NoSpeechError")
186        code = WebSpeechRecognizerClient::NoSpeechError;
187    else if (error == "AbortedError")
188        code = WebSpeechRecognizerClient::AbortedError;
189    else if (error == "AudioCaptureError")
190        code = WebSpeechRecognizerClient::AudioCaptureError;
191    else if (error == "NetworkError")
192        code = WebSpeechRecognizerClient::NetworkError;
193    else if (error == "NotAllowedError")
194        code = WebSpeechRecognizerClient::NotAllowedError;
195    else if (error == "ServiceNotAllowedError")
196        code = WebSpeechRecognizerClient::ServiceNotAllowedError;
197    else if (error == "BadGrammarError")
198        code = WebSpeechRecognizerClient::BadGrammarError;
199    else if (error == "LanguageNotSupportedError")
200        code = WebSpeechRecognizerClient::LanguageNotSupportedError;
201    else
202        return;
203
204    clearTaskQueue();
205    m_taskQueue.push_back(new ErrorTask(this, code, message));
206    m_taskQueue.push_back(new ClientCallTask(this, &WebSpeechRecognizerClient::didEnd));
207    startTaskQueue();
208}
209
210void MockWebSpeechRecognizer::startTaskQueue()
211{
212    if (m_taskQueueRunning)
213        return;
214    m_delegate->postTask(new StepTask(this));
215    m_taskQueueRunning = true;
216}
217
218void MockWebSpeechRecognizer::clearTaskQueue()
219{
220    while (!m_taskQueue.empty()) {
221        delete m_taskQueue.front();
222        m_taskQueue.pop_front();
223    }
224    m_taskQueueRunning = false;
225}
226
227void MockWebSpeechRecognizer::StepTask::runIfValid()
228{
229    if (m_object->m_taskQueue.empty()) {
230        m_object->m_taskQueueRunning = false;
231        return;
232    }
233
234    Task* task = m_object->m_taskQueue.front();
235    m_object->m_taskQueue.pop_front();
236    task->run();
237    delete task;
238
239    if (m_object->m_taskQueue.empty()) {
240        m_object->m_taskQueueRunning = false;
241        return;
242    }
243
244    m_object->m_delegate->postTask(new StepTask(m_object));
245}
246
247}
248