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