summaryrefslogtreecommitdiffstats
path: root/dom/media/webspeech/recognition/test
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webspeech/recognition/test')
-rw-r--r--dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp119
-rw-r--r--dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.h38
-rw-r--r--dom/media/webspeech/recognition/test/head.js181
-rw-r--r--dom/media/webspeech/recognition/test/hello.oggbin0 -> 11328 bytes
-rw-r--r--dom/media/webspeech/recognition/test/hello.ogg^headers^1
-rw-r--r--dom/media/webspeech/recognition/test/mochitest.ini21
-rw-r--r--dom/media/webspeech/recognition/test/silence.oggbin0 -> 106941 bytes
-rw-r--r--dom/media/webspeech/recognition/test/silence.ogg^headers^1
-rw-r--r--dom/media/webspeech/recognition/test/test_abort.html71
-rw-r--r--dom/media/webspeech/recognition/test/test_audio_capture_error.html40
-rw-r--r--dom/media/webspeech/recognition/test/test_call_start_from_end_handler.html100
-rw-r--r--dom/media/webspeech/recognition/test/test_nested_eventloop.html81
-rw-r--r--dom/media/webspeech/recognition/test/test_preference_enable.html43
-rw-r--r--dom/media/webspeech/recognition/test/test_recognition_service_error.html43
-rw-r--r--dom/media/webspeech/recognition/test/test_success_without_recognition_service.html43
-rw-r--r--dom/media/webspeech/recognition/test/test_timeout.html40
16 files changed, 822 insertions, 0 deletions
diff --git a/dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp b/dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp
new file mode 100644
index 000000000..97bf4b998
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsThreadUtils.h"
+
+#include "FakeSpeechRecognitionService.h"
+#include "MediaPrefs.h"
+
+#include "SpeechRecognition.h"
+#include "SpeechRecognitionAlternative.h"
+#include "SpeechRecognitionResult.h"
+#include "SpeechRecognitionResultList.h"
+#include "nsIObserverService.h"
+#include "mozilla/Services.h"
+
+namespace mozilla {
+
+using namespace dom;
+
+NS_IMPL_ISUPPORTS(FakeSpeechRecognitionService, nsISpeechRecognitionService, nsIObserver)
+
+FakeSpeechRecognitionService::FakeSpeechRecognitionService()
+{
+}
+
+FakeSpeechRecognitionService::~FakeSpeechRecognitionService()
+{
+}
+
+NS_IMETHODIMP
+FakeSpeechRecognitionService::Initialize(WeakPtr<SpeechRecognition> aSpeechRecognition)
+{
+ mRecognition = aSpeechRecognition;
+ nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+ obs->AddObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC, false);
+ obs->AddObserver(this, SPEECH_RECOGNITION_TEST_END_TOPIC, false);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+FakeSpeechRecognitionService::ProcessAudioSegment(AudioSegment* aAudioSegment, int32_t aSampleRate)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+FakeSpeechRecognitionService::SoundEnd()
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+FakeSpeechRecognitionService::ValidateAndSetGrammarList(mozilla::dom::SpeechGrammar*, nsISpeechGrammarCompilationCallback*)
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+FakeSpeechRecognitionService::Abort()
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+FakeSpeechRecognitionService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
+{
+ MOZ_ASSERT(MediaPrefs::WebSpeechFakeRecognitionService(),
+ "Got request to fake recognition service event, but "
+ TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE " is not set");
+
+ if (!strcmp(aTopic, SPEECH_RECOGNITION_TEST_END_TOPIC)) {
+ nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+ obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC);
+ obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_END_TOPIC);
+
+ return NS_OK;
+ }
+
+ const nsDependentString eventName = nsDependentString(aData);
+
+ if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_ERROR")) {
+ mRecognition->DispatchError(SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR,
+ SpeechRecognitionErrorCode::Network, // TODO different codes?
+ NS_LITERAL_STRING("RECOGNITIONSERVICE_ERROR test event"));
+
+ } else if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_FINAL_RESULT")) {
+ RefPtr<SpeechEvent> event =
+ new SpeechEvent(mRecognition,
+ SpeechRecognition::EVENT_RECOGNITIONSERVICE_FINAL_RESULT);
+
+ event->mRecognitionResultList = BuildMockResultList();
+ NS_DispatchToMainThread(event);
+ }
+
+ return NS_OK;
+}
+
+SpeechRecognitionResultList*
+FakeSpeechRecognitionService::BuildMockResultList()
+{
+ SpeechRecognitionResultList* resultList = new SpeechRecognitionResultList(mRecognition);
+ SpeechRecognitionResult* result = new SpeechRecognitionResult(mRecognition);
+ if (0 < mRecognition->MaxAlternatives()) {
+ SpeechRecognitionAlternative* alternative = new SpeechRecognitionAlternative(mRecognition);
+
+ alternative->mTranscript = NS_LITERAL_STRING("Mock final result");
+ alternative->mConfidence = 0.0f;
+
+ result->mItems.AppendElement(alternative);
+ }
+ resultList->mItems.AppendElement(result);
+
+ return resultList;
+}
+
+} // namespace mozilla
diff --git a/dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.h b/dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.h
new file mode 100644
index 000000000..9b850d4d0
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FakeSpeechRecognitionService_h
+#define mozilla_dom_FakeSpeechRecognitionService_h
+
+#include "nsCOMPtr.h"
+#include "nsIObserver.h"
+#include "nsISpeechRecognitionService.h"
+
+#define NS_FAKE_SPEECH_RECOGNITION_SERVICE_CID \
+ {0x48c345e7, 0x9929, 0x4f9a, {0xa5, 0x63, 0xf4, 0x78, 0x22, 0x2d, 0xab, 0xcd}};
+
+namespace mozilla {
+
+class FakeSpeechRecognitionService : public nsISpeechRecognitionService,
+ public nsIObserver
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISPEECHRECOGNITIONSERVICE
+ NS_DECL_NSIOBSERVER
+
+ FakeSpeechRecognitionService();
+
+private:
+ virtual ~FakeSpeechRecognitionService();
+
+ WeakPtr<dom::SpeechRecognition> mRecognition;
+ dom::SpeechRecognitionResultList* BuildMockResultList();
+};
+
+} // namespace mozilla
+
+#endif
diff --git a/dom/media/webspeech/recognition/test/head.js b/dom/media/webspeech/recognition/test/head.js
new file mode 100644
index 000000000..b5aa2d612
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/head.js
@@ -0,0 +1,181 @@
+"use strict";
+
+const DEFAULT_AUDIO_SAMPLE_FILE = "hello.ogg";
+const SPEECH_RECOGNITION_TEST_REQUEST_EVENT_TOPIC = "SpeechRecognitionTest:RequestEvent";
+const SPEECH_RECOGNITION_TEST_END_TOPIC = "SpeechRecognitionTest:End";
+
+var errorCodes = {
+ NO_SPEECH : "no-speech",
+ ABORTED : "aborted",
+ AUDIO_CAPTURE : "audio-capture",
+ NETWORK : "network",
+ NOT_ALLOWED : "not-allowed",
+ SERVICE_NOT_ALLOWED : "service-not-allowed",
+ BAD_GRAMMAR : "bad-grammar",
+ LANGUAGE_NOT_SUPPORTED : "language-not-supported"
+};
+
+var Services = SpecialPowers.Cu.import("resource://gre/modules/Services.jsm").Services;
+
+function EventManager(sr) {
+ var self = this;
+ var nEventsExpected = 0;
+ self.eventsReceived = [];
+
+ var allEvents = [
+ "audiostart",
+ "soundstart",
+ "speechstart",
+ "speechend",
+ "soundend",
+ "audioend",
+ "result",
+ "nomatch",
+ "error",
+ "start",
+ "end"
+ ];
+
+ var eventDependencies = {
+ "speechend": "speechstart",
+ "soundend": "soundstart",
+ "audioend": "audiostart"
+ };
+
+ var isDone = false;
+
+ // set up grammar
+ var sgl = new SpeechGrammarList();
+ sgl.addFromString("#JSGF V1.0; grammar test; public <simple> = hello ;", 1);
+ sr.grammars = sgl;
+
+ // AUDIO_DATA events are asynchronous,
+ // so we queue events requested while they are being
+ // issued to make them seem synchronous
+ var isSendingAudioData = false;
+ var queuedEventRequests = [];
+
+ // register default handlers
+ for (var i = 0; i < allEvents.length; i++) {
+ (function (eventName) {
+ sr["on" + eventName] = function (evt) {
+ var message = "unexpected event: " + eventName;
+ if (eventName == "error") {
+ message += " -- " + evt.message;
+ }
+
+ ok(false, message);
+ if (self.doneFunc && !isDone) {
+ isDone = true;
+ self.doneFunc();
+ }
+ };
+ })(allEvents[i]);
+ }
+
+ self.expect = function EventManager_expect(eventName, cb) {
+ nEventsExpected++;
+
+ sr["on" + eventName] = function(evt) {
+ self.eventsReceived.push(eventName);
+ ok(true, "received event " + eventName);
+
+ var dep = eventDependencies[eventName];
+ if (dep) {
+ ok(self.eventsReceived.indexOf(dep) >= 0,
+ eventName + " must come after " + dep);
+ }
+
+ cb && cb(evt, sr);
+ if (self.doneFunc && !isDone &&
+ nEventsExpected === self.eventsReceived.length) {
+ isDone = true;
+ self.doneFunc();
+ }
+ }
+ }
+
+ self.start = function EventManager_start() {
+ isSendingAudioData = true;
+ var audioTag = document.createElement("audio");
+ audioTag.src = self.audioSampleFile;
+
+ var stream = audioTag.mozCaptureStreamUntilEnded();
+ audioTag.addEventListener("ended", function() {
+ info("Sample stream ended, requesting queued events");
+ isSendingAudioData = false;
+ while (queuedEventRequests.length) {
+ self.requestFSMEvent(queuedEventRequests.shift());
+ }
+ });
+
+ audioTag.play();
+ sr.start(stream);
+ }
+
+ self.requestFSMEvent = function EventManager_requestFSMEvent(eventName) {
+ if (isSendingAudioData) {
+ info("Queuing event " + eventName + " until we're done sending audio data");
+ queuedEventRequests.push(eventName);
+ return;
+ }
+
+ info("requesting " + eventName);
+ Services.obs.notifyObservers(null,
+ SPEECH_RECOGNITION_TEST_REQUEST_EVENT_TOPIC,
+ eventName);
+ }
+
+ self.requestTestEnd = function EventManager_requestTestEnd() {
+ Services.obs.notifyObservers(null, SPEECH_RECOGNITION_TEST_END_TOPIC, null);
+ }
+}
+
+function buildResultCallback(transcript) {
+ return (function(evt) {
+ is(evt.results[0][0].transcript, transcript, "expect correct transcript");
+ });
+}
+
+function buildErrorCallback(errcode) {
+ return (function(err) {
+ is(err.error, errcode, "expect correct error code");
+ });
+}
+
+function performTest(options) {
+ var prefs = options.prefs;
+
+ prefs.unshift(
+ ["media.webspeech.recognition.enable", true],
+ ["media.webspeech.test.enable", true]
+ );
+
+ SpecialPowers.pushPrefEnv({set: prefs}, function() {
+ var sr = new SpeechRecognition();
+ var em = new EventManager(sr);
+
+ for (var eventName in options.expectedEvents) {
+ var cb = options.expectedEvents[eventName];
+ em.expect(eventName, cb);
+ }
+
+ em.doneFunc = function() {
+ em.requestTestEnd();
+ if (options.doneFunc) {
+ options.doneFunc();
+ }
+ }
+
+ em.audioSampleFile = DEFAULT_AUDIO_SAMPLE_FILE;
+ if (options.audioSampleFile) {
+ em.audioSampleFile = options.audioSampleFile;
+ }
+
+ em.start();
+
+ for (var i = 0; i < options.eventsToRequest.length; i++) {
+ em.requestFSMEvent(options.eventsToRequest[i]);
+ }
+ });
+}
diff --git a/dom/media/webspeech/recognition/test/hello.ogg b/dom/media/webspeech/recognition/test/hello.ogg
new file mode 100644
index 000000000..7a8092606
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/hello.ogg
Binary files differ
diff --git a/dom/media/webspeech/recognition/test/hello.ogg^headers^ b/dom/media/webspeech/recognition/test/hello.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/hello.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/webspeech/recognition/test/mochitest.ini b/dom/media/webspeech/recognition/test/mochitest.ini
new file mode 100644
index 000000000..0e5a7a8ed
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/mochitest.ini
@@ -0,0 +1,21 @@
+[DEFAULT]
+tags=msg
+subsuite = media
+support-files =
+ head.js
+ hello.ogg
+ hello.ogg^headers^
+ silence.ogg
+ silence.ogg^headers^
+[test_abort.html]
+skip-if = toolkit == 'android' # bug 1037287
+[test_audio_capture_error.html]
+[test_call_start_from_end_handler.html]
+tags=capturestream
+skip-if = (android_version == '18' && debug) # bug 967606
+[test_nested_eventloop.html]
+skip-if = toolkit == 'android'
+[test_preference_enable.html]
+[test_recognition_service_error.html]
+[test_success_without_recognition_service.html]
+[test_timeout.html]
diff --git a/dom/media/webspeech/recognition/test/silence.ogg b/dom/media/webspeech/recognition/test/silence.ogg
new file mode 100644
index 000000000..e6da3a502
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/silence.ogg
Binary files differ
diff --git a/dom/media/webspeech/recognition/test/silence.ogg^headers^ b/dom/media/webspeech/recognition/test/silence.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/silence.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/webspeech/recognition/test/test_abort.html b/dom/media/webspeech/recognition/test/test_abort.html
new file mode 100644
index 000000000..ae9a29964
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/test_abort.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650295
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 650295 -- Call abort from inside handlers</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="head.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ // Abort inside event handlers, should't get a
+ // result after that
+
+ var nextEventIdx = 0;
+ var eventsToAbortOn = [
+ "start",
+ "audiostart",
+ "speechstart",
+ "speechend",
+ "audioend"
+ ];
+
+ function doNextTest() {
+ var nextEvent = eventsToAbortOn[nextEventIdx];
+ var expectedEvents = {
+ "start": null,
+ "audiostart": null,
+ "audioend": null,
+ "end": null
+ };
+
+ if (nextEventIdx >= eventsToAbortOn.indexOf("speechstart")) {
+ expectedEvents["speechstart"] = null;
+ }
+
+ if (nextEventIdx >= eventsToAbortOn.indexOf("speechend")) {
+ expectedEvents["speechend"] = null;
+ }
+
+ info("Aborting on " + nextEvent);
+ expectedEvents[nextEvent] = function(evt, sr) {
+ sr.abort();
+ };
+
+ nextEventIdx++;
+
+ performTest({
+ eventsToRequest: [],
+ expectedEvents: expectedEvents,
+ doneFunc: (nextEventIdx < eventsToAbortOn.length) ? doNextTest : SimpleTest.finish,
+ prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
+ });
+ }
+
+ doNextTest();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/webspeech/recognition/test/test_audio_capture_error.html b/dom/media/webspeech/recognition/test/test_audio_capture_error.html
new file mode 100644
index 000000000..6869f4c9b
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/test_audio_capture_error.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650295
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 650295 -- Behavior on audio error</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="head.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ performTest({
+ eventsToRequest: ['EVENT_AUDIO_ERROR'],
+ expectedEvents: {
+ 'start': null,
+ 'audiostart': null,
+ 'speechstart': null,
+ 'speechend': null,
+ 'audioend': null,
+ 'error': buildErrorCallback(errorCodes.AUDIO_CAPTURE),
+ 'end': null
+ },
+ doneFunc: SimpleTest.finish,
+ prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
+ });
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/webspeech/recognition/test/test_call_start_from_end_handler.html b/dom/media/webspeech/recognition/test/test_call_start_from_end_handler.html
new file mode 100644
index 000000000..c8da267fc
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/test_call_start_from_end_handler.html
@@ -0,0 +1,100 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650295
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 650295 -- Restart recognition from end handler</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="head.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ function createAudioStream() {
+ var audioTag = document.createElement("audio");
+ audioTag.src = DEFAULT_AUDIO_SAMPLE_FILE;
+
+ var stream = audioTag.mozCaptureStreamUntilEnded();
+ audioTag.play();
+
+ return stream;
+ }
+
+ var done = false;
+ function endHandler(evt, sr) {
+ if (done) {
+ SimpleTest.finish();
+ return;
+ }
+
+ try {
+ var stream = createAudioStream();
+ sr.start(stream); // shouldn't fail
+ } catch (err) {
+ ok(false, "Failed to start() from end() callback");
+ }
+
+ // calling start() may cause some callbacks to fire, but we're
+ // no longer interested in them, except for onend, which is where
+ // we'll conclude the test.
+ sr.onstart = null;
+ sr.onaudiostart = null;
+ sr.onspeechstart = null;
+ sr.onspeechend = null;
+ sr.onaudioend = null;
+ sr.onresult = null;
+
+ // FIXME(ggp) the state transition caused by start() is async,
+ // but abort() is sync (see bug 1055093). until we normalize
+ // state transitions, we need to setTimeout here to make sure
+ // abort() finds the speech recognition object in the correct
+ // state (namely, STATE_STARTING).
+ setTimeout(function() {
+ sr.abort();
+ done = true;
+ });
+
+ info("Successfully start() from end() callback");
+ }
+
+ function expectExceptionHandler(evt, sr) {
+ try {
+ sr.start(createAudioStream());
+ } catch (err) {
+ is(err.name, "InvalidStateError");
+ return;
+ }
+
+ ok(false, "Calling start() didn't raise InvalidStateError");
+ }
+
+ performTest({
+ eventsToRequest: [
+ 'EVENT_RECOGNITIONSERVICE_FINAL_RESULT'
+ ],
+ expectedEvents: {
+ 'start': expectExceptionHandler,
+ 'audiostart': expectExceptionHandler,
+ 'speechstart': expectExceptionHandler,
+ 'speechend': expectExceptionHandler,
+ 'audioend': expectExceptionHandler,
+ 'result': buildResultCallback("Mock final result"),
+ 'end': endHandler,
+ },
+ prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
+ });
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/webspeech/recognition/test/test_nested_eventloop.html b/dom/media/webspeech/recognition/test/test_nested_eventloop.html
new file mode 100644
index 000000000..bdbed6524
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/test_nested_eventloop.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650295
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 650295 -- Spin the event loop from inside a callback</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="head.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ /*
+ * window.showModalDialog() can be used to spin the event loop, causing
+ * queued SpeechEvents (such as those created by calls to start(), stop()
+ * or abort()) to be processed immediately.
+ * When this is done from inside DOM event handlers, it is possible to
+ * cause reentrancy in our C++ code, which we should be able to withstand.
+ */
+ function abortAndSpinEventLoop(evt, sr) {
+ sr.abort();
+ SpecialPowers.spinEventLoop(window);
+ }
+ function doneFunc() {
+ // Trigger gc now and wait some time to make sure this test gets the blame
+ // for any assertions caused by showModalDialog
+ //
+ // NB - The assertions should be gone, but this looks too scary to touch
+ // during batch cleanup.
+ var count = 0, GC_COUNT = 4;
+
+ function triggerGCOrFinish() {
+ SpecialPowers.gc();
+ count++;
+
+ if (count == GC_COUNT) {
+ SimpleTest.finish();
+ }
+ }
+
+ for (var i = 0; i < GC_COUNT; i++) {
+ setTimeout(triggerGCOrFinish, 0);
+ }
+ }
+
+ /*
+ * We start by performing a normal start, then abort from the audiostart
+ * callback and force the EVENT_ABORT to be processed while still inside
+ * the event handler. This causes the recording to stop, which raises
+ * the audioend and (later on) end events.
+ * Then, we abort (once again spinning the event loop) from the audioend
+ * handler, attempting to cause a re-entry into the abort code. This second
+ * call should be ignored, and we get the end callback and finish.
+ */
+
+ performTest({
+ eventsToRequest: [],
+ expectedEvents: {
+ "audiostart": abortAndSpinEventLoop,
+ "audioend": abortAndSpinEventLoop,
+ "end": null
+ },
+ doneFunc: doneFunc,
+ prefs: [["media.webspeech.test.fake_fsm_events", true],
+ ["media.webspeech.test.fake_recognition_service", true]]
+ });
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/webspeech/recognition/test/test_preference_enable.html b/dom/media/webspeech/recognition/test/test_preference_enable.html
new file mode 100644
index 000000000..0946566a3
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/test_preference_enable.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650295
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 650295 -- No objects should be visible with preference disabled</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ SpecialPowers.pushPrefEnv({
+ set: [["media.webspeech.recognition.enable", false]]
+ }, function() {
+ var objects = [
+ "SpeechRecognition",
+ "SpeechGrammar",
+ "SpeechRecognitionResult",
+ "SpeechRecognitionResultList",
+ "SpeechRecognitionAlternative"
+ ];
+
+ for (var i = 0; i < objects.length; i++) {
+ is(window[objects[i]], undefined,
+ objects[i] + " should be undefined with pref off");
+ }
+
+ SimpleTest.finish();
+ });
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/webspeech/recognition/test/test_recognition_service_error.html b/dom/media/webspeech/recognition/test/test_recognition_service_error.html
new file mode 100644
index 000000000..e7e9fb7ca
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/test_recognition_service_error.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650295
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 650295 -- Behavior on recognition service error</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="head.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ performTest({
+ eventsToRequest: [
+ 'EVENT_RECOGNITIONSERVICE_ERROR'
+ ],
+ expectedEvents: {
+ 'start': null,
+ 'audiostart': null,
+ 'speechstart': null,
+ 'speechend': null,
+ 'audioend': null,
+ 'error': buildErrorCallback(errorCodes.NETWORK),
+ 'end': null
+ },
+ doneFunc: SimpleTest.finish,
+ prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
+ });
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/webspeech/recognition/test/test_success_without_recognition_service.html b/dom/media/webspeech/recognition/test/test_success_without_recognition_service.html
new file mode 100644
index 000000000..9ecf00f4b
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/test_success_without_recognition_service.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650295
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 650295 -- Success with fake recognition service</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="head.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ performTest({
+ eventsToRequest: [
+ 'EVENT_RECOGNITIONSERVICE_FINAL_RESULT'
+ ],
+ expectedEvents: {
+ 'start': null,
+ 'audiostart': null,
+ 'speechstart': null,
+ 'speechend': null,
+ 'audioend': null,
+ 'result': buildResultCallback("Mock final result"),
+ 'end': null
+ },
+ doneFunc:SimpleTest.finish,
+ prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
+ });
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/webspeech/recognition/test/test_timeout.html b/dom/media/webspeech/recognition/test/test_timeout.html
new file mode 100644
index 000000000..009964406
--- /dev/null
+++ b/dom/media/webspeech/recognition/test/test_timeout.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650295
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 650295 -- Timeout for user speech</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="head.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ performTest({
+ eventsToRequest: [],
+ expectedEvents: {
+ "start": null,
+ "audiostart": null,
+ "audioend": null,
+ "error": buildErrorCallback(errorCodes.NO_SPEECH),
+ "end": null
+ },
+ doneFunc: SimpleTest.finish,
+ audioSampleFile: "silence.ogg",
+ prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
+ });
+
+</script>
+</pre>
+</body>
+</html>