/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ add_task(async function invalid_input_throws() { Assert.throws( () => PlacesUtils.bookmarks.insert(), /Input should be a valid object/ ); Assert.throws( () => PlacesUtils.bookmarks.insert(null), /Input should be a valid object/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({}), /The following properties were expected/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ guid: "test" }), /Invalid value for property 'guid'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ guid: null }), /Invalid value for property 'guid'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ guid: 123 }), /Invalid value for property 'guid'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ parentGuid: "test" }), /Invalid value for property 'parentGuid'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ parentGuid: null }), /Invalid value for property 'parentGuid'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ parentGuid: 123 }), /Invalid value for property 'parentGuid'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ index: "1" }), /Invalid value for property 'index'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ index: -10 }), /Invalid value for property 'index'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ dateAdded: -10 }), /Invalid value for property 'dateAdded'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ dateAdded: "today" }), /Invalid value for property 'dateAdded'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ dateAdded: Date.now() }), /Invalid value for property 'dateAdded'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ dateAdded: new Date(NaN) }), /Invalid value for property 'dateAdded'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ lastModified: -10 }), /Invalid value for property 'lastModified'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ lastModified: "today" }), /Invalid value for property 'lastModified'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ lastModified: Date.now() }), /Invalid value for property 'lastModified'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ lastModified: new Date(NaN) }), /Invalid value for property 'lastModified'/ ); let past = new Date(Date.now() - 86400000); Assert.throws( () => PlacesUtils.bookmarks.insert({ lastModified: past }), /Invalid value for property 'lastModified'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ type: -1 }), /Invalid value for property 'type'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ type: 100 }), /Invalid value for property 'type'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ type: "bookmark" }), /Invalid value for property 'type'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ type: PlacesUtils.bookmarks.TYPE_BOOKMARK, title: -1, }), /Invalid value for property 'title'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ type: PlacesUtils.bookmarks.TYPE_BOOKMARK, url: 10, }), /Invalid value for property 'url'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ type: PlacesUtils.bookmarks.TYPE_BOOKMARK, url: "http://te st", }), /Invalid value for property 'url'/ ); let longurl = "http://www.example.com/"; for (let i = 0; i < 65536; i++) { longurl += "a"; } Assert.throws( () => PlacesUtils.bookmarks.insert({ type: PlacesUtils.bookmarks.TYPE_BOOKMARK, url: longurl, }), /Invalid value for property 'url'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ type: PlacesUtils.bookmarks.TYPE_BOOKMARK, url: NetUtil.newURI(longurl), }), /Invalid value for property 'url'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ type: PlacesUtils.bookmarks.TYPE_BOOKMARK, url: "te st", }), /Invalid value for property 'url'/ ); }); add_task(async function invalid_properties_for_bookmark_type() { Assert.throws( () => PlacesUtils.bookmarks.insert({ type: PlacesUtils.bookmarks.TYPE_FOLDER, url: "http://www.moz.com/", }), /Invalid value for property 'url'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ type: PlacesUtils.bookmarks.TYPE_SEPARATOR, url: "http://www.moz.com/", }), /Invalid value for property 'url'/ ); Assert.throws( () => PlacesUtils.bookmarks.insert({ type: PlacesUtils.bookmarks.TYPE_SEPARATOR, title: "test", }), /Invalid value for property 'title'/ ); }); add_task(async function test_insert_into_root_throws() { const { sinon } = ChromeUtils.importESModule( "resource://testing-common/Sinon.sys.mjs" ); const sandbox = sinon.createSandbox(); sandbox.stub(PlacesUtils, "isInAutomation").get(() => false); registerCleanupFunction(() => sandbox.restore()); Assert.throws( () => PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.rootGuid, url: "http://example.com", }), /Invalid value for property 'parentGuid'/, "Should throw when inserting a bookmark into the root." ); Assert.throws( () => PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.rootGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, }), /Invalid value for property 'parentGuid'/, "Should throw when inserting a folder into the root." ); sandbox.restore(); }); add_task(async function long_title_trim() { let longtitle = "a"; for (let i = 0; i < 4096; i++) { longtitle += "a"; } let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title: longtitle, }); checkBookmarkObject(bm); Assert.equal(bm.parentGuid, PlacesUtils.bookmarks.unfiledGuid); Assert.equal(bm.index, 0); Assert.equal(bm.dateAdded, bm.lastModified); Assert.equal(bm.type, PlacesUtils.bookmarks.TYPE_FOLDER); Assert.equal(bm.title.length, 4096, "title should have been trimmed"); Assert.ok(!("url" in bm), "url should not be set"); }); add_task(async function create_separator() { let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, type: PlacesUtils.bookmarks.TYPE_SEPARATOR, index: PlacesUtils.bookmarks.DEFAULT_INDEX, }); checkBookmarkObject(bm); Assert.equal(bm.parentGuid, PlacesUtils.bookmarks.unfiledGuid); Assert.equal(bm.index, 1); Assert.equal(bm.dateAdded, bm.lastModified); Assert.equal(bm.type, PlacesUtils.bookmarks.TYPE_SEPARATOR); Assert.strictEqual(bm.title, ""); }); add_task(async function create_separator_w_title_fail() { try { await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, type: PlacesUtils.bookmarks.TYPE_SEPARATOR, title: "a separator", }); Assert.ok(false, "Trying to set title for a separator should reject"); } catch (ex) {} }); add_task(async function create_separator_invalid_parent_fail() { try { await PlacesUtils.bookmarks.insert({ parentGuid: "123456789012", type: PlacesUtils.bookmarks.TYPE_SEPARATOR, title: "a separator", }); Assert.ok( false, "Trying to create an item in a non existing parent reject" ); } catch (ex) {} }); add_task(async function create_separator_given_guid() { let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, type: PlacesUtils.bookmarks.TYPE_SEPARATOR, index: PlacesUtils.bookmarks.DEFAULT_INDEX, guid: "123456789012", }); checkBookmarkObject(bm); Assert.equal(bm.guid, "123456789012"); Assert.equal(bm.parentGuid, PlacesUtils.bookmarks.unfiledGuid); Assert.equal(bm.index, 2); Assert.equal(bm.dateAdded, bm.lastModified); Assert.equal(bm.type, PlacesUtils.bookmarks.TYPE_SEPARATOR); Assert.strictEqual(bm.title, ""); }); add_task(async function create_item_given_guid_no_type_fail() { try { await PlacesUtils.bookmarks.insert({ parentGuid: "123456789012" }); Assert.ok( false, "Trying to create an item with a given guid but no type should reject" ); } catch (ex) {} }); add_task(async function create_separator_big_index() { let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, type: PlacesUtils.bookmarks.TYPE_SEPARATOR, index: 9999, }); checkBookmarkObject(bm); Assert.equal(bm.parentGuid, PlacesUtils.bookmarks.unfiledGuid); Assert.equal(bm.index, 3); Assert.equal(bm.dateAdded, bm.lastModified); Assert.equal(bm.type, PlacesUtils.bookmarks.TYPE_SEPARATOR); Assert.strictEqual(bm.title, ""); }); add_task(async function create_separator_given_dateAdded() { let time = new Date(); let past = new Date(time - 86400000); let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, type: PlacesUtils.bookmarks.TYPE_SEPARATOR, dateAdded: past, }); checkBookmarkObject(bm); Assert.equal(bm.dateAdded, past); Assert.equal(bm.lastModified, past); }); add_task(async function create_folder() { let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, }); checkBookmarkObject(bm); Assert.equal(bm.parentGuid, PlacesUtils.bookmarks.unfiledGuid); Assert.equal(bm.dateAdded, bm.lastModified); Assert.equal(bm.type, PlacesUtils.bookmarks.TYPE_FOLDER); Assert.strictEqual(bm.title, ""); // And then create a nested folder. let parentGuid = bm.guid; bm = await PlacesUtils.bookmarks.insert({ parentGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title: "a folder", }); checkBookmarkObject(bm); Assert.equal(bm.parentGuid, parentGuid); Assert.equal(bm.index, 0); Assert.equal(bm.type, PlacesUtils.bookmarks.TYPE_FOLDER); Assert.strictEqual(bm.title, "a folder"); }); add_task(async function create_bookmark() { let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, }); let parentGuid = bm.guid; bm = await PlacesUtils.bookmarks.insert({ parentGuid, type: PlacesUtils.bookmarks.TYPE_BOOKMARK, url: "http://example.com/", title: "a bookmark", }); checkBookmarkObject(bm); Assert.equal(bm.parentGuid, parentGuid); Assert.equal(bm.index, 0); Assert.equal(bm.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); Assert.equal(bm.url.href, "http://example.com/"); Assert.equal(bm.title, "a bookmark"); // Check parent lastModified. let parent = await PlacesUtils.bookmarks.fetch({ guid: bm.parentGuid }); Assert.deepEqual(parent.lastModified, bm.dateAdded); bm = await PlacesUtils.bookmarks.insert({ parentGuid, type: PlacesUtils.bookmarks.TYPE_BOOKMARK, url: new URL("http://example.com/"), }); checkBookmarkObject(bm); Assert.equal(bm.parentGuid, parentGuid); Assert.equal(bm.index, 1); Assert.equal(bm.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); Assert.equal(bm.url.href, "http://example.com/"); Assert.strictEqual(bm.title, ""); }); add_task(async function create_bookmark_frecency() { let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, type: PlacesUtils.bookmarks.TYPE_BOOKMARK, url: "http://example.com/", title: "a bookmark", }); checkBookmarkObject(bm); await PlacesFrecencyRecalculator.recalculateAnyOutdatedFrecencies(); Assert.greater( await PlacesTestUtils.getDatabaseValue("moz_places", "frecency", { url: bm.url, }), 0, "Check frecency has been updated" ); }); add_task(async function create_bookmark_without_type() { let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, url: "http://example.com/", title: "a bookmark", }); checkBookmarkObject(bm); Assert.equal(bm.parentGuid, PlacesUtils.bookmarks.unfiledGuid); Assert.equal(bm.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); Assert.equal(bm.url.href, "http://example.com/"); Assert.equal(bm.title, "a bookmark"); }); add_task(async function test_url_with_apices() { // Apices may confuse code and cause injection if mishandled. const url = `javascript:alert("%s");alert('%s');`; await PlacesUtils.bookmarks.insert({ url, parentGuid: PlacesUtils.bookmarks.unfiledGuid, }); // Just a sanity check, this should not throw. await PlacesUtils.history.remove(url); let bm = await PlacesUtils.bookmarks.fetch({ url }); await PlacesUtils.bookmarks.remove(bm); });