Bug 463154 - Form history should record creation/usage timestamps. r=mconnor, r=sdwilsh

This commit is contained in:
Justin Dolske 2008-11-13 10:30:45 -08:00
parent c39cb1e482
commit 326e268e54
13 changed files with 660 additions and 49 deletions

View File

@ -37,6 +37,7 @@
#include "nsISupports.idl"
interface nsIFile;
interface mozIStorageConnection;
/**
* The nsIFormHistory object is a service which holds a set of name/value
@ -49,7 +50,7 @@ interface nsIFile;
* autocomplete matches.
*/
[scriptable, uuid(a61f0a62-ae0a-4382-b474-d259442ca80c)]
[scriptable, uuid(d73f5924-3e39-4c67-8f4a-290b85448480)]
interface nsIFormHistory2 : nsISupports
{
/**
@ -86,6 +87,11 @@ interface nsIFormHistory2 : nsISupports
* Gets whether a name and value pair exists in the form history.
*/
boolean entryExists(in AString name, in AString value);
/**
* Returns the underlying DB connection the form history module is using.
*/
readonly attribute mozIStorageConnection DBConnection;
};
/**

View File

@ -215,6 +215,12 @@ nsFormHistory::RemoveAllEntries()
return rv;
}
NS_IMETHODIMP
nsFormHistory::GetDBConnection()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////
//// nsIObserver

View File

@ -24,6 +24,7 @@
* Brett Wilson <brettw@gmail.com>
* Michael Ventnor <m.ventnor@gmail.com>
* Ehsan Akhgari <ehsan.akhgari@gmail.com>
* Justin Dolske <dolske@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -76,6 +77,12 @@
// numbers. See StartCache
#define DATABASE_CACHE_PAGES 4000
#define DB_SCHEMA_VERSION 1
#define DB_FILENAME NS_LITERAL_STRING("formhistory.sqlite")
#define DB_CORRUPT_FILENAME NS_LITERAL_STRING("formhistory.sqlite.corrupt")
#define PR_HOURS (60 * 60 * 1000000)
// nsFormHistoryResult is a specialized autocomplete result class that knows
// how to remove entries from the form history table.
class nsFormHistoryResult : public nsIAutoCompleteSimpleResult
@ -180,9 +187,27 @@ nsFormHistory::~nsFormHistory()
nsresult
nsFormHistory::Init()
{
nsresult rv = OpenDatabase();
PRBool doImport = PR_FALSE;
nsresult rv = OpenDatabase(&doImport);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef MOZ_MORKREADER
if (doImport) {
// Locate the old formhistory.dat file and import it.
nsCOMPtr<nsIFile> historyFile;
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(historyFile));
if (NS_SUCCEEDED(rv)) {
historyFile->Append(NS_LITERAL_STRING("formhistory.dat"));
nsCOMPtr<nsIFormHistoryImporter> importer = new nsFormHistoryImporter();
NS_ENSURE_TRUE(importer, NS_ERROR_OUT_OF_MEMORY);
importer->ImportFormHistory(historyFile, this);
}
}
#endif
nsCOMPtr<nsIObserverService> service = do_GetService("@mozilla.org/observer-service;1");
if (service)
service->AddObserver(this, NS_EARLYFORMSUBMIT_SUBJECT, PR_TRUE);
@ -240,15 +265,39 @@ nsFormHistory::AddEntry(const nsAString &aName, const nsAString &aValue)
if (!FormHistoryEnabled())
return NS_OK;
PRBool exists = PR_TRUE;
EntryExists(aName, aValue, &exists);
if (!exists) {
mozStorageStatementScoper scope(mDBInsertNameValue);
nsresult rv = mDBInsertNameValue->BindStringParameter(0, aName);
nsresult rv;
PRInt64 existingID = GetExistingEntryID(aName, aValue);
if (existingID != -1) {
mozStorageStatementScoper scope(mDBUpdateEntry);
// lastUsed
rv = mDBUpdateEntry->BindInt64Parameter(0, PR_Now());
NS_ENSURE_SUCCESS(rv, rv);
// WHERE id
rv = mDBUpdateEntry->BindInt64Parameter(1, existingID);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBUpdateEntry->Execute();
NS_ENSURE_SUCCESS(rv, rv);
} else {
PRInt64 now = PR_Now();
mozStorageStatementScoper scope(mDBInsertNameValue);
// fieldname
rv = mDBInsertNameValue->BindStringParameter(0, aName);
NS_ENSURE_SUCCESS(rv, rv);
// value
rv = mDBInsertNameValue->BindStringParameter(1, aValue);
NS_ENSURE_SUCCESS(rv, rv);
// timesUsed
rv = mDBInsertNameValue->BindInt32Parameter(2, 1);
NS_ENSURE_SUCCESS(rv, rv);
// firstUsed
rv = mDBInsertNameValue->BindInt64Parameter(3, now);
NS_ENSURE_SUCCESS(rv, rv);
// lastUsed
rv = mDBInsertNameValue->BindInt64Parameter(4, now);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBInsertNameValue->Execute();
NS_ENSURE_SUCCESS(rv, rv);
@ -256,20 +305,38 @@ nsFormHistory::AddEntry(const nsAString &aName, const nsAString &aValue)
return NS_OK;
}
NS_IMETHODIMP
nsFormHistory::EntryExists(const nsAString &aName,
const nsAString &aValue, PRBool *_retval)
/* Returns -1 if entry not found, or the ID if it was. */
PRInt64
nsFormHistory::GetExistingEntryID (const nsAString &aName,
const nsAString &aValue)
{
mozStorageStatementScoper scope(mDBFindEntry);
nsresult rv = mDBFindEntry->BindStringParameter(0, aName);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(rv, -1);
rv = mDBFindEntry->BindStringParameter(1, aValue);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(rv, -1);
PRBool hasMore;
*_retval = NS_SUCCEEDED(mDBFindEntry->ExecuteStep(&hasMore)) && hasMore;
rv = mDBFindEntry->ExecuteStep(&hasMore);
NS_ENSURE_SUCCESS(rv, -1);
PRInt64 ID = -1;
if (hasMore) {
mDBFindEntry->GetInt64(0, &ID);
NS_ENSURE_SUCCESS(rv, -1);
}
return ID;
}
NS_IMETHODIMP
nsFormHistory::EntryExists(const nsAString &aName,
const nsAString &aValue, PRBool *_retval)
{
PRInt64 ID = GetExistingEntryID(aName, aValue);
*_retval = ID != -1;
return NS_OK;
}
@ -344,6 +411,14 @@ nsFormHistory::RemoveAllEntries()
return dbDeleteAll->Execute();
}
NS_IMETHODIMP
nsFormHistory::GetDBConnection(mozIStorageConnection **aResult)
{
NS_ADDREF(*aResult = mDBConn);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
//// nsIObserver
@ -415,8 +490,68 @@ nsFormHistory::Notify(nsIDOMHTMLFormElement* formElt, nsIDOMWindowInternal* aWin
return transaction.Commit();
}
nsresult
nsFormHistory::OpenDatabase()
nsFormHistory::CreateTable()
{
nsresult rv;
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"CREATE TABLE moz_formhistory ("
"id INTEGER PRIMARY KEY, fieldname TEXT NOT NULL, "
"value TEXT NOT NULL, timesUsed INTEGER NOT NULL, "
"firstUsed INTEGER NOT NULL, lastUsed INTEGER NOT NULL)"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE INDEX moz_formhistory_index ON moz_formhistory (fieldname)"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->SetSchemaVersion(DB_SCHEMA_VERSION);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
nsFormHistory::CreateStatements()
{
nsresult rv;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT * FROM moz_formhistory"),
getter_AddRefs(mDBSelectEntries));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT id FROM moz_formhistory WHERE fieldname=?1 AND value=?2"),
getter_AddRefs(mDBFindEntry));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT * FROM moz_formhistory WHERE fieldname=?1"),
getter_AddRefs(mDBFindEntryByName));
NS_ENSURE_SUCCESS(rv,rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT value FROM moz_formhistory WHERE fieldname=?1 ORDER BY value ASC"),
getter_AddRefs(mDBGetMatchingField));
NS_ENSURE_SUCCESS(rv,rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO moz_formhistory (fieldname, value, timesUsed, "
"firstUsed, lastUsed) VALUES (?1, ?2, ?3, ?4, ?5)"),
getter_AddRefs(mDBInsertNameValue));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_formhistory "
"SET timesUsed=timesUsed + 1, lastUsed=?1 "
"WHERE id = ?2"),
getter_AddRefs(mDBUpdateEntry));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
nsFormHistory::OpenDatabase(PRBool *aDoImport)
{
// init DB service and obtain a connection
nsresult rv;
@ -445,53 +580,109 @@ nsFormHistory::OpenDatabase()
PRBool exists;
mDBConn->TableExists(NS_LITERAL_CSTRING("moz_formhistory"), &exists);
if (!exists) {
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE TABLE moz_formhistory (id INTEGER PRIMARY KEY, fieldname LONGVARCHAR, value LONGVARCHAR)"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE INDEX moz_formhistory_index ON moz_formhistory (fieldname)"));
*aDoImport = PR_TRUE;
rv = CreateTable();
NS_ENSURE_SUCCESS(rv, rv);
}
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT * FROM moz_formhistory"),
getter_AddRefs(mDBSelectEntries));
PRInt32 schemaVersion;
rv = mDBConn->GetSchemaVersion(&schemaVersion);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT * FROM moz_formhistory WHERE fieldname=?1 AND value=?2"),
getter_AddRefs(mDBFindEntry));
NS_ENSURE_SUCCESS(rv, rv);
// Changing the database? Be sure to do these two things!
// 1) Increment DB_SCHEMA_VERSION
// 2) Implement the proper downgrade/upgrade code for the current version
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT * FROM moz_formhistory WHERE fieldname=?1"),
getter_AddRefs(mDBFindEntryByName));
NS_ENSURE_SUCCESS(rv,rv);
switch (schemaVersion) {
case 0:
{
mozStorageTransaction stepTransaction(mDBConn, PR_FALSE);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT value FROM moz_formhistory WHERE fieldname=?1 ORDER BY value ASC"),
getter_AddRefs(mDBGetMatchingField));
NS_ENSURE_SUCCESS(rv,rv);
// The formhistory.sqlite in Firefox 3 didn't have a schema version set
NS_WARNING("Could not get formhistory database's schema version!");
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_formhistory (fieldname, value) VALUES (?1, ?2)"),
getter_AddRefs(mDBInsertNameValue));
NS_ENSURE_SUCCESS(rv, rv);
// Add columns for timestamps and use counts (bug 463154)
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_formhistory ADD COLUMN timesUsed INTEGER"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_formhistory ADD COLUMN firstUsed INTEGER"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_formhistory ADD COLUMN lastUsed INTEGER"));
NS_ENSURE_SUCCESS(rv, rv);
// Set the default values for the new columns.
//
// Note that we set the timestamps to 24 hours in the past. We want a
// timestamp that's recent (so that "keep form history for 90 days"
// doesn't expire things surprisingly soon), but not so recent that
// "forget the last hour of stuff" deletes all freshly migrated data.
nsCOMPtr<mozIStorageStatement> addDefaultValues;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_formhistory "
"SET timesUsed=1, firstUsed=?1, lastUsed=?1"),
getter_AddRefs(addDefaultValues));
rv = addDefaultValues->BindInt64Parameter(0, PR_Now() - 24 * PR_HOURS);
NS_ENSURE_SUCCESS(rv, rv);
rv = addDefaultValues->Execute();
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->SetSchemaVersion(DB_SCHEMA_VERSION);
NS_ENSURE_SUCCESS(rv, rv);
rv = stepTransaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
}
// Fallthrough to the next upgrade
// Extra sanity checking for developers
#ifndef DEBUG
case DB_SCHEMA_VERSION:
#endif
break;
// Downgrades (and DEBUG build sanity checking)... Ensure that all the
// columns we're expecting are present, backup and reinit if not.
default:
{
// If the statement succeeds, all the columns are there.
nsCOMPtr<mozIStorageStatement> stmt;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT fieldname, value, timesUsed, firstUsed, lastUsed "
"FROM moz_formhistory"), getter_AddRefs(stmt));
if (NS_SUCCEEDED(rv))
break;
// Columns are screwy. Backup the DB, nuke it, start anew.
nsCOMPtr<mozIStorageService> storage =
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(storage, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIFile> backupFile;
rv = storage->BackupDatabaseFile(formHistoryFile, DB_CORRUPT_FILENAME,
nsnull, getter_AddRefs(backupFile));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"DROP TABLE moz_formhistory"));
NS_ENSURE_SUCCESS(rv, rv);
rv = CreateTable();
NS_ENSURE_SUCCESS(rv, rv);
}
break;
}
// should commit before starting cache
transaction.Commit();
// ignore errors since the cache is not critical for operation
StartCache();
#ifdef MOZ_MORKREADER
if (!exists) {
// Locate the old formhistory.dat file and import it.
nsCOMPtr<nsIFile> historyFile;
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
getter_AddRefs(historyFile));
if (NS_SUCCEEDED(rv)) {
historyFile->Append(NS_LITERAL_STRING("formhistory.dat"));
nsCOMPtr<nsIFormHistoryImporter> importer = new nsFormHistoryImporter();
NS_ENSURE_TRUE(importer, NS_ERROR_OUT_OF_MEMORY);
importer->ImportFormHistory(historyFile, this);
}
}
#endif
rv = CreateStatements();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@ -502,7 +693,7 @@ nsFormHistory::GetDatabaseFile(nsIFile** aFile)
{
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, aFile);
NS_ENSURE_SUCCESS(rv, rv);
return (*aFile)->Append(NS_LITERAL_STRING("formhistory.sqlite"));
return (*aFile)->Append(DB_FILENAME);
}

View File

@ -113,15 +113,20 @@ public:
protected:
// Database I/O
nsresult OpenDatabase();
nsresult OpenDatabase(PRBool *aDoImport);
nsresult CloseDatabase();
nsresult GetDatabaseFile(nsIFile** aFile);
nsresult CreateTable();
nsresult CreateStatements();
static PRBool FormHistoryEnabled();
static nsFormHistory *gFormHistory;
static PRBool gFormHistoryEnabled;
static PRBool gPrefsInitialized;
PRInt64 GetExistingEntryID(const nsAString &aName, const nsAString &aValue);
nsCOMPtr<nsIPrefBranch> mPrefBranch;
nsCOMPtr<mozIStorageService> mStorageService;
nsCOMPtr<mozIStorageStatement> mDBGetMatchingField;
@ -129,6 +134,7 @@ public:
nsCOMPtr<mozIStorageStatement> mDBFindEntryByName;
nsCOMPtr<mozIStorageStatement> mDBSelectEntries;
nsCOMPtr<mozIStorageStatement> mDBInsertNameValue;
nsCOMPtr<mozIStorageStatement> mDBUpdateEntry;
// dummy statement (see StartCache)
nsresult StartCache();

View File

@ -0,0 +1 @@
BACON

View File

@ -73,6 +73,6 @@ function cleanUpFormHist() {
var formhistFile = dirSvc.get("ProfD", Ci.nsIFile);
formhistFile.append("formhistory.dat");
if (formhistFile.exists())
formhistFile.remove();
formhistFile.remove(false);
}
cleanUpFormHist();

View File

@ -0,0 +1,85 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Satchel Test Code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Justin Dolske <dolske@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function run_test()
{
try {
var testnum = 0;
// ===== test init =====
var testfile = do_get_file("toolkit/components/satchel/test/unit/formhistory_CORRUPT.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");
var fh = Cc["@mozilla.org/satchel/form-history;1"].
getService(Ci.nsIFormHistory2);
// ===== 1 =====
testnum++;
// File should be empty
do_check_false(fh.hasEntries);
do_check_false(fh.entryExists("name-A", "value-A"));
// ===== 2 =====
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"));
// ===== 3 =====
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"));
} catch (e) {
throw "FAILED in test #" + testnum + " -- " + e;
}
}

View File

@ -0,0 +1,132 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Satchel Test Code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Justin Dolske <dolske@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// 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;
}
function run_test()
{
try {
var testnum = 0;
// ===== test init =====
var testfile = do_get_file("toolkit/components/satchel/test/unit/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");
var 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"));
// ===== 2 =====
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"));
// ===== 3 =====
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"));
var query = "SELECT timesUsed, firstUsed, lastUsed " +
"FROM moz_formhistory WHERE fieldname = 'name-E'";
var stmt = fh.DBConnection.createStatement(query);
stmt.executeStep();
var timesUsed = stmt.getInt32(0);
var firstUsed = stmt.getInt64(1);
var lastUsed = stmt.getInt64(2);
do_check_eq(1, timesUsed);
do_check_true(firstUsed == lastUsed);
do_check_true(is_about_now(firstUsed));
// ===== 4 =====
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"));
query = "SELECT timesUsed, firstUsed, lastUsed " +
"FROM moz_formhistory WHERE fieldname = 'name-E'";
stmt = fh.DBConnection.createStatement(query);
stmt.executeStep();
timesUsed = stmt.getInt32(0);
var firstUsed2 = stmt.getInt64(1);
var lastUsed2 = stmt.getInt64(2);
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);
} catch (e) {
throw "FAILED in test #" + testnum + " -- " + e;
}
}

View File

@ -0,0 +1,91 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Satchel Test Code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Justin Dolske <dolske@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* This test uses a formhistory.sqlite with schema version set to 999 (a
* future version). This exercies the code that allows using a future schema
* version as long as the expected columns are present.
*
* Part A tests this when the columns do match, so the DB is used.
* Part B tests this when the columns do *not* match, so the DB is reset.
*/
function run_test()
{
try {
var testnum = 0;
// ===== test init =====
var testfile = do_get_file("toolkit/components/satchel/test/unit/formhistory_v999a.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");
var fh = Cc["@mozilla.org/satchel/form-history;1"].
getService(Ci.nsIFormHistory2);
// ===== 1 =====
testnum++;
// Check for expected contents.
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"));
// ===== 2 =====
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"));
} catch (e) {
throw "FAILED in test #" + testnum + " -- " + e;
}
}

View File

@ -0,0 +1,93 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Satchel Test Code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Justin Dolske <dolske@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* This test uses a formhistory.sqlite with schema version set to 999 (a
* future version). This exercies the code that allows using a future schema
* version as long as the expected columns are present.
*
* Part A tests this when the columns do match, so the DB is used.
* Part B tests this when the columns do *not* match, so the DB is reset.
*/
function run_test()
{
try {
var testnum = 0;
// ===== test init =====
var testfile = do_get_file("toolkit/components/satchel/test/unit/formhistory_v999b.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");
var fh = Cc["@mozilla.org/satchel/form-history;1"].
getService(Ci.nsIFormHistory2);
// ===== 1 =====
testnum++;
// File should be empty
do_check_false(fh.hasEntries);
do_check_false(fh.entryExists("name-A", "value-A"));
// ===== 2 =====
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"));
// ===== 3 =====
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"));
} catch (e) {
throw "FAILED in test #" + testnum + " -- " + e;
}
}