mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-03 13:57:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
7
toolkit/components/places/tests/history/.eslintrc.js
Normal file
7
toolkit/components/places/tests/history/.eslintrc.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
]
|
||||
};
|
||||
19
toolkit/components/places/tests/history/head_history.js
Normal file
19
toolkit/components/places/tests/history/head_history.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
var Cr = Components.results;
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Import common head.
|
||||
{
|
||||
let commonFile = do_get_file("../head_common.js", false);
|
||||
let uri = Services.io.newFileURI(commonFile);
|
||||
Services.scriptloader.loadSubScript(uri.spec, this);
|
||||
}
|
||||
257
toolkit/components/places/tests/history/test_insert.js
Normal file
257
toolkit/components/places/tests/history/test_insert.js
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
|
||||
// Tests for `History.insert` and `History.insertMany`, as implemented in History.jsm
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_insert_error_cases() {
|
||||
const TEST_URL = "http://mozilla.com";
|
||||
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert(),
|
||||
/TypeError: pageInfo must be an object/,
|
||||
"passing a null into History.insert should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert(1),
|
||||
/TypeError: pageInfo must be an object/,
|
||||
"passing a non object into History.insert should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert({}),
|
||||
/TypeError: PageInfo object must have a url property/,
|
||||
"passing an object without a url to History.insert should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert({url: 123}),
|
||||
/TypeError: Invalid url or guid: 123/,
|
||||
"passing an object with an invalid url to History.insert should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert({url: TEST_URL}),
|
||||
/TypeError: PageInfo object must have an array of visits/,
|
||||
"passing an object without a visits property to History.insert should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert({url: TEST_URL, visits: 1}),
|
||||
/TypeError: PageInfo object must have an array of visits/,
|
||||
"passing an object with a non-array visits property to History.insert should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert({url: TEST_URL, visits: []}),
|
||||
/TypeError: PageInfo object must have an array of visits/,
|
||||
"passing an object with an empty array as the visits property to History.insert should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert({
|
||||
url: TEST_URL,
|
||||
visits: [
|
||||
{
|
||||
transition: TRANSITION_LINK,
|
||||
date: "a"
|
||||
}
|
||||
]}),
|
||||
/TypeError: Expected a Date, got a/,
|
||||
"passing a visit object with an invalid date to History.insert should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert({
|
||||
url: TEST_URL,
|
||||
visits: [
|
||||
{
|
||||
transition: TRANSITION_LINK
|
||||
},
|
||||
{
|
||||
transition: TRANSITION_LINK,
|
||||
date: "a"
|
||||
}
|
||||
]}),
|
||||
/TypeError: Expected a Date, got a/,
|
||||
"passing a second visit object with an invalid date to History.insert should throw a TypeError"
|
||||
);
|
||||
let futureDate = new Date();
|
||||
futureDate.setDate(futureDate.getDate() + 1000);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert({
|
||||
url: TEST_URL,
|
||||
visits: [
|
||||
{
|
||||
transition: TRANSITION_LINK,
|
||||
date: futureDate,
|
||||
}
|
||||
]}),
|
||||
`TypeError: date: ${futureDate} is not a valid date`,
|
||||
"passing a visit object with a future date to History.insert should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insert({
|
||||
url: TEST_URL,
|
||||
visits: [
|
||||
{transition: "a"}
|
||||
]}),
|
||||
/TypeError: transition: a is not a valid transition type/,
|
||||
"passing a visit object with an invalid transition to History.insert should throw a TypeError"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_history_insert() {
|
||||
const TEST_URL = "http://mozilla.com/";
|
||||
|
||||
let inserter = Task.async(function*(name, filter, referrer, date, transition) {
|
||||
do_print(name);
|
||||
do_print(`filter: ${filter}, referrer: ${referrer}, date: ${date}, transition: ${transition}`);
|
||||
|
||||
let uri = NetUtil.newURI(TEST_URL + Math.random());
|
||||
let title = "Visit " + Math.random();
|
||||
|
||||
let pageInfo = {
|
||||
title,
|
||||
visits: [
|
||||
{transition: transition, referrer: referrer, date: date, }
|
||||
]
|
||||
};
|
||||
|
||||
pageInfo.url = yield filter(uri);
|
||||
|
||||
let result = yield PlacesUtils.history.insert(pageInfo);
|
||||
|
||||
Assert.ok(PlacesUtils.isValidGuid(result.guid), "guid for pageInfo object is valid");
|
||||
Assert.equal(uri.spec, result.url.href, "url is correct for pageInfo object");
|
||||
Assert.equal(title, result.title, "title is correct for pageInfo object");
|
||||
Assert.equal(TRANSITION_LINK, result.visits[0].transition, "transition is correct for pageInfo object");
|
||||
if (referrer) {
|
||||
Assert.equal(referrer, result.visits[0].referrer.href, "url of referrer for visit is correct");
|
||||
} else {
|
||||
Assert.equal(null, result.visits[0].referrer, "url of referrer for visit is correct");
|
||||
}
|
||||
if (date) {
|
||||
Assert.equal(Number(date),
|
||||
Number(result.visits[0].date),
|
||||
"date of visit is correct");
|
||||
}
|
||||
|
||||
Assert.ok(yield PlacesTestUtils.isPageInDB(uri), "Page was added");
|
||||
Assert.ok(yield PlacesTestUtils.visitsInDB(uri), "Visit was added");
|
||||
});
|
||||
|
||||
try {
|
||||
for (let referrer of [TEST_URL, null]) {
|
||||
for (let date of [new Date(), null]) {
|
||||
for (let transition of [TRANSITION_LINK, null]) {
|
||||
yield inserter("Testing History.insert() with an nsIURI", x => x, referrer, date, transition);
|
||||
yield inserter("Testing History.insert() with a string url", x => x.spec, referrer, date, transition);
|
||||
yield inserter("Testing History.insert() with a URL object", x => new URL(x.spec), referrer, date, transition);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_insert_multiple_error_cases() {
|
||||
let validPageInfo = {
|
||||
url: "http://mozilla.com",
|
||||
visits: [
|
||||
{transition: TRANSITION_LINK}
|
||||
]
|
||||
};
|
||||
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insertMany(),
|
||||
/TypeError: pageInfos must be an array/,
|
||||
"passing a null into History.insertMany should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insertMany([]),
|
||||
/TypeError: pageInfos may not be an empty array/,
|
||||
"passing an empty array into History.insertMany should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.insertMany([validPageInfo, {}]),
|
||||
/TypeError: PageInfo object must have a url property/,
|
||||
"passing a second invalid PageInfo object to History.insertMany should throw a TypeError"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_history_insertMany() {
|
||||
const BAD_URLS = ["about:config", "chrome://browser/content/browser.xul"];
|
||||
const GOOD_URLS = [1, 2, 3].map(x => { return `http://mozilla.com/${x}`; });
|
||||
|
||||
let makePageInfos = Task.async(function*(urls, filter = x => x) {
|
||||
let pageInfos = [];
|
||||
for (let url of urls) {
|
||||
let uri = NetUtil.newURI(url);
|
||||
|
||||
let pageInfo = {
|
||||
title: `Visit to ${url}`,
|
||||
visits: [
|
||||
{transition: TRANSITION_LINK}
|
||||
]
|
||||
};
|
||||
|
||||
pageInfo.url = yield filter(uri);
|
||||
pageInfos.push(pageInfo);
|
||||
}
|
||||
return pageInfos;
|
||||
});
|
||||
|
||||
let inserter = Task.async(function*(name, filter, useCallbacks) {
|
||||
do_print(name);
|
||||
do_print(`filter: ${filter}`);
|
||||
do_print(`useCallbacks: ${useCallbacks}`);
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
|
||||
let result;
|
||||
let allUrls = GOOD_URLS.concat(BAD_URLS);
|
||||
let pageInfos = yield makePageInfos(allUrls, filter);
|
||||
|
||||
if (useCallbacks) {
|
||||
let onResultUrls = [];
|
||||
let onErrorUrls = [];
|
||||
result = yield PlacesUtils.history.insertMany(pageInfos, pageInfo => {
|
||||
let url = pageInfo.url.href;
|
||||
Assert.ok(GOOD_URLS.includes(url), "onResult callback called for correct url");
|
||||
onResultUrls.push(url);
|
||||
Assert.equal(`Visit to ${url}`, pageInfo.title, "onResult callback provides the correct title");
|
||||
Assert.ok(PlacesUtils.isValidGuid(pageInfo.guid), "onResult callback provides a valid guid");
|
||||
}, pageInfo => {
|
||||
let url = pageInfo.url.href;
|
||||
Assert.ok(BAD_URLS.includes(url), "onError callback called for correct uri");
|
||||
onErrorUrls.push(url);
|
||||
Assert.equal(undefined, pageInfo.title, "onError callback provides the correct title");
|
||||
Assert.equal(undefined, pageInfo.guid, "onError callback provides the expected guid");
|
||||
});
|
||||
Assert.equal(GOOD_URLS.sort().toString(), onResultUrls.sort().toString(), "onResult callback was called for each good url");
|
||||
Assert.equal(BAD_URLS.sort().toString(), onErrorUrls.sort().toString(), "onError callback was called for each bad url");
|
||||
} else {
|
||||
result = yield PlacesUtils.history.insertMany(pageInfos);
|
||||
}
|
||||
|
||||
Assert.equal(undefined, result, "insertMany returned undefined");
|
||||
|
||||
for (let url of allUrls) {
|
||||
let expected = GOOD_URLS.includes(url);
|
||||
Assert.equal(expected, yield PlacesTestUtils.isPageInDB(url), `isPageInDB for ${url} is ${expected}`);
|
||||
Assert.equal(expected, yield PlacesTestUtils.visitsInDB(url), `visitsInDB for ${url} is ${expected}`);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
for (let useCallbacks of [false, true]) {
|
||||
yield inserter("Testing History.insertMany() with an nsIURI", x => x, useCallbacks);
|
||||
yield inserter("Testing History.insertMany() with a string url", x => x.spec, useCallbacks);
|
||||
yield inserter("Testing History.insertMany() with a URL object", x => new URL(x.spec), useCallbacks);
|
||||
}
|
||||
// Test rejection when no items added
|
||||
let pageInfos = yield makePageInfos(BAD_URLS);
|
||||
PlacesUtils.history.insertMany(pageInfos).then(() => {
|
||||
Assert.ok(false, "History.insertMany rejected promise with all bad URLs");
|
||||
}, error => {
|
||||
Assert.equal("No items were added to history.", error.message, "History.insertMany rejected promise with all bad URLs");
|
||||
});
|
||||
} finally {
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
}
|
||||
});
|
||||
360
toolkit/components/places/tests/history/test_remove.js
Normal file
360
toolkit/components/places/tests/history/test_remove.js
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
|
||||
// Tests for `History.remove`, as implemented in History.jsm
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
|
||||
|
||||
// Test removing a single page
|
||||
add_task(function* test_remove_single() {
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
yield PlacesUtils.bookmarks.eraseEverything();
|
||||
|
||||
|
||||
let WITNESS_URI = NetUtil.newURI("http://mozilla.com/test_browserhistory/test_remove/" + Math.random());
|
||||
yield PlacesTestUtils.addVisits(WITNESS_URI);
|
||||
Assert.ok(page_in_database(WITNESS_URI));
|
||||
|
||||
let remover = Task.async(function*(name, filter, options) {
|
||||
do_print(name);
|
||||
do_print(JSON.stringify(options));
|
||||
do_print("Setting up visit");
|
||||
|
||||
let uri = NetUtil.newURI("http://mozilla.com/test_browserhistory/test_remove/" + Math.random());
|
||||
let title = "Visit " + Math.random();
|
||||
yield PlacesTestUtils.addVisits({uri: uri, title: title});
|
||||
Assert.ok(visits_in_database(uri), "History entry created");
|
||||
|
||||
let removeArg = yield filter(uri);
|
||||
|
||||
if (options.addBookmark) {
|
||||
PlacesUtils.bookmarks.insertBookmark(
|
||||
PlacesUtils.unfiledBookmarksFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"test bookmark");
|
||||
}
|
||||
|
||||
let shouldRemove = !options.addBookmark;
|
||||
let observer;
|
||||
let promiseObserved = new Promise((resolve, reject) => {
|
||||
observer = {
|
||||
onBeginUpdateBatch: function() {},
|
||||
onEndUpdateBatch: function() {},
|
||||
onVisit: function(aUri) {
|
||||
reject(new Error("Unexpected call to onVisit " + aUri.spec));
|
||||
},
|
||||
onTitleChanged: function(aUri) {
|
||||
reject(new Error("Unexpected call to onTitleChanged " + aUri.spec));
|
||||
},
|
||||
onClearHistory: function() {
|
||||
reject("Unexpected call to onClearHistory");
|
||||
},
|
||||
onPageChanged: function(aUri) {
|
||||
reject(new Error("Unexpected call to onPageChanged " + aUri.spec));
|
||||
},
|
||||
onFrecencyChanged: function(aURI) {
|
||||
try {
|
||||
Assert.ok(!shouldRemove, "Observing onFrecencyChanged");
|
||||
Assert.equal(aURI.spec, uri.spec, "Observing effect on the right uri");
|
||||
} finally {
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
onManyFrecenciesChanged: function() {
|
||||
try {
|
||||
Assert.ok(!shouldRemove, "Observing onManyFrecenciesChanged");
|
||||
} finally {
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
onDeleteURI: function(aURI) {
|
||||
try {
|
||||
Assert.ok(shouldRemove, "Observing onDeleteURI");
|
||||
Assert.equal(aURI.spec, uri.spec, "Observing effect on the right uri");
|
||||
} finally {
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
onDeleteVisits: function(aURI) {
|
||||
Assert.equal(aURI.spec, uri.spec, "Observing onDeleteVisits on the right uri");
|
||||
}
|
||||
};
|
||||
});
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
|
||||
do_print("Performing removal");
|
||||
let removed = false;
|
||||
if (options.useCallback) {
|
||||
let onRowCalled = false;
|
||||
let guid = do_get_guid_for_uri(uri);
|
||||
removed = yield PlacesUtils.history.remove(removeArg, page => {
|
||||
Assert.equal(onRowCalled, false, "Callback has not been called yet");
|
||||
onRowCalled = true;
|
||||
Assert.equal(page.url.href, uri.spec, "Callback provides the correct url");
|
||||
Assert.equal(page.guid, guid, "Callback provides the correct guid");
|
||||
Assert.equal(page.title, title, "Callback provides the correct title");
|
||||
});
|
||||
Assert.ok(onRowCalled, "Callback has been called");
|
||||
} else {
|
||||
removed = yield PlacesUtils.history.remove(removeArg);
|
||||
}
|
||||
|
||||
yield promiseObserved;
|
||||
PlacesUtils.history.removeObserver(observer);
|
||||
|
||||
Assert.equal(visits_in_database(uri), 0, "History entry has disappeared");
|
||||
Assert.notEqual(visits_in_database(WITNESS_URI), 0, "Witness URI still has visits");
|
||||
Assert.notEqual(page_in_database(WITNESS_URI), 0, "Witness URI is still here");
|
||||
if (shouldRemove) {
|
||||
Assert.ok(removed, "Something was removed");
|
||||
Assert.equal(page_in_database(uri), 0, "Page has disappeared");
|
||||
} else {
|
||||
Assert.ok(!removed, "The page was not removed, as there was a bookmark");
|
||||
Assert.notEqual(page_in_database(uri), 0, "The page is still present");
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
for (let useCallback of [false, true]) {
|
||||
for (let addBookmark of [false, true]) {
|
||||
let options = { useCallback: useCallback, addBookmark: addBookmark };
|
||||
yield remover("Testing History.remove() with a single URI", x => x, options);
|
||||
yield remover("Testing History.remove() with a single string url", x => x.spec, options);
|
||||
yield remover("Testing History.remove() with a single string guid", x => do_get_guid_for_uri(x), options);
|
||||
yield remover("Testing History.remove() with a single URI in an array", x => [x], options);
|
||||
yield remover("Testing History.remove() with a single string url in an array", x => [x.spec], options);
|
||||
yield remover("Testing History.remove() with a single string guid in an array", x => [do_get_guid_for_uri(x)], options);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
}
|
||||
return;
|
||||
});
|
||||
|
||||
// Test removing a list of pages
|
||||
add_task(function* test_remove_many() {
|
||||
const SIZE = 10;
|
||||
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
yield PlacesUtils.bookmarks.eraseEverything();
|
||||
|
||||
do_print("Adding a witness page");
|
||||
let WITNESS_URI = NetUtil.newURI("http://mozilla.com/test_browserhistory/test_remove/" + Math.random());
|
||||
yield PlacesTestUtils.addVisits(WITNESS_URI);
|
||||
Assert.ok(page_in_database(WITNESS_URI), "Witness page added");
|
||||
|
||||
do_print("Generating samples");
|
||||
let pages = [];
|
||||
for (let i = 0; i < SIZE; ++i) {
|
||||
let uri = NetUtil.newURI("http://mozilla.com/test_browserhistory/test_remove?sample=" + i + "&salt=" + Math.random());
|
||||
let title = "Visit " + i + ", " + Math.random();
|
||||
let hasBookmark = i % 3 == 0;
|
||||
let page = {
|
||||
uri: uri,
|
||||
title: title,
|
||||
hasBookmark: hasBookmark,
|
||||
// `true` once `onResult` has been called for this page
|
||||
onResultCalled: false,
|
||||
// `true` once `onDeleteVisits` has been called for this page
|
||||
onDeleteVisitsCalled: false,
|
||||
// `true` once `onFrecencyChangedCalled` has been called for this page
|
||||
onFrecencyChangedCalled: false,
|
||||
// `true` once `onDeleteURI` has been called for this page
|
||||
onDeleteURICalled: false,
|
||||
};
|
||||
do_print("Pushing: " + uri.spec);
|
||||
pages.push(page);
|
||||
|
||||
yield PlacesTestUtils.addVisits(page);
|
||||
page.guid = do_get_guid_for_uri(uri);
|
||||
if (hasBookmark) {
|
||||
PlacesUtils.bookmarks.insertBookmark(
|
||||
PlacesUtils.unfiledBookmarksFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"test bookmark " + i);
|
||||
}
|
||||
Assert.ok(page_in_database(uri), "Page added");
|
||||
}
|
||||
|
||||
do_print("Mixing key types and introducing dangling keys");
|
||||
let keys = [];
|
||||
for (let i = 0; i < SIZE; ++i) {
|
||||
if (i % 4 == 0) {
|
||||
keys.push(pages[i].uri);
|
||||
keys.push(NetUtil.newURI("http://example.org/dangling/nsIURI/" + i));
|
||||
} else if (i % 4 == 1) {
|
||||
keys.push(new URL(pages[i].uri.spec));
|
||||
keys.push(new URL("http://example.org/dangling/URL/" + i));
|
||||
} else if (i % 4 == 2) {
|
||||
keys.push(pages[i].uri.spec);
|
||||
keys.push("http://example.org/dangling/stringuri/" + i);
|
||||
} else {
|
||||
keys.push(pages[i].guid);
|
||||
keys.push(("guid_" + i + "_01234567890").substr(0, 12));
|
||||
}
|
||||
}
|
||||
|
||||
let observer = {
|
||||
onBeginUpdateBatch: function() {},
|
||||
onEndUpdateBatch: function() {},
|
||||
onVisit: function(aURI) {
|
||||
Assert.ok(false, "Unexpected call to onVisit " + aURI.spec);
|
||||
},
|
||||
onTitleChanged: function(aURI) {
|
||||
Assert.ok(false, "Unexpected call to onTitleChanged " + aURI.spec);
|
||||
},
|
||||
onClearHistory: function() {
|
||||
Assert.ok(false, "Unexpected call to onClearHistory");
|
||||
},
|
||||
onPageChanged: function(aURI) {
|
||||
Assert.ok(false, "Unexpected call to onPageChanged " + aURI.spec);
|
||||
},
|
||||
onFrecencyChanged: function(aURI) {
|
||||
let origin = pages.find(x => x.uri.spec == aURI.spec);
|
||||
Assert.ok(origin);
|
||||
Assert.ok(origin.hasBookmark, "Observing onFrecencyChanged on a page with a bookmark");
|
||||
origin.onFrecencyChangedCalled = true;
|
||||
// We do not make sure that `origin.onFrecencyChangedCalled` is `false`, as
|
||||
},
|
||||
onManyFrecenciesChanged: function() {
|
||||
Assert.ok(false, "Observing onManyFrecenciesChanges, this is most likely correct but not covered by this test");
|
||||
},
|
||||
onDeleteURI: function(aURI) {
|
||||
let origin = pages.find(x => x.uri.spec == aURI.spec);
|
||||
Assert.ok(origin);
|
||||
Assert.ok(!origin.hasBookmark, "Observing onDeleteURI on a page without a bookmark");
|
||||
Assert.ok(!origin.onDeleteURICalled, "Observing onDeleteURI for the first time");
|
||||
origin.onDeleteURICalled = true;
|
||||
},
|
||||
onDeleteVisits: function(aURI) {
|
||||
let origin = pages.find(x => x.uri.spec == aURI.spec);
|
||||
Assert.ok(origin);
|
||||
Assert.ok(!origin.onDeleteVisitsCalled, "Observing onDeleteVisits for the first time");
|
||||
origin.onDeleteVisitsCalled = true;
|
||||
}
|
||||
};
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
|
||||
do_print("Removing the pages and checking the callbacks");
|
||||
let removed = yield PlacesUtils.history.remove(keys, page => {
|
||||
let origin = pages.find(candidate => candidate.uri.spec == page.url.href);
|
||||
|
||||
Assert.ok(origin, "onResult has a valid page");
|
||||
Assert.ok(!origin.onResultCalled, "onResult has not seen this page yet");
|
||||
origin.onResultCalled = true;
|
||||
Assert.equal(page.guid, origin.guid, "onResult has the right guid");
|
||||
Assert.equal(page.title, origin.title, "onResult has the right title");
|
||||
});
|
||||
Assert.ok(removed, "Something was removed");
|
||||
|
||||
PlacesUtils.history.removeObserver(observer);
|
||||
|
||||
do_print("Checking out results");
|
||||
// By now the observers should have been called.
|
||||
for (let i = 0; i < pages.length; ++i) {
|
||||
let page = pages[i];
|
||||
do_print("Page: " + i);
|
||||
Assert.ok(page.onResultCalled, "We have reached the page from the callback");
|
||||
Assert.ok(visits_in_database(page.uri) == 0, "History entry has disappeared");
|
||||
Assert.equal(page_in_database(page.uri) != 0, page.hasBookmark, "Page is present only if it also has bookmarks");
|
||||
Assert.equal(page.onFrecencyChangedCalled, page.onDeleteVisitsCalled, "onDeleteVisits was called iff onFrecencyChanged was called");
|
||||
Assert.ok(page.onFrecencyChangedCalled ^ page.onDeleteURICalled, "Either onFrecencyChanged or onDeleteURI was called");
|
||||
}
|
||||
|
||||
Assert.notEqual(visits_in_database(WITNESS_URI), 0, "Witness URI still has visits");
|
||||
Assert.notEqual(page_in_database(WITNESS_URI), 0, "Witness URI is still here");
|
||||
});
|
||||
|
||||
add_task(function* cleanup() {
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
yield PlacesUtils.bookmarks.eraseEverything();
|
||||
});
|
||||
|
||||
// Test the various error cases
|
||||
add_task(function* test_error_cases() {
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(),
|
||||
/TypeError: Invalid url/,
|
||||
"History.remove with no argument should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(null),
|
||||
/TypeError: Invalid url/,
|
||||
"History.remove with `null` should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(undefined),
|
||||
/TypeError: Invalid url/,
|
||||
"History.remove with `undefined` should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove("not a guid, obviously"),
|
||||
/TypeError: .* is not a valid URL/,
|
||||
"History.remove with an ill-formed guid/url argument should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove({"not the kind of object we know how to handle": true}),
|
||||
/TypeError: Invalid url/,
|
||||
"History.remove with an unexpected object should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove([]),
|
||||
/TypeError: Expected at least one page/,
|
||||
"History.remove with an empty array should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove([null]),
|
||||
/TypeError: Invalid url or guid/,
|
||||
"History.remove with an array containing null should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(["http://example.org", "not a guid, obviously"]),
|
||||
/TypeError: .* is not a valid URL/,
|
||||
"History.remove with an array containing an ill-formed guid/url argument should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(["0123456789ab"/* valid guid*/, null]),
|
||||
/TypeError: Invalid url or guid: null/,
|
||||
"History.remove with an array containing a guid and a second argument that is null should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(["http://example.org", {"not the kind of object we know how to handle": true}]),
|
||||
/TypeError: Invalid url/,
|
||||
"History.remove with an array containing an unexpected objecgt should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove("http://example.org", "not a function, obviously"),
|
||||
/TypeError: Invalid function/,
|
||||
"History.remove with a second argument that is not a function argument should throw a TypeError"
|
||||
);
|
||||
try {
|
||||
PlacesUtils.history.remove("http://example.org/I/have/clearly/not/been/added", null);
|
||||
Assert.ok(true, "History.remove should ignore `null` as a second argument");
|
||||
} catch (ex) {
|
||||
Assert.ok(false, "History.remove should ignore `null` as a second argument");
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_orphans() {
|
||||
let uri = NetUtil.newURI("http://moz.org/");
|
||||
yield PlacesTestUtils.addVisits({ uri });
|
||||
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
uri, SMALLPNG_DATA_URI, true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
null, Services.scriptSecurityManager.getSystemPrincipal());
|
||||
PlacesUtils.annotations.setPageAnnotation(uri, "test", "restval", 0,
|
||||
PlacesUtils.annotations.EXPIRE_NEVER);
|
||||
|
||||
yield PlacesUtils.history.remove(uri);
|
||||
Assert.ok(!(yield PlacesTestUtils.isPageInDB(uri)), "Page should have been removed");
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
let rows = yield db.execute(`SELECT (SELECT count(*) FROM moz_annos) +
|
||||
(SELECT count(*) FROM moz_favicons) AS count`);
|
||||
Assert.equal(rows[0].getResultByName("count"), 0, "Should not find orphans");
|
||||
});
|
||||
316
toolkit/components/places/tests/history/test_removeVisits.js
Normal file
316
toolkit/components/places/tests/history/test_removeVisits.js
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
const JS_NOW = Date.now();
|
||||
const DB_NOW = JS_NOW * 1000;
|
||||
const TEST_URI = uri("http://example.com/");
|
||||
const PLACE_URI = uri("place:queryType=0&sort=8&maxResults=10");
|
||||
|
||||
function* cleanup() {
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
yield PlacesUtils.bookmarks.eraseEverything();
|
||||
// This is needed to remove place: entries.
|
||||
DBConn().executeSimpleSQL("DELETE FROM moz_places");
|
||||
}
|
||||
|
||||
add_task(function* remove_visits_outside_unbookmarked_uri() {
|
||||
do_print("*** TEST: Remove some visits outside valid timeframe from an unbookmarked URI");
|
||||
|
||||
do_print("Add 10 visits for the URI from way in the past.");
|
||||
let visits = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
visits.push({ uri: TEST_URI, visitDate: DB_NOW - 100000 - (i * 1000) });
|
||||
}
|
||||
yield PlacesTestUtils.addVisits(visits);
|
||||
|
||||
do_print("Remove visits using timerange outside the URI's visits.");
|
||||
let filter = {
|
||||
beginDate: new Date(JS_NOW - 10),
|
||||
endDate: new Date(JS_NOW)
|
||||
};
|
||||
yield PlacesUtils.history.removeVisitsByFilter(filter);
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("URI should still exist in moz_places.");
|
||||
do_check_true(page_in_database(TEST_URI.spec));
|
||||
|
||||
do_print("Run a history query and check that all visits still exist.");
|
||||
let query = PlacesUtils.history.getNewQuery();
|
||||
let opts = PlacesUtils.history.getNewQueryOptions();
|
||||
opts.resultType = opts.RESULTS_AS_VISIT;
|
||||
opts.sortingMode = opts.SORT_BY_DATE_DESCENDING;
|
||||
let root = PlacesUtils.history.executeQuery(query, opts).root;
|
||||
root.containerOpen = true;
|
||||
do_check_eq(root.childCount, 10);
|
||||
for (let i = 0; i < root.childCount; i++) {
|
||||
let visitTime = root.getChild(i).time;
|
||||
do_check_eq(visitTime, DB_NOW - 100000 - (i * 1000));
|
||||
}
|
||||
root.containerOpen = false;
|
||||
|
||||
do_print("asyncHistory.isURIVisited should return true.");
|
||||
do_check_true(yield promiseIsURIVisited(TEST_URI));
|
||||
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
do_print("Frecency should be positive.")
|
||||
do_check_true(frecencyForUrl(TEST_URI) > 0);
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* remove_visits_outside_bookmarked_uri() {
|
||||
do_print("*** TEST: Remove some visits outside valid timeframe from a bookmarked URI");
|
||||
|
||||
do_print("Add 10 visits for the URI from way in the past.");
|
||||
let visits = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
visits.push({ uri: TEST_URI, visitDate: DB_NOW - 100000 - (i * 1000) });
|
||||
}
|
||||
yield PlacesTestUtils.addVisits(visits);
|
||||
do_print("Bookmark the URI.");
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
TEST_URI,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"bookmark title");
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("Remove visits using timerange outside the URI's visits.");
|
||||
let filter = {
|
||||
beginDate: new Date(JS_NOW - 10),
|
||||
endDate: new Date(JS_NOW)
|
||||
};
|
||||
yield PlacesUtils.history.removeVisitsByFilter(filter);
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("URI should still exist in moz_places.");
|
||||
do_check_true(page_in_database(TEST_URI.spec));
|
||||
|
||||
do_print("Run a history query and check that all visits still exist.");
|
||||
let query = PlacesUtils.history.getNewQuery();
|
||||
let opts = PlacesUtils.history.getNewQueryOptions();
|
||||
opts.resultType = opts.RESULTS_AS_VISIT;
|
||||
opts.sortingMode = opts.SORT_BY_DATE_DESCENDING;
|
||||
let root = PlacesUtils.history.executeQuery(query, opts).root;
|
||||
root.containerOpen = true;
|
||||
do_check_eq(root.childCount, 10);
|
||||
for (let i = 0; i < root.childCount; i++) {
|
||||
let visitTime = root.getChild(i).time;
|
||||
do_check_eq(visitTime, DB_NOW - 100000 - (i * 1000));
|
||||
}
|
||||
root.containerOpen = false;
|
||||
|
||||
do_print("asyncHistory.isURIVisited should return true.");
|
||||
do_check_true(yield promiseIsURIVisited(TEST_URI));
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("Frecency should be positive.")
|
||||
do_check_true(frecencyForUrl(TEST_URI) > 0);
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* remove_visits_unbookmarked_uri() {
|
||||
do_print("*** TEST: Remove some visits from an unbookmarked URI");
|
||||
|
||||
do_print("Add 10 visits for the URI from now to 9 usecs in the past.");
|
||||
let visits = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
visits.push({ uri: TEST_URI, visitDate: DB_NOW - (i * 1000) });
|
||||
}
|
||||
yield PlacesTestUtils.addVisits(visits);
|
||||
|
||||
do_print("Remove the 5 most recent visits.");
|
||||
let filter = {
|
||||
beginDate: new Date(JS_NOW - 4),
|
||||
endDate: new Date(JS_NOW)
|
||||
};
|
||||
yield PlacesUtils.history.removeVisitsByFilter(filter);
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("URI should still exist in moz_places.");
|
||||
do_check_true(page_in_database(TEST_URI.spec));
|
||||
|
||||
do_print("Run a history query and check that only the older 5 visits still exist.");
|
||||
let query = PlacesUtils.history.getNewQuery();
|
||||
let opts = PlacesUtils.history.getNewQueryOptions();
|
||||
opts.resultType = opts.RESULTS_AS_VISIT;
|
||||
opts.sortingMode = opts.SORT_BY_DATE_DESCENDING;
|
||||
let root = PlacesUtils.history.executeQuery(query, opts).root;
|
||||
root.containerOpen = true;
|
||||
do_check_eq(root.childCount, 5);
|
||||
for (let i = 0; i < root.childCount; i++) {
|
||||
let visitTime = root.getChild(i).time;
|
||||
do_check_eq(visitTime, DB_NOW - (i * 1000) - 5000);
|
||||
}
|
||||
root.containerOpen = false;
|
||||
|
||||
do_print("asyncHistory.isURIVisited should return true.");
|
||||
do_check_true(yield promiseIsURIVisited(TEST_URI));
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("Frecency should be positive.")
|
||||
do_check_true(frecencyForUrl(TEST_URI) > 0);
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* remove_visits_bookmarked_uri() {
|
||||
do_print("*** TEST: Remove some visits from a bookmarked URI");
|
||||
|
||||
do_print("Add 10 visits for the URI from now to 9 usecs in the past.");
|
||||
let visits = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
visits.push({ uri: TEST_URI, visitDate: DB_NOW - (i * 1000) });
|
||||
}
|
||||
yield PlacesTestUtils.addVisits(visits);
|
||||
do_print("Bookmark the URI.");
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
TEST_URI,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"bookmark title");
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("Remove the 5 most recent visits.");
|
||||
let filter = {
|
||||
beginDate: new Date(JS_NOW - 4),
|
||||
endDate: new Date(JS_NOW)
|
||||
};
|
||||
yield PlacesUtils.history.removeVisitsByFilter(filter);
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("URI should still exist in moz_places.");
|
||||
do_check_true(page_in_database(TEST_URI.spec));
|
||||
|
||||
do_print("Run a history query and check that only the older 5 visits still exist.");
|
||||
let query = PlacesUtils.history.getNewQuery();
|
||||
let opts = PlacesUtils.history.getNewQueryOptions();
|
||||
opts.resultType = opts.RESULTS_AS_VISIT;
|
||||
opts.sortingMode = opts.SORT_BY_DATE_DESCENDING;
|
||||
let root = PlacesUtils.history.executeQuery(query, opts).root;
|
||||
root.containerOpen = true;
|
||||
do_check_eq(root.childCount, 5);
|
||||
for (let i = 0; i < root.childCount; i++) {
|
||||
let visitTime = root.getChild(i).time;
|
||||
do_check_eq(visitTime, DB_NOW - (i * 1000) - 5000);
|
||||
}
|
||||
root.containerOpen = false;
|
||||
|
||||
do_print("asyncHistory.isURIVisited should return true.");
|
||||
do_check_true(yield promiseIsURIVisited(TEST_URI));
|
||||
yield PlacesTestUtils.promiseAsyncUpdates()
|
||||
|
||||
do_print("Frecency should be positive.")
|
||||
do_check_true(frecencyForUrl(TEST_URI) > 0);
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* remove_all_visits_unbookmarked_uri() {
|
||||
do_print("*** TEST: Remove all visits from an unbookmarked URI");
|
||||
|
||||
do_print("Add some visits for the URI.");
|
||||
let visits = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
visits.push({ uri: TEST_URI, visitDate: DB_NOW - (i * 1000) });
|
||||
}
|
||||
yield PlacesTestUtils.addVisits(visits);
|
||||
|
||||
do_print("Remove all visits.");
|
||||
let filter = {
|
||||
beginDate: new Date(JS_NOW - 10),
|
||||
endDate: new Date(JS_NOW)
|
||||
};
|
||||
yield PlacesUtils.history.removeVisitsByFilter(filter);
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("URI should no longer exist in moz_places.");
|
||||
do_check_false(page_in_database(TEST_URI.spec));
|
||||
|
||||
do_print("Run a history query and check that no visits exist.");
|
||||
let query = PlacesUtils.history.getNewQuery();
|
||||
let opts = PlacesUtils.history.getNewQueryOptions();
|
||||
opts.resultType = opts.RESULTS_AS_VISIT;
|
||||
opts.sortingMode = opts.SORT_BY_DATE_DESCENDING;
|
||||
let root = PlacesUtils.history.executeQuery(query, opts).root;
|
||||
root.containerOpen = true;
|
||||
do_check_eq(root.childCount, 0);
|
||||
root.containerOpen = false;
|
||||
|
||||
do_print("asyncHistory.isURIVisited should return false.");
|
||||
do_check_false(yield promiseIsURIVisited(TEST_URI));
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* remove_all_visits_bookmarked_uri() {
|
||||
do_print("*** TEST: Remove all visits from a bookmarked URI");
|
||||
|
||||
do_print("Add some visits for the URI.");
|
||||
let visits = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
visits.push({ uri: TEST_URI, visitDate: DB_NOW - (i * 1000) });
|
||||
}
|
||||
yield PlacesTestUtils.addVisits(visits);
|
||||
do_print("Bookmark the URI.");
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
TEST_URI,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"bookmark title");
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
let initialFrecency = frecencyForUrl(TEST_URI);
|
||||
|
||||
do_print("Remove all visits.");
|
||||
let filter = {
|
||||
beginDate: new Date(JS_NOW - 10),
|
||||
endDate: new Date(JS_NOW)
|
||||
};
|
||||
yield PlacesUtils.history.removeVisitsByFilter(filter);
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("URI should still exist in moz_places.");
|
||||
do_check_true(page_in_database(TEST_URI.spec));
|
||||
|
||||
do_print("Run a history query and check that no visits exist.");
|
||||
let query = PlacesUtils.history.getNewQuery();
|
||||
let opts = PlacesUtils.history.getNewQueryOptions();
|
||||
opts.resultType = opts.RESULTS_AS_VISIT;
|
||||
opts.sortingMode = opts.SORT_BY_DATE_DESCENDING;
|
||||
let root = PlacesUtils.history.executeQuery(query, opts).root;
|
||||
root.containerOpen = true;
|
||||
do_check_eq(root.childCount, 0);
|
||||
root.containerOpen = false;
|
||||
|
||||
do_print("asyncHistory.isURIVisited should return false.");
|
||||
do_check_false(yield promiseIsURIVisited(TEST_URI));
|
||||
|
||||
do_print("nsINavBookmarksService.isBookmarked should return true.");
|
||||
do_check_true(PlacesUtils.bookmarks.isBookmarked(TEST_URI));
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("Frecency should be smaller.")
|
||||
do_check_true(frecencyForUrl(TEST_URI) < initialFrecency);
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
||||
add_task(function* remove_all_visits_bookmarked_uri() {
|
||||
do_print("*** TEST: Remove some visits from a zero frecency URI retains zero frecency");
|
||||
|
||||
do_print("Add some visits for the URI.");
|
||||
yield PlacesTestUtils.addVisits([
|
||||
{ uri: TEST_URI, transition: TRANSITION_FRAMED_LINK, visitDate: (DB_NOW - 86400000000000) },
|
||||
{ uri: TEST_URI, transition: TRANSITION_FRAMED_LINK, visitDate: DB_NOW }
|
||||
]);
|
||||
|
||||
do_print("Remove newer visit.");
|
||||
let filter = {
|
||||
beginDate: new Date(JS_NOW - 10),
|
||||
endDate: new Date(JS_NOW)
|
||||
};
|
||||
yield PlacesUtils.history.removeVisitsByFilter(filter);
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
do_print("URI should still exist in moz_places.");
|
||||
do_check_true(page_in_database(TEST_URI.spec));
|
||||
do_print("Frecency should be zero.")
|
||||
do_check_eq(frecencyForUrl(TEST_URI), 0);
|
||||
|
||||
yield cleanup();
|
||||
});
|
||||
|
|
@ -0,0 +1,345 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
|
||||
// Tests for `History.removeVisitsByFilter`, as implemented in History.jsm
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
|
||||
|
||||
add_task(function* test_removeVisitsByFilter() {
|
||||
let referenceDate = new Date(1999, 9, 9, 9, 9);
|
||||
|
||||
// Populate a database with 20 entries, remove a subset of entries,
|
||||
// ensure consistency.
|
||||
let remover = Task.async(function*(options) {
|
||||
do_print("Remover with options " + JSON.stringify(options));
|
||||
let SAMPLE_SIZE = options.sampleSize;
|
||||
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
yield PlacesUtils.bookmarks.eraseEverything();
|
||||
|
||||
// Populate the database.
|
||||
// Create `SAMPLE_SIZE` visits, from the oldest to the newest.
|
||||
|
||||
let bookmarkIndices = new Set(options.bookmarks);
|
||||
let visits = [];
|
||||
let frecencyChangePromises = new Map();
|
||||
let uriDeletePromises = new Map();
|
||||
let getURL = options.url ?
|
||||
i => "http://mozilla.com/test_browserhistory/test_removeVisitsByFilter/removeme/byurl/" + Math.floor(i / (SAMPLE_SIZE / 5)) + "/" :
|
||||
i => "http://mozilla.com/test_browserhistory/test_removeVisitsByFilter/removeme/" + i + "/" + Math.random();
|
||||
for (let i = 0; i < SAMPLE_SIZE; ++i) {
|
||||
let spec = getURL(i);
|
||||
let uri = NetUtil.newURI(spec);
|
||||
let jsDate = new Date(Number(referenceDate) + 3600 * 1000 * i);
|
||||
let dbDate = jsDate * 1000;
|
||||
let hasBookmark = bookmarkIndices.has(i);
|
||||
let hasOwnBookmark = hasBookmark;
|
||||
if (!hasOwnBookmark && options.url) {
|
||||
// Also mark as bookmarked if one of the earlier bookmarked items has the same URL.
|
||||
hasBookmark =
|
||||
options.bookmarks.filter(n => n < i).some(n => visits[n].uri.spec == spec && visits[n].test.hasBookmark);
|
||||
}
|
||||
do_print("Generating " + uri.spec + ", " + dbDate);
|
||||
let visit = {
|
||||
uri,
|
||||
title: "visit " + i,
|
||||
visitDate: dbDate,
|
||||
test: {
|
||||
// `visitDate`, as a Date
|
||||
jsDate: jsDate,
|
||||
// `true` if we expect that the visit will be removed
|
||||
toRemove: false,
|
||||
// `true` if `onRow` informed of the removal of this visit
|
||||
announcedByOnRow: false,
|
||||
// `true` if there is a bookmark for this URI, i.e. of the page
|
||||
// should not be entirely removed.
|
||||
hasBookmark: hasBookmark,
|
||||
onFrecencyChanged: null,
|
||||
onDeleteURI: null,
|
||||
},
|
||||
};
|
||||
visits.push(visit);
|
||||
if (hasOwnBookmark) {
|
||||
do_print("Adding a bookmark to visit " + i);
|
||||
yield PlacesUtils.bookmarks.insert({
|
||||
url: uri,
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
title: "test bookmark"
|
||||
});
|
||||
do_print("Bookmark added");
|
||||
}
|
||||
}
|
||||
|
||||
do_print("Adding visits");
|
||||
yield PlacesTestUtils.addVisits(visits);
|
||||
|
||||
do_print("Preparing filters");
|
||||
let filter = {
|
||||
};
|
||||
let beginIndex = 0;
|
||||
let endIndex = visits.length - 1;
|
||||
if ("begin" in options) {
|
||||
let ms = Number(visits[options.begin].test.jsDate) - 1000;
|
||||
filter.beginDate = new Date(ms);
|
||||
beginIndex = options.begin;
|
||||
}
|
||||
if ("end" in options) {
|
||||
let ms = Number(visits[options.end].test.jsDate) + 1000;
|
||||
filter.endDate = new Date(ms);
|
||||
endIndex = options.end;
|
||||
}
|
||||
if ("limit" in options) {
|
||||
endIndex = beginIndex + options.limit - 1; // -1 because the start index is inclusive.
|
||||
filter.limit = options.limit;
|
||||
}
|
||||
let removedItems = visits.slice(beginIndex);
|
||||
endIndex -= beginIndex;
|
||||
if (options.url) {
|
||||
let rawURL = "";
|
||||
switch (options.url) {
|
||||
case 1:
|
||||
filter.url = new URL(removedItems[0].uri.spec);
|
||||
rawURL = filter.url.href;
|
||||
break;
|
||||
case 2:
|
||||
filter.url = removedItems[0].uri;
|
||||
rawURL = filter.url.spec;
|
||||
break;
|
||||
case 3:
|
||||
filter.url = removedItems[0].uri.spec;
|
||||
rawURL = filter.url;
|
||||
break;
|
||||
}
|
||||
endIndex = Math.min(endIndex, removedItems.findIndex((v, index) => v.uri.spec != rawURL) - 1);
|
||||
}
|
||||
removedItems.splice(endIndex + 1);
|
||||
let remainingItems = visits.filter(v => !removedItems.includes(v));
|
||||
for (let i = 0; i < removedItems.length; i++) {
|
||||
let test = removedItems[i].test;
|
||||
do_print("Marking visit " + (beginIndex + i) + " as expecting removal");
|
||||
test.toRemove = true;
|
||||
if (test.hasBookmark ||
|
||||
(options.url && remainingItems.some(v => v.uri.spec == removedItems[i].uri.spec))) {
|
||||
frecencyChangePromises.set(removedItems[i].uri.spec, PromiseUtils.defer());
|
||||
} else if (!options.url || i == 0) {
|
||||
uriDeletePromises.set(removedItems[i].uri.spec, PromiseUtils.defer());
|
||||
}
|
||||
}
|
||||
|
||||
let observer = {
|
||||
deferred: PromiseUtils.defer(),
|
||||
onBeginUpdateBatch: function() {},
|
||||
onEndUpdateBatch: function() {},
|
||||
onVisit: function(uri) {
|
||||
this.deferred.reject(new Error("Unexpected call to onVisit " + uri.spec));
|
||||
},
|
||||
onTitleChanged: function(uri) {
|
||||
this.deferred.reject(new Error("Unexpected call to onTitleChanged " + uri.spec));
|
||||
},
|
||||
onClearHistory: function() {
|
||||
this.deferred.reject("Unexpected call to onClearHistory");
|
||||
},
|
||||
onPageChanged: function(uri) {
|
||||
this.deferred.reject(new Error("Unexpected call to onPageChanged " + uri.spec));
|
||||
},
|
||||
onFrecencyChanged: function(aURI) {
|
||||
do_print("onFrecencyChanged " + aURI.spec);
|
||||
let deferred = frecencyChangePromises.get(aURI.spec);
|
||||
Assert.ok(!!deferred, "Observing onFrecencyChanged");
|
||||
deferred.resolve();
|
||||
},
|
||||
onManyFrecenciesChanged: function() {
|
||||
do_print("Many frecencies changed");
|
||||
for (let [, deferred] of frecencyChangePromises) {
|
||||
deferred.resolve();
|
||||
}
|
||||
},
|
||||
onDeleteURI: function(aURI) {
|
||||
do_print("onDeleteURI " + aURI.spec);
|
||||
let deferred = uriDeletePromises.get(aURI.spec);
|
||||
Assert.ok(!!deferred, "Observing onDeleteURI");
|
||||
deferred.resolve();
|
||||
},
|
||||
onDeleteVisits: function(aURI) {
|
||||
// Not sure we can test anything.
|
||||
}
|
||||
};
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
|
||||
let cbarg;
|
||||
if (options.useCallback) {
|
||||
do_print("Setting up callback");
|
||||
cbarg = [info => {
|
||||
for (let visit of visits) {
|
||||
do_print("Comparing " + info.date + " and " + visit.test.jsDate);
|
||||
if (Math.abs(visit.test.jsDate - info.date) < 100) { // Assume rounding errors
|
||||
Assert.ok(!visit.test.announcedByOnRow,
|
||||
"This is the first time we announce the removal of this visit");
|
||||
Assert.ok(visit.test.toRemove,
|
||||
"This is a visit we intended to remove");
|
||||
visit.test.announcedByOnRow = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Assert.ok(false, "Could not find the visit we attempt to remove");
|
||||
}];
|
||||
} else {
|
||||
do_print("No callback");
|
||||
cbarg = [];
|
||||
}
|
||||
let result = yield PlacesUtils.history.removeVisitsByFilter(filter, ...cbarg);
|
||||
|
||||
Assert.ok(result, "Removal succeeded");
|
||||
|
||||
// Make sure that we have eliminated exactly the entries we expected
|
||||
// to eliminate.
|
||||
for (let i = 0; i < visits.length; ++i) {
|
||||
let visit = visits[i];
|
||||
do_print("Controlling the results on visit " + i);
|
||||
let remainingVisitsForURI = remainingItems.filter(v => visit.uri.spec == v.uri.spec).length;
|
||||
Assert.equal(
|
||||
visits_in_database(visit.uri),
|
||||
remainingVisitsForURI,
|
||||
"Visit is still present iff expected");
|
||||
if (options.useCallback) {
|
||||
Assert.equal(
|
||||
visit.test.toRemove,
|
||||
visit.test.announcedByOnRow,
|
||||
"Visit removal has been announced by onResult iff expected");
|
||||
}
|
||||
if (visit.test.hasBookmark || remainingVisitsForURI) {
|
||||
Assert.notEqual(page_in_database(visit.uri), 0, "The page should still appear in the db");
|
||||
} else {
|
||||
Assert.equal(page_in_database(visit.uri), 0, "The page should have been removed from the db");
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that the observer has been called wherever applicable.
|
||||
do_print("Checking URI delete promises.");
|
||||
yield Promise.all(Array.from(uriDeletePromises.values()));
|
||||
do_print("Checking frecency change promises.");
|
||||
yield Promise.all(Array.from(frecencyChangePromises.values()));
|
||||
PlacesUtils.history.removeObserver(observer);
|
||||
});
|
||||
|
||||
let size = 20;
|
||||
for (let range of [
|
||||
{begin: 0},
|
||||
{end: 19},
|
||||
{begin: 0, end: 10},
|
||||
{begin: 3, end: 4},
|
||||
{begin: 5, end: 8, limit: 2},
|
||||
{begin: 10, end: 18, limit: 5},
|
||||
]) {
|
||||
for (let bookmarks of [[], [5, 6]]) {
|
||||
let options = {
|
||||
sampleSize: size,
|
||||
bookmarks: bookmarks,
|
||||
};
|
||||
if ("begin" in range) {
|
||||
options.begin = range.begin;
|
||||
}
|
||||
if ("end" in range) {
|
||||
options.end = range.end;
|
||||
}
|
||||
if ("limit" in range) {
|
||||
options.limit = range.limit;
|
||||
}
|
||||
yield remover(options);
|
||||
options.url = 1;
|
||||
yield remover(options);
|
||||
options.url = 2;
|
||||
yield remover(options);
|
||||
options.url = 3;
|
||||
yield remover(options);
|
||||
}
|
||||
}
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
});
|
||||
|
||||
// Test the various error cases
|
||||
add_task(function* test_error_cases() {
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter(),
|
||||
/TypeError: Expected a filter/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter("obviously, not a filter"),
|
||||
/TypeError: Expected a filter/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({}),
|
||||
/TypeError: Expected a non-empty filter/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({beginDate: "now"}),
|
||||
/TypeError: Expected a Date/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({beginDate: Date.now()}),
|
||||
/TypeError: Expected a Date/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({beginDate: new Date()}, "obviously, not a callback"),
|
||||
/TypeError: Invalid function/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({beginDate: new Date(1000), endDate: new Date(0)}),
|
||||
/TypeError: `beginDate` should be at least as old/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({limit: {}}),
|
||||
/Expected a non-zero positive integer as a limit/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({limit: -1}),
|
||||
/Expected a non-zero positive integer as a limit/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({limit: 0.1}),
|
||||
/Expected a non-zero positive integer as a limit/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({limit: Infinity}),
|
||||
/Expected a non-zero positive integer as a limit/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({url: {}}),
|
||||
/Expected a valid URL for `url`/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({url: 0}),
|
||||
/Expected a valid URL for `url`/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({beginDate: new Date(1000), endDate: new Date(0)}),
|
||||
/TypeError: `beginDate` should be at least as old/
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.removeVisitsByFilter({beginDate: new Date(1000), endDate: new Date(0)}),
|
||||
/TypeError: `beginDate` should be at least as old/
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_orphans() {
|
||||
let uri = NetUtil.newURI("http://moz.org/");
|
||||
yield PlacesTestUtils.addVisits({ uri });
|
||||
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
uri, SMALLPNG_DATA_URI, true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
null, Services.scriptSecurityManager.getSystemPrincipal());
|
||||
PlacesUtils.annotations.setPageAnnotation(uri, "test", "restval", 0,
|
||||
PlacesUtils.annotations.EXPIRE_NEVER);
|
||||
|
||||
yield PlacesUtils.history.removeVisitsByFilter({ beginDate: new Date(1999, 9, 9, 9, 9),
|
||||
endDate: new Date() });
|
||||
Assert.ok(!(yield PlacesTestUtils.isPageInDB(uri)), "Page should have been removed");
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
let rows = yield db.execute(`SELECT (SELECT count(*) FROM moz_annos) +
|
||||
(SELECT count(*) FROM moz_favicons) AS count`);
|
||||
Assert.equal(rows[0].getResultByName("count"), 0, "Should not find orphans");
|
||||
});
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// Test that repeated additions of the same URI through updatePlaces, properly
|
||||
// update from_visit and notify titleChanged.
|
||||
|
||||
add_task(function* test() {
|
||||
let uri = "http://test.com/";
|
||||
|
||||
let promiseTitleChangedNotifications = new Promise(resolve => {
|
||||
let historyObserver = {
|
||||
_count: 0,
|
||||
__proto__: NavHistoryObserver.prototype,
|
||||
onTitleChanged(aURI, aTitle, aGUID) {
|
||||
Assert.equal(aURI.spec, uri, "Should notify the proper url");
|
||||
if (++this._count == 2) {
|
||||
PlacesUtils.history.removeObserver(historyObserver);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
PlacesUtils.history.addObserver(historyObserver, false);
|
||||
});
|
||||
|
||||
// This repeats the url on purpose, don't merge it into a single place entry.
|
||||
yield PlacesTestUtils.addVisits([
|
||||
{ uri, title: "test" },
|
||||
{ uri, referrer: uri, title: "test2" },
|
||||
]);
|
||||
|
||||
let options = PlacesUtils.history.getNewQueryOptions();
|
||||
let query = PlacesUtils.history.getNewQuery();
|
||||
query.uri = NetUtil.newURI(uri);
|
||||
options.resultType = options.RESULTS_AS_VISIT;
|
||||
let root = PlacesUtils.history.executeQuery(query, options).root;
|
||||
root.containerOpen = true;
|
||||
|
||||
Assert.equal(root.childCount, 2);
|
||||
|
||||
let child = root.getChild(0);
|
||||
Assert.equal(child.visitType, TRANSITION_LINK, "Visit type should be TRANSITION_LINK");
|
||||
Assert.equal(child.visitId, 1, "Visit ID should be 1");
|
||||
Assert.equal(child.fromVisitId, -1, "Should have no referrer visit ID");
|
||||
Assert.equal(child.title, "test2", "Should have the correct title");
|
||||
|
||||
child = root.getChild(1);
|
||||
Assert.equal(child.visitType, TRANSITION_LINK, "Visit type should be TRANSITION_LINK");
|
||||
Assert.equal(child.visitId, 2, "Visit ID should be 2");
|
||||
Assert.equal(child.fromVisitId, 1, "First visit should be the referring visit");
|
||||
Assert.equal(child.title, "test2", "Should have the correct title");
|
||||
|
||||
root.containerOpen = false;
|
||||
|
||||
yield promiseTitleChangedNotifications;
|
||||
});
|
||||
9
toolkit/components/places/tests/history/xpcshell.ini
Normal file
9
toolkit/components/places/tests/history/xpcshell.ini
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[DEFAULT]
|
||||
head = head_history.js
|
||||
tail =
|
||||
|
||||
[test_insert.js]
|
||||
[test_remove.js]
|
||||
[test_removeVisits.js]
|
||||
[test_removeVisitsByFilter.js]
|
||||
[test_updatePlaces_sameUri_titleChanged.js]
|
||||
Loading…
Add table
Add a link
Reference in a new issue