}
class DbException extends SQLTesterException {
- constructor(...args){
- super(...args);
- //TODO...
- //const db = args[0];
- //if( db instanceof sqlite3.oo1.DB )
+ constructor(pDb, rc, closeDb){
+ super("DB error #"+rc+": "+sqlite3.capi.sqlite3_errmsg(pDb));
+ if( closeDb ) sqlite3.capi.sqlite3_close_v2(pDb);
}
isFatal() { return true; }
}
return this;
}
- setOutputPrefix( func ){
- this.getOutputPrefix = func;
- return this;
+ outputPrefix(){
+ if( 0==arguments.length ){
+ return (this.getOutputPrefix
+ ? (this.getOutputPrefix() ?? '') : '');
+ }else{
+ this.getOutputPrefix = arguments[0];
+ return this;
+ }
}
verboseN(lvl, argv){
class SQLTester {
- #outer = new Outer().setOutputPrefix( ()=>'SQLTester: ' );
+ #outer = new Outer().outputPrefix( ()=>'SQLTester: ' );
#aFiles = [];
#inputBuffer = [];
#resultBuffer = [];
});
#emitColNames = false;
#keepGoing = false;
- #aDb = [];
#db = newObj({
- list: [],
- iCurrent: 0,
+ list: new Array(7),
+ iCurrentDb: 0,
initialDbName: "test.db",
+ initSql: ['select 1;'],
+ currentDb: function(){
+ return this.list[this.iCurrentDb];
+ }
});
constructor(){
}
+ outln(...args){ return this.#outer.outln(...args); }
+ out(...args){ return this.#outer.out(...args); }
+
+ reset(){
+ this.clearInputBuffer();
+ this.clearResultBuffer();
+ this.#clearBuffer(this.#db.initSql);
+ this.closeAllDbs();
+ this.nTest = 0;
+ this.nullView = "nil";
+ this.emitColNames = false;
+ this.#db.iCurrentDb = 0;
+ this.#db.initSql.push("SELECT 1;");
+ }
+
appendInput(line, addNL){
this.#inputBuffer.push(line);
if( addNL ) this.#inputBuffer.push('\n');
if( addNL ) this.#resultBuffer.push('\n');
}
- clearInputBuffer(){
- this.#inputBuffer.length = 0;
- return this.#inputBuffer;
- }
- clearResultBuffer(){
- this.#resultBuffer.length = 0;
- return this.#resultBuffer;
+ #clearBuffer(buffer){
+ buffer.length = 0;
+ return buffer;
}
+ clearInputBuffer(){ return this.#clearBuffer(this.#inputBuffer); }
+ clearResultBuffer(){return this.#clearBuffer(this.#resultBuffer); }
+
getInputText(){ return this.#inputBuffer.join(''); }
getResultText(){ return this.#resultBuffer.join(''); }
+ #takeBuffer(buffer){
+ const s = buffer.join('');
+ buffer.length = 0;
+ return s;
+ }
+
+ takeInputBuffer(){
+ return this.#takeBuffer(this.#inputBuffer);
+ }
+ takeResultBuffer(){
+ return this.#takeBuffer(this.#resultBuffer);
+ }
+
verbosity(...args){ return this.#outer.verbosity(...args); }
+ nullValue(){
+ if( 0==arguments.length ){
+ return this.#nullView;
+ }else{
+ this.#nullView = ''+arguments[0];
+ }
+ }
+
+ outputColumnNames(){
+ if( 0==arguments.length ){
+ return this.#emitColNames;
+ }else{
+ this.#emitColNames = !!arguments[0];
+ }
+ }
+
+ currentDbId(){
+ if( 0==arguments.length ){
+ return this.#db.iCurrentDb;
+ }else{
+ this.#affirmDbId(arguments[0]).#db.iCurrentDb = arguments[0];
+ }
+ }
+
+ #affirmDbId(id){
+ if(id<0 || id>=this.#db.list.length){
+ toss(SQLTesterException, "Database index ",id," is out of range.");
+ }
+ return this;
+ }
+
+ currentDb(...args){
+ if( 0!=args.length ){
+ this.#affirmDbId(id).#db.iCurrentDb = id;
+ }
+ return this.#db.currentDb();
+ }
+
+ getDbById(id){
+ return this.#affirmDbId(id).#db.list[id];
+ }
+
+ getCurrentDb(){ return this.#db.list[this.#db.iCurrentDb]; }
+
+
+ closeDb(id) {
+ if( 0==arguments.length ){
+ id = this.#db.iCurrentDb;
+ }
+ const db = this.#affirmDbId(id).#db.list[id];
+ if( db ){
+ sqlite3.capi.sqlite3_close_v2(db);
+ this.#db.list[id] = null;
+ }
+ }
+
+ closeAllDbs(){
+ for(let i = 0; i<this.#db.list.length; ++i){
+ if(this.#db.list[i]){
+ sqlite3.capi.sqlite3_close_v2(this.#db.list[i]);
+ this.#db.list[i] = null;
+ }
+ }
+ this.#db.iCurrentDb = 0;
+ }
+
+ openDb(name, createIfNeeded){
+ if( 3===arguments.length ){
+ const slot = arguments[0];
+ this.#affirmDbId(slot).#db.iCurrentDb = slot;
+ name = arguments[1];
+ createIfNeeded = arguments[2];
+ }
+ this.closeDb();
+ const capi = sqlite3.capi, wasm = sqlite3.wasm;
+ let pDb = 0;
+ let flags = capi.SQLITE_OPEN_READWRITE;
+ if( createIfNeeded ) flags |= capi.SQLITE_OPEN_CREATE;
+ try{
+ let rc;
+ wasm.pstack.call(function(){
+ let ppOut = wasm.pstack.allocPtr();
+ rc = sqlite3.capi.sqlite3_open_v2(name, ppOut, flags, null);
+ pDb = wasm.peekPtr(ppOut);
+ });
+ if( 0==rc && this.#db.initSql.length > 0){
+ //this.#outer.verbose2("RUNNING DB INIT CODE: ",this.#db.initSql.toString());
+ rc = this.execSql(pDb, false, ResultBufferMode.NONE,
+ null, this.#db.initSql.join(''));
+ }
+ if( 0!=rc ){
+ sqlite3.SQLite3Error.toss(
+ rc,
+ "sqlite3 result code",rc+":",
+ (pDb ? sqlite3.capi.sqlite3_errmsg(pDb)
+ : sqlite3.capi.sqlite3_errstr(rc))
+ );
+ }
+ return this.#db.list[this.#db.iCurrentDb] = pDb;
+ }catch(e){
+ sqlite3.capi.sqlite3_close_v2(pDb);
+ throw e;
+ }
+ }
+
+ #setupInitialDb(){
+ if( !this.#db.list[0] ){
+ Util.unlink(this.#db.initialDbName);
+ this.openDb(0, this.#db.initialDbName, true);
+ }else{
+ this.#outer.outln("WARNING: setupInitialDb() unexpectedly ",
+ "triggered while it is opened.");
+ }
+ }
+
+ /**
+ Returns v or some escaped form of v, as defined in the tester's
+ spec doc.
+ */
+ #escapeSqlValue(v){
+ if( !v ) return "{}";
+ if( !Rx.special.test(v) ){
+ return v /* no escaping needed */;
+ }
+ if( !Rx.squiggly.test(v) ){
+ return "{"+v+"}";
+ }
+ const sb = ["\""];
+ const n = v.length;
+ for(let i = 0; i < n; ++i){
+ const ch = v.charAt(i);
+ switch(ch){
+ case '\\': sb.push("\\\\"); break;
+ case '"': sb.push("\\\""); break;
+ default:{
+ //verbose("CHAR ",(int)ch," ",ch," octal=",String.format("\\%03o", (int)ch));
+ const ccode = ch.charCodeAt(i);
+ if( ccode < 32 ) sb.push('\\',ccode.toString(8),'o');
+ else sb.push(ch);
+ break;
+ }
+ }
+ }
+ sb.append("\"");
+ return sb.join('');
+ }
+
+ #appendDbErr(pDb, sb, rc){
+ sb.push(sqlite3.capi.sqlite3_js_rc_str(rc), ' ');
+ const msg = this.#escapeSqlValue(sqlite3.capi.sqlite3_errmsg(pDb));
+ if( '{' == msg.charAt(0) ){
+ sb.push(msg);
+ }else{
+ sb.push('{', msg, '}');
+ }
+ }
+
+ execSql(pDb, throwOnError, appendMode, lineMode, sql){
+ sql = sqlite3.capi.sqlite3_js_sql_to_string(sql);
+ this.#outer.outln("execSql() is TODO. ",sql);
+ return 0;
+ }
+
}/*SQLTester*/
class Command {
}
}
-class TestCase extends Command {
-
- process(tester, script, argv){
- this.argcCheck(script, argv,1);
- script.testCaseName(argv[1]);
- tester.clearResultBuffer();
- tester.clearInputBuffer();
- }
-}
-
class Cursor {
src;
sb = [];
requiredProperties: / REQUIRED_PROPERTIES:[ \t]*(\S.*)\s*$/,
scriptModuleName: / SCRIPT_MODULE_NAME:[ \t]*(\S+)\s*$/,
mixedModuleName: / ((MIXED_)?MODULE_NAME):[ \t]*(\S+)\s*$/,
- command: /^--(([a-z-]+)( .*)?)$/
+ command: /^--(([a-z-]+)( .*)?)$/,
+ //! "Special" characters - we have to escape output if it contains any.
+ special: /[\x00-\x20\x22\x5c\x7b\x7d]/,
+ //! Either of '{' or '}'.
+ squiggly: /[{}]/
});
class TestScript {
#moduleName = null;
#filename = null;
#testCaseName = null;
- #outer = new Outer().setOutputPrefix( ()=>this.getOutputPrefix() );
+ #outer = new Outer().outputPrefix( ()=>this.getOutputPrefix()+': ' );
constructor(...args){
let content, filename;
}
this.#filename = filename;
this.#cursor.src = content;
- this.#outer.outputPrefix = ()=>this.getOutputPrefix();
}
testCaseName(){
getOutputPrefix() {
let rc = "["+(this.#moduleName || this.#filename)+"]";
if( this.#testCaseName ) rc += "["+this.#testCaseName+"]";
- return rc + " line "+ this.#cursor.lineNo +" ";
+ return rc + " line "+ this.#cursor.lineNo;
}
reset(){
}/*TestScript*/;
+//! --close command
+class CloseDbCommand extends Command {
+ process(t, ts, argv){
+ this.argcCheck(ts,argv,0,1);
+ let id;
+ if(argv.length>1){
+ const arg = argv[1];
+ if("all".equals(arg)){
+ t.closeAllDbs();
+ return;
+ }
+ else{
+ id = parseInt(arg);
+ }
+ }else{
+ id = t.currentDbId();
+ }
+ t.closeDb(id);
+ }
+}
+
+//! --column-names command
+class ColumnNamesCommand extends Command {
+ process( st, ts, argv ){
+ this.argcCheck(ts,argv,1);
+ st.outputColumnNames( !!parseInt(argv[1]) );
+ }
+}
+
+//! --db command
+class DbCommand extends Command {
+ process(t, ts, argv){
+ this.argcCheck(ts,argv,1);
+ t.currentDbId( parseInt(argv[1]) );
+ }
+}
+
+//! --open command
+class OpenDbCommand extends Command {
+ #createIfNeeded = false;
+ constructor(createIfNeeded=false){
+ super();
+ this.#createIfNeeded = createIfNeeded;
+ }
+ process(t, ts, argv){
+ this.argcCheck(ts,argv,1);
+ t.openDb(argv[1], this.#createIfNeeded);
+ }
+}
+
+//! --new command
+class NewDbCommand extends OpenDbCommand {
+ constructor(){ super(true); }
+}
+
+//! Placeholder dummy/no-op commands
+class NoopCommand extends Command {
+ process(t, ts, argv){}
+}
+
+//! --null command
+class NullCommand extends Command {
+ process(st, ts, argv){
+ this.argcCheck(ts,argv,1);
+ st.nullValue( argv[1] );
+ }
+}
+
+//! --print command
+class PrintCommand extends Command {
+ process(st, ts, argv){
+ st.out(ts.getOutputPrefix(),': ');
+ if( 1==argv.length ){
+ st.out( st.getInputText() );
+ }else{
+ st.outln( Util.argvToString(argv) );
+ }
+ }
+}
+
+
+//! --testcase command
+class TestCaseCommand extends Command {
+ process(tester, script, argv){
+ this.argcCheck(script, argv,1);
+ script.testCaseName(argv[1]);
+ tester.clearResultBuffer();
+ tester.clearInputBuffer();
+ }
+}
+
+
+//! --verbosity command
+class VerbosityCommand extends Command {
+ process(t, ts, argv){
+ t.argcCheck(ts,argv,1);
+ ts.verbosity( parseInt(argv[1]) );
+ }
+}
+
class CommandDispatcher {
static map = newObj();
let rv = CommandDispatcher.map[name];
if( rv ) return rv;
switch(name){
- //todo: map name to Command instance
- case "testcase": rv = new TestCase(); break;
+ case "close": rv = new CloseDbCommand(); break;
+ case "column-names": rv = new ColumnNamesCommand(); break;
+ case "db": rv = new DbCommand(); break;
+ //case "glob": rv = new GlobCommand(); break;
+ //case "json": rv = new JsonCommand(); break;
+ //case "json-block": rv = new JsonBlockCommand(); break;
+ case "new": rv = new NewDbCommand(); break;
+ //case "notglob": rv = new NotGlobCommand(); break;
+ case "null": rv = new NullCommand(); break;
+ case "oom": rv = new NoopCommand(); break;
+ case "open": rv = new OpenDbCommand(); break;
+ case "print": rv = new PrintCommand(); break;
+ //case "result": rv = new ResultCommand(); break;
+ //case "run": rv = new RunCommand(); break;
+ //case "tableresult": rv = new TableResultCommand(); break;
+ case "testcase": rv = new TestCaseCommand(); break;
+ case "verbosity": rv = new VerbosityCommand(); break;
}
if( rv ){
CommandDispatcher.map[name] = rv;
TestScript,
TestScriptFailed,
UnknownCommand,
- Util
+ Util,
+ sqlite3
});
export {namespace as default};
-C Get\sthe\sbasic\sparsing\spieces\sand\scommand\sdispatching\sin\splace\sin\sthe\sJS\sSQLTester.
-D 2023-08-29T13:28:36.476
+C Get\sthe\sJS\sSQLTester\scommand\shandlers\sin\splace\ssans\sthose\swhich\shave\sto\srun\sSQL.
+D 2023-08-29T15:39:57.155
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/jni/src/org/sqlite/jni/sqlite3_context.java 66ca95ce904044263a4aff684abe262d56f73e6b06bca6cf650761d79d7779ad
F ext/jni/src/org/sqlite/jni/sqlite3_stmt.java 78e6d1b95ac600a9475e9db4623f69449322b0c93d1bd4e1616e76ed547ed9fc
F ext/jni/src/org/sqlite/jni/sqlite3_value.java 3d1d4903e267bc0bc81d57d21f5e85978eff389a1a6ed46726dbe75f85e6914a
-F ext/jni/src/org/sqlite/jni/tester/SQLTester.java bf350903abe04a9bed2d8a2a71692ed4291dbb4eece2d3329ed91d15b0321e6d
+F ext/jni/src/org/sqlite/jni/tester/SQLTester.java c8a9f20694e66f4d7ed677cd6d1f0d829f802c347a1f413ac2446c62e4cba23d
F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e
F ext/jni/src/tests/000-000-sanity.test cfe6dc1b950751d6096e3f5695becaadcdaa048bfe9567209d6eb676e693366d
F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
F ext/wasm/GNUmakefile 0e362f3fc04eab6628cbe4f1e35f4ab4a200881f6b5f753b27fb45eabeddd9d2
F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576
F ext/wasm/README.md a8a2962c3aebdf8d2104a9102e336c5554e78fc6072746e5daf9c61514e7d193
-F ext/wasm/SQLTester/SQLTester.mjs 2ea7d09f0c33e509aa3c4ca974be5705f59ddcd2173d4ff2721d7448c65be8bd
-F ext/wasm/SQLTester/SQLTester.run.mjs 478f4d90951591decaa7e1e3fa1729f6ed0043ae4cb48b0a92056b9707d44185
+F ext/wasm/SQLTester/SQLTester.mjs 90fc3d2eb831afed237c18b78c22b8871d8f855a742715ebee571a60b9fcd98e
+F ext/wasm/SQLTester/SQLTester.run.mjs 30a459ec400495cc52f1d693703f1629e141947a19eaf868a8e4c1fd3ef2a114
F ext/wasm/SQLTester/index.html 88d87e3ccbc33e7ab3773a8e48c1172e876951c4be31d1307c3700671262cddf
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api d6a5078f48a5301ed17b9a30331075d9b2506e1360c1f0dee0c7816c10acd9ab
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
F ext/wasm/api/sqlite3-api-cleanup.js d235ad237df6954145404305040991c72ef8b1881715d2a650dda7b3c2576d0e
F ext/wasm/api/sqlite3-api-glue.js b65e546568f1dfb35205b9792feb5146a6323d71b55cda58e2ed30def6dd52f3
F ext/wasm/api/sqlite3-api-oo1.js 9678dc4d9a5d39632b6ffe6ea94a023119260815bf32f265bf5f6c36c9516db8
-F ext/wasm/api/sqlite3-api-prologue.js ef6f67c5ea718490806e5e17d2644b8b2f6e6ba5284d23dc1fbfd14d401c1ab5
+F ext/wasm/api/sqlite3-api-prologue.js 7fe51f06cd855634cb3765f830393f544fb532ead1cf95b5de3dd0befc81b92d
F ext/wasm/api/sqlite3-api-worker1.js 9f32af64df1a031071912eea7a201557fe39b1738645c0134562bb84e88e2fec
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 60eec5ceda80c64870713df8e9aeabeef933c007f2010792225a07d5ef36baef
-R 0bdc268c3b78f235b9f50e80fcfe1a69
+P 8fcc2a553c1e26734902bbdee0c38183ee22b7b5c75f07405529bb79db34145a
+R 8ed29d2cdb1f79e88ba5ccad29a3151d
U stephan
-Z 00dd200744de92467554b7f23df0cf79
+Z 988ed72426998a455381761a89d498de
# Remove this line to create a well-formed Fossil manifest.