diff options
Diffstat (limited to 'toolkit/components/sqlite/tests/xpcshell')
6 files changed, 379 insertions, 0 deletions
diff --git a/toolkit/components/sqlite/tests/xpcshell/.eslintrc.js b/toolkit/components/sqlite/tests/xpcshell/.eslintrc.js new file mode 100644 index 000000000..d35787cd2 --- /dev/null +++ b/toolkit/components/sqlite/tests/xpcshell/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/xpcshell/xpcshell.eslintrc.js" + ] +}; diff --git a/toolkit/components/sqlite/tests/xpcshell/data/chrome.manifest b/toolkit/components/sqlite/tests/xpcshell/data/chrome.manifest new file mode 100644 index 000000000..92b9cf60b --- /dev/null +++ b/toolkit/components/sqlite/tests/xpcshell/data/chrome.manifest @@ -0,0 +1 @@ +content test_sqlite_internal ./ diff --git a/toolkit/components/sqlite/tests/xpcshell/data/worker_sqlite_internal.js b/toolkit/components/sqlite/tests/xpcshell/data/worker_sqlite_internal.js new file mode 100644 index 000000000..7f0b3af03 --- /dev/null +++ b/toolkit/components/sqlite/tests/xpcshell/data/worker_sqlite_internal.js @@ -0,0 +1,279 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +importScripts("worker_sqlite_shared.js", + "resource://gre/modules/workers/require.js"); + +self.onmessage = function onmessage(msg) { + try { + run_test(); + } catch (ex) { + let {message, moduleStack, moduleName, lineNumber} = ex; + let error = new Error(message, moduleName, lineNumber); + error.stack = moduleStack; + dump("Uncaught error: " + error + "\n"); + dump("Full stack: " + moduleStack + "\n"); + throw error; + } +}; + +var Sqlite; + +var SQLITE_OK; /* Successful result */ +var SQLITE_ROW; /* sqlite3_step() has another row ready */ +var SQLITE_DONE; /* sqlite3_step() has finished executing */ + +function test_init() { + do_print("Starting test_init"); + // Sqlite should be loaded. + Sqlite = require("resource://gre/modules/sqlite/sqlite_internal.js"); + do_check_neq(typeof Sqlite, "undefined"); + do_check_neq(typeof Sqlite.Constants, "undefined"); + SQLITE_OK = Sqlite.Constants.SQLITE_OK; + SQLITE_ROW = Sqlite.Constants.SQLITE_ROW; + SQLITE_DONE = Sqlite.Constants.SQLITE_DONE; +} + +/** + * Clean up the database. + * @param {sqlite3_ptr} db A pointer to the database. + */ +function cleanupDB(db) { + withQuery(db, "DROP TABLE IF EXISTS TEST;", SQLITE_DONE); +} + +/** + * Open and close sqlite3 database. + * @param {String} open A name of the sqlite3 open function to be + * used. + * @param {Array} openArgs = [] Optional arguments to open function. + * @param {Function} callback = null An optional callback to be run after the + * database is opened but before it is + * closed. + */ +function withDB(open, openArgs = [], callback = null) { + let db = Sqlite.Type.sqlite3_ptr.implementation(); + let dbPtr = db.address(); + + // Open database. + let result = Sqlite[open].apply(Sqlite, ["data/test.db", dbPtr].concat( + openArgs)); + do_check_eq(result, SQLITE_OK); + + // Drop the test table if it already exists. + cleanupDB(db); + + try { + if (callback) { + callback(db); + } + } catch (ex) { + do_check_true(false); + throw ex; + } finally { + // Drop the test table if it still exists. + cleanupDB(db); + // Close data base. + result = Sqlite.close(db); + do_check_eq(result, SQLITE_OK); + } +} + +/** + * Execute an SQL query using sqlite3 API. + * @param {sqlite3_ptr} db A pointer to the database. + * @param {String} sql A SQL query string. + * @param {Number} stepResult Expected result code after evaluating the + * SQL statement. + * @param {Function} bind An optional callback with SQL binding steps. + * @param {Function} callback An optional callback that runs after the SQL + * query completes. + */ +function withQuery(db, sql, stepResult, bind, callback) { + // Create an instance of a single SQL statement. + let sqlStmt = Sqlite.Type.sqlite3_stmt_ptr.implementation(); + let sqlStmtPtr = sqlStmt.address(); + + // Unused portion of an SQL query. + let unused = Sqlite.Type.cstring.implementation(); + let unusedPtr = unused.address(); + + // Compile an SQL statement. + let result = Sqlite.prepare_v2(db, sql, sql.length, sqlStmtPtr, unusedPtr); + do_check_eq(result, SQLITE_OK); + + try { + if (bind) { + bind(sqlStmt); + } + + // Evaluate an SQL statement. + result = Sqlite.step(sqlStmt); + do_check_eq(result, stepResult); + + if (callback) { + callback(sqlStmt); + } + } catch (ex) { + do_check_true(false); + throw ex; + } finally { + // Destroy a prepared statement object. + result = Sqlite.finalize(sqlStmt); + do_check_eq(result, SQLITE_OK); + } +} + +function test_open_close() { + do_print("Starting test_open_close"); + do_check_eq(typeof Sqlite.open, "function"); + do_check_eq(typeof Sqlite.close, "function"); + + withDB("open"); +} + +function test_open_v2_close() { + do_print("Starting test_open_v2_close"); + do_check_eq(typeof Sqlite.open_v2, "function"); + + withDB("open_v2", [0x02, null]); +} + +function createTableOnOpen(db) { + withQuery(db, "CREATE TABLE TEST(" + + "ID INT PRIMARY KEY NOT NULL," + + "FIELD1 INT," + + "FIELD2 REAL," + + "FIELD3 TEXT," + + "FIELD4 TEXT," + + "FIELD5 BLOB" + + ");", SQLITE_DONE); +} + +function test_create_table() { + do_print("Starting test_create_table"); + do_check_eq(typeof Sqlite.prepare_v2, "function"); + do_check_eq(typeof Sqlite.step, "function"); + do_check_eq(typeof Sqlite.finalize, "function"); + + withDB("open", [], createTableOnOpen); +} + +/** + * Read column values after evaluating the SQL SELECT statement. + * @param {sqlite3_stmt_ptr} sqlStmt A pointer to the SQL statement. + */ +function onSqlite3Step(sqlStmt) { + // Get an int value from a query result from the ID (column 0). + let field = Sqlite.column_int(sqlStmt, 0); + do_check_eq(field, 3); + + // Get an int value from a query result from the column 1. + field = Sqlite.column_int(sqlStmt, 1); + do_check_eq(field, 2); + // Get an int64 value from a query result from the column 1. + field = Sqlite.column_int64(sqlStmt, 1); + do_check_eq(field, 2); + + // Get a double value from a query result from the column 2. + field = Sqlite.column_double(sqlStmt, 2); + do_check_eq(field, 1.2); + + // Get a number of bytes of the value in the column 3. + let bytes = Sqlite.column_bytes(sqlStmt, 3); + do_check_eq(bytes, 4); + // Get a text(cstring) value from a query result from the column 3. + field = Sqlite.column_text(sqlStmt, 3); + do_check_eq(field.readString(), "DATA"); + + // Get a number of bytes of the UTF-16 value in the column 4. + bytes = Sqlite.column_bytes16(sqlStmt, 4); + do_check_eq(bytes, 8); + // Get a text16(wstring) value from a query result from the column 4. + field = Sqlite.column_text16(sqlStmt, 4); + do_check_eq(field.readString(), "TADA"); + + // Get a blob value from a query result from the column 5. + field = Sqlite.column_blob(sqlStmt, 5); + do_check_eq(ctypes.cast(field, + Sqlite.Type.cstring.implementation).readString(), "BLOB"); +} + +function test_insert_select() { + do_print("Starting test_insert_select"); + do_check_eq(typeof Sqlite.column_int, "function"); + do_check_eq(typeof Sqlite.column_int64, "function"); + do_check_eq(typeof Sqlite.column_double, "function"); + do_check_eq(typeof Sqlite.column_bytes, "function"); + do_check_eq(typeof Sqlite.column_text, "function"); + do_check_eq(typeof Sqlite.column_text16, "function"); + do_check_eq(typeof Sqlite.column_blob, "function"); + + function onOpen(db) { + createTableOnOpen(db); + withQuery(db, + "INSERT INTO TEST VALUES (3, 2, 1.2, \"DATA\", \"TADA\", \"BLOB\");", + SQLITE_DONE); + withQuery(db, "SELECT * FROM TEST;", SQLITE_ROW, null, onSqlite3Step); + } + + withDB("open", [], onOpen); +} + +function test_insert_bind_select() { + do_print("Starting test_insert_bind_select"); + do_check_eq(typeof Sqlite.bind_int, "function"); + do_check_eq(typeof Sqlite.bind_int64, "function"); + do_check_eq(typeof Sqlite.bind_double, "function"); + do_check_eq(typeof Sqlite.bind_text, "function"); + do_check_eq(typeof Sqlite.bind_text16, "function"); + do_check_eq(typeof Sqlite.bind_blob, "function"); + + function onBind(sqlStmt) { + // Bind an int value to the ID (column 0). + let result = Sqlite.bind_int(sqlStmt, 1, 3); + do_check_eq(result, SQLITE_OK); + + // Bind an int64 value to the FIELD1 (column 1). + result = Sqlite.bind_int64(sqlStmt, 2, 2); + do_check_eq(result, SQLITE_OK); + + // Bind a double value to the FIELD2 (column 2). + result = Sqlite.bind_double(sqlStmt, 3, 1.2); + do_check_eq(result, SQLITE_OK); + + // Destructor. + let destructor = Sqlite.Constants.SQLITE_TRANSIENT; + // Bind a text value to the FIELD3 (column 3). + result = Sqlite.bind_text(sqlStmt, 4, "DATA", 4, destructor); + do_check_eq(result, SQLITE_OK); + + // Bind a text16 value to the FIELD4 (column 4). + result = Sqlite.bind_text16(sqlStmt, 5, "TADA", 8, destructor); + do_check_eq(result, SQLITE_OK); + + // Bind a blob value to the FIELD5 (column 5). + result = Sqlite.bind_blob(sqlStmt, 6, ctypes.char.array()("BLOB"), 4, + destructor); + do_check_eq(result, SQLITE_OK); + } + + function onOpen(db) { + createTableOnOpen(db); + withQuery(db, "INSERT INTO TEST VALUES (?, ?, ?, ?, ?, ?);", SQLITE_DONE, + onBind); + withQuery(db, "SELECT * FROM TEST;", SQLITE_ROW, null, onSqlite3Step); + } + + withDB("open", [], onOpen); +} + +function run_test() { + test_init(); + test_open_close(); + test_open_v2_close(); + test_create_table(); + test_insert_select(); + test_insert_bind_select(); + do_test_complete(); +} diff --git a/toolkit/components/sqlite/tests/xpcshell/data/worker_sqlite_shared.js b/toolkit/components/sqlite/tests/xpcshell/data/worker_sqlite_shared.js new file mode 100644 index 000000000..54351a02a --- /dev/null +++ b/toolkit/components/sqlite/tests/xpcshell/data/worker_sqlite_shared.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function send(message) { + self.postMessage(message); +} + +function do_test_complete() { + send({kind: "do_test_complete", args: []}); +} + +function do_check_true(x) { + send({kind: "do_check_true", args: [!!x]}); + if (x) { + dump("TEST-PASS: " + x + "\n"); + } else { + throw new Error("do_check_true failed"); + } +} + +function do_check_eq(a, b) { + let result = a == b; + send({kind: "do_check_true", args: [result]}); + if (!result) { + throw new Error("do_check_eq failed " + a + " != " + b); + } +} + +function do_check_neq(a, b) { + let result = a != b; + send({kind: "do_check_true", args: [result]}); + if (!result) { + throw new Error("do_check_neq failed " + a + " == " + b); + } +} + +function do_print(x) { + dump("TEST-INFO: " + x + "\n"); +} diff --git a/toolkit/components/sqlite/tests/xpcshell/test_sqlite_internal.js b/toolkit/components/sqlite/tests/xpcshell/test_sqlite_internal.js new file mode 100644 index 000000000..725cbfaea --- /dev/null +++ b/toolkit/components/sqlite/tests/xpcshell/test_sqlite_internal.js @@ -0,0 +1,43 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +Components.utils.import("resource://gre/modules/Promise.jsm"); + +var WORKER_SOURCE_URI = + "chrome://test_sqlite_internal/content/worker_sqlite_internal.js"; +do_load_manifest("data/chrome.manifest"); + +function run_test() { + run_next_test(); +} + +add_task(function() { + let worker = new ChromeWorker(WORKER_SOURCE_URI); + let deferred = Promise.defer(); + worker.onmessage = function(event) { + let data = event.data; + switch (data.kind) { + case "do_check_true": + try { + do_check_true(data.args[0]); + } catch (ex) { + // Ignore errors + } + break; + case "do_test_complete": + deferred.resolve(); + worker.terminate(); + break; + case "do_print": + do_print(data.args[0]); + break; + } + }; + worker.onerror = function(event) { + let error = new Error(event.message, event.filename, event.lineno); + worker.terminate(); + deferred.reject(error); + }; + worker.postMessage("START"); + return deferred.promise; +}); diff --git a/toolkit/components/sqlite/tests/xpcshell/xpcshell.ini b/toolkit/components/sqlite/tests/xpcshell/xpcshell.ini new file mode 100644 index 000000000..d652dbb1d --- /dev/null +++ b/toolkit/components/sqlite/tests/xpcshell/xpcshell.ini @@ -0,0 +1,10 @@ +[DEFAULT] +head = +tail = +skip-if = toolkit == 'android' || (os == 'mac' && appname == 'thunderbird') +support-files = + data/worker_sqlite_shared.js + data/worker_sqlite_internal.js + data/chrome.manifest + +[test_sqlite_internal.js] |