]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add initial infrastructure for setting up function/regression tests for the JS/WASM...
authorstephan <stephan@noemail.net>
Wed, 12 Oct 2022 15:54:28 +0000 (15:54 +0000)
committerstephan <stephan@noemail.net>
Wed, 12 Oct 2022 15:54:28 +0000 (15:54 +0000)
FossilOrigin-Name: 7f5db9829b6e60fadb756fea5442da1f4368c8428bb5cdaf14f97f0c3c8451d9

ext/wasm/tester1-worker.html [new file with mode: 0644]
ext/wasm/tester1.html [new file with mode: 0644]
ext/wasm/tester1.js [new file with mode: 0644]
manifest
manifest.uuid

diff --git a/ext/wasm/tester1-worker.html b/ext/wasm/tester1-worker.html
new file mode 100644 (file)
index 0000000..32af0f4
--- /dev/null
@@ -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>
diff --git a/ext/wasm/tester1.html b/ext/wasm/tester1.html
new file mode 100644 (file)
index 0000000..cf4217a
--- /dev/null
@@ -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>
diff --git a/ext/wasm/tester1.js b/ext/wasm/tester1.js
new file mode 100644 (file)
index 0000000..d4b6cf7
--- /dev/null
@@ -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);
+    }
+  });
+})();
index 69d43e4bfc5538ceb4853273ac2a2d61da3ca043..a9dd2c89d3ad39b87d04714f2125f976b65ac8fd 100644 (file)
--- 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.
index 4b5abf10972cfdf865cd3546b089072d7d7a9c79..70d7ca7a233ed41abbfdc380aca1ada14e68252a 100644 (file)
@@ -1 +1 @@
-5144c122a921e4240901cf4eb46347b92213273eec7cf0977952ab2b60722c27
\ No newline at end of file
+7f5db9829b6e60fadb756fea5442da1f4368c8428bb5cdaf14f97f0c3c8451d9
\ No newline at end of file