michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: "use strict"; michael@0: michael@0: const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {}); michael@0: const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {}); michael@0: const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {}); michael@0: michael@0: let gScratchpadWindow; // Reference to the Scratchpad chrome window object michael@0: michael@0: gDevTools.testing = true; michael@0: SimpleTest.registerCleanupFunction(() => { michael@0: gDevTools.testing = false; michael@0: }); michael@0: michael@0: /** michael@0: * Open a Scratchpad window. michael@0: * michael@0: * @param function aReadyCallback michael@0: * Optional. The function you want invoked when the Scratchpad instance michael@0: * is ready. michael@0: * @param object aOptions michael@0: * Optional. Options for opening the scratchpad: michael@0: * - window michael@0: * Provide this if there's already a Scratchpad window you want to wait michael@0: * loading for. michael@0: * - state michael@0: * Scratchpad state object. This is used when Scratchpad is open. michael@0: * - noFocus michael@0: * Boolean that tells you do not want the opened window to receive michael@0: * focus. michael@0: * @return nsIDOMWindow michael@0: * The new window object that holds Scratchpad. Note that the michael@0: * gScratchpadWindow global is also updated to reference the new window michael@0: * object. michael@0: */ michael@0: function openScratchpad(aReadyCallback, aOptions) michael@0: { michael@0: aOptions = aOptions || {}; michael@0: michael@0: let win = aOptions.window || michael@0: Scratchpad.ScratchpadManager.openScratchpad(aOptions.state); michael@0: if (!win) { michael@0: return; michael@0: } michael@0: michael@0: let onLoad = function() { michael@0: win.removeEventListener("load", onLoad, false); michael@0: michael@0: win.Scratchpad.addObserver({ michael@0: onReady: function(aScratchpad) { michael@0: aScratchpad.removeObserver(this); michael@0: michael@0: if (aOptions.noFocus) { michael@0: aReadyCallback(win, aScratchpad); michael@0: } else { michael@0: waitForFocus(aReadyCallback.bind(null, win, aScratchpad), win); michael@0: } michael@0: } michael@0: }); michael@0: }; michael@0: michael@0: if (aReadyCallback) { michael@0: win.addEventListener("load", onLoad, false); michael@0: } michael@0: michael@0: gScratchpadWindow = win; michael@0: return gScratchpadWindow; michael@0: } michael@0: michael@0: /** michael@0: * Create a temporary file, write to it and call a callback michael@0: * when done. michael@0: * michael@0: * @param string aName michael@0: * Name of your temporary file. michael@0: * @param string aContent michael@0: * Temporary file's contents. michael@0: * @param function aCallback michael@0: * Optional callback to be called when we're done writing michael@0: * to the file. It will receive two parameters: status code michael@0: * and a file object. michael@0: */ michael@0: function createTempFile(aName, aContent, aCallback=function(){}) michael@0: { michael@0: // Create a temporary file. michael@0: let file = FileUtils.getFile("TmpD", [aName]); michael@0: file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8)); michael@0: michael@0: // Write the temporary file. michael@0: let fout = Cc["@mozilla.org/network/file-output-stream;1"]. michael@0: createInstance(Ci.nsIFileOutputStream); michael@0: fout.init(file.QueryInterface(Ci.nsILocalFile), 0x02 | 0x08 | 0x20, michael@0: parseInt("644", 8), fout.DEFER_OPEN); michael@0: michael@0: let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]. michael@0: createInstance(Ci.nsIScriptableUnicodeConverter); michael@0: converter.charset = "UTF-8"; michael@0: let fileContentStream = converter.convertToInputStream(aContent); michael@0: michael@0: NetUtil.asyncCopy(fileContentStream, fout, function (aStatus) { michael@0: aCallback(aStatus, file); michael@0: }); michael@0: } michael@0: michael@0: /** michael@0: * Run a set of asychronous tests sequentially defined by input and output. michael@0: * michael@0: * @param Scratchpad aScratchpad michael@0: * The scratchpad to use in running the tests. michael@0: * @param array aTests michael@0: * An array of test objects, each with the following properties: michael@0: * - method michael@0: * Scratchpad method to use, one of "run", "display", or "inspect". michael@0: * - code michael@0: * Code to run in the scratchpad. michael@0: * - result michael@0: * Expected code that will be in the scratchpad upon completion. michael@0: * - label michael@0: * The tests label which will be logged in the test runner output. michael@0: * @return Promise michael@0: * The promise that will be resolved when all tests are finished. michael@0: */ michael@0: function runAsyncTests(aScratchpad, aTests) michael@0: { michael@0: let deferred = promise.defer(); michael@0: michael@0: (function runTest() { michael@0: if (aTests.length) { michael@0: let test = aTests.shift(); michael@0: aScratchpad.setText(test.code); michael@0: aScratchpad[test.method]().then(function success() { michael@0: is(aScratchpad.getText(), test.result, test.label); michael@0: runTest(); michael@0: }, function failure(error) { michael@0: ok(false, error.stack + " " + test.label); michael@0: runTest(); michael@0: }); michael@0: } else { michael@0: deferred.resolve(); michael@0: } michael@0: })(); michael@0: michael@0: return deferred.promise; michael@0: } michael@0: michael@0: /** michael@0: * Run a set of asychronous tests sequentially with callbacks to prepare each michael@0: * test and to be called when the test result is ready. michael@0: * michael@0: * @param Scratchpad aScratchpad michael@0: * The scratchpad to use in running the tests. michael@0: * @param array aTests michael@0: * An array of test objects, each with the following properties: michael@0: * - method michael@0: * Scratchpad method to use, one of "run", "display", or "inspect". michael@0: * - prepare michael@0: * The callback to run just prior to executing the scratchpad method. michael@0: * - then michael@0: * The callback to run when the scratchpad execution promise resolves. michael@0: * @return Promise michael@0: * The promise that will be resolved when all tests are finished. michael@0: */ michael@0: function runAsyncCallbackTests(aScratchpad, aTests) michael@0: { michael@0: let deferred = promise.defer(); michael@0: michael@0: (function runTest() { michael@0: if (aTests.length) { michael@0: let test = aTests.shift(); michael@0: test.prepare(); michael@0: aScratchpad[test.method]().then(test.then.bind(test)).then(runTest); michael@0: } else { michael@0: deferred.resolve(); michael@0: } michael@0: })(); michael@0: michael@0: return deferred.promise; michael@0: } michael@0: michael@0: michael@0: function cleanup() michael@0: { michael@0: if (gScratchpadWindow) { michael@0: gScratchpadWindow.close(); michael@0: gScratchpadWindow = null; michael@0: } michael@0: while (gBrowser.tabs.length > 1) { michael@0: gBrowser.removeCurrentTab(); michael@0: } michael@0: } michael@0: michael@0: registerCleanupFunction(cleanup);