michael@0: /* -*- Mode: javascript; js-indent-level: 2; -*- */ michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: // Test that we can nest event loops and then automatically exit nested event michael@0: // loops when requested. michael@0: michael@0: var gClient; michael@0: var gThreadActor; michael@0: michael@0: function run_test() { michael@0: initTestDebuggerServer(); michael@0: let gDebuggee = addTestGlobal("test-nesting"); michael@0: gClient = new DebuggerClient(DebuggerServer.connectPipe()); michael@0: gClient.connect(function () { michael@0: attachTestTabAndResume(gClient, "test-nesting", function (aResponse, aTabClient, aThreadClient) { michael@0: // Reach over the protocol connection and get a reference to the thread actor. michael@0: gThreadActor = aThreadClient._transport._serverConnection.getActor(aThreadClient._actor); michael@0: michael@0: test_nesting(); michael@0: }); michael@0: }); michael@0: do_test_pending(); michael@0: } michael@0: michael@0: function test_nesting() { michael@0: const thread = gThreadActor; michael@0: const { resolve, reject, promise: p } = promise.defer(); michael@0: michael@0: // The following things should happen (in order): michael@0: // 1. In the new event loop (created by synchronize) michael@0: // 2. Resolve the promise (shouldn't exit any event loops) michael@0: // 3. Exit the event loop (should also then exit synchronize's event loop) michael@0: // 4. Be after the synchronize call michael@0: let currentStep = 0; michael@0: michael@0: executeSoon(function () { michael@0: let eventLoop; michael@0: michael@0: executeSoon(function () { michael@0: // Should be at step 2 michael@0: do_check_eq(++currentStep, 2); michael@0: // Before resolving, should have the synchronize event loop and the one just created. michael@0: do_check_eq(thread._nestedEventLoops.size, 2); michael@0: michael@0: executeSoon(function () { michael@0: // Should be at step 3 michael@0: do_check_eq(++currentStep, 3); michael@0: // Before exiting the manually created event loop, should have the michael@0: // synchronize event loop and the manual event loop. michael@0: do_check_eq(thread._nestedEventLoops.size, 2); michael@0: // Should have the event loop michael@0: do_check_true(!!eventLoop); michael@0: eventLoop.resolve(); michael@0: }); michael@0: michael@0: resolve(true); michael@0: // Shouldn't exit any event loops because a new one started since the call to synchronize michael@0: do_check_eq(thread._nestedEventLoops.size, 2); michael@0: }); michael@0: michael@0: // Should be at step 1 michael@0: do_check_eq(++currentStep, 1); michael@0: // Should have only the synchronize event loop michael@0: do_check_eq(thread._nestedEventLoops.size, 1); michael@0: eventLoop = thread._nestedEventLoops.push(); michael@0: eventLoop.enter(); michael@0: }); michael@0: michael@0: do_check_eq(thread.synchronize(p), true); michael@0: michael@0: // Should be on the fourth step michael@0: do_check_eq(++currentStep, 4); michael@0: // There shouldn't be any nested event loops anymore michael@0: do_check_eq(thread._nestedEventLoops.size, 0); michael@0: michael@0: finishClient(gClient); michael@0: }