From: stephan Date: Wed, 12 Oct 2022 15:54:28 +0000 (+0000) Subject: Add initial infrastructure for setting up function/regression tests for the JS/WASM... X-Git-Tag: version-3.40.0~169^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=402da26c1624c4ace6c60bd93f9b32d4131a422e;p=thirdparty%2Fsqlite.git Add initial infrastructure for setting up function/regression tests for the JS/WASM APIs. FossilOrigin-Name: 7f5db9829b6e60fadb756fea5442da1f4368c8428bb5cdaf14f97f0c3c8451d9 --- diff --git a/ext/wasm/tester1-worker.html b/ext/wasm/tester1-worker.html new file mode 100644 index 0000000000..32af0f47c9 --- /dev/null +++ b/ext/wasm/tester1-worker.html @@ -0,0 +1,37 @@ + + + + + + + + + sqlite3 tester #1 (Worker thread) + + + +

sqlite3 WASM/JS tester #1 (Worker thread)

+ + + diff --git a/ext/wasm/tester1.html b/ext/wasm/tester1.html new file mode 100644 index 0000000000..cf4217a78b --- /dev/null +++ b/ext/wasm/tester1.html @@ -0,0 +1,21 @@ + + + + + + + + + sqlite3 tester #1 (UI thread) + + + +

sqlite3 WASM/JS tester #1 (UI thread)

+ + + + diff --git a/ext/wasm/tester1.js b/ext/wasm/tester1.js new file mode 100644 index 0000000000..d4b6cf7d1a --- /dev/null +++ b/ext/wasm/tester1.js @@ -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); + } + }); +})(); diff --git a/manifest b/manifest index 69d43e4bfc..a9dd2c89d3 100644 --- a/manifest +++ b/manifest @@ -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. diff --git a/manifest.uuid b/manifest.uuid index 4b5abf1097..70d7ca7a23 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5144c122a921e4240901cf4eb46347b92213273eec7cf0977952ab2b60722c27 \ No newline at end of file +7f5db9829b6e60fadb756fea5442da1f4368c8428bb5cdaf14f97f0c3c8451d9 \ No newline at end of file