mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Backed out 17 changesets (bug 566746, bug 697377) for frequent OSX debug mochitest-5 crashes.
This commit is contained in:
parent
5645424d68
commit
0021e7aaee
@ -445,7 +445,6 @@
|
||||
@BINPATH@/components/satchel.manifest
|
||||
@BINPATH@/components/nsFormAutoComplete.js
|
||||
@BINPATH@/components/nsFormHistory.js
|
||||
@BINPATH@/components/FormHistoryStartup.js
|
||||
@BINPATH@/components/nsInputListAutoComplete.js
|
||||
@BINPATH@/components/contentSecurityPolicy.manifest
|
||||
@BINPATH@/components/contentSecurityPolicy.js
|
||||
|
@ -6,8 +6,6 @@
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
function Sanitizer() {}
|
||||
Sanitizer.prototype = {
|
||||
@ -18,16 +16,9 @@ Sanitizer.prototype = {
|
||||
this.items[aItemName].clear();
|
||||
},
|
||||
|
||||
canClearItem: function (aItemName, aCallback, aArg)
|
||||
canClearItem: function (aItemName)
|
||||
{
|
||||
let canClear = this.items[aItemName].canClear;
|
||||
if (typeof canClear == "function") {
|
||||
canClear(aCallback, aArg);
|
||||
return false;
|
||||
}
|
||||
|
||||
aCallback(aItemName, canClear, aArg);
|
||||
return canClear;
|
||||
return this.items[aItemName].canClear;
|
||||
},
|
||||
|
||||
prefDomain: "",
|
||||
@ -38,10 +29,12 @@ Sanitizer.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes privacy sensitive data in a batch, according to user preferences. Calls
|
||||
* errorHandler with a list of errors on failure.
|
||||
* Deletes privacy sensitive data in a batch, according to user preferences
|
||||
*
|
||||
* @returns null if everything's fine; an object in the form
|
||||
* { itemName: error, ... } on (partial) failure
|
||||
*/
|
||||
sanitize: function (errorHandler)
|
||||
sanitize: function ()
|
||||
{
|
||||
var psvc = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefService);
|
||||
@ -53,42 +46,27 @@ Sanitizer.prototype = {
|
||||
var range = null; // If we ignore timespan, clear everything
|
||||
else
|
||||
range = this.range || Sanitizer.getClearRange();
|
||||
|
||||
let itemCount = this.items.length;
|
||||
|
||||
for (var itemName in this.items) {
|
||||
let item = this.items[itemName];
|
||||
var item = this.items[itemName];
|
||||
item.range = range;
|
||||
if ("clear" in item && branch.getBoolPref(itemName)) {
|
||||
let clearCallback = (itemName, aCanClear) => {
|
||||
// Some of these clear() may raise exceptions (see bug #265028)
|
||||
// to sanitize as much as possible, we catch and store them,
|
||||
// rather than fail fast.
|
||||
// Callers should check returned errors and give user feedback
|
||||
// about items that could not be sanitized
|
||||
let item = this.items[itemName];
|
||||
try {
|
||||
if (aCanClear)
|
||||
item.clear();
|
||||
} catch(er) {
|
||||
if (!errors)
|
||||
errors = {};
|
||||
errors[itemName] = er;
|
||||
dump("Error sanitizing " + itemName + ": " + er + "\n");
|
||||
}
|
||||
|
||||
// If this is the last item that needs to receive the callback, call the error handler
|
||||
if (!--itemCount && errors) {
|
||||
errorHandler(error);
|
||||
}
|
||||
};
|
||||
|
||||
this.canClearItem(itemName, clearCallback);
|
||||
if ("clear" in item && item.canClear && branch.getBoolPref(itemName)) {
|
||||
// Some of these clear() may raise exceptions (see bug #265028)
|
||||
// to sanitize as much as possible, we catch and store them,
|
||||
// rather than fail fast.
|
||||
// Callers should check returned errors and give user feedback
|
||||
// about items that could not be sanitized
|
||||
try {
|
||||
item.clear();
|
||||
} catch(er) {
|
||||
if (!errors)
|
||||
errors = {};
|
||||
errors[itemName] = er;
|
||||
dump("Error sanitizing " + itemName + ": " + er + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors) {
|
||||
errorHandler(error);
|
||||
}
|
||||
return errors;
|
||||
},
|
||||
|
||||
// Time span only makes sense in certain cases. Consumers who want
|
||||
@ -253,14 +231,15 @@ Sanitizer.prototype = {
|
||||
findBar.clear();
|
||||
}
|
||||
|
||||
let change = { op: "remove" };
|
||||
if (this.range) {
|
||||
[ change.firstUsedStart, change.firstUsedEnd ] = this.range;
|
||||
}
|
||||
FormHistory.update(change);
|
||||
let formHistory = Components.classes["@mozilla.org/satchel/form-history;1"]
|
||||
.getService(Components.interfaces.nsIFormHistory2);
|
||||
if (this.range)
|
||||
formHistory.removeEntriesByTimeframe(this.range[0], this.range[1]);
|
||||
else
|
||||
formHistory.removeAllEntries();
|
||||
},
|
||||
|
||||
canClear : function(aCallback, aArg)
|
||||
get canClear()
|
||||
{
|
||||
var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1']
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
@ -272,27 +251,17 @@ Sanitizer.prototype = {
|
||||
let transactionMgr = searchBar.textbox.editor.transactionManager;
|
||||
if (searchBar.value ||
|
||||
transactionMgr.numberOfUndoItems ||
|
||||
transactionMgr.numberOfRedoItems) {
|
||||
aCallback("formdata", true, aArg);
|
||||
return false;
|
||||
}
|
||||
transactionMgr.numberOfRedoItems)
|
||||
return true;
|
||||
}
|
||||
let findBar = currentDocument.getElementById("FindToolbar");
|
||||
if (findBar && findBar.canClear) {
|
||||
aCallback("formdata", true, aArg);
|
||||
return false;
|
||||
}
|
||||
if (findBar && findBar.canClear)
|
||||
return true;
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
let countDone = {
|
||||
handleResult : function(aResult) count = aResult,
|
||||
handleError : function(aError) Components.utils.reportError(aError),
|
||||
handleCompletion :
|
||||
function(aReason) { aCallback("formdata", aReason == 0 && count > 0, aArg); }
|
||||
};
|
||||
FormHistory.count({}, countDone);
|
||||
return false;
|
||||
let formHistory = Components.classes["@mozilla.org/satchel/form-history;1"]
|
||||
.getService(Components.interfaces.nsIFormHistory2);
|
||||
return formHistory.hasEntries;
|
||||
}
|
||||
},
|
||||
|
||||
@ -517,7 +486,9 @@ Sanitizer._checkAndSanitize = function()
|
||||
// this is a shutdown or a startup after an unclean exit
|
||||
var s = new Sanitizer();
|
||||
s.prefDomain = "privacy.clearOnShutdown.";
|
||||
let errorHandler = function() prefs.setBoolPref(Sanitizer.prefDidShutdown, true);
|
||||
s.sanitize(errorHandler);
|
||||
s.sanitize() || // sanitize() returns null on full success
|
||||
prefs.setBoolPref(Sanitizer.prefDidShutdown, true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -47,13 +47,11 @@ var gSanitizePromptDialog = {
|
||||
for (let i = 0; i < sanitizeItemList.length; i++) {
|
||||
let prefItem = sanitizeItemList[i];
|
||||
let name = s.getNameFromPreference(prefItem.getAttribute("preference"));
|
||||
s.canClearItem(name, function canClearCallback(aItem, aCanClear, aPrefItem) {
|
||||
if (!aCanClear) {
|
||||
aPrefItem.preference = null;
|
||||
aPrefItem.checked = false;
|
||||
aPrefItem.disabled = true;
|
||||
}
|
||||
}, prefItem);
|
||||
if (!s.canClearItem(name)) {
|
||||
prefItem.preference = null;
|
||||
prefItem.checked = false;
|
||||
prefItem.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
document.documentElement.getButton("accept").label =
|
||||
@ -283,13 +281,11 @@ var gSanitizePromptDialog = {
|
||||
for (let i = 0; i < sanitizeItemList.length; i++) {
|
||||
let prefItem = sanitizeItemList[i];
|
||||
let name = s.getNameFromPreference(prefItem.getAttribute("preference"));
|
||||
s.canClearItem(name, function canClearCallback(aCanClear) {
|
||||
if (!aCanClear) {
|
||||
prefItem.preference = null;
|
||||
prefItem.checked = false;
|
||||
prefItem.disabled = true;
|
||||
}
|
||||
});
|
||||
if (!s.canClearItem(name)) {
|
||||
prefItem.preference = null;
|
||||
prefItem.checked = false;
|
||||
prefItem.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
document.documentElement.getButton("accept").label =
|
||||
|
@ -2,24 +2,9 @@
|
||||
* 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/. */
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// This test relies on the form history being empty to start with delete
|
||||
// all the items first.
|
||||
FormHistory.update({ op: "remove" },
|
||||
{ handleError: function (error) {
|
||||
do_throw("Error occurred updating form history: " + error);
|
||||
},
|
||||
handleCompletion: function (reason) { if (!reason) test2(); },
|
||||
});
|
||||
}
|
||||
|
||||
function test2()
|
||||
{
|
||||
let prefService = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch2);
|
||||
|
||||
@ -44,28 +29,13 @@ function test2()
|
||||
prefBranch.setBoolPref("sessions", false);
|
||||
prefBranch.setBoolPref("siteSettings", false);
|
||||
|
||||
// Sanitize now so we can test that canClear is correct. Formdata is cleared asynchronously.
|
||||
// Sanitize now so we can test that canClear is correct
|
||||
s.sanitize();
|
||||
s.canClearItem("formdata", clearDone1, s);
|
||||
}
|
||||
|
||||
function clearDone1(aItemName, aResult, aSanitizer)
|
||||
{
|
||||
ok(!aResult, "pre-test baseline for sanitizer");
|
||||
gFindBar.getElement("findbar-textbox").value = "m";
|
||||
aSanitizer.canClearItem("formdata", inputEntered, aSanitizer);
|
||||
}
|
||||
|
||||
function inputEntered(aItemName, aResult, aSanitizer)
|
||||
{
|
||||
ok(aResult, "formdata can be cleared after input");
|
||||
aSanitizer.sanitize();
|
||||
aSanitizer.canClearItem("formdata", clearDone2);
|
||||
}
|
||||
|
||||
function clearDone2(aItemName, aResult)
|
||||
{
|
||||
is(gFindBar.getElement("findbar-textbox").value, "", "findBar textbox should be empty after sanitize");
|
||||
ok(!aResult, "canClear now false after sanitize");
|
||||
ok(!s.canClearItem("formdata"), "pre-test baseline for sanitizer");
|
||||
textbox.value = "m";
|
||||
ok(s.canClearItem("formdata"), "formdata can be cleared after input");
|
||||
s.sanitize();
|
||||
is(textbox.value, "", "findBar textbox should be empty after sanitize");
|
||||
ok(!s.canClearItem("formdata"), "canClear now false after sanitize");
|
||||
finish();
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Bug 453440 - Test the timespan-based logic of the sanitizer code
|
||||
var now_uSec = Date.now() * 1000;
|
||||
|
||||
const dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
|
||||
const formhist = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
|
||||
|
||||
const kUsecPerMin = 60 * 1000000;
|
||||
|
||||
@ -13,50 +11,14 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
||||
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||
let Sanitizer = tempScope.Sanitizer;
|
||||
|
||||
let FormHistory = (Components.utils.import("resource://gre/modules/FormHistory.jsm", {})).FormHistory;
|
||||
|
||||
function promiseFormHistoryRemoved() {
|
||||
let deferred = Promise.defer();
|
||||
Services.obs.addObserver(function onfh() {
|
||||
Services.obs.removeObserver(onfh, "satchel-storage-changed", false);
|
||||
deferred.resolve();
|
||||
}, "satchel-storage-changed", false);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
Task.spawn(function() {
|
||||
setupDownloads();
|
||||
yield setupFormHistory();
|
||||
yield setupHistory();
|
||||
yield onHistoryReady();
|
||||
}).then(finish);
|
||||
}
|
||||
|
||||
function countEntries(name, message, check) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
var obj = {};
|
||||
if (name !== null)
|
||||
obj.fieldname = name;
|
||||
|
||||
let count;
|
||||
FormHistory.count(obj, { handleResult: function (result) count = result,
|
||||
handleError: function (error) {
|
||||
do_throw("Error occurred searching form history: " + error);
|
||||
deferred.reject(error)
|
||||
},
|
||||
handleCompletion: function (reason) {
|
||||
if (!reason) {
|
||||
check(count, message);
|
||||
deferred.resolve();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
setupDownloads();
|
||||
setupFormHistory();
|
||||
setupHistory(function() {
|
||||
Task.spawn(onHistoryReady).then(finish);
|
||||
});
|
||||
}
|
||||
|
||||
function onHistoryReady() {
|
||||
@ -85,8 +47,6 @@ function onHistoryReady() {
|
||||
s.sanitize();
|
||||
s.range = null;
|
||||
|
||||
yield promiseFormHistoryRemoved();
|
||||
|
||||
ok(!(yield promiseIsURIVisited(makeURI("http://10minutes.com"))),
|
||||
"Pretend visit to 10minutes.com should now be deleted");
|
||||
ok((yield promiseIsURIVisited(makeURI("http://1hour.com"))),
|
||||
@ -108,19 +68,16 @@ function onHistoryReady() {
|
||||
ok((yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||
"Pretend visit to before-today.com should still exist");
|
||||
|
||||
let checkZero = function(num, message) { is(num, 0, message); }
|
||||
let checkOne = function(num, message) { is(num, 1, message); }
|
||||
|
||||
yield countEntries("10minutes", "10minutes form entry should be deleted", checkZero);
|
||||
yield countEntries("1hour", "1hour form entry should still exist", checkOne);
|
||||
yield countEntries("1hour10minutes", "1hour10minutes form entry should still exist", checkOne);
|
||||
yield countEntries("2hour", "2hour form entry should still exist", checkOne);
|
||||
yield countEntries("2hour10minutes", "2hour10minutes form entry should still exist", checkOne);
|
||||
yield countEntries("4hour", "4hour form entry should still exist", checkOne);
|
||||
yield countEntries("4hour10minutes", "4hour10minutes form entry should still exist", checkOne);
|
||||
ok(!formhist.nameExists("10minutes"), "10minutes form entry should be deleted");
|
||||
ok(formhist.nameExists("1hour"), "1hour form entry should still exist");
|
||||
ok(formhist.nameExists("1hour10minutes"), "1hour10minutes form entry should still exist");
|
||||
ok(formhist.nameExists("2hour"), "2hour form entry should still exist");
|
||||
ok(formhist.nameExists("2hour10minutes"), "2hour10minutes form entry should still exist");
|
||||
ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
|
||||
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
|
||||
if (minutesSinceMidnight > 10)
|
||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||
ok(formhist.nameExists("today"), "today form entry should still exist");
|
||||
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
|
||||
|
||||
ok(!downloadExists(5555555), "10 minute download should now be deleted");
|
||||
ok(downloadExists(5555551), "<1 hour download should still be present");
|
||||
@ -138,8 +95,6 @@ function onHistoryReady() {
|
||||
Sanitizer.prefs.setIntPref("timeSpan", 1);
|
||||
s.sanitize();
|
||||
|
||||
yield promiseFormHistoryRemoved();
|
||||
|
||||
ok(!(yield promiseIsURIVisited(makeURI("http://1hour.com"))),
|
||||
"Pretend visit to 1hour.com should now be deleted");
|
||||
ok((yield promiseIsURIVisited(makeURI("http://1hour10minutes.com"))),
|
||||
@ -159,15 +114,15 @@ function onHistoryReady() {
|
||||
ok((yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||
"Pretend visit to before-today.com should still exist");
|
||||
|
||||
yield countEntries("1hour", "1hour form entry should be deleted", checkZero);
|
||||
yield countEntries("1hour10minutes", "1hour10minutes form entry should still exist", checkOne);
|
||||
yield countEntries("2hour", "2hour form entry should still exist", checkOne);
|
||||
yield countEntries("2hour10minutes", "2hour10minutes form entry should still exist", checkOne);
|
||||
yield countEntries("4hour", "4hour form entry should still exist", checkOne);
|
||||
yield countEntries("4hour10minutes", "4hour10minutes form entry should still exist", checkOne);
|
||||
ok(!formhist.nameExists("1hour"), "1hour form entry should be deleted");
|
||||
ok(formhist.nameExists("1hour10minutes"), "1hour10minutes form entry should still exist");
|
||||
ok(formhist.nameExists("2hour"), "2hour form entry should still exist");
|
||||
ok(formhist.nameExists("2hour10minutes"), "2hour10minutes form entry should still exist");
|
||||
ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
|
||||
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
|
||||
if (hoursSinceMidnight > 1)
|
||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||
ok(formhist.nameExists("today"), "today form entry should still exist");
|
||||
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
|
||||
|
||||
ok(!downloadExists(5555551), "<1 hour download should now be deleted");
|
||||
ok(downloadExists(5555556), "1 hour 10 minute download should still be present");
|
||||
@ -185,8 +140,6 @@ function onHistoryReady() {
|
||||
s.sanitize();
|
||||
s.range = null;
|
||||
|
||||
yield promiseFormHistoryRemoved();
|
||||
|
||||
ok(!(yield promiseIsURIVisited(makeURI("http://1hour10minutes.com"))),
|
||||
"Pretend visit to 1hour10minutes.com should now be deleted");
|
||||
ok((yield promiseIsURIVisited(makeURI("http://2hour.com"))),
|
||||
@ -204,14 +157,14 @@ function onHistoryReady() {
|
||||
ok((yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||
"Pretend visit to before-today.com should still exist");
|
||||
|
||||
yield countEntries("1hour10minutes", "1hour10minutes form entry should be deleted", checkZero);
|
||||
yield countEntries("2hour", "2hour form entry should still exist", checkOne);
|
||||
yield countEntries("2hour10minutes", "2hour10minutes form entry should still exist", checkOne);
|
||||
yield countEntries("4hour", "4hour form entry should still exist", checkOne);
|
||||
yield countEntries("4hour10minutes", "4hour10minutes form entry should still exist", checkOne);
|
||||
ok(!formhist.nameExists("1hour10minutes"), "1hour10minutes form entry should be deleted");
|
||||
ok(formhist.nameExists("2hour"), "2hour form entry should still exist");
|
||||
ok(formhist.nameExists("2hour10minutes"), "2hour10minutes form entry should still exist");
|
||||
ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
|
||||
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
|
||||
if (minutesSinceMidnight > 70)
|
||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||
ok(formhist.nameExists("today"), "today form entry should still exist");
|
||||
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
|
||||
|
||||
ok(!downloadExists(5555556), "1 hour 10 minute old download should now be deleted");
|
||||
ok(downloadExists(5555550), "Year old download should still be present");
|
||||
@ -226,8 +179,6 @@ function onHistoryReady() {
|
||||
Sanitizer.prefs.setIntPref("timeSpan", 2);
|
||||
s.sanitize();
|
||||
|
||||
yield promiseFormHistoryRemoved();
|
||||
|
||||
ok(!(yield promiseIsURIVisited(makeURI("http://2hour.com"))),
|
||||
"Pretend visit to 2hour.com should now be deleted");
|
||||
ok((yield promiseIsURIVisited(makeURI("http://2hour10minutes.com"))),
|
||||
@ -243,14 +194,15 @@ function onHistoryReady() {
|
||||
ok((yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||
"Pretend visit to before-today.com should still exist");
|
||||
|
||||
yield countEntries("2hour", "2hour form entry should be deleted", checkZero);
|
||||
yield countEntries("2hour10minutes", "2hour10minutes form entry should still exist", checkOne);
|
||||
yield countEntries("4hour", "4hour form entry should still exist", checkOne);
|
||||
yield countEntries("4hour10minutes", "4hour10minutes form entry should still exist", checkOne);
|
||||
ok(!formhist.nameExists("2hour"), "2hour form entry should be deleted");
|
||||
ok(formhist.nameExists("2hour10minutes"), "2hour10minutes form entry should still exist");
|
||||
ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
|
||||
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
|
||||
if (hoursSinceMidnight > 2)
|
||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||
ok(formhist.nameExists("today"), "today form entry should still exist");
|
||||
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
|
||||
|
||||
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
|
||||
ok(!downloadExists(5555552), "<2 hour old download should now be deleted");
|
||||
ok(downloadExists(5555550), "Year old download should still be present");
|
||||
ok(downloadExists(5555557), "2 hour 10 minute download should still be present");
|
||||
@ -264,8 +216,6 @@ function onHistoryReady() {
|
||||
s.sanitize();
|
||||
s.range = null;
|
||||
|
||||
yield promiseFormHistoryRemoved();
|
||||
|
||||
ok(!(yield promiseIsURIVisited(makeURI("http://2hour10minutes.com"))),
|
||||
"Pretend visit to 2hour10minutes.com should now be deleted");
|
||||
ok((yield promiseIsURIVisited(makeURI("http://4hour.com"))),
|
||||
@ -279,12 +229,12 @@ function onHistoryReady() {
|
||||
ok((yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||
"Pretend visit to before-today.com should still exist");
|
||||
|
||||
yield countEntries("2hour10minutes", "2hour10minutes form entry should be deleted", checkZero);
|
||||
yield countEntries("4hour", "4hour form entry should still exist", checkOne);
|
||||
yield countEntries("4hour10minutes", "4hour10minutes form entry should still exist", checkOne);
|
||||
ok(!formhist.nameExists("2hour10minutes"), "2hour10minutes form entry should be deleted");
|
||||
ok(formhist.nameExists("4hour"), "4hour form entry should still exist");
|
||||
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
|
||||
if (minutesSinceMidnight > 130)
|
||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||
ok(formhist.nameExists("today"), "today form entry should still exist");
|
||||
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
|
||||
|
||||
ok(!downloadExists(5555557), "2 hour 10 minute old download should now be deleted");
|
||||
ok(downloadExists(5555553), "<4 hour old download should still be present");
|
||||
@ -297,8 +247,6 @@ function onHistoryReady() {
|
||||
Sanitizer.prefs.setIntPref("timeSpan", 3);
|
||||
s.sanitize();
|
||||
|
||||
yield promiseFormHistoryRemoved();
|
||||
|
||||
ok(!(yield promiseIsURIVisited(makeURI("http://4hour.com"))),
|
||||
"Pretend visit to 4hour.com should now be deleted");
|
||||
ok((yield promiseIsURIVisited(makeURI("http://4hour10minutes.com"))),
|
||||
@ -310,11 +258,11 @@ function onHistoryReady() {
|
||||
ok((yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||
"Pretend visit to before-today.com should still exist");
|
||||
|
||||
yield countEntries("4hour", "4hour form entry should be deleted", checkZero);
|
||||
yield countEntries("4hour10minutes", "4hour10minutes form entry should still exist", checkOne);
|
||||
ok(!formhist.nameExists("4hour"), "4hour form entry should be deleted");
|
||||
ok(formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should still exist");
|
||||
if (hoursSinceMidnight > 4)
|
||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||
ok(formhist.nameExists("today"), "today form entry should still exist");
|
||||
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
|
||||
|
||||
ok(!downloadExists(5555553), "<4 hour old download should now be deleted");
|
||||
ok(downloadExists(5555558), "4 hour 10 minute download should still be present");
|
||||
@ -327,8 +275,6 @@ function onHistoryReady() {
|
||||
s.sanitize();
|
||||
s.range = null;
|
||||
|
||||
yield promiseFormHistoryRemoved();
|
||||
|
||||
ok(!(yield promiseIsURIVisited(makeURI("http://4hour10minutes.com"))),
|
||||
"Pretend visit to 4hour10minutes.com should now be deleted");
|
||||
if (minutesSinceMidnight > 250) {
|
||||
@ -337,12 +283,12 @@ function onHistoryReady() {
|
||||
}
|
||||
ok((yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||
"Pretend visit to before-today.com should still exist");
|
||||
|
||||
yield countEntries("4hour10minutes", "4hour10minutes form entry should be deleted", checkZero);
|
||||
if (minutesSinceMidnight > 250)
|
||||
yield countEntries("today", "today form entry should still exist", checkOne);
|
||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||
|
||||
ok(!formhist.nameExists("4hour10minutes"), "4hour10minutes form entry should be deleted");
|
||||
if (minutesSinceMidnight > 250)
|
||||
ok(formhist.nameExists("today"), "today form entry should still exist");
|
||||
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
|
||||
|
||||
ok(!downloadExists(5555558), "4 hour 10 minute download should now be deleted");
|
||||
ok(downloadExists(5555550), "Year old download should still be present");
|
||||
if (minutesSinceMidnight > 250)
|
||||
@ -352,8 +298,6 @@ function onHistoryReady() {
|
||||
Sanitizer.prefs.setIntPref("timeSpan", 4);
|
||||
s.sanitize();
|
||||
|
||||
yield promiseFormHistoryRemoved();
|
||||
|
||||
// Be careful. If we add our objectss just before midnight, and sanitize
|
||||
// runs immediately after, they won't be expired. This is expected, but
|
||||
// we should not test in that case. We cannot just test for opposite
|
||||
@ -363,33 +307,28 @@ function onHistoryReady() {
|
||||
if (today) {
|
||||
ok(!(yield promiseIsURIVisited(makeURI("http://today.com"))),
|
||||
"Pretend visit to today.com should now be deleted");
|
||||
|
||||
yield countEntries("today", "today form entry should be deleted", checkZero);
|
||||
ok(!formhist.nameExists("today"), "today form entry should be deleted");
|
||||
ok(!downloadExists(5555554), "'Today' download should now be deleted");
|
||||
}
|
||||
|
||||
ok((yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||
"Pretend visit to before-today.com should still exist");
|
||||
yield countEntries("b4today", "b4today form entry should still exist", checkOne);
|
||||
ok(formhist.nameExists("b4today"), "b4today form entry should still exist");
|
||||
ok(downloadExists(5555550), "Year old download should still be present");
|
||||
|
||||
// Choose everything
|
||||
Sanitizer.prefs.setIntPref("timeSpan", 0);
|
||||
s.sanitize();
|
||||
|
||||
yield promiseFormHistoryRemoved();
|
||||
|
||||
ok(!(yield promiseIsURIVisited(makeURI("http://before-today.com"))),
|
||||
"Pretend visit to before-today.com should now be deleted");
|
||||
|
||||
yield countEntries("b4today", "b4today form entry should be deleted", checkZero);
|
||||
ok(!formhist.nameExists("b4today"), "b4today form entry should be deleted");
|
||||
|
||||
ok(!downloadExists(5555550), "Year old download should now be deleted");
|
||||
}
|
||||
|
||||
function setupHistory() {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
function setupHistory(aCallback) {
|
||||
let places = [];
|
||||
|
||||
function addPlace(aURI, aTitle, aVisitDate) {
|
||||
@ -424,140 +363,73 @@ function setupHistory() {
|
||||
PlacesUtils.asyncHistory.updatePlaces(places, {
|
||||
handleError: function () ok(false, "Unexpected error in adding visit."),
|
||||
handleResult: function () { },
|
||||
handleCompletion: function () deferred.resolve()
|
||||
handleCompletion: function () aCallback()
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function setupFormHistory() {
|
||||
// Make sure we've got a clean DB to start with.
|
||||
formhist.removeAllEntries();
|
||||
|
||||
function searchEntries(terms, params) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let results = [];
|
||||
FormHistory.search(terms, params, { handleResult: function (result) results.push(result),
|
||||
handleError: function (error) {
|
||||
do_throw("Error occurred searching form history: " + error);
|
||||
deferred.reject(error);
|
||||
},
|
||||
handleCompletion: function (reason) { deferred.resolve(results); }
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function update(changes)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
FormHistory.update(changes, { handleError: function (error) {
|
||||
do_throw("Error occurred searching form history: " + error);
|
||||
deferred.reject(error);
|
||||
},
|
||||
handleCompletion: function (reason) { deferred.resolve(); }
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
// Make sure we've got a clean DB to start with, then add the entries we'll be testing.
|
||||
yield update(
|
||||
[{
|
||||
op: "remove"
|
||||
},
|
||||
{
|
||||
op : "add",
|
||||
fieldname : "10minutes",
|
||||
value : "10m"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "1hour",
|
||||
value : "1h"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "1hour10minutes",
|
||||
value : "1h10m"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "2hour",
|
||||
value : "2h"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "2hour10minutes",
|
||||
value : "2h10m"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "4hour",
|
||||
value : "4h"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "4hour10minutes",
|
||||
value : "4h10m"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "today",
|
||||
value : "1d"
|
||||
}, {
|
||||
op : "add",
|
||||
fieldname : "b4today",
|
||||
value : "1y"
|
||||
}]);
|
||||
// Add the entries we'll be testing.
|
||||
formhist.addEntry("10minutes", "10m");
|
||||
formhist.addEntry("1hour", "1h");
|
||||
formhist.addEntry("1hour10minutes", "1h10m");
|
||||
formhist.addEntry("2hour", "2h");
|
||||
formhist.addEntry("2hour10minutes", "2h10m");
|
||||
formhist.addEntry("4hour", "4h");
|
||||
formhist.addEntry("4hour10minutes", "4h10m");
|
||||
formhist.addEntry("today", "1d");
|
||||
formhist.addEntry("b4today", "1y");
|
||||
|
||||
// Artifically age the entries to the proper vintage.
|
||||
let db = formhist.DBConnection;
|
||||
let timestamp = now_uSec - 10 * kUsecPerMin;
|
||||
let results = yield searchEntries(["guid"], { fieldname: "10minutes" });
|
||||
yield update({ op: "update", firstUsed: timestamp, guid: results[0].guid });
|
||||
|
||||
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
|
||||
timestamp + " WHERE fieldname = '10minutes'");
|
||||
timestamp = now_uSec - 45 * kUsecPerMin;
|
||||
results = yield searchEntries(["guid"], { fieldname: "1hour" });
|
||||
yield update({ op: "update", firstUsed: timestamp, guid: results[0].guid });
|
||||
|
||||
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
|
||||
timestamp + " WHERE fieldname = '1hour'");
|
||||
timestamp = now_uSec - 70 * kUsecPerMin;
|
||||
results = yield searchEntries(["guid"], { fieldname: "1hour10minutes" });
|
||||
yield update({ op: "update", firstUsed: timestamp, guid: results[0].guid });
|
||||
|
||||
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
|
||||
timestamp + " WHERE fieldname = '1hour10minutes'");
|
||||
timestamp = now_uSec - 90 * kUsecPerMin;
|
||||
results = yield searchEntries(["guid"], { fieldname: "2hour" });
|
||||
yield update({ op: "update", firstUsed: timestamp, guid: results[0].guid });
|
||||
|
||||
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
|
||||
timestamp + " WHERE fieldname = '2hour'");
|
||||
timestamp = now_uSec - 130 * kUsecPerMin;
|
||||
results = yield searchEntries(["guid"], { fieldname: "2hour10minutes" });
|
||||
yield update({ op: "update", firstUsed: timestamp, guid: results[0].guid });
|
||||
|
||||
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
|
||||
timestamp + " WHERE fieldname = '2hour10minutes'");
|
||||
timestamp = now_uSec - 180 * kUsecPerMin;
|
||||
results = yield searchEntries(["guid"], { fieldname: "4hour" });
|
||||
yield update({ op: "update", firstUsed: timestamp, guid: results[0].guid });
|
||||
|
||||
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
|
||||
timestamp + " WHERE fieldname = '4hour'");
|
||||
timestamp = now_uSec - 250 * kUsecPerMin;
|
||||
results = yield searchEntries(["guid"], { fieldname: "4hour10minutes" });
|
||||
yield update({ op: "update", firstUsed: timestamp, guid: results[0].guid });
|
||||
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
|
||||
timestamp + " WHERE fieldname = '4hour10minutes'");
|
||||
|
||||
let today = new Date();
|
||||
today.setHours(0);
|
||||
today.setMinutes(0);
|
||||
today.setSeconds(1);
|
||||
timestamp = today.getTime() * 1000;
|
||||
results = yield searchEntries(["guid"], { fieldname: "today" });
|
||||
yield update({ op: "update", firstUsed: timestamp, guid: results[0].guid });
|
||||
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
|
||||
timestamp + " WHERE fieldname = 'today'");
|
||||
|
||||
let lastYear = new Date();
|
||||
lastYear.setFullYear(lastYear.getFullYear() - 1);
|
||||
timestamp = lastYear.getTime() * 1000;
|
||||
results = yield searchEntries(["guid"], { fieldname: "b4today" });
|
||||
yield update({ op: "update", firstUsed: timestamp, guid: results[0].guid });
|
||||
|
||||
var checks = 0;
|
||||
let checkOne = function(num, message) { is(num, 1, message); checks++; }
|
||||
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
|
||||
timestamp + " WHERE fieldname = 'b4today'");
|
||||
|
||||
// Sanity check.
|
||||
yield countEntries("10minutes", "Checking for 10minutes form history entry creation", checkOne);
|
||||
yield countEntries("1hour", "Checking for 1hour form history entry creation", checkOne);
|
||||
yield countEntries("1hour10minutes", "Checking for 1hour10minutes form history entry creation", checkOne);
|
||||
yield countEntries("2hour", "Checking for 2hour form history entry creation", checkOne);
|
||||
yield countEntries("2hour10minutes", "Checking for 2hour10minutes form history entry creation", checkOne);
|
||||
yield countEntries("4hour", "Checking for 4hour form history entry creation", checkOne);
|
||||
yield countEntries("4hour10minutes", "Checking for 4hour10minutes form history entry creation", checkOne);
|
||||
yield countEntries("today", "Checking for today form history entry creation", checkOne);
|
||||
yield countEntries("b4today", "Checking for b4today form history entry creation", checkOne);
|
||||
is(checks, 9, "9 checks made");
|
||||
ok(formhist.nameExists("10minutes"), "Checking for 10minutes form history entry creation");
|
||||
ok(formhist.nameExists("1hour"), "Checking for 1hour form history entry creation");
|
||||
ok(formhist.nameExists("1hour10minutes"), "Checking for 1hour10minutes form history entry creation");
|
||||
ok(formhist.nameExists("2hour"), "Checking for 2hour form history entry creation");
|
||||
ok(formhist.nameExists("2hour10minutes"), "Checking for 2hour10minutes form history entry creation");
|
||||
ok(formhist.nameExists("4hour"), "Checking for 4hour form history entry creation");
|
||||
ok(formhist.nameExists("4hour10minutes"), "Checking for 4hour10minutes form history entry creation");
|
||||
ok(formhist.nameExists("today"), "Checking for today form history entry creation");
|
||||
ok(formhist.nameExists("b4today"), "Checking for b4today form history entry creation");
|
||||
}
|
||||
|
||||
function setupDownloads() {
|
||||
|
@ -17,11 +17,6 @@
|
||||
* browser/base/content/test/browser_sanitize-timespans.js.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
let tempScope = {};
|
||||
Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
|
||||
.loadSubScript("chrome://browser/content/sanitize.js", tempScope);
|
||||
@ -29,11 +24,11 @@ let Sanitizer = tempScope.Sanitizer;
|
||||
|
||||
const dm = Cc["@mozilla.org/download-manager;1"].
|
||||
getService(Ci.nsIDownloadManager);
|
||||
const formhist = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
const kUsecPerMin = 60 * 1000000;
|
||||
|
||||
let formEntries;
|
||||
|
||||
// Add tests here. Each is a function that's called by doNextTest().
|
||||
var gAllTests = [
|
||||
|
||||
@ -85,7 +80,7 @@ var gAllTests = [
|
||||
};
|
||||
wh.onunload = function () {
|
||||
yield promiseHistoryClearedState(uris, false);
|
||||
yield blankSlate();
|
||||
blankSlate();
|
||||
yield promiseHistoryClearedState(uris, true);
|
||||
};
|
||||
wh.open();
|
||||
@ -153,7 +148,7 @@ var gAllTests = [
|
||||
ensureDownloadsClearedState(olderDownloadIDs, false);
|
||||
|
||||
// OK, done, cleanup after ourselves.
|
||||
yield blankSlate();
|
||||
blankSlate();
|
||||
yield promiseHistoryClearedState(olderURIs, true);
|
||||
ensureDownloadsClearedState(olderDownloadIDs, true);
|
||||
};
|
||||
@ -161,23 +156,6 @@ var gAllTests = [
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Add form history entries for the next test.
|
||||
*/
|
||||
function () {
|
||||
formEntries = [];
|
||||
|
||||
let iter = function() {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
formEntries.push(addFormEntryWithMinutesAgo(iter, i));
|
||||
yield;
|
||||
}
|
||||
doNextTest();
|
||||
}();
|
||||
|
||||
iter.next();
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensures that the combined history-downloads checkbox removes neither
|
||||
* history visits nor downloads when not checked.
|
||||
@ -198,6 +176,10 @@ var gAllTests = [
|
||||
for (let i = 0; i < 5; i++) {
|
||||
downloadIDs.push(addDownloadWithMinutesAgo(i));
|
||||
}
|
||||
let formEntries = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
formEntries.push(addFormEntryWithMinutesAgo(i));
|
||||
}
|
||||
|
||||
let wh = new WindowHelper();
|
||||
wh.onload = function () {
|
||||
@ -225,14 +207,10 @@ var gAllTests = [
|
||||
// Of the three only form entries should be cleared.
|
||||
yield promiseHistoryClearedState(uris, false);
|
||||
ensureDownloadsClearedState(downloadIDs, false);
|
||||
|
||||
formEntries.forEach(function (entry) {
|
||||
let exists = yield formNameExists(entry);
|
||||
is(exists, false, "form entry " + entry + " should no longer exist");
|
||||
});
|
||||
ensureFormEntriesClearedState(formEntries, true);
|
||||
|
||||
// OK, done, cleanup after ourselves.
|
||||
yield blankSlate();
|
||||
blankSlate();
|
||||
yield promiseHistoryClearedState(uris, true);
|
||||
ensureDownloadsClearedState(downloadIDs, true);
|
||||
};
|
||||
@ -323,19 +301,6 @@ var gAllTests = [
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Add form history entry for the next test.
|
||||
*/
|
||||
function () {
|
||||
let iter = function() {
|
||||
formEntries = [ addFormEntryWithMinutesAgo(iter, 10) ];
|
||||
yield;
|
||||
doNextTest();
|
||||
}();
|
||||
|
||||
iter.next();
|
||||
},
|
||||
|
||||
/**
|
||||
* The next three tests checks that when a certain history item cannot be
|
||||
* cleared then the checkbox should be both disabled and unchecked.
|
||||
@ -346,6 +311,7 @@ var gAllTests = [
|
||||
let pURI = makeURI("http://" + 10 + "-minutes-ago.com/");
|
||||
addVisits({uri: pURI, visitDate: visitTimeForMinutesAgo(10)}, function() {
|
||||
let uris = [ pURI ];
|
||||
let formEntries = [ addFormEntryWithMinutesAgo(10) ];
|
||||
|
||||
let wh = new WindowHelper();
|
||||
wh.onload = function() {
|
||||
@ -365,9 +331,7 @@ var gAllTests = [
|
||||
};
|
||||
wh.onunload = function () {
|
||||
yield promiseHistoryClearedState(uris, true);
|
||||
|
||||
let exists = yield formNameExists(formEntries[0]);
|
||||
is(exists, false, "form entry " + formEntries[0] + " should no longer exist");
|
||||
ensureFormEntriesClearedState(formEntries, true);
|
||||
};
|
||||
wh.open();
|
||||
});
|
||||
@ -401,21 +365,9 @@ var gAllTests = [
|
||||
}
|
||||
wh.open();
|
||||
},
|
||||
|
||||
/**
|
||||
* Add form history entry for the next test.
|
||||
*/
|
||||
function () {
|
||||
let iter = function() {
|
||||
formEntries = [ addFormEntryWithMinutesAgo(iter, 10) ];
|
||||
yield;
|
||||
doNextTest();
|
||||
}();
|
||||
let formEntries = [ addFormEntryWithMinutesAgo(10) ];
|
||||
|
||||
iter.next();
|
||||
},
|
||||
|
||||
function () {
|
||||
let wh = new WindowHelper();
|
||||
wh.onload = function() {
|
||||
boolPrefIs("cpd.formdata", true,
|
||||
@ -431,8 +383,7 @@ var gAllTests = [
|
||||
this.acceptDialog();
|
||||
};
|
||||
wh.onunload = function () {
|
||||
let exists = yield formNameExists(formEntries[0]);
|
||||
is(exists, false, "form entry " + formEntries[0] + " should no longer exist");
|
||||
ensureFormEntriesClearedState(formEntries, true);
|
||||
};
|
||||
wh.open();
|
||||
},
|
||||
@ -788,9 +739,7 @@ WindowHelper.prototype = {
|
||||
* Opens the clear recent history dialog. Before calling this, set
|
||||
* this.onload to a function to execute onload. It should close the dialog
|
||||
* when done so that the tests may continue. Set this.onunload to a function
|
||||
* to execute onunload. this.onunload is optional. If it returns true, the
|
||||
* caller is expected to call waitForAsyncUpdates at some point; if false is
|
||||
* returned, waitForAsyncUpdates is called automatically.
|
||||
* to execute onunload. this.onunload is optional.
|
||||
*/
|
||||
open: function () {
|
||||
let wh = this;
|
||||
@ -942,59 +891,28 @@ function addDownloadWithMinutesAgo(aMinutesAgo) {
|
||||
* @param aMinutesAgo
|
||||
* The entry will be added this many minutes ago
|
||||
*/
|
||||
function addFormEntryWithMinutesAgo(then, aMinutesAgo) {
|
||||
function addFormEntryWithMinutesAgo(aMinutesAgo) {
|
||||
let name = aMinutesAgo + "-minutes-ago";
|
||||
formhist.addEntry(name, "dummy");
|
||||
|
||||
// Artifically age the entry to the proper vintage.
|
||||
let db = formhist.DBConnection;
|
||||
let timestamp = now_uSec - (aMinutesAgo * kUsecPerMin);
|
||||
db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
|
||||
timestamp + " WHERE fieldname = '" + name + "'");
|
||||
|
||||
FormHistory.update({ op: "add", fieldname: name, value: "dummy", firstUsed: timestamp },
|
||||
{ handleError: function (error) {
|
||||
do_throw("Error occurred updating form history: " + error);
|
||||
},
|
||||
handleCompletion: function (reason) { then.next(); }
|
||||
});
|
||||
is(formhist.nameExists(name), true,
|
||||
"Sanity check: form entry " + name + " should exist after creating it");
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a form entry exists.
|
||||
*/
|
||||
function formNameExists(name)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let count = 0;
|
||||
FormHistory.count({ fieldname: name },
|
||||
{ handleResult: function (result) count = result,
|
||||
handleError: function (error) {
|
||||
do_throw("Error occurred searching form history: " + error);
|
||||
deferred.reject(error);
|
||||
},
|
||||
handleCompletion: function (reason) {
|
||||
if (!reason) deferred.resolve(count);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all history visits, downloads, and form entries.
|
||||
*/
|
||||
function blankSlate() {
|
||||
PlacesUtils.bhistory.removeAllPages();
|
||||
dm.cleanUp();
|
||||
|
||||
let deferred = Promise.defer();
|
||||
FormHistory.update({ op: "remove" },
|
||||
{ handleError: function (error) {
|
||||
do_throw("Error occurred updating form history: " + error);
|
||||
deferred.reject(error);
|
||||
},
|
||||
handleCompletion: function (reason) { if (!reason) deferred.resolve(); }
|
||||
});
|
||||
return deferred.promise;
|
||||
formhist.removeAllEntries();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1064,6 +982,22 @@ function ensureDownloadsClearedState(aDownloadIDs, aShouldBeCleared) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the specified form entries are either cleared or not.
|
||||
*
|
||||
* @param aFormEntries
|
||||
* Array of form entry names
|
||||
* @param aShouldBeCleared
|
||||
* True if each form entry should be cleared, false otherwise
|
||||
*/
|
||||
function ensureFormEntriesClearedState(aFormEntries, aShouldBeCleared) {
|
||||
let niceStr = aShouldBeCleared ? "no longer" : "still";
|
||||
aFormEntries.forEach(function (entry) {
|
||||
is(formhist.nameExists(entry), !aShouldBeCleared,
|
||||
"form entry " + entry + " should " + niceStr + " exist");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the given pref is the expected value.
|
||||
*
|
||||
@ -1092,8 +1026,8 @@ function visitTimeForMinutesAgo(aMinutesAgo) {
|
||||
|
||||
function test() {
|
||||
requestLongerTimeout(2);
|
||||
waitForExplicitFinish();
|
||||
blankSlate();
|
||||
waitForExplicitFinish();
|
||||
// Kick off all the tests in the gAllTests array.
|
||||
waitForAsyncUpdates(doNextTest);
|
||||
}
|
||||
|
@ -30,12 +30,6 @@ const UNEXPECTED_NOTIFICATIONS = [
|
||||
|
||||
const URL = "ftp://localhost/clearHistoryOnShutdown/";
|
||||
|
||||
// Send the profile-after-change notification to the form history component to ensure
|
||||
// that it has been initialized.
|
||||
var formHistoryStartup = Cc["@mozilla.org/satchel/form-history-startup;1"].
|
||||
getService(Ci.nsIObserver);
|
||||
formHistoryStartup.observe(null, "profile-after-change", null);
|
||||
|
||||
let notificationIndex = 0;
|
||||
|
||||
let notificationsObserver = {
|
||||
|
@ -109,9 +109,6 @@
|
||||
"anonid", "searchbar-popup");</field>
|
||||
<field name="_ss">null</field>
|
||||
<field name="_engines">null</field>
|
||||
<field name="FormHistory" readonly="true">
|
||||
(Components.utils.import("resource://gre/modules/FormHistory.jsm", {})).FormHistory;
|
||||
</field>
|
||||
|
||||
<property name="engines" readonly="true">
|
||||
<getter><![CDATA[
|
||||
@ -458,13 +455,12 @@
|
||||
|
||||
// Save the current value in the form history
|
||||
if (textValue && !PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
this.FormHistory.update(
|
||||
{ op : "bump",
|
||||
fieldname : textBox.getAttribute("autocompletesearchparam"),
|
||||
value : textValue },
|
||||
{ handleError : function(aError) {
|
||||
Components.utils.reportError("Saving search to form history failed: " + aError.message);
|
||||
}});
|
||||
try {
|
||||
textBox._formHistSvc.addEntry(textBox.getAttribute("autocompletesearchparam"),
|
||||
textValue);
|
||||
} catch (ex) {
|
||||
Components.utils.reportError("Saving search to form history failed: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
this.doSearch(textValue, where);
|
||||
@ -558,6 +554,7 @@
|
||||
]]></destructor>
|
||||
|
||||
<field name="_stringBundle"/>
|
||||
<field name="_formHistSvc"/>
|
||||
<field name="_prefBranch"/>
|
||||
<field name="_suggestMenuItem"/>
|
||||
<field name="_suggestEnabled"/>
|
||||
@ -568,6 +565,9 @@
|
||||
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
// Initialize fields
|
||||
this._stringBundle = document.getBindingParent(this)._stringBundle;
|
||||
this._formHistSvc =
|
||||
Components.classes["@mozilla.org/satchel/form-history;1"]
|
||||
.getService(Components.interfaces.nsIFormHistory2);
|
||||
this._prefBranch =
|
||||
Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch);
|
||||
@ -748,6 +748,10 @@
|
||||
},
|
||||
|
||||
isCommandEnabled: function(aCommand) {
|
||||
if (aCommand == "cmd_clearhistory") {
|
||||
var param = this._self.getAttribute("autocompletesearchparam");
|
||||
return this._self._formHistSvc.nameExists(param);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
@ -755,10 +759,7 @@
|
||||
switch (aCommand) {
|
||||
case "cmd_clearhistory":
|
||||
var param = this._self.getAttribute("autocompletesearchparam");
|
||||
|
||||
let searchBar = this._self.parentNode;
|
||||
|
||||
BrowserSearch.searchBar.FormHistory.update({ op : "remove", fieldname : param }, null);
|
||||
this._self._formHistSvc.removeEntriesForName(param);
|
||||
this._self.value = "";
|
||||
break;
|
||||
case "cmd_togglesuggest":
|
||||
|
@ -5,9 +5,6 @@ this._scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", chromeUtils);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
@ -23,8 +20,6 @@ function test() {
|
||||
|
||||
var ss = Services.search;
|
||||
|
||||
let testIterator;
|
||||
|
||||
function observer(aSub, aTopic, aData) {
|
||||
switch (aData) {
|
||||
case "engine-added":
|
||||
@ -187,64 +182,33 @@ function test() {
|
||||
content.location.href = "about:blank";
|
||||
simulateClick({ button: 2 }, searchButton);
|
||||
setTimeout(function() {
|
||||
|
||||
is(gBrowser.tabs.length, preTabNo, "RightClick did not open new tab");
|
||||
is(gBrowser.currentURI.spec, "about:blank", "RightClick did nothing");
|
||||
|
||||
testIterator = testSearchHistory();
|
||||
testIterator.next();
|
||||
testSearchHistory();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function countEntries(name, value, message) {
|
||||
let count = 0;
|
||||
FormHistory.count({ fieldname: name, value: value },
|
||||
{ handleResult: function(result) { count = result; },
|
||||
handleError: function(error) { throw error; },
|
||||
handleCompletion: function(reason) {
|
||||
if (!reason) {
|
||||
ok(count > 0, message);
|
||||
testIterator.next();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testSearchHistory() {
|
||||
var textbox = searchBar._textbox;
|
||||
for (var i = 0; i < searchEntries.length; i++) {
|
||||
yield countEntries(textbox.getAttribute("autocompletesearchparam"), searchEntries[i],
|
||||
"form history entry '" + searchEntries[i] + "' should exist");
|
||||
let exists = textbox._formHistSvc.entryExists(textbox.getAttribute("autocompletesearchparam"), searchEntries[i]);
|
||||
ok(exists, "form history entry '" + searchEntries[i] + "' should exist");
|
||||
}
|
||||
testAutocomplete();
|
||||
}
|
||||
|
||||
function testAutocomplete() {
|
||||
var popup = searchBar.textbox.popup;
|
||||
popup.addEventListener("popupshown", function testACPopupShowing() {
|
||||
popup.removeEventListener("popupshown", testACPopupShowing);
|
||||
popup.addEventListener("popupshowing", function testACPopupShowing() {
|
||||
popup.removeEventListener("popupshowing", testACPopupShowing);
|
||||
checkMenuEntries(searchEntries);
|
||||
testClearHistory();
|
||||
SimpleTest.executeSoon(finalize);
|
||||
});
|
||||
searchBar.textbox.showHistoryPopup();
|
||||
}
|
||||
|
||||
function testClearHistory() {
|
||||
let controller = searchBar.textbox.controllers.getControllerForCommand("cmd_clearhistory")
|
||||
ok(controller.isCommandEnabled("cmd_clearhistory"), "Clear history command enabled");
|
||||
controller.doCommand("cmd_clearhistory");
|
||||
let count = 0;
|
||||
FormHistory.count({ },
|
||||
{ handleResult: function(result) { count = result; },
|
||||
handleError: function(error) { throw error; },
|
||||
handleCompletion: function(reason) {
|
||||
if (!reason) {
|
||||
ok(count == 0, "History cleared");
|
||||
finalize();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
searchBar.value = "";
|
||||
while (gBrowser.tabs.length != 1) {
|
||||
|
@ -432,7 +432,6 @@
|
||||
@BINPATH@/components/satchel.manifest
|
||||
@BINPATH@/components/nsFormAutoComplete.js
|
||||
@BINPATH@/components/nsFormHistory.js
|
||||
@BINPATH@/components/FormHistoryStartup.js
|
||||
@BINPATH@/components/nsInputListAutoComplete.js
|
||||
@BINPATH@/components/contentSecurityPolicy.manifest
|
||||
@BINPATH@/components/contentSecurityPolicy.js
|
||||
|
@ -37,7 +37,7 @@ SimpleTest.waitForFocus(function() {
|
||||
function listener() {
|
||||
popupShown = true;
|
||||
}
|
||||
SpecialPowers.addAutoCompletePopupEventListener(window, "popupshowing", listener);
|
||||
SpecialPowers.addAutoCompletePopupEventListener(window, listener);
|
||||
|
||||
var event = document.createEvent("KeyboardEvent");
|
||||
|
||||
@ -49,7 +49,7 @@ SimpleTest.waitForFocus(function() {
|
||||
|
||||
hitEventLoop(function() {
|
||||
ok(!popupShown, "Popup must not be opened");
|
||||
SpecialPowers.removeAutoCompletePopupEventListener(window, "popupshowing", listener);
|
||||
SpecialPowers.removeAutoCompletePopupEventListener(window, listener);
|
||||
SimpleTest.finish();
|
||||
}, 100);
|
||||
}, 0);
|
||||
|
@ -4530,7 +4530,7 @@ var FormAssistant = {
|
||||
|
||||
if (this._showValidationMessage(focused))
|
||||
break;
|
||||
this._showAutoCompleteSuggestions(focused, function () {});
|
||||
this._showAutoCompleteSuggestions(focused);
|
||||
} else {
|
||||
// temporarily hide the form assist popup while we're panning or zooming the page
|
||||
this._hideFormAssistPopup();
|
||||
@ -4600,14 +4600,8 @@ var FormAssistant = {
|
||||
// only be available if an invalid form was submitted)
|
||||
if (this._showValidationMessage(currentElement))
|
||||
break;
|
||||
|
||||
let checkResultsClick = hasResults => {
|
||||
if (!hasResults) {
|
||||
this._hideFormAssistPopup();
|
||||
}
|
||||
};
|
||||
|
||||
this._showAutoCompleteSuggestions(currentElement, checkResultsClick);
|
||||
if (!this._showAutoCompleteSuggestions(currentElement))
|
||||
this._hideFormAssistPopup();
|
||||
break;
|
||||
|
||||
case "input":
|
||||
@ -4615,18 +4609,13 @@ var FormAssistant = {
|
||||
|
||||
// Since we can only show one popup at a time, prioritze autocomplete
|
||||
// suggestions over a form validation message
|
||||
let checkResultsInput = hasResults => {
|
||||
if (hasResults)
|
||||
return;
|
||||
if (this._showAutoCompleteSuggestions(currentElement))
|
||||
break;
|
||||
if (this._showValidationMessage(currentElement))
|
||||
break;
|
||||
|
||||
if (!this._showValidationMessage(currentElement))
|
||||
return;
|
||||
|
||||
// If we're not showing autocomplete suggestions, hide the form assist popup
|
||||
this._hideFormAssistPopup();
|
||||
};
|
||||
|
||||
this._showAutoCompleteSuggestions(currentElement, checkResultsInput);
|
||||
// If we're not showing autocomplete suggestions, hide the form assist popup
|
||||
this._hideFormAssistPopup();
|
||||
break;
|
||||
|
||||
// Reset invalid submit state on each pageshow
|
||||
@ -4650,31 +4639,27 @@ var FormAssistant = {
|
||||
},
|
||||
|
||||
// Retrieves autocomplete suggestions for an element from the form autocomplete service.
|
||||
// aCallback(array_of_suggestions) is called when results are available.
|
||||
_getAutoCompleteSuggestions: function _getAutoCompleteSuggestions(aSearchString, aElement, aCallback) {
|
||||
_getAutoCompleteSuggestions: function _getAutoCompleteSuggestions(aSearchString, aElement) {
|
||||
// Cache the form autocomplete service for future use
|
||||
if (!this._formAutoCompleteService)
|
||||
this._formAutoCompleteService = Cc["@mozilla.org/satchel/form-autocomplete;1"].
|
||||
getService(Ci.nsIFormAutoComplete);
|
||||
|
||||
let resultsAvailable = function (results) {
|
||||
let suggestions = [];
|
||||
for (let i = 0; i < results.matchCount; i++) {
|
||||
let value = results.getValueAt(i);
|
||||
let results = this._formAutoCompleteService.autoCompleteSearch(aElement.name || aElement.id,
|
||||
aSearchString, aElement, null);
|
||||
let suggestions = [];
|
||||
for (let i = 0; i < results.matchCount; i++) {
|
||||
let value = results.getValueAt(i);
|
||||
|
||||
// Do not show the value if it is the current one in the input field
|
||||
if (value == aSearchString)
|
||||
continue;
|
||||
// Do not show the value if it is the current one in the input field
|
||||
if (value == aSearchString)
|
||||
continue;
|
||||
|
||||
// Supply a label and value, since they can differ for datalist suggestions
|
||||
suggestions.push({ label: value, value: value });
|
||||
aCallback(suggestions);
|
||||
}
|
||||
};
|
||||
// Supply a label and value, since they can differ for datalist suggestions
|
||||
suggestions.push({ label: value, value: value });
|
||||
}
|
||||
|
||||
this._formAutoCompleteService.autoCompleteSearchAsync(aElement.name || aElement.id,
|
||||
aSearchString, aElement, null,
|
||||
resultsAvailable);
|
||||
return suggestions;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -4711,47 +4696,40 @@ var FormAssistant = {
|
||||
},
|
||||
|
||||
// Retrieves autocomplete suggestions for an element from the form autocomplete service
|
||||
// and sends the suggestions to the Java UI, along with element position data. As
|
||||
// autocomplete queries are asynchronous, calls aCallback when done with a true
|
||||
// argument if results were found and false if no results were found.
|
||||
_showAutoCompleteSuggestions: function _showAutoCompleteSuggestions(aElement, aCallback) {
|
||||
if (!this._isAutoComplete(aElement)) {
|
||||
aCallback(false);
|
||||
return;
|
||||
}
|
||||
// and sends the suggestions to the Java UI, along with element position data.
|
||||
// Returns true if there are suggestions to show, false otherwise.
|
||||
_showAutoCompleteSuggestions: function _showAutoCompleteSuggestions(aElement) {
|
||||
if (!this._isAutoComplete(aElement))
|
||||
return false;
|
||||
|
||||
// Don't display the form auto-complete popup after the user starts typing
|
||||
// to avoid confusing somes IME. See bug 758820 and bug 632744.
|
||||
if (this._isBlocklisted && aElement.value.length > 0) {
|
||||
aCallback(false);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
let resultsAvailable = autoCompleteSuggestions => {
|
||||
// On desktop, we show datalist suggestions below autocomplete suggestions,
|
||||
// without duplicates removed.
|
||||
let listSuggestions = this._getListSuggestions(aElement);
|
||||
let suggestions = autoCompleteSuggestions.concat(listSuggestions);
|
||||
let autoCompleteSuggestions = this._getAutoCompleteSuggestions(aElement.value, aElement);
|
||||
let listSuggestions = this._getListSuggestions(aElement);
|
||||
|
||||
// Return false if there are no suggestions to show
|
||||
if (!suggestions.length) {
|
||||
aCallback(false);
|
||||
return;
|
||||
}
|
||||
// On desktop, we show datalist suggestions below autocomplete suggestions,
|
||||
// without duplicates removed.
|
||||
let suggestions = autoCompleteSuggestions.concat(listSuggestions);
|
||||
|
||||
sendMessageToJava({
|
||||
type: "FormAssist:AutoComplete",
|
||||
suggestions: suggestions,
|
||||
rect: ElementTouchHelper.getBoundingContentRect(aElement)
|
||||
});
|
||||
// Return false if there are no suggestions to show
|
||||
if (!suggestions.length)
|
||||
return false;
|
||||
|
||||
// Keep track of input element so we can fill it in if the user
|
||||
// selects an autocomplete suggestion
|
||||
this._currentInputElement = aElement;
|
||||
aCallback(true);
|
||||
};
|
||||
sendMessageToJava({
|
||||
type: "FormAssist:AutoComplete",
|
||||
suggestions: suggestions,
|
||||
rect: ElementTouchHelper.getBoundingContentRect(aElement)
|
||||
});
|
||||
|
||||
this._getAutoCompleteSuggestions(aElement.value, aElement, resultsAvailable);
|
||||
// Keep track of input element so we can fill it in if the user
|
||||
// selects an autocomplete suggestion
|
||||
this._currentInputElement = aElement;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// Only show a validation message if the user submitted an invalid form,
|
||||
|
@ -102,21 +102,7 @@ FormAutoComplete.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
// This method is obsolete. Use autoCompleteSearchAsync instead.
|
||||
autoCompleteSearch: function autoCompleteSearch(aName, aQuery, aField, aPrev) {
|
||||
let result = null;
|
||||
let listener = function() { result = r; };
|
||||
this._autoCompleteSearchAsync(aName, aQuery, aField, aPrev, listener);
|
||||
|
||||
let thread = Components.classes["@mozilla.org/thread-manager;1"].getService().currentThread;
|
||||
while (!result) {
|
||||
thread.processNextEvent(true);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
autoCompleteSearchAsync: function autoCompleteSearch(aName, aQuery, aField, aPrev, aCallback) {
|
||||
if (!Services.prefs.getBoolPref("browser.formfill.enable"))
|
||||
return null;
|
||||
|
||||
@ -127,27 +113,23 @@ FormAutoComplete.prototype = {
|
||||
// Don't allow duplicates get merged into the final results
|
||||
let dupCheck = {};
|
||||
|
||||
let callback = aNormalResults => {
|
||||
if (aNormalResults.matchCount > 0) {
|
||||
for (let i = 0; i < aNormalResults.matchCount; i++) {
|
||||
dupCheck[aNormalResults.getValueAt(i)] = true;
|
||||
result.appendMatch(aNormalResults.getValueAt(i), aNormalResults.getCommentAt(i),
|
||||
aNormalResults.getImageAt(i), aNormalResults.getStyleAt(i));
|
||||
}
|
||||
// Use the base form autocomplete for non-contact searches
|
||||
let normal = FAC.autoCompleteSearch(aName, aQuery, aField, aPrev);
|
||||
if (normal.matchCount > 0) {
|
||||
for (let i = 0; i < normal.matchCount; i++) {
|
||||
dupCheck[normal.getValueAt(i)] = true;
|
||||
result.appendMatch(normal.getValueAt(i), normal.getCommentAt(i), normal.getImageAt(i), normal.getStyleAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Do searches for certain input fields
|
||||
let type = this.checkQueryType(aName, aField);
|
||||
if (type != null)
|
||||
this.findContact(aQuery, type, result, dupCheck);
|
||||
// Do searches for certain input fields
|
||||
let type = this.checkQueryType(aName, aField);
|
||||
if (type != null)
|
||||
this.findContact(aQuery, type, result, dupCheck);
|
||||
|
||||
let resultCode = result.matchCount ? "RESULT_SUCCESS" : "RESULT_NOMATCH";
|
||||
result.setSearchResult(Ci.nsIAutoCompleteResult[resultCode]);
|
||||
if (aCallback && aCallback.onSearchCompletion)
|
||||
aCallback.onSearchCompletion(result);
|
||||
};
|
||||
|
||||
FAC.autoCompleteSearchAsync(aName, aQuery, aField, aPrev, callback);
|
||||
let resultCode = result.matchCount ? "RESULT_SUCCESS" : "RESULT_NOMATCH";
|
||||
result.setSearchResult(Ci.nsIAutoCompleteResult[resultCode]);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -343,7 +343,6 @@
|
||||
@BINPATH@/components/satchel.manifest
|
||||
@BINPATH@/components/nsFormAutoComplete.js
|
||||
@BINPATH@/components/nsFormHistory.js
|
||||
@BINPATH@/components/FormHistoryStartup.js
|
||||
@BINPATH@/components/nsInputListAutoComplete.js
|
||||
@BINPATH@/components/contentSecurityPolicy.manifest
|
||||
@BINPATH@/components/contentSecurityPolicy.js
|
||||
|
@ -962,21 +962,16 @@ SpecialPowersAPI.prototype = {
|
||||
return this._getTopChromeWindow(window).document
|
||||
.getElementById("PopupAutoComplete");
|
||||
},
|
||||
addAutoCompletePopupEventListener: function(window, eventname, listener) {
|
||||
this._getAutoCompletePopup(window).addEventListener(eventname,
|
||||
addAutoCompletePopupEventListener: function(window, listener) {
|
||||
this._getAutoCompletePopup(window).addEventListener("popupshowing",
|
||||
listener,
|
||||
false);
|
||||
},
|
||||
removeAutoCompletePopupEventListener: function(window, eventname, listener) {
|
||||
this._getAutoCompletePopup(window).removeEventListener(eventname,
|
||||
removeAutoCompletePopupEventListener: function(window, listener) {
|
||||
this._getAutoCompletePopup(window).removeEventListener("popupshowing",
|
||||
listener,
|
||||
false);
|
||||
},
|
||||
get formHistory() {
|
||||
let tmp = {};
|
||||
Cu.import("resource://gre/modules/FormHistory.jsm", tmp);
|
||||
return wrapPrivileged(tmp.FormHistory);
|
||||
},
|
||||
getFormFillController: function(window) {
|
||||
return Components.classes["@mozilla.org/satchel/form-fill-controller;1"]
|
||||
.getService(Components.interfaces.nsIFormFillController);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,78 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
function FormHistoryStartup() { }
|
||||
|
||||
FormHistoryStartup.prototype = {
|
||||
classID: Components.ID("{3A0012EB-007F-4BB8-AA81-A07385F77A25}"),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsIFrameMessageListener
|
||||
]),
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "nsPref:changed":
|
||||
FormHistory.updatePrefs();
|
||||
break;
|
||||
case "idle-daily":
|
||||
case "formhistory-expire-now":
|
||||
FormHistory.expireOldEntries();
|
||||
break;
|
||||
case "profile-before-change":
|
||||
FormHistory.shutdown();
|
||||
break;
|
||||
case "profile-after-change":
|
||||
this.init();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
inited: false,
|
||||
|
||||
init: function()
|
||||
{
|
||||
if (this.inited)
|
||||
return;
|
||||
this.inited = true;
|
||||
|
||||
Services.prefs.addObserver("browser.formfill.", this, true);
|
||||
|
||||
// triggers needed service cleanup and db shutdown
|
||||
Services.obs.addObserver(this, "profile-before-change", true);
|
||||
Services.obs.addObserver(this, "formhistory-expire-now", true);
|
||||
|
||||
let messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Ci.nsIMessageListenerManager);
|
||||
messageManager.loadFrameScript("chrome://satchel/content/formSubmitListener.js", true);
|
||||
messageManager.addMessageListener("FormHistory:FormSubmitEntries", this);
|
||||
},
|
||||
|
||||
receiveMessage: function(message) {
|
||||
let entries = message.json;
|
||||
let changes = entries.map(function(entry) {
|
||||
return {
|
||||
op : "bump",
|
||||
fieldname : entry.name,
|
||||
value : entry.value,
|
||||
}
|
||||
});
|
||||
|
||||
FormHistory.update(changes);
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FormHistoryStartup]);
|
@ -25,7 +25,6 @@ CPPSRCS = \
|
||||
|
||||
EXTRA_COMPONENTS = \
|
||||
nsFormAutoComplete.js \
|
||||
FormHistoryStartup.js \
|
||||
nsInputListAutoComplete.js \
|
||||
satchel.manifest \
|
||||
$(NULL)
|
||||
@ -38,8 +37,4 @@ EXTRA_JS_MODULES = \
|
||||
nsFormAutoCompleteResult.jsm \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_PP_JS_MODULES = \
|
||||
FormHistory.jsm \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -10,11 +10,6 @@ const Cr = Components.results;
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
|
||||
"resource://gre/modules/Deprecated.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
function FormAutoComplete() {
|
||||
this.init();
|
||||
}
|
||||
@ -23,6 +18,14 @@ FormAutoComplete.prototype = {
|
||||
classID : Components.ID("{c11c21b2-71c9-4f87-a0f8-5e13f50495fd}"),
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIFormAutoComplete, Ci.nsISupportsWeakReference]),
|
||||
|
||||
__formHistory : null,
|
||||
get _formHistory() {
|
||||
if (!this.__formHistory)
|
||||
this.__formHistory = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
return this.__formHistory;
|
||||
},
|
||||
|
||||
_prefBranch : null,
|
||||
_debug : true, // mirrors browser.formfill.debug
|
||||
_enabled : true, // mirrors browser.formfill.enable preference
|
||||
@ -34,13 +37,6 @@ FormAutoComplete.prototype = {
|
||||
_boundaryWeight : 25,
|
||||
_prefixWeight : 5,
|
||||
|
||||
// Only one query is performed at a time, which will be stored in _pendingQuery
|
||||
// while the query is being performed. It will be cleared when the query finishes,
|
||||
// is cancelled, or an error occurs. If a new query occurs while one is already
|
||||
// pending, the existing one is cancelled. The pending query will be an
|
||||
// mozIStoragePendingStatement object.
|
||||
_pendingQuery : null,
|
||||
|
||||
init : function() {
|
||||
// Preferences. Add observer so we get notified of changes.
|
||||
this._prefBranch = Services.prefs.getBranch("browser.formfill.");
|
||||
@ -54,6 +50,10 @@ FormAutoComplete.prototype = {
|
||||
this._maxTimeGroupings = this._prefBranch.getIntPref("maxTimeGroupings");
|
||||
this._timeGroupingSize = this._prefBranch.getIntPref("timeGroupingSize") * 1000 * 1000;
|
||||
this._expireDays = this._prefBranch.getIntPref("expire_days");
|
||||
|
||||
this._dbStmts = {};
|
||||
|
||||
Services.obs.addObserver(this.observer, "profile-before-change", true);
|
||||
},
|
||||
|
||||
observer : {
|
||||
@ -96,6 +96,12 @@ FormAutoComplete.prototype = {
|
||||
default:
|
||||
self.log("Oops! Pref not handled, change ignored.");
|
||||
}
|
||||
} else if (topic == "profile-before-change") {
|
||||
for each (let stmt in self._dbStmts) {
|
||||
stmt.finalize();
|
||||
}
|
||||
self._dbStmts = {};
|
||||
self.__formHistory = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -115,64 +121,33 @@ FormAutoComplete.prototype = {
|
||||
},
|
||||
|
||||
|
||||
autoCompleteSearch : function (aInputName, aUntrimmedSearchString, aField, aPreviousResult) {
|
||||
Deprecated.warning("nsIFormAutoComplete::autoCompleteSearch is deprecated", "https://bugzilla.mozilla.org/show_bug.cgi?id=697377");
|
||||
|
||||
let result = null;
|
||||
let listener = {
|
||||
onSearchCompletion: function (r) result = r
|
||||
};
|
||||
this._autoCompleteSearchShared(aInputName, aUntrimmedSearchString, aField, aPreviousResult, listener);
|
||||
|
||||
// Just wait for the result to to be available.
|
||||
let thread = Components.classes["@mozilla.org/thread-manager;1"].getService().currentThread;
|
||||
while (!result && this._pendingQuery) {
|
||||
thread.processNextEvent(true);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
autoCompleteSearchAsync : function (aInputName, aUntrimmedSearchString, aField, aPreviousResult, aListener) {
|
||||
this._autoCompleteSearchShared(aInputName, aUntrimmedSearchString, aField, aPreviousResult, aListener);
|
||||
},
|
||||
|
||||
/*
|
||||
* autoCompleteSearchShared
|
||||
* autoCompleteSearch
|
||||
*
|
||||
* aInputName -- |name| attribute from the form input being autocompleted.
|
||||
* aUntrimmedSearchString -- current value of the input
|
||||
* aField -- nsIDOMHTMLInputElement being autocompleted (may be null if from chrome)
|
||||
* aPreviousResult -- previous search result, if any.
|
||||
* aListener -- nsIFormAutoCompleteObserver that listens for the nsIAutoCompleteResult
|
||||
* that may be returned asynchronously.
|
||||
*
|
||||
* Returns: an nsIAutoCompleteResult
|
||||
*/
|
||||
_autoCompleteSearchShared : function (aInputName, aUntrimmedSearchString, aField, aPreviousResult, aListener) {
|
||||
autoCompleteSearch : function (aInputName, aUntrimmedSearchString, aField, aPreviousResult) {
|
||||
function sortBytotalScore (a, b) {
|
||||
return b.totalScore - a.totalScore;
|
||||
}
|
||||
|
||||
let result = null;
|
||||
if (!this._enabled) {
|
||||
result = new FormAutoCompleteResult(FormHistory, [], aInputName, aUntrimmedSearchString);
|
||||
if (aListener) {
|
||||
aListener.onSearchCompletion(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!this._enabled)
|
||||
return null;
|
||||
|
||||
// don't allow form inputs (aField != null) to get results from search bar history
|
||||
if (aInputName == 'searchbar-history' && aField) {
|
||||
this.log('autoCompleteSearch for input name "' + aInputName + '" is denied');
|
||||
result = new FormAutoCompleteResult(FormHistory, [], aInputName, aUntrimmedSearchString);
|
||||
if (aListener) {
|
||||
aListener.onSearchCompletion(result);
|
||||
}
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
this.log("AutoCompleteSearch invoked. Search is: " + aUntrimmedSearchString);
|
||||
let searchString = aUntrimmedSearchString.trim().toLowerCase();
|
||||
let result = null;
|
||||
|
||||
// reuse previous results if:
|
||||
// a) length greater than one character (others searches are special cases) AND
|
||||
@ -201,80 +176,145 @@ FormAutoComplete.prototype = {
|
||||
}
|
||||
filteredEntries.sort(sortBytotalScore);
|
||||
result.wrappedJSObject.entries = filteredEntries;
|
||||
|
||||
if (aListener) {
|
||||
aListener.onSearchCompletion(result);
|
||||
}
|
||||
} else {
|
||||
this.log("Creating new autocomplete search result.");
|
||||
|
||||
// Start with an empty list.
|
||||
result = new FormAutoCompleteResult(FormHistory, [], aInputName, aUntrimmedSearchString);
|
||||
|
||||
let processEntry = function(aEntries) {
|
||||
if (aField && aField.maxLength > -1) {
|
||||
result.entries =
|
||||
aEntries.filter(function (el) { return el.text.length <= aField.maxLength; });
|
||||
} else {
|
||||
result.entries = aEntries;
|
||||
}
|
||||
|
||||
if (aListener) {
|
||||
aListener.onSearchCompletion(result);
|
||||
}
|
||||
let entries = this.getAutoCompleteValues(aInputName, searchString);
|
||||
result = new FormAutoCompleteResult(this._formHistory, entries, aInputName, aUntrimmedSearchString);
|
||||
if (aField && aField.maxLength > -1) {
|
||||
let original = result.wrappedJSObject.entries;
|
||||
let filtered = original.filter(function (el) el.text.length <= this.maxLength, aField);
|
||||
result.wrappedJSObject.entries = filtered;
|
||||
}
|
||||
|
||||
this.getAutoCompleteValues(aInputName, searchString, processEntry);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
stopAutoCompleteSearch : function () {
|
||||
if (this._pendingQuery) {
|
||||
this._pendingQuery.cancel();
|
||||
this._pendingQuery = null;
|
||||
}
|
||||
},
|
||||
getAutoCompleteValues : function (fieldName, searchString) {
|
||||
let values = [];
|
||||
let searchTokens;
|
||||
|
||||
/*
|
||||
* Get the values for an autocomplete list given a search string.
|
||||
*
|
||||
* fieldName - fieldname field within form history (the form input name)
|
||||
* searchString - string to search for
|
||||
* callback - called when the values are available. Passed an array of objects,
|
||||
* containing properties for each result. The callback is only called
|
||||
* when successful.
|
||||
*/
|
||||
getAutoCompleteValues : function (fieldName, searchString, callback) {
|
||||
let params = {
|
||||
agedWeight: this._agedWeight,
|
||||
bucketSize: this._bucketSize,
|
||||
expiryDate: 1000 * (Date.now() - this._expireDays * 24 * 60 * 60 * 1000),
|
||||
fieldname: fieldName,
|
||||
maxTimeGroupings: this._maxTimeGroupings,
|
||||
timeGroupingSize: this._timeGroupingSize,
|
||||
prefixWeight: this._prefixWeight,
|
||||
boundaryWeight: this._boundaryWeight
|
||||
now: Date.now() * 1000, // convert from ms to microseconds
|
||||
timeGroupingSize: this._timeGroupingSize
|
||||
}
|
||||
|
||||
this.stopAutoCompleteSearch();
|
||||
// only do substring matching when more than one character is typed
|
||||
let where = ""
|
||||
let boundaryCalc = "";
|
||||
if (searchString.length > 1) {
|
||||
searchTokens = searchString.split(/\s+/);
|
||||
|
||||
let results = [];
|
||||
let processResults = {
|
||||
handleResult: aResult => {
|
||||
results.push(aResult);
|
||||
},
|
||||
handleError: aError => {
|
||||
this.log("getAutocompleteValues failed: " + aError.message);
|
||||
},
|
||||
handleCompletion: aReason => {
|
||||
this._pendingQuery = null;
|
||||
if (!aReason) {
|
||||
callback(results);
|
||||
// build up the word boundary and prefix match bonus calculation
|
||||
boundaryCalc = "MAX(1, :prefixWeight * (value LIKE :valuePrefix ESCAPE '/') + (";
|
||||
// for each word, calculate word boundary weights for the SELECT clause and
|
||||
// add word to the WHERE clause of the query
|
||||
let tokenCalc = [];
|
||||
for (let i = 0; i < searchTokens.length; i++) {
|
||||
tokenCalc.push("(value LIKE :tokenBegin" + i + " ESCAPE '/') + " +
|
||||
"(value LIKE :tokenBoundary" + i + " ESCAPE '/')");
|
||||
where += "AND (value LIKE :tokenContains" + i + " ESCAPE '/') ";
|
||||
}
|
||||
}
|
||||
};
|
||||
// add more weight if we have a traditional prefix match and
|
||||
// multiply boundary bonuses by boundary weight
|
||||
boundaryCalc += tokenCalc.join(" + ") + ") * :boundaryWeight)";
|
||||
params.prefixWeight = this._prefixWeight;
|
||||
params.boundaryWeight = this._boundaryWeight;
|
||||
} else if (searchString.length == 1) {
|
||||
where = "AND (value LIKE :valuePrefix ESCAPE '/') ";
|
||||
boundaryCalc = "1";
|
||||
} else {
|
||||
where = "";
|
||||
boundaryCalc = "1";
|
||||
}
|
||||
/* Three factors in the frecency calculation for an entry (in order of use in calculation):
|
||||
* 1) average number of times used - items used more are ranked higher
|
||||
* 2) how recently it was last used - items used recently are ranked higher
|
||||
* 3) additional weight for aged entries surviving expiry - these entries are relevant
|
||||
* since they have been used multiple times over a large time span so rank them higher
|
||||
* The score is then divided by the bucket size and we round the result so that entries
|
||||
* with a very similar frecency are bucketed together with an alphabetical sort. This is
|
||||
* to reduce the amount of moving around by entries while typing.
|
||||
*/
|
||||
|
||||
this._pendingQuery = FormHistory.getAutoCompleteResults(searchString, params, processResults);
|
||||
let query = "/* do not warn (bug 496471): can't use an index */ " +
|
||||
"SELECT value, " +
|
||||
"ROUND( " +
|
||||
"timesUsed / MAX(1.0, (lastUsed - firstUsed) / :timeGroupingSize) * " +
|
||||
"MAX(1.0, :maxTimeGroupings - (:now - lastUsed) / :timeGroupingSize) * "+
|
||||
"MAX(1.0, :agedWeight * (firstUsed < :expiryDate)) / " +
|
||||
":bucketSize "+
|
||||
", 3) AS frecency, " +
|
||||
boundaryCalc + " AS boundaryBonuses " +
|
||||
"FROM moz_formhistory " +
|
||||
"WHERE fieldname=:fieldname " + where +
|
||||
"ORDER BY ROUND(frecency * boundaryBonuses) DESC, UPPER(value) ASC";
|
||||
|
||||
let stmt;
|
||||
try {
|
||||
stmt = this._dbCreateStatement(query, params);
|
||||
|
||||
// Chicken and egg problem: Need the statement to escape the params we
|
||||
// pass to the function that gives us the statement. So, fix it up now.
|
||||
if (searchString.length >= 1)
|
||||
stmt.params.valuePrefix = stmt.escapeStringForLIKE(searchString, "/") + "%";
|
||||
if (searchString.length > 1) {
|
||||
for (let i = 0; i < searchTokens.length; i++) {
|
||||
let escapedToken = stmt.escapeStringForLIKE(searchTokens[i], "/");
|
||||
stmt.params["tokenBegin" + i] = escapedToken + "%";
|
||||
stmt.params["tokenBoundary" + i] = "% " + escapedToken + "%";
|
||||
stmt.params["tokenContains" + i] = "%" + escapedToken + "%";
|
||||
}
|
||||
} else {
|
||||
// no addional params need to be substituted into the query when the
|
||||
// length is zero or one
|
||||
}
|
||||
|
||||
while (stmt.executeStep()) {
|
||||
let entry = {
|
||||
text: stmt.row.value,
|
||||
textLowerCase: stmt.row.value.toLowerCase(),
|
||||
frecency: stmt.row.frecency,
|
||||
totalScore: Math.round(stmt.row.frecency * stmt.row.boundaryBonuses)
|
||||
}
|
||||
values.push(entry);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
this.log("getValues failed: " + e.name + " : " + e.message);
|
||||
throw "DB failed getting form autocomplete values";
|
||||
} finally {
|
||||
if (stmt) {
|
||||
stmt.reset();
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
},
|
||||
|
||||
|
||||
_dbStmts : null,
|
||||
|
||||
_dbCreateStatement : function (query, params) {
|
||||
let stmt = this._dbStmts[query];
|
||||
// Memoize the statements
|
||||
if (!stmt) {
|
||||
this.log("Creating new statement for query: " + query);
|
||||
stmt = this._formHistory.DBConnection.createStatement(query);
|
||||
this._dbStmts[query] = stmt;
|
||||
}
|
||||
// Replace parameters, must be done 1 at a time
|
||||
if (params) {
|
||||
let stmtparams = stmt.params;
|
||||
for (let i in params)
|
||||
stmtparams[i] = params[i];
|
||||
}
|
||||
return stmt;
|
||||
},
|
||||
|
||||
/*
|
||||
@ -382,11 +422,8 @@ FormAutoCompleteResult.prototype = {
|
||||
|
||||
let [removedEntry] = this.entries.splice(index, 1);
|
||||
|
||||
if (removeFromDB) {
|
||||
this.formHistory.update({ op: "remove",
|
||||
fieldname: this.fieldName,
|
||||
value: removedEntry.text });
|
||||
}
|
||||
if (removeFromDB)
|
||||
this.formHistory.removeEntry(this.fieldName, removedEntry.text);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -36,12 +36,11 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS6(nsFormFillController,
|
||||
NS_IMPL_ISUPPORTS5(nsFormFillController,
|
||||
nsIFormFillController,
|
||||
nsIAutoCompleteInput,
|
||||
nsIAutoCompleteSearch,
|
||||
nsIDOMEventListener,
|
||||
nsIFormAutoCompleteObserver,
|
||||
nsIMutationObserver)
|
||||
|
||||
nsFormFillController::nsFormFillController() :
|
||||
@ -601,15 +600,11 @@ nsFormFillController::StartSearch(const nsAString &aSearchString, const nsAStrin
|
||||
// XXX aPreviousResult shouldn't ever be a historyResult type, since we're not letting
|
||||
// satchel manage the field?
|
||||
rv = mLoginManager->AutoCompleteSearch(aSearchString,
|
||||
aPreviousResult,
|
||||
mFocusedInput,
|
||||
getter_AddRefs(result));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aListener) {
|
||||
aListener->OnSearchResult(this, result);
|
||||
}
|
||||
aPreviousResult,
|
||||
mFocusedInput,
|
||||
getter_AddRefs(result));
|
||||
} else {
|
||||
mLastListener = aListener;
|
||||
nsCOMPtr<nsIAutoCompleteResult> formHistoryResult;
|
||||
|
||||
// It appears that mFocusedInput is always null when we are focusing a XUL
|
||||
// element. Scary :)
|
||||
@ -618,65 +613,48 @@ nsFormFillController::StartSearch(const nsAString &aSearchString, const nsAStrin
|
||||
do_GetService("@mozilla.org/satchel/form-autocomplete;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
formAutoComplete->AutoCompleteSearchAsync(aSearchParam,
|
||||
rv = formAutoComplete->AutoCompleteSearch(aSearchParam,
|
||||
aSearchString,
|
||||
mFocusedInput,
|
||||
aPreviousResult,
|
||||
this);
|
||||
mLastFormAutoComplete = formAutoComplete;
|
||||
} else {
|
||||
mLastSearchString = aSearchString;
|
||||
getter_AddRefs(formHistoryResult));
|
||||
|
||||
// Even if autocomplete is disabled, handle the inputlist anyway as that was
|
||||
// specifically requested by the page. This is so a field can have the default
|
||||
// autocomplete disabled and replaced with a custom inputlist autocomplete.
|
||||
return PerformInputListAutoComplete(aPreviousResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
mLastSearchResult = formHistoryResult;
|
||||
mLastListener = aListener;
|
||||
mLastSearchString = aSearchString;
|
||||
|
||||
nsresult
|
||||
nsFormFillController::PerformInputListAutoComplete(nsIAutoCompleteResult* aPreviousResult)
|
||||
{
|
||||
// If an <input> is focused, check if it has a list="<datalist>" which can
|
||||
// provide the list of suggestions.
|
||||
nsCOMPtr <nsIInputListAutoComplete> inputListAutoComplete =
|
||||
do_GetService("@mozilla.org/satchel/inputlist-autocomplete;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIAutoCompleteResult> result;
|
||||
rv = inputListAutoComplete->AutoCompleteSearch(formHistoryResult,
|
||||
aSearchString,
|
||||
mFocusedInput,
|
||||
getter_AddRefs(result));
|
||||
|
||||
nsCOMPtr <nsIInputListAutoComplete> inputListAutoComplete =
|
||||
do_GetService("@mozilla.org/satchel/inputlist-autocomplete;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = inputListAutoComplete->AutoCompleteSearch(aPreviousResult,
|
||||
mLastSearchString,
|
||||
mFocusedInput,
|
||||
getter_AddRefs(result));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (mFocusedInput) {
|
||||
nsCOMPtr<nsIDOMHTMLElement> list;
|
||||
mFocusedInput->GetList(getter_AddRefs(list));
|
||||
|
||||
if (mFocusedInput) {
|
||||
nsCOMPtr<nsIDOMHTMLElement> list;
|
||||
mFocusedInput->GetList(getter_AddRefs(list));
|
||||
|
||||
// Add a mutation observer to check for changes to the items in the <datalist>
|
||||
// and update the suggestions accordingly.
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(list);
|
||||
if (mListNode != node) {
|
||||
if (mListNode) {
|
||||
mListNode->RemoveMutationObserver(this);
|
||||
mListNode = nullptr;
|
||||
}
|
||||
if (node) {
|
||||
node->AddMutationObserverUnlessExists(this);
|
||||
mListNode = node;
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(list);
|
||||
if (mListNode != node) {
|
||||
if (mListNode) {
|
||||
mListNode->RemoveMutationObserver(this);
|
||||
mListNode = nullptr;
|
||||
}
|
||||
if (node) {
|
||||
node->AddMutationObserverUnlessExists(this);
|
||||
mListNode = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mLastListener) {
|
||||
mLastListener->OnSearchResult(this, result);
|
||||
}
|
||||
aListener->OnSearchResult(this, result);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -729,31 +707,9 @@ void nsFormFillController::RevalidateDataList()
|
||||
NS_IMETHODIMP
|
||||
nsFormFillController::StopSearch()
|
||||
{
|
||||
// Make sure to stop and clear this, otherwise the controller will prevent
|
||||
// mLastFormAutoComplete from being deleted.
|
||||
if (mLastFormAutoComplete) {
|
||||
mLastFormAutoComplete->StopAutoCompleteSearch();
|
||||
mLastFormAutoComplete = nullptr;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//// nsIFormAutoCompleteObserver
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFormFillController::OnSearchCompletion(nsIAutoCompleteResult *aResult)
|
||||
{
|
||||
nsCOMPtr<nsIAutoCompleteResult> resultParam = do_QueryInterface(aResult);
|
||||
|
||||
nsAutoString searchString;
|
||||
resultParam->GetSearchString(searchString);
|
||||
mLastSearchResult = aResult;
|
||||
mLastSearchString = searchString;
|
||||
|
||||
return PerformInputListAutoComplete(resultParam);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//// nsIDOMEventListener
|
||||
|
||||
@ -1222,3 +1178,4 @@ static const mozilla::Module kSatchelModule = {
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(satchel) = &kSatchelModule;
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "nsIAutoCompleteSearch.h"
|
||||
#include "nsIAutoCompleteController.h"
|
||||
#include "nsIAutoCompletePopup.h"
|
||||
#include "nsIFormAutoComplete.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDataHashtable.h"
|
||||
@ -34,7 +33,6 @@ class nsFormFillController : public nsIFormFillController,
|
||||
public nsIAutoCompleteInput,
|
||||
public nsIAutoCompleteSearch,
|
||||
public nsIDOMEventListener,
|
||||
public nsIFormAutoCompleteObserver,
|
||||
public nsIMutationObserver
|
||||
{
|
||||
public:
|
||||
@ -42,7 +40,6 @@ public:
|
||||
NS_DECL_NSIFORMFILLCONTROLLER
|
||||
NS_DECL_NSIAUTOCOMPLETESEARCH
|
||||
NS_DECL_NSIAUTOCOMPLETEINPUT
|
||||
NS_DECL_NSIFORMAUTOCOMPLETEOBSERVER
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
NS_DECL_NSIMUTATIONOBSERVER
|
||||
|
||||
@ -63,8 +60,6 @@ protected:
|
||||
void StartControllingInput(nsIDOMHTMLInputElement *aInput);
|
||||
void StopControllingInput();
|
||||
|
||||
nsresult PerformInputListAutoComplete(nsIAutoCompleteResult* aPreviousResult);
|
||||
|
||||
void RevalidateDataList();
|
||||
bool RowMatch(nsFormHistory *aHistory, uint32_t aIndex, const nsAString &aInputName, const nsAString &aInputValue);
|
||||
|
||||
@ -84,9 +79,6 @@ protected:
|
||||
nsCOMPtr<nsILoginManager> mLoginManager;
|
||||
nsIDOMHTMLInputElement* mFocusedInput;
|
||||
nsINode* mFocusedInputNode;
|
||||
|
||||
// mListNode is a <datalist> element which, is set, has the form fill controller
|
||||
// as a mutation observer for it.
|
||||
nsINode* mListNode;
|
||||
nsCOMPtr<nsIAutoCompletePopup> mFocusedPopup;
|
||||
|
||||
@ -95,13 +87,7 @@ protected:
|
||||
|
||||
//these are used to dynamically update the autocomplete
|
||||
nsCOMPtr<nsIAutoCompleteResult> mLastSearchResult;
|
||||
|
||||
// The observer passed to StartSearch. It will be notified when the search is
|
||||
// complete or the data from a datalist changes.
|
||||
nsCOMPtr<nsIAutoCompleteObserver> mLastListener;
|
||||
|
||||
// This is cleared by StopSearch().
|
||||
nsCOMPtr<nsIFormAutoComplete> mLastFormAutoComplete;
|
||||
nsString mLastSearchString;
|
||||
|
||||
nsDataHashtable<nsPtrHashKey<const nsINode>, bool> mPwmgrInputs;
|
||||
|
@ -27,6 +27,7 @@ FormHistory.prototype = {
|
||||
|
||||
debug : true,
|
||||
enabled : true,
|
||||
saveHttpsForms : true,
|
||||
|
||||
// The current database schema.
|
||||
dbSchema : {
|
||||
@ -81,14 +82,43 @@ FormHistory.prototype = {
|
||||
|
||||
|
||||
init : function init() {
|
||||
Services.prefs.addObserver("browser.formfill.", this, true);
|
||||
|
||||
this.updatePrefs();
|
||||
|
||||
this.dbStmts = {};
|
||||
|
||||
// Add observer
|
||||
this.messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Ci.nsIMessageListenerManager);
|
||||
this.messageManager.loadFrameScript("chrome://satchel/content/formSubmitListener.js", true);
|
||||
this.messageManager.addMessageListener("FormHistory:FormSubmitEntries", this);
|
||||
|
||||
// Add observers
|
||||
Services.obs.addObserver(this, "profile-before-change", true);
|
||||
Services.obs.addObserver(this, "idle-daily", true);
|
||||
Services.obs.addObserver(this, "formhistory-expire-now", true);
|
||||
},
|
||||
|
||||
/* ---- message listener ---- */
|
||||
|
||||
|
||||
receiveMessage: function receiveMessage(message) {
|
||||
// Open a transaction so multiple adds happen in one commit
|
||||
this.dbConnection.beginTransaction();
|
||||
|
||||
try {
|
||||
let entries = message.json;
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
this.addEntry(entries[i].name, entries[i].value);
|
||||
}
|
||||
} finally {
|
||||
// Don't need it to be atomic if there was an error. Commit what
|
||||
// we managed to put in the table.
|
||||
this.dbConnection.commitTransaction();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/* ---- nsIFormHistory2 interfaces ---- */
|
||||
|
||||
|
||||
@ -404,6 +434,10 @@ FormHistory.prototype = {
|
||||
case "nsPref:changed":
|
||||
this.updatePrefs();
|
||||
break;
|
||||
case "idle-daily":
|
||||
case "formhistory-expire-now":
|
||||
this.expireOldEntries();
|
||||
break;
|
||||
case "profile-before-change":
|
||||
this._dbClose(false);
|
||||
break;
|
||||
@ -535,9 +569,56 @@ FormHistory.prototype = {
|
||||
},
|
||||
|
||||
|
||||
expireOldEntries : function () {
|
||||
this.log("expireOldEntries");
|
||||
|
||||
// Determine how many days of history we're supposed to keep.
|
||||
let expireDays = 180;
|
||||
try {
|
||||
expireDays = Services.prefs.getIntPref("browser.formfill.expire_days");
|
||||
} catch (e) { /* ignore */ }
|
||||
|
||||
let expireTime = Date.now() - expireDays * DAY_IN_MS;
|
||||
expireTime *= 1000; // switch to microseconds
|
||||
|
||||
this.sendIntNotification("before-expireOldEntries", expireTime);
|
||||
|
||||
let beginningCount = this.countAllEntries();
|
||||
|
||||
// Purge the form history...
|
||||
let stmt;
|
||||
let query = "DELETE FROM moz_formhistory WHERE lastUsed <= :expireTime";
|
||||
let params = { expireTime : expireTime };
|
||||
|
||||
try {
|
||||
stmt = this.dbCreateStatement(query, params);
|
||||
stmt.execute();
|
||||
} catch (e) {
|
||||
this.log("expireOldEntries failed: " + e);
|
||||
throw e;
|
||||
} finally {
|
||||
if (stmt) {
|
||||
stmt.reset();
|
||||
}
|
||||
}
|
||||
|
||||
let endingCount = this.countAllEntries();
|
||||
|
||||
// If we expired a large batch of entries, shrink the DB to reclaim wasted
|
||||
// space. This is expected to happen when entries predating timestamps
|
||||
// (added in the v.1 schema) expire in mass, 180 days after the DB was
|
||||
// upgraded -- entries not used since then expire all at once.
|
||||
if (beginningCount - endingCount > 500)
|
||||
this.dbConnection.executeSimpleSQL("VACUUM");
|
||||
|
||||
this.sendIntNotification("expireOldEntries", expireTime);
|
||||
},
|
||||
|
||||
|
||||
updatePrefs : function () {
|
||||
this.debug = Services.prefs.getBoolPref("browser.formfill.debug");
|
||||
this.enabled = Services.prefs.getBoolPref("browser.formfill.enable");
|
||||
this.saveHttpsForms = Services.prefs.getBoolPref("browser.formfill.saveHttpsForms");
|
||||
},
|
||||
|
||||
//**************************************************************************//
|
||||
|
@ -6,47 +6,17 @@
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAutoCompleteResult;
|
||||
interface nsIFormAutoCompleteObserver;
|
||||
interface nsIDOMHTMLInputElement;
|
||||
|
||||
[scriptable, uuid(c079f18f-40ab-409d-800e-878889b83b58)]
|
||||
[scriptable, uuid(997c0c05-5d1d-47e5-9cbc-765c0b8ec699)]
|
||||
|
||||
interface nsIFormAutoComplete: nsISupports {
|
||||
|
||||
/**
|
||||
* Generate results for a form input autocomplete menu synchronously.
|
||||
* This method is deprecated in favour of autoCompleteSearchAsync.
|
||||
* Generate results for a form input autocomplete menu.
|
||||
*/
|
||||
nsIAutoCompleteResult autoCompleteSearch(in AString aInputName,
|
||||
in AString aSearchString,
|
||||
in nsIDOMHTMLInputElement aField,
|
||||
in nsIAutoCompleteResult aPreviousResult);
|
||||
|
||||
/**
|
||||
* Generate results for a form input autocomplete menu asynchronously.
|
||||
*/
|
||||
void autoCompleteSearchAsync(in AString aInputName,
|
||||
in AString aSearchString,
|
||||
in nsIDOMHTMLInputElement aField,
|
||||
in nsIAutoCompleteResult aPreviousResult,
|
||||
in nsIFormAutoCompleteObserver aListener);
|
||||
|
||||
/**
|
||||
* If a search is in progress, stop it. Otherwise, do nothing. This is used
|
||||
* to cancel an existing search, for example, in preparation for a new search.
|
||||
*/
|
||||
void stopAutoCompleteSearch();
|
||||
};
|
||||
|
||||
[scriptable, function, uuid(604419ab-55a0-4831-9eca-1b9e67cc4751)]
|
||||
interface nsIFormAutoCompleteObserver : nsISupports
|
||||
{
|
||||
/*
|
||||
* Called when a search is complete and the results are ready even if the
|
||||
* result set is empty. If the search is cancelled or a new search is
|
||||
* started, this is not called.
|
||||
*
|
||||
* @param result - The search result object
|
||||
*/
|
||||
void onSearchCompletion(in nsIAutoCompleteResult result);
|
||||
nsIAutoCompleteResult autoCompleteSearch(
|
||||
in AString aInputName,
|
||||
in AString aSearchString,
|
||||
in nsIDOMHTMLInputElement aField,
|
||||
in nsIAutoCompleteResult aPreviousResult);
|
||||
};
|
||||
|
@ -4,7 +4,3 @@ component {c11c21b2-71c9-4f87-a0f8-5e13f50495fd} nsFormAutoComplete.js
|
||||
contract @mozilla.org/satchel/form-autocomplete;1 {c11c21b2-71c9-4f87-a0f8-5e13f50495fd}
|
||||
component {bf1e01d0-953e-11df-981c-0800200c9a66} nsInputListAutoComplete.js
|
||||
contract @mozilla.org/satchel/inputlist-autocomplete;1 {bf1e01d0-953e-11df-981c-0800200c9a66}
|
||||
component {3a0012eb-007f-4bb8-aa81-a07385f77a25} FormHistoryStartup.js
|
||||
contract @mozilla.org/satchel/form-history-startup;1 {3a0012eb-007f-4bb8-aa81-a07385f77a25}
|
||||
category profile-after-change formHistoryStartup @mozilla.org/satchel/form-history-startup;1
|
||||
category idle-daily formHistoryStartup @mozilla.org/satchel/form-history-startup;1
|
||||
|
@ -2,8 +2,6 @@
|
||||
* 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/. */
|
||||
|
||||
let FormHistory = (Components.utils.import("resource://gre/modules/FormHistory.jsm", {})).FormHistory;
|
||||
|
||||
/** Test for Bug 472396 **/
|
||||
function test() {
|
||||
// initialization
|
||||
@ -11,40 +9,23 @@ function test() {
|
||||
let windowsToClose = [];
|
||||
let testURI =
|
||||
"http://example.com/tests/toolkit/components/satchel/test/subtst_privbrowsing.html";
|
||||
let formHistory = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
function doTest(aIsPrivateMode, aShouldValueExist, aWindow, aCallback) {
|
||||
aWindow.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
|
||||
aWindow.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
|
||||
|
||||
let checks = 0;
|
||||
function doneCheck() {
|
||||
checks++;
|
||||
if (checks == 2) {
|
||||
executeSoon(aCallback);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the second load of the page to call the callback,
|
||||
// because the first load submits the form and the page reloads after
|
||||
// the form submission.
|
||||
aWindow.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
|
||||
aWindow.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
|
||||
doneCheck();
|
||||
executeSoon(aCallback);
|
||||
}, true);
|
||||
|
||||
let count = 0;
|
||||
FormHistory.count({ fieldname: "field", value: "value" },
|
||||
{ handleResult: function(result) {
|
||||
count = result;
|
||||
},
|
||||
handleError: function (error) {
|
||||
do_throw("Error occurred searching form history: " + error);
|
||||
},
|
||||
handleCompletion: function(num) {
|
||||
is(count >= 1, aShouldValueExist, "Checking value exists in form history");
|
||||
doneCheck();
|
||||
}
|
||||
});
|
||||
is(formHistory.entryExists("field", "value"), aShouldValueExist,
|
||||
"Checking value exists in form history");
|
||||
}, true);
|
||||
|
||||
aWindow.gBrowser.selectedBrowser.loadURI(testURI);
|
||||
|
@ -71,7 +71,9 @@ function getAutocompletePopup() {
|
||||
|
||||
|
||||
function cleanUpFormHist() {
|
||||
SpecialPowers.formHistory.update({ op : "remove" });
|
||||
var formhist = SpecialPowers.Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(SpecialPowers.Ci.nsIFormHistory2);
|
||||
formhist.removeAllEntries();
|
||||
}
|
||||
cleanUpFormHist();
|
||||
|
||||
@ -88,7 +90,7 @@ var checkObserver = {
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
if (data != "formhistory-add" && data != "formhistory-update")
|
||||
if (data != "addEntry" && data != "modifyEntry")
|
||||
return;
|
||||
ok(this.verifyStack.length > 0, "checking if saved form data was expected");
|
||||
|
||||
@ -102,16 +104,13 @@ var checkObserver = {
|
||||
// - if there are too many messages, test will error out here
|
||||
//
|
||||
var expected = this.verifyStack.shift();
|
||||
ok(fh.entryExists(expected.name, expected.value), expected.message);
|
||||
|
||||
countEntries(expected.name, expected.value,
|
||||
function(num) {
|
||||
ok(num > 0, expected.message);
|
||||
if (checkObserver.verifyStack.length == 0) {
|
||||
var callback = checkObserver.callback;
|
||||
checkObserver.callback = null;
|
||||
callback();
|
||||
}
|
||||
});
|
||||
if (this.verifyStack.length == 0) {
|
||||
var callback = this.callback;
|
||||
this.callback = null;
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -132,30 +131,3 @@ function getFormSubmitButton(formNum) {
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
// Count the number of entries with the given name and value, and call then(number)
|
||||
// when done. If name or value is null, then the value of that field does not matter.
|
||||
function countEntries(name, value, then) {
|
||||
var obj = {};
|
||||
if (name !== null)
|
||||
obj.fieldname = name;
|
||||
if (value !== null)
|
||||
obj.value = value;
|
||||
|
||||
var count = 0;
|
||||
SpecialPowers.formHistory.count(obj, { handleResult: function (result) { count = result },
|
||||
handleError: function (error) {
|
||||
do_throw("Error occurred searching form history: " + error);
|
||||
},
|
||||
handleCompletion: function (reason) { if (!reason) then(count); }
|
||||
});
|
||||
}
|
||||
|
||||
// Wrapper around FormHistory.update which handles errors. Calls then() when done.
|
||||
function updateFormHistory(changes, then) {
|
||||
SpecialPowers.formHistory.update(changes, { handleError: function (error) {
|
||||
do_throw("Error occurred updating form history: " + error);
|
||||
},
|
||||
handleCompletion: function (reason) { if (!reason) then(); },
|
||||
});
|
||||
}
|
||||
|
@ -36,20 +36,20 @@ autocompletePopup.style.direction = "ltr";
|
||||
var input = $_(1, "field1");
|
||||
|
||||
// Get the form history service
|
||||
function setupFormHistory(aCallback) {
|
||||
updateFormHistory([
|
||||
{ op : "remove" },
|
||||
{ op : "add", fieldname : "field1", value : "value1" },
|
||||
{ op : "add", fieldname : "field1", value : "value2" },
|
||||
{ op : "add", fieldname : "field1", value : "value3" },
|
||||
{ op : "add", fieldname : "field1", value : "value4" },
|
||||
{ op : "add", fieldname : "field1", value : "value5" },
|
||||
{ op : "add", fieldname : "field1", value : "value6" },
|
||||
{ op : "add", fieldname : "field1", value : "value7" },
|
||||
{ op : "add", fieldname : "field1", value : "value8" },
|
||||
{ op : "add", fieldname : "field1", value : "value9" },
|
||||
], aCallback);
|
||||
}
|
||||
var fh = SpecialPowers.Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(SpecialPowers.Ci.nsIFormHistory2);
|
||||
ok(fh != null, "got form history service");
|
||||
|
||||
fh.removeAllEntries();
|
||||
fh.addEntry("field1", "value1");
|
||||
fh.addEntry("field1", "value2");
|
||||
fh.addEntry("field1", "value3");
|
||||
fh.addEntry("field1", "value4");
|
||||
fh.addEntry("field1", "value5");
|
||||
fh.addEntry("field1", "value6");
|
||||
fh.addEntry("field1", "value7");
|
||||
fh.addEntry("field1", "value8");
|
||||
fh.addEntry("field1", "value9");
|
||||
|
||||
function checkForm(expectedValue) {
|
||||
var formID = input.parentNode.id;
|
||||
@ -117,29 +117,6 @@ function doClickUnprivileged() {
|
||||
input.dispatchEvent(ckEvent);
|
||||
}
|
||||
|
||||
var testNum = 0;
|
||||
var expectingPopup = false;
|
||||
|
||||
function expectPopup()
|
||||
{
|
||||
info("expecting popup for test " + testNum);
|
||||
expectingPopup = true;
|
||||
}
|
||||
|
||||
function popupShownListener()
|
||||
{
|
||||
info("popup shown for test " + testNum);
|
||||
if (expectingPopup) {
|
||||
expectingPopup = false;
|
||||
SimpleTest.executeSoon(runTest);
|
||||
}
|
||||
else {
|
||||
ok(false, "Autocomplete popup not expected" + testNum);
|
||||
}
|
||||
}
|
||||
|
||||
SpecialPowers.addAutoCompletePopupEventListener(window, "popupshown", popupShownListener);
|
||||
|
||||
/*
|
||||
* Main section of test...
|
||||
*
|
||||
@ -148,9 +125,7 @@ SpecialPowers.addAutoCompletePopupEventListener(window, "popupshown", popupShown
|
||||
* setTimeout() calls. The case statements are executed in order, one per
|
||||
* timeout.
|
||||
*/
|
||||
function runTest() {
|
||||
testNum++;
|
||||
|
||||
function runTest(testNum) {
|
||||
ok(true, "Starting test #" + testNum);
|
||||
|
||||
switch(testNum) {
|
||||
@ -243,9 +218,7 @@ function runTest() {
|
||||
// We're privileged for this test, so open the popup.
|
||||
checkPopupOpen(false);
|
||||
checkForm("");
|
||||
expectPopup();
|
||||
doKey("down");
|
||||
return;
|
||||
break;
|
||||
case 21:
|
||||
checkPopupOpen(true, -1);
|
||||
@ -363,22 +336,20 @@ function runTest() {
|
||||
checkForm("");
|
||||
is(autocompletePopup.style.direction, "rtl", "direction should have been changed from ltr to rtl");
|
||||
|
||||
SpecialPowers.removeAutoCompletePopupEventListener(window, "popupshown", popupShownListener);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
|
||||
default:
|
||||
ok(false, "Unexpected invocation of test #" + testNum);
|
||||
SpecialPowers.removeAutoCompletePopupEventListener(window, "popupshown", popupShownListener);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleTest.executeSoon(runTest);
|
||||
setTimeout(runTest, 50, testNum + 1);
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
setupFormHistory(runTest);
|
||||
runTest(1);
|
||||
}
|
||||
|
||||
window.onload = startTest;
|
||||
|
@ -65,13 +65,13 @@ var input = $_(1, "field1");
|
||||
var rect = input.getBoundingClientRect();
|
||||
|
||||
// Get the form history service
|
||||
function setupFormHistory() {
|
||||
updateFormHistory([
|
||||
{ op : "remove" },
|
||||
{ op : "add", fieldname : "field1", value : "value1" },
|
||||
{ op : "add", fieldname : "field1", value : "value2" },
|
||||
], function() runTest(1));
|
||||
}
|
||||
var fh = SpecialPowers.Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(SpecialPowers.Ci.nsIFormHistory2);
|
||||
ok(fh != null, "got form history service");
|
||||
|
||||
fh.removeAllEntries();
|
||||
fh.addEntry("field1", "value1");
|
||||
fh.addEntry("field1", "value2");
|
||||
|
||||
function checkForm(expectedValue) {
|
||||
var formID = input.parentNode.id;
|
||||
@ -172,7 +172,7 @@ function runTest(testNum) {
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
setupFormHistory();
|
||||
runTest(1);
|
||||
}
|
||||
|
||||
window.onload = startTest;
|
||||
|
@ -11,9 +11,8 @@
|
||||
Form History test: form field autocomplete
|
||||
<p id="display"></p>
|
||||
|
||||
<!-- We presumably can't hide the content for this test. The large top padding is to allow
|
||||
listening for scrolls to occur. -->
|
||||
<div id="content" style="padding-top: 20000px;">
|
||||
<!-- we presumably can't hide the content for this test. -->
|
||||
<div id="content">
|
||||
|
||||
<!-- normal, basic form -->
|
||||
<form id="form1" onsubmit="return false;">
|
||||
@ -121,39 +120,40 @@ Form History test: form field autocomplete
|
||||
var input = $_(1, "field1");
|
||||
const shiftModifier = Event.SHIFT_MASK;
|
||||
|
||||
function setupFormHistory(aCallback) {
|
||||
updateFormHistory([
|
||||
{ op : "remove" },
|
||||
{ op : "add", fieldname : "field1", value : "value1" },
|
||||
{ op : "add", fieldname : "field1", value : "value2" },
|
||||
{ op : "add", fieldname : "field1", value : "value3" },
|
||||
{ op : "add", fieldname : "field1", value : "value4" },
|
||||
{ op : "add", fieldname : "field2", value : "value1" },
|
||||
{ op : "add", fieldname : "field3", value : "a" },
|
||||
{ op : "add", fieldname : "field3", value : "aa" },
|
||||
{ op : "add", fieldname : "field3", value : "aaz" },
|
||||
{ op : "add", fieldname : "field3", value : "aa\xe6" }, // 0xae == latin ae pair (0xc6 == AE)
|
||||
{ op : "add", fieldname : "field3", value : "az" },
|
||||
{ op : "add", fieldname : "field3", value : "z" },
|
||||
{ op : "add", fieldname : "field4", value : "a\xe6" },
|
||||
{ op : "add", fieldname : "field4", value : "aa a\xe6" },
|
||||
{ op : "add", fieldname : "field4", value : "aba\xe6" },
|
||||
{ op : "add", fieldname : "field4", value : "bc d\xe6" },
|
||||
{ op : "add", fieldname : "field5", value : "1" },
|
||||
{ op : "add", fieldname : "field5", value : "12" },
|
||||
{ op : "add", fieldname : "field5", value : "123" },
|
||||
{ op : "add", fieldname : "field5", value : "1234" },
|
||||
{ op : "add", fieldname : "field6", value : "value" },
|
||||
{ op : "add", fieldname : "field7", value : "value" },
|
||||
{ op : "add", fieldname : "field8", value : "value" },
|
||||
{ op : "add", fieldname : "field9", value : "value" },
|
||||
{ op : "add", fieldname : "field10", value : "42" },
|
||||
{ op : "add", fieldname : "field11", value : "2010-10-10" },
|
||||
{ op : "add", fieldname : "field12", value : "21:21" },
|
||||
{ op : "add", fieldname : "field13", value : "32" }, // not used, since type=range doesn't have a drop down menu
|
||||
{ op : "add", fieldname : "searchbar-history", value : "blacklist test" },
|
||||
], aCallback);
|
||||
}
|
||||
// Get the form history service
|
||||
var fh = SpecialPowers.Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(SpecialPowers.Ci.nsIFormHistory2);
|
||||
ok(fh != null, "got form history service");
|
||||
|
||||
fh.removeAllEntries();
|
||||
fh.addEntry("field1", "value1");
|
||||
fh.addEntry("field1", "value2");
|
||||
fh.addEntry("field1", "value3");
|
||||
fh.addEntry("field1", "value4");
|
||||
fh.addEntry("field2", "value1");
|
||||
fh.addEntry("field3", "a");
|
||||
fh.addEntry("field3", "aa");
|
||||
fh.addEntry("field3", "aaz");
|
||||
fh.addEntry("field3", "aa\xe6"); // 0xae == latin ae pair (0xc6 == AE)
|
||||
fh.addEntry("field3", "az");
|
||||
fh.addEntry("field3", "z");
|
||||
fh.addEntry("field4", "a\xe6");
|
||||
fh.addEntry("field4", "aa a\xe6");
|
||||
fh.addEntry("field4", "aba\xe6");
|
||||
fh.addEntry("field4", "bc d\xe6");
|
||||
fh.addEntry("field5", "1");
|
||||
fh.addEntry("field5", "12");
|
||||
fh.addEntry("field5", "123");
|
||||
fh.addEntry("field5", "1234");
|
||||
fh.addEntry("field6", "value");
|
||||
fh.addEntry("field7", "value");
|
||||
fh.addEntry("field8", "value");
|
||||
fh.addEntry("field9", "value");
|
||||
fh.addEntry("field10", "42");
|
||||
fh.addEntry("field11", "2010-10-10");
|
||||
fh.addEntry("field12", "21:21");
|
||||
fh.addEntry("field13", "32"); // not used, since type=range doesn't have a drop down menu
|
||||
fh.addEntry("searchbar-history", "blacklist test");
|
||||
|
||||
// All these non-implemeted types might need autocomplete tests in the future.
|
||||
var todoTypes = [ "datetime", "month", "week", "datetime-local", "color" ];
|
||||
@ -182,45 +182,16 @@ function checkForm(expectedValue) {
|
||||
is(input.value, expectedValue, "Checking " + formID + " input");
|
||||
}
|
||||
|
||||
var testNum = 0;
|
||||
var expectingPopup = false;
|
||||
|
||||
function expectPopup()
|
||||
{
|
||||
info("expecting popup for test " + testNum);
|
||||
expectingPopup = true;
|
||||
}
|
||||
|
||||
function popupShownListener()
|
||||
{
|
||||
info("popup shown for test " + testNum);
|
||||
if (expectingPopup) {
|
||||
expectingPopup = false;
|
||||
SimpleTest.executeSoon(runTest);
|
||||
}
|
||||
else {
|
||||
ok(false, "Autocomplete popup not expected during test " + testNum);
|
||||
}
|
||||
}
|
||||
|
||||
SpecialPowers.addAutoCompletePopupEventListener(window, "popupshown", popupShownListener);
|
||||
|
||||
/*
|
||||
* Main section of test...
|
||||
*
|
||||
* This is a bit hacky, as many operations happen asynchronously.
|
||||
* Various mechanisms call runTests as a result of operations:
|
||||
* - set expectingPopup to true, and the next test will occur when the autocomplete popup is shown
|
||||
* - call waitForMenuChange(x) to run the next test when the autocomplete popup to have x items in it
|
||||
* - addEntry calls runs the test when an entry has been added
|
||||
* - some tests scroll the window. This is because the form fill controller happens to scroll
|
||||
* the field into view near the end of the search, and there isn't any other good notification
|
||||
* to listen to for when the search is complete.
|
||||
* - some items still use setTimeout
|
||||
* This is a bit hacky, because the events are either being sent or
|
||||
* processed asynchronously, so we need to interrupt our flow with lots of
|
||||
* setTimeout() calls. The case statements are executed in order, one per
|
||||
* timeout.
|
||||
*/
|
||||
function runTest() {
|
||||
testNum++;
|
||||
|
||||
function runTest(testNum) {
|
||||
ok(true, "Starting test #" + testNum);
|
||||
|
||||
switch(testNum) {
|
||||
@ -228,13 +199,12 @@ function runTest() {
|
||||
// Make sure initial form is empty.
|
||||
checkForm("");
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
checkMenuEntries(["value1", "value2", "value3", "value4"], testNum);
|
||||
checkMenuEntries(["value1", "value2", "value3", "value4"]);
|
||||
// Check first entry
|
||||
doKey("down");
|
||||
checkForm(""); // value shouldn't update
|
||||
@ -242,7 +212,6 @@ function runTest() {
|
||||
checkForm("value1");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -255,7 +224,6 @@ function runTest() {
|
||||
checkForm("value2");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -269,7 +237,6 @@ function runTest() {
|
||||
checkForm("value3");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -284,7 +251,6 @@ function runTest() {
|
||||
checkForm("value4");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -301,7 +267,6 @@ function runTest() {
|
||||
checkForm("value1");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -313,7 +278,6 @@ function runTest() {
|
||||
checkForm("value4");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -327,7 +291,6 @@ function runTest() {
|
||||
checkForm("value4");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -346,7 +309,6 @@ function runTest() {
|
||||
checkForm("value4");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -358,7 +320,6 @@ function runTest() {
|
||||
checkForm("value1");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -370,7 +331,6 @@ function runTest() {
|
||||
checkForm("value1");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -384,7 +344,6 @@ function runTest() {
|
||||
checkForm("value1");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -397,16 +356,15 @@ function runTest() {
|
||||
checkForm("value4");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
testNum = 49;
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
testNum = 49;
|
||||
break;
|
||||
|
||||
/* Test removing entries from the dropdown */
|
||||
|
||||
case 50:
|
||||
checkMenuEntries(["value1", "value2", "value3", "value4"], testNum);
|
||||
checkMenuEntries(["value1", "value2", "value3", "value4"]);
|
||||
// Delete the first entry (of 4)
|
||||
setForm("value");
|
||||
doKey("down");
|
||||
@ -420,144 +378,95 @@ function runTest() {
|
||||
|
||||
// This tests that on OS X shift-backspace didn't delete the last character
|
||||
// in the input (bug 480262).
|
||||
waitForMenuChange(3);
|
||||
break;
|
||||
|
||||
case 51:
|
||||
checkForm("value");
|
||||
countEntries("field1", "value1",
|
||||
function (num) {
|
||||
ok(!num, testNum + " checking that f1/v1 was deleted");
|
||||
runTest();
|
||||
});
|
||||
break;
|
||||
|
||||
case 52:
|
||||
ok(!fh.entryExists("field1", "value1"), "checking that f1/v1 was deleted");
|
||||
doKey("return");
|
||||
checkForm("value2");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 53:
|
||||
checkMenuEntries(["value2", "value3", "value4"], testNum);
|
||||
case 51:
|
||||
checkMenuEntries(["value2", "value3", "value4"]);
|
||||
// Check the new first entry (of 3)
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("value2");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 54:
|
||||
case 52:
|
||||
// Delete the second entry (of 3)
|
||||
doKey("down");
|
||||
doKey("down");
|
||||
doKey("delete", shiftModifier);
|
||||
waitForMenuChange(2);
|
||||
break;
|
||||
|
||||
case 55:
|
||||
checkForm("");
|
||||
countEntries("field1", "value3",
|
||||
function (num) {
|
||||
ok(!num, testNum + " checking that f1/v3 was deleted");
|
||||
runTest();
|
||||
});
|
||||
break;
|
||||
|
||||
case 56:
|
||||
ok(!fh.entryExists("field1", "value3"), "checking that f1/v3 was deleted");
|
||||
doKey("return");
|
||||
checkForm("value4")
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 57:
|
||||
checkMenuEntries(["value2", "value4"], testNum);
|
||||
case 53:
|
||||
checkMenuEntries(["value2", "value4"]);
|
||||
// Check the new first entry (of 2)
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("value2");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 58:
|
||||
case 54:
|
||||
// Delete the last entry (of 2)
|
||||
doKey("down");
|
||||
doKey("down");
|
||||
doKey("delete", shiftModifier);
|
||||
checkForm("");
|
||||
waitForMenuChange(1);
|
||||
break;
|
||||
|
||||
case 59:
|
||||
countEntries("field1", "value4",
|
||||
function (num) {
|
||||
ok(!num, testNum + " checking that f1/v4 was deleted");
|
||||
runTest();
|
||||
});
|
||||
break;
|
||||
|
||||
case 60:
|
||||
ok(!fh.entryExists("field1", "value4"), "checking that f1/v4 was deleted");
|
||||
doKey("return");
|
||||
checkForm("value2");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 61:
|
||||
checkMenuEntries(["value2"], testNum);
|
||||
case 55:
|
||||
checkMenuEntries(["value2"]);
|
||||
// Check the new first entry (of 1)
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("value2");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 62:
|
||||
case 56:
|
||||
// Delete the only remaining entry
|
||||
doKey("down");
|
||||
doKey("delete", shiftModifier);
|
||||
waitForMenuChange(0);
|
||||
break;
|
||||
|
||||
case 63:
|
||||
checkForm("");
|
||||
countEntries("field1", "value2",
|
||||
function (num) {
|
||||
ok(!num, testNum + " checking that f1/v2 was deleted");
|
||||
runTest();
|
||||
});
|
||||
break;
|
||||
ok(!fh.entryExists("field1", "value2"), "checking that f1/v2 was deleted");
|
||||
|
||||
case 64:
|
||||
// Look at form 2, trigger autocomplete popup
|
||||
input = $_(2, "field2");
|
||||
testNum = 99;
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
testNum = 99;
|
||||
break;
|
||||
|
||||
/* Test entries with autocomplete=off */
|
||||
@ -571,11 +480,7 @@ function runTest() {
|
||||
// Look at form 3, try to trigger autocomplete popup
|
||||
input = $_(3, "field2");
|
||||
restoreForm();
|
||||
// Sometimes, this will fail if scrollTo(0, 0) is called, so that doesn't
|
||||
// happen here. Fortunately, a different input is used from the last test,
|
||||
// so a scroll should still occur.
|
||||
doKey("down");
|
||||
waitForScroll();
|
||||
break;
|
||||
|
||||
case 101:
|
||||
@ -588,7 +493,6 @@ function runTest() {
|
||||
input = $_(4, "field2");
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
waitForMenuChange(0);
|
||||
break;
|
||||
|
||||
case 102:
|
||||
@ -601,7 +505,6 @@ function runTest() {
|
||||
input = $_(5, "field3");
|
||||
restoreForm();
|
||||
testNum = 199;
|
||||
expectPopup();
|
||||
input.focus();
|
||||
sendChar("a");
|
||||
break;
|
||||
@ -609,81 +512,65 @@ function runTest() {
|
||||
/* Test filtering as characters are typed. */
|
||||
|
||||
case 200:
|
||||
checkMenuEntries(["a", "aa", "aaz", "aa\xe6", "az"], testNum);
|
||||
checkMenuEntries(["a", "aa", "aaz", "aa\xe6", "az"]);
|
||||
input.focus();
|
||||
sendChar("a");
|
||||
waitForMenuChange(3);
|
||||
break;
|
||||
|
||||
case 201:
|
||||
checkMenuEntries(["aa", "aaz", "aa\xe6"], testNum);
|
||||
checkMenuEntries(["aa", "aaz", "aa\xe6"]);
|
||||
input.focus();
|
||||
sendChar("\xc6");
|
||||
waitForMenuChange(1);
|
||||
break;
|
||||
|
||||
case 202:
|
||||
checkMenuEntries(["aa\xe6"], testNum);
|
||||
checkMenuEntries(["aa\xe6"]);
|
||||
doKey("back_space");
|
||||
waitForMenuChange(3);
|
||||
break;
|
||||
|
||||
case 203:
|
||||
checkMenuEntries(["aa", "aaz", "aa\xe6"], testNum);
|
||||
checkMenuEntries(["aa", "aaz", "aa\xe6"]);
|
||||
doKey("back_space");
|
||||
waitForMenuChange(5);
|
||||
break;
|
||||
|
||||
case 204:
|
||||
checkMenuEntries(["a", "aa", "aaz", "aa\xe6", "az"], testNum);
|
||||
checkMenuEntries(["a", "aa", "aaz", "aa\xe6", "az"]);
|
||||
input.focus();
|
||||
sendChar("z");
|
||||
waitForMenuChange(2);
|
||||
break;
|
||||
|
||||
case 205:
|
||||
checkMenuEntries(["az", "aaz"], testNum);
|
||||
ok(getMenuEntries().length > 0, "checking typing in middle of text");
|
||||
input.focus();
|
||||
doKey("left");
|
||||
expectPopup();
|
||||
sendChar("a");
|
||||
break;
|
||||
|
||||
case 206:
|
||||
checkMenuEntries(["aaz"], testNum);
|
||||
addEntry("field3", "aazq");
|
||||
break;
|
||||
|
||||
case 207:
|
||||
checkMenuEntries(["aaz"]);
|
||||
fh.addEntry("field3", "aazq");
|
||||
input.focus();
|
||||
doKey("right");
|
||||
sendChar("q");
|
||||
waitForMenuChange(0);
|
||||
break;
|
||||
|
||||
case 207:
|
||||
// check that results were cached
|
||||
checkMenuEntries([]);
|
||||
fh.addEntry("field3", "aazqq");
|
||||
input.focus();
|
||||
sendChar("q");
|
||||
break;
|
||||
|
||||
case 208:
|
||||
// check that results were cached
|
||||
checkMenuEntries([], testNum);
|
||||
addEntry("field3", "aazqq");
|
||||
break;
|
||||
|
||||
case 209:
|
||||
input.focus();
|
||||
window.scrollTo(0, 0);
|
||||
sendChar("q");
|
||||
waitForScroll();
|
||||
break;
|
||||
|
||||
case 210:
|
||||
// check that empty results were cached - bug 496466
|
||||
checkMenuEntries([], testNum);
|
||||
checkMenuEntries([]);
|
||||
doKey("escape");
|
||||
|
||||
// Look at form 6, try to trigger autocomplete popup
|
||||
input = $_(6, "field4");
|
||||
restoreForm();
|
||||
testNum = 249;
|
||||
expectPopup();
|
||||
input.focus();
|
||||
sendChar("a");
|
||||
break;
|
||||
@ -692,159 +579,138 @@ function runTest() {
|
||||
|
||||
case 250:
|
||||
// alphabetical results for first character
|
||||
checkMenuEntries(["aa a\xe6", "aba\xe6", "a\xe6"], testNum);
|
||||
checkMenuEntries(["aa a\xe6", "aba\xe6", "a\xe6"]);
|
||||
input.focus();
|
||||
|
||||
// for this test, hide the popup first as it contains the same number of menu
|
||||
|
||||
sendChar("\xc6");
|
||||
waitForMenuChange(3, "a\xe6");
|
||||
break;
|
||||
|
||||
case 251:
|
||||
// prefix match comes first, then word boundary match
|
||||
// followed by substring match
|
||||
checkMenuEntries(["a\xe6", "aa a\xe6", "aba\xe6"], testNum);
|
||||
checkMenuEntries(["a\xe6", "aa a\xe6", "aba\xe6"]);
|
||||
|
||||
restoreForm();
|
||||
input.focus();
|
||||
sendChar("b");
|
||||
waitForMenuChange(1, "bc d\xe6");
|
||||
break;
|
||||
|
||||
case 252:
|
||||
checkMenuEntries(["bc d\xe6"], testNum);
|
||||
checkMenuEntries(["bc d\xe6"]);
|
||||
input.focus();
|
||||
sendChar(" ");
|
||||
setTimeout(runTest, 300);
|
||||
break;
|
||||
|
||||
case 253:
|
||||
// check that trailing space has no effect after single char.
|
||||
checkMenuEntries(["bc d\xe6"], testNum);
|
||||
checkMenuEntries(["bc d\xe6"]);
|
||||
input.focus();
|
||||
sendChar("\xc6");
|
||||
waitForMenuChange(2);
|
||||
break;
|
||||
|
||||
case 254:
|
||||
// check multi-word substring matches
|
||||
checkMenuEntries(["bc d\xe6", "aba\xe6"]);
|
||||
input.focus();
|
||||
expectPopup();
|
||||
doKey("left");
|
||||
sendChar("d");
|
||||
break;
|
||||
|
||||
case 255:
|
||||
// check inserting in multi-word searches
|
||||
checkMenuEntries(["bc d\xe6"], testNum);
|
||||
checkMenuEntries(["bc d\xe6"]);
|
||||
input.focus();
|
||||
sendChar("z");
|
||||
waitForMenuChange(0);
|
||||
break;
|
||||
|
||||
case 256:
|
||||
checkMenuEntries([], testNum);
|
||||
checkMenuEntries([]);
|
||||
|
||||
// Look at form 7, try to trigger autocomplete popup
|
||||
input = $_(7, "field5");
|
||||
testNum = 299;
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
testNum = 299;
|
||||
break;
|
||||
|
||||
case 300:
|
||||
checkMenuEntries(["1", "12", "123", "1234"], testNum);
|
||||
checkMenuEntries(["1", "12", "123", "1234"]);
|
||||
input.maxLength = 4;
|
||||
expectPopup();
|
||||
doKey("escape");
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 301:
|
||||
checkMenuEntries(["1", "12", "123", "1234"], testNum);
|
||||
checkMenuEntries(["1", "12", "123", "1234"]);
|
||||
input.maxLength = 3;
|
||||
expectPopup();
|
||||
doKey("escape");
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 302:
|
||||
checkMenuEntries(["1", "12", "123"], testNum);
|
||||
checkMenuEntries(["1", "12", "123"]);
|
||||
input.maxLength = 2;
|
||||
expectPopup();
|
||||
doKey("escape");
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 303:
|
||||
checkMenuEntries(["1", "12"], testNum);
|
||||
checkMenuEntries(["1", "12"]);
|
||||
input.maxLength = 1;
|
||||
expectPopup();
|
||||
doKey("escape");
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 304:
|
||||
checkMenuEntries(["1"], testNum);
|
||||
checkMenuEntries(["1"]);
|
||||
input.maxLength = 0;
|
||||
doKey("escape");
|
||||
doKey("down");
|
||||
waitForMenuChange(0);
|
||||
break;
|
||||
|
||||
case 305:
|
||||
checkMenuEntries([], testNum);
|
||||
checkMenuEntries([]);
|
||||
input.maxLength = 4;
|
||||
|
||||
// now again with a character typed
|
||||
input.focus();
|
||||
sendChar("1");
|
||||
expectPopup();
|
||||
doKey("escape");
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 306:
|
||||
checkMenuEntries(["1", "12", "123", "1234"], testNum);
|
||||
checkMenuEntries(["1", "12", "123", "1234"]);
|
||||
input.maxLength = 3;
|
||||
expectPopup();
|
||||
doKey("escape");
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 307:
|
||||
checkMenuEntries(["1", "12", "123"], testNum);
|
||||
checkMenuEntries(["1", "12", "123"]);
|
||||
input.maxLength = 2;
|
||||
expectPopup();
|
||||
doKey("escape");
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 308:
|
||||
checkMenuEntries(["1", "12"], testNum);
|
||||
checkMenuEntries(["1", "12"]);
|
||||
input.maxLength = 1;
|
||||
expectPopup();
|
||||
doKey("escape");
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 309:
|
||||
checkMenuEntries(["1"], testNum);
|
||||
checkMenuEntries(["1"]);
|
||||
input.maxLength = 0;
|
||||
doKey("escape");
|
||||
doKey("down");
|
||||
waitForMenuChange(0);
|
||||
break;
|
||||
|
||||
case 310:
|
||||
checkMenuEntries([], testNum);
|
||||
checkMenuEntries([]);
|
||||
|
||||
input = $_(8, "field6");
|
||||
testNum = 399;
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -853,7 +719,7 @@ function runTest() {
|
||||
case 401:
|
||||
case 402:
|
||||
case 403:
|
||||
checkMenuEntries(["value"], testNum);
|
||||
checkMenuEntries(["value"]);
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("value");
|
||||
@ -868,20 +734,18 @@ function runTest() {
|
||||
input = $_(12, "field10");
|
||||
}
|
||||
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 404:
|
||||
checkMenuEntries(["42"], testNum);
|
||||
checkMenuEntries(["42"]);
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("42");
|
||||
|
||||
input = $_(14, "field11");
|
||||
restoreForm();
|
||||
expectPopup();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
@ -893,7 +757,6 @@ function runTest() {
|
||||
|
||||
input = $_(15, "field12");
|
||||
restoreForm();
|
||||
expectPopup();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
@ -906,24 +769,19 @@ function runTest() {
|
||||
input = $_(16, "field13");
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
waitForMenuChange(0);
|
||||
break;
|
||||
|
||||
case 407:
|
||||
case 407:
|
||||
checkMenuEntries([]); // type=range does not have a drop down menu
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("30"); // default (midway between minimum (0) and maximum (64)) - step
|
||||
|
||||
addEntry("field1", "value1");
|
||||
break;
|
||||
|
||||
case 408:
|
||||
input = $_(1, "field1");
|
||||
// Go to test 500.
|
||||
fh.addEntry("field1", "value1");
|
||||
input = $_(1, "field1");
|
||||
testNum = 499;
|
||||
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -932,9 +790,9 @@ function runTest() {
|
||||
case 500:
|
||||
input.addEventListener("input", function(event) {
|
||||
input.removeEventListener("input", arguments.callee, false);
|
||||
ok(true, testNum + " oninput should have been received");
|
||||
ok(event.bubbles, testNum + " input event should bubble");
|
||||
ok(event.cancelable, testNum + " input event should be cancelable");
|
||||
ok(true, "oninput should have been received");
|
||||
ok(event.bubbles, "input event should bubble");
|
||||
ok(event.cancelable, "input event should be cancelable");
|
||||
}, false);
|
||||
|
||||
doKey("down");
|
||||
@ -942,7 +800,6 @@ function runTest() {
|
||||
doKey("return");
|
||||
checkForm("value1");
|
||||
testNum = 599;
|
||||
setTimeout(runTest, 100);
|
||||
break;
|
||||
|
||||
case 600:
|
||||
@ -953,59 +810,27 @@ function runTest() {
|
||||
checkForm("");
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
waitForMenuChange(0);
|
||||
break;
|
||||
|
||||
case 601:
|
||||
checkMenuEntries([], testNum);
|
||||
SpecialPowers.removeAutoCompletePopupEventListener(window, "popupshown", popupShownListener);
|
||||
checkMenuEntries([]);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
|
||||
default:
|
||||
ok(false, "Unexpected invocation of test #" + testNum);
|
||||
SpecialPowers.removeAutoCompletePopupEventListener(window, "popupshown", popupShownListener);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(runTest, 50, testNum + 1); // XXX 40ms was too slow, why?
|
||||
}
|
||||
|
||||
function addEntry(name, value)
|
||||
{
|
||||
updateFormHistory({ op : "add", fieldname : name, value: value }, runTest);
|
||||
}
|
||||
|
||||
// Runs the next test when scroll event occurs
|
||||
function waitForScroll()
|
||||
{
|
||||
addEventListener("scroll", function() {
|
||||
if (!window.pageYOffset)
|
||||
return;
|
||||
|
||||
removeEventListener("scroll", arguments.callee, false);
|
||||
setTimeout(runTest, 50);
|
||||
}, false);
|
||||
}
|
||||
|
||||
function waitForMenuChange(expectedCount, expectedFirstValue)
|
||||
{
|
||||
if (autocompleteMenu.tree.view.rowCount != expectedCount) {
|
||||
SimpleTest.executeSoon(function () waitForMenuChange(expectedCount, expectedFirstValue));
|
||||
}
|
||||
else if (expectedFirstValue && autocompleteMenu.tree.view.rowCount > 1 &&
|
||||
autocompleteMenu.tree.view.getValueAt(0, autocompleteMenu.tree.columns[0]) != expectedFirstValue) {
|
||||
SimpleTest.executeSoon(function () waitForMenuChange(expectedCount, expectedFirstValue));
|
||||
}
|
||||
else {
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
function checkMenuEntries(expectedValues, testNum) {
|
||||
function checkMenuEntries(expectedValues) {
|
||||
var actualValues = getMenuEntries();
|
||||
is(actualValues.length, expectedValues.length, testNum + " Checking length of expected menu");
|
||||
is(actualValues.length, expectedValues.length, "Checking length of expected menu");
|
||||
for (var i = 0; i < expectedValues.length; i++)
|
||||
is(actualValues[i], expectedValues[i], testNum + " Checking menu entry #"+i);
|
||||
is(actualValues[i], expectedValues[i], "Checking menu entry #"+i);
|
||||
}
|
||||
|
||||
function getMenuEntries() {
|
||||
@ -1022,9 +847,7 @@ function getMenuEntries() {
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
setupFormHistory(function() {
|
||||
runTest();
|
||||
});
|
||||
runTest(1);
|
||||
}
|
||||
|
||||
window.onload = startTest;
|
||||
|
@ -44,16 +44,19 @@ Form History test: form field autocomplete
|
||||
|
||||
/** Test for Form History autocomplete **/
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var input = $_(1, "field1");
|
||||
const shiftModifier = Components.interfaces.nsIDOMEvent.SHIFT_MASK;
|
||||
|
||||
function setupFormHistory(aCallback) {
|
||||
updateFormHistory([
|
||||
{ op : "remove" },
|
||||
{ op : "add", fieldname : "field1", value : "historyvalue" },
|
||||
{ op : "add", fieldname : "field2", value : "othervalue" },
|
||||
], aCallback);
|
||||
}
|
||||
// Get the form history service
|
||||
var fh = Components.classes["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Components.interfaces.nsIFormHistory2);
|
||||
ok(fh != null, "got form history service");
|
||||
|
||||
fh.removeAllEntries();
|
||||
fh.addEntry("field1", "historyvalue");
|
||||
fh.addEntry("field2", "othervalue");
|
||||
|
||||
function setForm(value) {
|
||||
input.value = value;
|
||||
@ -73,41 +76,19 @@ function checkForm(expectedValue) {
|
||||
is(input.value, expectedValue, "Checking " + formID + " input");
|
||||
}
|
||||
|
||||
var testNum = 0;
|
||||
var prevValue;
|
||||
var expectingPopup = false;
|
||||
|
||||
function expectPopup()
|
||||
{
|
||||
info("expecting popup for test " + testNum);
|
||||
expectingPopup = true;
|
||||
function nextTest(aTestNum) {
|
||||
setTimeout(runTest, 50, aTestNum + 1); // XXX 40ms was too slow, why?
|
||||
}
|
||||
|
||||
function popupShownListener()
|
||||
{
|
||||
info("popup shown for test " + testNum);
|
||||
if (expectingPopup) {
|
||||
expectingPopup = false;
|
||||
SimpleTest.executeSoon(runTest);
|
||||
}
|
||||
else {
|
||||
ok(false, "Autocomplete popup not expected during test " + testNum);
|
||||
}
|
||||
}
|
||||
|
||||
SpecialPowers.addAutoCompletePopupEventListener(window, "popupshown", popupShownListener);
|
||||
|
||||
/*
|
||||
* Main section of test...
|
||||
*
|
||||
* This is a bit hacky, as many operations happen asynchronously.
|
||||
* Various mechanisms call runTests as a result of operations:
|
||||
* - set expectingPopup to true, and the next test will occur when the autocomplete popup is shown
|
||||
* - call waitForMenuChange(x) to run the next test when the autocomplete popup to have x items in it
|
||||
* This is a bit hacky, because the events are either being sent or
|
||||
* processed asynchronously, so we need to interrupt our flow with lots of
|
||||
* setTimeout() calls. The case statements are executed in order, one per
|
||||
* timeout.
|
||||
*/
|
||||
function runTest() {
|
||||
testNum++;
|
||||
|
||||
function runTest(testNum) {
|
||||
// Seems we need to enable this again, or sendKeyEvent() complaints.
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
info("Starting test #" + testNum);
|
||||
@ -117,12 +98,12 @@ function runTest() {
|
||||
// Make sure initial form is empty.
|
||||
checkForm("");
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
checkMenuEntries(["historyvalue", "PASS1", "PASS2", "final"], testNum);
|
||||
checkMenuEntries(["historyvalue", "PASS1", "PASS2", "final"]);
|
||||
// Check first entry
|
||||
doKey("down");
|
||||
checkForm(""); // value shouldn't update
|
||||
@ -130,7 +111,6 @@ function runTest() {
|
||||
checkForm("historyvalue");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -143,7 +123,6 @@ function runTest() {
|
||||
checkForm("Google");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -157,7 +136,6 @@ function runTest() {
|
||||
checkForm("Reddit");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -170,7 +148,6 @@ function runTest() {
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("final");
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -179,31 +156,18 @@ function runTest() {
|
||||
//Delete the first entry (of 3)
|
||||
doKey("down");
|
||||
doKey("delete", shiftModifier);
|
||||
waitForMenuChange(3);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
checkForm("");
|
||||
countEntries("field1", "historyvalue",
|
||||
function (num) {
|
||||
ok(!num, testNum + " checking that form history value was deleted");
|
||||
runTest();
|
||||
});
|
||||
break;
|
||||
|
||||
case 8:
|
||||
ok(!fh.entryExists("field1", "historyvalue"), "checking that form history value was deleted");
|
||||
doKey("return");
|
||||
checkForm("Google")
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 9:
|
||||
case 7:
|
||||
//Test deletion
|
||||
checkMenuEntries(["PASS1", "PASS2", "final"], testNum);
|
||||
checkMenuEntries(["PASS1", "PASS2", "final"]);
|
||||
// Check the new first entry (of 3)
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
@ -214,13 +178,12 @@ function runTest() {
|
||||
input.value = "";
|
||||
input = $_(3, "field2");
|
||||
testNum = 99;
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 100:
|
||||
checkMenuEntries(["PASS1", "PASS2", "final"], testNum);
|
||||
checkMenuEntries(["PASS1", "PASS2", "final"]);
|
||||
// Check first entry
|
||||
doKey("down");
|
||||
checkForm(""); // value shouldn't update
|
||||
@ -228,7 +191,6 @@ function runTest() {
|
||||
checkForm("Google");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -241,7 +203,6 @@ function runTest() {
|
||||
checkForm("Reddit");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -255,13 +216,12 @@ function runTest() {
|
||||
checkForm("final");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 103:
|
||||
checkMenuEntries(["PASS1", "PASS2", "final"], testNum);
|
||||
checkMenuEntries(["PASS1", "PASS2", "final"]);
|
||||
// Check first entry
|
||||
doKey("down");
|
||||
checkForm(""); // value shouldn't update
|
||||
@ -269,7 +229,6 @@ function runTest() {
|
||||
checkForm("Google");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -282,7 +241,6 @@ function runTest() {
|
||||
checkForm("Reddit");
|
||||
|
||||
// Trigger autocomplete popup
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -296,7 +254,6 @@ function runTest() {
|
||||
checkForm("final");
|
||||
|
||||
testNum = 199;
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
@ -321,11 +278,11 @@ function runTest() {
|
||||
|
||||
// Restore the element.
|
||||
datalist.insertBefore(toRemove, datalist.children[1]);
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
nextTest(testNum);
|
||||
});
|
||||
break;
|
||||
return;
|
||||
|
||||
case 201:
|
||||
// Adding an attribute after the first one while on the first then going
|
||||
@ -343,87 +300,83 @@ function runTest() {
|
||||
|
||||
// Remove the element.
|
||||
datalist.removeChild(added);
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
nextTest(testNum);
|
||||
});
|
||||
break;
|
||||
return;
|
||||
|
||||
case 202:
|
||||
// Change the first element value attribute.
|
||||
doKey("down");
|
||||
var datalist = document.getElementById('suggest');
|
||||
prevValue = datalist.children[0].value;
|
||||
var prevValue = datalist.children[0].value;
|
||||
datalist.children[0].value = "foo";
|
||||
expectPopup();
|
||||
break;
|
||||
|
||||
SimpleTest.executeSoon(function() {
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("foo");
|
||||
|
||||
datalist.children[0].value = prevValue;
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
nextTest(testNum);
|
||||
});
|
||||
return;
|
||||
|
||||
case 203:
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("foo");
|
||||
|
||||
var datalist = document.getElementById('suggest');
|
||||
datalist.children[0].value = prevValue;
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 204:
|
||||
// Change the textContent to update the value attribute.
|
||||
doKey("down");
|
||||
var datalist = document.getElementById('suggest');
|
||||
prevValue = datalist.children[0].getAttribute('value');
|
||||
var prevValue = datalist.children[0].getAttribute('value');
|
||||
datalist.children[0].removeAttribute('value');
|
||||
datalist.children[0].textContent = "foobar";
|
||||
expectPopup();
|
||||
break;
|
||||
|
||||
case 205:
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("foobar");
|
||||
SimpleTest.executeSoon(function() {
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("foobar");
|
||||
|
||||
var datalist = document.getElementById('suggest');
|
||||
datalist.children[0].setAttribute('value', prevValue);
|
||||
testNum = 299;
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
datalist.children[0].setAttribute('value', prevValue);
|
||||
testNum = 299;
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
nextTest(testNum);
|
||||
});
|
||||
return;
|
||||
|
||||
// Tests for filtering (or not).
|
||||
case 300:
|
||||
// Filters with first letter of the word.
|
||||
synthesizeKey("f", {});
|
||||
expectPopup();
|
||||
setTimeout(function() {
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("final");
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
nextTest(testNum);
|
||||
}, 500);
|
||||
return;
|
||||
break;
|
||||
|
||||
case 301:
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("final");
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
break;
|
||||
|
||||
case 302:
|
||||
// Filter with a letter in the middle of the word.
|
||||
// Filter with a leterr in the middle of the word.
|
||||
synthesizeKey("i", {});
|
||||
synthesizeKey("n", {});
|
||||
setTimeout(function() {
|
||||
doKey("down");
|
||||
doKey("return");
|
||||
checkForm("final");
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
nextTest(testNum);
|
||||
}, 500);
|
||||
return;
|
||||
break;
|
||||
|
||||
case 303:
|
||||
case 302:
|
||||
// Filter is disabled with mozNoFilter.
|
||||
input.setAttribute('mozNoFilter', 'true');
|
||||
synthesizeKey("f", {});
|
||||
@ -432,11 +385,12 @@ function runTest() {
|
||||
doKey("return");
|
||||
checkForm("Google");
|
||||
input.removeAttribute('mozNoFilter');
|
||||
testNum = 399;
|
||||
expectPopup();
|
||||
restoreForm();
|
||||
doKey("down");
|
||||
testNum = 399;
|
||||
nextTest(testNum);
|
||||
}, 500);
|
||||
return;
|
||||
break;
|
||||
|
||||
case 400:
|
||||
@ -447,38 +401,28 @@ function runTest() {
|
||||
ok(event.bubbles, "input event should bubble");
|
||||
ok(event.cancelable, "input event should be cancelable");
|
||||
checkForm("Google");
|
||||
SpecialPowers.removeAutoCompletePopupEventListener(window, "popupshown", popupShownListener);
|
||||
SimpleTest.finish();
|
||||
}, false);
|
||||
|
||||
doKey("down");
|
||||
checkForm("");
|
||||
doKey("return");
|
||||
break;
|
||||
return;
|
||||
|
||||
default:
|
||||
ok(false, "Unexpected invocation of test #" + testNum);
|
||||
SpecialPowers.removeAutoCompletePopupEventListener(window, "popupshown", popupShownListener);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
ok(false, "Unexpected invocation of test #" + testNum);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
nextTest(testNum);
|
||||
}
|
||||
|
||||
function waitForMenuChange(expectedCount)
|
||||
{
|
||||
if (autocompleteMenu.tree.view.rowCount != expectedCount) {
|
||||
SimpleTest.executeSoon(function () waitForMenuChange(expectedCount));
|
||||
}
|
||||
else {
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
function checkMenuEntries(expectedValues, testNum) {
|
||||
function checkMenuEntries(expectedValues) {
|
||||
var actualValues = getMenuEntries();
|
||||
is(actualValues.length, expectedValues.length, testNum + " Checking length of expected menu");
|
||||
is(actualValues.length, expectedValues.length, "Checking length of expected menu");
|
||||
for (var i = 0; i < expectedValues.length; i++)
|
||||
is(actualValues[i], expectedValues[i], testNum + " Checking menu entry #"+i);
|
||||
is(actualValues[i], expectedValues[i], "Checking menu entry #"+i);
|
||||
}
|
||||
|
||||
function getMenuEntries() {
|
||||
@ -495,7 +439,7 @@ function getMenuEntries() {
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
setupFormHistory(runTest);
|
||||
runTest(1);
|
||||
}
|
||||
|
||||
window.onload = startTest;
|
||||
|
@ -293,15 +293,10 @@ var ccNumbers = {
|
||||
],
|
||||
};
|
||||
|
||||
function checkInitialState() {
|
||||
countEntries(null, null,
|
||||
function (num) {
|
||||
ok(!num, "checking for initially empty storage");
|
||||
startTest();
|
||||
});
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
ok(!fh.hasEntries, "checking for initially empty storage");
|
||||
|
||||
// Fill in values for the various fields. We could just set the <input>'s
|
||||
// value attribute, but we don't save default form values (and we want to
|
||||
// ensure unsaved values are because of autocomplete=off or whatever).
|
||||
@ -374,6 +369,7 @@ function checkSubmit(formNum) {
|
||||
ok(true, "form " + formNum + " submitted");
|
||||
numSubmittedForms++;
|
||||
|
||||
|
||||
// Check for expected storage state.
|
||||
switch (formNum) {
|
||||
// Test 1-24 should not save anything.
|
||||
@ -401,12 +397,7 @@ function checkSubmit(formNum) {
|
||||
case 22:
|
||||
case 23:
|
||||
case 24:
|
||||
countEntries(null, null,
|
||||
function (num) {
|
||||
ok(!num, "checking for empty storage");
|
||||
submitForm(formNum);
|
||||
});
|
||||
return false;
|
||||
ok(!fh.hasEntries, "checking for empty storage");
|
||||
break;
|
||||
case 100:
|
||||
checkForSave("subtest2", "subtestValue", "checking saved subtest value");
|
||||
@ -450,24 +441,19 @@ function checkSubmit(formNum) {
|
||||
break;
|
||||
}
|
||||
|
||||
return submitForm(formNum);
|
||||
}
|
||||
|
||||
function submitForm(formNum)
|
||||
{
|
||||
// Forms 13 and 14 would trigger a save-password notification. Temporarily
|
||||
// disable pwmgr, then reenable it.
|
||||
if (formNum == 12)
|
||||
SpecialPowers.setBoolPref("signon.rememberSignons", false);
|
||||
prefBranch.setBoolPref("signon.rememberSignons", false);
|
||||
if (formNum == 14)
|
||||
SpecialPowers.clearUserPref("signon.rememberSignons");
|
||||
prefBranch.clearUserPref("signon.rememberSignons");
|
||||
|
||||
// Forms 20 and 21 requires browser.formfill.saveHttpsForms to be false
|
||||
if (formNum == 19)
|
||||
SpecialPowers.setBoolPref("browser.formfill.saveHttpsForms", false);
|
||||
prefBranch.setBoolPref("browser.formfill.saveHttpsForms", false);
|
||||
// Reset preference now that 20 and 21 are over
|
||||
if (formNum == 21)
|
||||
SpecialPowers.clearUserPref("browser.formfill.saveHttpsForms");
|
||||
prefBranch.clearUserPref("browser.formfill.saveHttpsForms");
|
||||
|
||||
// End the test now on SeaMonkey.
|
||||
if (formNum == 21 && navigator.userAgent.match(/ SeaMonkey\//)) {
|
||||
@ -484,11 +470,11 @@ function submitForm(formNum)
|
||||
// Form 109 requires browser.formfill.save_https_forms to be true;
|
||||
// Form 110 requires it to be false.
|
||||
if (formNum == 108)
|
||||
SpecialPowers.setBoolPref("browser.formfill.saveHttpsForms", true);
|
||||
prefBranch.setBoolPref("browser.formfill.saveHttpsForms", true);
|
||||
if (formNum == 109)
|
||||
SpecialPowers.setBoolPref("browser.formfill.saveHttpsForms", false);
|
||||
prefBranch.setBoolPref("browser.formfill.saveHttpsForms", false);
|
||||
if (formNum == 110)
|
||||
SpecialPowers.clearUserPref("browser.formfill.saveHttpsForms");
|
||||
prefBranch.clearUserPref("browser.formfill.saveHttpsForms");
|
||||
|
||||
// End the test at the last form.
|
||||
if (formNum == 110) {
|
||||
@ -508,6 +494,8 @@ function submitForm(formNum)
|
||||
//
|
||||
setTimeout(function() {
|
||||
checkObserver.waitForChecks(function() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var nextFormNum = formNum == 24 ? 100 : (formNum + 1);
|
||||
|
||||
// Submit the next form. Special cases are Forms 21 and 100, which happen
|
||||
@ -526,9 +514,18 @@ function submitForm(formNum)
|
||||
return false; // cancel current form submission
|
||||
}
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var fh = Components.classes["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Components.interfaces.nsIFormHistory2);
|
||||
ok(fh != null, "Got formHistory service");
|
||||
|
||||
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"].
|
||||
getService(Components.interfaces.nsIPrefBranch);
|
||||
|
||||
Services.obs.addObserver(checkObserver, "satchel-storage-changed", false);
|
||||
|
||||
window.onload = checkInitialState;
|
||||
window.onload = startTest;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
|
@ -28,15 +28,10 @@
|
||||
var numSubmittedForms = 0;
|
||||
var numInputFields = 101;
|
||||
|
||||
function checkInitialState() {
|
||||
countEntries(null, null,
|
||||
function (num) {
|
||||
ok(!num, "checking for initially empty storage");
|
||||
startTest();
|
||||
});
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
ok(!fh.hasEntries, "checking for initially empty storage");
|
||||
|
||||
var form = document.getElementById("form1");
|
||||
for (i = 1; i <= numInputFields; i++) {
|
||||
var newField = document.createElement("input");
|
||||
@ -60,6 +55,8 @@ function startTest() {
|
||||
|
||||
// Called by each form's onsubmit handler.
|
||||
function checkSubmit(formNum) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
ok(true, "form " + formNum + " submitted");
|
||||
numSubmittedForms++;
|
||||
|
||||
@ -68,14 +65,33 @@ function checkSubmit(formNum) {
|
||||
checkForSave("test" + i, i, "checking saved value " + i);
|
||||
}
|
||||
|
||||
// End the test.
|
||||
is(numSubmittedForms, 1, "Ensuring all forms were submitted.");
|
||||
SimpleTest.finish();
|
||||
return false; // return false to cancel current form submission
|
||||
// End the test at the last form.
|
||||
if (formNum == 1) {
|
||||
is(numSubmittedForms, 1, "Ensuring all forms were submitted.");
|
||||
Services.obs.removeObserver(checkObserver, "satchel-storage-changed");
|
||||
SimpleTest.finish();
|
||||
return false; // return false to cancel current form submission
|
||||
}
|
||||
|
||||
checkObserver.waitForChecks(function() {
|
||||
// submit the next form.
|
||||
var button = getFormSubmitButton(formNum + 1);
|
||||
button.click();
|
||||
});
|
||||
|
||||
return false; // cancel current form submission
|
||||
}
|
||||
|
||||
|
||||
window.onload = checkInitialState;
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var fh = Components.classes["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Components.interfaces.nsIFormHistory2);
|
||||
ok(fh != null, "Got formHistory service");
|
||||
|
||||
window.onload = startTest;
|
||||
|
||||
Services.obs.addObserver(checkObserver, "satchel-storage-changed", false);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
|
@ -126,15 +126,10 @@
|
||||
var numSubmittedForms = 0;
|
||||
var numInputFields = 101;
|
||||
|
||||
function checkInitialState() {
|
||||
countEntries(null, null,
|
||||
function (num) {
|
||||
ok(!num, "checking for initially empty storage");
|
||||
startTest();
|
||||
});
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
ok(!fh.hasEntries, "checking for initially empty storage");
|
||||
|
||||
// Fill in values for the various fields. We could just set the <input>'s
|
||||
// value attribute, but we don't save default form values (and we want to
|
||||
// ensure unsaved values are because of autocomplete=off or whatever).
|
||||
@ -145,42 +140,50 @@ function startTest() {
|
||||
button.click();
|
||||
}
|
||||
|
||||
// Make sure that the first (numInputFields - 1) were not saved (as they were not changed).
|
||||
// Call done() when finished.
|
||||
function checkCountEntries(formNum, index, done)
|
||||
{
|
||||
countEntries("test" + index, index,
|
||||
function (num) {
|
||||
ok(!num, "checking unsaved value " + index);
|
||||
if (index < numInputFields) {
|
||||
checkCountEntries(formNum, index + 1, done);
|
||||
}
|
||||
else {
|
||||
done(formNum);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Called by each form's onsubmit handler.
|
||||
function checkSubmit(formNum) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
ok(true, "form " + formNum + " submitted");
|
||||
numSubmittedForms++;
|
||||
|
||||
// make sure that the first (numInputFields - 1) were not saved (as they were not changed)
|
||||
for (i = 1; i < numInputFields; i++) {
|
||||
ok(!fh.entryExists("test" + i, i), "checking unsaved value " + i);
|
||||
}
|
||||
|
||||
// make sure that the field # numInputFields was saved
|
||||
checkForSave("test" + numInputFields, numInputFields + " changed", "checking saved value " + numInputFields);
|
||||
|
||||
checkCountEntries(formNum, 1, checkSubmitCounted);
|
||||
|
||||
// End the test at the last form.
|
||||
if (formNum == 1) {
|
||||
is(numSubmittedForms, 1, "Ensuring all forms were submitted.");
|
||||
Services.obs.removeObserver(checkObserver, "satchel-storage-changed");
|
||||
SimpleTest.finish();
|
||||
return false; // return false to cancel current form submission
|
||||
}
|
||||
|
||||
checkObserver.waitForChecks(function() {
|
||||
// submit the next form.
|
||||
var button = getFormSubmitButton(formNum + 1);
|
||||
button.click();
|
||||
});
|
||||
|
||||
return false; // cancel current form submission
|
||||
}
|
||||
|
||||
function checkSubmitCounted(formNum) {
|
||||
is(numSubmittedForms, 1, "Ensuring all forms were submitted.");
|
||||
SimpleTest.finish();
|
||||
return false;
|
||||
}
|
||||
|
||||
window.onload = checkInitialState;
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
var fh = Components.classes["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Components.interfaces.nsIFormHistory2);
|
||||
ok(fh != null, "Got formHistory service");
|
||||
|
||||
window.onload = startTest;
|
||||
|
||||
Services.obs.addObserver(checkObserver, "satchel-storage-changed", false);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
toolkit/components/satchel/test/unit/formhistory_expire.sqlite
Normal file
BIN
toolkit/components/satchel/test/unit/formhistory_expire.sqlite
Normal file
Binary file not shown.
BIN
toolkit/components/satchel/test/unit/formhistory_v0.sqlite
Normal file
BIN
toolkit/components/satchel/test/unit/formhistory_v0.sqlite
Normal file
Binary file not shown.
BIN
toolkit/components/satchel/test/unit/formhistory_v0v1.sqlite
Normal file
BIN
toolkit/components/satchel/test/unit/formhistory_v0v1.sqlite
Normal file
Binary file not shown.
BIN
toolkit/components/satchel/test/unit/formhistory_v1.sqlite
Normal file
BIN
toolkit/components/satchel/test/unit/formhistory_v1.sqlite
Normal file
Binary file not shown.
BIN
toolkit/components/satchel/test/unit/formhistory_v1v2.sqlite
Normal file
BIN
toolkit/components/satchel/test/unit/formhistory_v1v2.sqlite
Normal file
Binary file not shown.
BIN
toolkit/components/satchel/test/unit/formhistory_v2.sqlite
Normal file
BIN
toolkit/components/satchel/test/unit/formhistory_v2.sqlite
Normal file
Binary file not shown.
BIN
toolkit/components/satchel/test/unit/formhistory_v2v3.sqlite
Normal file
BIN
toolkit/components/satchel/test/unit/formhistory_v2v3.sqlite
Normal file
Binary file not shown.
@ -2,13 +2,8 @@
|
||||
* 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/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
|
||||
const CURRENT_SCHEMA = 4;
|
||||
const PR_HOURS = 60 * 60 * 1000000;
|
||||
@ -18,12 +13,6 @@ do_get_profile();
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
|
||||
// Send the profile-after-change notification to the form history component to ensure
|
||||
// that it has been initialized.
|
||||
var formHistoryStartup = Cc["@mozilla.org/satchel/form-history-startup;1"].
|
||||
getService(Ci.nsIObserver);
|
||||
formHistoryStartup.observe(null, "profile-after-change", null);
|
||||
|
||||
function getDBVersion(dbfile) {
|
||||
var ss = Cc["@mozilla.org/storage/service;1"].
|
||||
getService(Ci.mozIStorageService);
|
||||
@ -36,67 +25,10 @@ function getDBVersion(dbfile) {
|
||||
|
||||
const isGUID = /[A-Za-z0-9\+\/]{16}/;
|
||||
|
||||
// Find form history entries.
|
||||
function searchEntries(terms, params, iter) {
|
||||
let results = [];
|
||||
FormHistory.search(terms, params, { handleResult: function (result) results.push(result),
|
||||
handleError: function (error) {
|
||||
do_throw("Error occurred searching form history: " + error);
|
||||
},
|
||||
handleCompletion: function (reason) { if (!reason) iter.send(results); }
|
||||
});
|
||||
}
|
||||
|
||||
// Count the number of entries with the given name and value, and call then(number)
|
||||
// when done. If name or value is null, then the value of that field does not matter.
|
||||
function countEntries(name, value, then) {
|
||||
var obj = {};
|
||||
if (name !== null)
|
||||
obj.fieldname = name;
|
||||
if (value !== null)
|
||||
obj.value = value;
|
||||
|
||||
let count = 0;
|
||||
FormHistory.count(obj, { handleResult: function (result) count = result,
|
||||
handleError: function (error) {
|
||||
do_throw("Error occurred searching form history: " + error);
|
||||
},
|
||||
handleCompletion: function (reason) { if (!reason) then(count); }
|
||||
});
|
||||
}
|
||||
|
||||
// Perform a single form history update and call then() when done.
|
||||
function updateEntry(op, name, value, then) {
|
||||
var obj = { op: op };
|
||||
if (name !== null)
|
||||
obj.fieldname = name;
|
||||
if (value !== null)
|
||||
obj.value = value;
|
||||
updateFormHistory(obj, then);
|
||||
}
|
||||
|
||||
// Add a single form history entry with the current time and call then() when done.
|
||||
function addEntry(name, value, then) {
|
||||
let now = Date.now() * 1000;
|
||||
updateFormHistory({ op: "add", fieldname: name, value: value, timesUsed: 1,
|
||||
firstUsed: now, lastUsed: now }, then);
|
||||
}
|
||||
|
||||
// Wrapper around FormHistory.update which handles errors. Calls then() when done.
|
||||
function updateFormHistory(changes, then) {
|
||||
FormHistory.update(changes, { handleError: function (error) {
|
||||
do_throw("Error occurred updating form history: " + error);
|
||||
},
|
||||
handleCompletion: function (reason) { if (!reason) then(); },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs info to the console in the standard way (includes the filename).
|
||||
*
|
||||
* @param aMessage
|
||||
* The message to log to the console.
|
||||
*/
|
||||
function do_log_info(aMessage) {
|
||||
print("TEST-INFO | " + _TEST_FILE + " | " + aMessage);
|
||||
function getGUIDforID(conn, id) {
|
||||
var stmt = conn.createStatement("SELECT guid from moz_formhistory WHERE id = " + id);
|
||||
stmt.executeStep();
|
||||
var guid = stmt.getString(0);
|
||||
stmt.finalize();
|
||||
return guid;
|
||||
}
|
||||
|
@ -1,168 +0,0 @@
|
||||
/* 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 dbFile, oldSize;
|
||||
var currentTestIndex = 0;
|
||||
|
||||
function triggerExpiration() {
|
||||
// We can't easily fake a "daily idle" event, so for testing purposes form
|
||||
// history listens for another notification to trigger an immediate
|
||||
// expiration.
|
||||
Services.obs.notifyObservers(null, "formhistory-expire-now", null);
|
||||
}
|
||||
|
||||
let checkExists = function(num) { do_check_true(num > 0); next_test(); }
|
||||
let checkNotExists = function(num) { do_check_true(!num); next_test(); }
|
||||
|
||||
var TestObserver = {
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
||||
|
||||
observe : function (subject, topic, data) {
|
||||
do_check_eq(topic, "satchel-storage-changed");
|
||||
|
||||
if (data == "formhistory-expireoldentries") {
|
||||
next_test();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function test_finished() {
|
||||
// Make sure we always reset prefs.
|
||||
if (Services.prefs.prefHasUserValue("browser.formfill.expire_days"))
|
||||
Services.prefs.clearUserPref("browser.formfill.expire_days");
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
let iter = tests();
|
||||
|
||||
function run_test()
|
||||
{
|
||||
do_test_pending();
|
||||
iter.next();
|
||||
}
|
||||
|
||||
function next_test()
|
||||
{
|
||||
iter.next();
|
||||
}
|
||||
|
||||
function tests()
|
||||
{
|
||||
Services.obs.addObserver(TestObserver, "satchel-storage-changed", true);
|
||||
|
||||
// ===== test init =====
|
||||
var testfile = do_get_file("asyncformhistory_expire.sqlite");
|
||||
var profileDir = do_get_profile();
|
||||
|
||||
// Cleanup from any previous tests or failures.
|
||||
dbFile = profileDir.clone();
|
||||
dbFile.append("formhistory.sqlite");
|
||||
if (dbFile.exists())
|
||||
dbFile.remove(false);
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_true(dbFile.exists());
|
||||
|
||||
// We're going to clear this at the end, so it better have the default value now.
|
||||
do_check_false(Services.prefs.prefHasUserValue("browser.formfill.expire_days"));
|
||||
|
||||
// Sanity check initial state
|
||||
yield countEntries(null, null, function(num) { do_check_eq(508, num); next_test(); });
|
||||
yield countEntries("name-A", "value-A", checkExists); // lastUsed == distant past
|
||||
yield countEntries("name-B", "value-B", checkExists); // lastUsed == distant future
|
||||
|
||||
do_check_eq(CURRENT_SCHEMA, FormHistory.schemaVersion);
|
||||
|
||||
// Add a new entry
|
||||
yield countEntries("name-C", "value-C", checkNotExists);
|
||||
yield addEntry("name-C", "value-C", next_test);
|
||||
yield countEntries("name-C", "value-C", checkExists);
|
||||
|
||||
// Update some existing entries to have ages relative to when the test runs.
|
||||
var now = 1000 * Date.now();
|
||||
let updateLastUsed = function updateLastUsedFn(results, age)
|
||||
{
|
||||
let lastUsed = now - age * 24 * PR_HOURS;
|
||||
|
||||
let changes = [ ];
|
||||
for (let r = 0; r < results.length; r++) {
|
||||
changes.push({ op: "update", lastUsed: lastUsed, guid: results[r].guid });
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
let results = yield searchEntries(["guid"], { lastUsed: 181 }, iter);
|
||||
yield updateFormHistory(updateLastUsed(results, 181), next_test);
|
||||
|
||||
results = yield searchEntries(["guid"], { lastUsed: 179 }, iter);
|
||||
yield updateFormHistory(updateLastUsed(results, 179), next_test);
|
||||
|
||||
results = yield searchEntries(["guid"], { lastUsed: 31 }, iter);
|
||||
yield updateFormHistory(updateLastUsed(results, 31), next_test);
|
||||
|
||||
results = yield searchEntries(["guid"], { lastUsed: 29 }, iter);
|
||||
yield updateFormHistory(updateLastUsed(results, 29), next_test);
|
||||
|
||||
results = yield searchEntries(["guid"], { lastUsed: 9999 }, iter);
|
||||
yield updateFormHistory(updateLastUsed(results, 11), next_test);
|
||||
|
||||
results = yield searchEntries(["guid"], { lastUsed: 9 }, iter);
|
||||
yield updateFormHistory(updateLastUsed(results, 9), next_test);
|
||||
|
||||
yield countEntries("name-A", "value-A", checkExists);
|
||||
yield countEntries("181DaysOld", "foo", checkExists);
|
||||
yield countEntries("179DaysOld", "foo", checkExists);
|
||||
yield countEntries(null, null, function(num) { do_check_eq(509, num); next_test(); });
|
||||
|
||||
// 2 entries are expected to expire.
|
||||
triggerExpiration();
|
||||
yield;
|
||||
|
||||
yield countEntries("name-A", "value-A", checkNotExists);
|
||||
yield countEntries("181DaysOld", "foo", checkNotExists);
|
||||
yield countEntries("179DaysOld", "foo", checkExists);
|
||||
yield countEntries(null, null, function(num) { do_check_eq(507, num); next_test(); });
|
||||
|
||||
// And again. No change expected.
|
||||
triggerExpiration();
|
||||
yield;
|
||||
|
||||
yield countEntries(null, null, function(num) { do_check_eq(507, num); next_test(); });
|
||||
|
||||
// Set formfill pref to 30 days.
|
||||
Services.prefs.setIntPref("browser.formfill.expire_days", 30);
|
||||
yield countEntries("179DaysOld", "foo", checkExists);
|
||||
yield countEntries("bar", "31days", checkExists);
|
||||
yield countEntries("bar", "29days", checkExists);
|
||||
yield countEntries(null, null, function(num) { do_check_eq(507, num); next_test(); });
|
||||
|
||||
triggerExpiration();
|
||||
yield;
|
||||
|
||||
yield countEntries("179DaysOld", "foo", checkNotExists);
|
||||
yield countEntries("bar", "31days", checkNotExists);
|
||||
yield countEntries("bar", "29days", checkExists);
|
||||
yield countEntries(null, null, function(num) { do_check_eq(505, num); next_test(); });
|
||||
|
||||
// Set override pref to 10 days and expire. This expires a large batch of
|
||||
// entries, and should trigger a VACCUM to reduce file size.
|
||||
Services.prefs.setIntPref("browser.formfill.expire_days", 10);
|
||||
|
||||
yield countEntries("bar", "29days", checkExists);
|
||||
yield countEntries("9DaysOld", "foo", checkExists);
|
||||
yield countEntries(null, null, function(num) { do_check_eq(505, num); next_test(); });
|
||||
|
||||
triggerExpiration();
|
||||
yield;
|
||||
|
||||
yield countEntries("bar", "29days", checkNotExists);
|
||||
yield countEntries("9DaysOld", "foo", checkExists);
|
||||
yield countEntries("name-B", "value-B", checkExists);
|
||||
yield countEntries("name-C", "value-C", checkExists);
|
||||
yield countEntries(null, null, function(num) { do_check_eq(3, num); next_test(); });
|
||||
|
||||
test_finished();
|
||||
};
|
@ -3,13 +3,20 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var testnum = 0;
|
||||
var fh;
|
||||
var fac;
|
||||
var prefs;
|
||||
|
||||
let numRecords, timeGroupingSize, now;
|
||||
|
||||
const DEFAULT_EXPIRE_DAYS = 180;
|
||||
|
||||
function countAllEntries() {
|
||||
let stmt = fh.DBConnection.createStatement("SELECT COUNT(*) as numEntries FROM moz_formhistory");
|
||||
do_check_true(stmt.executeStep());
|
||||
let numEntries = stmt.row.numEntries;
|
||||
stmt.finalize();
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
function padLeft(number, length) {
|
||||
var str = number + '';
|
||||
while (str.length < length)
|
||||
@ -17,7 +24,7 @@ function padLeft(number, length) {
|
||||
return str;
|
||||
}
|
||||
|
||||
function getFormExpiryDays() {
|
||||
function getFormExpiryDays () {
|
||||
if (prefs.prefHasUserValue("browser.formfill.expire_days"))
|
||||
return prefs.getIntPref("browser.formfill.expire_days");
|
||||
else
|
||||
@ -25,213 +32,205 @@ function getFormExpiryDays() {
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// ===== test init =====
|
||||
var testfile = do_get_file("formhistory_autocomplete.sqlite");
|
||||
var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
try {
|
||||
|
||||
// Cleanup from any previous tests or failures.
|
||||
var destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
if (destFile.exists())
|
||||
destFile.remove(false);
|
||||
// ===== test init =====
|
||||
var testfile = do_get_file("formhistory_autocomplete.sqlite");
|
||||
var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
// Cleanup from any previous tests or failures.
|
||||
var destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
if (destFile.exists())
|
||||
destFile.remove(false);
|
||||
|
||||
fac = Cc["@mozilla.org/satchel/form-autocomplete;1"].
|
||||
getService(Ci.nsIFormAutoComplete);
|
||||
prefs = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
|
||||
timeGroupingSize = prefs.getIntPref("browser.formfill.timeGroupingSize") * 1000 * 1000;
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
fac = Cc["@mozilla.org/satchel/form-autocomplete;1"].
|
||||
getService(Ci.nsIFormAutoComplete);
|
||||
prefs = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
|
||||
run_next_test();
|
||||
var timeGroupingSize = prefs.getIntPref("browser.formfill.timeGroupingSize") * 1000 * 1000;
|
||||
var maxTimeGroupings = prefs.getIntPref("browser.formfill.maxTimeGroupings");
|
||||
var bucketSize = prefs.getIntPref("browser.formfill.bucketSize");
|
||||
|
||||
// ===== Tests with constant timesUsed and varying lastUsed date =====
|
||||
// insert 2 records per bucket to check alphabetical sort within
|
||||
var now = 1000 * Date.now();
|
||||
var numRecords = Math.ceil(maxTimeGroupings / bucketSize) * 2;
|
||||
|
||||
fh.DBConnection.beginTransaction();
|
||||
for (let i = 0; i < numRecords; i+=2) {
|
||||
let useDate = now - (i/2 * bucketSize * timeGroupingSize);
|
||||
|
||||
fh.DBConnection.executeSimpleSQL(
|
||||
"INSERT INTO moz_formhistory "+
|
||||
"(fieldname, value, timesUsed, firstUsed, lastUsed) " +
|
||||
"VALUES ("+
|
||||
"'field1', " +
|
||||
"'value" + padLeft(numRecords - 1 - i, 2) + "', " +
|
||||
"1, " +
|
||||
(useDate + 1) + ", " +
|
||||
(useDate + 1) +
|
||||
");");
|
||||
|
||||
fh.DBConnection.executeSimpleSQL(
|
||||
"INSERT INTO moz_formhistory "+
|
||||
"(fieldname, value, timesUsed, firstUsed, lastUsed) " +
|
||||
"VALUES ("+
|
||||
"'field1', " +
|
||||
"'value" + padLeft(numRecords - 2 - i, 2) + "', " +
|
||||
"1, " +
|
||||
useDate + ", " +
|
||||
useDate +
|
||||
");");
|
||||
}
|
||||
fh.DBConnection.commitTransaction();
|
||||
|
||||
// ===== 1 =====
|
||||
// Check initial state is as expected
|
||||
testnum++;
|
||||
do_check_true(fh.hasEntries);
|
||||
do_check_eq(numRecords, countAllEntries());
|
||||
do_check_true(fh.nameExists("field1"));
|
||||
|
||||
// ===== 2 =====
|
||||
// Check search contains all entries
|
||||
testnum++;
|
||||
var results = fac.autoCompleteSearch("field1", "", null, null);
|
||||
do_check_eq(numRecords, results.matchCount);
|
||||
|
||||
// ===== 3 =====
|
||||
// Check search result ordering with empty search term
|
||||
testnum++;
|
||||
results = fac.autoCompleteSearch("field1", "", null, null);
|
||||
let lastFound = numRecords;
|
||||
for (let i = 0; i < numRecords; i+=2) {
|
||||
do_check_eq(parseInt(results.getValueAt(i + 1).substr(5), 10), --lastFound);
|
||||
do_check_eq(parseInt(results.getValueAt(i).substr(5), 10), --lastFound);
|
||||
}
|
||||
|
||||
// ===== 4 =====
|
||||
// Check search result ordering with "v"
|
||||
testnum++;
|
||||
results = fac.autoCompleteSearch("field1", "v", null, null);
|
||||
lastFound = numRecords;
|
||||
for (let i = 0; i < numRecords; i+=2) {
|
||||
do_check_eq(parseInt(results.getValueAt(i + 1).substr(5), 10), --lastFound);
|
||||
do_check_eq(parseInt(results.getValueAt(i).substr(5), 10), --lastFound);
|
||||
}
|
||||
|
||||
// ===== Tests with constant use dates and varying timesUsed =====
|
||||
|
||||
let timesUsedSamples = 20;
|
||||
fh.DBConnection.beginTransaction();
|
||||
for (let i = 0; i < timesUsedSamples; i++) {
|
||||
let timesUsed = (timesUsedSamples - i);
|
||||
fh.DBConnection.executeSimpleSQL(
|
||||
"INSERT INTO moz_formhistory "+
|
||||
"(fieldname, value, timesUsed, firstUsed, lastUsed) " +
|
||||
"VALUES ("+
|
||||
"'field2', "+
|
||||
"'value" + (timesUsedSamples - 1 - i) + "', " +
|
||||
timesUsed * timeGroupingSize + ", " +
|
||||
now + ", " +
|
||||
now +
|
||||
");");
|
||||
}
|
||||
fh.DBConnection.commitTransaction();
|
||||
|
||||
// ===== 5 =====
|
||||
// Check search result ordering with empty search term
|
||||
testnum++;
|
||||
results = fac.autoCompleteSearch("field2", "", null, null);
|
||||
lastFound = timesUsedSamples;
|
||||
for (let i = 0; i < timesUsedSamples; i++) {
|
||||
do_check_eq(parseInt(results.getValueAt(i).substr(5)), --lastFound);
|
||||
}
|
||||
|
||||
// ===== 6 =====
|
||||
// Check search result ordering with "v"
|
||||
testnum++;
|
||||
results = fac.autoCompleteSearch("field2", "v", null, null);
|
||||
lastFound = timesUsedSamples;
|
||||
for (let i = 0; i < timesUsedSamples; i++) {
|
||||
do_check_eq(parseInt(results.getValueAt(i).substr(5)), --lastFound);
|
||||
}
|
||||
|
||||
// ===== 7 =====
|
||||
// Check that "senior citizen" entries get a bonus (browser.formfill.agedBonus)
|
||||
testnum++;
|
||||
|
||||
let agedDate = 1000 * (Date.now() - getFormExpiryDays() * 24 * 60 * 60 * 1000);
|
||||
fh.DBConnection.executeSimpleSQL(
|
||||
"INSERT INTO moz_formhistory "+
|
||||
"(fieldname, value, timesUsed, firstUsed, lastUsed) " +
|
||||
"VALUES ("+
|
||||
"'field3', " +
|
||||
"'old but not senior', " +
|
||||
"100, " +
|
||||
(agedDate + 60 * 1000 * 1000) + ", " +
|
||||
now +
|
||||
");");
|
||||
fh.DBConnection.executeSimpleSQL(
|
||||
"INSERT INTO moz_formhistory "+
|
||||
"(fieldname, value, timesUsed, firstUsed, lastUsed) " +
|
||||
"VALUES ("+
|
||||
"'field3', " +
|
||||
"'senior citizen', " +
|
||||
"100, " +
|
||||
(agedDate - 60 * 1000 * 1000) + ", " +
|
||||
now +
|
||||
");");
|
||||
|
||||
results = fac.autoCompleteSearch("field3", "", null, null);
|
||||
do_check_eq(results.getValueAt(0), "senior citizen");
|
||||
do_check_eq(results.getValueAt(1), "old but not senior");
|
||||
|
||||
// ===== 8 =====
|
||||
// Check entries that are really old or in the future
|
||||
testnum++;
|
||||
fh.DBConnection.executeSimpleSQL(
|
||||
"INSERT INTO moz_formhistory "+
|
||||
"(fieldname, value, timesUsed, firstUsed, lastUsed) " +
|
||||
"VALUES ("+
|
||||
"'field4', " +
|
||||
"'date of 0', " +
|
||||
"1, " +
|
||||
0 + ", " +
|
||||
0 +
|
||||
");");
|
||||
|
||||
fh.DBConnection.executeSimpleSQL(
|
||||
"INSERT INTO moz_formhistory "+
|
||||
"(fieldname, value, timesUsed, firstUsed, lastUsed) " +
|
||||
"VALUES ("+
|
||||
"'field4', " +
|
||||
"'in the future 1', " +
|
||||
"1, " +
|
||||
0 + ", " +
|
||||
(now * 2) +
|
||||
");");
|
||||
|
||||
fh.DBConnection.executeSimpleSQL(
|
||||
"INSERT INTO moz_formhistory "+
|
||||
"(fieldname, value, timesUsed, firstUsed, lastUsed) " +
|
||||
"VALUES ("+
|
||||
"'field4', " +
|
||||
"'in the future 2', " +
|
||||
"1, " +
|
||||
(now * 2) + ", " +
|
||||
(now * 2) +
|
||||
");");
|
||||
|
||||
results = fac.autoCompleteSearch("field4", "", null, null);
|
||||
do_check_eq(results.matchCount, 3);
|
||||
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
}
|
||||
|
||||
add_test(function test0() {
|
||||
var maxTimeGroupings = prefs.getIntPref("browser.formfill.maxTimeGroupings");
|
||||
var bucketSize = prefs.getIntPref("browser.formfill.bucketSize");
|
||||
|
||||
// ===== Tests with constant timesUsed and varying lastUsed date =====
|
||||
// insert 2 records per bucket to check alphabetical sort within
|
||||
now = 1000 * Date.now();
|
||||
numRecords = Math.ceil(maxTimeGroupings / bucketSize) * 2;
|
||||
|
||||
let changes = [ ];
|
||||
for (let i = 0; i < numRecords; i+=2) {
|
||||
let useDate = now - (i/2 * bucketSize * timeGroupingSize);
|
||||
|
||||
changes.push({ op : "add", fieldname: "field1", value: "value" + padLeft(numRecords - 1 - i, 2),
|
||||
timesUsed: 1, firstUsed: useDate, lastUsed: useDate });
|
||||
changes.push({ op : "add", fieldname: "field1", value: "value" + padLeft(numRecords - 2 - i, 2),
|
||||
timesUsed: 1, firstUsed: useDate, lastUsed: useDate });
|
||||
}
|
||||
|
||||
updateFormHistory(changes, run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test1() {
|
||||
do_log_info("Check initial state is as expected");
|
||||
|
||||
countEntries(null, null, function (count) {
|
||||
countEntries("field1", null, function (count) {
|
||||
do_check_true(count > 0);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test2() {
|
||||
do_log_info("Check search contains all entries");
|
||||
|
||||
fac.autoCompleteSearchAsync("field1", "", null, null, {
|
||||
onSearchCompletion : function(aResults) {
|
||||
do_check_eq(numRecords, aResults.matchCount);
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test3() {
|
||||
do_log_info("Check search result ordering with empty search term");
|
||||
|
||||
let lastFound = numRecords;
|
||||
fac.autoCompleteSearchAsync("field1", "", null, null, {
|
||||
onSearchCompletion : function(aResults) {
|
||||
for (let i = 0; i < numRecords; i+=2) {
|
||||
do_check_eq(parseInt(aResults.getValueAt(i + 1).substr(5), 10), --lastFound);
|
||||
do_check_eq(parseInt(aResults.getValueAt(i).substr(5), 10), --lastFound);
|
||||
}
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test4() {
|
||||
do_log_info("Check search result ordering with \"v\"");
|
||||
|
||||
let lastFound = numRecords;
|
||||
fac.autoCompleteSearchAsync("field1", "v", null, null, {
|
||||
onSearchCompletion : function(aResults) {
|
||||
for (let i = 0; i < numRecords; i+=2) {
|
||||
do_check_eq(parseInt(aResults.getValueAt(i + 1).substr(5), 10), --lastFound);
|
||||
do_check_eq(parseInt(aResults.getValueAt(i).substr(5), 10), --lastFound);
|
||||
}
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const timesUsedSamples = 20;
|
||||
|
||||
add_test(function test5() {
|
||||
do_log_info("Begin tests with constant use dates and varying timesUsed");
|
||||
|
||||
let changes = [];
|
||||
for (let i = 0; i < timesUsedSamples; i++) {
|
||||
let timesUsed = (timesUsedSamples - i);
|
||||
let change = { op : "add", fieldname: "field2", value: "value" + (timesUsedSamples - 1 - i),
|
||||
timesUsed: timesUsed * timeGroupingSize, firstUsed: now, lastUsed: now };
|
||||
changes.push(change);
|
||||
}
|
||||
updateFormHistory(changes, run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test6() {
|
||||
do_log_info("Check search result ordering with empty search term");
|
||||
|
||||
let lastFound = timesUsedSamples;
|
||||
fac.autoCompleteSearchAsync("field2", "", null, null, {
|
||||
onSearchCompletion : function(aResults) {
|
||||
for (let i = 0; i < timesUsedSamples; i++) {
|
||||
do_check_eq(parseInt(aResults.getValueAt(i).substr(5)), --lastFound);
|
||||
}
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test7() {
|
||||
do_log_info("Check search result ordering with \"v\"");
|
||||
|
||||
let lastFound = timesUsedSamples;
|
||||
fac.autoCompleteSearchAsync("field2", "v", null, null, {
|
||||
onSearchCompletion : function(aResults) {
|
||||
for (let i = 0; i < timesUsedSamples; i++) {
|
||||
do_check_eq(parseInt(aResults.getValueAt(i).substr(5)), --lastFound);
|
||||
}
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test8() {
|
||||
do_log_info("Check that \"senior citizen\" entries get a bonus (browser.formfill.agedBonus)");
|
||||
|
||||
let agedDate = 1000 * (Date.now() - getFormExpiryDays() * 24 * 60 * 60 * 1000);
|
||||
|
||||
let changes = [ ];
|
||||
changes.push({ op : "add", fieldname: "field3", value: "old but not senior",
|
||||
timesUsed: 100, firstUsed: (agedDate + 60 * 1000 * 1000), lastUsed: now });
|
||||
changes.push({ op : "add", fieldname: "field3", value: "senior citizen",
|
||||
timesUsed: 100, firstUsed: (agedDate - 60 * 1000 * 1000), lastUsed: now });
|
||||
updateFormHistory(changes, run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test9() {
|
||||
fac.autoCompleteSearchAsync("field3", "", null, null, {
|
||||
onSearchCompletion : function(aResults) {
|
||||
do_check_eq(aResults.getValueAt(0), "senior citizen");
|
||||
do_check_eq(aResults.getValueAt(1), "old but not senior");
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test10() {
|
||||
do_log_info("Check entries that are really old or in the future");
|
||||
|
||||
let changes = [ ];
|
||||
changes.push({ op : "add", fieldname: "field4", value: "date of 0",
|
||||
timesUsed: 1, firstUsed: 0, lastUsed: 0 });
|
||||
changes.push({ op : "add", fieldname: "field4", value: "in the future 1",
|
||||
timesUsed: 1, firstUsed: 0, lastUsed: now * 2 });
|
||||
changes.push({ op : "add", fieldname: "field4", value: "in the future 2",
|
||||
timesUsed: 1, firstUsed: now * 2, lastUsed: now * 2 });
|
||||
updateFormHistory(changes, run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test11() {
|
||||
fac.autoCompleteSearchAsync("field4", "", null, null, {
|
||||
onSearchCompletion : function(aResults) {
|
||||
do_check_eq(aResults.matchCount, 3);
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let syncValues = ["sync1", "sync1a", "sync2", "sync3"]
|
||||
|
||||
add_test(function test12() {
|
||||
do_log_info("Check old synchronous api");
|
||||
|
||||
let changes = [ ];
|
||||
for (let value of syncValues) {
|
||||
changes.push({ op : "add", fieldname: "field5", value: value });
|
||||
}
|
||||
updateFormHistory(changes, run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test13() {
|
||||
let autocompleteService = Cc["@mozilla.org/satchel/form-autocomplete;1"].getService(Ci.nsIFormAutoComplete);
|
||||
let results = autocompleteService.autoCompleteSearch("field5", "", null, null);
|
||||
do_check_eq(results.matchCount, syncValues.length, "synchronous matchCount");
|
||||
for (let i = 0; i < results.matchCount; i++) {
|
||||
do_check_eq(results.getValueAt(i), syncValues[i]);
|
||||
}
|
||||
|
||||
let results = autocompleteService.autoCompleteSearch("field5", "sync1", null, null);
|
||||
do_check_eq(results.matchCount, 2, "synchronous matchCount");
|
||||
do_check_eq(results.getValueAt(0), "sync1");
|
||||
do_check_eq(results.getValueAt(1), "sync1a");
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -2,88 +2,65 @@
|
||||
* 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/. */
|
||||
|
||||
let bakFile;
|
||||
function run_test()
|
||||
{
|
||||
try {
|
||||
var testnum = 0;
|
||||
|
||||
function run_test() {
|
||||
// ===== test init =====
|
||||
let testfile = do_get_file("formhistory_CORRUPT.sqlite");
|
||||
let profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
var testfile = do_get_file("formhistory_CORRUPT.sqlite");
|
||||
var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
// Cleanup from any previous tests or failures.
|
||||
let destFile = profileDir.clone();
|
||||
var destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
if (destFile.exists())
|
||||
destFile.remove(false);
|
||||
|
||||
bakFile = profileDir.clone();
|
||||
var bakFile = profileDir.clone();
|
||||
bakFile.append("formhistory.sqlite.corrupt");
|
||||
if (bakFile.exists())
|
||||
bakFile.remove(false);
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(function test_corruptFormHistoryDB_lazyCorruptInit1() {
|
||||
do_log_info("ensure FormHistory backs up a corrupt DB on initialization.");
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
// Open the DB, ensure that a backup of the corrupt DB is made.
|
||||
do_check_false(bakFile.exists());
|
||||
var fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
// DB init is done lazily so the DB shouldn't be created yet.
|
||||
do_check_false(bakFile.exists());
|
||||
// Doing any request to the DB should create it.
|
||||
countEntries(null, null, run_next_test);
|
||||
});
|
||||
|
||||
add_test(function test_corruptFormHistoryDB_lazyCorruptInit2() {
|
||||
fh.DBConnection;
|
||||
do_check_true(bakFile.exists());
|
||||
bakFile.remove(false);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// ===== 2 =====
|
||||
testnum++;
|
||||
// File should be empty
|
||||
do_check_false(fh.hasEntries);
|
||||
do_check_false(fh.entryExists("name-A", "value-A"));
|
||||
|
||||
|
||||
add_test(function test_corruptFormHistoryDB_emptyInit() {
|
||||
do_log_info("test that FormHistory initializes an empty DB in place of corrupt DB.");
|
||||
// ===== 3 =====
|
||||
testnum++;
|
||||
// Try adding an entry
|
||||
fh.addEntry("name-A", "value-A");
|
||||
do_check_true(fh.hasEntries);
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
|
||||
FormHistory.count({}, {
|
||||
handleResult : function(aNumEntries) {
|
||||
do_check_true(aNumEntries == 0);
|
||||
FormHistory.count({ fieldname : "name-A", value : "value-A" }, {
|
||||
handleResult : function(aNumEntries2) {
|
||||
do_check_true(aNumEntries2 == 0);
|
||||
run_next_test();
|
||||
},
|
||||
handleError : function(aError2) {
|
||||
do_throw("DB initialized after reading a corrupt DB file found an entry.");
|
||||
}
|
||||
});
|
||||
},
|
||||
handleError : function (aError) {
|
||||
do_throw("DB initialized after reading a corrupt DB file is not empty.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_corruptFormHistoryDB_addEntry() {
|
||||
do_log_info("test adding an entry to the empty DB.");
|
||||
// ===== 4 =====
|
||||
testnum++;
|
||||
// Try removing an entry
|
||||
fh.removeEntry("name-A", "value-A");
|
||||
do_check_false(fh.hasEntries);
|
||||
do_check_false(fh.entryExists("name-A", "value-A"));
|
||||
|
||||
updateEntry("add", "name-A", "value-A",
|
||||
function() {
|
||||
countEntries("name-A", "value-A",
|
||||
function(count) {
|
||||
do_check_true(count == 1);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_corruptFormHistoryDB_removeEntry() {
|
||||
do_log_info("test removing an entry to the empty DB.");
|
||||
|
||||
updateEntry("remove", "name-A", "value-A",
|
||||
function() {
|
||||
countEntries("name-A", "value-A",
|
||||
function(count) {
|
||||
do_check_true(count == 0);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
}
|
||||
|
143
toolkit/components/satchel/test/unit/test_db_update_v1.js
Normal file
143
toolkit/components/satchel/test/unit/test_db_update_v1.js
Normal file
@ -0,0 +1,143 @@
|
||||
/* 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/. */
|
||||
|
||||
// Returns true if the timestamp is within 30 seconds of now.
|
||||
function is_about_now(timestamp) {
|
||||
var delta = Math.abs(timestamp - 1000 * Date.now());
|
||||
var seconds = 30 * 1000000;
|
||||
return delta < seconds;
|
||||
}
|
||||
|
||||
var testnum = 0;
|
||||
var fh;
|
||||
var timesUsed, firstUsed, lastUsed;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
try {
|
||||
|
||||
// ===== test init =====
|
||||
var testfile = do_get_file("formhistory_v0.sqlite");
|
||||
var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
// Cleanup from any previous tests or failures.
|
||||
var destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
if (destFile.exists())
|
||||
destFile.remove(false);
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_eq(0, getDBVersion(testfile));
|
||||
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
// Check for expected contents.
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
do_check_true(fh.entryExists("name-B", "value-B"));
|
||||
do_check_true(fh.entryExists("name-C", "value-C1"));
|
||||
do_check_true(fh.entryExists("name-C", "value-C2"));
|
||||
// check for upgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
|
||||
|
||||
// ===== 2 =====
|
||||
testnum++;
|
||||
// Check that timestamps were created correctly.
|
||||
|
||||
var query = "SELECT timesUsed, firstUsed, lastUsed " +
|
||||
"FROM moz_formhistory WHERE fieldname = 'name-A'";
|
||||
var stmt = fh.DBConnection.createStatement(query);
|
||||
stmt.executeStep();
|
||||
|
||||
timesUsed = stmt.getInt32(0);
|
||||
firstUsed = stmt.getInt64(1);
|
||||
lastUsed = stmt.getInt64(2);
|
||||
stmt.finalize();
|
||||
|
||||
do_check_eq(1, timesUsed);
|
||||
do_check_true(firstUsed == lastUsed);
|
||||
// Upgraded entries timestamped 24 hours in the past.
|
||||
do_check_true(is_about_now(firstUsed + 24 * PR_HOURS));
|
||||
|
||||
|
||||
// ===== 3 =====
|
||||
testnum++;
|
||||
// Exercise adding and removing a name/value pair
|
||||
do_check_false(fh.entryExists("name-D", "value-D"));
|
||||
fh.addEntry("name-D", "value-D");
|
||||
do_check_true(fh.entryExists("name-D", "value-D"));
|
||||
fh.removeEntry("name-D", "value-D");
|
||||
do_check_false(fh.entryExists("name-D", "value-D"));
|
||||
|
||||
|
||||
// ===== 4 =====
|
||||
testnum++;
|
||||
// Add a new entry, check expected properties
|
||||
do_check_false(fh.entryExists("name-E", "value-E"));
|
||||
fh.addEntry("name-E", "value-E");
|
||||
do_check_true(fh.entryExists("name-E", "value-E"));
|
||||
|
||||
query = "SELECT timesUsed, firstUsed, lastUsed " +
|
||||
"FROM moz_formhistory WHERE fieldname = 'name-E'";
|
||||
stmt = fh.DBConnection.createStatement(query);
|
||||
stmt.executeStep();
|
||||
|
||||
timesUsed = stmt.getInt32(0);
|
||||
firstUsed = stmt.getInt64(1);
|
||||
lastUsed = stmt.getInt64(2);
|
||||
stmt.finalize();
|
||||
|
||||
do_check_eq(1, timesUsed);
|
||||
do_check_true(firstUsed == lastUsed);
|
||||
do_check_true(is_about_now(firstUsed));
|
||||
|
||||
// The next test adds the entry again, and check to see that the lastUsed
|
||||
// field is updated. Unfortunately, on Windows PR_Now() is granular
|
||||
// (robarnold says usually 16.5ms, sometimes 10ms), so if we execute the
|
||||
// test too soon the timestamp will be the same! So, we'll wait a short
|
||||
// period of time to make sure the timestamp will differ.
|
||||
do_test_pending();
|
||||
do_timeout(50, delayed_test);
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
}
|
||||
|
||||
function delayed_test() {
|
||||
try {
|
||||
|
||||
// ===== 5 =====
|
||||
testnum++;
|
||||
// Add entry again, check for updated properties.
|
||||
do_check_true(fh.entryExists("name-E", "value-E"));
|
||||
fh.addEntry("name-E", "value-E");
|
||||
do_check_true(fh.entryExists("name-E", "value-E"));
|
||||
|
||||
var query = "SELECT timesUsed, firstUsed, lastUsed " +
|
||||
"FROM moz_formhistory WHERE fieldname = 'name-E'";
|
||||
var stmt = fh.DBConnection.createStatement(query);
|
||||
stmt.executeStep();
|
||||
|
||||
timesUsed = stmt.getInt32(0);
|
||||
var firstUsed2 = stmt.getInt64(1);
|
||||
var lastUsed2 = stmt.getInt64(2);
|
||||
stmt.finalize();
|
||||
|
||||
do_check_eq(2, timesUsed);
|
||||
do_check_true(is_about_now(lastUsed2));
|
||||
|
||||
do_check_true(firstUsed == firstUsed2); //unchanged
|
||||
do_check_true(lastUsed != lastUsed2); //changed
|
||||
do_check_true(firstUsed2 != lastUsed2);
|
||||
|
||||
do_test_finished();
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
}
|
90
toolkit/components/satchel/test/unit/test_db_update_v1b.js
Normal file
90
toolkit/components/satchel/test/unit/test_db_update_v1b.js
Normal file
@ -0,0 +1,90 @@
|
||||
/* 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/. */
|
||||
|
||||
// Returns true if the timestamp is within 30 seconds of now.
|
||||
function is_about_now(timestamp) {
|
||||
var delta = Math.abs(timestamp - 1000 * Date.now());
|
||||
var seconds = 30 * 1000000;
|
||||
return delta < seconds;
|
||||
}
|
||||
|
||||
var testnum = 0;
|
||||
var fh;
|
||||
var timesUsed, firstUsed, lastUsed;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
try {
|
||||
|
||||
// ===== test init =====
|
||||
var testfile = do_get_file("formhistory_v0v1.sqlite");
|
||||
var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
// Cleanup from any previous tests or failures.
|
||||
var destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
if (destFile.exists())
|
||||
destFile.remove(false);
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_eq(0, getDBVersion(testfile));
|
||||
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
// Check for expected contents.
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
do_check_true(fh.entryExists("name-B", "value-B"));
|
||||
do_check_true(fh.entryExists("name-C", "value-C1"));
|
||||
do_check_true(fh.entryExists("name-C", "value-C2"));
|
||||
do_check_true(fh.entryExists("name-D", "value-D"));
|
||||
// check for upgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
|
||||
// ===== 2 =====
|
||||
testnum++;
|
||||
|
||||
// The name-D entry was added by v0 code, so no timestamps were set. Make
|
||||
// sure the upgrade set timestamps on that entry.
|
||||
var query = "SELECT timesUsed, firstUsed, lastUsed " +
|
||||
"FROM moz_formhistory WHERE fieldname = 'name-D'";
|
||||
var stmt = fh.DBConnection.createStatement(query);
|
||||
stmt.executeStep();
|
||||
|
||||
timesUsed = stmt.getInt32(0);
|
||||
firstUsed = stmt.getInt64(1);
|
||||
lastUsed = stmt.getInt64(2);
|
||||
stmt.finalize();
|
||||
|
||||
do_check_eq(1, timesUsed);
|
||||
do_check_true(firstUsed == lastUsed);
|
||||
// Upgraded entries timestamped 24 hours in the past.
|
||||
do_check_true(is_about_now(firstUsed + 24 * PR_HOURS));
|
||||
|
||||
|
||||
// ===== 3 =====
|
||||
testnum++;
|
||||
|
||||
// Check to make sure the existing timestamps are unmodified.
|
||||
var query = "SELECT timesUsed, firstUsed, lastUsed " +
|
||||
"FROM moz_formhistory WHERE fieldname = 'name-A'";
|
||||
var stmt = fh.DBConnection.createStatement(query);
|
||||
stmt.executeStep();
|
||||
|
||||
timesUsed = stmt.getInt32(0);
|
||||
firstUsed = stmt.getInt64(1);
|
||||
lastUsed = stmt.getInt64(2);
|
||||
stmt.finalize();
|
||||
|
||||
do_check_eq(1, timesUsed);
|
||||
do_check_eq(lastUsed, 1231984073012182);
|
||||
do_check_eq(firstUsed, 1231984073012182);
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
}
|
55
toolkit/components/satchel/test/unit/test_db_update_v2.js
Normal file
55
toolkit/components/satchel/test/unit/test_db_update_v2.js
Normal file
@ -0,0 +1,55 @@
|
||||
/* 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 testnum = 0;
|
||||
var fh;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
try {
|
||||
|
||||
// ===== test init =====
|
||||
var testfile = do_get_file("formhistory_v1.sqlite");
|
||||
var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
// Cleanup from any previous tests or failures.
|
||||
var destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
if (destFile.exists())
|
||||
destFile.remove(false);
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_eq(1, getDBVersion(testfile));
|
||||
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
|
||||
// Check that the index was added (which is all the v2 upgrade does)
|
||||
do_check_true(fh.DBConnection.indexExists("moz_formhistory_lastused_index"));
|
||||
// check for upgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
// Check that old table was removed
|
||||
do_check_false(fh.DBConnection.tableExists("moz_dummy_table"));
|
||||
|
||||
|
||||
// ===== 2 =====
|
||||
testnum++;
|
||||
|
||||
// Just sanity check for expected contents and that DB is working.
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
do_check_false(fh.entryExists("name-B", "value-B"));
|
||||
fh.addEntry("name-B", "value-B");
|
||||
do_check_true(fh.entryExists("name-B", "value-B"));
|
||||
fh.removeEntry("name-B", "value-B");
|
||||
do_check_false(fh.entryExists("name-B", "value-B"));
|
||||
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
}
|
55
toolkit/components/satchel/test/unit/test_db_update_v2b.js
Normal file
55
toolkit/components/satchel/test/unit/test_db_update_v2b.js
Normal file
@ -0,0 +1,55 @@
|
||||
/* 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 testnum = 0;
|
||||
var fh;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
try {
|
||||
|
||||
// ===== test init =====
|
||||
var testfile = do_get_file("formhistory_v1v2.sqlite");
|
||||
var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
// Cleanup from any previous tests or failures.
|
||||
var destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
if (destFile.exists())
|
||||
destFile.remove(false);
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_eq(1, getDBVersion(testfile));
|
||||
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
|
||||
// Check that the index was added / still exists (which is all the v2 upgrade does)
|
||||
do_check_true(fh.DBConnection.indexExists("moz_formhistory_lastused_index"));
|
||||
// check for upgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
// Check that old table was removed
|
||||
do_check_false(fh.DBConnection.tableExists("moz_dummy_table"));
|
||||
|
||||
|
||||
// ===== 2 =====
|
||||
testnum++;
|
||||
|
||||
// Just sanity check for expected contents and that DB is working.
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
do_check_false(fh.entryExists("name-B", "value-B"));
|
||||
fh.addEntry("name-B", "value-B");
|
||||
do_check_true(fh.entryExists("name-B", "value-B"));
|
||||
fh.removeEntry("name-B", "value-B");
|
||||
do_check_false(fh.entryExists("name-B", "value-B"));
|
||||
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
}
|
52
toolkit/components/satchel/test/unit/test_db_update_v3.js
Normal file
52
toolkit/components/satchel/test/unit/test_db_update_v3.js
Normal file
@ -0,0 +1,52 @@
|
||||
/* 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 testnum = 0;
|
||||
var fh;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
try {
|
||||
|
||||
// ===== test init =====
|
||||
var testfile = do_get_file("formhistory_v2.sqlite");
|
||||
var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
// Cleanup from any previous tests or failures.
|
||||
var destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
if (destFile.exists())
|
||||
destFile.remove(false);
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_eq(2, getDBVersion(testfile));
|
||||
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
|
||||
// Check that the index was added
|
||||
do_check_true(fh.DBConnection.indexExists("moz_formhistory_guid_index"));
|
||||
// check for upgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
var guid = getGUIDforID(fh.DBConnection, 1);
|
||||
do_check_true(isGUID.test(guid));
|
||||
|
||||
// Add a new entry and check that it gets a GUID
|
||||
do_check_false(fh.entryExists("name-B", "value-B"));
|
||||
fh.addEntry("name-B", "value-B");
|
||||
do_check_true(fh.entryExists("name-B", "value-B"));
|
||||
|
||||
guid = getGUIDforID(fh.DBConnection, 2);
|
||||
do_check_true(isGUID.test(guid));
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
}
|
58
toolkit/components/satchel/test/unit/test_db_update_v3b.js
Normal file
58
toolkit/components/satchel/test/unit/test_db_update_v3b.js
Normal file
@ -0,0 +1,58 @@
|
||||
/* 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 testnum = 0;
|
||||
var fh;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
try {
|
||||
|
||||
// ===== test init =====
|
||||
var testfile = do_get_file("formhistory_v2v3.sqlite");
|
||||
var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
// Cleanup from any previous tests or failures.
|
||||
var destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
if (destFile.exists())
|
||||
destFile.remove(false);
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_eq(2, getDBVersion(testfile));
|
||||
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
|
||||
// Check that the index was added
|
||||
do_check_true(fh.DBConnection.indexExists("moz_formhistory_guid_index"));
|
||||
// check for upgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
|
||||
// Entry added by v3 code, has a GUID that shouldn't be changed.
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
var guid = getGUIDforID(fh.DBConnection, 1);
|
||||
do_check_eq(guid, "dgdaRfzsTnOOZ7wK");
|
||||
|
||||
// Entry added by v2 code after a downgrade, GUID should be assigned on upgrade.
|
||||
do_check_true(fh.entryExists("name-B", "value-B"));
|
||||
guid = getGUIDforID(fh.DBConnection, 2);
|
||||
do_check_true(isGUID.test(guid));
|
||||
|
||||
// Add a new entry and check that it gets a GUID
|
||||
do_check_false(fh.entryExists("name-C", "value-C"));
|
||||
fh.addEntry("name-C", "value-C");
|
||||
do_check_true(fh.entryExists("name-C", "value-C"));
|
||||
|
||||
guid = getGUIDforID(fh.DBConnection, 3);
|
||||
do_check_true(isGUID.test(guid));
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
}
|
@ -3,17 +3,9 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var testnum = 0;
|
||||
|
||||
let iter;
|
||||
var fh;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
do_test_pending();
|
||||
iter = next_test();
|
||||
iter.next();
|
||||
}
|
||||
|
||||
function next_test()
|
||||
{
|
||||
try {
|
||||
|
||||
@ -30,29 +22,19 @@ function next_test()
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_eq(3, getDBVersion(testfile));
|
||||
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
|
||||
destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
let dbConnection = Services.storage.openUnsharedDatabase(destFile);
|
||||
|
||||
// check for upgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, FormHistory.schemaVersion);
|
||||
|
||||
// Check that the index was added
|
||||
do_check_true(dbConnection.tableExists("moz_deleted_formhistory"));
|
||||
dbConnection.close();
|
||||
|
||||
do_check_true(fh.DBConnection.tableExists("moz_deleted_formhistory"));
|
||||
// check for upgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, FormHistory.schemaVersion);
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
// check that an entry still exists
|
||||
yield countEntries("name-A", "value-A",
|
||||
function (num) {
|
||||
do_check_true(num > 0);
|
||||
do_test_finished();
|
||||
}
|
||||
);
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
|
@ -3,17 +3,9 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var testnum = 0;
|
||||
|
||||
let iter;
|
||||
var fh;
|
||||
|
||||
function run_test()
|
||||
{
|
||||
do_test_pending();
|
||||
iter = next_test();
|
||||
iter.next();
|
||||
}
|
||||
|
||||
function next_test()
|
||||
{
|
||||
try {
|
||||
|
||||
@ -30,27 +22,19 @@ function next_test()
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_eq(3, getDBVersion(testfile));
|
||||
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
|
||||
destFile = profileDir.clone();
|
||||
destFile.append("formhistory.sqlite");
|
||||
dbConnection = Services.storage.openUnsharedDatabase(destFile);
|
||||
|
||||
// check for upgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, FormHistory.schemaVersion);
|
||||
|
||||
// Check that the index was added
|
||||
do_check_true(dbConnection.tableExists("moz_deleted_formhistory"));
|
||||
dbConnection.close();
|
||||
|
||||
do_check_true(fh.DBConnection.tableExists("moz_deleted_formhistory"));
|
||||
// check for upgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
// check that an entry still exists
|
||||
yield countEntries("name-A", "value-A",
|
||||
function (num) {
|
||||
do_check_true(num > 0);
|
||||
do_test_finished();
|
||||
}
|
||||
);
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
|
@ -11,20 +11,7 @@
|
||||
* Part B tests this when the columns do *not* match, so the DB is reset.
|
||||
*/
|
||||
|
||||
let iter = tests();
|
||||
|
||||
function run_test()
|
||||
{
|
||||
do_test_pending();
|
||||
iter.next();
|
||||
}
|
||||
|
||||
function next_test()
|
||||
{
|
||||
iter.next();
|
||||
}
|
||||
|
||||
function tests()
|
||||
{
|
||||
try {
|
||||
var testnum = 0;
|
||||
@ -42,34 +29,32 @@ function tests()
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_eq(999, getDBVersion(testfile));
|
||||
|
||||
let checkZero = function(num) { do_check_eq(num, 0); next_test(); }
|
||||
let checkOne = function(num) { do_check_eq(num, 1); next_test(); }
|
||||
var fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
// Check for expected contents.
|
||||
yield countEntries(null, null, function(num) { do_check_true(num > 0); next_test(); });
|
||||
yield countEntries("name-A", "value-A", checkOne);
|
||||
yield countEntries("name-B", "value-B", checkOne);
|
||||
yield countEntries("name-C", "value-C1", checkOne);
|
||||
yield countEntries("name-C", "value-C2", checkOne);
|
||||
yield countEntries("name-E", "value-E", checkOne);
|
||||
|
||||
do_check_true(fh.hasEntries);
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
do_check_true(fh.entryExists("name-B", "value-B"));
|
||||
do_check_true(fh.entryExists("name-C", "value-C1"));
|
||||
do_check_true(fh.entryExists("name-C", "value-C2"));
|
||||
do_check_true(fh.entryExists("name-E", "value-E"));
|
||||
// check for downgraded schema.
|
||||
do_check_eq(CURRENT_SCHEMA, FormHistory.schemaVersion);
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
|
||||
// ===== 2 =====
|
||||
testnum++;
|
||||
// Exercise adding and removing a name/value pair
|
||||
yield countEntries("name-D", "value-D", checkZero);
|
||||
yield updateEntry("add", "name-D", "value-D", next_test);
|
||||
yield countEntries("name-D", "value-D", checkOne);
|
||||
yield updateEntry("remove", "name-D", "value-D", next_test);
|
||||
yield countEntries("name-D", "value-D", checkZero);
|
||||
do_check_false(fh.entryExists("name-D", "value-D"));
|
||||
fh.addEntry("name-D", "value-D");
|
||||
do_check_true(fh.entryExists("name-D", "value-D"));
|
||||
fh.removeEntry("name-D", "value-D");
|
||||
do_check_false(fh.entryExists("name-D", "value-D"));
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
@ -11,20 +11,7 @@
|
||||
* Part B tests this when the columns do *not* match, so the DB is reset.
|
||||
*/
|
||||
|
||||
let iter = tests();
|
||||
|
||||
function run_test()
|
||||
{
|
||||
do_test_pending();
|
||||
iter.next();
|
||||
}
|
||||
|
||||
function next_test()
|
||||
{
|
||||
iter.next();
|
||||
}
|
||||
|
||||
function tests()
|
||||
{
|
||||
try {
|
||||
var testnum = 0;
|
||||
@ -47,46 +34,43 @@ function tests()
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_eq(999, getDBVersion(testfile));
|
||||
|
||||
let checkZero = function(num) { do_check_eq(num, 0); next_test(); }
|
||||
let checkOne = function(num) { do_check_eq(num, 1); next_test(); }
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
|
||||
// Open the DB, ensure that a backup of the corrupt DB is made.
|
||||
do_check_false(bakFile.exists());
|
||||
var fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
// DB init is done lazily so the DB shouldn't be created yet.
|
||||
do_check_false(bakFile.exists());
|
||||
// Doing any request to the DB should create it.
|
||||
yield countEntries("", "", next_test);
|
||||
|
||||
fh.DBConnection;
|
||||
do_check_true(bakFile.exists());
|
||||
bakFile.remove(false);
|
||||
|
||||
// ===== 2 =====
|
||||
testnum++;
|
||||
// File should be empty
|
||||
yield countEntries(null, null, function(num) { do_check_false(num); next_test(); });
|
||||
yield countEntries("name-A", "value-A", checkZero);
|
||||
do_check_false(fh.hasEntries);
|
||||
do_check_false(fh.entryExists("name-A", "value-A"));
|
||||
// check for current schema.
|
||||
do_check_eq(CURRENT_SCHEMA, FormHistory.schemaVersion);
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
|
||||
// ===== 3 =====
|
||||
testnum++;
|
||||
// Try adding an entry
|
||||
yield updateEntry("add", "name-A", "value-A", next_test);
|
||||
yield countEntries(null, null, checkOne);
|
||||
yield countEntries("name-A", "value-A", checkOne);
|
||||
fh.addEntry("name-A", "value-A");
|
||||
do_check_true(fh.hasEntries);
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
|
||||
|
||||
// ===== 4 =====
|
||||
testnum++;
|
||||
// Try removing an entry
|
||||
yield updateEntry("remove", "name-A", "value-A", next_test);
|
||||
yield countEntries(null, null, checkZero);
|
||||
yield countEntries("name-A", "value-A", checkZero);
|
||||
fh.removeEntry("name-A", "value-A");
|
||||
do_check_false(fh.hasEntries);
|
||||
do_check_false(fh.entryExists("name-A", "value-A"));
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
164
toolkit/components/satchel/test/unit/test_expire.js
Normal file
164
toolkit/components/satchel/test/unit/test_expire.js
Normal file
@ -0,0 +1,164 @@
|
||||
/* 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 testnum = 0;
|
||||
var fh, prefs;
|
||||
|
||||
function countAllEntries() {
|
||||
let stmt = fh.DBConnection.createStatement("SELECT COUNT(*) as numEntries FROM moz_formhistory");
|
||||
do_check_true(stmt.executeStep());
|
||||
let numEntries = stmt.row.numEntries;
|
||||
stmt.finalize();
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
function triggerExpiration() {
|
||||
// We can't easily fake a "daily idle" event, so for testing purposes form
|
||||
// history listens for another notification to trigger an immediate
|
||||
// expiration.
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.notifyObservers(null, "formhistory-expire-now", null);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
try {
|
||||
|
||||
// ===== test init =====
|
||||
var testfile = do_get_file("formhistory_expire.sqlite");
|
||||
var profileDir = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
|
||||
// Cleanup from any previous tests or failures.
|
||||
var dbFile = profileDir.clone();
|
||||
dbFile.append("formhistory.sqlite");
|
||||
if (dbFile.exists())
|
||||
dbFile.remove(false);
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
do_check_true(dbFile.exists());
|
||||
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
prefs = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
|
||||
// We're going to clear this at the end, so it better have the default value now.
|
||||
do_check_false(prefs.prefHasUserValue("browser.formfill.expire_days"));
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
testnum++;
|
||||
|
||||
// Sanity check initial state
|
||||
do_check_eq(CURRENT_SCHEMA, fh.DBConnection.schemaVersion);
|
||||
do_check_eq(508, countAllEntries());
|
||||
do_check_true(fh.entryExists("name-A", "value-A")); // lastUsed == distant past
|
||||
do_check_true(fh.entryExists("name-B", "value-B")); // lastUsed == distant future
|
||||
|
||||
// Add a new entry
|
||||
do_check_false(fh.entryExists("name-C", "value-C"));
|
||||
fh.addEntry("name-C", "value-C");
|
||||
do_check_true(fh.entryExists("name-C", "value-C"));
|
||||
|
||||
// Check the original db size.
|
||||
// Do a vacuum to make sure the db has current page size.
|
||||
fh.DBConnection.executeSimpleSQL("VACUUM");
|
||||
var oldSize = dbFile.clone().fileSize;
|
||||
|
||||
// Update some existing entries to have ages relative to when the test runs.
|
||||
var now = 1000 * Date.now();
|
||||
var age181 = now - 181 * 24 * PR_HOURS;
|
||||
var age179 = now - 179 * 24 * PR_HOURS;
|
||||
var age31 = now - 31 * 24 * PR_HOURS;
|
||||
var age29 = now - 29 * 24 * PR_HOURS;
|
||||
var age11 = now - 11 * 24 * PR_HOURS;
|
||||
var age9 = now - 9 * 24 * PR_HOURS;
|
||||
|
||||
fh.DBConnection.executeSimpleSQL("UPDATE moz_formhistory SET lastUsed=" + age181 + " WHERE lastUsed=181");
|
||||
fh.DBConnection.executeSimpleSQL("UPDATE moz_formhistory SET lastUsed=" + age179 + " WHERE lastUsed=179");
|
||||
fh.DBConnection.executeSimpleSQL("UPDATE moz_formhistory SET lastUsed=" + age31 + " WHERE lastUsed=31");
|
||||
fh.DBConnection.executeSimpleSQL("UPDATE moz_formhistory SET lastUsed=" + age29 + " WHERE lastUsed=29");
|
||||
fh.DBConnection.executeSimpleSQL("UPDATE moz_formhistory SET lastUsed=" + age11 + " WHERE lastUsed=9999");
|
||||
fh.DBConnection.executeSimpleSQL("UPDATE moz_formhistory SET lastUsed=" + age9 + " WHERE lastUsed=9");
|
||||
|
||||
|
||||
// ===== 2 =====
|
||||
testnum++;
|
||||
|
||||
// Expire history with default pref (180 days)
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
do_check_true(fh.entryExists("181DaysOld", "foo"));
|
||||
do_check_true(fh.entryExists("179DaysOld", "foo"));
|
||||
do_check_eq(509, countAllEntries());
|
||||
|
||||
// 2 entries are expected to expire.
|
||||
triggerExpiration();
|
||||
|
||||
do_check_false(fh.entryExists("name-A", "value-A"));
|
||||
do_check_false(fh.entryExists("181DaysOld", "foo"));
|
||||
do_check_true(fh.entryExists("179DaysOld", "foo"));
|
||||
do_check_eq(507, countAllEntries());
|
||||
|
||||
|
||||
// ===== 3 =====
|
||||
testnum++;
|
||||
|
||||
// And again. No change expected.
|
||||
triggerExpiration();
|
||||
do_check_eq(507, countAllEntries());
|
||||
|
||||
|
||||
// ===== 4 =====
|
||||
testnum++;
|
||||
|
||||
// Set formfill pref to 30 days.
|
||||
prefs.setIntPref("browser.formfill.expire_days", 30);
|
||||
do_check_true(fh.entryExists("179DaysOld", "foo"));
|
||||
do_check_true(fh.entryExists("bar", "31days"));
|
||||
do_check_true(fh.entryExists("bar", "29days"));
|
||||
do_check_eq(507, countAllEntries());
|
||||
|
||||
triggerExpiration();
|
||||
|
||||
do_check_false(fh.entryExists("179DaysOld", "foo"));
|
||||
do_check_false(fh.entryExists("bar", "31days"));
|
||||
do_check_true(fh.entryExists("bar", "29days"));
|
||||
do_check_eq(505, countAllEntries());
|
||||
|
||||
|
||||
// ===== 5 =====
|
||||
testnum++;
|
||||
|
||||
// Set override pref to 10 days and expire. This expires a large batch of
|
||||
// entries, and should trigger a VACCUM to reduce file size.
|
||||
prefs.setIntPref("browser.formfill.expire_days", 10);
|
||||
|
||||
do_check_true(fh.entryExists("bar", "29days"));
|
||||
do_check_true(fh.entryExists("9DaysOld", "foo"));
|
||||
do_check_eq(505, countAllEntries());
|
||||
|
||||
triggerExpiration();
|
||||
|
||||
do_check_false(fh.entryExists("bar", "29days"));
|
||||
do_check_true(fh.entryExists("9DaysOld", "foo"));
|
||||
do_check_true(fh.entryExists("name-B", "value-B"));
|
||||
do_check_true(fh.entryExists("name-C", "value-C"));
|
||||
do_check_eq(3, countAllEntries());
|
||||
|
||||
// Check that the file size was reduced.
|
||||
// Need to clone the nsIFile because the size is being cached on Windows.
|
||||
dbFile = dbFile.clone();
|
||||
do_check_true(dbFile.fileSize < oldSize);
|
||||
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
} finally {
|
||||
// Make sure we always reset prefs.
|
||||
if (prefs.prefHasUserValue("browser.formfill.expire_days"))
|
||||
prefs.clearUserPref("browser.formfill.expire_days");
|
||||
}
|
||||
}
|
@ -3,101 +3,10 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var testnum = 0;
|
||||
let dbConnection; // used for deleted table tests
|
||||
var fh;
|
||||
|
||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
|
||||
function countDeletedEntries(expected)
|
||||
function run_test()
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
let stmt = dbConnection.createAsyncStatement("SELECT COUNT(*) AS numEntries FROM moz_deleted_formhistory");
|
||||
stmt.executeAsync({
|
||||
handleResult: function(resultSet) {
|
||||
do_check_eq(expected, resultSet.getNextRow().getResultByName("numEntries"));
|
||||
deferred.resolve();
|
||||
},
|
||||
handleError : function () {
|
||||
do_throw("Error occurred counting deleted entries: " + error);
|
||||
deferred.reject();
|
||||
},
|
||||
handleCompletion : function () {
|
||||
stmt.finalize();
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkTimeDeleted(guid, checkFunction)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
let stmt = dbConnection.createAsyncStatement("SELECT timeDeleted FROM moz_deleted_formhistory WHERE guid = :guid");
|
||||
stmt.params.guid = guid;
|
||||
stmt.executeAsync({
|
||||
handleResult: function(resultSet) {
|
||||
checkFunction(resultSet.getNextRow().getResultByName("timeDeleted"));
|
||||
deferred.resolve();
|
||||
},
|
||||
handleError : function () {
|
||||
do_throw("Error occurred getting deleted entries: " + error);
|
||||
deferred.reject();
|
||||
},
|
||||
handleCompletion : function () {
|
||||
stmt.finalize();
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseUpdateEntry(op, name, value)
|
||||
{
|
||||
var change = { op: op };
|
||||
if (name !== null)
|
||||
change.fieldname = name;
|
||||
if (value !== null)
|
||||
change.value = value;
|
||||
return promiseUpdate(change);
|
||||
}
|
||||
|
||||
function promiseUpdate(change)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
FormHistory.update(change,
|
||||
{ handleError: function (error) {
|
||||
do_throw("Error occurred updating form history: " + error);
|
||||
deferred.reject(error);
|
||||
},
|
||||
handleCompletion: function (reason) { if (!reason) deferred.resolve(); }
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseSearchEntries(terms, params)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
let results = [];
|
||||
FormHistory.search(terms, params,
|
||||
{ handleResult: function(result) results.push(result),
|
||||
handleError: function (error) {
|
||||
do_throw("Error occurred searching form history: " + error);
|
||||
deferred.reject(error);
|
||||
},
|
||||
handleCompletion: function (reason) { if (!reason) deferred.resolve(results); }
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseCountEntries(name, value, checkFn)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
countEntries(name, value, function (result) { checkFn(result); deferred.resolve(); } );
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
add_task(function ()
|
||||
{
|
||||
let oldSupportsDeletedTable = FormHistory._supportsDeletedTable;
|
||||
FormHistory._supportsDeletedTable = true;
|
||||
|
||||
try {
|
||||
|
||||
// ===== test init =====
|
||||
@ -112,286 +21,105 @@ add_task(function ()
|
||||
|
||||
testfile.copyTo(profileDir, "formhistory.sqlite");
|
||||
|
||||
function checkExists(num) { do_check_true(num > 0); }
|
||||
function checkNotExists(num) { do_check_true(num == 0); }
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
|
||||
// ===== 1 =====
|
||||
// Check initial state is as expected
|
||||
testnum++;
|
||||
yield promiseCountEntries("name-A", null, checkExists);
|
||||
yield promiseCountEntries("name-B", null, checkExists);
|
||||
yield promiseCountEntries("name-C", null, checkExists);
|
||||
yield promiseCountEntries("name-D", null, checkExists);
|
||||
yield promiseCountEntries("name-A", "value-A", checkExists);
|
||||
yield promiseCountEntries("name-B", "value-B1", checkExists);
|
||||
yield promiseCountEntries("name-B", "value-B2", checkExists);
|
||||
yield promiseCountEntries("name-C", "value-C", checkExists);
|
||||
yield promiseCountEntries("name-D", "value-D", checkExists);
|
||||
do_check_true(fh.hasEntries);
|
||||
do_check_true(fh.nameExists("name-A"));
|
||||
do_check_true(fh.nameExists("name-B"));
|
||||
do_check_true(fh.nameExists("name-C"));
|
||||
do_check_true(fh.nameExists("name-D"));
|
||||
do_check_true(fh.entryExists("name-A", "value-A"));
|
||||
do_check_true(fh.entryExists("name-B", "value-B1"));
|
||||
do_check_true(fh.entryExists("name-B", "value-B2"));
|
||||
do_check_true(fh.entryExists("name-C", "value-C"));
|
||||
do_check_true(fh.entryExists("name-D", "value-D"));
|
||||
// time-A/B/C/D checked below.
|
||||
|
||||
// Delete anything from the deleted table
|
||||
let dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile).clone();
|
||||
dbFile.append("formhistory.sqlite");
|
||||
dbConnection = Services.storage.openUnsharedDatabase(dbFile);
|
||||
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let stmt = dbConnection.createAsyncStatement("DELETE FROM moz_deleted_formhistory");
|
||||
stmt.executeAsync({
|
||||
handleResult: function(resultSet) { },
|
||||
handleError : function () {
|
||||
do_throw("Error occurred counting deleted all entries: " + error);
|
||||
},
|
||||
handleCompletion : function () {
|
||||
stmt.finalize();
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
yield deferred.promise;
|
||||
|
||||
// ===== 2 =====
|
||||
// Test looking for nonexistent / bogus data.
|
||||
testnum++;
|
||||
yield promiseCountEntries("blah", null, checkNotExists);
|
||||
yield promiseCountEntries("", null, checkNotExists);
|
||||
yield promiseCountEntries("name-A", "blah", checkNotExists);
|
||||
yield promiseCountEntries("name-A", "", checkNotExists);
|
||||
yield promiseCountEntries("name-A", null, checkExists);
|
||||
yield promiseCountEntries("blah", "value-A", checkNotExists);
|
||||
yield promiseCountEntries("", "value-A", checkNotExists);
|
||||
yield promiseCountEntries(null, "value-A", checkExists);
|
||||
|
||||
// Cannot use promiseCountEntries when name and value are null because it treats null values as not set
|
||||
// and here a search should be done explicity for null.
|
||||
deferred = Promise.defer();
|
||||
yield FormHistory.count({ fieldname: null, value: null },
|
||||
{ handleResult: function(result) checkNotExists(result),
|
||||
handleError: function (error) {
|
||||
do_throw("Error occurred searching form history: " + error);
|
||||
},
|
||||
handleCompletion: function(reason) { if (!reason) deferred.resolve() }
|
||||
});
|
||||
yield deferred.promise;
|
||||
do_check_false(fh.nameExists("blah"));
|
||||
do_check_false(fh.nameExists(""));
|
||||
do_check_false(fh.nameExists(null));
|
||||
do_check_false(fh.entryExists("name-A", "blah"));
|
||||
do_check_false(fh.entryExists("name-A", ""));
|
||||
do_check_false(fh.entryExists("name-A", null));
|
||||
do_check_false(fh.entryExists("blah", "value-A"));
|
||||
do_check_false(fh.entryExists("", "value-A"));
|
||||
do_check_false(fh.entryExists(null, "value-A"));
|
||||
|
||||
// ===== 3 =====
|
||||
// Test removeEntriesForName with a single matching value
|
||||
testnum++;
|
||||
yield promiseUpdateEntry("remove", "name-A", null);
|
||||
|
||||
yield promiseCountEntries("name-A", "value-A", checkNotExists);
|
||||
yield promiseCountEntries("name-B", "value-B1", checkExists);
|
||||
yield promiseCountEntries("name-B", "value-B2", checkExists);
|
||||
yield promiseCountEntries("name-C", "value-C", checkExists);
|
||||
yield promiseCountEntries("name-D", "value-D", checkExists);
|
||||
yield countDeletedEntries(1);
|
||||
fh.removeEntriesForName("name-A");
|
||||
do_check_false(fh.entryExists("name-A", "value-A"));
|
||||
do_check_true(fh.entryExists("name-B", "value-B1"));
|
||||
do_check_true(fh.entryExists("name-B", "value-B2"));
|
||||
do_check_true(fh.entryExists("name-C", "value-C"));
|
||||
do_check_true(fh.entryExists("name-D", "value-D"));
|
||||
|
||||
// ===== 4 =====
|
||||
// Test removeEntriesForName with multiple matching values
|
||||
testnum++;
|
||||
yield promiseUpdateEntry("remove", "name-B", null);
|
||||
|
||||
yield promiseCountEntries("name-A", "value-A", checkNotExists);
|
||||
yield promiseCountEntries("name-B", "value-B1", checkNotExists);
|
||||
yield promiseCountEntries("name-B", "value-B2", checkNotExists);
|
||||
yield promiseCountEntries("name-C", "value-C", checkExists);
|
||||
yield promiseCountEntries("name-D", "value-D", checkExists);
|
||||
yield countDeletedEntries(3);
|
||||
fh.removeEntriesForName("name-B");
|
||||
do_check_false(fh.entryExists("name-A", "value-A"));
|
||||
do_check_false(fh.entryExists("name-B", "value-B1"));
|
||||
do_check_false(fh.entryExists("name-B", "value-B2"));
|
||||
do_check_true(fh.entryExists("name-C", "value-C"));
|
||||
do_check_true(fh.entryExists("name-D", "value-D"));
|
||||
|
||||
// ===== 5 =====
|
||||
// Test removing by time range (single entry, not surrounding entries)
|
||||
testnum++;
|
||||
yield promiseCountEntries("time-A", null, checkExists); // firstUsed=1000, lastUsed=1000
|
||||
yield promiseCountEntries("time-B", null, checkExists); // firstUsed=1000, lastUsed=1099
|
||||
yield promiseCountEntries("time-C", null, checkExists); // firstUsed=1099, lastUsed=1099
|
||||
yield promiseCountEntries("time-D", null, checkExists); // firstUsed=2001, lastUsed=2001
|
||||
yield promiseUpdate({ op : "remove", firstUsedStart: 1050, firstUsedEnd: 2000 });
|
||||
|
||||
yield promiseCountEntries("time-A", null, checkExists);
|
||||
yield promiseCountEntries("time-B", null, checkExists);
|
||||
yield promiseCountEntries("time-C", null, checkNotExists);
|
||||
yield promiseCountEntries("time-D", null, checkExists);
|
||||
yield countDeletedEntries(4);
|
||||
do_check_true(fh.nameExists("time-A")); // firstUsed=1000, lastUsed=1000
|
||||
do_check_true(fh.nameExists("time-B")); // firstUsed=1000, lastUsed=1099
|
||||
do_check_true(fh.nameExists("time-C")); // firstUsed=1099, lastUsed=1099
|
||||
do_check_true(fh.nameExists("time-D")); // firstUsed=2001, lastUsed=2001
|
||||
fh.removeEntriesByTimeframe(1050, 2000);
|
||||
do_check_true(fh.nameExists("time-A"));
|
||||
do_check_true(fh.nameExists("time-B"));
|
||||
do_check_false(fh.nameExists("time-C"));
|
||||
do_check_true(fh.nameExists("time-D"));
|
||||
|
||||
// ===== 6 =====
|
||||
// Test removing by time range (multiple entries)
|
||||
testnum++;
|
||||
yield promiseUpdate({ op : "remove", firstUsedStart: 1000, firstUsedEnd: 2000 });
|
||||
|
||||
yield promiseCountEntries("time-A", null, checkNotExists);
|
||||
yield promiseCountEntries("time-B", null, checkNotExists);
|
||||
yield promiseCountEntries("time-C", null, checkNotExists);
|
||||
yield promiseCountEntries("time-D", null, checkExists);
|
||||
yield countDeletedEntries(6);
|
||||
fh.removeEntriesByTimeframe(1000, 2000);
|
||||
do_check_false(fh.nameExists("time-A"));
|
||||
do_check_false(fh.nameExists("time-B"));
|
||||
do_check_false(fh.nameExists("time-C"));
|
||||
do_check_true(fh.nameExists("time-D"));
|
||||
|
||||
// ===== 7 =====
|
||||
// test removeAllEntries
|
||||
testnum++;
|
||||
yield promiseUpdateEntry("remove", null, null);
|
||||
|
||||
yield promiseCountEntries("name-C", null, checkNotExists);
|
||||
yield promiseCountEntries("name-D", null, checkNotExists);
|
||||
yield promiseCountEntries("name-C", "value-C", checkNotExists);
|
||||
yield promiseCountEntries("name-D", "value-D", checkNotExists);
|
||||
|
||||
yield promiseCountEntries(null, null, checkNotExists);
|
||||
yield countDeletedEntries(6);
|
||||
fh.removeAllEntries();
|
||||
do_check_false(fh.hasEntries);
|
||||
do_check_false(fh.nameExists("name-C"));
|
||||
do_check_false(fh.nameExists("name-D"));
|
||||
do_check_false(fh.entryExists("name-C", "value-C"));
|
||||
do_check_false(fh.entryExists("name-D", "value-D"));
|
||||
|
||||
// ===== 8 =====
|
||||
// Add a single entry back
|
||||
testnum++;
|
||||
yield promiseUpdateEntry("add", "newname-A", "newvalue-A");
|
||||
yield promiseCountEntries("newname-A", "newvalue-A", checkExists);
|
||||
fh.addEntry("newname-A", "newvalue-A");
|
||||
do_check_true(fh.hasEntries);
|
||||
do_check_true(fh.entryExists("newname-A", "newvalue-A"));
|
||||
|
||||
// ===== 9 =====
|
||||
// Remove the single entry
|
||||
testnum++;
|
||||
yield promiseUpdateEntry("remove", "newname-A", "newvalue-A");
|
||||
yield promiseCountEntries("newname-A", "newvalue-A", checkNotExists);
|
||||
|
||||
// ===== 10 =====
|
||||
// Add a single entry
|
||||
testnum++;
|
||||
yield promiseUpdateEntry("add", "field1", "value1");
|
||||
yield promiseCountEntries("field1", "value1", checkExists);
|
||||
|
||||
let processFirstResult = function processResults(results)
|
||||
{
|
||||
// Only handle the first result
|
||||
if (results.length > 0) {
|
||||
let result = results[0];
|
||||
return [result.timesUsed, result.firstUsed, result.lastUsed, result.guid];
|
||||
}
|
||||
}
|
||||
|
||||
results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
|
||||
{ fieldname: "field1", value: "value1" });
|
||||
let [timesUsed, firstUsed, lastUsed] = processFirstResult(results);
|
||||
do_check_eq(1, timesUsed);
|
||||
do_check_true(firstUsed > 0);
|
||||
do_check_true(lastUsed > 0);
|
||||
yield promiseCountEntries(null, null, function(num) do_check_eq(num, 1));
|
||||
|
||||
// ===== 11 =====
|
||||
// Add another single entry
|
||||
testnum++;
|
||||
yield promiseUpdateEntry("add", "field1", "value1b");
|
||||
yield promiseCountEntries("field1", "value1", checkExists);
|
||||
yield promiseCountEntries("field1", "value1b", checkExists);
|
||||
yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2));
|
||||
|
||||
// ===== 12 =====
|
||||
// Update a single entry
|
||||
testnum++;
|
||||
|
||||
results = yield promiseSearchEntries(["guid"], { fieldname: "field1", value: "value1" });
|
||||
let guid = processFirstResult(results)[3];
|
||||
|
||||
yield promiseUpdate({ op : "update", guid: guid, value: "modifiedValue" });
|
||||
yield promiseCountEntries("field1", "modifiedValue", checkExists);
|
||||
yield promiseCountEntries("field1", "value1", checkNotExists);
|
||||
yield promiseCountEntries("field1", "value1b", checkExists);
|
||||
yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2));
|
||||
|
||||
// ===== 13 =====
|
||||
// Add a single entry with times
|
||||
testnum++;
|
||||
yield promiseUpdate({ op : "add", fieldname: "field2", value: "value2",
|
||||
timesUsed: 20, firstUsed: 100, lastUsed: 500 });
|
||||
|
||||
results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
|
||||
{ fieldname: "field2", value: "value2" });
|
||||
[timesUsed, firstUsed, lastUsed] = processFirstResult(results);
|
||||
|
||||
do_check_eq(20, timesUsed);
|
||||
do_check_eq(100, firstUsed);
|
||||
do_check_eq(500, lastUsed);
|
||||
yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3));
|
||||
|
||||
// ===== 14 =====
|
||||
// Bump an entry, which updates its lastUsed field
|
||||
testnum++;
|
||||
yield promiseUpdate({ op : "bump", fieldname: "field2", value: "value2",
|
||||
timesUsed: 20, firstUsed: 100, lastUsed: 500 });
|
||||
results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
|
||||
{ fieldname: "field2", value: "value2" });
|
||||
[timesUsed, firstUsed, lastUsed] = processFirstResult(results);
|
||||
do_check_eq(21, timesUsed);
|
||||
do_check_eq(100, firstUsed);
|
||||
do_check_true(lastUsed > 500);
|
||||
yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3));
|
||||
|
||||
// ===== 15 =====
|
||||
// Bump an entry that does not exist
|
||||
testnum++;
|
||||
yield promiseUpdate({ op : "bump", fieldname: "field3", value: "value3",
|
||||
timesUsed: 10, firstUsed: 50, lastUsed: 400 });
|
||||
results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
|
||||
{ fieldname: "field3", value: "value3" });
|
||||
[timesUsed, firstUsed, lastUsed] = processFirstResult(results);
|
||||
do_check_eq(10, timesUsed);
|
||||
do_check_eq(50, firstUsed);
|
||||
do_check_eq(400, lastUsed);
|
||||
yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
|
||||
|
||||
// ===== 16 =====
|
||||
// Bump an entry with a guid
|
||||
testnum++;
|
||||
results = yield promiseSearchEntries(["guid"], { fieldname: "field3", value: "value3" });
|
||||
guid = processFirstResult(results)[3];
|
||||
yield promiseUpdate({ op : "bump", guid: guid, timesUsed: 20, firstUsed: 55, lastUsed: 400 });
|
||||
results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
|
||||
{ fieldname: "field3", value: "value3" });
|
||||
[timesUsed, firstUsed, lastUsed] = processFirstResult(results);
|
||||
do_check_eq(11, timesUsed);
|
||||
do_check_eq(50, firstUsed);
|
||||
do_check_true(lastUsed > 400);
|
||||
yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
|
||||
|
||||
// ===== 17 =====
|
||||
// Remove an entry
|
||||
testnum++;
|
||||
yield countDeletedEntries(7);
|
||||
|
||||
results = yield promiseSearchEntries(["guid"], { fieldname: "field1", value: "value1b" });
|
||||
guid = processFirstResult(results)[3];
|
||||
|
||||
yield promiseUpdate({ op : "remove", guid: guid});
|
||||
yield promiseCountEntries("field1", "modifiedValue", checkExists);
|
||||
yield promiseCountEntries("field1", "value1b", checkNotExists);
|
||||
yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3));
|
||||
|
||||
yield countDeletedEntries(8);
|
||||
yield checkTimeDeleted(guid, function (timeDeleted) do_check_true(timeDeleted > 10000));
|
||||
|
||||
// ===== 18 =====
|
||||
// Add yet another single entry
|
||||
testnum++;
|
||||
yield promiseUpdate({ op : "add", fieldname: "field4", value: "value4",
|
||||
timesUsed: 5, firstUsed: 230, lastUsed: 600 });
|
||||
yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4));
|
||||
|
||||
// ===== 19 =====
|
||||
// Remove an entry by time
|
||||
testnum++;
|
||||
results = yield promiseSearchEntries(["timesUsed", "firstUsed", "lastUsed"],
|
||||
{ fieldname: "field1", value: "modifiedValue" });
|
||||
[timesUsed, firstUsed, lastUsed] = processFirstResult(results);
|
||||
|
||||
yield promiseUpdate({ op : "remove", firstUsedStart: 60, firstUsedEnd: 250 });
|
||||
yield promiseCountEntries("field1", "modifiedValue", checkExists);
|
||||
yield promiseCountEntries("field2", "value2", checkNotExists);
|
||||
yield promiseCountEntries("field3", "value3", checkExists);
|
||||
yield promiseCountEntries("field4", "value4", checkNotExists);
|
||||
yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2));
|
||||
yield countDeletedEntries(10);
|
||||
fh.removeEntry("newname-A", "newvalue-A");
|
||||
do_check_false(fh.hasEntries);
|
||||
do_check_false(fh.entryExists("newname-A", "newvalue-A"));
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + e;
|
||||
}
|
||||
finally {
|
||||
FormHistory._supportsDeletedTable = oldSupportsDeletedTable;
|
||||
dbConnection.asyncClose(do_test_finished);
|
||||
}
|
||||
});
|
||||
|
||||
function run_test() run_next_test();
|
||||
}
|
||||
|
@ -5,7 +5,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
var expectedNotification;
|
||||
var expectedBeforeNotification = null;
|
||||
var expectedData;
|
||||
|
||||
var TestObserver = {
|
||||
@ -13,146 +16,197 @@ var TestObserver = {
|
||||
|
||||
observe : function (subject, topic, data) {
|
||||
do_check_eq(topic, "satchel-storage-changed");
|
||||
do_check_eq(data, expectedNotification);
|
||||
|
||||
// ensure that the "before-" notification comes before the other
|
||||
dump(expectedBeforeNotification + " : " + expectedNotification + "\n");
|
||||
if (!expectedBeforeNotification)
|
||||
do_check_eq(data, expectedNotification);
|
||||
else
|
||||
do_check_eq(data, expectedBeforeNotification);
|
||||
|
||||
switch (data) {
|
||||
case "formhistory-add":
|
||||
case "formhistory-update":
|
||||
do_check_true(subject instanceof Ci.nsISupportsString);
|
||||
do_check_true(isGUID.test(subject.toString()));
|
||||
case "addEntry":
|
||||
do_check_true(subject instanceof Ci.nsIMutableArray);
|
||||
do_check_eq(expectedData[0], subject.queryElementAt(0, Ci.nsISupportsString));
|
||||
do_check_eq(expectedData[1], subject.queryElementAt(1, Ci.nsISupportsString));
|
||||
do_check_true(isGUID.test(subject.queryElementAt(2, Ci.nsISupportsString).toString()));
|
||||
break;
|
||||
case "formhistory-remove":
|
||||
do_check_eq(null, subject);
|
||||
case "modifyEntry":
|
||||
do_check_true(subject instanceof Ci.nsIMutableArray);
|
||||
do_check_eq(expectedData[0], subject.queryElementAt(0, Ci.nsISupportsString));
|
||||
do_check_eq(expectedData[1], subject.queryElementAt(1, Ci.nsISupportsString));
|
||||
do_check_true(isGUID.test(subject.queryElementAt(2, Ci.nsISupportsString).toString()));
|
||||
break;
|
||||
case "before-removeEntry":
|
||||
case "removeEntry":
|
||||
do_check_true(subject instanceof Ci.nsIMutableArray);
|
||||
do_check_eq(expectedData[0], subject.queryElementAt(0, Ci.nsISupportsString));
|
||||
do_check_eq(expectedData[1], subject.queryElementAt(1, Ci.nsISupportsString));
|
||||
do_check_true(isGUID.test(subject.queryElementAt(2, Ci.nsISupportsString).toString()));
|
||||
break;
|
||||
case "before-removeAllEntries":
|
||||
case "removeAllEntries":
|
||||
do_check_eq(subject, expectedData);
|
||||
break;
|
||||
case "before-removeEntriesForName":
|
||||
case "removeEntriesForName":
|
||||
do_check_true(subject instanceof Ci.nsISupportsString);
|
||||
do_check_eq(subject, expectedData);
|
||||
break;
|
||||
case "before-removeEntriesByTimeframe":
|
||||
case "removeEntriesByTimeframe":
|
||||
do_check_true(subject instanceof Ci.nsIMutableArray);
|
||||
do_check_eq(expectedData[0], subject.queryElementAt(0, Ci.nsISupportsPRInt64));
|
||||
do_check_eq(expectedData[1], subject.queryElementAt(1, Ci.nsISupportsPRInt64));
|
||||
break;
|
||||
case "before-expireOldEntries":
|
||||
case "expireOldEntries":
|
||||
do_check_true(subject instanceof Ci.nsISupportsPRInt64);
|
||||
do_check_true(subject.data > 0);
|
||||
break;
|
||||
default:
|
||||
do_throw("Unhandled notification: " + data + " / " + topic);
|
||||
}
|
||||
|
||||
expectedNotification = null;
|
||||
expectedData = null;
|
||||
// ensure a duplicate is flagged as unexpected
|
||||
if (expectedBeforeNotification) {
|
||||
expectedBeforeNotification = null;
|
||||
} else {
|
||||
expectedNotification = null;
|
||||
expectedData = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let testIterator = null;
|
||||
function countAllEntries() {
|
||||
let stmt = fh.DBConnection.createStatement("SELECT COUNT(*) as numEntries FROM moz_formhistory");
|
||||
do_check_true(stmt.step());
|
||||
let numEntries = stmt.row.numEntries;
|
||||
stmt.finalize();
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
function triggerExpiration() {
|
||||
// We can't easily fake a "daily idle" event, so for testing purposes form
|
||||
// history listens for another notification to trigger an immediate
|
||||
// expiration.
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.notifyObservers(null, "formhistory-expire-now", null);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
testIterator = run_test_steps();
|
||||
testIterator.next();
|
||||
}
|
||||
|
||||
function next_test()
|
||||
{
|
||||
testIterator.next();
|
||||
}
|
||||
|
||||
function run_test_steps() {
|
||||
|
||||
try {
|
||||
|
||||
var testnum = 0;
|
||||
var testdesc = "Setup of test form history entries";
|
||||
fh = Cc["@mozilla.org/satchel/form-history;1"].
|
||||
getService(Ci.nsIFormHistory2);
|
||||
|
||||
do_check_true(fh != null);
|
||||
|
||||
var entry1 = ["entry1", "value1"];
|
||||
var entry2 = ["entry2", "value2"];
|
||||
|
||||
|
||||
/* ========== 1 ========== */
|
||||
var testnum = 1;
|
||||
var testdesc = "Initial connection to storage module"
|
||||
|
||||
yield updateEntry("remove", null, null, next_test);
|
||||
yield countEntries(null, null, function (num) { do_check_false(num, "Checking initial DB is empty"); next_test(); });
|
||||
|
||||
// Add the observer
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(TestObserver, "satchel-storage-changed", false);
|
||||
|
||||
|
||||
/* ========== 1 ========== */
|
||||
var testnum = 1;
|
||||
var testdesc = "Initial connection to storage module"
|
||||
|
||||
fh.DBConnection.executeSimpleSQL("DELETE FROM moz_formhistory");
|
||||
do_check_eq(countAllEntries(), 0, "Checking initial DB is empty");
|
||||
|
||||
/* ========== 2 ========== */
|
||||
testnum++;
|
||||
testdesc = "addEntry";
|
||||
|
||||
expectedNotification = "formhistory-add";
|
||||
expectedNotification = "addEntry";
|
||||
expectedData = entry1;
|
||||
|
||||
yield updateEntry("add", entry1[0], entry1[1], next_test);
|
||||
fh.addEntry(entry1[0], entry1[1]);
|
||||
do_check_true(fh.entryExists(entry1[0], entry1[1]));
|
||||
do_check_eq(expectedNotification, null); // check that observer got a notification
|
||||
|
||||
yield countEntries(entry1[0], entry1[1], function (num) { do_check_true(num > 0); next_test(); });
|
||||
|
||||
/* ========== 3 ========== */
|
||||
testnum++;
|
||||
testdesc = "modifyEntry";
|
||||
|
||||
expectedNotification = "formhistory-update";
|
||||
expectedNotification = "modifyEntry";
|
||||
expectedData = entry1;
|
||||
// will update previous entry
|
||||
yield updateEntry("update", entry1[0], entry1[1], next_test);
|
||||
yield countEntries(entry1[0], entry1[1], function (num) { do_check_true(num > 0); next_test(); });
|
||||
|
||||
fh.addEntry(entry1[0], entry1[1]); // will update previous entry
|
||||
do_check_eq(expectedNotification, null);
|
||||
|
||||
/* ========== 4 ========== */
|
||||
testnum++;
|
||||
testdesc = "removeEntry";
|
||||
|
||||
expectedNotification = "formhistory-remove";
|
||||
expectedNotification = "removeEntry";
|
||||
expectedBeforeNotification = "before-" + expectedNotification;
|
||||
expectedData = entry1;
|
||||
yield updateEntry("remove", entry1[0], entry1[1], next_test);
|
||||
|
||||
fh.removeEntry(entry1[0], entry1[1]);
|
||||
do_check_eq(expectedNotification, null);
|
||||
yield countEntries(entry1[0], entry1[1], function(num) { do_check_false(num, "doesn't exist after remove"); next_test(); });
|
||||
do_check_eq(expectedBeforeNotification, null);
|
||||
do_check_true(!fh.entryExists(entry1[0], entry1[1]));
|
||||
|
||||
/* ========== 5 ========== */
|
||||
testnum++;
|
||||
testdesc = "removeAllEntries";
|
||||
|
||||
expectedNotification = "formhistory-remove";
|
||||
expectedNotification = "removeAllEntries";
|
||||
expectedBeforeNotification = "before-" + expectedNotification;
|
||||
expectedData = null; // no data expected
|
||||
yield updateEntry("remove", null, null, next_test);
|
||||
|
||||
fh.removeAllEntries();
|
||||
do_check_eq(expectedNotification, null);
|
||||
do_check_eq(expectedBeforeNotification, null);
|
||||
|
||||
/* ========== 6 ========== */
|
||||
testnum++;
|
||||
testdesc = "removeAllEntries (again)";
|
||||
|
||||
expectedNotification = "formhistory-remove";
|
||||
expectedNotification = "removeAllEntries";
|
||||
expectedBeforeNotification = "before-" + expectedNotification;
|
||||
expectedData = null;
|
||||
yield updateEntry("remove", null, null, next_test);
|
||||
|
||||
fh.removeAllEntries();
|
||||
do_check_eq(expectedNotification, null);
|
||||
do_check_eq(expectedBeforeNotification, null);
|
||||
|
||||
/* ========== 7 ========== */
|
||||
testnum++;
|
||||
testdesc = "removeEntriesForName";
|
||||
|
||||
expectedNotification = "formhistory-remove";
|
||||
expectedNotification = "removeEntriesForName";
|
||||
expectedBeforeNotification = "before-" + expectedNotification;
|
||||
expectedData = "field2";
|
||||
yield updateEntry("remove", null, "field2", next_test);
|
||||
|
||||
fh.removeEntriesForName("field2");
|
||||
do_check_eq(expectedNotification, null);
|
||||
do_check_eq(expectedBeforeNotification, null);
|
||||
|
||||
/* ========== 8 ========== */
|
||||
testnum++;
|
||||
testdesc = "removeEntriesByTimeframe";
|
||||
|
||||
expectedNotification = "formhistory-remove";
|
||||
expectedNotification = "removeEntriesByTimeframe";
|
||||
expectedBeforeNotification = "before-" + expectedNotification;
|
||||
expectedData = [10, 99999999999];
|
||||
|
||||
yield FormHistory.update({ op: "remove", firstUsedStart: expectedData[0], firstUsedEnd: expectedData[1] },
|
||||
{ handleCompletion: function(reason) { if (!reason) next_test() },
|
||||
handleErrors: function (error) {
|
||||
do_throw("Error occurred updating form history: " + error);
|
||||
}
|
||||
});
|
||||
|
||||
fh.removeEntriesByTimeframe(expectedData[0], expectedData[1]);
|
||||
do_check_eq(expectedNotification, null);
|
||||
do_check_eq(expectedBeforeNotification, null);
|
||||
|
||||
os.removeObserver(TestObserver, "satchel-storage-changed", false);
|
||||
/* ========== 9 ========== */
|
||||
testnum++;
|
||||
testdesc = "expireOldEntries";
|
||||
|
||||
do_test_finished();
|
||||
expectedNotification = "expireOldEntries";
|
||||
expectedBeforeNotification = "before-" + expectedNotification;
|
||||
expectedData = null; // TestObserver checks expiryDate > 0
|
||||
triggerExpiration();
|
||||
do_check_eq(expectedNotification, null);
|
||||
do_check_eq(expectedBeforeNotification, null);
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + testdesc + ": " + e;
|
||||
|
@ -2,12 +2,18 @@
|
||||
head = head_satchel.js
|
||||
tail =
|
||||
|
||||
[test_async_expire.js]
|
||||
[test_autocomplete.js]
|
||||
[test_db_corrupt.js]
|
||||
[test_db_update_v1.js]
|
||||
[test_db_update_v1b.js]
|
||||
[test_db_update_v2.js]
|
||||
[test_db_update_v2b.js]
|
||||
[test_db_update_v3.js]
|
||||
[test_db_update_v3b.js]
|
||||
[test_db_update_v4.js]
|
||||
[test_db_update_v4b.js]
|
||||
[test_db_update_v999a.js]
|
||||
[test_db_update_v999b.js]
|
||||
[test_expire.js]
|
||||
[test_history_api.js]
|
||||
[test_notify.js]
|
||||
|
Loading…
Reference in New Issue
Block a user