summaryrefslogtreecommitdiffstats
path: root/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js')
-rw-r--r--toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js640
1 files changed, 640 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js b/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js
new file mode 100644
index 000000000..06f45b18e
--- /dev/null
+++ b/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js
@@ -0,0 +1,640 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that each nsINavBookmarksObserver method gets the correct input.
+Cu.import("resource://gre/modules/PromiseUtils.jsm");
+
+const GUID_RE = /^[a-zA-Z0-9\-_]{12}$/;
+
+var gBookmarksObserver = {
+ expected: [],
+ setup(expected) {
+ this.expected = expected;
+ this.deferred = PromiseUtils.defer();
+ return this.deferred.promise;
+ },
+ validate: function (aMethodName, aArguments) {
+ do_check_eq(this.expected[0].name, aMethodName);
+
+ let args = this.expected.shift().args;
+ do_check_eq(aArguments.length, args.length);
+ for (let i = 0; i < aArguments.length; i++) {
+ do_check_true(args[i].check(aArguments[i]), aMethodName + "(args[" + i + "]: " + args[i].name + ")");
+ }
+
+ if (this.expected.length === 0) {
+ this.deferred.resolve();
+ }
+ },
+
+ // nsINavBookmarkObserver
+ onBeginUpdateBatch() {
+ return this.validate("onBeginUpdateBatch", arguments);
+ },
+ onEndUpdateBatch() {
+ return this.validate("onEndUpdateBatch", arguments);
+ },
+ onItemAdded() {
+ return this.validate("onItemAdded", arguments);
+ },
+ onItemRemoved() {
+ return this.validate("onItemRemoved", arguments);
+ },
+ onItemChanged() {
+ return this.validate("onItemChanged", arguments);
+ },
+ onItemVisited() {
+ return this.validate("onItemVisited", arguments);
+ },
+ onItemMoved() {
+ return this.validate("onItemMoved", arguments);
+ },
+
+ // nsISupports
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]),
+};
+
+var gBookmarkSkipObserver = {
+ skipTags: true,
+ skipDescendantsOnItemRemoval: true,
+
+ expected: null,
+ setup(expected) {
+ this.expected = expected;
+ this.deferred = PromiseUtils.defer();
+ return this.deferred.promise;
+ },
+ validate: function (aMethodName) {
+ do_check_eq(this.expected.shift(), aMethodName);
+ if (this.expected.length === 0) {
+ this.deferred.resolve();
+ }
+ },
+
+ // nsINavBookmarkObserver
+ onBeginUpdateBatch() {
+ return this.validate("onBeginUpdateBatch", arguments);
+ },
+ onEndUpdateBatch() {
+ return this.validate("onEndUpdateBatch", arguments);
+ },
+ onItemAdded() {
+ return this.validate("onItemAdded", arguments);
+ },
+ onItemRemoved() {
+ return this.validate("onItemRemoved", arguments);
+ },
+ onItemChanged() {
+ return this.validate("onItemChanged", arguments);
+ },
+ onItemVisited() {
+ return this.validate("onItemVisited", arguments);
+ },
+ onItemMoved() {
+ return this.validate("onItemMoved", arguments);
+ },
+
+ // nsISupports
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]),
+};
+
+
+add_task(function setup() {
+ PlacesUtils.bookmarks.addObserver(gBookmarksObserver, false);
+ PlacesUtils.bookmarks.addObserver(gBookmarkSkipObserver, false);
+});
+
+add_task(function* batch() {
+ let promise = Promise.all([
+ gBookmarksObserver.setup([
+ { name: "onBeginUpdateBatch",
+ args: [] },
+ { name: "onEndUpdateBatch",
+ args: [] },
+ ]),
+ gBookmarkSkipObserver.setup([
+ "onBeginUpdateBatch", "onEndUpdateBatch"
+ ])]);
+ PlacesUtils.bookmarks.runInBatchMode({
+ runBatched: function () {
+ // Nothing.
+ }
+ }, null);
+ yield promise;
+});
+
+add_task(function* onItemAdded_bookmark() {
+ const TITLE = "Bookmark 1";
+ let uri = NetUtil.newURI("http://1.mozilla.org/");
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemAdded"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemAdded",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) },
+ { name: "title", check: v => v === TITLE },
+ { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ ])]);
+ PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
+ uri, PlacesUtils.bookmarks.DEFAULT_INDEX,
+ TITLE);
+ yield promise;
+});
+
+add_task(function* onItemAdded_separator() {
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemAdded"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemAdded",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "index", check: v => v === 1 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_SEPARATOR },
+ { name: "uri", check: v => v === null },
+ { name: "title", check: v => v === null },
+ { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ ])]);
+ PlacesUtils.bookmarks.insertSeparator(PlacesUtils.unfiledBookmarksFolderId,
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ yield promise;
+});
+
+add_task(function* onItemAdded_folder() {
+ const TITLE = "Folder 1";
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemAdded"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemAdded",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "index", check: v => v === 2 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER },
+ { name: "uri", check: v => v === null },
+ { name: "title", check: v => v === TITLE },
+ { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ ])]);
+ PlacesUtils.bookmarks.createFolder(PlacesUtils.unfiledBookmarksFolderId,
+ TITLE,
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ yield promise;
+});
+
+add_task(function* onItemChanged_title_bookmark() {
+ let id = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0);
+ const TITLE = "New title";
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemChanged"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemChanged", // This is an unfortunate effect of bug 653910.
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "property", check: v => v === "title" },
+ { name: "isAnno", check: v => v === false },
+ { name: "newValue", check: v => v === TITLE },
+ { name: "lastModified", check: v => typeof(v) == "number" && v > 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "oldValue", check: v => typeof(v) == "string" },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ ])]);
+ PlacesUtils.bookmarks.setItemTitle(id, TITLE);
+ yield promise;
+});
+
+add_task(function* onItemChanged_tags_bookmark() {
+ let id = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0);
+ let uri = PlacesUtils.bookmarks.getBookmarkURI(id);
+ const TAG = "tag";
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemChanged", "onItemChanged"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemAdded", // This is the tag folder.
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => v === PlacesUtils.tagsFolderId },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER },
+ { name: "uri", check: v => v === null },
+ { name: "title", check: v => v === TAG },
+ { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemAdded", // This is the tag.
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) },
+ { name: "title", check: v => v === null },
+ { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemChanged",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "property", check: v => v === "tags" },
+ { name: "isAnno", check: v => v === false },
+ { name: "newValue", check: v => v === "" },
+ { name: "lastModified", check: v => typeof(v) == "number" && v > 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "oldValue", check: v => typeof(v) == "string" },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemRemoved", // This is the tag.
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemRemoved", // This is the tag folder.
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => v === PlacesUtils.tagsFolderId },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER },
+ { name: "uri", check: v => v === null },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemChanged",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "property", check: v => v === "tags" },
+ { name: "isAnno", check: v => v === false },
+ { name: "newValue", check: v => v === "" },
+ { name: "lastModified", check: v => typeof(v) == "number" && v > 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "oldValue", check: v => typeof(v) == "string" },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ ])]);
+ PlacesUtils.tagging.tagURI(uri, [TAG]);
+ PlacesUtils.tagging.untagURI(uri, [TAG]);
+ yield promise;
+});
+
+add_task(function* onItemMoved_bookmark() {
+ let id = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0);
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemMoved", "onItemMoved"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemMoved",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "oldParentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "oldIndex", check: v => v === 0 },
+ { name: "newParentId", check: v => v === PlacesUtils.toolbarFolderId },
+ { name: "newIndex", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "oldParentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "newParentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemMoved",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "oldParentId", check: v => v === PlacesUtils.toolbarFolderId },
+ { name: "oldIndex", check: v => v === 0 },
+ { name: "newParentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "newIndex", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "oldParentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "newParentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ ])]);
+ PlacesUtils.bookmarks.moveItem(id, PlacesUtils.toolbarFolderId, 0);
+ PlacesUtils.bookmarks.moveItem(id, PlacesUtils.unfiledBookmarksFolderId, 0);
+ yield promise;
+});
+
+add_task(function* onItemMoved_bookmark() {
+ let id = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0);
+ let uri = PlacesUtils.bookmarks.getBookmarkURI(id);
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemVisited"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemVisited",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "visitId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "time", check: v => typeof(v) == "number" && v > 0 },
+ { name: "transitionType", check: v => v === PlacesUtils.history.TRANSITION_TYPED },
+ { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) },
+ { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ ] },
+ ])]);
+ PlacesTestUtils.addVisits({ uri: uri, transition: TRANSITION_TYPED });
+ yield promise;
+});
+
+add_task(function* onItemRemoved_bookmark() {
+ let id = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0);
+ let uri = PlacesUtils.bookmarks.getBookmarkURI(id);
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemChanged", "onItemRemoved"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemChanged", // This is an unfortunate effect of bug 653910.
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "property", check: v => v === "" },
+ { name: "isAnno", check: v => v === true },
+ { name: "newValue", check: v => v === "" },
+ { name: "lastModified", check: v => typeof(v) == "number" && v > 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "oldValue", check: v => typeof(v) == "string" },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemRemoved",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ ])]);
+ PlacesUtils.bookmarks.removeItem(id);
+ yield promise;
+});
+
+add_task(function* onItemRemoved_separator() {
+ let id = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0);
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemChanged", "onItemRemoved"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemChanged", // This is an unfortunate effect of bug 653910.
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "property", check: v => v === "" },
+ { name: "isAnno", check: v => v === true },
+ { name: "newValue", check: v => v === "" },
+ { name: "lastModified", check: v => typeof(v) == "number" && v > 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_SEPARATOR },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "oldValue", check: v => typeof(v) == "string" },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemRemoved",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_SEPARATOR },
+ { name: "uri", check: v => v === null },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ ])]);
+ PlacesUtils.bookmarks.removeItem(id);
+ yield promise;
+});
+
+add_task(function* onItemRemoved_folder() {
+ let id = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0);
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemChanged", "onItemRemoved"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemChanged", // This is an unfortunate effect of bug 653910.
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "property", check: v => v === "" },
+ { name: "isAnno", check: v => v === true },
+ { name: "newValue", check: v => v === "" },
+ { name: "lastModified", check: v => typeof(v) == "number" && v > 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "oldValue", check: v => typeof(v) == "string" },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemRemoved",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER },
+ { name: "uri", check: v => v === null },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ ])]);
+ PlacesUtils.bookmarks.removeItem(id);
+ yield promise;
+});
+
+add_task(function* onItemRemoved_folder_recursive() {
+ const TITLE = "Folder 3";
+ const BMTITLE = "Bookmark 1";
+ let uri = NetUtil.newURI("http://1.mozilla.org/");
+ let promise = Promise.all([
+ gBookmarkSkipObserver.setup([
+ "onItemAdded", "onItemAdded", "onItemAdded", "onItemAdded",
+ "onItemChanged", "onItemRemoved"
+ ]),
+ gBookmarksObserver.setup([
+ { name: "onItemAdded",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER },
+ { name: "uri", check: v => v === null },
+ { name: "title", check: v => v === TITLE },
+ { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemAdded",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => v === PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0) },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) },
+ { name: "title", check: v => v === BMTITLE },
+ { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemAdded",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => v === PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0) },
+ { name: "index", check: v => v === 1 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER },
+ { name: "uri", check: v => v === null },
+ { name: "title", check: v => v === TITLE },
+ { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemAdded",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => v === PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, 0), 1) },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) },
+ { name: "title", check: v => v === BMTITLE },
+ { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemChanged", // This is an unfortunate effect of bug 653910.
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "property", check: v => v === "" },
+ { name: "isAnno", check: v => v === true },
+ { name: "newValue", check: v => v === "" },
+ { name: "lastModified", check: v => typeof(v) == "number" && v > 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "oldValue", check: v => typeof(v) == "string" },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemRemoved",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemRemoved",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "index", check: v => v === 1 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER },
+ { name: "uri", check: v => v === null },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemRemoved",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK },
+ { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ { name: "onItemRemoved",
+ args: [
+ { name: "itemId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "parentId", check: v => typeof(v) == "number" && v > 0 },
+ { name: "index", check: v => v === 0 },
+ { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER },
+ { name: "uri", check: v => v === null },
+ { name: "guid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "parentGuid", check: v => typeof(v) == "string" && GUID_RE.test(v) },
+ { name: "source", check: v => Object.values(PlacesUtils.bookmarks.SOURCES).includes(v) },
+ ] },
+ ])]);
+ let folder = PlacesUtils.bookmarks.createFolder(PlacesUtils.unfiledBookmarksFolderId,
+ TITLE,
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ PlacesUtils.bookmarks.insertBookmark(folder,
+ uri, PlacesUtils.bookmarks.DEFAULT_INDEX,
+ BMTITLE);
+ let folder2 = PlacesUtils.bookmarks.createFolder(folder, TITLE,
+ PlacesUtils.bookmarks.DEFAULT_INDEX);
+ PlacesUtils.bookmarks.insertBookmark(folder2,
+ uri, PlacesUtils.bookmarks.DEFAULT_INDEX,
+ BMTITLE);
+
+ PlacesUtils.bookmarks.removeItem(folder);
+ yield promise;
+});
+
+add_task(function cleanup()
+{
+ PlacesUtils.bookmarks.removeObserver(gBookmarksObserver);
+ PlacesUtils.bookmarks.removeObserver(gBookmarkSkipObserver);
+});