diff options
author | stephan <stephan@noemail.net> | 2023-08-30 00:22:54 +0000 |
---|---|---|
committer | stephan <stephan@noemail.net> | 2023-08-30 00:22:54 +0000 |
commit | ac5e1f82ce5e4103bf31882252587f3cbb2a564b (patch) | |
tree | 7c267dd8b847cc375a7ab68ec1aaca16e5adcd6f /ext/wasm/SQLTester | |
parent | 4f1387e9ab1b5aed8c1c901be23eb02af47854d6 (diff) | |
download | sqlite-ac5e1f82ce5e4103bf31882252587f3cbb2a564b.tar.gz sqlite-ac5e1f82ce5e4103bf31882252587f3cbb2a564b.zip |
Add a mechanism with which to import external SQLTester scripts into the JS testing tool.
FossilOrigin-Name: bb08ba020ce1d86ca6aa92f43d5ae915f67d08fa73120e1f603d150e76166624
Diffstat (limited to 'ext/wasm/SQLTester')
-rw-r--r-- | ext/wasm/SQLTester/GNUmakefile | 55 | ||||
-rw-r--r-- | ext/wasm/SQLTester/SQLTester.mjs | 81 | ||||
-rw-r--r-- | ext/wasm/SQLTester/SQLTester.run.mjs | 58 | ||||
-rw-r--r-- | ext/wasm/SQLTester/index.html | 13 | ||||
-rw-r--r-- | ext/wasm/SQLTester/touint8array.c | 29 |
5 files changed, 198 insertions, 38 deletions
diff --git a/ext/wasm/SQLTester/GNUmakefile b/ext/wasm/SQLTester/GNUmakefile new file mode 100644 index 000000000..63388084d --- /dev/null +++ b/ext/wasm/SQLTester/GNUmakefile @@ -0,0 +1,55 @@ +#!/this/is/make +# +# This makefile compiles SQLTester test files into something +# we can readily import into JavaScript. +all: + +SHELL := $(shell which bash 2>/dev/null) +MAKEFILE := $(lastword $(MAKEFILE_LIST)) +CLEAN_FILES := +DISTCLEAN_FILES := ./--dummy-- *~ + +test-list.mjs := test-list.mjs +test-list.mjs.gz := $(test-list.mjs).gz +CLEAN_FILES += $(test-list.mjs) + +tests.dir := $(firstword $(wildcard tests ../../jni/src/tests)) +$(info test script dir=$(tests.dir)) + +tests.all := $(wildcard $(tests.dir)/*.test) + +bin.touint8array := ./touint8array +$(bin.touint8array): $(bin.touint8array).c $(MAKEFILE) + $(CC) -o $@ $< +CLEAN_FILES += $(bin.touint8array) + +ifneq (,$(tests.all)) +$(test-list.mjs): $(bin.touint8array) $(tests.all) $(MAKEFILE) + @{\ + echo 'export default ['; \ + sep=''; \ + for f in $(sort $(tests.all)); do \ + echo -en $$sep'{"name": "'$${f##*/}'", "content":'; \ + $(bin.touint8array) < $$f; \ + echo -n '}'; \ + sep=',\n'; \ + done; \ + echo '];'; \ + } > $@ + @echo "Created $@" +$(test-list.mjs.gz): $(test-list.mjs) + gzip -c $< > $@ +CLEAAN_FILES += $(test-list.mjs.gz) +all: $(test-list.mjs.gz) +else + @echo "Cannot build $(test-list.mjs) for lack of input test files."; \ + echo "Symlink ./tests to a directory containing SQLTester-format "; \ + echo "test scripts named *.test, then try again"; \ + exit 1 +endif + +.PHONY: clean distclean +clean: + -rm -f $(CLEAN_FILES) +distclean: clean + -rm -f $(DISTCLEAN_FILES) diff --git a/ext/wasm/SQLTester/SQLTester.mjs b/ext/wasm/SQLTester/SQLTester.mjs index aa02d7a5e..0ec82ca46 100644 --- a/ext/wasm/SQLTester/SQLTester.mjs +++ b/ext/wasm/SQLTester/SQLTester.mjs @@ -9,12 +9,13 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file contains the main application entry pointer for the -** JS implementation of the SQLTester framework. +** This file contains the main application entry pointer for the JS +** implementation of the SQLTester framework. This version is not well +** documented because the one it's a direct port of is documented: +** in the main SQLite3 source tree, see +** ext/jni/src/org/sqlite/jni/tester/SQLite3Tester.java. */ -// UNDER CONSTRUCTION. Still being ported from the Java impl. - import sqlite3ApiInit from '/jswasm/sqlite3.mjs'; const sqlite3 = await sqlite3ApiInit(); @@ -23,6 +24,43 @@ const log = (...args)=>{ console.log('SQLTester:',...args); }; +const tryInstallVfs = function f(vfsName){ + if(f.vfsName) return false; + const pVfs = sqlite3.capi.sqlite3_vfs_find(vfsName); + if(pVfs){ + log("Installing",'"'+vfsName+'"',"as default VFS."); + const rc = sqlite3.capi.sqlite3_vfs_register(pVfs, 1); + if(rc){ + sqlite3.SQLite3Error.toss(rc,"While trying to register",vfsName,"vfs."); + } + f.vfsName = vfsName; + } + return !!pVfs; +}; +tryInstallVfs.vfsName = undefined; + +if( 1 ){ + // Try OPFS storage, if available... + if(sqlite3.installOpfsSAHPoolVfs){ + await sqlite3.installOpfsSAHPoolVfs({ + clearOnInit: true, + initialCapacity: 15, + name: 'opfs-SQLTester' + }).then(pool=>{ + tryInstallVfs(pool.vfsName); + }).catch(e=>{ + log("OpfsSAHPool could not load:",e); + }); + } + if(sqlite3.oo1.OpfsDb){ + tryInstallVfs("opfs"); + } +} + +const wPost = (type,...payload)=>{ + postMessage({type, payload}); +}; + // Return a new enum entry value const newE = ()=>Object.create(null); @@ -215,7 +253,7 @@ class SQLTester { //! Test result buffer. #resultBuffer = []; //! Output representation of SQL NULL. - #nullView = "nil"; + #nullView; metrics = newObj({ //! Total tests run nTotalTest: 0, @@ -245,6 +283,7 @@ class SQLTester { }); constructor(){ + this.reset(); } outln(...args){ return this.#outer.outln(...args); } @@ -261,7 +300,7 @@ class SQLTester { this.#clearBuffer(this.#db.initSql); this.closeAllDbs(); this.metrics.nTest = 0; - this.nullView = "nil"; + this.#nullView = "nil"; this.emitColNames = false; this.#db.iCurrentDb = 0; //this.#db.initSql.push("SELECT 1;"); @@ -424,12 +463,19 @@ class SQLTester { runTests(){ const tStart = (new Date()).getTime(); + let isVerbose = this.verbosity(); for(const ts of this.#aScripts){ this.reset(); ++this.metrics.nTestFile; let threw = false; const timeStart = (new Date()).getTime(); + let msgTail = ''; try{ + if( isVerbose ){ + this.#outer.verbose1("Running ",ts.filename()); + }else{ + msgTail = ' '+ts.filename(); + } ts.run(this); }catch(e){ if(e instanceof SQLTesterException){ @@ -446,7 +492,7 @@ class SQLTester { }finally{ const timeEnd = (new Date()).getTime(); this.outln("🏁", (threw ? "❌" : "✅"), " ", this.metrics.nTest, - " test(s) in ", (timeEnd-timeStart),"ms."); + " test(s) in ", (timeEnd-timeStart),"ms.",msgTail); } } const tEnd = (new Date()).getTime(); @@ -544,7 +590,7 @@ class SQLTester { if(throwOnError){ throw new DbException(self, pDb, rc); }else if( sb ){ - self.#appendDbErr(db, sb, rc); + self.#appendDbErr(pDb, sb, rc); } break; } @@ -666,13 +712,20 @@ class TestScript { if( 2 == args.length ){ filename = args[0]; content = args[1]; - }else{ - content = args[0]; + }else if( 1 == args.length ){ + if(args[0] instanceof Object){ + const o = args[0]; + filename = o.name; + content = o.content; + }else{ + content = args[0]; + } } if(!(content instanceof Uint8Array)){ if('string' === typeof content){ content = Util.utf8Encode(content); - }else if(content instanceof ArrayBuffer){ + }else if((content instanceof ArrayBuffer) + ||(content instanceof Array)){ content = new Uint8Array(content); }else{ toss(Error, "Invalid content type for TestScript constructor."); @@ -686,6 +739,10 @@ class TestScript { return (0==arguments.length) ? this.#testCaseName : (this.#testCaseName = arguments[0]); } + filename(){ + return (0==arguments.length) + ? this.#filename : (this.#filename = arguments[0]); + } getOutputPrefix() { let rc = "["+(this.#moduleName || this.#filename)+"]"; @@ -1041,7 +1098,7 @@ class RunCommand extends Command { ResultRowMode.ONELINE, sql); if( 0!==rc && t.verbosity()>0 ){ const msg = sqlite3.capi.sqlite3_errmsg(pDb); - ts.verbose1(argv[0]," non-fatal command error #",rc,": ", + ts.verbose2(argv[0]," non-fatal command error #",rc,": ", msg,"\nfor SQL:\n",sql); } } diff --git a/ext/wasm/SQLTester/SQLTester.run.mjs b/ext/wasm/SQLTester/SQLTester.run.mjs index e58db9345..e6730253b 100644 --- a/ext/wasm/SQLTester/SQLTester.run.mjs +++ b/ext/wasm/SQLTester/SQLTester.run.mjs @@ -1,4 +1,18 @@ +/* +** 2023-08-29 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains a test application for SQLTester.js. +*/ import {default as ns} from './SQLTester.mjs'; +import {default as tests} from './test-list.mjs'; globalThis.sqlite3 = ns.sqlite3; const log = function f(...args){ @@ -19,16 +33,13 @@ const affirm = function(expr, msg){ } } -console.log("Loaded",ns); - -log("ns =",ns); -outln("SQLTester is ready."); +log("SQLTester is ready."); let ts = new ns.TestScript('/foo.test',` /* ** This is a comment. There are many like it but this one is mine. ** -** SCRIPT_MODULE_NAME: sanity-check +** SCRIPT_MODULE_NAME: sanity-check-0 ** xMIXED_MODULE_NAME: mixed-module ** xMODULE_NAME: module-name ** xREQUIRED_PROPERTIES: small fast reliable @@ -45,10 +56,10 @@ let ts = new ns.TestScript('/foo.test',` --oom --db 0 --new my.db ---null zilch +--null zilchy --testcase 1.0 SELECT 1, null; ---result 1 zilch +--result 1 zilchy --glob *zil* --notglob *ZIL* SELECT 1, 2; @@ -85,20 +96,27 @@ SELECT json_array(1,2,3) const sqt = new ns.SQLTester(); try{ - affirm( !sqt.getCurrentDb(), 'sqt.getCurrentDb()' ); - sqt.openDb('/foo.db', true); - affirm( !!sqt.getCurrentDb(),'sqt.getCurrentDb()' ); - sqt.verbosity(0); - if(false){ - affirm( 'zilch' !== sqt.nullValue() ); - ts.run(sqt); - affirm( 'zilch' === sqt.nullValue() ); + if( 0 ){ + affirm( !sqt.getCurrentDb(), 'sqt.getCurrentDb()' ); + sqt.openDb('/foo.db', true); + affirm( !!sqt.getCurrentDb(),'sqt.getCurrentDb()' ); + sqt.verbosity(0); + if(false){ + affirm( 'zilch' !== sqt.nullValue() ); + ts.run(sqt); + affirm( 'zilch' === sqt.nullValue() ); + } + sqt.addTestScript(ts); + sqt.runTests(); + }else{ + for(const t of tests){ + sqt.addTestScript( new ns.TestScript(t) ); + } + tests.length = 0; + sqt.verbosity(0); + sqt.runTests(); } - sqt.addTestScript(ts); - sqt.runTests(); }finally{ + log( "Metrics:", sqt.metrics ); sqt.reset(); } -log( 'sqt.getCurrentDb()', sqt.getCurrentDb() ); -log( "Metrics:", sqt.metrics ); - diff --git a/ext/wasm/SQLTester/index.html b/ext/wasm/SQLTester/index.html index e782f1367..8ae3e27a3 100644 --- a/ext/wasm/SQLTester/index.html +++ b/ext/wasm/SQLTester/index.html @@ -14,13 +14,14 @@ <p>All stuff on this page happens in the dev console.</p> <hr> <div id='test-output'></div> - <script src='SQLTester.run.mjs' type='module'></script> - <!--script> + <!--script src='SQLTester.run.mjs' type='module'></script--> + <script> (function(){ - const W = new Worker('scratchpad-wasmfs.mjs',{ - type: 'module' - }); + // Noting that Firefox can't do this yet. + const W = new Worker('SQLTester.run.mjs',{ + type: 'module' + }); })(); - </script--> + </script> </body> </html> diff --git a/ext/wasm/SQLTester/touint8array.c b/ext/wasm/SQLTester/touint8array.c new file mode 100644 index 000000000..b03ad42f0 --- /dev/null +++ b/ext/wasm/SQLTester/touint8array.c @@ -0,0 +1,29 @@ +/* +** 2023-08-29 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains a tool for writing out the contents of stdin as +** a comma-separated list of numbers, one per byte. +*/ + +#include <stdio.h> +int main(int argc, char const **argv){ + int i; + int rc = 0, colWidth = 30; + int ch; + printf("["); + for( i=0; EOF!=(ch = fgetc(stdin)); ++i ){ + if( 0!=i ) printf(","); + if( i && 0==(i%colWidth) ) puts(""); + printf("%d",ch); + } + printf("]"); + return rc; +} |