diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index e6b32521231..c1e0ac38a16 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -68,6 +68,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils", XPCOMUtils.defineLazyModuleGetter(this, "webappsUI", "resource:///modules/webappsUI.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", + "resource:///modules/PageThumbs.jsm"); + const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser"; const PREF_PLUGINS_UPDATEURL = "plugins.update.url"; @@ -358,6 +361,8 @@ BrowserGlue.prototype = { // Initialize webapps UI webappsUI.init(); + PageThumbs.init(); + Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); }, @@ -379,6 +384,7 @@ BrowserGlue.prototype = { _onProfileShutdown: function BG__onProfileShutdown() { this._shutdownPlaces(); this._sanitizer.onShutdown(); + PageThumbs.uninit(); }, // All initial windows have opened. diff --git a/browser/components/thumbnails/PageThumbs.jsm b/browser/components/thumbnails/PageThumbs.jsm index 4cefd4befdc..64dc943ff6d 100644 --- a/browser/components/thumbnails/PageThumbs.jsm +++ b/browser/components/thumbnails/PageThumbs.jsm @@ -4,7 +4,7 @@ "use strict"; -let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsCache"]; +let EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsStorage", "PageThumbsCache"]; const Cu = Components.utils; const Cc = Components.classes; @@ -12,6 +12,11 @@ const Ci = Components.interfaces; const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; +/** + * Name of the directory in the profile that contains the thumbnails. + */ +const THUMBNAIL_DIRECTORY = "thumbnails"; + /** * The default background color for page thumbnails. */ @@ -25,11 +30,29 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", + "resource://gre/modules/PlacesUtils.jsm"); + +XPCOMUtils.defineLazyGetter(this, "gCryptoHash", function () { + return Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash); +}); + +XPCOMUtils.defineLazyGetter(this, "gUnicodeConverter", function () { + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = 'utf8'; + return converter; +}); + /** * Singleton providing functionality for capturing web page thumbnails and for * accessing them if already cached. */ let PageThumbs = { + _initialized: false, /** * The calculated width and height of the thumbnails. @@ -52,6 +75,20 @@ let PageThumbs = { */ get contentType() "image/png", + init: function PageThumbs_init() { + if (!this._initialized) { + this._initialized = true; + PlacesUtils.history.addObserver(PageThumbsHistoryObserver, false); + } + }, + + uninit: function PageThumbs_uninit() { + if (this._initialized) { + this._initialized = false; + PlacesUtils.history.removeObserver(PageThumbsHistoryObserver); + } + }, + /** * Gets the thumbnail image's url for a given web page's url. * @param aUrl The web page's url that is depicted in the thumbnail. @@ -124,32 +161,14 @@ let PageThumbs = { // Sync and therefore also redirect sources appear on the newtab // page. We also want thumbnails for those. if (url != originalURL) - PageThumbsCache._copy(url, originalURL); + PageThumbsStorage.copy(url, originalURL); } if (aCallback) aCallback(aSuccessful); } - // Get a writeable cache entry. - PageThumbsCache.getWriteEntry(url, function (aEntry) { - if (!aEntry) { - finish(false); - return; - } - - let outputStream = aEntry.openOutputStream(0); - - // Write the image data to the cache entry. - NetUtil.asyncCopy(aInputStream, outputStream, function (aResult) { - let success = Components.isSuccessCode(aResult); - if (success) - aEntry.markValid(); - - aEntry.close(); - finish(success); - }); - }); + PageThumbsStorage.write(url, aInputStream, finish); }); }, @@ -197,7 +216,7 @@ let PageThumbs = { */ _getThumbnailSize: function PageThumbs_getThumbnailSize() { if (!this._thumbnailWidth || !this._thumbnailHeight) { - let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"] + let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"] .getService(Ci.nsIScreenManager); let left = {}, top = {}, width = {}, height = {}; screenManager.primaryScreen.GetRect(left, top, width, height); @@ -208,6 +227,88 @@ let PageThumbs = { } }; +let PageThumbsStorage = { + getFileForURL: function Storage_getFileForURL(aURL) { + let hash = this._calculateMD5Hash(aURL); + let parts = [THUMBNAIL_DIRECTORY, hash[0], hash[1], hash.slice(2) + ".png"]; + return FileUtils.getFile("ProfD", parts); + }, + + write: function Storage_write(aURL, aDataStream, aCallback) { + let file = this.getFileForURL(aURL); + let fos = FileUtils.openSafeFileOutputStream(file); + + NetUtil.asyncCopy(aDataStream, fos, function (aResult) { + FileUtils.closeSafeFileOutputStream(fos); + aCallback(Components.isSuccessCode(aResult)); + }); + }, + + copy: function Storage_copy(aSourceURL, aTargetURL) { + let sourceFile = this.getFileForURL(aSourceURL); + let targetFile = this.getFileForURL(aTargetURL); + + try { + sourceFile.copyTo(targetFile.parent, targetFile.leafName); + } catch (e) { + /* We might not be permitted to write to the file. */ + } + }, + + remove: function Storage_remove(aURL) { + try { + this.getFileForURL(aURL).remove(false); + } catch (e) { + /* The file might not exist or we're not permitted to remove it. */ + } + }, + + wipe: function Storage_wipe() { + try { + FileUtils.getDir("ProfD", [THUMBNAIL_DIRECTORY]).remove(true); + } catch (e) { + /* The file might not exist or we're not permitted to remove it. */ + } + }, + + _calculateMD5Hash: function Storage_calculateMD5Hash(aValue) { + let hash = gCryptoHash; + let value = gUnicodeConverter.convertToByteArray(aValue); + + hash.init(hash.MD5); + hash.update(value, value.length); + return this._convertToHexString(hash.finish(false)); + }, + + _convertToHexString: function Storage_convertToHexString(aData) { + let hex = ""; + for (let i = 0; i < aData.length; i++) + hex += ("0" + aData.charCodeAt(i).toString(16)).slice(-2); + return hex; + }, + +}; + +let PageThumbsHistoryObserver = { + onDeleteURI: function Thumbnails_onDeleteURI(aURI, aGUID) { + PageThumbsStorage.remove(aURI.spec); + }, + + onClearHistory: function Thumbnails_onClearHistory() { + PageThumbsStorage.wipe(); + }, + + onTitleChanged: function () {}, + onBeginUpdateBatch: function () {}, + onEndUpdateBatch: function () {}, + onVisit: function () {}, + onBeforeDeleteURI: function () {}, + onPageChanged: function () {}, + onDeleteVisits: function () {}, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver]) +}; + /** * A singleton handling the storage of page thumbnails. */ @@ -222,64 +323,6 @@ let PageThumbsCache = { this._openCacheEntry(aKey, Ci.nsICache.ACCESS_READ, aCallback); }, - /** - * Calls the given callback with a cache entry opened for writing. - * @param aKey The key identifying the desired cache entry. - * @param aCallback The callback that is called when the cache entry is ready. - */ - getWriteEntry: function Cache_getWriteEntry(aKey, aCallback) { - // Try to open the desired cache entry. - this._openCacheEntry(aKey, Ci.nsICache.ACCESS_WRITE, aCallback); - }, - - /** - * Copies an existing cache entry's data to a new cache entry. - * @param aSourceKey The key that contains the data to copy. - * @param aTargetKey The key that will be the copy of aSourceKey's data. - */ - _copy: function Cache_copy(aSourceKey, aTargetKey) { - let sourceEntry, targetEntry, waitingCount = 2; - - function finish() { - if (sourceEntry) - sourceEntry.close(); - - if (targetEntry) - targetEntry.close(); - } - - function copyDataWhenReady() { - if (--waitingCount > 0) - return; - - if (!sourceEntry || !targetEntry) { - finish(); - return; - } - - let inputStream = sourceEntry.openInputStream(0); - let outputStream = targetEntry.openOutputStream(0); - - // Copy the image data to a new entry. - NetUtil.asyncCopy(inputStream, outputStream, function (aResult) { - if (Components.isSuccessCode(aResult)) - targetEntry.markValid(); - - finish(); - }); - } - - this.getReadEntry(aSourceKey, function (aSourceEntry) { - sourceEntry = aSourceEntry; - copyDataWhenReady(); - }); - - this.getWriteEntry(aTargetKey, function (aTargetEntry) { - targetEntry = aTargetEntry; - copyDataWhenReady(); - }); - }, - /** * Opens the cache entry identified by the given key. * @param aKey The key identifying the desired cache entry. diff --git a/browser/components/thumbnails/PageThumbsProtocol.js b/browser/components/thumbnails/PageThumbsProtocol.js index 4cf06067b73..d72e8279857 100644 --- a/browser/components/thumbnails/PageThumbsProtocol.js +++ b/browser/components/thumbnails/PageThumbsProtocol.js @@ -72,6 +72,14 @@ Protocol.prototype = { * @return The newly created channel. */ newChannel: function Proto_newChannel(aURI) { + let {url} = parseURI(aURI); + let file = PageThumbsStorage.getFileForURL(url); + + if (file.exists()) { + let fileuri = Services.io.newFileURI(file); + return Services.io.newChannelFromURI(fileuri); + } + return new Channel(aURI); }, diff --git a/browser/components/thumbnails/test/Makefile.in b/browser/components/thumbnails/test/Makefile.in index ac00a023a67..c7af21dc9a5 100644 --- a/browser/components/thumbnails/test/Makefile.in +++ b/browser/components/thumbnails/test/Makefile.in @@ -14,6 +14,7 @@ include $(topsrcdir)/config/rules.mk _BROWSER_FILES = \ browser_thumbnails_capture.js \ browser_thumbnails_redirect.js \ + browser_thumbnails_storage.js \ browser_thumbnails_bug726727.js \ head.js \ background_red.html \ diff --git a/browser/components/thumbnails/test/browser_thumbnails_redirect.js b/browser/components/thumbnails/test/browser_thumbnails_redirect.js index 54803e1e348..7bc420c1ed6 100644 --- a/browser/components/thumbnails/test/browser_thumbnails_redirect.js +++ b/browser/components/thumbnails/test/browser_thumbnails_redirect.js @@ -4,9 +4,6 @@ const URL = "http://mochi.test:8888/browser/browser/components/thumbnails/" + "test/background_red_redirect.sjs"; -let cacheService = Cc["@mozilla.org/network/cache-service;1"] - .getService(Ci.nsICacheService); - /** * These tests ensure that we save and provide thumbnails for redirecting sites. */ @@ -19,33 +16,17 @@ function runTests() { yield addTab(URL); yield captureAndCheckColor(255, 0, 0, "we have a red thumbnail"); - // Wait until the referrer's thumbnail's cache entry has been written. - yield whenCacheEntryExists(URL); + // Wait until the referrer's thumbnail's file has been written. + yield whenFileExists(URL); yield checkThumbnailColor(URL, 255, 0, 0, "referrer has a red thumbnail"); } -function whenCacheEntryExists(aKey) { +function whenFileExists(aURL) { let callback = next; - checkCacheEntryExists(aKey, function (aExists) { - if (!aExists) - callback = function () whenCacheEntryExists(aKey); + let file = PageThumbsStorage.getFileForURL(aURL); + if (!file.exists()) + callback = function () whenFileExists(aURL); - executeSoon(callback); - }); -} - -function checkCacheEntryExists(aKey, aCallback) { - PageThumbsCache.getReadEntry(aKey, function (aEntry) { - let inputStream = aEntry && aEntry.openInputStream(0); - let exists = inputStream && inputStream.available(); - - if (inputStream) - inputStream.close(); - - if (aEntry) - aEntry.close(); - - aCallback(exists); - }); + executeSoon(callback); } diff --git a/browser/components/thumbnails/test/browser_thumbnails_storage.js b/browser/components/thumbnails/test/browser_thumbnails_storage.js new file mode 100644 index 00000000000..db91a980173 --- /dev/null +++ b/browser/components/thumbnails/test/browser_thumbnails_storage.js @@ -0,0 +1,89 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const URL = "http://mochi.test:8888/"; +const URL_COPY = URL + "#copy"; + +XPCOMUtils.defineLazyGetter(this, "Sanitizer", function () { + let tmp = {}; + Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader) + .loadSubScript("chrome://browser/content/sanitize.js", tmp); + return tmp.Sanitizer; +}); + +/** + * These tests ensure that the thumbnail storage is working as intended. + * Newly captured thumbnails should be saved as files and they should as well + * be removed when the user sanitizes their history. + */ +function runTests() { + clearHistory(); + + // create a thumbnail + yield addTab(URL); + yield whenFileExists(); + gBrowser.removeTab(gBrowser.selectedTab); + + // clear all browser history + yield clearHistory(); + + // create a thumbnail + yield addTab(URL); + yield whenFileExists(); + gBrowser.removeTab(gBrowser.selectedTab); + + // make sure copy() updates an existing file + PageThumbsStorage.copy(URL, URL_COPY); + let copy = PageThumbsStorage.getFileForURL(URL_COPY); + let mtime = copy.lastModifiedTime -= 60; + + PageThumbsStorage.copy(URL, URL_COPY); + isnot(PageThumbsStorage.getFileForURL(URL_COPY).lastModifiedTime, mtime, + "thumbnail file was updated"); + + // clear last 10 mins of history + yield clearHistory(true); + ok(!copy.exists(), "copy of thumbnail has been removed"); +} + +function clearHistory(aUseRange) { + let s = new Sanitizer(); + s.prefDomain = "privacy.cpd."; + + let prefs = gPrefService.getBranch(s.prefDomain); + prefs.setBoolPref("history", true); + prefs.setBoolPref("downloads", false); + prefs.setBoolPref("cache", false); + prefs.setBoolPref("cookies", false); + prefs.setBoolPref("formdata", false); + prefs.setBoolPref("offlineApps", false); + prefs.setBoolPref("passwords", false); + prefs.setBoolPref("sessions", false); + prefs.setBoolPref("siteSettings", false); + + if (aUseRange) { + let usec = Date.now() * 1000; + s.range = [usec - 10 * 60 * 1000 * 1000, usec]; + } + + s.sanitize(); + s.range = null; + + executeSoon(function () { + if (PageThumbsStorage.getFileForURL(URL).exists()) + clearHistory(aFile, aUseRange); + else + next(); + }); +} + +function whenFileExists() { + let callback = whenFileExists; + + let file = PageThumbsStorage.getFileForURL(URL); + if (file.exists() && file.fileSize) + callback = next; + + executeSoon(callback); +} diff --git a/browser/components/thumbnails/test/head.js b/browser/components/thumbnails/test/head.js index 6bfd76e7d30..6a4ee10335d 100644 --- a/browser/components/thumbnails/test/head.js +++ b/browser/components/thumbnails/test/head.js @@ -4,7 +4,7 @@ let tmp = {}; Cu.import("resource:///modules/PageThumbs.jsm", tmp); let PageThumbs = tmp.PageThumbs; -let PageThumbsCache = tmp.PageThumbsCache; +let PageThumbsStorage = tmp.PageThumbsStorage; registerCleanupFunction(function () { while (gBrowser.tabs.length > 1) diff --git a/config/rules.mk b/config/rules.mk index 9fab64014b6..515024256b8 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -112,7 +112,7 @@ testxpcsrcdir = $(topsrcdir)/testing/xpcshell # See also testsuite-targets.mk 'xpcshell-tests' target for global execution. xpcshell-tests: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ @@ -142,7 +142,7 @@ xpcshell-tests-remote: # attach a debugger and then start the test. check-interactive: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ @@ -155,7 +155,7 @@ check-interactive: # Execute a single test, specified in $(SOLO_FILE) check-one: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk index 9fab64014b6..515024256b8 100644 --- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -112,7 +112,7 @@ testxpcsrcdir = $(topsrcdir)/testing/xpcshell # See also testsuite-targets.mk 'xpcshell-tests' target for global execution. xpcshell-tests: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ @@ -142,7 +142,7 @@ xpcshell-tests-remote: # attach a debugger and then start the test. check-interactive: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ @@ -155,7 +155,7 @@ check-interactive: # Execute a single test, specified in $(SOLO_FILE) check-one: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(testxpcsrcdir)/runxpcshelltests.py \ --symbols-path=$(DIST)/crashreporter-symbols \ --build-info-json=$(DEPTH)/mozinfo.json \ diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 9a869a8e436..194ed384ce0 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -239,7 +239,7 @@ GARBAGE += $(addsuffix .log,$(MOCHITESTS) reftest crashtest jstestbrowser) # Usage: |make [TEST_PATH=...] [EXTRA_TEST_ARGS=...] xpcshell-tests|. xpcshell-tests: $(PYTHON) -u $(topsrcdir)/config/pythonpath.py \ - -I$(topsrcdir)/build \ + -I$(topsrcdir)/build -I$(DEPTH)/_tests/mozbase/mozinfo \ $(topsrcdir)/testing/xpcshell/runxpcshelltests.py \ --manifest=$(DEPTH)/_tests/xpcshell/xpcshell.ini \ --build-info-json=$(DEPTH)/mozinfo.json \ diff --git a/toolkit/devtools/debugger/Makefile.in b/toolkit/devtools/debugger/Makefile.in index 43508985e69..871e93d4a89 100644 --- a/toolkit/devtools/debugger/Makefile.in +++ b/toolkit/devtools/debugger/Makefile.in @@ -72,5 +72,5 @@ endif include $(topsrcdir)/config/rules.mk libs:: - $(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools - $(NSINSTALL) $(srcdir)/server/*.jsm $(FINAL_TARGET)/modules/devtools + $(INSTALL) $(IFLAGS1) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools + $(INSTALL) $(IFLAGS1) $(srcdir)/server/*.jsm $(FINAL_TARGET)/modules/devtools diff --git a/toolkit/devtools/debugger/dbg-client.jsm b/toolkit/devtools/debugger/dbg-client.jsm index 36156207e2d..c81b1699afb 100644 --- a/toolkit/devtools/debugger/dbg-client.jsm +++ b/toolkit/devtools/debugger/dbg-client.jsm @@ -375,10 +375,10 @@ DebuggerClient.prototype = { */ request: function DC_request(aRequest, aOnResponse) { if (!this._connected) { - throw "Have not yet received a hello packet from the server."; + throw Error("Have not yet received a hello packet from the server."); } if (!aRequest.to) { - throw "Request packet has no destination."; + throw Error("Request packet has no destination."); } this._pendingRequests.push({ to: aRequest.to, @@ -449,7 +449,7 @@ DebuggerClient.prototype = { onResponse(aPacket); } } catch(ex) { - dumpn("Error handling response: " + ex + " - " + ex.stack); + dumpn("Error handling response: " + ex + " - stack:\n" + ex.stack); Cu.reportError(ex); } @@ -536,7 +536,7 @@ ThreadClient.prototype = { _assertPaused: function TC_assertPaused(aCommand) { if (!this.paused) { - throw aCommand + " command sent while not paused."; + throw Error(aCommand + " command sent while not paused."); } }, diff --git a/toolkit/devtools/debugger/server/dbg-server.js b/toolkit/devtools/debugger/server/dbg-server.js index 49591d44f2e..6afaaa36771 100644 --- a/toolkit/devtools/debugger/server/dbg-server.js +++ b/toolkit/devtools/debugger/server/dbg-server.js @@ -63,6 +63,17 @@ function dbg_assert(cond, e) { } } +/* Turn the error e into a string, without fail. */ +function safeErrorString(aError) { + try { + var s = aError.toString(); + if (typeof s === "string") + return s; + } catch (ee) { } + + return ""; +} + loadSubScript.call(this, "chrome://global/content/devtools/dbg-transport.js"); // XPCOM constructors @@ -445,11 +456,14 @@ DebuggerServerConnection.prototype = { } catch(e) { Cu.reportError(e); ret = { error: "unknownError", - message: "An unknown error has occurred while processing request." }; + message: ("error occurred while processing '" + aPacket.type + + "' request: " + safeErrorString(e)) }; } } else { ret = { error: "unrecognizedPacketType", - message: 'Actor "' + actor.actorID + '" does not recognize the packet type "' + aPacket.type + '"' }; + message: ('Actor "' + actor.actorID + + '" does not recognize the packet type "' + + aPacket.type + '"') }; } if (!ret) { diff --git a/toolkit/devtools/debugger/tests/unit/head_dbg.js b/toolkit/devtools/debugger/tests/unit/head_dbg.js index 57374f6e952..eb96facf6ac 100644 --- a/toolkit/devtools/debugger/tests/unit/head_dbg.js +++ b/toolkit/devtools/debugger/tests/unit/head_dbg.js @@ -7,10 +7,61 @@ const Ci = Components.interfaces; const Cu = Components.utils; const Cr = Components.results; -Cu.import("resource:///modules/devtools/dbg-server.jsm"); -Cu.import("resource:///modules/devtools/dbg-client.jsm"); Cu.import("resource://gre/modules/Services.jsm"); +// Always log packets when running tests. runxpcshelltests.py will throw +// the output away anyway, unless you give it the --verbose flag. +Services.prefs.setBoolPref("devtools.debugger.log", true); + +Cu.import("resource:///modules/devtools/dbg-server.jsm"); +Cu.import("resource:///modules/devtools/dbg-client.jsm"); + +// Convert an nsIScriptError 'aFlags' value into an appropriate string. +function scriptErrorFlagsToKind(aFlags) { + var kind; + if (aFlags & Ci.nsIScriptError.warningFlag) + kind = "warning"; + if (aFlags & Ci.nsIScriptError.exceptionFlag) + kind = "exception"; + else + kind = "error"; + + if (aFlags & Ci.nsIScriptError.strictFlag) + kind = "strict " + kind; + + return kind; +} + +// Register a console listener, so console messages don't just disappear +// into the ether. +let errorCount = 0; +let listener = { + observe: function (aMessage) { + errorCount++; + try { + // If we've been given an nsIScriptError, then we can print out + // something nicely formatted, for tools like Emacs to pick up. + var scriptError = aMessage.QueryInterface(Ci.nsIScriptError); + dump(aMessage.sourceName + ":" + aMessage.lineNumber + ": " + + scriptErrorFlagsToKind(aMessage.flags) + ": " + + aMessage.errorMessage + "\n"); + var string = aMessage.errorMessage; + } catch (x) { + // Be a little paranoid with message, as the whole goal here is to lose + // no information. + try { + var string = "" + aMessage.message; + } catch (x) { + var string = ""; + } + } + + do_throw("head_dbg.js got console message: " + string + "\n"); + } +}; + +let consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService); +consoleService.registerListener(listener); function check_except(func) { diff --git a/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js b/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js index ab5df24536b..2aecc881b11 100644 --- a/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js +++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js @@ -27,8 +27,8 @@ function run_test() function test_breakpoint_running() { - let path = getFilePath('test_breakpoint-01.js'); - let location = { url: path, line: gDebuggee.line0 + 3}; + let path = getFilePath('test_breakpoint-02.js'); + let location = { url: path, line: gDebuggee.line0 + 2}; gDebuggee.eval("var line0 = Error().lineNumber;\n" + "var a = 1;\n" + // line0 + 1 @@ -37,8 +37,6 @@ function test_breakpoint_running() // Setting the breakpoint later should interrupt the debuggee. gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) { do_check_eq(aPacket.type, "paused"); - do_check_eq(aPacket.frame.where.url, path); - do_check_eq(aPacket.frame.where.line, location); do_check_eq(aPacket.why.type, "interrupted"); }); diff --git a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js index e0796fe830c..a6b056e9b52 100644 --- a/toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js +++ b/toolkit/devtools/debugger/tests/unit/test_threadlifetime-05.js @@ -70,10 +70,10 @@ function release_grips(aFrameArgs, aThreadGrips) arg_grips(aFrameArgs, function (aNewGrips) { for (let i = 0; i < aNewGrips.length; i++) { do_check_neq(aThreadGrips[i].actor, aNewGrips[i].actor); - gThreadClient.resume(function () { - finishClient(gClient); - }); } + gThreadClient.resume(function () { + finishClient(gClient); + }); }); }); });