diff options
Diffstat (limited to 'browser/components/places/tests/unit')
21 files changed, 2159 insertions, 0 deletions
diff --git a/browser/components/places/tests/unit/.eslintrc.js b/browser/components/places/tests/unit/.eslintrc.js new file mode 100644 index 000000000..d35787cd2 --- /dev/null +++ b/browser/components/places/tests/unit/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/xpcshell/xpcshell.eslintrc.js" + ] +}; diff --git a/browser/components/places/tests/unit/bookmarks.glue.html b/browser/components/places/tests/unit/bookmarks.glue.html new file mode 100644 index 000000000..07b22e9b3 --- /dev/null +++ b/browser/components/places/tests/unit/bookmarks.glue.html @@ -0,0 +1,16 @@ +<!DOCTYPE NETSCAPE-Bookmark-file-1> +<!-- This is an automatically generated file. + It will be read and overwritten. + DO NOT EDIT! --> +<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> +<TITLE>Bookmarks</TITLE> +<H1>Bookmarks Menu</H1> + +<DL><p> + <DT><A HREF="http://example.com/" ADD_DATE="1233157972" LAST_MODIFIED="1233157984">example</A> + <DT><H3 ADD_DATE="1233157910" LAST_MODIFIED="1233157972" PERSONAL_TOOLBAR_FOLDER="true">Bookmarks Toolbar</H3> +<DD>Add bookmarks to this folder to see them displayed on the Bookmarks Toolbar + <DL><p> + <DT><A HREF="http://example.com/" ADD_DATE="1233157972" LAST_MODIFIED="1233157984">example</A> + </DL><p> +</DL><p> diff --git a/browser/components/places/tests/unit/bookmarks.glue.json b/browser/components/places/tests/unit/bookmarks.glue.json new file mode 100644 index 000000000..95900e176 --- /dev/null +++ b/browser/components/places/tests/unit/bookmarks.glue.json @@ -0,0 +1 @@ +{"title":"","id":1,"dateAdded":1233157910552624,"lastModified":1233157955206833,"type":"text/x-moz-place-container","root":"placesRoot","children":[{"title":"Bookmarks Menu","id":2,"parent":1,"dateAdded":1233157910552624,"lastModified":1233157993171424,"type":"text/x-moz-place-container","root":"bookmarksMenuFolder","children":[{"title":"examplejson","id":27,"parent":2,"dateAdded":1233157972101126,"lastModified":1233157984999673,"type":"text/x-moz-place","uri":"http://example.com/"}]},{"index":1,"title":"Bookmarks Toolbar","id":3,"parent":1,"dateAdded":1233157910552624,"lastModified":1233157972101126,"annos":[{"name":"bookmarkProperties/description","flags":0,"expires":4,"mimeType":null,"type":3,"value":"Add bookmarks to this folder to see them displayed on the Bookmarks Toolbar"}],"type":"text/x-moz-place-container","root":"toolbarFolder","children":[{"title":"examplejson","id":26,"parent":3,"dateAdded":1233157972101126,"lastModified":1233157984999673,"type":"text/x-moz-place","uri":"http://example.com/"}]},{"index":2,"title":"Tags","id":4,"parent":1,"dateAdded":1233157910552624,"lastModified":1233157910582667,"type":"text/x-moz-place-container","root":"tagsFolder","children":[]},{"index":3,"title":"Other Bookmarks","id":5,"parent":1,"dateAdded":1233157910552624,"lastModified":1233157911033315,"type":"text/x-moz-place-container","root":"unfiledBookmarksFolder","children":[]}]} diff --git a/browser/components/places/tests/unit/corruptDB.sqlite b/browser/components/places/tests/unit/corruptDB.sqlite Binary files differnew file mode 100644 index 000000000..b234246ca --- /dev/null +++ b/browser/components/places/tests/unit/corruptDB.sqlite diff --git a/browser/components/places/tests/unit/distribution.ini b/browser/components/places/tests/unit/distribution.ini new file mode 100644 index 000000000..93e73cb5c --- /dev/null +++ b/browser/components/places/tests/unit/distribution.ini @@ -0,0 +1,27 @@ +# Distribution Configuration File +# Bug 516444 demo + +[Global] +id=516444 +version=1.0 +about=Test distribution file + +[BookmarksToolbar] +item.1.title=Toolbar Link Before +item.1.link=https://example.org/toolbar/before/ +item.1.keyword=e:t:b +item.1.icon=https://example.org/favicon.png +item.1.iconData=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg== +item.2.type=default +item.3.title=Toolbar Link After +item.3.link=https://example.org/toolbar/after/ +item.3.keyword=e:t:a + +[BookmarksMenu] +item.1.title=Menu Link Before +item.1.link=https://example.org/menu/before/ +item.1.icon=https://example.org/favicon.png +item.1.iconData=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg== +item.2.type=default +item.3.title=Menu Link After +item.3.link=https://example.org/menu/after/ diff --git a/browser/components/places/tests/unit/head_bookmarks.js b/browser/components/places/tests/unit/head_bookmarks.js new file mode 100644 index 000000000..460295f96 --- /dev/null +++ b/browser/components/places/tests/unit/head_bookmarks.js @@ -0,0 +1,133 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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/. */ + +var Ci = Components.interfaces; +var Cc = Components.classes; +var Cr = Components.results; +var Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/LoadContextInfo.jsm"); + +// Import common head. +var commonFile = do_get_file("../../../../../toolkit/components/places/tests/head_common.js", false); +if (commonFile) { + let uri = Services.io.newFileURI(commonFile); + Services.scriptloader.loadSubScript(uri.spec, this); +} + +// Put any other stuff relative to this test folder below. + +XPCOMUtils.defineLazyGetter(this, "PlacesUIUtils", function() { + Cu.import("resource:///modules/PlacesUIUtils.jsm"); + return PlacesUIUtils; +}); + +const ORGANIZER_FOLDER_ANNO = "PlacesOrganizer/OrganizerFolder"; +const ORGANIZER_QUERY_ANNO = "PlacesOrganizer/OrganizerQuery"; + +// Needed by some test that relies on having an app registered. +Cu.import("resource://testing-common/AppInfo.jsm", this); +updateAppInfo({ + name: "PlacesTest", + ID: "{230de50e-4cd1-11dc-8314-0800200c9a66}", + version: "1", + platformVersion: "", +}); + +// Smart bookmarks constants. +const SMART_BOOKMARKS_VERSION = 8; +const SMART_BOOKMARKS_ON_TOOLBAR = 1; +const SMART_BOOKMARKS_ON_MENU = 2; // Takes into account the additional separator. + +// Default bookmarks constants. +const DEFAULT_BOOKMARKS_ON_TOOLBAR = 1; +const DEFAULT_BOOKMARKS_ON_MENU = 1; + +const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark"; + +function checkItemHasAnnotation(guid, name) { + return PlacesUtils.promiseItemId(guid).then(id => { + let hasAnnotation = PlacesUtils.annotations.itemHasAnnotation(id, name); + Assert.ok(hasAnnotation, `Expected annotation ${name}`); + }); +} + +var createCorruptDB = Task.async(function* () { + let dbPath = OS.Path.join(OS.Constants.Path.profileDir, "places.sqlite"); + yield OS.File.remove(dbPath); + + // Create a corrupt database. + let dir = yield OS.File.getCurrentDirectory(); + let src = OS.Path.join(dir, "corruptDB.sqlite"); + yield OS.File.copy(src, dbPath); + + // Check there's a DB now. + Assert.ok((yield OS.File.exists(dbPath)), "should have a DB now"); +}); + +/** + * Rebuilds smart bookmarks listening to console output to report any message or + * exception generated. + * + * @return {Promise} + * Resolved when done. + */ +function rebuildSmartBookmarks() { + let consoleListener = { + observe(aMsg) { + if (aMsg.message.startsWith("[JavaScript Warning:")) { + // TODO (Bug 1300416): Ignore spurious strict warnings. + return; + } + do_throw("Got console message: " + aMsg.message); + }, + QueryInterface: XPCOMUtils.generateQI([ Ci.nsIConsoleListener ]), + }; + Services.console.reset(); + Services.console.registerListener(consoleListener); + do_register_cleanup(() => { + try { + Services.console.unregisterListener(consoleListener); + } catch (ex) { /* will likely fail */ } + }); + Cc["@mozilla.org/browser/browserglue;1"] + .getService(Ci.nsIObserver) + .observe(null, "browser-glue-test", "smart-bookmarks-init"); + return promiseTopicObserved("test-smart-bookmarks-done").then(() => { + Services.console.unregisterListener(consoleListener); + }); +} + +const SINGLE_TRY_TIMEOUT = 100; +const NUMBER_OF_TRIES = 30; + +/** + * Similar to waitForConditionPromise, but poll for an asynchronous value + * every SINGLE_TRY_TIMEOUT ms, for no more than tryCount times. + * + * @param promiseFn + * A function to generate a promise, which resolves to the expected + * asynchronous value. + * @param timeoutMsg + * The reason to reject the returned promise with. + * @param [optional] tryCount + * Maximum times to try before rejecting the returned promise with + * timeoutMsg, defaults to NUMBER_OF_TRIES. + * @return {Promise} + * @resolves to the asynchronous value being polled. + * @rejects if the asynchronous value is not available after tryCount attempts. + */ +var waitForResolvedPromise = Task.async(function* (promiseFn, timeoutMsg, tryCount=NUMBER_OF_TRIES) { + let tries = 0; + do { + try { + let value = yield promiseFn(); + return value; + } catch (ex) {} + yield new Promise(resolve => do_timeout(SINGLE_TRY_TIMEOUT, resolve)); + } while (++tries <= tryCount); + throw new Error(timeoutMsg); +}); diff --git a/browser/components/places/tests/unit/test_421483.js b/browser/components/places/tests/unit/test_421483.js new file mode 100644 index 000000000..a0d138372 --- /dev/null +++ b/browser/components/places/tests/unit/test_421483.js @@ -0,0 +1,103 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + + +const SMART_BOOKMARKS_PREF = "browser.places.smartBookmarksVersion"; + +var gluesvc = Cc["@mozilla.org/browser/browserglue;1"]. + getService(Ci.nsIObserver); +// Avoid default bookmarks import. +gluesvc.observe(null, "initial-migration-will-import-default-bookmarks", ""); + +function run_test() { + run_next_test(); +} + +add_task(function* smart_bookmarks_disabled() { + Services.prefs.setIntPref("browser.places.smartBookmarksVersion", -1); + yield rebuildSmartBookmarks(); + + let smartBookmarkItemIds = + PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO); + Assert.equal(smartBookmarkItemIds.length, 0); + + do_print("check that pref has not been bumped up"); + Assert.equal(Services.prefs.getIntPref("browser.places.smartBookmarksVersion"), -1); +}); + +add_task(function* create_smart_bookmarks() { + Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0); + yield rebuildSmartBookmarks(); + + let smartBookmarkItemIds = + PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO); + Assert.notEqual(smartBookmarkItemIds.length, 0); + + do_print("check that pref has been bumped up"); + Assert.ok(Services.prefs.getIntPref("browser.places.smartBookmarksVersion") > 0); +}); + +add_task(function* remove_smart_bookmark_and_restore() { + let smartBookmarkItemIds = + PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO); + let smartBookmarksCount = smartBookmarkItemIds.length; + do_print("remove one smart bookmark and restore"); + + let guid = yield PlacesUtils.promiseItemGuid(smartBookmarkItemIds[0]); + yield PlacesUtils.bookmarks.remove(guid); + Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0); + + yield rebuildSmartBookmarks(); + smartBookmarkItemIds = + PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO); + Assert.equal(smartBookmarkItemIds.length, smartBookmarksCount); + + do_print("check that pref has been bumped up"); + Assert.ok(Services.prefs.getIntPref("browser.places.smartBookmarksVersion") > 0); +}); + +add_task(function* move_smart_bookmark_rename_and_restore() { + let smartBookmarkItemIds = + PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO); + let smartBookmarksCount = smartBookmarkItemIds.length; + do_print("smart bookmark should be restored in place"); + + let guid = yield PlacesUtils.promiseItemGuid(smartBookmarkItemIds[0]); + let bm = yield PlacesUtils.bookmarks.fetch(guid); + let oldTitle = bm.title; + + // create a subfolder and move inside it + let subfolder = yield PlacesUtils.bookmarks.insert({ + parentGuid: bm.parentGuid, + title: "test", + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + type: PlacesUtils.bookmarks.TYPE_FOLDER + }); + + // change title and move into new subfolder + yield PlacesUtils.bookmarks.update({ + guid: guid, + parentGuid: subfolder.guid, + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + title: "new title" + }); + + // restore + Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0); + yield rebuildSmartBookmarks(); + + smartBookmarkItemIds = + PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO); + Assert.equal(smartBookmarkItemIds.length, smartBookmarksCount); + + guid = yield PlacesUtils.promiseItemGuid(smartBookmarkItemIds[0]); + bm = yield PlacesUtils.bookmarks.fetch(guid); + Assert.equal(bm.parentGuid, subfolder.guid); + Assert.equal(bm.title, oldTitle); + + do_print("check that pref has been bumped up"); + Assert.ok(Services.prefs.getIntPref("browser.places.smartBookmarksVersion") > 0); +}); diff --git a/browser/components/places/tests/unit/test_PUIU_makeTransaction.js b/browser/components/places/tests/unit/test_PUIU_makeTransaction.js new file mode 100644 index 000000000..c0626f53b --- /dev/null +++ b/browser/components/places/tests/unit/test_PUIU_makeTransaction.js @@ -0,0 +1,361 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function waitForBookmarkNotification(aNotification, aCallback, aProperty) +{ + PlacesUtils.bookmarks.addObserver({ + validate: function (aMethodName, aData) + { + if (aMethodName == aNotification && + (!aProperty || aProperty == aData.property)) { + PlacesUtils.bookmarks.removeObserver(this); + aCallback(aData); + } + }, + + // nsINavBookmarkObserver + QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]), + onBeginUpdateBatch: function onBeginUpdateBatch() { + return this.validate(arguments.callee.name, arguments); + }, + onEndUpdateBatch: function onEndUpdateBatch() { + return this.validate(arguments.callee.name, arguments); + }, + onItemAdded: function onItemAdded(aItemId, aParentId, aIndex, aItemType, + aURI, aTitle) + { + return this.validate(arguments.callee.name, { id: aItemId, + index: aIndex, + type: aItemType, + url: aURI ? aURI.spec : null, + title: aTitle }); + }, + onItemRemoved: function onItemRemoved() { + return this.validate(arguments.callee.name, arguments); + }, + onItemChanged: function onItemChanged(id, property, aIsAnno, + aNewValue, aLastModified, type) + { + return this.validate(arguments.callee.name, + { id, + get index() { + return PlacesUtils.bookmarks.getItemIndex(this.id); + }, + type, + property, + get url() { + return type == PlacesUtils.bookmarks.TYPE_BOOKMARK ? + PlacesUtils.bookmarks.getBookmarkURI(this.id).spec : + null; + }, + get title() { + return PlacesUtils.bookmarks.getItemTitle(this.id); + }, + }); + }, + onItemVisited: function onItemVisited() { + return this.validate(arguments.callee.name, arguments); + }, + onItemMoved: function onItemMoved(aItemId, aOldParentId, aOldIndex, + aNewParentId, aNewIndex, aItemType) + { + this.validate(arguments.callee.name, { id: aItemId, + index: aNewIndex, + type: aItemType }); + } + }, false); +} + +function wrapNodeByIdAndParent(aItemId, aParentId) +{ + let wrappedNode; + let root = PlacesUtils.getFolderContents(aParentId, false, false).root; + for (let i = 0; i < root.childCount; ++i) { + let node = root.getChild(i); + if (node.itemId == aItemId) { + let type; + if (PlacesUtils.nodeIsContainer(node)) { + type = PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER; + } + else if (PlacesUtils.nodeIsURI(node)) { + type = PlacesUtils.TYPE_X_MOZ_PLACE; + } + else if (PlacesUtils.nodeIsSeparator(node)) { + type = PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR; + } + else { + do_throw("Unknown node type"); + } + wrappedNode = PlacesUtils.wrapNode(node, type); + } + } + root.containerOpen = false; + return JSON.parse(wrappedNode); +} + +add_test(function test_text_paste() +{ + const TEST_URL = "http://places.moz.org/" + const TEST_TITLE = "Places bookmark" + + waitForBookmarkNotification("onItemAdded", function(aData) + { + do_check_eq(aData.title, TEST_TITLE); + do_check_eq(aData.url, TEST_URL); + do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); + do_check_eq(aData.index, 0); + run_next_test(); + }); + + let txn = PlacesUIUtils.makeTransaction( + { title: TEST_TITLE, uri: TEST_URL }, + PlacesUtils.TYPE_X_MOZ_URL, + PlacesUtils.unfiledBookmarksFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX, + true // Unused for text. + ); + PlacesUtils.transactionManager.doTransaction(txn); +}); + +add_test(function test_container() +{ + const TEST_TITLE = "Places folder" + + waitForBookmarkNotification("onItemChanged", function(aChangedData) + { + do_check_eq(aChangedData.title, TEST_TITLE); + do_check_eq(aChangedData.type, PlacesUtils.bookmarks.TYPE_FOLDER); + do_check_eq(aChangedData.index, 1); + + waitForBookmarkNotification("onItemAdded", function(aAddedData) + { + do_check_eq(aAddedData.title, TEST_TITLE); + do_check_eq(aAddedData.type, PlacesUtils.bookmarks.TYPE_FOLDER); + do_check_eq(aAddedData.index, 2); + let id = aAddedData.id; + + waitForBookmarkNotification("onItemMoved", function(aMovedData) + { + do_check_eq(aMovedData.id, id); + do_check_eq(aMovedData.type, PlacesUtils.bookmarks.TYPE_FOLDER); + do_check_eq(aMovedData.index, 1); + + run_next_test(); + }); + + let txn = PlacesUIUtils.makeTransaction( + wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId), + 0, // Unused for real nodes. + PlacesUtils.unfiledBookmarksFolderId, + 1, // Move to position 1. + false + ); + PlacesUtils.transactionManager.doTransaction(txn); + }); + + try { + let txn = PlacesUIUtils.makeTransaction( + wrapNodeByIdAndParent(aChangedData.id, PlacesUtils.unfiledBookmarksFolderId), + 0, // Unused for real nodes. + PlacesUtils.unfiledBookmarksFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX, + true + ); + PlacesUtils.transactionManager.doTransaction(txn); + } catch (ex) { + do_throw(ex); + } + }, "random-anno"); + + let id = PlacesUtils.bookmarks.createFolder(PlacesUtils.unfiledBookmarksFolderId, + TEST_TITLE, + PlacesUtils.bookmarks.DEFAULT_INDEX); + PlacesUtils.annotations.setItemAnnotation(id, PlacesUIUtils.DESCRIPTION_ANNO, + "description", 0, + PlacesUtils.annotations.EXPIRE_NEVER); + PlacesUtils.annotations.setItemAnnotation(id, "random-anno", + "random-value", 0, + PlacesUtils.annotations.EXPIRE_NEVER); +}); + + +add_test(function test_separator() +{ + waitForBookmarkNotification("onItemChanged", function(aChangedData) + { + do_check_eq(aChangedData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR); + do_check_eq(aChangedData.index, 3); + + waitForBookmarkNotification("onItemAdded", function(aAddedData) + { + do_check_eq(aAddedData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR); + do_check_eq(aAddedData.index, 4); + let id = aAddedData.id; + + waitForBookmarkNotification("onItemMoved", function(aMovedData) + { + do_check_eq(aMovedData.id, id); + do_check_eq(aMovedData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR); + do_check_eq(aMovedData.index, 1); + + run_next_test(); + }); + + let txn = PlacesUIUtils.makeTransaction( + wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId), + 0, // Unused for real nodes. + PlacesUtils.unfiledBookmarksFolderId, + 1, // Move to position 1. + false + ); + PlacesUtils.transactionManager.doTransaction(txn); + }); + + try { + let txn = PlacesUIUtils.makeTransaction( + wrapNodeByIdAndParent(aChangedData.id, PlacesUtils.unfiledBookmarksFolderId), + 0, // Unused for real nodes. + PlacesUtils.unfiledBookmarksFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX, + true + ); + PlacesUtils.transactionManager.doTransaction(txn); + } catch (ex) { + do_throw(ex); + } + }, "random-anno"); + + let id = PlacesUtils.bookmarks.insertSeparator(PlacesUtils.unfiledBookmarksFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX); + PlacesUtils.annotations.setItemAnnotation(id, "random-anno", + "random-value", 0, + PlacesUtils.annotations.EXPIRE_NEVER); +}); + +add_test(function test_bookmark() +{ + const TEST_URL = "http://places.moz.org/" + const TEST_TITLE = "Places bookmark" + + waitForBookmarkNotification("onItemChanged", function(aChangedData) + { + do_check_eq(aChangedData.title, TEST_TITLE); + do_check_eq(aChangedData.url, TEST_URL); + do_check_eq(aChangedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); + do_check_eq(aChangedData.index, 5); + + waitForBookmarkNotification("onItemAdded", function(aAddedData) + { + do_check_eq(aAddedData.title, TEST_TITLE); + do_check_eq(aAddedData.url, TEST_URL); + do_check_eq(aAddedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); + do_check_eq(aAddedData.index, 6); + let id = aAddedData.id; + + waitForBookmarkNotification("onItemMoved", function(aMovedData) + { + do_check_eq(aMovedData.id, id); + do_check_eq(aMovedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); + do_check_eq(aMovedData.index, 1); + + run_next_test(); + }); + + let txn = PlacesUIUtils.makeTransaction( + wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId), + 0, // Unused for real nodes. + PlacesUtils.unfiledBookmarksFolderId, + 1, // Move to position 1. + false + ); + PlacesUtils.transactionManager.doTransaction(txn); + }); + + try { + let txn = PlacesUIUtils.makeTransaction( + wrapNodeByIdAndParent(aChangedData.id, PlacesUtils.unfiledBookmarksFolderId), + 0, // Unused for real nodes. + PlacesUtils.unfiledBookmarksFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX, + true + ); + PlacesUtils.transactionManager.doTransaction(txn); + } catch (ex) { + do_throw(ex); + } + }, "random-anno"); + + let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, + NetUtil.newURI(TEST_URL), + PlacesUtils.bookmarks.DEFAULT_INDEX, + TEST_TITLE); + PlacesUtils.annotations.setItemAnnotation(id, PlacesUIUtils.DESCRIPTION_ANNO, + "description", 0, + PlacesUtils.annotations.EXPIRE_NEVER); + PlacesUtils.annotations.setItemAnnotation(id, "random-anno", + "random-value", 0, + PlacesUtils.annotations.EXPIRE_NEVER); +}); + +add_test(function test_visit() +{ + const TEST_URL = "http://places.moz.org/" + const TEST_TITLE = "Places bookmark" + + waitForBookmarkNotification("onItemAdded", function(aAddedData) + { + do_check_eq(aAddedData.title, TEST_TITLE); + do_check_eq(aAddedData.url, TEST_URL); + do_check_eq(aAddedData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); + do_check_eq(aAddedData.index, 7); + + waitForBookmarkNotification("onItemAdded", function(aAddedData2) + { + do_check_eq(aAddedData2.title, TEST_TITLE); + do_check_eq(aAddedData2.url, TEST_URL); + do_check_eq(aAddedData2.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); + do_check_eq(aAddedData2.index, 8); + run_next_test(); + }); + + try { + let node = wrapNodeByIdAndParent(aAddedData.id, PlacesUtils.unfiledBookmarksFolderId); + // Simulate a not-bookmarked node, will copy it to a new bookmark. + node.id = -1; + let txn = PlacesUIUtils.makeTransaction( + node, + 0, // Unused for real nodes. + PlacesUtils.unfiledBookmarksFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX, + true + ); + PlacesUtils.transactionManager.doTransaction(txn); + } catch (ex) { + do_throw(ex); + } + }); + + PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, + NetUtil.newURI(TEST_URL), + PlacesUtils.bookmarks.DEFAULT_INDEX, + TEST_TITLE); +}); + +add_test(function check_annotations() { + // As last step check how many items for each annotation exist. + + // Copies should retain the description annotation. + let descriptions = + PlacesUtils.annotations.getItemsWithAnnotation(PlacesUIUtils.DESCRIPTION_ANNO, {}); + do_check_eq(descriptions.length, 4); + + // Only the original bookmarks should have this annotation. + let others = PlacesUtils.annotations.getItemsWithAnnotation("random-anno", {}); + do_check_eq(others.length, 3); + run_next_test(); +}); + +function run_test() +{ + run_next_test(); +} diff --git a/browser/components/places/tests/unit/test_browserGlue_bookmarkshtml.js b/browser/components/places/tests/unit/test_browserGlue_bookmarkshtml.js new file mode 100644 index 000000000..4db21555f --- /dev/null +++ b/browser/components/places/tests/unit/test_browserGlue_bookmarkshtml.js @@ -0,0 +1,33 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + +/** + * Tests that nsBrowserGlue correctly exports bookmarks.html at shutdown if + * browser.bookmarks.autoExportHTML is set to true. + */ + +function run_test() { + run_next_test(); +} + +add_task(function* () { + remove_bookmarks_html(); + + Services.prefs.setBoolPref("browser.bookmarks.autoExportHTML", true); + do_register_cleanup(() => Services.prefs.clearUserPref("browser.bookmarks.autoExportHTML")); + + // Initialize nsBrowserGlue before Places. + Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsISupports); + + // Initialize Places through the History Service. + Cc["@mozilla.org/browser/nav-history-service;1"] + .getService(Ci.nsINavHistoryService); + + Services.obs.addObserver(function observer() { + Services.obs.removeObserver(observer, "profile-before-change"); + check_bookmarks_html(); + }, "profile-before-change", false); +}); diff --git a/browser/components/places/tests/unit/test_browserGlue_corrupt.js b/browser/components/places/tests/unit/test_browserGlue_corrupt.js new file mode 100644 index 000000000..5b2a09068 --- /dev/null +++ b/browser/components/places/tests/unit/test_browserGlue_corrupt.js @@ -0,0 +1,59 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + +/** + * Tests that nsBrowserGlue correctly restores bookmarks from a JSON backup if + * database is corrupt and one backup is available. + */ + +function run_test() { + // Create our bookmarks.html from bookmarks.glue.html. + create_bookmarks_html("bookmarks.glue.html"); + + remove_all_JSON_backups(); + + // Create our JSON backup from bookmarks.glue.json. + create_JSON_backup("bookmarks.glue.json"); + + run_next_test(); +} + +do_register_cleanup(function () { + remove_bookmarks_html(); + remove_all_JSON_backups(); + return PlacesUtils.bookmarks.eraseEverything(); +}); + +add_task(function* test_main() { + // Create a corrupt database. + yield createCorruptDB(); + + // Initialize nsBrowserGlue before Places. + Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsISupports); + + // Check the database was corrupt. + // nsBrowserGlue uses databaseStatus to manage initialization. + Assert.equal(PlacesUtils.history.databaseStatus, + PlacesUtils.history.DATABASE_STATUS_CORRUPT); + + // The test will continue once restore has finished and smart bookmarks + // have been created. + yield promiseTopicObserved("places-browser-init-complete"); + + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + yield checkItemHasAnnotation(bm.guid, SMART_BOOKMARKS_ANNO); + + // Check that JSON backup has been restored. + // Notice restore from JSON notification is fired before smart bookmarks creation. + bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: SMART_BOOKMARKS_ON_TOOLBAR + }); + Assert.equal(bm.title, "examplejson"); +}); diff --git a/browser/components/places/tests/unit/test_browserGlue_corrupt_nobackup.js b/browser/components/places/tests/unit/test_browserGlue_corrupt_nobackup.js new file mode 100644 index 000000000..7cb4e5e4c --- /dev/null +++ b/browser/components/places/tests/unit/test_browserGlue_corrupt_nobackup.js @@ -0,0 +1,52 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + +/** + * Tests that nsBrowserGlue correctly imports from bookmarks.html if database + * is corrupt but a JSON backup is not available. + */ + +function run_test() { + // Create our bookmarks.html from bookmarks.glue.html. + create_bookmarks_html("bookmarks.glue.html"); + + // Remove JSON backup from profile. + remove_all_JSON_backups(); + + run_next_test(); +} + +do_register_cleanup(remove_bookmarks_html); + +add_task(function* () { + // Create a corrupt database. + yield createCorruptDB(); + + // Initialize nsBrowserGlue before Places. + Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsISupports); + + // Check the database was corrupt. + // nsBrowserGlue uses databaseStatus to manage initialization. + Assert.equal(PlacesUtils.history.databaseStatus, + PlacesUtils.history.DATABASE_STATUS_CORRUPT); + + // The test will continue once import has finished and smart bookmarks + // have been created. + yield promiseTopicObserved("places-browser-init-complete"); + + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + yield checkItemHasAnnotation(bm.guid, SMART_BOOKMARKS_ANNO); + + // Check that bookmarks html has been restored. + bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: SMART_BOOKMARKS_ON_TOOLBAR + }); + Assert.equal(bm.title, "example"); +}); diff --git a/browser/components/places/tests/unit/test_browserGlue_corrupt_nobackup_default.js b/browser/components/places/tests/unit/test_browserGlue_corrupt_nobackup_default.js new file mode 100644 index 000000000..480420091 --- /dev/null +++ b/browser/components/places/tests/unit/test_browserGlue_corrupt_nobackup_default.js @@ -0,0 +1,55 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + +/** + * Tests that nsBrowserGlue correctly restores default bookmarks if database is + * corrupt, nor a JSON backup nor bookmarks.html are available. + */ + +Components.utils.import("resource://gre/modules/AppConstants.jsm"); + +function run_test() { + // Remove bookmarks.html from profile. + remove_bookmarks_html(); + + // Remove JSON backup from profile. + remove_all_JSON_backups(); + + run_next_test(); +} + +add_task(function* () { + // Create a corrupt database. + yield createCorruptDB(); + + // Initialize nsBrowserGlue before Places. + Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsISupports); + + // Check the database was corrupt. + // nsBrowserGlue uses databaseStatus to manage initialization. + Assert.equal(PlacesUtils.history.databaseStatus, + PlacesUtils.history.DATABASE_STATUS_CORRUPT); + + // The test will continue once import has finished and smart bookmarks + // have been created. + yield promiseTopicObserved("places-browser-init-complete"); + + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + yield checkItemHasAnnotation(bm.guid, SMART_BOOKMARKS_ANNO); + + // Check that default bookmarks have been restored. + bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: SMART_BOOKMARKS_ON_TOOLBAR + }); + + // Bug 1283076: Nightly bookmark points to Get Involved page, not Getting Started one + let chanTitle = AppConstants.NIGHTLY_BUILD ? "Get Involved" : "Getting Started"; + do_check_eq(bm.title, chanTitle); +}); diff --git a/browser/components/places/tests/unit/test_browserGlue_distribution.js b/browser/components/places/tests/unit/test_browserGlue_distribution.js new file mode 100644 index 000000000..c3d6e1d9e --- /dev/null +++ b/browser/components/places/tests/unit/test_browserGlue_distribution.js @@ -0,0 +1,125 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that nsBrowserGlue correctly imports bookmarks from distribution.ini. + */ + +const PREF_SMART_BOOKMARKS_VERSION = "browser.places.smartBookmarksVersion"; +const PREF_BMPROCESSED = "distribution.516444.bookmarksProcessed"; +const PREF_DISTRIBUTION_ID = "distribution.id"; + +const TOPICDATA_DISTRIBUTION_CUSTOMIZATION = "force-distribution-customization"; +const TOPIC_CUSTOMIZATION_COMPLETE = "distribution-customization-complete"; +const TOPIC_BROWSERGLUE_TEST = "browser-glue-test"; + +function run_test() { + // Set special pref to load distribution.ini from the profile folder. + Services.prefs.setBoolPref("distribution.testing.loadFromProfile", true); + + // Copy distribution.ini file to the profile dir. + let distroDir = gProfD.clone(); + distroDir.leafName = "distribution"; + let iniFile = distroDir.clone(); + iniFile.append("distribution.ini"); + if (iniFile.exists()) { + iniFile.remove(false); + print("distribution.ini already exists, did some test forget to cleanup?"); + } + + let testDistributionFile = gTestDir.clone(); + testDistributionFile.append("distribution.ini"); + testDistributionFile.copyTo(distroDir, "distribution.ini"); + Assert.ok(testDistributionFile.exists()); + + run_next_test(); +} + +do_register_cleanup(function () { + // Remove the distribution file, even if the test failed, otherwise all + // next tests will import it. + let iniFile = gProfD.clone(); + iniFile.leafName = "distribution"; + iniFile.append("distribution.ini"); + if (iniFile.exists()) { + iniFile.remove(false); + } + Assert.ok(!iniFile.exists()); +}); + +add_task(function* () { + // Disable Smart Bookmarks creation. + Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, -1); + + // Initialize Places through the History Service and check that a new + // database has been created. + Assert.equal(PlacesUtils.history.databaseStatus, + PlacesUtils.history.DATABASE_STATUS_CREATE); + + // Force distribution. + let glue = Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsIObserver) + glue.observe(null, TOPIC_BROWSERGLUE_TEST, TOPICDATA_DISTRIBUTION_CUSTOMIZATION); + + // Test will continue on customization complete notification. + yield promiseTopicObserved(TOPIC_CUSTOMIZATION_COMPLETE); + + // Check the custom bookmarks exist on menu. + let menuItem = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: 0 + }); + Assert.equal(menuItem.title, "Menu Link Before"); + + menuItem = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: 1 + DEFAULT_BOOKMARKS_ON_MENU + }); + Assert.equal(menuItem.title, "Menu Link After"); + + // Check no favicon or keyword exists for this bookmark + yield Assert.rejects(waitForResolvedPromise(() => { + return PlacesUtils.promiseFaviconData(menuItem.url.href); + }, "Favicon not found", 10), /Favicon\snot\sfound/, "Favicon not found"); + + let keywordItem = yield PlacesUtils.keywords.fetch({ + url: menuItem.url.href + }); + Assert.strictEqual(keywordItem, null); + + // Check the custom bookmarks exist on toolbar. + let toolbarItem = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + Assert.equal(toolbarItem.title, "Toolbar Link Before"); + + // Check the custom favicon and keyword exist for this bookmark + let faviconItem = yield waitForResolvedPromise(() => { + return PlacesUtils.promiseFaviconData(toolbarItem.url.href); + }, "Favicon not found", 10); + Assert.equal(faviconItem.uri.spec, "https://example.org/favicon.png"); + Assert.greater(faviconItem.dataLen, 0); + Assert.equal(faviconItem.mimeType, "image/png"); + + let base64Icon = "data:image/png;base64," + + base64EncodeString(String.fromCharCode.apply(String, faviconItem.data)); + Assert.equal(base64Icon, SMALLPNG_DATA_URI.spec); + + keywordItem = yield PlacesUtils.keywords.fetch({ + url: toolbarItem.url.href + }); + Assert.notStrictEqual(keywordItem, null); + Assert.equal(keywordItem.keyword, "e:t:b"); + + toolbarItem = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 1 + DEFAULT_BOOKMARKS_ON_TOOLBAR + }); + Assert.equal(toolbarItem.title, "Toolbar Link After"); + + // Check the bmprocessed pref has been created. + Assert.ok(Services.prefs.getBoolPref(PREF_BMPROCESSED)); + + // Check distribution prefs have been created. + Assert.equal(Services.prefs.getCharPref(PREF_DISTRIBUTION_ID), "516444"); +}); diff --git a/browser/components/places/tests/unit/test_browserGlue_migrate.js b/browser/components/places/tests/unit/test_browserGlue_migrate.js new file mode 100644 index 000000000..817f10c81 --- /dev/null +++ b/browser/components/places/tests/unit/test_browserGlue_migrate.js @@ -0,0 +1,70 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that nsBrowserGlue does not overwrite bookmarks imported from the + * migrators. They usually run before nsBrowserGlue, so if we find any + * bookmark on init, we should not try to import. + */ + +const PREF_SMART_BOOKMARKS_VERSION = "browser.places.smartBookmarksVersion"; + +function run_test() { + // Create our bookmarks.html from bookmarks.glue.html. + create_bookmarks_html("bookmarks.glue.html"); + + // Remove current database file. + clearDB(); + + run_next_test(); +} + +do_register_cleanup(remove_bookmarks_html); + +add_task(function* test_migrate_bookmarks() { + // Initialize Places through the History Service and check that a new + // database has been created. + Assert.equal(PlacesUtils.history.databaseStatus, + PlacesUtils.history.DATABASE_STATUS_CREATE); + + // A migrator would run before nsBrowserGlue Places initialization, so mimic + // that behavior adding a bookmark and notifying the migration. + let bg = Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsIObserver); + bg.observe(null, "initial-migration-will-import-default-bookmarks", null); + + yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + url: "http://mozilla.org/", + title: "migrated" + }); + + let promise = promiseTopicObserved("places-browser-init-complete"); + bg.observe(null, "initial-migration-did-import-default-bookmarks", null); + yield promise; + + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + yield checkItemHasAnnotation(bm.guid, SMART_BOOKMARKS_ANNO); + + // Check the created bookmark still exists. + bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: SMART_BOOKMARKS_ON_MENU + }); + Assert.equal(bm.title, "migrated"); + + // Check that we have not imported any new bookmark. + Assert.ok(!(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: SMART_BOOKMARKS_ON_MENU + 1 + }))); + + Assert.ok(!(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: SMART_BOOKMARKS_ON_MENU + }))); +}); diff --git a/browser/components/places/tests/unit/test_browserGlue_prefs.js b/browser/components/places/tests/unit/test_browserGlue_prefs.js new file mode 100644 index 000000000..9f3504636 --- /dev/null +++ b/browser/components/places/tests/unit/test_browserGlue_prefs.js @@ -0,0 +1,240 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that nsBrowserGlue is correctly interpreting the preferences settable + * by the user or by other components. + */ + +const PREF_IMPORT_BOOKMARKS_HTML = "browser.places.importBookmarksHTML"; +const PREF_RESTORE_DEFAULT_BOOKMARKS = "browser.bookmarks.restore_default_bookmarks"; +const PREF_SMART_BOOKMARKS_VERSION = "browser.places.smartBookmarksVersion"; +const PREF_AUTO_EXPORT_HTML = "browser.bookmarks.autoExportHTML"; + +const TOPIC_BROWSERGLUE_TEST = "browser-glue-test"; +const TOPICDATA_FORCE_PLACES_INIT = "force-places-init"; + +var bg = Cc["@mozilla.org/browser/browserglue;1"]. + getService(Ci.nsIObserver); + +function run_test() { + // Create our bookmarks.html from bookmarks.glue.html. + create_bookmarks_html("bookmarks.glue.html"); + + remove_all_JSON_backups(); + + // Create our JSON backup from bookmarks.glue.json. + create_JSON_backup("bookmarks.glue.json"); + + run_next_test(); +} + +do_register_cleanup(function () { + remove_bookmarks_html(); + remove_all_JSON_backups(); + + return PlacesUtils.bookmarks.eraseEverything(); +}); + +function simulatePlacesInit() { + do_print("Simulate Places init"); + // Force nsBrowserGlue::_initPlaces(). + bg.observe(null, TOPIC_BROWSERGLUE_TEST, TOPICDATA_FORCE_PLACES_INIT); + return promiseTopicObserved("places-browser-init-complete"); +} + +add_task(function* test_checkPreferences() { + // Initialize Places through the History Service and check that a new + // database has been created. + Assert.equal(PlacesUtils.history.databaseStatus, + PlacesUtils.history.DATABASE_STATUS_CREATE); + + // Wait for Places init notification. + yield promiseTopicObserved("places-browser-init-complete"); + + // Ensure preferences status. + Assert.ok(!Services.prefs.getBoolPref(PREF_AUTO_EXPORT_HTML)); + + Assert.throws(() => Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML)); + Assert.throws(() => Services.prefs.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS)); +}); + +add_task(function* test_import() { + do_print("Import from bookmarks.html if importBookmarksHTML is true."); + + yield PlacesUtils.bookmarks.eraseEverything(); + + // Sanity check: we should not have any bookmark on the toolbar. + Assert.ok(!(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }))); + + // Set preferences. + Services.prefs.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true); + + yield simulatePlacesInit(); + + // Check bookmarks.html has been imported, and a smart bookmark has been + // created. + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: SMART_BOOKMARKS_ON_TOOLBAR + }); + Assert.equal(bm.title, "example"); + + // Check preferences have been reverted. + Assert.ok(!Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML)); +}); + +add_task(function* test_import_noSmartBookmarks() { + do_print("import from bookmarks.html, but don't create smart bookmarks " + + "if they are disabled"); + + yield PlacesUtils.bookmarks.eraseEverything(); + + // Sanity check: we should not have any bookmark on the toolbar. + Assert.ok(!(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }))); + + // Set preferences. + Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, -1); + Services.prefs.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true); + + yield simulatePlacesInit(); + + // Check bookmarks.html has been imported, but smart bookmarks have not + // been created. + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + Assert.equal(bm.title, "example"); + + // Check preferences have been reverted. + Assert.ok(!Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML)); +}); + +add_task(function* test_import_autoExport_updatedSmartBookmarks() { + do_print("Import from bookmarks.html, but don't create smart bookmarks " + + "if autoExportHTML is true and they are at latest version"); + + yield PlacesUtils.bookmarks.eraseEverything(); + + // Sanity check: we should not have any bookmark on the toolbar. + Assert.ok(!(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }))); + + // Set preferences. + Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 999); + Services.prefs.setBoolPref(PREF_AUTO_EXPORT_HTML, true); + Services.prefs.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true); + + yield simulatePlacesInit(); + + // Check bookmarks.html has been imported, but smart bookmarks have not + // been created. + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + Assert.equal(bm.title, "example"); + + // Check preferences have been reverted. + Assert.ok(!Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML)); + + Services.prefs.setBoolPref(PREF_AUTO_EXPORT_HTML, false); +}); + +add_task(function* test_import_autoExport_oldSmartBookmarks() { + do_print("Import from bookmarks.html, and create smart bookmarks if " + + "autoExportHTML is true and they are not at latest version."); + + yield PlacesUtils.bookmarks.eraseEverything(); + + // Sanity check: we should not have any bookmark on the toolbar. + Assert.ok(!(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }))); + + // Set preferences. + Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 0); + Services.prefs.setBoolPref(PREF_AUTO_EXPORT_HTML, true); + Services.prefs.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true); + + yield simulatePlacesInit(); + + // Check bookmarks.html has been imported, but smart bookmarks have not + // been created. + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: SMART_BOOKMARKS_ON_TOOLBAR + }); + Assert.equal(bm.title, "example"); + + // Check preferences have been reverted. + Assert.ok(!Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML)); + + Services.prefs.setBoolPref(PREF_AUTO_EXPORT_HTML, false); +}); + +add_task(function* test_restore() { + do_print("restore from default bookmarks.html if " + + "restore_default_bookmarks is true."); + + yield PlacesUtils.bookmarks.eraseEverything(); + + // Sanity check: we should not have any bookmark on the toolbar. + Assert.ok(!(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }))); + + // Set preferences. + Services.prefs.setBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS, true); + + yield simulatePlacesInit(); + + // Check bookmarks.html has been restored. + Assert.ok(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: SMART_BOOKMARKS_ON_TOOLBAR + })); + + // Check preferences have been reverted. + Assert.ok(!Services.prefs.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS)); +}); + +add_task(function* test_restore_import() { + do_print("setting both importBookmarksHTML and " + + "restore_default_bookmarks should restore defaults."); + + yield PlacesUtils.bookmarks.eraseEverything(); + + // Sanity check: we should not have any bookmark on the toolbar. + Assert.ok(!(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }))); + + // Set preferences. + Services.prefs.setBoolPref(PREF_IMPORT_BOOKMARKS_HTML, true); + Services.prefs.setBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS, true); + + yield simulatePlacesInit(); + + // Check bookmarks.html has been restored. + Assert.ok(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: SMART_BOOKMARKS_ON_TOOLBAR + })); + + // Check preferences have been reverted. + Assert.ok(!Services.prefs.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS)); + Assert.ok(!Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML)); +}); diff --git a/browser/components/places/tests/unit/test_browserGlue_restore.js b/browser/components/places/tests/unit/test_browserGlue_restore.js new file mode 100644 index 000000000..9d7ac5ac1 --- /dev/null +++ b/browser/components/places/tests/unit/test_browserGlue_restore.js @@ -0,0 +1,62 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + +/** + * Tests that nsBrowserGlue correctly restores bookmarks from a JSON backup if + * database has been created and one backup is available. + */ + +function run_test() { + // Create our bookmarks.html from bookmarks.glue.html. + create_bookmarks_html("bookmarks.glue.html"); + + remove_all_JSON_backups(); + + // Create our JSON backup from bookmarks.glue.json. + create_JSON_backup("bookmarks.glue.json"); + + // Remove current database file. + clearDB(); + + run_next_test(); +} + +do_register_cleanup(function () { + remove_bookmarks_html(); + remove_all_JSON_backups(); + return PlacesUtils.bookmarks.eraseEverything(); +}); + +add_task(function* test_main() { + // Initialize nsBrowserGlue before Places. + Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsISupports); + + // Initialize Places through the History Service. + let hs = Cc["@mozilla.org/browser/nav-history-service;1"]. + getService(Ci.nsINavHistoryService); + + // Check a new database has been created. + // nsBrowserGlue uses databaseStatus to manage initialization. + Assert.equal(hs.databaseStatus, hs.DATABASE_STATUS_CREATE); + + // The test will continue once restore has finished and smart bookmarks + // have been created. + yield promiseTopicObserved("places-browser-init-complete"); + + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + yield checkItemHasAnnotation(bm.guid, SMART_BOOKMARKS_ANNO); + + // Check that JSON backup has been restored. + // Notice restore from JSON notification is fired before smart bookmarks creation. + bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: SMART_BOOKMARKS_ON_TOOLBAR + }); + Assert.equal(bm.title, "examplejson"); +}); diff --git a/browser/components/places/tests/unit/test_browserGlue_smartBookmarks.js b/browser/components/places/tests/unit/test_browserGlue_smartBookmarks.js new file mode 100644 index 000000000..6ecaec4fe --- /dev/null +++ b/browser/components/places/tests/unit/test_browserGlue_smartBookmarks.js @@ -0,0 +1,285 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + +/** + * Tests that nsBrowserGlue is correctly interpreting the preferences settable + * by the user or by other components. + */ + +const PREF_SMART_BOOKMARKS_VERSION = "browser.places.smartBookmarksVersion"; +const PREF_AUTO_EXPORT_HTML = "browser.bookmarks.autoExportHTML"; +const PREF_IMPORT_BOOKMARKS_HTML = "browser.places.importBookmarksHTML"; +const PREF_RESTORE_DEFAULT_BOOKMARKS = "browser.bookmarks.restore_default_bookmarks"; + +function run_test() { + remove_bookmarks_html(); + remove_all_JSON_backups(); + run_next_test(); +} + +do_register_cleanup(() => PlacesUtils.bookmarks.eraseEverything()); + +function countFolderChildren(aFolderItemId) { + let rootNode = PlacesUtils.getFolderContents(aFolderItemId).root; + let cc = rootNode.childCount; + // Dump contents. + for (let i = 0; i < cc ; i++) { + let node = rootNode.getChild(i); + let title = PlacesUtils.nodeIsSeparator(node) ? "---" : node.title; + print("Found child(" + i + "): " + title); + } + rootNode.containerOpen = false; + return cc; +} + +add_task(function* setup() { + // Initialize browserGlue, but remove it's listener to places-init-complete. + Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsIObserver); + + // Initialize Places. + PlacesUtils.history; + + // Wait for Places init notification. + yield promiseTopicObserved("places-browser-init-complete"); + + // Ensure preferences status. + Assert.ok(!Services.prefs.getBoolPref(PREF_AUTO_EXPORT_HTML)); + Assert.ok(!Services.prefs.getBoolPref(PREF_RESTORE_DEFAULT_BOOKMARKS)); + Assert.throws(() => Services.prefs.getBoolPref(PREF_IMPORT_BOOKMARKS_HTML)); +}); + +add_task(function* test_version_0() { + do_print("All smart bookmarks are created if smart bookmarks version is 0."); + + // Sanity check: we should have default bookmark. + Assert.ok(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + })); + + Assert.ok(yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: 0 + })); + + // Set preferences. + Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 0); + + yield rebuildSmartBookmarks(); + + // Count items. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + // Check version has been updated. + Assert.equal(Services.prefs.getIntPref(PREF_SMART_BOOKMARKS_VERSION), + SMART_BOOKMARKS_VERSION); +}); + +add_task(function* test_version_change() { + do_print("An existing smart bookmark is replaced when version changes."); + + // Sanity check: we have a smart bookmark on the toolbar. + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + yield checkItemHasAnnotation(bm.guid, SMART_BOOKMARKS_ANNO); + + // Change its title. + yield PlacesUtils.bookmarks.update({guid: bm.guid, title: "new title"}); + bm = yield PlacesUtils.bookmarks.fetch({guid: bm.guid}); + Assert.equal(bm.title, "new title"); + + // Sanity check items. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + // Set preferences. + Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 1); + + yield rebuildSmartBookmarks(); + + // Count items. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + // Check smart bookmark has been replaced, itemId has changed. + bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + yield checkItemHasAnnotation(bm.guid, SMART_BOOKMARKS_ANNO); + Assert.notEqual(bm.title, "new title"); + + // Check version has been updated. + Assert.equal(Services.prefs.getIntPref(PREF_SMART_BOOKMARKS_VERSION), + SMART_BOOKMARKS_VERSION); +}); + +add_task(function* test_version_change_pos() { + do_print("bookmarks position is retained when version changes."); + + // Sanity check items. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: 0 + }); + yield checkItemHasAnnotation(bm.guid, SMART_BOOKMARKS_ANNO); + let firstItemTitle = bm.title; + + // Set preferences. + Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 1); + + yield rebuildSmartBookmarks(); + + // Count items. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + // Check smart bookmarks are still in correct position. + bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: 0 + }); + yield checkItemHasAnnotation(bm.guid, SMART_BOOKMARKS_ANNO); + Assert.equal(bm.title, firstItemTitle); + + // Check version has been updated. + Assert.equal(Services.prefs.getIntPref(PREF_SMART_BOOKMARKS_VERSION), + SMART_BOOKMARKS_VERSION); +}); + +add_task(function* test_version_change_pos_moved() { + do_print("moved bookmarks position is retained when version changes."); + + // Sanity check items. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + let bm1 = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: 0 + }); + yield checkItemHasAnnotation(bm1.guid, SMART_BOOKMARKS_ANNO); + let firstItemTitle = bm1.title; + + // Move the first smart bookmark to the end of the menu. + yield PlacesUtils.bookmarks.update({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + guid: bm1.guid, + index: PlacesUtils.bookmarks.DEFAULT_INDEX + }); + + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: PlacesUtils.bookmarks.DEFAULT_INDEX + }); + Assert.equal(bm.guid, bm1.guid); + + // Set preferences. + Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 1); + + yield rebuildSmartBookmarks(); + + // Count items. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + bm1 = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + index: PlacesUtils.bookmarks.DEFAULT_INDEX + }); + yield checkItemHasAnnotation(bm1.guid, SMART_BOOKMARKS_ANNO); + Assert.equal(bm1.title, firstItemTitle); + + // Move back the smart bookmark to the original position. + yield PlacesUtils.bookmarks.update({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + guid: bm1.guid, + index: 1 + }); + + // Check version has been updated. + Assert.equal(Services.prefs.getIntPref(PREF_SMART_BOOKMARKS_VERSION), + SMART_BOOKMARKS_VERSION); +}); + +add_task(function* test_recreation() { + do_print("An explicitly removed smart bookmark should not be recreated."); + + // Remove toolbar's smart bookmarks + let bm = yield PlacesUtils.bookmarks.fetch({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + index: 0 + }); + yield PlacesUtils.bookmarks.remove(bm.guid); + + // Sanity check items. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + // Set preferences. + Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 1); + + yield rebuildSmartBookmarks(); + + // Count items. + // We should not have recreated the smart bookmark on toolbar. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + // Check version has been updated. + Assert.equal(Services.prefs.getIntPref(PREF_SMART_BOOKMARKS_VERSION), + SMART_BOOKMARKS_VERSION); +}); + +add_task(function* test_recreation_version_0() { + do_print("Even if a smart bookmark has been removed recreate it if version is 0."); + + // Sanity check items. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + // Set preferences. + Services.prefs.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 0); + + yield rebuildSmartBookmarks(); + + // Count items. + // We should not have recreated the smart bookmark on toolbar. + Assert.equal(countFolderChildren(PlacesUtils.toolbarFolderId), + SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR); + Assert.equal(countFolderChildren(PlacesUtils.bookmarksMenuFolderId), + SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU); + + // Check version has been updated. + Assert.equal(Services.prefs.getIntPref(PREF_SMART_BOOKMARKS_VERSION), + SMART_BOOKMARKS_VERSION); +}); diff --git a/browser/components/places/tests/unit/test_browserGlue_urlbar_defaultbehavior_migration.js b/browser/components/places/tests/unit/test_browserGlue_urlbar_defaultbehavior_migration.js new file mode 100644 index 000000000..072056b3f --- /dev/null +++ b/browser/components/places/tests/unit/test_browserGlue_urlbar_defaultbehavior_migration.js @@ -0,0 +1,150 @@ +/* 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/. */ + +const UI_VERSION = 26; +const TOPIC_BROWSERGLUE_TEST = "browser-glue-test"; +const TOPICDATA_BROWSERGLUE_TEST = "force-ui-migration"; +const DEFAULT_BEHAVIOR_PREF = "browser.urlbar.default.behavior"; +const AUTOCOMPLETE_PREF = "browser.urlbar.autocomplete.enabled"; + +var gBrowserGlue = Cc["@mozilla.org/browser/browserglue;1"] + .getService(Ci.nsIObserver); +var gGetBoolPref = Services.prefs.getBoolPref; + +function run_test() { + run_next_test(); +} + +do_register_cleanup(cleanup); + +function cleanup() { + let prefix = "browser.urlbar.suggest."; + for (let type of ["history", "bookmark", "openpage", "history.onlyTyped"]) { + Services.prefs.clearUserPref(prefix + type); + } + Services.prefs.clearUserPref("browser.migration.version"); + Services.prefs.clearUserPref(AUTOCOMPLETE_PREF); +} + +function setupBehaviorAndMigrate(aDefaultBehavior, aAutocompleteEnabled = true) { + cleanup(); + // Migrate browser.urlbar.default.behavior preference. + Services.prefs.setIntPref("browser.migration.version", UI_VERSION - 1); + Services.prefs.setIntPref(DEFAULT_BEHAVIOR_PREF, aDefaultBehavior); + Services.prefs.setBoolPref(AUTOCOMPLETE_PREF, aAutocompleteEnabled); + // Simulate a migration. + gBrowserGlue.observe(null, TOPIC_BROWSERGLUE_TEST, TOPICDATA_BROWSERGLUE_TEST); +} + +add_task(function*() { + do_print("Migrate default.behavior = 0"); + setupBehaviorAndMigrate(0); + + Assert.ok(gGetBoolPref("browser.urlbar.suggest.history"), + "History preference should be true."); + Assert.ok(gGetBoolPref("browser.urlbar.suggest.bookmark"), + "Bookmark preference should be true."); + Assert.ok(gGetBoolPref("browser.urlbar.suggest.openpage"), + "Openpage preference should be true."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.history.onlyTyped"), false, + "Typed preference should be false."); +}); + +add_task(function*() { + do_print("Migrate default.behavior = 1"); + setupBehaviorAndMigrate(1); + + Assert.ok(gGetBoolPref("browser.urlbar.suggest.history"), + "History preference should be true."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.bookmark"), false, + "Bookmark preference should be false."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.openpage"), false, + "Openpage preference should be false"); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.history.onlyTyped"), false, + "Typed preference should be false"); +}); + +add_task(function*() { + do_print("Migrate default.behavior = 2"); + setupBehaviorAndMigrate(2); + + Assert.equal(gGetBoolPref("browser.urlbar.suggest.history"), false, + "History preference should be false."); + Assert.ok(gGetBoolPref("browser.urlbar.suggest.bookmark"), + "Bookmark preference should be true."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.openpage"), false, + "Openpage preference should be false"); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.history.onlyTyped"), false, + "Typed preference should be false"); +}); + +add_task(function*() { + do_print("Migrate default.behavior = 3"); + setupBehaviorAndMigrate(3); + + Assert.ok(gGetBoolPref("browser.urlbar.suggest.history"), + "History preference should be true."); + Assert.ok(gGetBoolPref("browser.urlbar.suggest.bookmark"), + "Bookmark preference should be true."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.openpage"), false, + "Openpage preference should be false"); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.history.onlyTyped"), false, + "Typed preference should be false"); +}); + +add_task(function*() { + do_print("Migrate default.behavior = 19"); + setupBehaviorAndMigrate(19); + + Assert.ok(gGetBoolPref("browser.urlbar.suggest.history"), + "History preference should be true."); + Assert.ok(gGetBoolPref("browser.urlbar.suggest.bookmark"), + "Bookmark preference should be true."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.openpage"), false, + "Openpage preference should be false"); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.history.onlyTyped"), false, + "Typed preference should be false"); +}); + +add_task(function*() { + do_print("Migrate default.behavior = 33"); + setupBehaviorAndMigrate(33); + + Assert.ok(gGetBoolPref("browser.urlbar.suggest.history"), + "History preference should be true."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.bookmark"), false, + "Bookmark preference should be false."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.openpage"), false, + "Openpage preference should be false"); + Assert.ok(gGetBoolPref("browser.urlbar.suggest.history.onlyTyped"), + "Typed preference should be true"); +}); + +add_task(function*() { + do_print("Migrate default.behavior = 129"); + setupBehaviorAndMigrate(129); + + Assert.ok(gGetBoolPref("browser.urlbar.suggest.history"), + "History preference should be true."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.bookmark"), false, + "Bookmark preference should be false."); + Assert.ok(gGetBoolPref("browser.urlbar.suggest.openpage"), + "Openpage preference should be true"); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.history.onlyTyped"), false, + "Typed preference should be false"); +}); + +add_task(function*() { + do_print("Migrate default.behavior = 0, autocomplete.enabled = false"); + setupBehaviorAndMigrate(0, false); + + Assert.equal(gGetBoolPref("browser.urlbar.suggest.history"), false, + "History preference should be false."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.bookmark"), false, + "Bookmark preference should be false."); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.openpage"), false, + "Openpage preference should be false"); + Assert.equal(gGetBoolPref("browser.urlbar.suggest.history.onlyTyped"), false, + "Typed preference should be false"); +}); diff --git a/browser/components/places/tests/unit/test_clearHistory_shutdown.js b/browser/components/places/tests/unit/test_clearHistory_shutdown.js new file mode 100644 index 000000000..0c1d78801 --- /dev/null +++ b/browser/components/places/tests/unit/test_clearHistory_shutdown.js @@ -0,0 +1,181 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + +/** + * Tests that requesting clear history at shutdown will really clear history. + */ + +const URIS = [ + "http://a.example1.com/" +, "http://b.example1.com/" +, "http://b.example2.com/" +, "http://c.example3.com/" +]; + +const TOPIC_CONNECTION_CLOSED = "places-connection-closed"; + +var EXPECTED_NOTIFICATIONS = [ + "places-shutdown" +, "places-will-close-connection" +, "places-expiration-finished" +, "places-connection-closed" +]; + +const UNEXPECTED_NOTIFICATIONS = [ + "xpcom-shutdown" +]; + +const FTP_URL = "ftp://localhost/clearHistoryOnShutdown/"; + +// Send the profile-after-change notification to the form history component to ensure +// that it has been initialized. +var formHistoryStartup = Cc["@mozilla.org/satchel/form-history-startup;1"]. + getService(Ci.nsIObserver); +formHistoryStartup.observe(null, "profile-after-change", null); +XPCOMUtils.defineLazyModuleGetter(this, "FormHistory", + "resource://gre/modules/FormHistory.jsm"); + +var timeInMicroseconds = Date.now() * 1000; + +function run_test() { + run_next_test(); +} + +add_task(function* test_execute() { + do_print("Initialize browserglue before Places"); + + // Avoid default bookmarks import. + let glue = Cc["@mozilla.org/browser/browserglue;1"]. + getService(Ci.nsIObserver); + glue.observe(null, "initial-migration-will-import-default-bookmarks", null); + glue.observe(null, "test-initialize-sanitizer", null); + + + Services.prefs.setBoolPref("privacy.clearOnShutdown.cache", true); + Services.prefs.setBoolPref("privacy.clearOnShutdown.cookies", true); + Services.prefs.setBoolPref("privacy.clearOnShutdown.offlineApps", true); + Services.prefs.setBoolPref("privacy.clearOnShutdown.history", true); + Services.prefs.setBoolPref("privacy.clearOnShutdown.downloads", true); + Services.prefs.setBoolPref("privacy.clearOnShutdown.cookies", true); + Services.prefs.setBoolPref("privacy.clearOnShutdown.formData", true); + Services.prefs.setBoolPref("privacy.clearOnShutdown.sessions", true); + Services.prefs.setBoolPref("privacy.clearOnShutdown.siteSettings", true); + + Services.prefs.setBoolPref("privacy.sanitize.sanitizeOnShutdown", true); + + do_print("Add visits."); + for (let aUrl of URIS) { + yield PlacesTestUtils.addVisits({ + uri: uri(aUrl), visitDate: timeInMicroseconds++, + transition: PlacesUtils.history.TRANSITION_TYPED + }); + } + do_print("Add cache."); + yield storeCache(FTP_URL, "testData"); + do_print("Add form history."); + yield addFormHistory(); + Assert.equal((yield getFormHistoryCount()), 1, "Added form history"); + + do_print("Simulate and wait shutdown."); + yield shutdownPlaces(); + + Assert.equal((yield getFormHistoryCount()), 0, "Form history cleared"); + + let stmt = DBConn(true).createStatement( + "SELECT id FROM moz_places WHERE url = :page_url " + ); + + try { + URIS.forEach(function(aUrl) { + stmt.params.page_url = aUrl; + do_check_false(stmt.executeStep()); + stmt.reset(); + }); + } finally { + stmt.finalize(); + } + + do_print("Check cache"); + // Check cache. + yield checkCache(FTP_URL); +}); + +function addFormHistory() { + return new Promise(resolve => { + let now = Date.now() * 1000; + FormHistory.update({ op: "add", + fieldname: "testfield", + value: "test", + timesUsed: 1, + firstUsed: now, + lastUsed: now + }, + { handleCompletion(reason) { resolve(); } }); + }); +} + +function getFormHistoryCount() { + return new Promise((resolve, reject) => { + let count = -1; + FormHistory.count({ fieldname: "testfield" }, + { handleResult(result) { count = result; }, + handleCompletion(reason) { resolve(count); } + }); + }); +} + +function storeCache(aURL, aContent) { + let cache = Services.cache2; + let storage = cache.diskCacheStorage(LoadContextInfo.default, false); + + return new Promise(resolve => { + let storeCacheListener = { + onCacheEntryCheck: function (entry, appcache) { + return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; + }, + + onCacheEntryAvailable: function (entry, isnew, appcache, status) { + do_check_eq(status, Cr.NS_OK); + + entry.setMetaDataElement("servertype", "0"); + var os = entry.openOutputStream(0); + + var written = os.write(aContent, aContent.length); + if (written != aContent.length) { + do_throw("os.write has not written all data!\n" + + " Expected: " + written + "\n" + + " Actual: " + aContent.length + "\n"); + } + os.close(); + entry.close(); + resolve(); + } + }; + + storage.asyncOpenURI(Services.io.newURI(aURL, null, null), "", + Ci.nsICacheStorage.OPEN_NORMALLY, + storeCacheListener); + }); +} + + +function checkCache(aURL) { + let cache = Services.cache2; + let storage = cache.diskCacheStorage(LoadContextInfo.default, false); + + return new Promise(resolve => { + let checkCacheListener = { + onCacheEntryAvailable: function (entry, isnew, appcache, status) { + do_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND); + resolve(); + } + }; + + storage.asyncOpenURI(Services.io.newURI(aURL, null, null), "", + Ci.nsICacheStorage.OPEN_READONLY, + checkCacheListener); + }); +} diff --git a/browser/components/places/tests/unit/test_leftpane_corruption_handling.js b/browser/components/places/tests/unit/test_leftpane_corruption_handling.js new file mode 100644 index 000000000..0af6f4e95 --- /dev/null +++ b/browser/components/places/tests/unit/test_leftpane_corruption_handling.js @@ -0,0 +1,174 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* 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/. */ + +/** + * Tests that we build a working leftpane in various corruption situations. + */ + +// Used to store the original leftPaneFolderId getter. +var gLeftPaneFolderIdGetter; +var gAllBookmarksFolderIdGetter; +// Used to store the original left Pane status as a JSON string. +var gReferenceHierarchy; +var gLeftPaneFolderId; + +add_task(function* () { + // We want empty roots. + yield PlacesUtils.bookmarks.eraseEverything(); + + // Sanity check. + Assert.ok(!!PlacesUIUtils); + + // Check getters. + gLeftPaneFolderIdGetter = Object.getOwnPropertyDescriptor(PlacesUIUtils, "leftPaneFolderId"); + Assert.equal(typeof(gLeftPaneFolderIdGetter.get), "function"); + gAllBookmarksFolderIdGetter = Object.getOwnPropertyDescriptor(PlacesUIUtils, "allBookmarksFolderId"); + Assert.equal(typeof(gAllBookmarksFolderIdGetter.get), "function"); + + do_register_cleanup(() => PlacesUtils.bookmarks.eraseEverything()); +}); + +add_task(function* () { + // Add a third party bogus annotated item. Should not be removed. + let folder = yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: "test", + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + type: PlacesUtils.bookmarks.TYPE_FOLDER + }); + + let folderId = yield PlacesUtils.promiseItemId(folder.guid); + PlacesUtils.annotations.setItemAnnotation(folderId, ORGANIZER_QUERY_ANNO, + "test", 0, + PlacesUtils.annotations.EXPIRE_NEVER); + + // Create the left pane, and store its current status, it will be used + // as reference value. + gLeftPaneFolderId = PlacesUIUtils.leftPaneFolderId; + gReferenceHierarchy = folderIdToHierarchy(gLeftPaneFolderId); + + while (gTests.length) { + // Run current test. + yield Task.spawn(gTests.shift()); + + // Regenerate getters. + Object.defineProperty(PlacesUIUtils, "leftPaneFolderId", gLeftPaneFolderIdGetter); + gLeftPaneFolderId = PlacesUIUtils.leftPaneFolderId; + Object.defineProperty(PlacesUIUtils, "allBookmarksFolderId", gAllBookmarksFolderIdGetter); + + // Check the new left pane folder. + let leftPaneHierarchy = folderIdToHierarchy(gLeftPaneFolderId) + Assert.equal(gReferenceHierarchy, leftPaneHierarchy); + + folder = yield PlacesUtils.bookmarks.fetch({guid: folder.guid}); + Assert.equal(folder.title, "test"); + } +}); + +// Corruption cases. +var gTests = [ + + function* test1() { + print("1. Do nothing, checks test calibration."); + }, + + function* test2() { + print("2. Delete the left pane folder."); + let guid = yield PlacesUtils.promiseItemGuid(gLeftPaneFolderId); + yield PlacesUtils.bookmarks.remove(guid); + }, + + function* test3() { + print("3. Delete a child of the left pane folder."); + let guid = yield PlacesUtils.promiseItemGuid(gLeftPaneFolderId); + let bm = yield PlacesUtils.bookmarks.fetch({parentGuid: guid, index: 0}); + yield PlacesUtils.bookmarks.remove(bm.guid); + }, + + function* test4() { + print("4. Delete AllBookmarks."); + let guid = yield PlacesUtils.promiseItemGuid(PlacesUIUtils.allBookmarksFolderId); + yield PlacesUtils.bookmarks.remove(guid); + }, + + function* test5() { + print("5. Create a duplicated left pane folder."); + let folder = yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: "PlacesRoot", + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + type: PlacesUtils.bookmarks.TYPE_FOLDER + }); + + let folderId = yield PlacesUtils.promiseItemId(folder.guid); + PlacesUtils.annotations.setItemAnnotation(folderId, ORGANIZER_FOLDER_ANNO, + "PlacesRoot", 0, + PlacesUtils.annotations.EXPIRE_NEVER); + }, + + function* test6() { + print("6. Create a duplicated left pane query."); + let folder = yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: "AllBookmarks", + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + type: PlacesUtils.bookmarks.TYPE_FOLDER + }); + + let folderId = yield PlacesUtils.promiseItemId(folder.guid); + PlacesUtils.annotations.setItemAnnotation(folderId, ORGANIZER_QUERY_ANNO, + "AllBookmarks", 0, + PlacesUtils.annotations.EXPIRE_NEVER); + }, + + function* test7() { + print("7. Remove the left pane folder annotation."); + PlacesUtils.annotations.removeItemAnnotation(gLeftPaneFolderId, + ORGANIZER_FOLDER_ANNO); + }, + + function* test8() { + print("8. Remove a left pane query annotation."); + PlacesUtils.annotations.removeItemAnnotation(PlacesUIUtils.allBookmarksFolderId, + ORGANIZER_QUERY_ANNO); + }, + + function* test9() { + print("9. Remove a child of AllBookmarks."); + let guid = yield PlacesUtils.promiseItemGuid(PlacesUIUtils.allBookmarksFolderId); + let bm = yield PlacesUtils.bookmarks.fetch({parentGuid: guid, index: 0}); + yield PlacesUtils.bookmarks.remove(bm.guid); + } + +]; + +/** + * Convert a folder item id to a JSON representation of it and its contents. + */ +function folderIdToHierarchy(aFolderId) { + let root = PlacesUtils.getFolderContents(aFolderId).root; + let hier = JSON.stringify(hierarchyToObj(root)); + root.containerOpen = false; + return hier; +} + +function hierarchyToObj(aNode) { + let o = {} + o.title = aNode.title; + o.annos = PlacesUtils.getAnnotationsForItem(aNode.itemId) + if (PlacesUtils.nodeIsURI(aNode)) { + o.uri = aNode.uri; + } + else if (PlacesUtils.nodeIsFolder(aNode)) { + o.children = []; + PlacesUtils.asContainer(aNode).containerOpen = true; + for (let i = 0; i < aNode.childCount; ++i) { + o.children.push(hierarchyToObj(aNode.getChild(i))); + } + aNode.containerOpen = false; + } + return o; +} diff --git a/browser/components/places/tests/unit/xpcshell.ini b/browser/components/places/tests/unit/xpcshell.ini new file mode 100644 index 000000000..1c40e1c53 --- /dev/null +++ b/browser/components/places/tests/unit/xpcshell.ini @@ -0,0 +1,25 @@ +[DEFAULT] +head = head_bookmarks.js +tail = +firefox-appdir = browser +skip-if = toolkit == 'android' +support-files = + bookmarks.glue.html + bookmarks.glue.json + corruptDB.sqlite + distribution.ini + +[test_421483.js] +[test_browserGlue_bookmarkshtml.js] +[test_browserGlue_corrupt.js] +[test_browserGlue_corrupt_nobackup.js] +[test_browserGlue_corrupt_nobackup_default.js] +[test_browserGlue_distribution.js] +[test_browserGlue_migrate.js] +[test_browserGlue_prefs.js] +[test_browserGlue_restore.js] +[test_browserGlue_smartBookmarks.js] +[test_browserGlue_urlbar_defaultbehavior_migration.js] +[test_clearHistory_shutdown.js] +[test_leftpane_corruption_handling.js] +[test_PUIU_makeTransaction.js] |