| /* |
| 2022-05-22 |
| |
| 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 bootstrapping code used by various test scripts |
| which live in this file's directory. |
| */ |
| 'use strict'; |
| (function(self){ |
| /* querySelectorAll() proxy */ |
| const EAll = function(/*[element=document,] cssSelector*/){ |
| return (arguments.length>1 ? arguments[0] : document) |
| .querySelectorAll(arguments[arguments.length-1]); |
| }; |
| /* querySelector() proxy */ |
| const E = function(/*[element=document,] cssSelector*/){ |
| return (arguments.length>1 ? arguments[0] : document) |
| .querySelector(arguments[arguments.length-1]); |
| }; |
| |
| /** |
| Helpers for writing sqlite3-specific tests. |
| */ |
| self.SqliteTestUtil = { |
| /** 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; |
| }, |
| |
| /** |
| Parses window.location.search-style string into an object |
| containing key/value pairs of URL arguments (already |
| urldecoded). The object is created using Object.create(null), |
| so contains only parsed-out properties and has no prototype |
| (and thus no inherited properties). |
| |
| If the str argument is not passed (arguments.length==0) then |
| window.location.search.substring(1) is used by default. If |
| neither str is passed in nor window exists then false is returned. |
| |
| On success it returns an Object containing the key/value pairs |
| parsed from the string. Keys which have no value are treated |
| has having the boolean true value. |
| |
| Pedantic licensing note: this code has appeared in other source |
| trees, but was originally written by the same person who pasted |
| it into those trees. |
| */ |
| processUrlArgs: function(str) { |
| if( 0 === arguments.length ) { |
| if( ('undefined' === typeof window) || |
| !window.location || |
| !window.location.search ) return false; |
| else str = (''+window.location.search).substring(1); |
| } |
| if( ! str ) return false; |
| str = (''+str).split(/#/,2)[0]; // remove #... to avoid it being added as part of the last value. |
| const args = Object.create(null); |
| const sp = str.split(/&+/); |
| const rx = /^([^=]+)(=(.+))?/; |
| var i, m; |
| for( i in sp ) { |
| m = rx.exec( sp[i] ); |
| if( ! m ) continue; |
| args[decodeURIComponent(m[1])] = (m[3] ? decodeURIComponent(m[3]) : true); |
| } |
| return args; |
| } |
| }; |
| |
| /** |
| This is a module object for use with the emscripten-installed |
| sqlite3InitModule() factory function. |
| */ |
| self.sqlite3TestModule = { |
| /** |
| Array of functions to call after Emscripten has initialized the |
| wasm module. Each gets passed the Emscripten module object |
| (which is _this_ object). |
| */ |
| postRun: [ |
| /* function(theModule){...} */ |
| ], |
| //onRuntimeInitialized: function(){}, |
| /* Proxy for C-side stdout output. */ |
| print: (...args)=>{console.log(...args)}, |
| /* Proxy for C-side stderr output. */ |
| printErr: (...args)=>{console.error(...args)}, |
| /** |
| Called by the Emscripten module init bits to report loading |
| progress. It gets passed an empty argument when loading is done |
| (after onRuntimeInitialized() and any this.postRun callbacks |
| have been run). |
| */ |
| setStatus: function f(text){ |
| if(!f.last){ |
| f.last = { text: '', step: 0 }; |
| f.ui = { |
| status: E('#module-status'), |
| progress: E('#module-progress'), |
| spinner: E('#module-spinner') |
| }; |
| } |
| if(text === f.last.text) return; |
| f.last.text = text; |
| if(f.ui.progress){ |
| f.ui.progress.value = f.last.step; |
| f.ui.progress.max = f.last.step + 1; |
| } |
| ++f.last.step; |
| if(text) { |
| f.ui.status.classList.remove('hidden'); |
| f.ui.status.innerText = text; |
| }else{ |
| if(f.ui.progress){ |
| f.ui.progress.remove(); |
| f.ui.spinner.remove(); |
| delete f.ui.progress; |
| delete f.ui.spinner; |
| } |
| f.ui.status.classList.add('hidden'); |
| } |
| }, |
| /** |
| Config options used by the Emscripten-dependent initialization |
| which happens via this.initSqlite3(). This object gets |
| (indirectly) passed to sqlite3ApiBootstrap() to configure the |
| sqlite3 API. |
| */ |
| sqlite3ApiConfig: { |
| wasmfsOpfsDir: "/opfs" |
| }, |
| /** |
| Intended to be called by apps which need to call the |
| Emscripten-installed sqlite3InitModule() routine. This function |
| temporarily installs this.sqlite3ApiConfig into the self |
| object, calls it sqlite3InitModule(), and removes |
| self.sqlite3ApiConfig after initialization is done. Returns the |
| promise from sqlite3InitModule(), and the next then() handler |
| will get the sqlite3 API object as its argument. |
| */ |
| initSqlite3: function(){ |
| self.sqlite3ApiConfig = this.sqlite3ApiConfig; |
| return self.sqlite3InitModule(this).finally(()=>delete self.sqlite3ApiConfig); |
| } |
| }; |
| })(self/*window or worker*/); |