1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/webspeech/recognition/test/test_nested_eventloop.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,86 @@ 1.4 +<!DOCTYPE HTML> 1.5 +<html> 1.6 +<!-- 1.7 +https://bugzilla.mozilla.org/show_bug.cgi?id=650295 1.8 +--> 1.9 +<head> 1.10 + <meta charset="utf-8"> 1.11 + <title>Test for Bug 650295 -- Spin the event loop from inside a callback</title> 1.12 + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> 1.13 + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 1.14 + <script type="application/javascript" src="head.js"></script> 1.15 +</head> 1.16 +<body> 1.17 +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a> 1.18 +<p id="display"></p> 1.19 +<div id="content" style="display: none"> 1.20 + 1.21 +</div> 1.22 +<pre id="test"> 1.23 +<script type="text/javascript"> 1.24 + SimpleTest.waitForExplicitFinish(); 1.25 + 1.26 + /* 1.27 + * window.showModalDialog() can be used to spin the event loop, causing 1.28 + * queued SpeechEvents (such as those created by calls to start(), stop() 1.29 + * or abort()) to be processed immediately. 1.30 + * When this is done from inside DOM event handlers, it is possible to 1.31 + * cause reentrancy in our C++ code, which we should be able to withstand. 1.32 + */ 1.33 + 1.34 + function abortAndSpinEventLoop(evt, sr) { 1.35 + sr.abort(); 1.36 + window.showModalDialog("javascript:window.close()"); 1.37 + } 1.38 + 1.39 + function doneFunc() { 1.40 + // Trigger gc now and wait some time to make sure this test gets the blame 1.41 + // for any assertions caused by showModalDialog 1.42 + // 1.43 + // NB - The assertions should be gone, but this looks too scary to touch 1.44 + // during batch cleanup. 1.45 + var count = 0, GC_COUNT = 4; 1.46 + 1.47 + function triggerGCOrFinish() { 1.48 + SpecialPowers.gc(); 1.49 + count++; 1.50 + 1.51 + if (count == GC_COUNT) { 1.52 + SimpleTest.finish(); 1.53 + } 1.54 + } 1.55 + 1.56 + for (var i = 0; i < GC_COUNT; i++) { 1.57 + setTimeout(triggerGCOrFinish, 0); 1.58 + } 1.59 + } 1.60 + 1.61 + /* 1.62 + * We start by performing a normal start, then abort from the audiostart 1.63 + * callback and force the EVENT_ABORT to be processed while still inside 1.64 + * the event handler. This causes the recording to stop, which raises 1.65 + * the audioend and (later on) end events. 1.66 + * Then, we abort (once again spinning the event loop) from the audioend 1.67 + * handler, attempting to cause a re-entry into the abort code. This second 1.68 + * call should be ignored, and we get the end callback and finish. 1.69 + */ 1.70 + 1.71 + performTest({ 1.72 + eventsToRequest: [ 1.73 + "EVENT_START", 1.74 + "EVENT_AUDIO_DATA", 1.75 + ], 1.76 + expectedEvents: { 1.77 + "audiostart": abortAndSpinEventLoop, 1.78 + "audioend": abortAndSpinEventLoop, 1.79 + "end": null 1.80 + }, 1.81 + doneFunc: doneFunc, 1.82 + prefs: [["media.webspeech.test.fake_fsm_events", true], 1.83 + ["media.webspeech.test.fake_recognition_service", true]] 1.84 + }); 1.85 + 1.86 +</script> 1.87 +</pre> 1.88 +</body> 1.89 +</html>