mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-20 22:27:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
BIN
storage/test/unit/corruptDB.sqlite
Normal file
BIN
storage/test/unit/corruptDB.sqlite
Normal file
Binary file not shown.
1
storage/test/unit/fakeDB.sqlite
Normal file
1
storage/test/unit/fakeDB.sqlite
Normal file
|
|
@ -0,0 +1 @@
|
|||
BACON
|
||||
372
storage/test/unit/head_storage.js
Normal file
372
storage/test/unit/head_storage.js
Normal file
|
|
@ -0,0 +1,372 @@
|
|||
/* 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 Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
|
||||
do_get_profile();
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
|
||||
var gDBConn = null;
|
||||
|
||||
function getTestDB()
|
||||
{
|
||||
var db = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
db.append("test_storage.sqlite");
|
||||
return db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a corrupt database to test against.
|
||||
*/
|
||||
function getCorruptDB()
|
||||
{
|
||||
return do_get_file("corruptDB.sqlite");
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a fake (non-SQLite format) database to test against.
|
||||
*/
|
||||
function getFakeDB()
|
||||
{
|
||||
return do_get_file("fakeDB.sqlite");
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the test database file.
|
||||
*/
|
||||
function deleteTestDB()
|
||||
{
|
||||
print("*** Storage Tests: Trying to remove file!");
|
||||
var dbFile = getTestDB();
|
||||
if (dbFile.exists())
|
||||
try { dbFile.remove(false); } catch (e) { /* stupid windows box */ }
|
||||
}
|
||||
|
||||
function cleanup()
|
||||
{
|
||||
// close the connection
|
||||
print("*** Storage Tests: Trying to close!");
|
||||
getOpenedDatabase().close();
|
||||
|
||||
// we need to null out the database variable to get a new connection the next
|
||||
// time getOpenedDatabase is called
|
||||
gDBConn = null;
|
||||
|
||||
// removing test db
|
||||
deleteTestDB();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use asyncClose to cleanup a connection. Synchronous by means of internally
|
||||
* spinning an event loop.
|
||||
*/
|
||||
function asyncCleanup()
|
||||
{
|
||||
let closed = false;
|
||||
|
||||
// close the connection
|
||||
print("*** Storage Tests: Trying to asyncClose!");
|
||||
getOpenedDatabase().asyncClose(function () { closed = true; });
|
||||
|
||||
let curThread = Components.classes["@mozilla.org/thread-manager;1"]
|
||||
.getService().currentThread;
|
||||
while (!closed)
|
||||
curThread.processNextEvent(true);
|
||||
|
||||
// we need to null out the database variable to get a new connection the next
|
||||
// time getOpenedDatabase is called
|
||||
gDBConn = null;
|
||||
|
||||
// removing test db
|
||||
deleteTestDB();
|
||||
}
|
||||
|
||||
function getService()
|
||||
{
|
||||
return Cc["@mozilla.org/storage/service;1"].getService(Ci.mozIStorageService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a connection to the test database. Creates and caches the connection
|
||||
* if necessary, otherwise reuses the existing cached connection. This
|
||||
* connection shares its cache.
|
||||
*
|
||||
* @returns the mozIStorageConnection for the file.
|
||||
*/
|
||||
function getOpenedDatabase()
|
||||
{
|
||||
if (!gDBConn) {
|
||||
gDBConn = getService().openDatabase(getTestDB());
|
||||
}
|
||||
return gDBConn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a connection to the test database. Creates and caches the connection
|
||||
* if necessary, otherwise reuses the existing cached connection. This
|
||||
* connection doesn't share its cache.
|
||||
*
|
||||
* @returns the mozIStorageConnection for the file.
|
||||
*/
|
||||
function getOpenedUnsharedDatabase()
|
||||
{
|
||||
if (!gDBConn) {
|
||||
gDBConn = getService().openUnsharedDatabase(getTestDB());
|
||||
}
|
||||
return gDBConn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a specific database to use.
|
||||
*
|
||||
* @param aFile
|
||||
* The nsIFile representing the db file to open.
|
||||
* @returns the mozIStorageConnection for the file.
|
||||
*/
|
||||
function getDatabase(aFile)
|
||||
{
|
||||
return getService().openDatabase(aFile);
|
||||
}
|
||||
|
||||
function createStatement(aSQL)
|
||||
{
|
||||
return getOpenedDatabase().createStatement(aSQL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an asynchronous SQL statement.
|
||||
*
|
||||
* @param aSQL
|
||||
* The SQL to parse into a statement.
|
||||
* @returns a mozIStorageAsyncStatement from aSQL.
|
||||
*/
|
||||
function createAsyncStatement(aSQL)
|
||||
{
|
||||
return getOpenedDatabase().createAsyncStatement(aSQL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the given function and assert that it throws an exception expressing
|
||||
* the provided error code in its 'result' attribute. JS function expressions
|
||||
* can be used to do this concisely.
|
||||
*
|
||||
* Example:
|
||||
* expectError(Cr.NS_ERROR_INVALID_ARG, () => explodingFunction());
|
||||
*
|
||||
* @param aErrorCode
|
||||
* The error code to expect from invocation of aFunction.
|
||||
* @param aFunction
|
||||
* The function to invoke and expect an XPCOM-style error from.
|
||||
*/
|
||||
function expectError(aErrorCode, aFunction)
|
||||
{
|
||||
let exceptionCaught = false;
|
||||
try {
|
||||
aFunction();
|
||||
}
|
||||
catch (e) {
|
||||
if (e.result != aErrorCode) {
|
||||
do_throw("Got an exception, but the result code was not the expected " +
|
||||
"one. Expected " + aErrorCode + ", got " + e.result);
|
||||
}
|
||||
exceptionCaught = true;
|
||||
}
|
||||
if (!exceptionCaught)
|
||||
do_throw(aFunction + " should have thrown an exception but did not!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a query synchronously and verify that we get back the expected results.
|
||||
*
|
||||
* @param aSQLString
|
||||
* The SQL string for the query.
|
||||
* @param aBind
|
||||
* The value to bind at index 0.
|
||||
* @param aResults
|
||||
* A list of the expected values returned in the sole result row.
|
||||
* Express blobs as lists.
|
||||
*/
|
||||
function verifyQuery(aSQLString, aBind, aResults)
|
||||
{
|
||||
let stmt = getOpenedDatabase().createStatement(aSQLString);
|
||||
stmt.bindByIndex(0, aBind);
|
||||
try {
|
||||
do_check_true(stmt.executeStep());
|
||||
let nCols = stmt.numEntries;
|
||||
if (aResults.length != nCols)
|
||||
do_throw("Expected " + aResults.length + " columns in result but " +
|
||||
"there are only " + aResults.length + "!");
|
||||
for (let iCol = 0; iCol < nCols; iCol++) {
|
||||
let expectedVal = aResults[iCol];
|
||||
let valType = stmt.getTypeOfIndex(iCol);
|
||||
if (expectedVal === null) {
|
||||
do_check_eq(stmt.VALUE_TYPE_NULL, valType);
|
||||
do_check_true(stmt.getIsNull(iCol));
|
||||
}
|
||||
else if (typeof expectedVal == "number") {
|
||||
if (Math.floor(expectedVal) == expectedVal) {
|
||||
do_check_eq(stmt.VALUE_TYPE_INTEGER, valType);
|
||||
do_check_eq(expectedVal, stmt.getInt32(iCol));
|
||||
}
|
||||
else {
|
||||
do_check_eq(stmt.VALUE_TYPE_FLOAT, valType);
|
||||
do_check_eq(expectedVal, stmt.getDouble(iCol));
|
||||
}
|
||||
}
|
||||
else if (typeof expectedVal == "string") {
|
||||
do_check_eq(stmt.VALUE_TYPE_TEXT, valType);
|
||||
do_check_eq(expectedVal, stmt.getUTF8String(iCol));
|
||||
}
|
||||
else { // blob
|
||||
do_check_eq(stmt.VALUE_TYPE_BLOB, valType);
|
||||
let count = { value: 0 }, blob = { value: null };
|
||||
stmt.getBlob(iCol, count, blob);
|
||||
do_check_eq(count.value, expectedVal.length);
|
||||
for (let i = 0; i < count.value; i++) {
|
||||
do_check_eq(expectedVal[i], blob.value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of rows in the able with the given name using a synchronous
|
||||
* query.
|
||||
*
|
||||
* @param aTableName
|
||||
* The name of the table.
|
||||
* @return The number of rows.
|
||||
*/
|
||||
function getTableRowCount(aTableName)
|
||||
{
|
||||
var currentRows = 0;
|
||||
var countStmt = getOpenedDatabase().createStatement(
|
||||
"SELECT COUNT(1) AS count FROM " + aTableName
|
||||
);
|
||||
try {
|
||||
do_check_true(countStmt.executeStep());
|
||||
currentRows = countStmt.row.count;
|
||||
}
|
||||
finally {
|
||||
countStmt.finalize();
|
||||
}
|
||||
return currentRows;
|
||||
}
|
||||
|
||||
// Promise-Returning Functions
|
||||
|
||||
function asyncClone(db, readOnly) {
|
||||
let deferred = Promise.defer();
|
||||
db.asyncClone(readOnly, function (status, db2) {
|
||||
if (Components.isSuccessCode(status)) {
|
||||
deferred.resolve(db2);
|
||||
} else {
|
||||
deferred.reject(status);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function asyncClose(db) {
|
||||
let deferred = Promise.defer();
|
||||
db.asyncClose(function (status) {
|
||||
if (Components.isSuccessCode(status)) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject(status);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function openAsyncDatabase(file, options) {
|
||||
let deferred = Promise.defer();
|
||||
let properties;
|
||||
if (options) {
|
||||
properties = Cc["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Ci.nsIWritablePropertyBag);
|
||||
for (let k in options) {
|
||||
properties.setProperty(k, options[k]);
|
||||
}
|
||||
}
|
||||
getService().openAsyncDatabase(file, properties, function (status, db) {
|
||||
if (Components.isSuccessCode(status)) {
|
||||
deferred.resolve(db.QueryInterface(Ci.mozIStorageAsyncConnection));
|
||||
} else {
|
||||
deferred.reject(status);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function executeAsync(statement, onResult) {
|
||||
let deferred = Promise.defer();
|
||||
statement.executeAsync({
|
||||
handleError: function (error) {
|
||||
deferred.reject(error);
|
||||
},
|
||||
handleResult: function (result) {
|
||||
if (onResult) {
|
||||
onResult(result);
|
||||
}
|
||||
},
|
||||
handleCompletion: function (result) {
|
||||
deferred.resolve(result);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function executeMultipleStatementsAsync(db, statements, onResult) {
|
||||
let deferred = Promise.defer();
|
||||
db.executeAsync(statements, statements.length, {
|
||||
handleError: function (error) {
|
||||
deferred.reject(error);
|
||||
},
|
||||
handleResult: function (result) {
|
||||
if (onResult) {
|
||||
onResult(result);
|
||||
}
|
||||
},
|
||||
handleCompletion: function (result) {
|
||||
deferred.resolve(result);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function executeSimpleSQLAsync(db, query, onResult) {
|
||||
let deferred = Promise.defer();
|
||||
db.executeSimpleSQLAsync(query, {
|
||||
handleError(error) {
|
||||
deferred.reject(error);
|
||||
},
|
||||
handleResult(result) {
|
||||
if (onResult) {
|
||||
onResult(result);
|
||||
} else {
|
||||
do_throw("No results were expected");
|
||||
}
|
||||
},
|
||||
handleCompletion(result) {
|
||||
deferred.resolve(result);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
cleanup();
|
||||
174
storage/test/unit/locale_collation.txt
Normal file
174
storage/test/unit/locale_collation.txt
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
|
||||
!
|
||||
"
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
)
|
||||
*
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
;
|
||||
<
|
||||
=
|
||||
>
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
[
|
||||
\
|
||||
]
|
||||
^
|
||||
_
|
||||
`
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
{
|
||||
|
|
||||
}
|
||||
~
|
||||
ludwig van beethoven
|
||||
Ludwig van Beethoven
|
||||
Ludwig van beethoven
|
||||
Jane
|
||||
jane
|
||||
JANE
|
||||
jAne
|
||||
jaNe
|
||||
janE
|
||||
JAne
|
||||
JaNe
|
||||
JanE
|
||||
JANe
|
||||
JaNE
|
||||
JAnE
|
||||
jANE
|
||||
Umberto Eco
|
||||
Umberto eco
|
||||
umberto eco
|
||||
umberto Eco
|
||||
UMBERTO ECO
|
||||
ace
|
||||
bash
|
||||
*ace
|
||||
!ace
|
||||
%ace
|
||||
~ace
|
||||
#ace
|
||||
cork
|
||||
denizen
|
||||
[denizen]
|
||||
(denizen)
|
||||
{denizen}
|
||||
/denizen/
|
||||
#denizen#
|
||||
$denizen$
|
||||
@denizen
|
||||
elf
|
||||
full
|
||||
gnome
|
||||
gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Japanese
|
||||
gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Javanese
|
||||
hint
|
||||
Internationalization
|
||||
Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization
|
||||
Zinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizatio
|
||||
n
|
||||
Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalization
|
||||
ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTioninternationalizationinternationalizationinternationalizationinternationalization
|
||||
ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTion
|
||||
jostle
|
||||
kin
|
||||
Laymen
|
||||
lumens
|
||||
Lumens
|
||||
motleycrew
|
||||
motley crew
|
||||
niven's creative talents
|
||||
nivens creative talents
|
||||
opie
|
||||
posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rockies
|
||||
posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rokkies
|
||||
posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the rockies
|
||||
quilt's
|
||||
quilts
|
||||
quilt
|
||||
Rondo
|
||||
street
|
||||
tamale oxidization and iodization in rapid progress
|
||||
tamale oxidization and iodization in rapid Progress
|
||||
until
|
||||
vera
|
||||
Wobble
|
||||
Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoneme
|
||||
Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoname
|
||||
yearn
|
||||
zodiac
|
||||
a
|
||||
å
|
||||
26
storage/test/unit/test_bug-365166.js
Normal file
26
storage/test/unit/test_bug-365166.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Testcase for bug 365166 - crash [@ strlen] calling
|
||||
// mozIStorageStatement::getColumnName of a statement created with
|
||||
// "PRAGMA user_version" or "PRAGMA schema_version"
|
||||
function run_test() {
|
||||
test('user');
|
||||
test('schema');
|
||||
|
||||
function test(param)
|
||||
{
|
||||
var colName = param + "_version";
|
||||
var sql = "PRAGMA " + colName;
|
||||
|
||||
var file = getTestDB();
|
||||
var storageService = Components.classes["@mozilla.org/storage/service;1"].
|
||||
getService(Components.interfaces.mozIStorageService);
|
||||
var conn = storageService.openDatabase(file);
|
||||
var statement = conn.createStatement(sql);
|
||||
try {
|
||||
// This shouldn't crash:
|
||||
do_check_eq(statement.getColumnName(0), colName);
|
||||
} finally {
|
||||
statement.reset();
|
||||
statement.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
38
storage/test/unit/test_bug-393952.js
Normal file
38
storage/test/unit/test_bug-393952.js
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* 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/. */
|
||||
|
||||
// Testcase for bug 393952: crash when I try to VACUUM and one of the tables
|
||||
// has a UNIQUE text column. StorageUnicodeFunctions::likeFunction()
|
||||
// needs to handle null aArgv[0] and aArgv[1]
|
||||
|
||||
function setup()
|
||||
{
|
||||
getOpenedDatabase().createTable("t1", "x TEXT UNIQUE");
|
||||
|
||||
var stmt = createStatement("INSERT INTO t1 (x) VALUES ('a')");
|
||||
stmt.execute();
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_vacuum()
|
||||
{
|
||||
var stmt = createStatement("VACUUM;");
|
||||
stmt.executeStep();
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
var tests = [test_vacuum];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setup();
|
||||
|
||||
for (var i = 0; i < tests.length; i++)
|
||||
tests[i]();
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
46
storage/test/unit/test_bug-429521.js
Normal file
46
storage/test/unit/test_bug-429521.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* 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/. */
|
||||
|
||||
function setup() {
|
||||
getOpenedDatabase().createTable("t1", "x TEXT");
|
||||
|
||||
var stmt = createStatement("INSERT INTO t1 (x) VALUES ('/mozilla.org/20070129_1/Europe/Berlin')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_bug429521() {
|
||||
var stmt = createStatement(
|
||||
"SELECT DISTINCT(zone) FROM (" +
|
||||
"SELECT x AS zone FROM t1 WHERE x LIKE '/mozilla.org%'" +
|
||||
");");
|
||||
|
||||
print("*** test_bug429521: started");
|
||||
|
||||
try {
|
||||
while (stmt.executeStep()) {
|
||||
print("*** test_bug429521: step() Read wrapper.row.zone");
|
||||
|
||||
// BUG: the print commands after the following statement
|
||||
// are never executed. Script stops immediately.
|
||||
var tzId = stmt.row.zone;
|
||||
|
||||
print("*** test_bug429521: step() Read wrapper.row.zone finished");
|
||||
}
|
||||
} catch (e) {
|
||||
print("*** test_bug429521: " + e);
|
||||
}
|
||||
|
||||
print("*** test_bug429521: finished");
|
||||
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
setup();
|
||||
|
||||
test_bug429521();
|
||||
|
||||
cleanup();
|
||||
}
|
||||
51
storage/test/unit/test_bug-444233.js
Normal file
51
storage/test/unit/test_bug-444233.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/* 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/. */
|
||||
|
||||
function setup() {
|
||||
// Create the table
|
||||
getOpenedDatabase().createTable("test_bug444233",
|
||||
"id INTEGER PRIMARY KEY, value TEXT");
|
||||
|
||||
// Insert dummy data, using wrapper methods
|
||||
var stmt = createStatement("INSERT INTO test_bug444233 (value) VALUES (:value)");
|
||||
stmt.params.value = "value1";
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO test_bug444233 (value) VALUES (:value)");
|
||||
stmt.params.value = "value2";
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_bug444233() {
|
||||
print("*** test_bug444233: started");
|
||||
|
||||
// Check that there are 2 results
|
||||
var stmt = createStatement("SELECT COUNT(*) AS number FROM test_bug444233");
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(2, stmt.row.number);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
|
||||
print("*** test_bug444233: doing delete");
|
||||
|
||||
// Now try to delete using IN
|
||||
// Cheating since we know ids are 1,2
|
||||
try {
|
||||
var ids = [1, 2];
|
||||
stmt = createStatement("DELETE FROM test_bug444233 WHERE id IN (:ids)");
|
||||
stmt.params.ids = ids;
|
||||
} catch (e) {
|
||||
print("*** test_bug444233: successfully caught exception");
|
||||
}
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
setup();
|
||||
test_bug444233();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
72
storage/test/unit/test_cache_size.js
Normal file
72
storage/test/unit/test_cache_size.js
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// This file tests that dbs of various page sizes are using the right cache
|
||||
// size (bug 703113).
|
||||
|
||||
/**
|
||||
* In order to change the cache size, we must open a DB, change the page
|
||||
* size, create a table, close the DB, then re-open the DB. We then check
|
||||
* the cache size after reopening.
|
||||
*
|
||||
* @param dbOpener
|
||||
* function that opens the DB specified in file
|
||||
* @param file
|
||||
* file holding the database
|
||||
* @param pageSize
|
||||
* the DB's page size
|
||||
* @param expectedCacheSize
|
||||
* the expected cache size for the given page size
|
||||
*/
|
||||
function check_size(dbOpener, file, pageSize, expectedCacheSize)
|
||||
{
|
||||
// Open the DB, immediately change its page size.
|
||||
let db = dbOpener(file);
|
||||
db.executeSimpleSQL("PRAGMA page_size = " + pageSize);
|
||||
|
||||
// Check the page size change worked.
|
||||
let stmt = db.createStatement("PRAGMA page_size");
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(stmt.row.page_size, pageSize);
|
||||
stmt.finalize();
|
||||
|
||||
// Create a simple table.
|
||||
db.executeSimpleSQL("CREATE TABLE test ( id INTEGER PRIMARY KEY )");
|
||||
|
||||
// Close and re-open the DB.
|
||||
db.close();
|
||||
db = dbOpener(file);
|
||||
|
||||
// Check cache size is as expected.
|
||||
stmt = db.createStatement("PRAGMA cache_size");
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(stmt.row.cache_size, expectedCacheSize);
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function new_file(name)
|
||||
{
|
||||
let file = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
file.append(name + ".sqlite");
|
||||
do_check_false(file.exists());
|
||||
return file;
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
const kExpectedCacheSize = -2048; // 2MiB
|
||||
|
||||
let pageSizes = [
|
||||
1024,
|
||||
4096,
|
||||
32768,
|
||||
];
|
||||
|
||||
for (let i = 0; i < pageSizes.length; i++) {
|
||||
let pageSize = pageSizes[i];
|
||||
check_size(getDatabase,
|
||||
new_file("shared" + pageSize), pageSize, kExpectedCacheSize);
|
||||
check_size(getService().openUnsharedDatabase,
|
||||
new_file("unshared" + pageSize), pageSize, kExpectedCacheSize);
|
||||
}
|
||||
}
|
||||
52
storage/test/unit/test_chunk_growth.js
Normal file
52
storage/test/unit/test_chunk_growth.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// This file tests SQLITE_FCNTL_CHUNK_SIZE behaves as expected
|
||||
|
||||
function run_sql(d, sql) {
|
||||
var stmt = d.createStatement(sql);
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function new_file(name) {
|
||||
var file = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
file.append(name);
|
||||
return file;
|
||||
}
|
||||
|
||||
function get_size(name) {
|
||||
return new_file(name).fileSize;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
const filename = "chunked.sqlite";
|
||||
const CHUNK_SIZE = 512 * 1024;
|
||||
var d = getDatabase(new_file(filename));
|
||||
try {
|
||||
d.setGrowthIncrement(CHUNK_SIZE, "");
|
||||
} catch (e) {
|
||||
if (e.result != Cr.NS_ERROR_FILE_TOO_BIG) {
|
||||
throw e;
|
||||
}
|
||||
print("Too little free space to set CHUNK_SIZE!");
|
||||
return;
|
||||
}
|
||||
run_sql(d, "CREATE TABLE bloat(data varchar)");
|
||||
|
||||
var orig_size = get_size(filename);
|
||||
/* Dump in at least 32K worth of data.
|
||||
* While writing ensure that the file size growth in chunksize set above.
|
||||
*/
|
||||
const str1024 = new Array(1024).join("T");
|
||||
for (var i = 0; i < 32; i++) {
|
||||
run_sql(d, "INSERT INTO bloat VALUES('" + str1024 + "')");
|
||||
var size = get_size(filename);
|
||||
// Must not grow in small increments.
|
||||
do_check_true(size == orig_size || size >= CHUNK_SIZE);
|
||||
}
|
||||
/* In addition to growing in chunk-size increments, the db
|
||||
* should shrink in chunk-size increments too.
|
||||
*/
|
||||
run_sql(d, "DELETE FROM bloat");
|
||||
run_sql(d, "VACUUM");
|
||||
do_check_true(get_size(filename) >= CHUNK_SIZE);
|
||||
}
|
||||
|
||||
125
storage/test/unit/test_connection_asyncClose.js
Normal file
125
storage/test/unit/test_connection_asyncClose.js
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/* 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/. */
|
||||
|
||||
/*
|
||||
* Thorough branch coverage for asyncClose.
|
||||
*
|
||||
* Coverage of asyncClose by connection state at time of AsyncClose invocation:
|
||||
* - (asyncThread && mDBConn) => AsyncCloseConnection used, actually closes
|
||||
* - test_asyncClose_does_not_complete_before_statements
|
||||
* - test_double_asyncClose_throws
|
||||
* - test_asyncClose_does_not_throw_without_callback
|
||||
* - (asyncThread && !mDBConn) => AsyncCloseConnection used, although no close
|
||||
* is required. Note that this is only possible in the event that
|
||||
* openAsyncDatabase was used and we failed to open the database.
|
||||
* Additionally, the async connection will never be exposed to the caller and
|
||||
* AsyncInitDatabase will be the one to (automatically) call AsyncClose.
|
||||
* - test_asyncClose_failed_open
|
||||
* - (!asyncThread && mDBConn) => Close() invoked, actually closes
|
||||
* - test_asyncClose_on_sync_db
|
||||
* - (!asyncThread && !mDBConn) => Close() invoked, no close needed, errors.
|
||||
* This happens if the database has already been closed.
|
||||
* - test_double_asyncClose_throws
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Sanity check that our close indeed happens after asynchronously executed
|
||||
* statements scheduled during the same turn of the event loop. Note that we
|
||||
* just care that the statement says it completed without error, we're not
|
||||
* worried that the close will happen and then the statement will magically
|
||||
* complete.
|
||||
*/
|
||||
add_task(function* test_asyncClose_does_not_complete_before_statements() {
|
||||
let db = getService().openDatabase(getTestDB());
|
||||
let stmt = db.createStatement("SELECT * FROM sqlite_master");
|
||||
// Issue the executeAsync but don't yield for it...
|
||||
let asyncStatementPromise = executeAsync(stmt);
|
||||
stmt.finalize();
|
||||
|
||||
// Issue the close. (And now the order of yielding doesn't matter.)
|
||||
// Branch coverage: (asyncThread && mDBConn)
|
||||
yield asyncClose(db);
|
||||
equal((yield asyncStatementPromise),
|
||||
Ci.mozIStorageStatementCallback.REASON_FINISHED);
|
||||
});
|
||||
|
||||
/**
|
||||
* Open an async database (ensures the async thread is created) and then invoke
|
||||
* AsyncClose() twice without yielding control flow. The first will initiate
|
||||
* the actual async close after calling setClosedState which synchronously
|
||||
* impacts what the second call will observe. The second call will then see the
|
||||
* async thread is not available and fall back to invoking Close() which will
|
||||
* notice the mDBConn is already gone.
|
||||
*/
|
||||
add_task(function* test_double_asyncClose_throws() {
|
||||
let db = yield openAsyncDatabase(getTestDB());
|
||||
|
||||
// (Don't yield control flow yet, save the promise for after we make the
|
||||
// second call.)
|
||||
// Branch coverage: (asyncThread && mDBConn)
|
||||
let realClosePromise = yield asyncClose(db);
|
||||
try {
|
||||
// Branch coverage: (!asyncThread && !mDBConn)
|
||||
db.asyncClose();
|
||||
ok(false, "should have thrown");
|
||||
} catch (e) {
|
||||
equal(e.result, Cr.NS_ERROR_NOT_INITIALIZED);
|
||||
}
|
||||
|
||||
yield realClosePromise;
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a sync db connection and never take it asynchronous and then call
|
||||
* asyncClose on it. This will bring the async thread to life to perform the
|
||||
* shutdown to avoid blocking the main thread, although we won't be able to
|
||||
* tell the difference between this happening and the method secretly shunting
|
||||
* to close().
|
||||
*/
|
||||
add_task(function* test_asyncClose_on_sync_db() {
|
||||
let db = getService().openDatabase(getTestDB());
|
||||
|
||||
// Branch coverage: (!asyncThread && mDBConn)
|
||||
yield asyncClose(db);
|
||||
ok(true, 'closed sync connection asynchronously');
|
||||
});
|
||||
|
||||
/**
|
||||
* Fail to asynchronously open a DB in order to get an async thread existing
|
||||
* without having an open database and asyncClose invoked. As per the file
|
||||
* doc-block, note that asyncClose will automatically be invoked by the
|
||||
* AsyncInitDatabase when it fails to open the database. We will never be
|
||||
* provided with a reference to the connection and so cannot call AsyncClose on
|
||||
* it ourselves.
|
||||
*/
|
||||
add_task(function* test_asyncClose_failed_open() {
|
||||
// This will fail and the promise will be rejected.
|
||||
let openPromise = openAsyncDatabase(getFakeDB());
|
||||
yield openPromise.then(
|
||||
() => {
|
||||
ok(false, 'we should have failed to open the db; this test is broken!');
|
||||
},
|
||||
() => {
|
||||
ok(true, 'correctly failed to open db; bg asyncClose should happen');
|
||||
}
|
||||
);
|
||||
// (NB: we are unable to observe the thread shutdown, but since we never open
|
||||
// a database, this test is not going to interfere with other tests so much.)
|
||||
});
|
||||
|
||||
// THE TEST BELOW WANTS TO BE THE LAST TEST WE RUN. DO NOT MAKE IT SAD.
|
||||
/**
|
||||
* Verify that asyncClose without a callback does not explode. Without a
|
||||
* callback the shutdown is not actually observable, so we run this test last
|
||||
* in order to avoid weird overlaps.
|
||||
*/
|
||||
add_task(function* test_asyncClose_does_not_throw_without_callback() {
|
||||
let db = yield openAsyncDatabase(getTestDB());
|
||||
// Branch coverage: (asyncThread && mDBConn)
|
||||
db.asyncClose();
|
||||
ok(true, 'if we shutdown cleanly and do not crash, then we succeeded');
|
||||
});
|
||||
// OBEY SHOUTING UPPER-CASE COMMENTS.
|
||||
// ADD TESTS ABOVE THE FORMER TEST, NOT BELOW IT.
|
||||
171
storage/test/unit/test_connection_executeAsync.js
Normal file
171
storage/test/unit/test_connection_executeAsync.js
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/* 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/. */
|
||||
|
||||
/*
|
||||
* This file tests the functionality of mozIStorageConnection::executeAsync for
|
||||
* both mozIStorageStatement and mozIStorageAsyncStatement.
|
||||
*
|
||||
* A single database connection is used for the entirety of the test, which is
|
||||
* a legacy thing, but we otherwise use the modern promise-based driver and
|
||||
* async helpers.
|
||||
*/
|
||||
|
||||
const INTEGER = 1;
|
||||
const TEXT = "this is test text";
|
||||
const REAL = 3.23;
|
||||
const BLOB = [1, 2];
|
||||
|
||||
add_task(function* test_first_create_and_add() {
|
||||
// synchronously open the database and let gDBConn hold onto it because we
|
||||
// use this database
|
||||
let db = getOpenedDatabase();
|
||||
// synchronously set up our table *that will be used for the rest of the file*
|
||||
db.executeSimpleSQL(
|
||||
"CREATE TABLE test (" +
|
||||
"id INTEGER, " +
|
||||
"string TEXT, " +
|
||||
"number REAL, " +
|
||||
"nuller NULL, " +
|
||||
"blober BLOB" +
|
||||
")"
|
||||
);
|
||||
|
||||
let stmts = [];
|
||||
stmts[0] = db.createStatement(
|
||||
"INSERT INTO test (id, string, number, nuller, blober) VALUES (?, ?, ?, ?, ?)"
|
||||
);
|
||||
stmts[0].bindByIndex(0, INTEGER);
|
||||
stmts[0].bindByIndex(1, TEXT);
|
||||
stmts[0].bindByIndex(2, REAL);
|
||||
stmts[0].bindByIndex(3, null);
|
||||
stmts[0].bindBlobByIndex(4, BLOB, BLOB.length);
|
||||
stmts[1] = getOpenedDatabase().createAsyncStatement(
|
||||
"INSERT INTO test (string, number, nuller, blober) VALUES (?, ?, ?, ?)"
|
||||
);
|
||||
stmts[1].bindByIndex(0, TEXT);
|
||||
stmts[1].bindByIndex(1, REAL);
|
||||
stmts[1].bindByIndex(2, null);
|
||||
stmts[1].bindBlobByIndex(3, BLOB, BLOB.length);
|
||||
|
||||
// asynchronously execute the statements
|
||||
let execResult = yield executeMultipleStatementsAsync(
|
||||
db,
|
||||
stmts,
|
||||
function(aResultSet) {
|
||||
ok(false, 'we only did inserts so we should not have gotten results!');
|
||||
});
|
||||
equal(Ci.mozIStorageStatementCallback.REASON_FINISHED, execResult,
|
||||
'execution should have finished successfully.');
|
||||
|
||||
// Check that the result is in the table
|
||||
let stmt = db.createStatement(
|
||||
"SELECT string, number, nuller, blober FROM test WHERE id = ?"
|
||||
);
|
||||
stmt.bindByIndex(0, INTEGER);
|
||||
try {
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(TEXT, stmt.getString(0));
|
||||
do_check_eq(REAL, stmt.getDouble(1));
|
||||
do_check_true(stmt.getIsNull(2));
|
||||
let count = { value: 0 };
|
||||
let blob = { value: null };
|
||||
stmt.getBlob(3, count, blob);
|
||||
do_check_eq(BLOB.length, count.value);
|
||||
for (let i = 0; i < BLOB.length; i++)
|
||||
do_check_eq(BLOB[i], blob.value[i]);
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
// Make sure we have two rows in the table
|
||||
stmt = db.createStatement(
|
||||
"SELECT COUNT(1) FROM test"
|
||||
);
|
||||
try {
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(2, stmt.getInt32(0));
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
stmts[0].finalize();
|
||||
stmts[1].finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_last_multiple_bindings_on_statements() {
|
||||
// This tests to make sure that we pass all the statements multiply bound
|
||||
// parameters when we call executeAsync.
|
||||
const AMOUNT_TO_ADD = 5;
|
||||
const ITERATIONS = 5;
|
||||
|
||||
let stmts = [];
|
||||
let db = getOpenedDatabase();
|
||||
let sqlString = "INSERT INTO test (id, string, number, nuller, blober) " +
|
||||
"VALUES (:int, :text, :real, :null, :blob)";
|
||||
// We run the same statement twice, and should insert 2 * AMOUNT_TO_ADD.
|
||||
for (let i = 0; i < ITERATIONS; i++) {
|
||||
// alternate the type of statement we create
|
||||
if (i % 2)
|
||||
stmts[i] = db.createStatement(sqlString);
|
||||
else
|
||||
stmts[i] = db.createAsyncStatement(sqlString);
|
||||
|
||||
let params = stmts[i].newBindingParamsArray();
|
||||
for (let j = 0; j < AMOUNT_TO_ADD; j++) {
|
||||
let bp = params.newBindingParams();
|
||||
bp.bindByName("int", INTEGER);
|
||||
bp.bindByName("text", TEXT);
|
||||
bp.bindByName("real", REAL);
|
||||
bp.bindByName("null", null);
|
||||
bp.bindBlobByName("blob", BLOB, BLOB.length);
|
||||
params.addParams(bp);
|
||||
}
|
||||
stmts[i].bindParameters(params);
|
||||
}
|
||||
|
||||
// Get our current number of rows in the table.
|
||||
let currentRows = 0;
|
||||
let countStmt = getOpenedDatabase().createStatement(
|
||||
"SELECT COUNT(1) AS count FROM test"
|
||||
);
|
||||
try {
|
||||
do_check_true(countStmt.executeStep());
|
||||
currentRows = countStmt.row.count;
|
||||
}
|
||||
finally {
|
||||
countStmt.reset();
|
||||
}
|
||||
|
||||
// Execute asynchronously.
|
||||
let execResult = yield executeMultipleStatementsAsync(
|
||||
db,
|
||||
stmts,
|
||||
function(aResultSet) {
|
||||
ok(false, 'we only did inserts so we should not have gotten results!');
|
||||
});
|
||||
equal(Ci.mozIStorageStatementCallback.REASON_FINISHED, execResult,
|
||||
'execution should have finished successfully.');
|
||||
|
||||
// Check to make sure we added all of our rows.
|
||||
try {
|
||||
do_check_true(countStmt.executeStep());
|
||||
do_check_eq(currentRows + (ITERATIONS * AMOUNT_TO_ADD),
|
||||
countStmt.row.count);
|
||||
}
|
||||
finally {
|
||||
countStmt.finalize();
|
||||
}
|
||||
|
||||
stmts.forEach(stmt => stmt.finalize());
|
||||
|
||||
// we are the last test using this connection and since it has gone async
|
||||
// we *must* call asyncClose on it.
|
||||
yield asyncClose(db);
|
||||
gDBConn = null;
|
||||
});
|
||||
|
||||
// If you add a test down here you will need to move the asyncClose or clean
|
||||
// things up a little more.
|
||||
79
storage/test/unit/test_connection_executeSimpleSQLAsync.js
Normal file
79
storage/test/unit/test_connection_executeSimpleSQLAsync.js
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/* 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/. */
|
||||
|
||||
/*
|
||||
* This file tests the functionality of
|
||||
* mozIStorageAsyncConnection::executeSimpleSQLAsync.
|
||||
*/
|
||||
|
||||
const INTEGER = 1;
|
||||
const TEXT = "this is test text";
|
||||
const REAL = 3.23;
|
||||
|
||||
add_task(function* test_create_and_add() {
|
||||
let adb = yield openAsyncDatabase(getTestDB());
|
||||
|
||||
let completion = yield executeSimpleSQLAsync(adb,
|
||||
"CREATE TABLE test (id INTEGER, string TEXT, number REAL)");
|
||||
|
||||
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, completion);
|
||||
|
||||
completion = yield executeSimpleSQLAsync(adb,
|
||||
"INSERT INTO test (id, string, number) " +
|
||||
"VALUES (" + INTEGER + ", \"" + TEXT + "\", " + REAL + ")");
|
||||
|
||||
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, completion);
|
||||
|
||||
let result = null;
|
||||
|
||||
completion = yield executeSimpleSQLAsync(adb,
|
||||
"SELECT string, number FROM test WHERE id = 1",
|
||||
function (aResultSet) {
|
||||
result = aResultSet.getNextRow();
|
||||
do_check_eq(2, result.numEntries);
|
||||
do_check_eq(TEXT, result.getString(0));
|
||||
do_check_eq(REAL, result.getDouble(1));
|
||||
}
|
||||
);
|
||||
|
||||
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, completion);
|
||||
do_check_neq(result, null);
|
||||
result = null;
|
||||
|
||||
yield executeSimpleSQLAsync(adb, "SELECT COUNT(0) FROM test",
|
||||
function (aResultSet) {
|
||||
result = aResultSet.getNextRow();
|
||||
do_check_eq(1, result.getInt32(0));
|
||||
});
|
||||
|
||||
do_check_neq(result, null);
|
||||
|
||||
yield asyncClose(adb);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_asyncClose_does_not_complete_before_statement() {
|
||||
let adb = yield openAsyncDatabase(getTestDB());
|
||||
let executed = false;
|
||||
|
||||
let reason = yield executeSimpleSQLAsync(adb, "SELECT * FROM test",
|
||||
function (aResultSet) {
|
||||
let result = aResultSet.getNextRow();
|
||||
|
||||
do_check_neq(result, null);
|
||||
do_check_eq(3, result.numEntries);
|
||||
do_check_eq(INTEGER, result.getInt32(0));
|
||||
do_check_eq(TEXT, result.getString(1));
|
||||
do_check_eq(REAL, result.getDouble(2));
|
||||
executed = true;
|
||||
}
|
||||
);
|
||||
|
||||
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, reason);
|
||||
|
||||
// Ensure that the statement executed to completion.
|
||||
do_check_true(executed);
|
||||
|
||||
yield asyncClose(adb);
|
||||
});
|
||||
125
storage/test/unit/test_js_helpers.js
Normal file
125
storage/test/unit/test_js_helpers.js
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sw=2 ts=2 sts=2 et : */
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file tests that the JS language helpers in various ways.
|
||||
*/
|
||||
|
||||
// Test Functions
|
||||
|
||||
function test_params_enumerate()
|
||||
{
|
||||
let stmt = createStatement(
|
||||
"SELECT * FROM test WHERE id IN (:a, :b, :c)"
|
||||
);
|
||||
|
||||
// Make sure they are right.
|
||||
let expected = ["a", "b", "c"];
|
||||
let index = 0;
|
||||
for (let name in stmt.params) {
|
||||
if (name == "QueryInterface")
|
||||
continue;
|
||||
do_check_eq(name, expected[index++]);
|
||||
}
|
||||
}
|
||||
|
||||
function test_params_prototype()
|
||||
{
|
||||
let stmt = createStatement(
|
||||
"SELECT * FROM sqlite_master"
|
||||
);
|
||||
|
||||
// Set a property on the prototype and make sure it exist (will not be a
|
||||
// bindable parameter, however).
|
||||
Object.getPrototypeOf(stmt.params).test = 2;
|
||||
do_check_eq(stmt.params.test, 2);
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_row_prototype()
|
||||
{
|
||||
let stmt = createStatement(
|
||||
"SELECT * FROM sqlite_master"
|
||||
);
|
||||
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
// Set a property on the prototype and make sure it exists (will not be in the
|
||||
// results, however).
|
||||
Object.getPrototypeOf(stmt.row).test = 2;
|
||||
do_check_eq(stmt.row.test, 2);
|
||||
|
||||
// Clean up after ourselves.
|
||||
delete Object.getPrototypeOf(stmt.row).test;
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_params_gets_sync()
|
||||
{
|
||||
// Added for bug 562866.
|
||||
/*
|
||||
let stmt = createStatement(
|
||||
"SELECT * FROM test WHERE id IN (:a, :b, :c)"
|
||||
);
|
||||
|
||||
// Make sure we do not assert in getting the value.
|
||||
let originalCount = Object.getOwnPropertyNames(stmt.params).length;
|
||||
let expected = ["a", "b", "c"];
|
||||
for (let name of expected) {
|
||||
stmt.params[name];
|
||||
}
|
||||
|
||||
// Now make sure we didn't magically get any additional properties.
|
||||
let finalCount = Object.getOwnPropertyNames(stmt.params).length;
|
||||
do_check_eq(originalCount + expected.length, finalCount);
|
||||
*/
|
||||
}
|
||||
|
||||
function test_params_gets_async()
|
||||
{
|
||||
// Added for bug 562866.
|
||||
/*
|
||||
let stmt = createAsyncStatement(
|
||||
"SELECT * FROM test WHERE id IN (:a, :b, :c)"
|
||||
);
|
||||
|
||||
// Make sure we do not assert in getting the value.
|
||||
let originalCount = Object.getOwnPropertyNames(stmt.params).length;
|
||||
let expected = ["a", "b", "c"];
|
||||
for (let name of expected) {
|
||||
stmt.params[name];
|
||||
}
|
||||
|
||||
// Now make sure we didn't magically get any additional properties.
|
||||
let finalCount = Object.getOwnPropertyNames(stmt.params).length;
|
||||
do_check_eq(originalCount + expected.length, finalCount);
|
||||
*/
|
||||
}
|
||||
|
||||
// Test Runner
|
||||
|
||||
var tests = [
|
||||
test_params_enumerate,
|
||||
test_params_prototype,
|
||||
test_row_prototype,
|
||||
test_params_gets_sync,
|
||||
test_params_gets_async,
|
||||
];
|
||||
function run_test()
|
||||
{
|
||||
cleanup();
|
||||
|
||||
// Create our database.
|
||||
getOpenedDatabase().executeSimpleSQL(
|
||||
"CREATE TABLE test (" +
|
||||
"id INTEGER PRIMARY KEY " +
|
||||
")"
|
||||
);
|
||||
|
||||
// Run the tests.
|
||||
tests.forEach(test => test());
|
||||
}
|
||||
74
storage/test/unit/test_levenshtein.js
Normal file
74
storage/test/unit/test_levenshtein.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests the Levenshtein Distance function we've registered.
|
||||
|
||||
function createUtf16Database()
|
||||
{
|
||||
print("Creating the in-memory UTF-16-encoded database.");
|
||||
let conn = getService().openSpecialDatabase("memory");
|
||||
conn.executeSimpleSQL("PRAGMA encoding = 'UTF-16'");
|
||||
|
||||
print("Make sure the encoding was set correctly and is now UTF-16.");
|
||||
let stmt = conn.createStatement("PRAGMA encoding");
|
||||
do_check_true(stmt.executeStep());
|
||||
let enc = stmt.getString(0);
|
||||
stmt.finalize();
|
||||
|
||||
// The value returned will actually be UTF-16le or UTF-16be.
|
||||
do_check_true(enc === "UTF-16le" || enc === "UTF-16be");
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
function check_levenshtein(db, s, t, expectedDistance)
|
||||
{
|
||||
var stmt = db.createStatement("SELECT levenshteinDistance(:s, :t) AS result");
|
||||
stmt.params.s = s;
|
||||
stmt.params.t = t;
|
||||
try {
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(expectedDistance, stmt.row.result);
|
||||
} finally {
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
function testLevenshtein(db)
|
||||
{
|
||||
// Basic tests.
|
||||
check_levenshtein(db, "", "", 0);
|
||||
check_levenshtein(db, "foo", "", 3);
|
||||
check_levenshtein(db, "", "bar", 3);
|
||||
check_levenshtein(db, "yellow", "hello", 2);
|
||||
check_levenshtein(db, "gumbo", "gambol", 2);
|
||||
check_levenshtein(db, "kitten", "sitten", 1);
|
||||
check_levenshtein(db, "sitten", "sittin", 1);
|
||||
check_levenshtein(db, "sittin", "sitting", 1);
|
||||
check_levenshtein(db, "kitten", "sitting", 3);
|
||||
check_levenshtein(db, "Saturday", "Sunday", 3);
|
||||
check_levenshtein(db, "YHCQPGK", "LAHYQQKPGKA", 6);
|
||||
|
||||
// Test SQL NULL handling.
|
||||
check_levenshtein(db, "foo", null, null);
|
||||
check_levenshtein(db, null, "bar", null);
|
||||
check_levenshtein(db, null, null, null);
|
||||
|
||||
// The levenshteinDistance function allocates temporary memory on the stack
|
||||
// if it can. Test some strings long enough to force a heap allocation.
|
||||
var dots1000 = Array(1001).join(".");
|
||||
var dashes1000 = Array(1001).join("-");
|
||||
check_levenshtein(db, dots1000, dashes1000, 1000);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
testLevenshtein(getOpenedDatabase());
|
||||
testLevenshtein(createUtf16Database());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
202
storage/test/unit/test_like.js
Normal file
202
storage/test/unit/test_like.js
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests our LIKE implementation since we override it for unicode
|
||||
|
||||
function setup()
|
||||
{
|
||||
getOpenedDatabase().createTable("t1", "x TEXT");
|
||||
|
||||
var stmt = createStatement("INSERT INTO t1 (x) VALUES ('a')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('ab')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('abc')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('abcd')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('acd')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('abd')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('bc')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('bcd')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('xyz')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('ABC')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('CDE')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES ('ABC abc xyz')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_count()
|
||||
{
|
||||
var stmt = createStatement("SELECT count(*) FROM t1;");
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(stmt.getInt32(0), 12);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_like_1()
|
||||
{
|
||||
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
|
||||
stmt.bindByIndex(0, 'abc');
|
||||
var solutions = ["abc", "ABC"];
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_false(stmt.executeStep());
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_like_2()
|
||||
{
|
||||
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
|
||||
stmt.bindByIndex(0, 'ABC');
|
||||
var solutions = ["abc", "ABC"];
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_false(stmt.executeStep());
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_like_3()
|
||||
{
|
||||
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
|
||||
stmt.bindByIndex(0, 'aBc');
|
||||
var solutions = ["abc", "ABC"];
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_false(stmt.executeStep());
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_like_4()
|
||||
{
|
||||
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
|
||||
stmt.bindByIndex(0, 'abc%');
|
||||
var solutions = ["abc", "abcd", "ABC", "ABC abc xyz"];
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_false(stmt.executeStep());
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_like_5()
|
||||
{
|
||||
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
|
||||
stmt.bindByIndex(0, 'a_c');
|
||||
var solutions = ["abc", "ABC"];
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_false(stmt.executeStep());
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_like_6()
|
||||
{
|
||||
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
|
||||
stmt.bindByIndex(0, 'ab%d');
|
||||
var solutions = ["abcd", "abd"];
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_false(stmt.executeStep());
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_like_7()
|
||||
{
|
||||
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
|
||||
stmt.bindByIndex(0, 'a_c%');
|
||||
var solutions = ["abc", "abcd", "ABC", "ABC abc xyz"];
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_false(stmt.executeStep());
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_like_8()
|
||||
{
|
||||
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
|
||||
stmt.bindByIndex(0, '%bcd');
|
||||
var solutions = ["abcd", "bcd"];
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_true(solutions.indexOf(stmt.getString(0)) != -1);
|
||||
do_check_false(stmt.executeStep());
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
var tests = [test_count, test_like_1, test_like_2, test_like_3, test_like_4,
|
||||
test_like_5, test_like_6, test_like_7, test_like_8];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setup();
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
tests[i]();
|
||||
}
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
60
storage/test/unit/test_like_escape.js
Normal file
60
storage/test/unit/test_like_escape.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/* 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 LATIN1_AE = "\xc6";
|
||||
const LATIN1_ae = "\xe6";
|
||||
|
||||
function setup()
|
||||
{
|
||||
getOpenedDatabase().createTable("t1", "x TEXT");
|
||||
|
||||
var stmt = createStatement("INSERT INTO t1 (x) VALUES ('foo/bar_baz%20cheese')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("INSERT INTO t1 (x) VALUES (?1)");
|
||||
// insert LATIN_ae, but search on LATIN_AE
|
||||
stmt.bindByIndex(0, "foo%20" + LATIN1_ae + "/_bar");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_escape_for_like_ascii()
|
||||
{
|
||||
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?1 ESCAPE '/'");
|
||||
var paramForLike = stmt.escapeStringForLIKE("oo/bar_baz%20chees", '/');
|
||||
// verify that we escaped / _ and %
|
||||
do_check_eq(paramForLike, "oo//bar/_baz/%20chees");
|
||||
// prepend and append with % for "contains"
|
||||
stmt.bindByIndex(0, "%" + paramForLike + "%");
|
||||
stmt.executeStep();
|
||||
do_check_eq("foo/bar_baz%20cheese", stmt.getString(0));
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_escape_for_like_non_ascii()
|
||||
{
|
||||
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?1 ESCAPE '/'");
|
||||
var paramForLike = stmt.escapeStringForLIKE("oo%20" + LATIN1_AE + "/_ba", '/');
|
||||
// verify that we escaped / _ and %
|
||||
do_check_eq(paramForLike, "oo/%20" + LATIN1_AE + "///_ba");
|
||||
// prepend and append with % for "contains"
|
||||
stmt.bindByIndex(0, "%" + paramForLike + "%");
|
||||
stmt.executeStep();
|
||||
do_check_eq("foo%20" + LATIN1_ae + "/_bar", stmt.getString(0));
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
var tests = [test_escape_for_like_ascii, test_escape_for_like_non_ascii];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setup();
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
tests[i]();
|
||||
}
|
||||
|
||||
cleanup();
|
||||
}
|
||||
304
storage/test/unit/test_locale_collation.js
Normal file
304
storage/test/unit/test_locale_collation.js
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* 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/. */
|
||||
|
||||
/**
|
||||
* Bug 499990 - Locale-aware collation
|
||||
*
|
||||
* Tests our custom, locale-aware collating sequences.
|
||||
*/
|
||||
|
||||
// The name of the file containing the strings we'll sort during this test.
|
||||
// The file's data is taken from intl/locale/tests/sort/us-ascii_base.txt and
|
||||
// and intl/locale/tests/sort/us-ascii_sort.txt.
|
||||
const DATA_BASENAME = "locale_collation.txt";
|
||||
|
||||
// The test data from DATA_BASENAME is read into this array.
|
||||
var gStrings;
|
||||
|
||||
// A collation created from the application's locale. Used by localeCompare().
|
||||
var gLocaleCollation;
|
||||
|
||||
// A connection to our in-memory UTF-16-encoded database.
|
||||
var gUtf16Conn;
|
||||
|
||||
// Helper Functions
|
||||
|
||||
/**
|
||||
* Since we create a UTF-16 database we have to clean it up, in addition to
|
||||
* the normal cleanup of Storage tests.
|
||||
*/
|
||||
function cleanupLocaleTests()
|
||||
{
|
||||
print("-- Cleaning up test_locale_collation.js suite.");
|
||||
gUtf16Conn.close();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test database similar to the default one created in
|
||||
* head_storage.js, except that this one uses UTF-16 encoding.
|
||||
*
|
||||
* @return A connection to the database.
|
||||
*/
|
||||
function createUtf16Database()
|
||||
{
|
||||
print("Creating the in-memory UTF-16-encoded database.");
|
||||
let conn = getService().openSpecialDatabase("memory");
|
||||
conn.executeSimpleSQL("PRAGMA encoding = 'UTF-16'");
|
||||
|
||||
print("Make sure the encoding was set correctly and is now UTF-16.");
|
||||
let stmt = conn.createStatement("PRAGMA encoding");
|
||||
do_check_true(stmt.executeStep());
|
||||
let enc = stmt.getString(0);
|
||||
stmt.finalize();
|
||||
|
||||
// The value returned will actually be UTF-16le or UTF-16be.
|
||||
do_check_true(enc === "UTF-16le" || enc === "UTF-16be");
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares aActual to aExpected, ensuring that the numbers and orderings of
|
||||
* the two arrays' elements are the same.
|
||||
*
|
||||
* @param aActual
|
||||
* An array of strings retrieved from the database.
|
||||
* @param aExpected
|
||||
* An array of strings to which aActual should be equivalent.
|
||||
*/
|
||||
function ensureResultsAreCorrect(aActual, aExpected)
|
||||
{
|
||||
print("Actual results: " + aActual);
|
||||
print("Expected results: " + aExpected);
|
||||
|
||||
do_check_eq(aActual.length, aExpected.length);
|
||||
for (let i = 0; i < aActual.length; i++)
|
||||
do_check_eq(aActual[i], aExpected[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously SELECTs all rows from the test table of the given database
|
||||
* using the given collation.
|
||||
*
|
||||
* @param aCollation
|
||||
* The name of one of our custom locale collations. The rows are
|
||||
* ordered by this collation.
|
||||
* @param aConn
|
||||
* A connection to either the UTF-8 database or the UTF-16 database.
|
||||
* @return The resulting strings in an array.
|
||||
*/
|
||||
function getResults(aCollation, aConn)
|
||||
{
|
||||
let results = [];
|
||||
let stmt = aConn.createStatement("SELECT t FROM test " +
|
||||
"ORDER BY t COLLATE " + aCollation + " ASC");
|
||||
while (stmt.executeStep())
|
||||
results.push(stmt.row.t);
|
||||
stmt.finalize();
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts strings into our test table of the given database in the order given.
|
||||
*
|
||||
* @param aStrings
|
||||
* An array of strings.
|
||||
* @param aConn
|
||||
* A connection to either the UTF-8 database or the UTF-16 database.
|
||||
*/
|
||||
function initTableWithStrings(aStrings, aConn)
|
||||
{
|
||||
print("Initializing test table.");
|
||||
|
||||
aConn.executeSimpleSQL("DROP TABLE IF EXISTS test");
|
||||
aConn.createTable("test", "t TEXT");
|
||||
let stmt = aConn.createStatement("INSERT INTO test (t) VALUES (:t)");
|
||||
aStrings.forEach(function (str) {
|
||||
stmt.params.t = str;
|
||||
stmt.execute();
|
||||
stmt.reset();
|
||||
});
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sorting function suitable for passing to Array.prototype.sort().
|
||||
* The returned function uses the application's locale to compare strings.
|
||||
*
|
||||
* @param aCollation
|
||||
* The name of one of our custom locale collations. The sorting
|
||||
* strength is computed from this value.
|
||||
* @return A function to use as a sorting callback.
|
||||
*/
|
||||
function localeCompare(aCollation)
|
||||
{
|
||||
var strength;
|
||||
|
||||
switch (aCollation) {
|
||||
case "locale":
|
||||
strength = Ci.nsICollation.kCollationCaseInSensitive;
|
||||
break;
|
||||
case "locale_case_sensitive":
|
||||
strength = Ci.nsICollation.kCollationAccentInsenstive;
|
||||
break;
|
||||
case "locale_accent_sensitive":
|
||||
strength = Ci.nsICollation.kCollationCaseInsensitiveAscii;
|
||||
break;
|
||||
case "locale_case_accent_sensitive":
|
||||
strength = Ci.nsICollation.kCollationCaseSensitive;
|
||||
break;
|
||||
default:
|
||||
do_throw("Error in test: unknown collation '" + aCollation + "'");
|
||||
break;
|
||||
}
|
||||
return function (aStr1, aStr2) {
|
||||
return gLocaleCollation.compareString(strength, aStr1, aStr2);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in the test data from the file DATA_BASENAME and returns it as an array
|
||||
* of strings.
|
||||
*
|
||||
* @return The test data as an array of strings.
|
||||
*/
|
||||
function readTestData()
|
||||
{
|
||||
print("Reading in test data.");
|
||||
|
||||
let file = do_get_file(DATA_BASENAME);
|
||||
|
||||
let istream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
istream.init(file, -1, -1, 0);
|
||||
istream.QueryInterface(Components.interfaces.nsILineInputStream);
|
||||
|
||||
let line = {};
|
||||
let lines = [];
|
||||
while (istream.readLine(line)) {
|
||||
lines.push(line.value);
|
||||
}
|
||||
istream.close();
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the results from the given database using the given collation and
|
||||
* ensures that they match gStrings sorted by the same collation.
|
||||
*
|
||||
* @param aCollation
|
||||
* The name of one of our custom locale collations. The rows from the
|
||||
* database and the expected results are ordered by this collation.
|
||||
* @param aConn
|
||||
* A connection to either the UTF-8 database or the UTF-16 database.
|
||||
*/
|
||||
function runTest(aCollation, aConn)
|
||||
{
|
||||
ensureResultsAreCorrect(getResults(aCollation, aConn),
|
||||
gStrings.slice(0).sort(localeCompare(aCollation)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the results from the UTF-8 database using the given collation and
|
||||
* ensures that they match gStrings sorted by the same collation.
|
||||
*
|
||||
* @param aCollation
|
||||
* The name of one of our custom locale collations. The rows from the
|
||||
* database and the expected results are ordered by this collation.
|
||||
*/
|
||||
function runUtf8Test(aCollation)
|
||||
{
|
||||
runTest(aCollation, getOpenedDatabase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the results from the UTF-16 database using the given collation and
|
||||
* ensures that they match gStrings sorted by the same collation.
|
||||
*
|
||||
* @param aCollation
|
||||
* The name of one of our custom locale collations. The rows from the
|
||||
* database and the expected results are ordered by this collation.
|
||||
*/
|
||||
function runUtf16Test(aCollation)
|
||||
{
|
||||
runTest(aCollation, gUtf16Conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the test suite.
|
||||
*/
|
||||
function setup()
|
||||
{
|
||||
print("-- Setting up the test_locale_collation.js suite.");
|
||||
|
||||
gStrings = readTestData();
|
||||
|
||||
initTableWithStrings(gStrings, getOpenedDatabase());
|
||||
|
||||
gUtf16Conn = createUtf16Database();
|
||||
initTableWithStrings(gStrings, gUtf16Conn);
|
||||
|
||||
let localeSvc = Cc["@mozilla.org/intl/nslocaleservice;1"].
|
||||
getService(Ci.nsILocaleService);
|
||||
let collFact = Cc["@mozilla.org/intl/collation-factory;1"].
|
||||
createInstance(Ci.nsICollationFactory);
|
||||
gLocaleCollation = collFact.CreateCollation(localeSvc.getApplicationLocale());
|
||||
}
|
||||
|
||||
// Test Runs
|
||||
|
||||
var gTests = [
|
||||
{
|
||||
desc: "Case and accent sensitive UTF-8",
|
||||
run: () => runUtf8Test("locale_case_accent_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case sensitive, accent insensitive UTF-8",
|
||||
run: () => runUtf8Test("locale_case_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case insensitive, accent sensitive UTF-8",
|
||||
run: () => runUtf8Test("locale_accent_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case and accent insensitive UTF-8",
|
||||
run: () => runUtf8Test("locale")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case and accent sensitive UTF-16",
|
||||
run: () => runUtf16Test("locale_case_accent_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case sensitive, accent insensitive UTF-16",
|
||||
run: () => runUtf16Test("locale_case_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case insensitive, accent sensitive UTF-16",
|
||||
run: () => runUtf16Test("locale_accent_sensitive")
|
||||
},
|
||||
|
||||
{
|
||||
desc: "Case and accent insensitive UTF-16",
|
||||
run: () => runUtf16Test("locale")
|
||||
},
|
||||
];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setup();
|
||||
gTests.forEach(function (test) {
|
||||
print("-- Running test: " + test.desc);
|
||||
test.run();
|
||||
});
|
||||
}
|
||||
35
storage/test/unit/test_page_size_is_32k.js
Normal file
35
storage/test/unit/test_page_size_is_32k.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// This file tests that dbs are using 32k pagesize
|
||||
|
||||
const kExpectedPageSize = 32768; // 32K
|
||||
const kExpectedCacheSize = -2048; // 2MiB
|
||||
|
||||
function check_size(db)
|
||||
{
|
||||
var stmt = db.createStatement("PRAGMA page_size");
|
||||
stmt.executeStep();
|
||||
do_check_eq(stmt.getInt32(0), kExpectedPageSize);
|
||||
stmt.finalize();
|
||||
stmt = db.createStatement("PRAGMA cache_size");
|
||||
stmt.executeStep();
|
||||
do_check_eq(stmt.getInt32(0), kExpectedCacheSize);
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function new_file(name)
|
||||
{
|
||||
var file = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
file.append(name + ".sqlite");
|
||||
do_check_false(file.exists());
|
||||
return file;
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
check_size(getDatabase(new_file("shared32k")));
|
||||
check_size(getService().openUnsharedDatabase(new_file("unshared32k")));
|
||||
}
|
||||
|
||||
80
storage/test/unit/test_sqlite_secure_delete.js
Normal file
80
storage/test/unit/test_sqlite_secure_delete.js
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
*vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* 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/. */
|
||||
|
||||
/**
|
||||
* This file tests to make sure that SQLite was compiled with
|
||||
* SQLITE_SECURE_DELETE=1.
|
||||
*/
|
||||
|
||||
// Helper Methods
|
||||
|
||||
/**
|
||||
* Reads the contents of a file and returns it as a string.
|
||||
*
|
||||
* @param aFile
|
||||
* The file to return from.
|
||||
* @return the contents of the file in the form of a string.
|
||||
*/
|
||||
function getFileContents(aFile)
|
||||
{
|
||||
let fstream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fstream.init(aFile, -1, 0, 0);
|
||||
|
||||
let bstream = Cc["@mozilla.org/binaryinputstream;1"].
|
||||
createInstance(Ci.nsIBinaryInputStream);
|
||||
bstream.setInputStream(fstream);
|
||||
return bstream.readBytes(bstream.available());
|
||||
}
|
||||
|
||||
// Tests
|
||||
|
||||
add_test(function test_delete_removes_data() {
|
||||
const TEST_STRING = "SomeRandomStringToFind";
|
||||
|
||||
let file = getTestDB();
|
||||
let db = getService().openDatabase(file);
|
||||
|
||||
// Create the table and insert the data.
|
||||
db.createTable("test", "data TEXT");
|
||||
let stmt = db.createStatement("INSERT INTO test VALUES(:data)");
|
||||
stmt.params.data = TEST_STRING;
|
||||
try {
|
||||
stmt.execute();
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
// Make sure this test is actually testing what it thinks by making sure the
|
||||
// string shows up in the database. Because the previous statement was
|
||||
// automatically wrapped in a transaction, the contents are already on disk.
|
||||
let contents = getFileContents(file);
|
||||
do_check_neq(-1, contents.indexOf(TEST_STRING));
|
||||
|
||||
// Delete the data, and then close the database.
|
||||
stmt = db.createStatement("DELETE FROM test WHERE data = :data");
|
||||
stmt.params.data = TEST_STRING;
|
||||
try {
|
||||
stmt.execute();
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
db.close();
|
||||
|
||||
// Check the file to see if the string can be found.
|
||||
contents = getFileContents(file);
|
||||
do_check_eq(-1, contents.indexOf(TEST_STRING));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
function run_test()
|
||||
{
|
||||
cleanup();
|
||||
run_next_test();
|
||||
}
|
||||
998
storage/test/unit/test_statement_executeAsync.js
Normal file
998
storage/test/unit/test_statement_executeAsync.js
Normal file
|
|
@ -0,0 +1,998 @@
|
|||
/* 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/. */
|
||||
|
||||
/*
|
||||
* This file tests the functionality of mozIStorageBaseStatement::executeAsync
|
||||
* for both mozIStorageStatement and mozIStorageAsyncStatement.
|
||||
*/
|
||||
|
||||
const INTEGER = 1;
|
||||
const TEXT = "this is test text";
|
||||
const REAL = 3.23;
|
||||
const BLOB = [1, 2];
|
||||
|
||||
/**
|
||||
* Execute the given statement asynchronously, spinning an event loop until the
|
||||
* async statement completes.
|
||||
*
|
||||
* @param aStmt
|
||||
* The statement to execute.
|
||||
* @param [aOptions={}]
|
||||
* @param [aOptions.error=false]
|
||||
* If true we should expect an error whose code we do not care about. If
|
||||
* a numeric value, that's the error code we expect and require. If we
|
||||
* are expecting an error, we expect a completion reason of REASON_ERROR.
|
||||
* Otherwise we expect no error notification and a completion reason of
|
||||
* REASON_FINISHED.
|
||||
* @param [aOptions.cancel]
|
||||
* If true we cancel the pending statement and additionally return the
|
||||
* pending statement in case you want to further manipulate it.
|
||||
* @param [aOptions.returnPending=false]
|
||||
* If true we keep the pending statement around and return it to you. We
|
||||
* normally avoid doing this to try and minimize the amount of time a
|
||||
* reference is held to the returned pending statement.
|
||||
* @param [aResults]
|
||||
* If omitted, we assume no results rows are expected. If it is a
|
||||
* number, we assume it is the number of results rows expected. If it is
|
||||
* a function, we assume it is a function that takes the 1) result row
|
||||
* number, 2) result tuple, 3) call stack for the original call to
|
||||
* execAsync as arguments. If it is a list, we currently assume it is a
|
||||
* list of functions where each function is intended to evaluate the
|
||||
* result row at that ordinal position and takes the result tuple and
|
||||
* the call stack for the original call.
|
||||
*/
|
||||
function execAsync(aStmt, aOptions, aResults)
|
||||
{
|
||||
let caller = Components.stack.caller;
|
||||
if (aOptions == null)
|
||||
aOptions = {};
|
||||
|
||||
let resultsExpected;
|
||||
let resultsChecker;
|
||||
if (aResults == null) {
|
||||
resultsExpected = 0;
|
||||
}
|
||||
else if (typeof aResults == "number") {
|
||||
resultsExpected = aResults;
|
||||
}
|
||||
else if (typeof aResults == "function") {
|
||||
resultsChecker = aResults;
|
||||
}
|
||||
else { // array
|
||||
resultsExpected = aResults.length;
|
||||
resultsChecker = function (aResultNum, aTup, aCaller) {
|
||||
aResults[aResultNum](aTup, aCaller);
|
||||
};
|
||||
}
|
||||
let resultsSeen = 0;
|
||||
|
||||
let errorCodeExpected = false;
|
||||
let reasonExpected = Ci.mozIStorageStatementCallback.REASON_FINISHED;
|
||||
let altReasonExpected = null;
|
||||
if ("error" in aOptions) {
|
||||
errorCodeExpected = aOptions.error;
|
||||
if (errorCodeExpected)
|
||||
reasonExpected = Ci.mozIStorageStatementCallback.REASON_ERROR;
|
||||
}
|
||||
let errorCodeSeen = false;
|
||||
|
||||
if ("cancel" in aOptions && aOptions.cancel)
|
||||
altReasonExpected = Ci.mozIStorageStatementCallback.REASON_CANCELED;
|
||||
|
||||
let completed = false;
|
||||
|
||||
let listener = {
|
||||
handleResult(aResultSet)
|
||||
{
|
||||
let row, resultsSeenThisCall = 0;
|
||||
while ((row = aResultSet.getNextRow()) != null) {
|
||||
if (resultsChecker)
|
||||
resultsChecker(resultsSeen, row, caller);
|
||||
resultsSeen++;
|
||||
resultsSeenThisCall++;
|
||||
}
|
||||
|
||||
if (!resultsSeenThisCall)
|
||||
do_throw("handleResult invoked with 0 result rows!");
|
||||
},
|
||||
handleError(aError)
|
||||
{
|
||||
if (errorCodeSeen != false)
|
||||
do_throw("handleError called when we already had an error!");
|
||||
errorCodeSeen = aError.result;
|
||||
},
|
||||
handleCompletion(aReason)
|
||||
{
|
||||
if (completed) // paranoia check
|
||||
do_throw("Received a second handleCompletion notification!", caller);
|
||||
|
||||
if (resultsSeen != resultsExpected)
|
||||
do_throw("Expected " + resultsExpected + " rows of results but " +
|
||||
"got " + resultsSeen + " rows!", caller);
|
||||
|
||||
if (errorCodeExpected == true && errorCodeSeen == false)
|
||||
do_throw("Expected an error, but did not see one.", caller);
|
||||
else if (errorCodeExpected != errorCodeSeen)
|
||||
do_throw("Expected error code " + errorCodeExpected + " but got " +
|
||||
errorCodeSeen, caller);
|
||||
|
||||
if (aReason != reasonExpected && aReason != altReasonExpected)
|
||||
do_throw("Expected reason " + reasonExpected +
|
||||
(altReasonExpected ? (" or " + altReasonExpected) : "") +
|
||||
" but got " + aReason, caller);
|
||||
|
||||
completed = true;
|
||||
}
|
||||
};
|
||||
|
||||
let pending;
|
||||
// Only get a pending reference if we're supposed to do.
|
||||
// (note: This does not stop XPConnect from holding onto one currently.)
|
||||
if (("cancel" in aOptions && aOptions.cancel) ||
|
||||
("returnPending" in aOptions && aOptions.returnPending)) {
|
||||
pending = aStmt.executeAsync(listener);
|
||||
}
|
||||
else {
|
||||
aStmt.executeAsync(listener);
|
||||
}
|
||||
|
||||
if ("cancel" in aOptions && aOptions.cancel)
|
||||
pending.cancel();
|
||||
|
||||
let curThread = Components.classes["@mozilla.org/thread-manager;1"]
|
||||
.getService().currentThread;
|
||||
while (!completed && !_quit)
|
||||
curThread.processNextEvent(true);
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that illegal SQL generates the expected runtime error and does not
|
||||
* result in any crashes. Async-only since the synchronous case generates the
|
||||
* error synchronously (and is tested elsewhere).
|
||||
*/
|
||||
function test_illegal_sql_async_deferred()
|
||||
{
|
||||
// gibberish
|
||||
let stmt = makeTestStatement("I AM A ROBOT. DO AS I SAY.");
|
||||
execAsync(stmt, {error: Ci.mozIStorageError.ERROR});
|
||||
stmt.finalize();
|
||||
|
||||
// legal SQL syntax, but with semantics issues.
|
||||
stmt = makeTestStatement("SELECT destination FROM funkytown");
|
||||
execAsync(stmt, {error: Ci.mozIStorageError.ERROR});
|
||||
stmt.finalize();
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
test_illegal_sql_async_deferred.asyncOnly = true;
|
||||
|
||||
function test_create_table()
|
||||
{
|
||||
// Ensure our table doesn't exist
|
||||
do_check_false(getOpenedDatabase().tableExists("test"));
|
||||
|
||||
var stmt = makeTestStatement(
|
||||
"CREATE TABLE test (" +
|
||||
"id INTEGER, " +
|
||||
"string TEXT, " +
|
||||
"number REAL, " +
|
||||
"nuller NULL, " +
|
||||
"blober BLOB" +
|
||||
")"
|
||||
);
|
||||
execAsync(stmt);
|
||||
stmt.finalize();
|
||||
|
||||
// Check that the table has been created
|
||||
do_check_true(getOpenedDatabase().tableExists("test"));
|
||||
|
||||
// Verify that it's created correctly (this will throw if it wasn't)
|
||||
let checkStmt = getOpenedDatabase().createStatement(
|
||||
"SELECT id, string, number, nuller, blober FROM test"
|
||||
);
|
||||
checkStmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_add_data()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"INSERT INTO test (id, string, number, nuller, blober) " +
|
||||
"VALUES (?, ?, ?, ?, ?)"
|
||||
);
|
||||
stmt.bindBlobByIndex(4, BLOB, BLOB.length);
|
||||
stmt.bindByIndex(3, null);
|
||||
stmt.bindByIndex(2, REAL);
|
||||
stmt.bindByIndex(1, TEXT);
|
||||
stmt.bindByIndex(0, INTEGER);
|
||||
|
||||
execAsync(stmt);
|
||||
stmt.finalize();
|
||||
|
||||
// Check that the result is in the table
|
||||
verifyQuery("SELECT string, number, nuller, blober FROM test WHERE id = ?",
|
||||
INTEGER,
|
||||
[TEXT, REAL, null, BLOB]);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_get_data()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"SELECT string, number, nuller, blober, id FROM test WHERE id = ?"
|
||||
);
|
||||
stmt.bindByIndex(0, INTEGER);
|
||||
execAsync(stmt, {}, [
|
||||
function (tuple) {
|
||||
do_check_neq(null, tuple);
|
||||
|
||||
// Check that it's what we expect
|
||||
do_check_false(tuple.getIsNull(0));
|
||||
do_check_eq(tuple.getResultByName("string"), tuple.getResultByIndex(0));
|
||||
do_check_eq(TEXT, tuple.getResultByName("string"));
|
||||
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_TEXT,
|
||||
tuple.getTypeOfIndex(0));
|
||||
|
||||
do_check_false(tuple.getIsNull(1));
|
||||
do_check_eq(tuple.getResultByName("number"), tuple.getResultByIndex(1));
|
||||
do_check_eq(REAL, tuple.getResultByName("number"));
|
||||
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_FLOAT,
|
||||
tuple.getTypeOfIndex(1));
|
||||
|
||||
do_check_true(tuple.getIsNull(2));
|
||||
do_check_eq(tuple.getResultByName("nuller"), tuple.getResultByIndex(2));
|
||||
do_check_eq(null, tuple.getResultByName("nuller"));
|
||||
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_NULL,
|
||||
tuple.getTypeOfIndex(2));
|
||||
|
||||
do_check_false(tuple.getIsNull(3));
|
||||
var blobByName = tuple.getResultByName("blober");
|
||||
do_check_eq(BLOB.length, blobByName.length);
|
||||
var blobByIndex = tuple.getResultByIndex(3);
|
||||
do_check_eq(BLOB.length, blobByIndex.length);
|
||||
for (let i = 0; i < BLOB.length; i++) {
|
||||
do_check_eq(BLOB[i], blobByName[i]);
|
||||
do_check_eq(BLOB[i], blobByIndex[i]);
|
||||
}
|
||||
var count = { value: 0 };
|
||||
var blob = { value: null };
|
||||
tuple.getBlob(3, count, blob);
|
||||
do_check_eq(BLOB.length, count.value);
|
||||
for (let i = 0; i < BLOB.length; i++)
|
||||
do_check_eq(BLOB[i], blob.value[i]);
|
||||
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_BLOB,
|
||||
tuple.getTypeOfIndex(3));
|
||||
|
||||
do_check_false(tuple.getIsNull(4));
|
||||
do_check_eq(tuple.getResultByName("id"), tuple.getResultByIndex(4));
|
||||
do_check_eq(INTEGER, tuple.getResultByName("id"));
|
||||
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_INTEGER,
|
||||
tuple.getTypeOfIndex(4));
|
||||
}]);
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_tuple_out_of_bounds()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"SELECT string FROM test"
|
||||
);
|
||||
execAsync(stmt, {}, [
|
||||
function (tuple) {
|
||||
do_check_neq(null, tuple);
|
||||
|
||||
// Check all out of bounds - should throw
|
||||
var methods = [
|
||||
"getTypeOfIndex",
|
||||
"getInt32",
|
||||
"getInt64",
|
||||
"getDouble",
|
||||
"getUTF8String",
|
||||
"getString",
|
||||
"getIsNull",
|
||||
];
|
||||
for (var i in methods) {
|
||||
try {
|
||||
tuple[methods[i]](tuple.numEntries);
|
||||
do_throw("did not throw :(");
|
||||
}
|
||||
catch (e) {
|
||||
do_check_eq(Cr.NS_ERROR_ILLEGAL_VALUE, e.result);
|
||||
}
|
||||
}
|
||||
|
||||
// getBlob requires more args...
|
||||
try {
|
||||
var blob = { value: null };
|
||||
var size = { value: 0 };
|
||||
tuple.getBlob(tuple.numEntries, blob, size);
|
||||
do_throw("did not throw :(");
|
||||
}
|
||||
catch (e) {
|
||||
do_check_eq(Cr.NS_ERROR_ILLEGAL_VALUE, e.result);
|
||||
}
|
||||
}]);
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_no_listener_works_on_success()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"DELETE FROM test WHERE id = ?"
|
||||
);
|
||||
stmt.bindByIndex(0, 0);
|
||||
stmt.executeAsync();
|
||||
stmt.finalize();
|
||||
|
||||
// Run the next test.
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_no_listener_works_on_results()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"SELECT ?"
|
||||
);
|
||||
stmt.bindByIndex(0, 1);
|
||||
stmt.executeAsync();
|
||||
stmt.finalize();
|
||||
|
||||
// Run the next test.
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_no_listener_works_on_error()
|
||||
{
|
||||
// commit without a transaction will trigger an error
|
||||
var stmt = makeTestStatement(
|
||||
"COMMIT"
|
||||
);
|
||||
stmt.executeAsync();
|
||||
stmt.finalize();
|
||||
|
||||
// Run the next test.
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_partial_listener_works()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"DELETE FROM test WHERE id = ?"
|
||||
);
|
||||
stmt.bindByIndex(0, 0);
|
||||
stmt.executeAsync({
|
||||
handleResult(aResultSet) {}
|
||||
});
|
||||
stmt.executeAsync({
|
||||
handleError(aError) {}
|
||||
});
|
||||
stmt.executeAsync({
|
||||
handleCompletion(aReason) {}
|
||||
});
|
||||
stmt.finalize();
|
||||
|
||||
// Run the next test.
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dubious cancellation test that depends on system loading may or may not
|
||||
* succeed in canceling things. It does at least test if calling cancel blows
|
||||
* up. test_AsyncCancellation in test_true_async.cpp is our test that canceling
|
||||
* actually works correctly.
|
||||
*/
|
||||
function test_immediate_cancellation()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"DELETE FROM test WHERE id = ?"
|
||||
);
|
||||
stmt.bindByIndex(0, 0);
|
||||
execAsync(stmt, {cancel: true});
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that calling cancel twice throws the second time.
|
||||
*/
|
||||
function test_double_cancellation()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"DELETE FROM test WHERE id = ?"
|
||||
);
|
||||
stmt.bindByIndex(0, 0);
|
||||
let pendingStatement = execAsync(stmt, {cancel: true});
|
||||
// And cancel again - expect an exception
|
||||
expectError(Cr.NS_ERROR_UNEXPECTED,
|
||||
() => pendingStatement.cancel());
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that nothing untoward happens if we try and cancel something after it
|
||||
* has fully run to completion.
|
||||
*/
|
||||
function test_cancellation_after_execution()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"DELETE FROM test WHERE id = ?"
|
||||
);
|
||||
stmt.bindByIndex(0, 0);
|
||||
let pendingStatement = execAsync(stmt, {returnPending: true});
|
||||
// (the statement has fully executed at this point)
|
||||
// canceling after the statement has run to completion should not throw!
|
||||
pendingStatement.cancel();
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that a single statement can be executed more than once. Might once
|
||||
* have been intended to also ensure that callback notifications were not
|
||||
* incorrectly interleaved, but that part was brittle (it's totally fine for
|
||||
* handleResult to get called multiple times) and not comprehensive.
|
||||
*/
|
||||
function test_double_execute()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"SELECT 1"
|
||||
);
|
||||
execAsync(stmt, null, 1);
|
||||
execAsync(stmt, null, 1);
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_finalized_statement_does_not_crash()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"SELECT * FROM TEST"
|
||||
);
|
||||
stmt.finalize();
|
||||
// we are concerned about a crash here; an error is fine.
|
||||
try {
|
||||
stmt.executeAsync();
|
||||
} catch (ex) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
// Run the next test.
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind by mozIStorageBindingParams on the mozIStorageBaseStatement by index.
|
||||
*/
|
||||
function test_bind_direct_binding_params_by_index()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"INSERT INTO test (id, string, number, nuller, blober) " +
|
||||
"VALUES (?, ?, ?, ?, ?)"
|
||||
);
|
||||
let insertId = nextUniqueId++;
|
||||
stmt.bindByIndex(0, insertId);
|
||||
stmt.bindByIndex(1, TEXT);
|
||||
stmt.bindByIndex(2, REAL);
|
||||
stmt.bindByIndex(3, null);
|
||||
stmt.bindBlobByIndex(4, BLOB, BLOB.length);
|
||||
execAsync(stmt);
|
||||
stmt.finalize();
|
||||
verifyQuery("SELECT string, number, nuller, blober FROM test WHERE id = ?",
|
||||
insertId,
|
||||
[TEXT, REAL, null, BLOB]);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind by mozIStorageBindingParams on the mozIStorageBaseStatement by name.
|
||||
*/
|
||||
function test_bind_direct_binding_params_by_name()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"INSERT INTO test (id, string, number, nuller, blober) " +
|
||||
"VALUES (:int, :text, :real, :null, :blob)"
|
||||
);
|
||||
let insertId = nextUniqueId++;
|
||||
stmt.bindByName("int", insertId);
|
||||
stmt.bindByName("text", TEXT);
|
||||
stmt.bindByName("real", REAL);
|
||||
stmt.bindByName("null", null);
|
||||
stmt.bindBlobByName("blob", BLOB, BLOB.length);
|
||||
execAsync(stmt);
|
||||
stmt.finalize();
|
||||
verifyQuery("SELECT string, number, nuller, blober FROM test WHERE id = ?",
|
||||
insertId,
|
||||
[TEXT, REAL, null, BLOB]);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_bind_js_params_helper_by_index()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"INSERT INTO test (id, string, number, nuller, blober) " +
|
||||
"VALUES (?, ?, ?, ?, NULL)"
|
||||
);
|
||||
let insertId = nextUniqueId++;
|
||||
// we cannot bind blobs this way; no blober
|
||||
stmt.params[3] = null;
|
||||
stmt.params[2] = REAL;
|
||||
stmt.params[1] = TEXT;
|
||||
stmt.params[0] = insertId;
|
||||
execAsync(stmt);
|
||||
stmt.finalize();
|
||||
verifyQuery("SELECT string, number, nuller FROM test WHERE id = ?", insertId,
|
||||
[TEXT, REAL, null]);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_bind_js_params_helper_by_name()
|
||||
{
|
||||
var stmt = makeTestStatement(
|
||||
"INSERT INTO test (id, string, number, nuller, blober) " +
|
||||
"VALUES (:int, :text, :real, :null, NULL)"
|
||||
);
|
||||
let insertId = nextUniqueId++;
|
||||
// we cannot bind blobs this way; no blober
|
||||
stmt.params.null = null;
|
||||
stmt.params.real = REAL;
|
||||
stmt.params.text = TEXT;
|
||||
stmt.params.int = insertId;
|
||||
execAsync(stmt);
|
||||
stmt.finalize();
|
||||
verifyQuery("SELECT string, number, nuller FROM test WHERE id = ?", insertId,
|
||||
[TEXT, REAL, null]);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_bind_multiple_rows_by_index()
|
||||
{
|
||||
const AMOUNT_TO_ADD = 5;
|
||||
var stmt = makeTestStatement(
|
||||
"INSERT INTO test (id, string, number, nuller, blober) " +
|
||||
"VALUES (?, ?, ?, ?, ?)"
|
||||
);
|
||||
var array = stmt.newBindingParamsArray();
|
||||
for (let i = 0; i < AMOUNT_TO_ADD; i++) {
|
||||
let bp = array.newBindingParams();
|
||||
bp.bindByIndex(0, INTEGER);
|
||||
bp.bindByIndex(1, TEXT);
|
||||
bp.bindByIndex(2, REAL);
|
||||
bp.bindByIndex(3, null);
|
||||
bp.bindBlobByIndex(4, BLOB, BLOB.length);
|
||||
array.addParams(bp);
|
||||
do_check_eq(array.length, i + 1);
|
||||
}
|
||||
stmt.bindParameters(array);
|
||||
|
||||
let rowCount = getTableRowCount("test");
|
||||
execAsync(stmt);
|
||||
do_check_eq(rowCount + AMOUNT_TO_ADD, getTableRowCount("test"));
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_bind_multiple_rows_by_name()
|
||||
{
|
||||
const AMOUNT_TO_ADD = 5;
|
||||
var stmt = makeTestStatement(
|
||||
"INSERT INTO test (id, string, number, nuller, blober) " +
|
||||
"VALUES (:int, :text, :real, :null, :blob)"
|
||||
);
|
||||
var array = stmt.newBindingParamsArray();
|
||||
for (let i = 0; i < AMOUNT_TO_ADD; i++) {
|
||||
let bp = array.newBindingParams();
|
||||
bp.bindByName("int", INTEGER);
|
||||
bp.bindByName("text", TEXT);
|
||||
bp.bindByName("real", REAL);
|
||||
bp.bindByName("null", null);
|
||||
bp.bindBlobByName("blob", BLOB, BLOB.length);
|
||||
array.addParams(bp);
|
||||
do_check_eq(array.length, i + 1);
|
||||
}
|
||||
stmt.bindParameters(array);
|
||||
|
||||
let rowCount = getTableRowCount("test");
|
||||
execAsync(stmt);
|
||||
do_check_eq(rowCount + AMOUNT_TO_ADD, getTableRowCount("test"));
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a mozIStorageStatement instance throws immediately when we
|
||||
* try and bind to an illegal index.
|
||||
*/
|
||||
function test_bind_out_of_bounds_sync_immediate()
|
||||
{
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (?)"
|
||||
);
|
||||
|
||||
let array = stmt.newBindingParamsArray();
|
||||
let bp = array.newBindingParams();
|
||||
|
||||
// Check variant binding.
|
||||
expectError(Cr.NS_ERROR_INVALID_ARG,
|
||||
() => bp.bindByIndex(1, INTEGER));
|
||||
// Check blob binding.
|
||||
expectError(Cr.NS_ERROR_INVALID_ARG,
|
||||
() => bp.bindBlobByIndex(1, BLOB, BLOB.length));
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
test_bind_out_of_bounds_sync_immediate.syncOnly = true;
|
||||
|
||||
/**
|
||||
* Verify that a mozIStorageAsyncStatement reports an error asynchronously when
|
||||
* we bind to an illegal index.
|
||||
*/
|
||||
function test_bind_out_of_bounds_async_deferred()
|
||||
{
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (?)"
|
||||
);
|
||||
|
||||
let array = stmt.newBindingParamsArray();
|
||||
let bp = array.newBindingParams();
|
||||
|
||||
// There is no difference between variant and blob binding for async purposes.
|
||||
bp.bindByIndex(1, INTEGER);
|
||||
array.addParams(bp);
|
||||
stmt.bindParameters(array);
|
||||
execAsync(stmt, {error: Ci.mozIStorageError.RANGE});
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
test_bind_out_of_bounds_async_deferred.asyncOnly = true;
|
||||
|
||||
function test_bind_no_such_name_sync_immediate()
|
||||
{
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (:foo)"
|
||||
);
|
||||
|
||||
let array = stmt.newBindingParamsArray();
|
||||
let bp = array.newBindingParams();
|
||||
|
||||
// Check variant binding.
|
||||
expectError(Cr.NS_ERROR_INVALID_ARG,
|
||||
() => bp.bindByName("doesnotexist", INTEGER));
|
||||
// Check blob binding.
|
||||
expectError(Cr.NS_ERROR_INVALID_ARG,
|
||||
() => bp.bindBlobByName("doesnotexist", BLOB, BLOB.length));
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
test_bind_no_such_name_sync_immediate.syncOnly = true;
|
||||
|
||||
function test_bind_no_such_name_async_deferred()
|
||||
{
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (:foo)"
|
||||
);
|
||||
|
||||
let array = stmt.newBindingParamsArray();
|
||||
let bp = array.newBindingParams();
|
||||
|
||||
bp.bindByName("doesnotexist", INTEGER);
|
||||
array.addParams(bp);
|
||||
stmt.bindParameters(array);
|
||||
execAsync(stmt, {error: Ci.mozIStorageError.RANGE});
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
test_bind_no_such_name_async_deferred.asyncOnly = true;
|
||||
|
||||
function test_bind_bogus_type_by_index()
|
||||
{
|
||||
// We try to bind a JS Object here that should fail to bind.
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (blober) " +
|
||||
"VALUES (?)"
|
||||
);
|
||||
|
||||
let array = stmt.newBindingParamsArray();
|
||||
let bp = array.newBindingParams();
|
||||
Assert.throws(() => bp.bindByIndex(0, run_test), /NS_ERROR_UNEXPECTED/);
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_bind_bogus_type_by_name()
|
||||
{
|
||||
// We try to bind a JS Object here that should fail to bind.
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (blober) " +
|
||||
"VALUES (:blob)"
|
||||
);
|
||||
|
||||
let array = stmt.newBindingParamsArray();
|
||||
let bp = array.newBindingParams();
|
||||
Assert.throws(() => bp.bindByName("blob", run_test), /NS_ERROR_UNEXPECTED/);
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_bind_params_already_locked()
|
||||
{
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (:int)"
|
||||
);
|
||||
|
||||
let array = stmt.newBindingParamsArray();
|
||||
let bp = array.newBindingParams();
|
||||
bp.bindByName("int", INTEGER);
|
||||
array.addParams(bp);
|
||||
|
||||
// We should get an error after we call addParams and try to bind again.
|
||||
expectError(Cr.NS_ERROR_UNEXPECTED,
|
||||
() => bp.bindByName("int", INTEGER));
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_bind_params_array_already_locked()
|
||||
{
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (:int)"
|
||||
);
|
||||
|
||||
let array = stmt.newBindingParamsArray();
|
||||
let bp1 = array.newBindingParams();
|
||||
bp1.bindByName("int", INTEGER);
|
||||
array.addParams(bp1);
|
||||
let bp2 = array.newBindingParams();
|
||||
stmt.bindParameters(array);
|
||||
bp2.bindByName("int", INTEGER);
|
||||
|
||||
// We should get an error after we have bound the array to the statement.
|
||||
expectError(Cr.NS_ERROR_UNEXPECTED,
|
||||
() => array.addParams(bp2));
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_no_binding_params_from_locked_array()
|
||||
{
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (:int)"
|
||||
);
|
||||
|
||||
let array = stmt.newBindingParamsArray();
|
||||
let bp = array.newBindingParams();
|
||||
bp.bindByName("int", INTEGER);
|
||||
array.addParams(bp);
|
||||
stmt.bindParameters(array);
|
||||
|
||||
// We should not be able to get a new BindingParams object after we have bound
|
||||
// to the statement.
|
||||
expectError(Cr.NS_ERROR_UNEXPECTED,
|
||||
() => array.newBindingParams());
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_not_right_owning_array()
|
||||
{
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (:int)"
|
||||
);
|
||||
|
||||
let array1 = stmt.newBindingParamsArray();
|
||||
let array2 = stmt.newBindingParamsArray();
|
||||
let bp = array1.newBindingParams();
|
||||
bp.bindByName("int", INTEGER);
|
||||
|
||||
// We should not be able to add bp to array2 since it was created from array1.
|
||||
expectError(Cr.NS_ERROR_UNEXPECTED,
|
||||
() => array2.addParams(bp));
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_not_right_owning_statement()
|
||||
{
|
||||
let stmt1 = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (:int)"
|
||||
);
|
||||
let stmt2 = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (:int)"
|
||||
);
|
||||
|
||||
let array1 = stmt1.newBindingParamsArray();
|
||||
let array2 = stmt2.newBindingParamsArray();
|
||||
let bp = array1.newBindingParams();
|
||||
bp.bindByName("int", INTEGER);
|
||||
array1.addParams(bp);
|
||||
|
||||
// We should not be able to bind array1 since it was created from stmt1.
|
||||
expectError(Cr.NS_ERROR_UNEXPECTED,
|
||||
() => stmt2.bindParameters(array1));
|
||||
|
||||
stmt1.finalize();
|
||||
stmt2.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_bind_empty_array()
|
||||
{
|
||||
let stmt = makeTestStatement(
|
||||
"INSERT INTO test (id) " +
|
||||
"VALUES (:int)"
|
||||
);
|
||||
|
||||
let paramsArray = stmt.newBindingParamsArray();
|
||||
|
||||
// We should not be able to bind this array to the statement because it is
|
||||
// empty.
|
||||
expectError(Cr.NS_ERROR_UNEXPECTED,
|
||||
() => stmt.bindParameters(paramsArray));
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_multiple_results()
|
||||
{
|
||||
let expectedResults = getTableRowCount("test");
|
||||
// Sanity check - we should have more than one result, but let's be sure.
|
||||
do_check_true(expectedResults > 1);
|
||||
|
||||
// Now check that we get back two rows of data from our async query.
|
||||
let stmt = makeTestStatement("SELECT * FROM test");
|
||||
execAsync(stmt, {}, expectedResults);
|
||||
|
||||
stmt.finalize();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Test Runner
|
||||
|
||||
const TEST_PASS_SYNC = 0;
|
||||
const TEST_PASS_ASYNC = 1;
|
||||
/**
|
||||
* We run 2 passes against the test. One where makeTestStatement generates
|
||||
* synchronous (mozIStorageStatement) statements and one where it generates
|
||||
* asynchronous (mozIStorageAsyncStatement) statements.
|
||||
*
|
||||
* Because of differences in the ability to know the number of parameters before
|
||||
* dispatching, some tests are sync/async specific. These functions are marked
|
||||
* with 'syncOnly' or 'asyncOnly' attributes and run_next_test knows what to do.
|
||||
*/
|
||||
var testPass = TEST_PASS_SYNC;
|
||||
|
||||
/**
|
||||
* Create a statement of the type under test per testPass.
|
||||
*
|
||||
* @param aSQL
|
||||
* The SQL string from which to build a statement.
|
||||
* @return a statement of the type under test per testPass.
|
||||
*/
|
||||
function makeTestStatement(aSQL) {
|
||||
if (testPass == TEST_PASS_SYNC) {
|
||||
return getOpenedDatabase().createStatement(aSQL);
|
||||
}
|
||||
return getOpenedDatabase().createAsyncStatement(aSQL);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test_illegal_sql_async_deferred,
|
||||
test_create_table,
|
||||
test_add_data,
|
||||
test_get_data,
|
||||
test_tuple_out_of_bounds,
|
||||
test_no_listener_works_on_success,
|
||||
test_no_listener_works_on_results,
|
||||
test_no_listener_works_on_error,
|
||||
test_partial_listener_works,
|
||||
test_immediate_cancellation,
|
||||
test_double_cancellation,
|
||||
test_cancellation_after_execution,
|
||||
test_double_execute,
|
||||
test_finalized_statement_does_not_crash,
|
||||
test_bind_direct_binding_params_by_index,
|
||||
test_bind_direct_binding_params_by_name,
|
||||
test_bind_js_params_helper_by_index,
|
||||
test_bind_js_params_helper_by_name,
|
||||
test_bind_multiple_rows_by_index,
|
||||
test_bind_multiple_rows_by_name,
|
||||
test_bind_out_of_bounds_sync_immediate,
|
||||
test_bind_out_of_bounds_async_deferred,
|
||||
test_bind_no_such_name_sync_immediate,
|
||||
test_bind_no_such_name_async_deferred,
|
||||
test_bind_bogus_type_by_index,
|
||||
test_bind_bogus_type_by_name,
|
||||
test_bind_params_already_locked,
|
||||
test_bind_params_array_already_locked,
|
||||
test_bind_empty_array,
|
||||
test_no_binding_params_from_locked_array,
|
||||
test_not_right_owning_array,
|
||||
test_not_right_owning_statement,
|
||||
test_multiple_results,
|
||||
];
|
||||
var index = 0;
|
||||
|
||||
const STARTING_UNIQUE_ID = 2;
|
||||
var nextUniqueId = STARTING_UNIQUE_ID;
|
||||
|
||||
function run_next_test()
|
||||
{
|
||||
function _run_next_test() {
|
||||
// use a loop so we can skip tests...
|
||||
while (index < tests.length) {
|
||||
let test = tests[index++];
|
||||
// skip tests not appropriate to the current test pass
|
||||
if ((testPass == TEST_PASS_SYNC && ("asyncOnly" in test)) ||
|
||||
(testPass == TEST_PASS_ASYNC && ("syncOnly" in test)))
|
||||
continue;
|
||||
|
||||
// Asynchronous tests means that exceptions don't kill the test.
|
||||
try {
|
||||
print("****** Running the next test: " + test.name);
|
||||
test();
|
||||
return;
|
||||
}
|
||||
catch (e) {
|
||||
do_throw(e);
|
||||
}
|
||||
}
|
||||
|
||||
// if we only completed the first pass, move to the next pass
|
||||
if (testPass == TEST_PASS_SYNC) {
|
||||
print("********* Beginning mozIStorageAsyncStatement pass.");
|
||||
testPass++;
|
||||
index = 0;
|
||||
// a new pass demands a new database
|
||||
asyncCleanup();
|
||||
nextUniqueId = STARTING_UNIQUE_ID;
|
||||
_run_next_test();
|
||||
return;
|
||||
}
|
||||
|
||||
// we did some async stuff; we need to clean up.
|
||||
asyncCleanup();
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
// Don't actually schedule another test if we're quitting.
|
||||
if (!_quit) {
|
||||
// For saner stacks, we execute this code RSN.
|
||||
do_execute_soon(_run_next_test);
|
||||
}
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
cleanup();
|
||||
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
}
|
||||
167
storage/test/unit/test_statement_wrapper_automatically.js
Normal file
167
storage/test/unit/test_statement_wrapper_automatically.js
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
vim:set ts=2 sw=2 sts=2 et:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This file tests the functions of mozIStorageStatementWrapper
|
||||
|
||||
function setup()
|
||||
{
|
||||
getOpenedDatabase().createTable("test", "id INTEGER PRIMARY KEY, val NONE," +
|
||||
"alt_val NONE");
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience wrapper for do_check_eq. Calls do_check_eq on aActualVal
|
||||
* and aReturnedVal, with one caveat.
|
||||
*
|
||||
* Date objects are converted before parameter binding to PRTime's (microsecs
|
||||
* since epoch). They are not reconverted when retrieved from the database.
|
||||
* This function abstracts away this reconversion so that you can pass in,
|
||||
* for example:
|
||||
*
|
||||
* checkVal(new Date(), aReturnedVal) // this
|
||||
* checkVal(new Date().valueOf() * 1000.0, aReturnedVal) // instead of this
|
||||
*
|
||||
* Should any other types require conversion in the future, their conversions
|
||||
* may also be abstracted away here.
|
||||
*
|
||||
* @param aActualVal
|
||||
* the value inserted into the database
|
||||
* @param aReturnedVal
|
||||
* the value retrieved from the database
|
||||
*/
|
||||
function checkVal(aActualVal, aReturnedVal)
|
||||
{
|
||||
if (aActualVal instanceof Date) aActualVal = aActualVal.valueOf() * 1000.0;
|
||||
do_check_eq(aActualVal, aReturnedVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all rows from our test table.
|
||||
*/
|
||||
function clearTable()
|
||||
{
|
||||
var stmt = createStatement("DELETE FROM test");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
ensureNumRows(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the number of rows in our test table is equal to aNumRows.
|
||||
* Calls do_check_eq on aNumRows and the value retrieved by SELECT'ing COUNT(*).
|
||||
*
|
||||
* @param aNumRows
|
||||
* the number of rows our test table should contain
|
||||
*/
|
||||
function ensureNumRows(aNumRows)
|
||||
{
|
||||
var stmt = createStatement("SELECT COUNT(*) AS number FROM test");
|
||||
do_check_true(stmt.step());
|
||||
do_check_eq(aNumRows, stmt.row.number);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts aVal into our test table and checks that insertion was successful by
|
||||
* retrieving the newly inserted value from the database and comparing it
|
||||
* against aVal. aVal is bound to a single parameter.
|
||||
*
|
||||
* @param aVal
|
||||
* value to insert into our test table and check
|
||||
*/
|
||||
function insertAndCheckSingleParam(aVal)
|
||||
{
|
||||
clearTable();
|
||||
|
||||
var stmt = createStatement("INSERT INTO test (val) VALUES (:val)");
|
||||
stmt.params.val = aVal;
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
ensureNumRows(1);
|
||||
|
||||
stmt = createStatement("SELECT val FROM test WHERE id = 1");
|
||||
do_check_true(stmt.step());
|
||||
checkVal(aVal, stmt.row.val);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts aVal into our test table and checks that insertion was successful by
|
||||
* retrieving the newly inserted value from the database and comparing it
|
||||
* against aVal. aVal is bound to two separate parameters, both of which are
|
||||
* checked against aVal.
|
||||
*
|
||||
* @param aVal
|
||||
* value to insert into our test table and check
|
||||
*/
|
||||
function insertAndCheckMultipleParams(aVal)
|
||||
{
|
||||
clearTable();
|
||||
|
||||
var stmt = createStatement("INSERT INTO test (val, alt_val) " +
|
||||
"VALUES (:val, :val)");
|
||||
stmt.params.val = aVal;
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
ensureNumRows(1);
|
||||
|
||||
stmt = createStatement("SELECT val, alt_val FROM test WHERE id = 1");
|
||||
do_check_true(stmt.step());
|
||||
checkVal(aVal, stmt.row.val);
|
||||
checkVal(aVal, stmt.row.alt_val);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience function that prints out a description of aVal using
|
||||
* aVal.toString and aVal.toSource. Output is useful when the test fails.
|
||||
*
|
||||
* @param aVal
|
||||
* a value inserted or to be inserted into our test table
|
||||
*/
|
||||
function printValDesc(aVal)
|
||||
{
|
||||
try {
|
||||
var toSource = aVal.toSource();
|
||||
} catch (ex) {
|
||||
toSource = "";
|
||||
}
|
||||
print("Testing value: toString=" + aVal +
|
||||
(toSource ? " toSource=" + toSource : ""));
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setup();
|
||||
|
||||
// function JSValStorageStatementBinder in
|
||||
// storage/mozStorageStatementParams.cpp tells us that the following types
|
||||
// and only the following types are valid as statement parameters:
|
||||
var vals = [
|
||||
1337, // int
|
||||
3.1337, // double
|
||||
"foo", // string
|
||||
true, // boolean
|
||||
null, // null
|
||||
new Date(), // Date object
|
||||
];
|
||||
|
||||
vals.forEach(function (val)
|
||||
{
|
||||
printValDesc(val);
|
||||
print("Single parameter");
|
||||
insertAndCheckSingleParam(val);
|
||||
print("Multiple parameters");
|
||||
insertAndCheckMultipleParams(val);
|
||||
});
|
||||
|
||||
cleanup();
|
||||
}
|
||||
116
storage/test/unit/test_storage_aggregates.js
Normal file
116
storage/test/unit/test_storage_aggregates.js
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests the custom aggregate functions
|
||||
|
||||
var testNums = [1, 2, 3, 4];
|
||||
|
||||
function setup()
|
||||
{
|
||||
getOpenedDatabase().createTable("function_tests", "id INTEGER PRIMARY KEY");
|
||||
|
||||
var stmt = createStatement("INSERT INTO function_tests (id) VALUES(?1)");
|
||||
for (let i = 0; i < testNums.length; ++i) {
|
||||
stmt.bindByIndex(0, testNums[i]);
|
||||
stmt.execute();
|
||||
}
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
var testSquareAndSumFunction = {
|
||||
calls: 0,
|
||||
_sas: 0,
|
||||
|
||||
reset() {
|
||||
this.calls = 0;
|
||||
this._sas = 0;
|
||||
},
|
||||
|
||||
onStep(val) {
|
||||
++this.calls;
|
||||
this._sas += val.getInt32(0) * val.getInt32(0);
|
||||
},
|
||||
|
||||
onFinal() {
|
||||
var retval = this._sas;
|
||||
this._sas = 0; // Prepare for next group
|
||||
return retval;
|
||||
}
|
||||
};
|
||||
|
||||
function test_aggregate_registration()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
msc.createAggregateFunction("test_sas_aggr", 1, testSquareAndSumFunction);
|
||||
}
|
||||
|
||||
function test_aggregate_no_double_registration()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
try {
|
||||
msc.createAggregateFunction("test_sas_aggr", 2, testSquareAndSumFunction);
|
||||
do_throw("We shouldn't get here!");
|
||||
} catch (e) {
|
||||
do_check_eq(Cr.NS_ERROR_FAILURE, e.result);
|
||||
}
|
||||
}
|
||||
|
||||
function test_aggregate_removal()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
msc.removeFunction("test_sas_aggr");
|
||||
// Should be Ok now
|
||||
msc.createAggregateFunction("test_sas_aggr", 1, testSquareAndSumFunction);
|
||||
}
|
||||
|
||||
function test_aggregate_no_aliases()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
try {
|
||||
msc.createAggregateFunction("test_sas_aggr2", 1, testSquareAndSumFunction);
|
||||
do_throw("We shouldn't get here!");
|
||||
} catch (e) {
|
||||
do_check_eq(Cr.NS_ERROR_FAILURE, e.result);
|
||||
}
|
||||
}
|
||||
|
||||
function test_aggregate_call()
|
||||
{
|
||||
var stmt = createStatement("SELECT test_sas_aggr(id) FROM function_tests");
|
||||
while (stmt.executeStep()) {
|
||||
// Do nothing.
|
||||
}
|
||||
do_check_eq(testNums.length, testSquareAndSumFunction.calls);
|
||||
testSquareAndSumFunction.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_aggregate_result()
|
||||
{
|
||||
var sas = 0;
|
||||
for (var i = 0; i < testNums.length; ++i) {
|
||||
sas += testNums[i] * testNums[i];
|
||||
}
|
||||
var stmt = createStatement("SELECT test_sas_aggr(id) FROM function_tests");
|
||||
stmt.executeStep();
|
||||
do_check_eq(sas, stmt.getInt32(0));
|
||||
testSquareAndSumFunction.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
var tests = [test_aggregate_registration, test_aggregate_no_double_registration,
|
||||
test_aggregate_removal, test_aggregate_no_aliases, test_aggregate_call,
|
||||
test_aggregate_result];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setup();
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
tests[i]();
|
||||
}
|
||||
|
||||
cleanup();
|
||||
}
|
||||
763
storage/test/unit/test_storage_connection.js
Normal file
763
storage/test/unit/test_storage_connection.js
Normal file
|
|
@ -0,0 +1,763 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests the functions of mozIStorageConnection
|
||||
|
||||
// Test Functions
|
||||
|
||||
add_task(function* test_connectionReady_open() {
|
||||
// there doesn't seem to be a way for the connection to not be ready (unless
|
||||
// we close it with mozIStorageConnection::Close(), but we don't for this).
|
||||
// It can only fail if GetPath fails on the database file, or if we run out
|
||||
// of memory trying to use an in-memory database
|
||||
|
||||
var msc = getOpenedDatabase();
|
||||
do_check_true(msc.connectionReady);
|
||||
});
|
||||
|
||||
add_task(function* test_connectionReady_closed() {
|
||||
// This also tests mozIStorageConnection::Close()
|
||||
|
||||
var msc = getOpenedDatabase();
|
||||
msc.close();
|
||||
do_check_false(msc.connectionReady);
|
||||
gDBConn = null; // this is so later tests don't start to fail.
|
||||
});
|
||||
|
||||
add_task(function* test_databaseFile() {
|
||||
var msc = getOpenedDatabase();
|
||||
do_check_true(getTestDB().equals(msc.databaseFile));
|
||||
});
|
||||
|
||||
add_task(function* test_tableExists_not_created() {
|
||||
var msc = getOpenedDatabase();
|
||||
do_check_false(msc.tableExists("foo"));
|
||||
});
|
||||
|
||||
add_task(function* test_indexExists_not_created() {
|
||||
var msc = getOpenedDatabase();
|
||||
do_check_false(msc.indexExists("foo"));
|
||||
});
|
||||
|
||||
add_task(function* test_temp_tableExists_and_indexExists() {
|
||||
var msc = getOpenedDatabase();
|
||||
msc.executeSimpleSQL("CREATE TEMP TABLE test_temp(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)");
|
||||
do_check_true(msc.tableExists("test_temp"));
|
||||
|
||||
msc.executeSimpleSQL("CREATE INDEX test_temp_ind ON test_temp (name)");
|
||||
do_check_true(msc.indexExists("test_temp_ind"));
|
||||
|
||||
msc.executeSimpleSQL("DROP INDEX test_temp_ind");
|
||||
msc.executeSimpleSQL("DROP TABLE test_temp");
|
||||
});
|
||||
|
||||
add_task(function* test_createTable_not_created() {
|
||||
var msc = getOpenedDatabase();
|
||||
msc.createTable("test", "id INTEGER PRIMARY KEY, name TEXT");
|
||||
do_check_true(msc.tableExists("test"));
|
||||
});
|
||||
|
||||
add_task(function* test_indexExists_created() {
|
||||
var msc = getOpenedDatabase();
|
||||
msc.executeSimpleSQL("CREATE INDEX name_ind ON test (name)");
|
||||
do_check_true(msc.indexExists("name_ind"));
|
||||
});
|
||||
|
||||
add_task(function* test_createTable_already_created() {
|
||||
var msc = getOpenedDatabase();
|
||||
do_check_true(msc.tableExists("test"));
|
||||
Assert.throws(() => msc.createTable("test", "id INTEGER PRIMARY KEY, name TEXT"),
|
||||
/NS_ERROR_FAILURE/);
|
||||
});
|
||||
|
||||
add_task(function* test_attach_createTable_tableExists_indexExists() {
|
||||
var msc = getOpenedDatabase();
|
||||
var file = do_get_file("storage_attach.sqlite", true);
|
||||
var msc2 = getDatabase(file);
|
||||
msc.executeSimpleSQL("ATTACH DATABASE '" + file.path + "' AS sample");
|
||||
|
||||
do_check_false(msc.tableExists("sample.test"));
|
||||
msc.createTable("sample.test", "id INTEGER PRIMARY KEY, name TEXT");
|
||||
do_check_true(msc.tableExists("sample.test"));
|
||||
Assert.throws(() => msc.createTable("sample.test", "id INTEGER PRIMARY KEY, name TEXT"),
|
||||
/NS_ERROR_FAILURE/);
|
||||
|
||||
do_check_false(msc.indexExists("sample.test_ind"));
|
||||
msc.executeSimpleSQL("CREATE INDEX sample.test_ind ON test (name)");
|
||||
do_check_true(msc.indexExists("sample.test_ind"));
|
||||
|
||||
msc.executeSimpleSQL("DETACH DATABASE sample");
|
||||
msc2.close();
|
||||
try {
|
||||
file.remove(false);
|
||||
} catch (e) {
|
||||
// Do nothing.
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_lastInsertRowID() {
|
||||
var msc = getOpenedDatabase();
|
||||
msc.executeSimpleSQL("INSERT INTO test (name) VALUES ('foo')");
|
||||
do_check_eq(1, msc.lastInsertRowID);
|
||||
});
|
||||
|
||||
add_task(function* test_transactionInProgress_no() {
|
||||
var msc = getOpenedDatabase();
|
||||
do_check_false(msc.transactionInProgress);
|
||||
});
|
||||
|
||||
add_task(function* test_transactionInProgress_yes() {
|
||||
var msc = getOpenedDatabase();
|
||||
msc.beginTransaction();
|
||||
do_check_true(msc.transactionInProgress);
|
||||
msc.commitTransaction();
|
||||
do_check_false(msc.transactionInProgress);
|
||||
|
||||
msc.beginTransaction();
|
||||
do_check_true(msc.transactionInProgress);
|
||||
msc.rollbackTransaction();
|
||||
do_check_false(msc.transactionInProgress);
|
||||
});
|
||||
|
||||
add_task(function* test_commitTransaction_no_transaction() {
|
||||
var msc = getOpenedDatabase();
|
||||
do_check_false(msc.transactionInProgress);
|
||||
Assert.throws(() => msc.commitTransaction(), /NS_ERROR_UNEXPECTED/);
|
||||
});
|
||||
|
||||
add_task(function* test_rollbackTransaction_no_transaction() {
|
||||
var msc = getOpenedDatabase();
|
||||
do_check_false(msc.transactionInProgress);
|
||||
Assert.throws(() => msc.rollbackTransaction(), /NS_ERROR_UNEXPECTED/);
|
||||
});
|
||||
|
||||
add_task(function* test_get_schemaVersion_not_set() {
|
||||
do_check_eq(0, getOpenedDatabase().schemaVersion);
|
||||
});
|
||||
|
||||
add_task(function* test_set_schemaVersion() {
|
||||
var msc = getOpenedDatabase();
|
||||
const version = 1;
|
||||
msc.schemaVersion = version;
|
||||
do_check_eq(version, msc.schemaVersion);
|
||||
});
|
||||
|
||||
add_task(function* test_set_schemaVersion_same() {
|
||||
var msc = getOpenedDatabase();
|
||||
const version = 1;
|
||||
msc.schemaVersion = version; // should still work ok
|
||||
do_check_eq(version, msc.schemaVersion);
|
||||
});
|
||||
|
||||
add_task(function* test_set_schemaVersion_negative() {
|
||||
var msc = getOpenedDatabase();
|
||||
const version = -1;
|
||||
msc.schemaVersion = version;
|
||||
do_check_eq(version, msc.schemaVersion);
|
||||
});
|
||||
|
||||
add_task(function* test_createTable() {
|
||||
var temp = getTestDB().parent;
|
||||
temp.append("test_db_table");
|
||||
try {
|
||||
var con = getService().openDatabase(temp);
|
||||
con.createTable("a", "");
|
||||
} catch (e) {
|
||||
if (temp.exists()) {
|
||||
try {
|
||||
temp.remove(false);
|
||||
} catch (e2) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
do_check_true(e.result == Cr.NS_ERROR_NOT_INITIALIZED ||
|
||||
e.result == Cr.NS_ERROR_FAILURE);
|
||||
} finally {
|
||||
if (con) {
|
||||
con.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_defaultSynchronousAtNormal() {
|
||||
var msc = getOpenedDatabase();
|
||||
var stmt = createStatement("PRAGMA synchronous;");
|
||||
try {
|
||||
stmt.executeStep();
|
||||
do_check_eq(1, stmt.getInt32(0));
|
||||
}
|
||||
finally {
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
});
|
||||
|
||||
// must be ran before executeAsync tests
|
||||
add_task(function* test_close_does_not_spin_event_loop() {
|
||||
// We want to make sure that the event loop on the calling thread does not
|
||||
// spin when close is called.
|
||||
let event = {
|
||||
ran: false,
|
||||
run() {
|
||||
this.ran = true;
|
||||
},
|
||||
};
|
||||
|
||||
// Post the event before we call close, so it would run if the event loop was
|
||||
// spun during close.
|
||||
let thread = Cc["@mozilla.org/thread-manager;1"].
|
||||
getService(Ci.nsIThreadManager).
|
||||
currentThread;
|
||||
thread.dispatch(event, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
|
||||
// Sanity check, then close the database. Afterwards, we should not have ran!
|
||||
do_check_false(event.ran);
|
||||
getOpenedDatabase().close();
|
||||
do_check_false(event.ran);
|
||||
|
||||
// Reset gDBConn so that later tests will get a new connection object.
|
||||
gDBConn = null;
|
||||
});
|
||||
|
||||
add_task(function* test_asyncClose_succeeds_with_finalized_async_statement() {
|
||||
// XXX this test isn't perfect since we can't totally control when events will
|
||||
// run. If this paticular function fails randomly, it means we have a
|
||||
// real bug.
|
||||
|
||||
// We want to make sure we create a cached async statement to make sure that
|
||||
// when we finalize our statement, we end up finalizing the async one too so
|
||||
// close will succeed.
|
||||
let stmt = createStatement("SELECT * FROM test");
|
||||
stmt.executeAsync();
|
||||
stmt.finalize();
|
||||
|
||||
yield asyncClose(getOpenedDatabase());
|
||||
// Reset gDBConn so that later tests will get a new connection object.
|
||||
gDBConn = null;
|
||||
});
|
||||
|
||||
add_task(function* test_close_then_release_statement() {
|
||||
// Testing the behavior in presence of a bad client that finalizes
|
||||
// statements after the database has been closed (typically by
|
||||
// letting the gc finalize the statement).
|
||||
let db = getOpenedDatabase();
|
||||
let stmt = createStatement("SELECT * FROM test -- test_close_then_release_statement");
|
||||
db.close();
|
||||
stmt.finalize(); // Finalize too late - this should not crash
|
||||
|
||||
// Reset gDBConn so that later tests will get a new connection object.
|
||||
gDBConn = null;
|
||||
});
|
||||
|
||||
add_task(function* test_asyncClose_then_release_statement() {
|
||||
// Testing the behavior in presence of a bad client that finalizes
|
||||
// statements after the database has been async closed (typically by
|
||||
// letting the gc finalize the statement).
|
||||
let db = getOpenedDatabase();
|
||||
let stmt = createStatement("SELECT * FROM test -- test_asyncClose_then_release_statement");
|
||||
yield asyncClose(db);
|
||||
stmt.finalize(); // Finalize too late - this should not crash
|
||||
|
||||
// Reset gDBConn so that later tests will get a new connection object.
|
||||
gDBConn = null;
|
||||
});
|
||||
|
||||
add_task(function* test_close_fails_with_async_statement_ran() {
|
||||
let deferred = Promise.defer();
|
||||
let stmt = createStatement("SELECT * FROM test");
|
||||
stmt.executeAsync();
|
||||
stmt.finalize();
|
||||
|
||||
let db = getOpenedDatabase();
|
||||
Assert.throws(() => db.close(), /NS_ERROR_UNEXPECTED/);
|
||||
|
||||
// Clean up after ourselves.
|
||||
db.asyncClose(function () {
|
||||
// Reset gDBConn so that later tests will get a new connection object.
|
||||
gDBConn = null;
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
yield deferred.promise;
|
||||
});
|
||||
|
||||
add_task(function* test_clone_optional_param() {
|
||||
let db1 = getService().openUnsharedDatabase(getTestDB());
|
||||
let db2 = db1.clone();
|
||||
do_check_true(db2.connectionReady);
|
||||
|
||||
// A write statement should not fail here.
|
||||
let stmt = db2.createStatement("INSERT INTO test (name) VALUES (:name)");
|
||||
stmt.params.name = "dwitte";
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
// And a read statement should succeed.
|
||||
stmt = db2.createStatement("SELECT * FROM test");
|
||||
do_check_true(stmt.executeStep());
|
||||
stmt.finalize();
|
||||
|
||||
// Additionally check that it is a connection on the same database.
|
||||
do_check_true(db1.databaseFile.equals(db2.databaseFile));
|
||||
|
||||
db1.close();
|
||||
db2.close();
|
||||
});
|
||||
|
||||
function* standardAsyncTest(promisedDB, name, shouldInit = false) {
|
||||
do_print("Performing standard async test " + name);
|
||||
|
||||
let adb = yield promisedDB;
|
||||
do_check_true(adb instanceof Ci.mozIStorageAsyncConnection);
|
||||
do_check_false(adb instanceof Ci.mozIStorageConnection);
|
||||
|
||||
if (shouldInit) {
|
||||
let stmt = adb.createAsyncStatement("CREATE TABLE test(name TEXT)");
|
||||
yield executeAsync(stmt);
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
// Generate a name to insert and fetch back
|
||||
name = "worker bee " + Math.random() + " (" + name + ")";
|
||||
|
||||
let stmt = adb.createAsyncStatement("INSERT INTO test (name) VALUES (:name)");
|
||||
stmt.params.name = name;
|
||||
let result = yield executeAsync(stmt);
|
||||
do_print("Request complete");
|
||||
stmt.finalize();
|
||||
do_check_true(Components.isSuccessCode(result));
|
||||
do_print("Extracting data");
|
||||
stmt = adb.createAsyncStatement("SELECT * FROM test");
|
||||
let found = false;
|
||||
yield executeAsync(stmt, function (results) {
|
||||
do_print("Data has been extracted");
|
||||
for (let row = results.getNextRow(); row != null; row = results.getNextRow()) {
|
||||
if (row.getResultByName("name") == name) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
do_check_true(found);
|
||||
stmt.finalize();
|
||||
yield asyncClose(adb);
|
||||
|
||||
do_print("Standard async test " + name + " complete");
|
||||
}
|
||||
|
||||
add_task(function* test_open_async() {
|
||||
yield standardAsyncTest(openAsyncDatabase(getTestDB(), null), "default");
|
||||
yield standardAsyncTest(openAsyncDatabase(getTestDB()), "no optional arg");
|
||||
yield standardAsyncTest(openAsyncDatabase(getTestDB(),
|
||||
{shared: false, growthIncrement: 54}), "non-default options");
|
||||
yield standardAsyncTest(openAsyncDatabase("memory"),
|
||||
"in-memory database", true);
|
||||
yield standardAsyncTest(openAsyncDatabase("memory",
|
||||
{shared: false}),
|
||||
"in-memory database and options", true);
|
||||
|
||||
do_print("Testing async opening with bogus options 0");
|
||||
let raised = false;
|
||||
let adb = null;
|
||||
|
||||
try {
|
||||
adb = yield openAsyncDatabase("memory", {shared: false, growthIncrement: 54});
|
||||
} catch (ex) {
|
||||
raised = true;
|
||||
} finally {
|
||||
if (adb) {
|
||||
yield asyncClose(adb);
|
||||
}
|
||||
}
|
||||
do_check_true(raised);
|
||||
|
||||
do_print("Testing async opening with bogus options 1");
|
||||
raised = false;
|
||||
adb = null;
|
||||
try {
|
||||
adb = yield openAsyncDatabase(getTestDB(), {shared: "forty-two"});
|
||||
} catch (ex) {
|
||||
raised = true;
|
||||
} finally {
|
||||
if (adb) {
|
||||
yield asyncClose(adb);
|
||||
}
|
||||
}
|
||||
do_check_true(raised);
|
||||
|
||||
do_print("Testing async opening with bogus options 2");
|
||||
raised = false;
|
||||
adb = null;
|
||||
try {
|
||||
adb = yield openAsyncDatabase(getTestDB(), {growthIncrement: "forty-two"});
|
||||
} catch (ex) {
|
||||
raised = true;
|
||||
} finally {
|
||||
if (adb) {
|
||||
yield asyncClose(adb);
|
||||
}
|
||||
}
|
||||
do_check_true(raised);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_async_open_with_shared_cache() {
|
||||
do_print("Testing that opening with a shared cache doesn't break stuff");
|
||||
let adb = yield openAsyncDatabase(getTestDB(), {shared: true});
|
||||
|
||||
let stmt = adb.createAsyncStatement("INSERT INTO test (name) VALUES (:name)");
|
||||
stmt.params.name = "clockworker";
|
||||
let result = yield executeAsync(stmt);
|
||||
do_print("Request complete");
|
||||
stmt.finalize();
|
||||
do_check_true(Components.isSuccessCode(result));
|
||||
do_print("Extracting data");
|
||||
stmt = adb.createAsyncStatement("SELECT * FROM test");
|
||||
let found = false;
|
||||
yield executeAsync(stmt, function (results) {
|
||||
do_print("Data has been extracted");
|
||||
for (let row = results.getNextRow(); row != null; row = results.getNextRow()) {
|
||||
if (row.getResultByName("name") == "clockworker") {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
do_check_true(found);
|
||||
stmt.finalize();
|
||||
yield asyncClose(adb);
|
||||
});
|
||||
|
||||
add_task(function* test_clone_trivial_async() {
|
||||
do_print("Open connection");
|
||||
let db = getService().openDatabase(getTestDB());
|
||||
do_check_true(db instanceof Ci.mozIStorageAsyncConnection);
|
||||
do_print("AsyncClone connection");
|
||||
let clone = yield asyncClone(db, true);
|
||||
do_check_true(clone instanceof Ci.mozIStorageAsyncConnection);
|
||||
do_print("Close connection");
|
||||
yield asyncClose(db);
|
||||
do_print("Close clone");
|
||||
yield asyncClose(clone);
|
||||
});
|
||||
|
||||
add_task(function* test_clone_no_optional_param_async() {
|
||||
"use strict";
|
||||
do_print("Testing async cloning");
|
||||
let adb1 = yield openAsyncDatabase(getTestDB(), null);
|
||||
do_check_true(adb1 instanceof Ci.mozIStorageAsyncConnection);
|
||||
|
||||
do_print("Cloning database");
|
||||
|
||||
let adb2 = yield asyncClone(adb1);
|
||||
do_print("Testing that the cloned db is a mozIStorageAsyncConnection " +
|
||||
"and not a mozIStorageConnection");
|
||||
do_check_true(adb2 instanceof Ci.mozIStorageAsyncConnection);
|
||||
do_check_false(adb2 instanceof Ci.mozIStorageConnection);
|
||||
|
||||
do_print("Inserting data into source db");
|
||||
let stmt = adb1.
|
||||
createAsyncStatement("INSERT INTO test (name) VALUES (:name)");
|
||||
|
||||
stmt.params.name = "yoric";
|
||||
let result = yield executeAsync(stmt);
|
||||
do_print("Request complete");
|
||||
stmt.finalize();
|
||||
do_check_true(Components.isSuccessCode(result));
|
||||
do_print("Extracting data from clone db");
|
||||
stmt = adb2.createAsyncStatement("SELECT * FROM test");
|
||||
let found = false;
|
||||
yield executeAsync(stmt, function (results) {
|
||||
do_print("Data has been extracted");
|
||||
for (let row = results.getNextRow(); row != null; row = results.getNextRow()) {
|
||||
if (row.getResultByName("name") == "yoric") {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
do_check_true(found);
|
||||
stmt.finalize();
|
||||
do_print("Closing databases");
|
||||
yield asyncClose(adb2);
|
||||
do_print("First db closed");
|
||||
|
||||
yield asyncClose(adb1);
|
||||
do_print("Second db closed");
|
||||
});
|
||||
|
||||
add_task(function* test_clone_readonly() {
|
||||
let db1 = getService().openUnsharedDatabase(getTestDB());
|
||||
let db2 = db1.clone(true);
|
||||
do_check_true(db2.connectionReady);
|
||||
|
||||
// A write statement should fail here.
|
||||
let stmt = db2.createStatement("INSERT INTO test (name) VALUES (:name)");
|
||||
stmt.params.name = "reed";
|
||||
expectError(Cr.NS_ERROR_FILE_READ_ONLY, () => stmt.execute());
|
||||
stmt.finalize();
|
||||
|
||||
// And a read statement should succeed.
|
||||
stmt = db2.createStatement("SELECT * FROM test");
|
||||
do_check_true(stmt.executeStep());
|
||||
stmt.finalize();
|
||||
|
||||
db1.close();
|
||||
db2.close();
|
||||
});
|
||||
|
||||
add_task(function* test_clone_shared_readonly() {
|
||||
let db1 = getService().openDatabase(getTestDB());
|
||||
let db2 = db1.clone(true);
|
||||
do_check_true(db2.connectionReady);
|
||||
|
||||
let stmt = db2.createStatement("INSERT INTO test (name) VALUES (:name)");
|
||||
stmt.params.name = "parker";
|
||||
// TODO currently SQLite does not actually work correctly here. The behavior
|
||||
// we want is commented out, and the current behavior is being tested
|
||||
// for. Our IDL comments will have to be updated when this starts to
|
||||
// work again.
|
||||
stmt.execute();
|
||||
// expectError(Components.results.NS_ERROR_FILE_READ_ONLY, () => stmt.execute());
|
||||
stmt.finalize();
|
||||
|
||||
// And a read statement should succeed.
|
||||
stmt = db2.createStatement("SELECT * FROM test");
|
||||
do_check_true(stmt.executeStep());
|
||||
stmt.finalize();
|
||||
|
||||
db1.close();
|
||||
db2.close();
|
||||
});
|
||||
|
||||
add_task(function* test_close_clone_fails() {
|
||||
let calls = [
|
||||
"openDatabase",
|
||||
"openUnsharedDatabase",
|
||||
];
|
||||
calls.forEach(function (methodName) {
|
||||
let db = getService()[methodName](getTestDB());
|
||||
db.close();
|
||||
expectError(Cr.NS_ERROR_NOT_INITIALIZED, () => db.clone());
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_memory_clone_fails() {
|
||||
let db = getService().openSpecialDatabase("memory");
|
||||
db.close();
|
||||
expectError(Cr.NS_ERROR_NOT_INITIALIZED, () => db.clone());
|
||||
});
|
||||
|
||||
add_task(function* test_clone_copies_functions() {
|
||||
const FUNC_NAME = "test_func";
|
||||
let calls = [
|
||||
"openDatabase",
|
||||
"openUnsharedDatabase",
|
||||
];
|
||||
let functionMethods = [
|
||||
"createFunction",
|
||||
"createAggregateFunction",
|
||||
];
|
||||
calls.forEach(function (methodName) {
|
||||
[true, false].forEach(function (readOnly) {
|
||||
functionMethods.forEach(function (functionMethod) {
|
||||
let db1 = getService()[methodName](getTestDB());
|
||||
// Create a function for db1.
|
||||
db1[functionMethod](FUNC_NAME, 1, {
|
||||
onFunctionCall: () => 0,
|
||||
onStep: () => 0,
|
||||
onFinal: () => 0,
|
||||
});
|
||||
|
||||
// Clone it, and make sure the function exists still.
|
||||
let db2 = db1.clone(readOnly);
|
||||
// Note: this would fail if the function did not exist.
|
||||
let stmt = db2.createStatement("SELECT " + FUNC_NAME + "(id) FROM test");
|
||||
stmt.finalize();
|
||||
db1.close();
|
||||
db2.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_clone_copies_overridden_functions() {
|
||||
const FUNC_NAME = "lower";
|
||||
function test_func() {
|
||||
this.called = false;
|
||||
}
|
||||
test_func.prototype = {
|
||||
onFunctionCall() {
|
||||
this.called = true;
|
||||
},
|
||||
onStep() {
|
||||
this.called = true;
|
||||
},
|
||||
onFinal: () => 0,
|
||||
};
|
||||
|
||||
let calls = [
|
||||
"openDatabase",
|
||||
"openUnsharedDatabase",
|
||||
];
|
||||
let functionMethods = [
|
||||
"createFunction",
|
||||
"createAggregateFunction",
|
||||
];
|
||||
calls.forEach(function (methodName) {
|
||||
[true, false].forEach(function (readOnly) {
|
||||
functionMethods.forEach(function (functionMethod) {
|
||||
let db1 = getService()[methodName](getTestDB());
|
||||
// Create a function for db1.
|
||||
let func = new test_func();
|
||||
db1[functionMethod](FUNC_NAME, 1, func);
|
||||
do_check_false(func.called);
|
||||
|
||||
// Clone it, and make sure the function gets called.
|
||||
let db2 = db1.clone(readOnly);
|
||||
let stmt = db2.createStatement("SELECT " + FUNC_NAME + "(id) FROM test");
|
||||
stmt.executeStep();
|
||||
do_check_true(func.called);
|
||||
stmt.finalize();
|
||||
db1.close();
|
||||
db2.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_clone_copies_pragmas() {
|
||||
const PRAGMAS = [
|
||||
{ name: "cache_size", value: 500, copied: true },
|
||||
{ name: "temp_store", value: 2, copied: true },
|
||||
{ name: "foreign_keys", value: 1, copied: true },
|
||||
{ name: "journal_size_limit", value: 524288, copied: true },
|
||||
{ name: "synchronous", value: 2, copied: true },
|
||||
{ name: "wal_autocheckpoint", value: 16, copied: true },
|
||||
{ name: "busy_timeout", value: 50, copied: true },
|
||||
{ name: "ignore_check_constraints", value: 1, copied: false },
|
||||
];
|
||||
|
||||
let db1 = getService().openUnsharedDatabase(getTestDB());
|
||||
|
||||
// Sanity check initial values are different from enforced ones.
|
||||
PRAGMAS.forEach(function (pragma) {
|
||||
let stmt = db1.createStatement("PRAGMA " + pragma.name);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_neq(pragma.value, stmt.getInt32(0));
|
||||
stmt.finalize();
|
||||
});
|
||||
// Execute pragmas.
|
||||
PRAGMAS.forEach(function (pragma) {
|
||||
db1.executeSimpleSQL("PRAGMA " + pragma.name + " = " + pragma.value);
|
||||
});
|
||||
|
||||
let db2 = db1.clone();
|
||||
do_check_true(db2.connectionReady);
|
||||
|
||||
// Check cloned connection inherited pragma values.
|
||||
PRAGMAS.forEach(function (pragma) {
|
||||
let stmt = db2.createStatement("PRAGMA " + pragma.name);
|
||||
do_check_true(stmt.executeStep());
|
||||
let validate = pragma.copied ? do_check_eq : do_check_neq;
|
||||
validate(pragma.value, stmt.getInt32(0));
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
db1.close();
|
||||
db2.close();
|
||||
});
|
||||
|
||||
add_task(function* test_readonly_clone_copies_pragmas() {
|
||||
const PRAGMAS = [
|
||||
{ name: "cache_size", value: 500, copied: true },
|
||||
{ name: "temp_store", value: 2, copied: true },
|
||||
{ name: "foreign_keys", value: 1, copied: false },
|
||||
{ name: "journal_size_limit", value: 524288, copied: false },
|
||||
{ name: "synchronous", value: 2, copied: false },
|
||||
{ name: "wal_autocheckpoint", value: 16, copied: false },
|
||||
{ name: "busy_timeout", value: 50, copied: false },
|
||||
{ name: "ignore_check_constraints", value: 1, copied: false },
|
||||
];
|
||||
|
||||
let db1 = getService().openUnsharedDatabase(getTestDB());
|
||||
|
||||
// Sanity check initial values are different from enforced ones.
|
||||
PRAGMAS.forEach(function (pragma) {
|
||||
let stmt = db1.createStatement("PRAGMA " + pragma.name);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_neq(pragma.value, stmt.getInt32(0));
|
||||
stmt.finalize();
|
||||
});
|
||||
// Execute pragmas.
|
||||
PRAGMAS.forEach(function (pragma) {
|
||||
db1.executeSimpleSQL("PRAGMA " + pragma.name + " = " + pragma.value);
|
||||
});
|
||||
|
||||
let db2 = db1.clone(true);
|
||||
do_check_true(db2.connectionReady);
|
||||
|
||||
// Check cloned connection inherited pragma values.
|
||||
PRAGMAS.forEach(function (pragma) {
|
||||
let stmt = db2.createStatement("PRAGMA " + pragma.name);
|
||||
do_check_true(stmt.executeStep());
|
||||
let validate = pragma.copied ? do_check_eq : do_check_neq;
|
||||
validate(pragma.value, stmt.getInt32(0));
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
db1.close();
|
||||
db2.close();
|
||||
});
|
||||
|
||||
add_task(function* test_clone_attach_database() {
|
||||
let db1 = getService().openUnsharedDatabase(getTestDB());
|
||||
|
||||
let c = 0;
|
||||
function attachDB(conn, name) {
|
||||
let file = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
file.append("test_storage_" + (++c) + ".sqlite");
|
||||
let db = getService().openUnsharedDatabase(file);
|
||||
conn.executeSimpleSQL(`ATTACH DATABASE '${db.databaseFile.path}' AS ${name}`);
|
||||
db.close();
|
||||
}
|
||||
attachDB(db1, "attached_1");
|
||||
attachDB(db1, "attached_2");
|
||||
|
||||
// These should not throw.
|
||||
db1.createStatement("SELECT * FROM attached_1.sqlite_master");
|
||||
db1.createStatement("SELECT * FROM attached_2.sqlite_master");
|
||||
|
||||
// R/W clone.
|
||||
let db2 = db1.clone();
|
||||
do_check_true(db2.connectionReady);
|
||||
|
||||
// These should not throw.
|
||||
db2.createStatement("SELECT * FROM attached_1.sqlite_master");
|
||||
db2.createStatement("SELECT * FROM attached_2.sqlite_master");
|
||||
|
||||
// R/O clone.
|
||||
let db3 = db1.clone(true);
|
||||
do_check_true(db3.connectionReady);
|
||||
|
||||
// These should not throw.
|
||||
db3.createStatement("SELECT * FROM attached_1.sqlite_master");
|
||||
db3.createStatement("SELECT * FROM attached_2.sqlite_master");
|
||||
|
||||
db1.close();
|
||||
db2.close();
|
||||
db3.close();
|
||||
});
|
||||
|
||||
add_task(function* test_getInterface() {
|
||||
let db = getOpenedDatabase();
|
||||
let target = db.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIEventTarget);
|
||||
// Just check that target is non-null. Other tests will ensure that it has
|
||||
// the correct value.
|
||||
do_check_true(target != null);
|
||||
|
||||
yield asyncClose(db);
|
||||
gDBConn = null;
|
||||
});
|
||||
86
storage/test/unit/test_storage_fulltextindex.js
Normal file
86
storage/test/unit/test_storage_fulltextindex.js
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests support for the fts3 (full-text index) module.
|
||||
|
||||
// Example statements in these tests are taken from the Full Text Index page
|
||||
// on the SQLite wiki: http://www.sqlite.org/cvstrac/wiki?p=FullTextIndex
|
||||
|
||||
function test_table_creation()
|
||||
{
|
||||
var msc = getOpenedUnsharedDatabase();
|
||||
|
||||
msc.executeSimpleSQL(
|
||||
"CREATE VIRTUAL TABLE recipe USING fts3(name, ingredients)");
|
||||
|
||||
do_check_true(msc.tableExists("recipe"));
|
||||
}
|
||||
|
||||
function test_insertion()
|
||||
{
|
||||
var msc = getOpenedUnsharedDatabase();
|
||||
|
||||
msc.executeSimpleSQL("INSERT INTO recipe (name, ingredients) VALUES " +
|
||||
"('broccoli stew', 'broccoli peppers cheese tomatoes')");
|
||||
msc.executeSimpleSQL("INSERT INTO recipe (name, ingredients) VALUES " +
|
||||
"('pumpkin stew', 'pumpkin onions garlic celery')");
|
||||
msc.executeSimpleSQL("INSERT INTO recipe (name, ingredients) VALUES " +
|
||||
"('broccoli pie', 'broccoli cheese onions flour')");
|
||||
msc.executeSimpleSQL("INSERT INTO recipe (name, ingredients) VALUES " +
|
||||
"('pumpkin pie', 'pumpkin sugar flour butter')");
|
||||
|
||||
var stmt = msc.createStatement("SELECT COUNT(*) FROM recipe");
|
||||
stmt.executeStep();
|
||||
|
||||
do_check_eq(stmt.getInt32(0), 4);
|
||||
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_selection()
|
||||
{
|
||||
var msc = getOpenedUnsharedDatabase();
|
||||
|
||||
var stmt = msc.createStatement(
|
||||
"SELECT rowid, name, ingredients FROM recipe WHERE name MATCH 'pie'");
|
||||
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(stmt.getInt32(0), 3);
|
||||
do_check_eq(stmt.getString(1), "broccoli pie");
|
||||
do_check_eq(stmt.getString(2), "broccoli cheese onions flour");
|
||||
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(stmt.getInt32(0), 4);
|
||||
do_check_eq(stmt.getString(1), "pumpkin pie");
|
||||
do_check_eq(stmt.getString(2), "pumpkin sugar flour butter");
|
||||
|
||||
do_check_false(stmt.executeStep());
|
||||
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
var tests = [test_table_creation, test_insertion, test_selection];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
// It's extra important to start from scratch, since these tests won't work
|
||||
// with an existing shared cache connection, so we do it even though the last
|
||||
// test probably did it already.
|
||||
cleanup();
|
||||
|
||||
try {
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
tests[i]();
|
||||
}
|
||||
}
|
||||
// It's extra important to clean up afterwards, since later tests that use
|
||||
// a shared cache connection will not be able to read the database we create,
|
||||
// so we do this in a finally block to ensure it happens even if some of our
|
||||
// tests fail.
|
||||
finally {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
95
storage/test/unit/test_storage_function.js
Normal file
95
storage/test/unit/test_storage_function.js
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests the custom functions
|
||||
|
||||
var testNums = [1, 2, 3, 4];
|
||||
|
||||
function setup()
|
||||
{
|
||||
getOpenedDatabase().createTable("function_tests", "id INTEGER PRIMARY KEY");
|
||||
|
||||
var stmt = createStatement("INSERT INTO function_tests (id) VALUES(?1)");
|
||||
for (let i = 0; i < testNums.length; ++i) {
|
||||
stmt.bindByIndex(0, testNums[i]);
|
||||
stmt.execute();
|
||||
}
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
var testSquareFunction = {
|
||||
calls: 0,
|
||||
|
||||
onFunctionCall(val) {
|
||||
++this.calls;
|
||||
return val.getInt32(0) * val.getInt32(0);
|
||||
}
|
||||
};
|
||||
|
||||
function test_function_registration()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
msc.createFunction("test_square", 1, testSquareFunction);
|
||||
}
|
||||
|
||||
function test_function_no_double_registration()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
try {
|
||||
msc.createFunction("test_square", 2, testSquareFunction);
|
||||
do_throw("We shouldn't get here!");
|
||||
} catch (e) {
|
||||
do_check_eq(Cr.NS_ERROR_FAILURE, e.result);
|
||||
}
|
||||
}
|
||||
|
||||
function test_function_removal()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
msc.removeFunction("test_square");
|
||||
// Should be Ok now
|
||||
msc.createFunction("test_square", 1, testSquareFunction);
|
||||
}
|
||||
|
||||
function test_function_aliases()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
msc.createFunction("test_square2", 1, testSquareFunction);
|
||||
}
|
||||
|
||||
function test_function_call()
|
||||
{
|
||||
var stmt = createStatement("SELECT test_square(id) FROM function_tests");
|
||||
while (stmt.executeStep()) {
|
||||
// Do nothing.
|
||||
}
|
||||
do_check_eq(testNums.length, testSquareFunction.calls);
|
||||
testSquareFunction.calls = 0;
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_function_result()
|
||||
{
|
||||
var stmt = createStatement("SELECT test_square(42) FROM function_tests");
|
||||
stmt.executeStep();
|
||||
do_check_eq(42 * 42, stmt.getInt32(0));
|
||||
testSquareFunction.calls = 0;
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
var tests = [test_function_registration, test_function_no_double_registration,
|
||||
test_function_removal, test_function_aliases, test_function_call,
|
||||
test_function_result];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setup();
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
tests[i]();
|
||||
}
|
||||
|
||||
cleanup();
|
||||
}
|
||||
111
storage/test/unit/test_storage_progresshandler.js
Normal file
111
storage/test/unit/test_storage_progresshandler.js
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests the custom progress handlers
|
||||
|
||||
function setup()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
msc.createTable("handler_tests", "id INTEGER PRIMARY KEY, num INTEGER");
|
||||
msc.beginTransaction();
|
||||
|
||||
var stmt = createStatement("INSERT INTO handler_tests (id, num) VALUES(?1, ?2)");
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
stmt.bindByIndex(0, i);
|
||||
stmt.bindByIndex(1, Math.floor(Math.random() * 1000));
|
||||
stmt.execute();
|
||||
}
|
||||
stmt.reset();
|
||||
msc.commitTransaction();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
var testProgressHandler = {
|
||||
calls: 0,
|
||||
abort: false,
|
||||
|
||||
onProgress(comm) {
|
||||
++this.calls;
|
||||
return this.abort;
|
||||
}
|
||||
};
|
||||
|
||||
function test_handler_registration()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
msc.setProgressHandler(10, testProgressHandler);
|
||||
}
|
||||
|
||||
function test_handler_return()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
var oldH = msc.setProgressHandler(5, testProgressHandler);
|
||||
do_check_true(oldH instanceof Ci.mozIStorageProgressHandler);
|
||||
}
|
||||
|
||||
function test_handler_removal()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
msc.removeProgressHandler();
|
||||
var oldH = msc.removeProgressHandler();
|
||||
do_check_eq(oldH, null);
|
||||
}
|
||||
|
||||
function test_handler_call()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
msc.setProgressHandler(50, testProgressHandler);
|
||||
// Some long-executing request
|
||||
var stmt = createStatement(
|
||||
"SELECT SUM(t1.num * t2.num) FROM handler_tests AS t1, handler_tests AS t2");
|
||||
while (stmt.executeStep()) {
|
||||
// Do nothing.
|
||||
}
|
||||
do_check_true(testProgressHandler.calls > 0);
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_handler_abort()
|
||||
{
|
||||
var msc = getOpenedDatabase();
|
||||
testProgressHandler.abort = true;
|
||||
msc.setProgressHandler(50, testProgressHandler);
|
||||
// Some long-executing request
|
||||
var stmt = createStatement(
|
||||
"SELECT SUM(t1.num * t2.num) FROM handler_tests AS t1, handler_tests AS t2");
|
||||
|
||||
const SQLITE_INTERRUPT = 9;
|
||||
try {
|
||||
while (stmt.executeStep()) {
|
||||
// Do nothing.
|
||||
}
|
||||
do_throw("We shouldn't get here!");
|
||||
} catch (e) {
|
||||
do_check_eq(Cr.NS_ERROR_ABORT, e.result);
|
||||
do_check_eq(SQLITE_INTERRUPT, msc.lastError);
|
||||
}
|
||||
try {
|
||||
stmt.finalize();
|
||||
do_throw("We shouldn't get here!");
|
||||
} catch (e) {
|
||||
// finalize should return the error code since we encountered an error
|
||||
do_check_eq(Cr.NS_ERROR_ABORT, e.result);
|
||||
do_check_eq(SQLITE_INTERRUPT, msc.lastError);
|
||||
}
|
||||
}
|
||||
|
||||
var tests = [test_handler_registration, test_handler_return,
|
||||
test_handler_removal, test_handler_call,
|
||||
test_handler_abort];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setup();
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
tests[i]();
|
||||
}
|
||||
|
||||
cleanup();
|
||||
}
|
||||
142
storage/test/unit/test_storage_service.js
Normal file
142
storage/test/unit/test_storage_service.js
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests the functions of mozIStorageService except for
|
||||
// openUnsharedDatabase, which is tested by test_storage_service_unshared.js.
|
||||
|
||||
const BACKUP_FILE_NAME = "test_storage.sqlite.backup";
|
||||
|
||||
function test_openSpecialDatabase_invalid_arg()
|
||||
{
|
||||
try {
|
||||
getService().openSpecialDatabase("abcd");
|
||||
do_throw("We should not get here!");
|
||||
} catch (e) {
|
||||
print(e);
|
||||
print("e.result is " + e.result);
|
||||
do_check_eq(Cr.NS_ERROR_INVALID_ARG, e.result);
|
||||
}
|
||||
}
|
||||
|
||||
function test_openDatabase_null_file()
|
||||
{
|
||||
try {
|
||||
getService().openDatabase(null);
|
||||
do_throw("We should not get here!");
|
||||
} catch (e) {
|
||||
print(e);
|
||||
print("e.result is " + e.result);
|
||||
do_check_eq(Cr.NS_ERROR_INVALID_ARG, e.result);
|
||||
}
|
||||
}
|
||||
|
||||
function test_openUnsharedDatabase_null_file()
|
||||
{
|
||||
try {
|
||||
getService().openUnsharedDatabase(null);
|
||||
do_throw("We should not get here!");
|
||||
} catch (e) {
|
||||
print(e);
|
||||
print("e.result is " + e.result);
|
||||
do_check_eq(Cr.NS_ERROR_INVALID_ARG, e.result);
|
||||
}
|
||||
}
|
||||
|
||||
function test_openDatabase_file_DNE()
|
||||
{
|
||||
// the file should be created after calling
|
||||
var db = getTestDB();
|
||||
do_check_false(db.exists());
|
||||
getService().openDatabase(db);
|
||||
do_check_true(db.exists());
|
||||
}
|
||||
|
||||
function test_openDatabase_file_exists()
|
||||
{
|
||||
// it should already exist from our last test
|
||||
var db = getTestDB();
|
||||
do_check_true(db.exists());
|
||||
getService().openDatabase(db);
|
||||
do_check_true(db.exists());
|
||||
}
|
||||
|
||||
function test_corrupt_db_throws_with_openDatabase()
|
||||
{
|
||||
try {
|
||||
getDatabase(getCorruptDB());
|
||||
do_throw("should not be here");
|
||||
}
|
||||
catch (e) {
|
||||
do_check_eq(Cr.NS_ERROR_FILE_CORRUPTED, e.result);
|
||||
}
|
||||
}
|
||||
|
||||
function test_fake_db_throws_with_openDatabase()
|
||||
{
|
||||
try {
|
||||
getDatabase(getFakeDB());
|
||||
do_throw("should not be here");
|
||||
}
|
||||
catch (e) {
|
||||
do_check_eq(Cr.NS_ERROR_FILE_CORRUPTED, e.result);
|
||||
}
|
||||
}
|
||||
|
||||
function test_backup_not_new_filename()
|
||||
{
|
||||
const fname = getTestDB().leafName;
|
||||
|
||||
var backup = getService().backupDatabaseFile(getTestDB(), fname);
|
||||
do_check_neq(fname, backup.leafName);
|
||||
|
||||
backup.remove(false);
|
||||
}
|
||||
|
||||
function test_backup_new_filename()
|
||||
{
|
||||
var backup = getService().backupDatabaseFile(getTestDB(), BACKUP_FILE_NAME);
|
||||
do_check_eq(BACKUP_FILE_NAME, backup.leafName);
|
||||
|
||||
backup.remove(false);
|
||||
}
|
||||
|
||||
function test_backup_new_folder()
|
||||
{
|
||||
var parentDir = getTestDB().parent;
|
||||
parentDir.append("test_storage_temp");
|
||||
if (parentDir.exists())
|
||||
parentDir.remove(true);
|
||||
parentDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
|
||||
do_check_true(parentDir.exists());
|
||||
|
||||
var backup = getService().backupDatabaseFile(getTestDB(), BACKUP_FILE_NAME,
|
||||
parentDir);
|
||||
do_check_eq(BACKUP_FILE_NAME, backup.leafName);
|
||||
do_check_true(parentDir.equals(backup.parent));
|
||||
|
||||
parentDir.remove(true);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test_openSpecialDatabase_invalid_arg,
|
||||
test_openDatabase_null_file,
|
||||
test_openUnsharedDatabase_null_file,
|
||||
test_openDatabase_file_DNE,
|
||||
test_openDatabase_file_exists,
|
||||
test_corrupt_db_throws_with_openDatabase,
|
||||
test_fake_db_throws_with_openDatabase,
|
||||
test_backup_not_new_filename,
|
||||
test_backup_new_filename,
|
||||
test_backup_new_folder,
|
||||
];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
tests[i]();
|
||||
}
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
35
storage/test/unit/test_storage_service_unshared.js
Normal file
35
storage/test/unit/test_storage_service_unshared.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests the openUnsharedDatabase function of mozIStorageService.
|
||||
|
||||
function test_openUnsharedDatabase_file_DNE()
|
||||
{
|
||||
// the file should be created after calling
|
||||
var db = getTestDB();
|
||||
do_check_false(db.exists());
|
||||
getService().openUnsharedDatabase(db);
|
||||
do_check_true(db.exists());
|
||||
}
|
||||
|
||||
function test_openUnsharedDatabase_file_exists()
|
||||
{
|
||||
// it should already exist from our last test
|
||||
var db = getTestDB();
|
||||
do_check_true(db.exists());
|
||||
getService().openUnsharedDatabase(db);
|
||||
do_check_true(db.exists());
|
||||
}
|
||||
|
||||
var tests = [test_openUnsharedDatabase_file_DNE,
|
||||
test_openUnsharedDatabase_file_exists];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
for (var i = 0; i < tests.length; i++)
|
||||
tests[i]();
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
184
storage/test/unit/test_storage_statement.js
Normal file
184
storage/test/unit/test_storage_statement.js
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests the functions of mozIStorageStatement
|
||||
|
||||
function setup()
|
||||
{
|
||||
getOpenedDatabase().createTable("test", "id INTEGER PRIMARY KEY, name TEXT");
|
||||
}
|
||||
|
||||
function test_parameterCount_none()
|
||||
{
|
||||
var stmt = createStatement("SELECT * FROM test");
|
||||
do_check_eq(0, stmt.parameterCount);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_parameterCount_one()
|
||||
{
|
||||
var stmt = createStatement("SELECT * FROM test WHERE id = ?1");
|
||||
do_check_eq(1, stmt.parameterCount);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_getParameterName()
|
||||
{
|
||||
var stmt = createStatement("SELECT * FROM test WHERE id = :id");
|
||||
do_check_eq(":id", stmt.getParameterName(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_getParameterIndex_different()
|
||||
{
|
||||
var stmt = createStatement("SELECT * FROM test WHERE id = :id OR name = :name");
|
||||
do_check_eq(0, stmt.getParameterIndex("id"));
|
||||
do_check_eq(1, stmt.getParameterIndex("name"));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_getParameterIndex_same()
|
||||
{
|
||||
var stmt = createStatement("SELECT * FROM test WHERE id = :test OR name = :test");
|
||||
do_check_eq(0, stmt.getParameterIndex("test"));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_columnCount()
|
||||
{
|
||||
var stmt = createStatement("SELECT * FROM test WHERE id = ?1 OR name = ?2");
|
||||
do_check_eq(2, stmt.columnCount);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_getColumnName()
|
||||
{
|
||||
var stmt = createStatement("SELECT name, id FROM test");
|
||||
do_check_eq("id", stmt.getColumnName(1));
|
||||
do_check_eq("name", stmt.getColumnName(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_getColumnIndex_same_case()
|
||||
{
|
||||
var stmt = createStatement("SELECT name, id FROM test");
|
||||
do_check_eq(0, stmt.getColumnIndex("name"));
|
||||
do_check_eq(1, stmt.getColumnIndex("id"));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_getColumnIndex_different_case()
|
||||
{
|
||||
var stmt = createStatement("SELECT name, id FROM test");
|
||||
try {
|
||||
do_check_eq(0, stmt.getColumnIndex("NaMe"));
|
||||
do_throw("should not get here");
|
||||
} catch (e) {
|
||||
do_check_eq(Cr.NS_ERROR_INVALID_ARG, e.result);
|
||||
}
|
||||
try {
|
||||
do_check_eq(1, stmt.getColumnIndex("Id"));
|
||||
do_throw("should not get here");
|
||||
} catch (e) {
|
||||
do_check_eq(Cr.NS_ERROR_INVALID_ARG, e.result);
|
||||
}
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_state_ready()
|
||||
{
|
||||
var stmt = createStatement("SELECT name, id FROM test");
|
||||
do_check_eq(Ci.mozIStorageStatement.MOZ_STORAGE_STATEMENT_READY, stmt.state);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_state_executing()
|
||||
{
|
||||
var stmt = createStatement("INSERT INTO test (name) VALUES ('foo')");
|
||||
stmt.execute();
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
stmt = createStatement("SELECT name, id FROM test");
|
||||
stmt.executeStep();
|
||||
do_check_eq(Ci.mozIStorageStatement.MOZ_STORAGE_STATEMENT_EXECUTING,
|
||||
stmt.state);
|
||||
stmt.executeStep();
|
||||
do_check_eq(Ci.mozIStorageStatement.MOZ_STORAGE_STATEMENT_EXECUTING,
|
||||
stmt.state);
|
||||
stmt.reset();
|
||||
do_check_eq(Ci.mozIStorageStatement.MOZ_STORAGE_STATEMENT_READY, stmt.state);
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_state_after_finalize()
|
||||
{
|
||||
var stmt = createStatement("SELECT name, id FROM test");
|
||||
stmt.executeStep();
|
||||
stmt.finalize();
|
||||
do_check_eq(Ci.mozIStorageStatement.MOZ_STORAGE_STATEMENT_INVALID, stmt.state);
|
||||
}
|
||||
|
||||
function test_failed_execute()
|
||||
{
|
||||
var stmt = createStatement("INSERT INTO test (name) VALUES ('foo')");
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
var id = getOpenedDatabase().lastInsertRowID;
|
||||
stmt = createStatement("INSERT INTO test(id, name) VALUES(:id, 'bar')");
|
||||
stmt.params.id = id;
|
||||
try {
|
||||
// Should throw a constraint error
|
||||
stmt.execute();
|
||||
do_throw("Should have seen a constraint error");
|
||||
}
|
||||
catch (e) {
|
||||
do_check_eq(getOpenedDatabase().lastError, Ci.mozIStorageError.CONSTRAINT);
|
||||
}
|
||||
do_check_eq(Ci.mozIStorageStatement.MOZ_STORAGE_STATEMENT_READY, stmt.state);
|
||||
// Should succeed without needing to reset the statement manually
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function test_bind_undefined()
|
||||
{
|
||||
var stmt = createStatement("INSERT INTO test (name) VALUES ('foo')");
|
||||
|
||||
expectError(Cr.NS_ERROR_ILLEGAL_VALUE,
|
||||
() => stmt.bindParameters(undefined));
|
||||
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
var tests = [test_parameterCount_none, test_parameterCount_one,
|
||||
test_getParameterName, test_getParameterIndex_different,
|
||||
test_getParameterIndex_same, test_columnCount,
|
||||
test_getColumnName, test_getColumnIndex_same_case,
|
||||
test_getColumnIndex_different_case, test_state_ready,
|
||||
test_state_executing, test_state_after_finalize,
|
||||
test_failed_execute,
|
||||
test_bind_undefined,
|
||||
];
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setup();
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
tests[i]();
|
||||
}
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
182
storage/test/unit/test_storage_value_array.js
Normal file
182
storage/test/unit/test_storage_value_array.js
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests the functions of mozIStorageValueArray
|
||||
|
||||
add_task(function* setup() {
|
||||
getOpenedDatabase().createTable("test", "id INTEGER PRIMARY KEY, name TEXT," +
|
||||
"number REAL, nuller NULL, blobber BLOB");
|
||||
|
||||
var stmt = createStatement("INSERT INTO test (name, number, blobber) " +
|
||||
"VALUES (?1, ?2, ?3)");
|
||||
stmt.bindByIndex(0, "foo");
|
||||
stmt.bindByIndex(1, 2.34);
|
||||
stmt.bindBlobByIndex(2, [], 0);
|
||||
stmt.execute();
|
||||
|
||||
stmt.bindByIndex(0, "");
|
||||
stmt.bindByIndex(1, 1.23);
|
||||
stmt.bindBlobByIndex(2, [1, 2], 2);
|
||||
stmt.execute();
|
||||
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
|
||||
do_register_cleanup(cleanup);
|
||||
});
|
||||
|
||||
add_task(function* test_getIsNull_for_null() {
|
||||
var stmt = createStatement("SELECT nuller, blobber FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 1);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_true(stmt.getIsNull(0)); // null field
|
||||
do_check_true(stmt.getIsNull(1)); // data is null if size is 0
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_getIsNull_for_non_null() {
|
||||
var stmt = createStatement("SELECT name, blobber FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 2);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_false(stmt.getIsNull(0));
|
||||
do_check_false(stmt.getIsNull(1));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_value_type_null() {
|
||||
var stmt = createStatement("SELECT nuller FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 1);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_NULL,
|
||||
stmt.getTypeOfIndex(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_value_type_integer() {
|
||||
var stmt = createStatement("SELECT id FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 1);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_INTEGER,
|
||||
stmt.getTypeOfIndex(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_value_type_float() {
|
||||
var stmt = createStatement("SELECT number FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 1);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_FLOAT,
|
||||
stmt.getTypeOfIndex(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_value_type_text() {
|
||||
var stmt = createStatement("SELECT name FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 1);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_TEXT,
|
||||
stmt.getTypeOfIndex(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_value_type_blob() {
|
||||
var stmt = createStatement("SELECT blobber FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 2);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_BLOB,
|
||||
stmt.getTypeOfIndex(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_numEntries_one() {
|
||||
var stmt = createStatement("SELECT blobber FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 2);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq(1, stmt.numEntries);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_numEntries_all() {
|
||||
var stmt = createStatement("SELECT * FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 2);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq(5, stmt.numEntries);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_getInt() {
|
||||
var stmt = createStatement("SELECT id FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 2);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq(2, stmt.getInt32(0));
|
||||
do_check_eq(2, stmt.getInt64(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_getDouble() {
|
||||
var stmt = createStatement("SELECT number FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 2);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq(1.23, stmt.getDouble(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_getUTF8String() {
|
||||
var stmt = createStatement("SELECT name FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 1);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq("foo", stmt.getUTF8String(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_getString() {
|
||||
var stmt = createStatement("SELECT name FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 2);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
do_check_eq("", stmt.getString(0));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_getBlob() {
|
||||
var stmt = createStatement("SELECT blobber FROM test WHERE id = ?1");
|
||||
stmt.bindByIndex(0, 2);
|
||||
do_check_true(stmt.executeStep());
|
||||
|
||||
var count = { value: 0 };
|
||||
var arr = { value: null };
|
||||
stmt.getBlob(0, count, arr);
|
||||
do_check_eq(2, count.value);
|
||||
do_check_eq(1, arr.value[0]);
|
||||
do_check_eq(2, arr.value[1]);
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
|
||||
30
storage/test/unit/test_telemetry_vfs.js
Normal file
30
storage/test/unit/test_telemetry_vfs.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Make sure that there are telemetry entries created by sqlite io
|
||||
|
||||
function run_sql(d, sql) {
|
||||
var stmt = d.createStatement(sql);
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function new_file(name)
|
||||
{
|
||||
var file = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
file.append(name);
|
||||
return file;
|
||||
}
|
||||
function run_test()
|
||||
{
|
||||
const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
let read_hgram = Telemetry.getHistogramById("MOZ_SQLITE_OTHER_READ_B");
|
||||
let old_sum = read_hgram.snapshot().sum;
|
||||
const file = new_file("telemetry.sqlite");
|
||||
var d = getDatabase(file);
|
||||
run_sql(d, "CREATE TABLE bloat(data varchar)");
|
||||
run_sql(d, "DROP TABLE bloat");
|
||||
do_check_true(read_hgram.snapshot().sum > old_sum);
|
||||
}
|
||||
|
||||
83
storage/test/unit/test_unicode.js
Normal file
83
storage/test/unit/test_unicode.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file tests the unicode functions that we have added
|
||||
|
||||
const LATIN1_AE = "\xc6"; // "Æ"
|
||||
const LATIN1_ae = "\xe6"; // "æ"
|
||||
|
||||
add_task(function* setup() {
|
||||
getOpenedDatabase().createTable("test", "id INTEGER PRIMARY KEY, name TEXT");
|
||||
|
||||
var stmt = createStatement("INSERT INTO test (name, id) VALUES (?1, ?2)");
|
||||
stmt.bindByIndex(0, LATIN1_AE);
|
||||
stmt.bindByIndex(1, 1);
|
||||
stmt.execute();
|
||||
stmt.bindByIndex(0, "A");
|
||||
stmt.bindByIndex(1, 2);
|
||||
stmt.execute();
|
||||
stmt.bindByIndex(0, "b");
|
||||
stmt.bindByIndex(1, 3);
|
||||
stmt.execute();
|
||||
stmt.bindByIndex(0, LATIN1_ae);
|
||||
stmt.bindByIndex(1, 4);
|
||||
stmt.execute();
|
||||
stmt.finalize();
|
||||
|
||||
do_register_cleanup(cleanup);
|
||||
});
|
||||
|
||||
add_task(function* test_upper_ascii() {
|
||||
var stmt = createStatement("SELECT name, id FROM test WHERE name = upper('a')");
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq("A", stmt.getString(0));
|
||||
do_check_eq(2, stmt.getInt32(1));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_upper_non_ascii() {
|
||||
var stmt = createStatement("SELECT name, id FROM test WHERE name = upper(?1)");
|
||||
stmt.bindByIndex(0, LATIN1_ae);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(LATIN1_AE, stmt.getString(0));
|
||||
do_check_eq(1, stmt.getInt32(1));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_lower_ascii() {
|
||||
var stmt = createStatement("SELECT name, id FROM test WHERE name = lower('B')");
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq("b", stmt.getString(0));
|
||||
do_check_eq(3, stmt.getInt32(1));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_lower_non_ascii() {
|
||||
var stmt = createStatement("SELECT name, id FROM test WHERE name = lower(?1)");
|
||||
stmt.bindByIndex(0, LATIN1_AE);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(LATIN1_ae, stmt.getString(0));
|
||||
do_check_eq(4, stmt.getInt32(1));
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_like_search_different() {
|
||||
var stmt = createStatement("SELECT COUNT(*) FROM test WHERE name LIKE ?1");
|
||||
stmt.bindByIndex(0, LATIN1_AE);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(2, stmt.getInt32(0));
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
add_task(function* test_like_search_same() {
|
||||
var stmt = createStatement("SELECT COUNT(*) FROM test WHERE name LIKE ?1");
|
||||
stmt.bindByIndex(0, LATIN1_ae);
|
||||
do_check_true(stmt.executeStep());
|
||||
do_check_eq(2, stmt.getInt32(0));
|
||||
stmt.finalize();
|
||||
});
|
||||
335
storage/test/unit/test_vacuum.js
Normal file
335
storage/test/unit/test_vacuum.js
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// This file tests the Vacuum Manager.
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* Loads a test component that will register as a vacuum-participant.
|
||||
* If other participants are found they will be unregistered, to avoid conflicts
|
||||
* with the test itself.
|
||||
*/
|
||||
function load_test_vacuum_component()
|
||||
{
|
||||
const CATEGORY_NAME = "vacuum-participant";
|
||||
|
||||
do_load_manifest("vacuumParticipant.manifest");
|
||||
|
||||
// This is a lazy check, there could be more participants than just this test
|
||||
// we just mind that the test exists though.
|
||||
const EXPECTED_ENTRIES = ["vacuumParticipant"];
|
||||
let catMan = Cc["@mozilla.org/categorymanager;1"].
|
||||
getService(Ci.nsICategoryManager);
|
||||
let found = false;
|
||||
let entries = catMan.enumerateCategory(CATEGORY_NAME);
|
||||
while (entries.hasMoreElements()) {
|
||||
let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data;
|
||||
print("Check if the found category entry (" + entry + ") is expected.");
|
||||
if (EXPECTED_ENTRIES.indexOf(entry) != -1) {
|
||||
print("Check that only one test entry exists.");
|
||||
do_check_false(found);
|
||||
found = true;
|
||||
}
|
||||
else {
|
||||
// Temporary unregister other participants for this test.
|
||||
catMan.deleteCategoryEntry("vacuum-participant", entry, false);
|
||||
}
|
||||
}
|
||||
print("Check the test entry exists.");
|
||||
do_check_true(found);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a fake idle-daily notification to the VACUUM Manager.
|
||||
*/
|
||||
function synthesize_idle_daily()
|
||||
{
|
||||
let vm = Cc["@mozilla.org/storage/vacuum;1"].getService(Ci.nsIObserver);
|
||||
vm.observe(null, "idle-daily", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new nsIFile reference for a profile database.
|
||||
* @param filename for the database, excluded the .sqlite extension.
|
||||
*/
|
||||
function new_db_file(name)
|
||||
{
|
||||
let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
file.append(name + ".sqlite");
|
||||
return file;
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
do_test_pending();
|
||||
|
||||
// Change initial page size. Do it immediately since it would require an
|
||||
// additional vacuum op to do it later. As a bonus this makes the page size
|
||||
// change test really fast since it only has to check results.
|
||||
let conn = getDatabase(new_db_file("testVacuum"));
|
||||
conn.executeSimpleSQL("PRAGMA page_size = 1024");
|
||||
print("Check current page size.");
|
||||
let stmt = conn.createStatement("PRAGMA page_size");
|
||||
try {
|
||||
while (stmt.executeStep()) {
|
||||
do_check_eq(stmt.row.page_size, 1024);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
load_test_vacuum_component();
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
const TESTS = [
|
||||
|
||||
function test_common_vacuum()
|
||||
{
|
||||
print("\n*** Test that a VACUUM correctly happens and all notifications are fired.");
|
||||
// Wait for VACUUM begin.
|
||||
let beginVacuumReceived = false;
|
||||
Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(onVacuum, aTopic);
|
||||
beginVacuumReceived = true;
|
||||
}, "test-begin-vacuum", false);
|
||||
|
||||
// Wait for heavy IO notifications.
|
||||
let heavyIOTaskBeginReceived = false;
|
||||
let heavyIOTaskEndReceived = false;
|
||||
Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) {
|
||||
if (heavyIOTaskBeginReceived && heavyIOTaskEndReceived) {
|
||||
Services.obs.removeObserver(onVacuum, aTopic);
|
||||
}
|
||||
|
||||
if (aData == "vacuum-begin") {
|
||||
heavyIOTaskBeginReceived = true;
|
||||
}
|
||||
else if (aData == "vacuum-end") {
|
||||
heavyIOTaskEndReceived = true;
|
||||
}
|
||||
}, "heavy-io-task", false);
|
||||
|
||||
// Wait for VACUUM end.
|
||||
Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(onVacuum, aTopic);
|
||||
print("Check we received onBeginVacuum");
|
||||
do_check_true(beginVacuumReceived);
|
||||
print("Check we received heavy-io-task notifications");
|
||||
do_check_true(heavyIOTaskBeginReceived);
|
||||
do_check_true(heavyIOTaskEndReceived);
|
||||
print("Received onEndVacuum");
|
||||
run_next_test();
|
||||
}, "test-end-vacuum", false);
|
||||
|
||||
synthesize_idle_daily();
|
||||
},
|
||||
|
||||
function test_skipped_if_recent_vacuum()
|
||||
{
|
||||
print("\n*** Test that a VACUUM is skipped if it was run recently.");
|
||||
Services.prefs.setIntPref("storage.vacuum.last.testVacuum.sqlite",
|
||||
parseInt(Date.now() / 1000));
|
||||
|
||||
// Wait for VACUUM begin.
|
||||
let vacuumObserver = {
|
||||
gotNotification: false,
|
||||
observe: function VO_observe(aSubject, aTopic, aData) {
|
||||
this.gotNotification = true;
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
|
||||
};
|
||||
Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false);
|
||||
|
||||
// Check after a couple seconds that no VACUUM has been run.
|
||||
do_timeout(2000, function () {
|
||||
print("Check VACUUM did not run.");
|
||||
do_check_false(vacuumObserver.gotNotification);
|
||||
Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum");
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
synthesize_idle_daily();
|
||||
},
|
||||
|
||||
function test_page_size_change()
|
||||
{
|
||||
print("\n*** Test that a VACUUM changes page_size");
|
||||
|
||||
// We did setup the database with a small page size, the previous vacuum
|
||||
// should have updated it.
|
||||
print("Check that page size was updated.");
|
||||
let conn = getDatabase(new_db_file("testVacuum"));
|
||||
let stmt = conn.createStatement("PRAGMA page_size");
|
||||
try {
|
||||
while (stmt.executeStep()) {
|
||||
do_check_eq(stmt.row.page_size, conn.defaultPageSize);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
},
|
||||
|
||||
function test_skipped_optout_vacuum()
|
||||
{
|
||||
print("\n*** Test that a VACUUM is skipped if the participant wants to opt-out.");
|
||||
Services.obs.notifyObservers(null, "test-options", "opt-out");
|
||||
|
||||
// Wait for VACUUM begin.
|
||||
let vacuumObserver = {
|
||||
gotNotification: false,
|
||||
observe: function VO_observe(aSubject, aTopic, aData) {
|
||||
this.gotNotification = true;
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
|
||||
};
|
||||
Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false);
|
||||
|
||||
// Check after a couple seconds that no VACUUM has been run.
|
||||
do_timeout(2000, function () {
|
||||
print("Check VACUUM did not run.");
|
||||
do_check_false(vacuumObserver.gotNotification);
|
||||
Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum");
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
synthesize_idle_daily();
|
||||
},
|
||||
|
||||
/* Changing page size on WAL is not supported till Bug 634374 is properly fixed.
|
||||
function test_page_size_change_with_wal()
|
||||
{
|
||||
print("\n*** Test that a VACUUM changes page_size with WAL mode");
|
||||
Services.obs.notifyObservers(null, "test-options", "wal");
|
||||
|
||||
// Set a small page size.
|
||||
let conn = getDatabase(new_db_file("testVacuum2"));
|
||||
conn.executeSimpleSQL("PRAGMA page_size = 1024");
|
||||
let stmt = conn.createStatement("PRAGMA page_size");
|
||||
try {
|
||||
while (stmt.executeStep()) {
|
||||
do_check_eq(stmt.row.page_size, 1024);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
// Use WAL journal mode.
|
||||
conn.executeSimpleSQL("PRAGMA journal_mode = WAL");
|
||||
stmt = conn.createStatement("PRAGMA journal_mode");
|
||||
try {
|
||||
while (stmt.executeStep()) {
|
||||
do_check_eq(stmt.row.journal_mode, "wal");
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
// Wait for VACUUM end.
|
||||
let vacuumObserver = {
|
||||
observe: function VO_observe(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(this, aTopic);
|
||||
print("Check page size has been updated.");
|
||||
let stmt = conn.createStatement("PRAGMA page_size");
|
||||
try {
|
||||
while (stmt.executeStep()) {
|
||||
do_check_eq(stmt.row.page_size, Ci.mozIStorageConnection.DEFAULT_PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
print("Check journal mode has been restored.");
|
||||
stmt = conn.createStatement("PRAGMA journal_mode");
|
||||
try {
|
||||
while (stmt.executeStep()) {
|
||||
do_check_eq(stmt.row.journal_mode, "wal");
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
|
||||
}
|
||||
Services.obs.addObserver(vacuumObserver, "test-end-vacuum", false);
|
||||
|
||||
synthesize_idle_daily();
|
||||
},
|
||||
*/
|
||||
|
||||
function test_memory_database_crash()
|
||||
{
|
||||
print("\n*** Test that we don't crash trying to vacuum a memory database");
|
||||
Services.obs.notifyObservers(null, "test-options", "memory");
|
||||
|
||||
// Wait for VACUUM begin.
|
||||
let vacuumObserver = {
|
||||
gotNotification: false,
|
||||
observe: function VO_observe(aSubject, aTopic, aData) {
|
||||
this.gotNotification = true;
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
|
||||
};
|
||||
Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false);
|
||||
|
||||
// Check after a couple seconds that no VACUUM has been run.
|
||||
do_timeout(2000, function () {
|
||||
print("Check VACUUM did not run.");
|
||||
do_check_false(vacuumObserver.gotNotification);
|
||||
Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum");
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
synthesize_idle_daily();
|
||||
},
|
||||
|
||||
/* Changing page size on WAL is not supported till Bug 634374 is properly fixed.
|
||||
function test_wal_restore_fail()
|
||||
{
|
||||
print("\n*** Test that a failing WAL restoration notifies failure");
|
||||
Services.obs.notifyObservers(null, "test-options", "wal-fail");
|
||||
|
||||
// Wait for VACUUM end.
|
||||
let vacuumObserver = {
|
||||
observe: function VO_observe(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(vacuumObserver, "test-end-vacuum");
|
||||
print("Check WAL restoration failed.");
|
||||
do_check_false(aData);
|
||||
run_next_test();
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
|
||||
}
|
||||
Services.obs.addObserver(vacuumObserver, "test-end-vacuum", false);
|
||||
|
||||
synthesize_idle_daily();
|
||||
},
|
||||
*/
|
||||
];
|
||||
|
||||
function run_next_test()
|
||||
{
|
||||
if (TESTS.length == 0) {
|
||||
Services.obs.notifyObservers(null, "test-options", "dispose");
|
||||
do_test_finished();
|
||||
}
|
||||
else {
|
||||
// Set last VACUUM to a date in the past.
|
||||
Services.prefs.setIntPref("storage.vacuum.last.testVacuum.sqlite",
|
||||
parseInt(Date.now() / 1000 - 31 * 86400));
|
||||
do_execute_soon(TESTS.shift());
|
||||
}
|
||||
}
|
||||
125
storage/test/unit/vacuumParticipant.js
Normal file
125
storage/test/unit/vacuumParticipant.js
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// This testing component is used in test_vacuum* tests.
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* Returns a new nsIFile reference for a profile database.
|
||||
* @param filename for the database, excluded the .sqlite extension.
|
||||
*/
|
||||
function new_db_file(name)
|
||||
{
|
||||
let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
file.append(name + ".sqlite");
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens and returns a connection to the provided database file.
|
||||
* @param nsIFile interface to the database file.
|
||||
*/
|
||||
function getDatabase(aFile)
|
||||
{
|
||||
return Cc["@mozilla.org/storage/service;1"].getService(Ci.mozIStorageService)
|
||||
.openDatabase(aFile);
|
||||
}
|
||||
|
||||
function vacuumParticipant()
|
||||
{
|
||||
this._dbConn = getDatabase(new_db_file("testVacuum"));
|
||||
Services.obs.addObserver(this, "test-options", false);
|
||||
}
|
||||
|
||||
vacuumParticipant.prototype =
|
||||
{
|
||||
classDescription: "vacuumParticipant",
|
||||
classID: Components.ID("{52aa0b22-b82f-4e38-992a-c3675a3355d2}"),
|
||||
contractID: "@unit.test.com/test-vacuum-participant;1",
|
||||
|
||||
get expectedDatabasePageSize() {
|
||||
return this._dbConn.defaultPageSize;
|
||||
},
|
||||
get databaseConnection() {
|
||||
return this._dbConn;
|
||||
},
|
||||
|
||||
_grant: true,
|
||||
onBeginVacuum: function TVP_onBeginVacuum()
|
||||
{
|
||||
if (!this._grant) {
|
||||
this._grant = true;
|
||||
return false;
|
||||
}
|
||||
Services.obs.notifyObservers(null, "test-begin-vacuum", null);
|
||||
return true;
|
||||
},
|
||||
onEndVacuum: function TVP_EndVacuum(aSucceeded)
|
||||
{
|
||||
if (this._stmt) {
|
||||
this._stmt.finalize();
|
||||
}
|
||||
Services.obs.notifyObservers(null, "test-end-vacuum", aSucceeded);
|
||||
},
|
||||
|
||||
observe: function TVP_observe(aSubject, aTopic, aData)
|
||||
{
|
||||
if (aData == "opt-out") {
|
||||
this._grant = false;
|
||||
}
|
||||
else if (aData == "wal") {
|
||||
try {
|
||||
this._dbConn.close();
|
||||
} catch (e) {
|
||||
// Do nothing.
|
||||
}
|
||||
this._dbConn = getDatabase(new_db_file("testVacuum2"));
|
||||
}
|
||||
else if (aData == "wal-fail") {
|
||||
try {
|
||||
this._dbConn.close();
|
||||
} catch (e) {
|
||||
// Do nothing.
|
||||
}
|
||||
this._dbConn = getDatabase(new_db_file("testVacuum3"));
|
||||
// Use WAL journal mode.
|
||||
this._dbConn.executeSimpleSQL("PRAGMA journal_mode = WAL");
|
||||
// Create a not finalized statement.
|
||||
this._stmt = this._dbConn.createStatement("SELECT :test");
|
||||
this._stmt.params.test = 1;
|
||||
this._stmt.executeStep();
|
||||
}
|
||||
else if (aData == "memory") {
|
||||
try {
|
||||
this._dbConn.asyncClose();
|
||||
} catch (e) {
|
||||
// Do nothing.
|
||||
}
|
||||
this._dbConn = Cc["@mozilla.org/storage/service;1"].
|
||||
getService(Ci.mozIStorageService).
|
||||
openSpecialDatabase("memory");
|
||||
}
|
||||
else if (aData == "dispose") {
|
||||
Services.obs.removeObserver(this, "test-options");
|
||||
try {
|
||||
this._dbConn.asyncClose();
|
||||
} catch (e) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.mozIStorageVacuumParticipant,
|
||||
Ci.nsIObserver,
|
||||
])
|
||||
};
|
||||
|
||||
var gComponentsArray = [vacuumParticipant];
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(gComponentsArray);
|
||||
3
storage/test/unit/vacuumParticipant.manifest
Normal file
3
storage/test/unit/vacuumParticipant.manifest
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
component {52aa0b22-b82f-4e38-992a-c3675a3355d2} vacuumParticipant.js
|
||||
contract @unit.test.com/test-vacuum-participant;1 {52aa0b22-b82f-4e38-992a-c3675a3355d2}
|
||||
category vacuum-participant vacuumParticipant @unit.test.com/test-vacuum-participant;1
|
||||
46
storage/test/unit/xpcshell.ini
Normal file
46
storage/test/unit/xpcshell.ini
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
[DEFAULT]
|
||||
head = head_storage.js
|
||||
tail =
|
||||
support-files =
|
||||
corruptDB.sqlite
|
||||
fakeDB.sqlite
|
||||
locale_collation.txt
|
||||
vacuumParticipant.js
|
||||
vacuumParticipant.manifest
|
||||
|
||||
[test_bug-365166.js]
|
||||
[test_bug-393952.js]
|
||||
[test_bug-429521.js]
|
||||
[test_bug-444233.js]
|
||||
[test_cache_size.js]
|
||||
[test_chunk_growth.js]
|
||||
# Bug 676981: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_connection_asyncClose.js]
|
||||
[test_connection_executeAsync.js]
|
||||
[test_connection_executeSimpleSQLAsync.js]
|
||||
[test_js_helpers.js]
|
||||
[test_levenshtein.js]
|
||||
[test_like.js]
|
||||
[test_like_escape.js]
|
||||
[test_locale_collation.js]
|
||||
[test_page_size_is_32k.js]
|
||||
[test_sqlite_secure_delete.js]
|
||||
[test_statement_executeAsync.js]
|
||||
[test_statement_wrapper_automatically.js]
|
||||
[test_storage_aggregates.js]
|
||||
[test_storage_connection.js]
|
||||
# Bug 676981: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_storage_fulltextindex.js]
|
||||
[test_storage_function.js]
|
||||
[test_storage_progresshandler.js]
|
||||
[test_storage_service.js]
|
||||
[test_storage_service_unshared.js]
|
||||
[test_storage_statement.js]
|
||||
[test_storage_value_array.js]
|
||||
[test_unicode.js]
|
||||
[test_vacuum.js]
|
||||
[test_telemetry_vfs.js]
|
||||
# Bug 676981: test fails consistently on Android
|
||||
# fail-if = os == "android"
|
||||
Loading…
Add table
Add a link
Reference in a new issue