aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/SQLTester
diff options
context:
space:
mode:
authorstephan <stephan@noemail.net>2023-08-30 00:22:54 +0000
committerstephan <stephan@noemail.net>2023-08-30 00:22:54 +0000
commitac5e1f82ce5e4103bf31882252587f3cbb2a564b (patch)
tree7c267dd8b847cc375a7ab68ec1aaca16e5adcd6f /ext/wasm/SQLTester
parent4f1387e9ab1b5aed8c1c901be23eb02af47854d6 (diff)
downloadsqlite-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/GNUmakefile55
-rw-r--r--ext/wasm/SQLTester/SQLTester.mjs81
-rw-r--r--ext/wasm/SQLTester/SQLTester.run.mjs58
-rw-r--r--ext/wasm/SQLTester/index.html13
-rw-r--r--ext/wasm/SQLTester/touint8array.c29
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;
+}