Add initial infrastructure for setting up function/regression tests for the JS/WASM APIs.

FossilOrigin-Name: 7f5db9829b6e60fadb756fea5442da1f4368c8428bb5cdaf14f97f0c3c8451d9
This commit is contained in:
stephan 2022-10-12 15:54:28 +00:00
parent b75971e6e9
commit 402da26c16
5 changed files with 267 additions and 6 deletions

View File

@ -0,0 +1,37 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="../common/emscripten.css"/>
<link rel="stylesheet" href="../common/testing.css"/>
<title>sqlite3 tester #1 (Worker thread)</title>
<style>
body {
font-family: monospace;
}
</style>
</head>
<body>
<h1>sqlite3 WASM/JS tester #1 (Worker thread)</h1>
<script>(function(){
const logHtml = function(cssClass,...args){
const ln = document.createElement('div');
if(cssClass) ln.classList.add(cssClass);
ln.append(document.createTextNode(args.join(' ')));
document.body.append(ln);
};
const w = new Worker("tester1.js");
w.onmessage = function({data}){
switch(data.type){
case 'log':
logHtml(data.payload.cssClass, ...data.payload.args);
break;
default:
logHtml('error',"Unhandled message:",data.type);
};
};
})();</script>
</body>
</html>

21
ext/wasm/tester1.html Normal file
View File

@ -0,0 +1,21 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="../common/emscripten.css"/>
<link rel="stylesheet" href="../common/testing.css"/>
<title>sqlite3 tester #1 (UI thread)</title>
<style>
body {
font-family: monospace;
}
</style>
</head>
<body>
<h1>sqlite3 WASM/JS tester #1 (UI thread)</h1>
<script src="sqlite3.js"></script>
<script src="tester1.js"></script>
</body>
</html>

200
ext/wasm/tester1.js Normal file
View File

@ -0,0 +1,200 @@
/*
2022-10-12
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.
***********************************************************************
Main functional and regression tests for the sqlite3 WASM API.
*/
'use strict';
(function(){
/**
Set up our output channel differently depending
on whether we are running in a worker thread or
the main (UI) thread.
*/
let logHtml;
const isUIThread = ()=>(self.window===self && self.document);
const mapToString = (v)=>{
switch(typeof v){
case 'number': case 'string': case 'boolean':
case 'undefined':
return ''+v;
default: break;
}
if(null===v) return 'null';
return JSON.stringify(v,undefined,2);
};
const normalizeArgs = (args)=>args.map(mapToString);
if( isUIThread() ){
console.log("Running UI thread.");
logHtml = function(cssClass,...args){
const ln = document.createElement('div');
if(cssClass) ln.classList.add(cssClass);
ln.append(document.createTextNode(normalizeArgs(args).join(' ')));
document.body.append(ln);
};
}else{ /* Worker thread */
console.log("Running Worker thread.");
logHtml = function(cssClass,...args){
postMessage({
type:'log',
payload:{cssClass, args: normalizeArgs(args)}
});
};
}
const log = (...args)=>{
//console.log(...args);
logHtml('',...args);
}
const warn = (...args)=>{
console.warn(...args);
logHtml('warning',...args);
}
const error = (...args)=>{
console.error(...args);
logHtml('error',...args);
};
const toss = (...args)=>{
error(...args);
throw new Error(args.join(' '));
};
/**
Helpers for writing sqlite3-specific tests.
*/
const TestUtil = {
/** Running total of the number of tests run via
this API. */
counter: 0,
/**
If expr is a function, it is called and its result
is returned, coerced to a bool, else expr, coerced to
a bool, is returned.
*/
toBool: function(expr){
return (expr instanceof Function) ? !!expr() : !!expr;
},
/** abort() if expr is false. If expr is a function, it
is called and its result is evaluated.
*/
assert: function f(expr, msg){
if(!f._){
f._ = ('undefined'===typeof abort
? (msg)=>{throw new Error(msg)}
: abort);
}
++this.counter;
if(!this.toBool(expr)){
f._(msg || "Assertion failed.");
}
return this;
},
/** Identical to assert() but throws instead of calling
abort(). */
affirm: function(expr, msg){
++this.counter;
if(!this.toBool(expr)) throw new Error(msg || "Affirmation failed.");
return this;
},
/** Calls f() and squelches any exception it throws. If it
does not throw, this function throws. */
mustThrow: function(f, msg){
++this.counter;
let err;
try{ f(); } catch(e){err=e;}
if(!err) throw new Error(msg || "Expected exception.");
return this;
},
/**
Works like mustThrow() but expects filter to be a regex,
function, or string to match/filter the resulting exception
against. If f() does not throw, this test fails and an Error is
thrown. If filter is a regex, the test passes if
filter.test(error.message) passes. If it's a function, the test
passes if filter(error) returns truthy. If it's a string, the
test passes if the filter matches the exception message
precisely. In all other cases the test fails, throwing an
Error.
If it throws, msg is used as the error report unless it's falsy,
in which case a default is used.
*/
mustThrowMatching: function(f, filter, msg){
++this.counter;
let err;
try{ f(); } catch(e){err=e;}
if(!err) throw new Error(msg || "Expected exception.");
let pass = false;
if(filter instanceof RegExp) pass = filter.test(err.message);
else if(filter instanceof Function) pass = filter(err);
else if('string' === typeof filter) pass = (err.message === filter);
if(!pass){
throw new Error(msg || ("Filter rejected this exception: "+err.message));
}
return this;
},
/** Throws if expr is truthy or expr is a function and expr()
returns truthy. */
throwIf: function(expr, msg){
++this.counter;
if(this.toBool(expr)) throw new Error(msg || "throwIf() failed");
return this;
},
/** Throws if expr is falsy or expr is a function and expr()
returns falsy. */
throwUnless: function(expr, msg){
++this.counter;
if(!this.toBool(expr)) throw new Error(msg || "throwUnless() failed");
return this;
},
TestGroup: class {
constructor(name){
this.name = name;
this.tests = [];
}
push(name,callback){
}
}/*TestGroup*/,
testGroups: [],
currentTestGroup: undefined,
addGroup: function(name){
if(this.testGroups[name]){
toss("Test group already exists:",name);
}
this.testGroups.push( this.currentTestGroup = new this.TestGroup(name) );
return this;
},
addTest: function(name, callback){
this.currentTestGroup.push(name, callback);
},
runTests: function(){
toss("TODO: runTests()");
}
}/*TestUtil*/;
log("Loading and initializing sqlite3 WASM module...");
if(!isUIThread()){
importScripts("sqlite3.js");
}
self.sqlite3InitModule({
print: log,
printErr: error
}).then(function(sqlite3){
//console.log('sqlite3 =',sqlite3);
log("Done initializing. Running tests...");
try {
TestUtil.runTests();
}catch(e){
error("Tests failed:",e.message);
}
});
})();

View File

@ -1,5 +1,5 @@
C Minor\sdoc\scleanups\sand\scorrections\sin\ssqlite3-wasm.c
D 2022-10-12T15:40:16.122
C Add\sinitial\sinfrastructure\sfor\ssetting\sup\sfunction/regression\stests\sfor\sthe\sJS/WASM\sAPIs.
D 2022-10-12T15:54:28.657
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -527,6 +527,9 @@ F ext/wasm/sqlite3-worker1-promiser.js 307d7837420ca6a9d3780dfc81194f1c0715637e6
F ext/wasm/sqlite3-worker1.js 466e9bd39409ab03f3e00999887aaffc11e95b416e2689596e3d7f1516673fdf
F ext/wasm/test-opfs-vfs.html eb69dda21eb414b8f5e3f7c1cc0f774103cc9c0f87b2d28a33419e778abfbab5
F ext/wasm/test-opfs-vfs.js 56c3d725044c668fa7910451e96c1195d25ad95825f9ac79f747a7759d1973d0
F ext/wasm/tester1-worker.html 9d24bfc5aec4d81ce00695dea2dbed262eb486f59e3ce75746de9f5b58b128a0
F ext/wasm/tester1.html 13ad0dc087bdd8be1e9a4869d591d0c9915e89c8e191bce7803dc23b45cdd912
F ext/wasm/tester1.js 2f05d90d7c8f519ff6a09bb5a7a1a3ad853aea72c4e51553f2c004446465b179
F ext/wasm/testing-worker1-promiser.html 6eaec6e04a56cf24cf4fa8ef49d78ce8905dde1354235c9125dca6885f7ce893
F ext/wasm/testing-worker1-promiser.js bd788e33c1807e0a6dda9c9a9d784bd3350ca49c9dd8ae2cc8719b506b6e013e
F ext/wasm/testing1.html 50575755e43232dbe4c2f97c9086b3118eb91ec2ee1fae931e6d7669fb17fcae
@ -2029,8 +2032,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 4d8eb90a370054d4482c20637ab56f5e01f4d10215f2af4e35fb9a1f85ecb700
R ec480873b71afa3a4f3e56bd5ade8bb5
P 5144c122a921e4240901cf4eb46347b92213273eec7cf0977952ab2b60722c27
R a82c7637aadf073be20dddba63284e1f
U stephan
Z 751b3d56cb87f4b752682f04e4cf1f99
Z 2f8d1fea1ed0d036410539dd7b357510
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
5144c122a921e4240901cf4eb46347b92213273eec7cf0977952ab2b60722c27
7f5db9829b6e60fadb756fea5442da1f4368c8428bb5cdaf14f97f0c3c8451d9