--- /dev/null
+/*
+ 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);
+ }
+ });
+})();
-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
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
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.