aboutsummaryrefslogtreecommitdiff
path: root/ext/wasm/testing1.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/wasm/testing1.js')
-rw-r--r--ext/wasm/testing1.js1169
1 files changed, 0 insertions, 1169 deletions
diff --git a/ext/wasm/testing1.js b/ext/wasm/testing1.js
deleted file mode 100644
index 6bda58773..000000000
--- a/ext/wasm/testing1.js
+++ /dev/null
@@ -1,1169 +0,0 @@
-/*
- 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.
-
- ***********************************************************************
-
- A basic test script for sqlite3-api.js. This file must be run in
- main JS thread and sqlite3.js must have been loaded before it.
-*/
-'use strict';
-(function(){
- const T = self.SqliteTestUtil;
- const toss = function(...args){throw new Error(args.join(' '))};
- const debug = console.debug.bind(console);
- const eOutput = document.querySelector('#test-output');
- const log = console.log.bind(console),
- warn = console.warn.bind(console);
- const logHtml = function(...args){
- log.apply(this, args);
- const ln = document.createElement('div');
- ln.append(document.createTextNode(args.join(' ')));
- eOutput.append(ln);
- };
-
- const eqApprox = function(v1,v2,factor=0.05){
- //debug('eqApprox',v1, v2);
- return v1>=(v2-factor) && v1<=(v2+factor);
- };
-
- let sqlite3 /* loaded later */;
-
- const testBasicSanity = function(db,sqlite3){
- const capi = sqlite3.capi;
- log("Basic sanity tests...");
- T.assert(Number.isInteger(db.pointer)).
- mustThrowMatching(()=>db.pointer=1, /read-only/).
- assert(0===capi.sqlite3_extended_result_codes(db.pointer,1)).
- assert('main'===db.dbName(0));
- let pId;
- let st = db.prepare(
- new TextEncoder('utf-8').encode("select 3 as a")
- /* Testing handling of Uint8Array input */
- );
- //debug("statement =",st);
- try {
- T.assert(Number.isInteger(st.pointer))
- .mustThrowMatching(()=>st.pointer=1, /read-only/)
- .assert(1===db.openStatementCount())
- .assert(!st._mayGet)
- .assert('a' === st.getColumnName(0))
- .assert(1===st.columnCount)
- .assert(0===st.parameterCount)
- .mustThrow(()=>st.bind(1,null))
- .assert(true===st.step())
- .assert(3 === st.get(0))
- .mustThrow(()=>st.get(1))
- .mustThrow(()=>st.get(0,~capi.SQLITE_INTEGER))
- .assert(3 === st.get(0,capi.SQLITE_INTEGER))
- .assert(3 === st.getInt(0))
- .assert('3' === st.get(0,capi.SQLITE_TEXT))
- .assert('3' === st.getString(0))
- .assert(3.0 === st.get(0,capi.SQLITE_FLOAT))
- .assert(3.0 === st.getFloat(0))
- .assert(3 === st.get({}).a)
- .assert(3 === st.get([])[0])
- .assert(3 === st.getJSON(0))
- .assert(st.get(0,capi.SQLITE_BLOB) instanceof Uint8Array)
- .assert(1===st.get(0,capi.SQLITE_BLOB).length)
- .assert(st.getBlob(0) instanceof Uint8Array)
- .assert('3'.charCodeAt(0) === st.getBlob(0)[0])
- .assert(st._mayGet)
- .assert(false===st.step())
- .assert(!st._mayGet)
- ;
- pId = st.pointer;
- T.assert(0===capi.sqlite3_strglob("*.txt", "foo.txt")).
- assert(0!==capi.sqlite3_strglob("*.txt", "foo.xtx")).
- assert(0===capi.sqlite3_strlike("%.txt", "foo.txt", 0)).
- assert(0!==capi.sqlite3_strlike("%.txt", "foo.xtx", 0));
- }finally{
- st.finalize();
- }
- T.assert(!st.pointer)
- .assert(0===db.openStatementCount());
- let list = [];
- db.exec({
- sql:['CREATE TABLE t(a,b);',
- "INSERT INTO t(a,b) VALUES(1,2),(3,4),",
- "(?,?),('blob',X'6869')"/*intentionally missing semicolon to test for
- off-by-one bug in string-to-WASM conversion*/],
- saveSql: list,
- bind: [5,6]
- });
- //debug("Exec'd SQL:", list);
- T.assert(2 === list.length)
- .assert('string'===typeof list[1])
- .assert(4===db.changes());
- if(capi.wasm.bigIntEnabled){
- T.assert(4n===db.changes(false,true));
- }
- let blob = db.selectValue("select b from t where a='blob'");
- T.assert(blob instanceof Uint8Array).
- assert(0x68===blob[0] && 0x69===blob[1]);
- blob = null;
-
- let counter = 0, colNames = [];
- list.length = 0;
- db.exec(new TextEncoder('utf-8').encode("SELECT a a, b b FROM t"),{
- rowMode: 'object',
- resultRows: list,
- columnNames: colNames,
- callback: function(row,stmt){
- ++counter;
- T.assert((row.a%2 && row.a<6) || 'blob'===row.a);
- }
- });
- T.assert(2 === colNames.length)
- .assert('a' === colNames[0])
- .assert(4 === counter)
- .assert(4 === list.length);
- list.length = 0;
- db.exec("SELECT a a, b b FROM t",{
- rowMode: 'array',
- callback: function(row,stmt){
- ++counter;
- T.assert(Array.isArray(row))
- .assert((0===row[1]%2 && row[1]<7)
- || (row[1] instanceof Uint8Array));
- }
- });
- T.assert(8 === counter);
- T.assert(Number.MIN_SAFE_INTEGER ===
- db.selectValue("SELECT "+Number.MIN_SAFE_INTEGER)).
- assert(Number.MAX_SAFE_INTEGER ===
- db.selectValue("SELECT "+Number.MAX_SAFE_INTEGER));
- if(capi.wasm.bigIntEnabled){
- const mI = capi.wasm.xCall('jaccwabyt_test_int64_max');
- const b = BigInt(Number.MAX_SAFE_INTEGER * 2);
- T.assert(b === db.selectValue("SELECT "+b)).
- assert(b === db.selectValue("SELECT ?", b)).
- assert(mI == db.selectValue("SELECT $x", {$x:mI}));
- }else{
- /* Curiously, the JS spec seems to be off by one with the definitions
- of MIN/MAX_SAFE_INTEGER:
-
- https://github.com/emscripten-core/emscripten/issues/17391 */
- T.mustThrow(()=>db.selectValue("SELECT "+(Number.MAX_SAFE_INTEGER+1))).
- mustThrow(()=>db.selectValue("SELECT "+(Number.MIN_SAFE_INTEGER-1)));
- }
-
- st = db.prepare("update t set b=:b where a='blob'");
- try {
- const ndx = st.getParamIndex(':b');
- T.assert(1===ndx);
- st.bindAsBlob(ndx, "ima blob").reset(true);
- } finally {
- st.finalize();
- }
-
- try {
- throw new sqlite3.WasmAllocError;
- }catch(e){
- T.assert(e instanceof Error)
- .assert(e instanceof sqlite3.WasmAllocError);
- }
-
- try {
- db.prepare("/*empty SQL*/");
- toss("Must not be reached.");
- }catch(e){
- T.assert(e instanceof sqlite3.SQLite3Error)
- .assert(0==e.message.indexOf('Cannot prepare empty'));
- }
-
- T.assert(capi.sqlite3_errstr(capi.SQLITE_IOERR_ACCESS).indexOf("I/O")>=0).
- assert(capi.sqlite3_errstr(capi.SQLITE_CORRUPT).indexOf('malformed')>0).
- assert(capi.sqlite3_errstr(capi.SQLITE_OK) === 'not an error');
-
- // Custom db error message handling via sqlite3_prepare_v2/v3()
- if(capi.wasm.exports.sqlite3_wasm_db_error){
- log("Testing custom error message via prepare_v3()...");
- let rc = capi.sqlite3_prepare_v3(db.pointer, {/*invalid*/}, -1, 0, null, null);
- T.assert(capi.SQLITE_MISUSE === rc)
- .assert(0 === capi.sqlite3_errmsg(db.pointer).indexOf("Invalid SQL"));
- log("errmsg =",capi.sqlite3_errmsg(db.pointer));
- }
- }/*testBasicSanity()*/;
-
- const testUDF = function(db){
- db.createFunction("foo",(pCx,a,b)=>a+b);
- T.assert(7===db.selectValue("select foo(3,4)")).
- assert(5===db.selectValue("select foo(3,?)",2)).
- assert(5===db.selectValue("select foo(?,?2)",[1,4])).
- assert(5===db.selectValue("select foo($a,$b)",{$a:0,$b:5}));
- db.createFunction("bar", {
- arity: -1,
- callback: function(pCx){
- var rc = 0;
- for(let i = 1; i < arguments.length; ++i) rc += arguments[i];
- return rc;
- }
- }).createFunction({
- name: "asis",
- callback: (pCx,arg)=>arg
- });
-
- //log("Testing DB::selectValue() w/ UDF...");
- T.assert(0===db.selectValue("select bar()")).
- assert(1===db.selectValue("select bar(1)")).
- assert(3===db.selectValue("select bar(1,2)")).
- assert(-1===db.selectValue("select bar(1,2,-4)")).
- assert('hi' === db.selectValue("select asis('hi')")).
- assert('hi' === db.selectValue("select ?",'hi')).
- assert(null === db.selectValue("select null")).
- assert(null === db.selectValue("select asis(null)")).
- assert(1 === db.selectValue("select ?",1)).
- assert(2 === db.selectValue("select ?",[2])).
- assert(3 === db.selectValue("select $a",{$a:3})).
- assert(eqApprox(3.1,db.selectValue("select 3.0 + 0.1"))).
- assert(eqApprox(1.3,db.selectValue("select asis(1 + 0.3)")));
-
- //log("Testing binding and UDF propagation of blobs...");
- let blobArg = new Uint8Array(2);
- blobArg.set([0x68, 0x69], 0);
- let blobRc = db.selectValue("select asis(?1)", blobArg);
- T.assert(blobRc instanceof Uint8Array).
- assert(2 === blobRc.length).
- assert(0x68==blobRc[0] && 0x69==blobRc[1]);
- blobRc = db.selectValue("select asis(X'6869')");
- T.assert(blobRc instanceof Uint8Array).
- assert(2 === blobRc.length).
- assert(0x68==blobRc[0] && 0x69==blobRc[1]);
-
- blobArg = new Int8Array(2);
- blobArg.set([0x68, 0x69]);
- //debug("blobArg=",blobArg);
- blobRc = db.selectValue("select asis(?1)", blobArg);
- T.assert(blobRc instanceof Uint8Array).
- assert(2 === blobRc.length);
- //debug("blobRc=",blobRc);
- T.assert(0x68==blobRc[0] && 0x69==blobRc[1]);
- };
-
- const testAttach = function(db){
- const resultRows = [];
- db.exec({
- sql:new TextEncoder('utf-8').encode([
- // ^^^ testing string-vs-typedarray handling in exec()
- "attach 'session' as foo;" /* name 'session' is magic for kvvfs! */,
- "create table foo.bar(a);",
- "insert into foo.bar(a) values(1),(2),(3);",
- "select a from foo.bar order by a;"
- ].join('')),
- rowMode: 0,
- resultRows
- });
- T.assert(3===resultRows.length)
- .assert(2===resultRows[1]);
- T.assert(2===db.selectValue('select a from foo.bar where a>1 order by a'));
- let colCount = 0, rowCount = 0;
- const execCallback = function(pVoid, nCols, aVals, aNames){
- colCount = nCols;
- ++rowCount;
- T.assert(2===aVals.length)
- .assert(2===aNames.length)
- .assert(+(aVals[1]) === 2 * +(aVals[0]));
- };
- const capi = sqlite3.capi;
- let rc = capi.sqlite3_exec(
- db.pointer, "select a, a*2 from foo.bar", execCallback,
- 0, 0
- );
- T.assert(0===rc).assert(3===rowCount).assert(2===colCount);
- rc = capi.sqlite3_exec(
- db.pointer, "select a from foo.bar", ()=>{
- toss("Testing throwing from exec() callback.");
- }, 0, 0
- );
- T.assert(capi.SQLITE_ABORT === rc);
- db.exec("detach foo");
- T.mustThrow(()=>db.exec("select * from foo.bar"));
- };
-
- const testIntPtr = function(db,S){
- const w = S.capi.wasm;
- const stack = w.scopedAllocPush();
- let ptrInt;
- const origValue = 512;
- const ptrValType = 'i32';
- try{
- ptrInt = w.scopedAlloc(4);
- w.setMemValue(ptrInt,origValue, ptrValType);
- const cf = w.xGet('jaccwabyt_test_intptr');
- const oldPtrInt = ptrInt;
- //log('ptrInt',ptrInt);
- //log('getMemValue(ptrInt)',w.getMemValue(ptrInt));
- T.assert(origValue === w.getMemValue(ptrInt, ptrValType));
- const rc = cf(ptrInt);
- //log('cf(ptrInt)',rc);
- //log('ptrInt',ptrInt);
- //log('getMemValue(ptrInt)',w.getMemValue(ptrInt,ptrValType));
- T.assert(2*origValue === rc).
- assert(rc === w.getMemValue(ptrInt,ptrValType)).
- assert(oldPtrInt === ptrInt);
- const pi64 = w.scopedAlloc(8)/*ptr to 64-bit integer*/;
- const o64 = 0x010203040506/*>32-bit integer*/;
- const ptrType64 = 'i64';
- if(w.bigIntEnabled){
- log("BigInt support is enabled...");
- w.setMemValue(pi64, o64, ptrType64);
- //log("pi64 =",pi64, "o64 = 0x",o64.toString(16), o64);
- const v64 = ()=>w.getMemValue(pi64,ptrType64)
- //log("getMemValue(pi64)",v64());
- T.assert(v64() == o64);
- //T.assert(o64 === w.getMemValue(pi64, ptrType64));
- const cf64w = w.xGet('jaccwabyt_test_int64ptr');
- cf64w(pi64);
- //log("getMemValue(pi64)",v64());
- T.assert(v64() == BigInt(2 * o64));
- cf64w(pi64);
- T.assert(v64() == BigInt(4 * o64));
-
- const biTimes2 = w.xGet('jaccwabyt_test_int64_times2');
- T.assert(BigInt(2 * o64) ===
- biTimes2(BigInt(o64)/*explicit conv. required to avoid TypeError
- in the call :/ */));
-
- const pMin = w.scopedAlloc(16);
- const pMax = pMin + 8;
- const g64 = (p)=>w.getMemValue(p,ptrType64);
- w.setMemValue(pMin, 0, ptrType64);
- w.setMemValue(pMax, 0, ptrType64);
- const minMaxI64 = [
- w.xCall('jaccwabyt_test_int64_min'),
- w.xCall('jaccwabyt_test_int64_max')
- ];
- T.assert(minMaxI64[0] < BigInt(Number.MIN_SAFE_INTEGER)).
- assert(minMaxI64[1] > BigInt(Number.MAX_SAFE_INTEGER));
- //log("int64_min/max() =",minMaxI64, typeof minMaxI64[0]);
- w.xCall('jaccwabyt_test_int64_minmax', pMin, pMax);
- T.assert(g64(pMin) === minMaxI64[0], "int64 mismatch").
- assert(g64(pMax) === minMaxI64[1], "int64 mismatch");
- //log("pMin",g64(pMin), "pMax",g64(pMax));
- w.setMemValue(pMin, minMaxI64[0], ptrType64);
- T.assert(g64(pMin) === minMaxI64[0]).
- assert(minMaxI64[0] === db.selectValue("select ?",g64(pMin))).
- assert(minMaxI64[1] === db.selectValue("select ?",g64(pMax)));
- const rxRange = /too big/;
- T.mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[0] - BigInt(1))},
- rxRange).
- mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[1] + BigInt(1))},
- (e)=>rxRange.test(e.message));
- }else{
- log("No BigInt support. Skipping related tests.");
- log("\"The problem\" here is that we can manipulate, at the byte level,",
- "heap memory to set 64-bit values, but we can't get those values",
- "back into JS because of the lack of 64-bit integer support.");
- }
- }finally{
- const x = w.scopedAlloc(1), y = w.scopedAlloc(1), z = w.scopedAlloc(1);
- //log("x=",x,"y=",y,"z=",z); // just looking at the alignment
- w.scopedAllocPop(stack);
- }
- }/*testIntPtr()*/;
-
- const testStructStuff = function(db,S,M){
- const W = S.capi.wasm, C = S;
- /** Maintenance reminder: the rest of this function is copy/pasted
- from the upstream jaccwabyt tests. */
- log("Jaccwabyt tests...");
- const MyStructDef = {
- sizeof: 16,
- members: {
- p4: {offset: 0, sizeof: 4, signature: "i"},
- pP: {offset: 4, sizeof: 4, signature: "P"},
- ro: {offset: 8, sizeof: 4, signature: "i", readOnly: true},
- cstr: {offset: 12, sizeof: 4, signature: "s"}
- }
- };
- if(W.bigIntEnabled){
- const m = MyStructDef;
- m.members.p8 = {offset: m.sizeof, sizeof: 8, signature: "j"};
- m.sizeof += m.members.p8.sizeof;
- }
- const StructType = C.StructBinder.StructType;
- const K = C.StructBinder('my_struct',MyStructDef);
- T.mustThrowMatching(()=>K(), /via 'new'/).
- mustThrowMatching(()=>new K('hi'), /^Invalid pointer/);
- const k1 = new K(), k2 = new K();
- try {
- T.assert(k1.constructor === K).
- assert(K.isA(k1)).
- assert(k1 instanceof K).
- assert(K.prototype.lookupMember('p4').key === '$p4').
- assert(K.prototype.lookupMember('$p4').name === 'p4').
- mustThrowMatching(()=>K.prototype.lookupMember('nope'), /not a mapped/).
- assert(undefined === K.prototype.lookupMember('nope',false)).
- assert(k1 instanceof StructType).
- assert(StructType.isA(k1)).
- assert(K.resolveToInstance(k1.pointer)===k1).
- mustThrowMatching(()=>K.resolveToInstance(null,true), /is-not-a my_struct/).
- assert(k1 === StructType.instanceForPointer(k1.pointer)).
- mustThrowMatching(()=>k1.$ro = 1, /read-only/);
- Object.keys(MyStructDef.members).forEach(function(key){
- key = K.memberKey(key);
- T.assert(0 == k1[key],
- "Expecting allocation to zero the memory "+
- "for "+key+" but got: "+k1[key]+
- " from "+k1.memoryDump());
- });
- T.assert('number' === typeof k1.pointer).
- mustThrowMatching(()=>k1.pointer = 1, /pointer/).
- assert(K.instanceForPointer(k1.pointer) === k1);
- k1.$p4 = 1; k1.$pP = 2;
- T.assert(1 === k1.$p4).assert(2 === k1.$pP);
- if(MyStructDef.members.$p8){
- k1.$p8 = 1/*must not throw despite not being a BigInt*/;
- k1.$p8 = BigInt(Number.MAX_SAFE_INTEGER * 2);
- T.assert(BigInt(2 * Number.MAX_SAFE_INTEGER) === k1.$p8);
- }
- T.assert(!k1.ondispose);
- k1.setMemberCString('cstr', "A C-string.");
- T.assert(Array.isArray(k1.ondispose)).
- assert(k1.ondispose[0] === k1.$cstr).
- assert('number' === typeof k1.$cstr).
- assert('A C-string.' === k1.memberToJsString('cstr'));
- k1.$pP = k2;
- T.assert(k1.$pP === k2);
- k1.$pP = null/*null is special-cased to 0.*/;
- T.assert(0===k1.$pP);
- let ptr = k1.pointer;
- k1.dispose();
- T.assert(undefined === k1.pointer).
- assert(undefined === K.instanceForPointer(ptr)).
- mustThrowMatching(()=>{k1.$pP=1}, /disposed instance/);
- const k3 = new K();
- ptr = k3.pointer;
- T.assert(k3 === K.instanceForPointer(ptr));
- K.disposeAll();
- T.assert(ptr).
- assert(undefined === k2.pointer).
- assert(undefined === k3.pointer).
- assert(undefined === K.instanceForPointer(ptr));
- }finally{
- k1.dispose();
- k2.dispose();
- }
-
- if(!W.bigIntEnabled){
- log("Skipping WasmTestStruct tests: BigInt not enabled.");
- return;
- }
-
- const ctype = W.xCallWrapped('jaccwabyt_test_ctype_json', 'json');
- log("Struct descriptions:",ctype.structs);
- const WTStructDesc =
- ctype.structs.filter((e)=>'WasmTestStruct'===e.name)[0];
- const autoResolvePtr = true /* EXPERIMENTAL */;
- if(autoResolvePtr){
- WTStructDesc.members.ppV.signature = 'P';
- }
- const WTStruct = C.StructBinder(WTStructDesc);
- log(WTStruct.structName, WTStruct.structInfo);
- const wts = new WTStruct();
- log("WTStruct.prototype keys:",Object.keys(WTStruct.prototype));
- try{
- T.assert(wts.constructor === WTStruct).
- assert(WTStruct.memberKeys().indexOf('$ppV')>=0).
- assert(wts.memberKeys().indexOf('$v8')>=0).
- assert(!K.isA(wts)).
- assert(WTStruct.isA(wts)).
- assert(wts instanceof WTStruct).
- assert(wts instanceof StructType).
- assert(StructType.isA(wts)).
- assert(wts === StructType.instanceForPointer(wts.pointer));
- T.assert(wts.pointer>0).assert(0===wts.$v4).assert(0n===wts.$v8).
- assert(0===wts.$ppV).assert(0===wts.$xFunc).
- assert(WTStruct.instanceForPointer(wts.pointer) === wts);
- const testFunc =
- W.xGet('jaccwabyt_test_struct'/*name gets mangled in -O3 builds!*/);
- let counter = 0;
- log("wts.pointer =",wts.pointer);
- const wtsFunc = function(arg){
- log("This from a JS function called from C, "+
- "which itself was called from JS. arg =",arg);
- ++counter;
- T.assert(WTStruct.instanceForPointer(arg) === wts);
- if(3===counter){
- toss("Testing exception propagation.");
- }
- }
- wts.$v4 = 10; wts.$v8 = 20;
- wts.$xFunc = W.installFunction(wtsFunc, wts.memberSignature('xFunc'))
- /* ^^^ compiles wtsFunc to WASM and returns its new function pointer */;
- T.assert(0===counter).assert(10 === wts.$v4).assert(20n === wts.$v8)
- .assert(0 === wts.$ppV).assert('number' === typeof wts.$xFunc)
- .assert(0 === wts.$cstr)
- .assert(wts.memberIsString('$cstr'))
- .assert(!wts.memberIsString('$v4'))
- .assert(null === wts.memberToJsString('$cstr'))
- .assert(W.functionEntry(wts.$xFunc) instanceof Function);
- /* It might seem silly to assert that the values match
- what we just set, but recall that all of those property
- reads and writes are, via property interceptors,
- actually marshaling their data to/from a raw memory
- buffer, so merely reading them back is actually part of
- testing the struct-wrapping API. */
-
- testFunc(wts.pointer);
- log("wts.pointer, wts.$ppV",wts.pointer, wts.$ppV);
- T.assert(1===counter).assert(20 === wts.$v4).assert(40n === wts.$v8)
- .assert(autoResolvePtr ? (wts.$ppV === wts) : (wts.$ppV === wts.pointer))
- .assert('string' === typeof wts.memberToJsString('cstr'))
- .assert(wts.memberToJsString('cstr') === wts.memberToJsString('$cstr'))
- .mustThrowMatching(()=>wts.memberToJsString('xFunc'),
- /Invalid member type signature for C-string/)
- ;
- testFunc(wts.pointer);
- T.assert(2===counter).assert(40 === wts.$v4).assert(80n === wts.$v8)
- .assert(autoResolvePtr ? (wts.$ppV === wts) : (wts.$ppV === wts.pointer));
- /** The 3rd call to wtsFunc throw from JS, which is called
- from C, which is called from JS. Let's ensure that
- that exception propagates back here... */
- T.mustThrowMatching(()=>testFunc(wts.pointer),/^Testing/);
- W.uninstallFunction(wts.$xFunc);
- wts.$xFunc = 0;
- if(autoResolvePtr){
- wts.$ppV = 0;
- T.assert(!wts.$ppV);
- WTStruct.debugFlags(0x03);
- wts.$ppV = wts;
- T.assert(wts === wts.$ppV)
- WTStruct.debugFlags(0);
- }
- wts.setMemberCString('cstr', "A C-string.");
- T.assert(Array.isArray(wts.ondispose)).
- assert(wts.ondispose[0] === wts.$cstr).
- assert('A C-string.' === wts.memberToJsString('cstr'));
- const ptr = wts.pointer;
- wts.dispose();
- T.assert(ptr).assert(undefined === wts.pointer).
- assert(undefined === WTStruct.instanceForPointer(ptr))
- }finally{
- wts.dispose();
- }
- }/*testStructStuff()*/;
-
- const testSqliteStructs = function(db,sqlite3,M){
- log("Tinkering with sqlite3_io_methods...");
- // https://www.sqlite.org/c3ref/vfs.html
- // https://www.sqlite.org/c3ref/io_methods.html
- const capi = sqlite3.capi, W = capi.wasm;
- const sqlite3_io_methods = capi.sqlite3_io_methods,
- sqlite3_vfs = capi.sqlite3_vfs,
- sqlite3_file = capi.sqlite3_file;
- log("struct sqlite3_file", sqlite3_file.memberKeys());
- log("struct sqlite3_vfs", sqlite3_vfs.memberKeys());
- log("struct sqlite3_io_methods", sqlite3_io_methods.memberKeys());
-
- const installMethod = function callee(tgt, name, func){
- if(1===arguments.length){
- return (n,f)=>callee(tgt,n,f);
- }
- if(!callee.argcProxy){
- callee.argcProxy = function(func,sig){
- return function(...args){
- if(func.length!==arguments.length){
- toss("Argument mismatch. Native signature is:",sig);
- }
- return func.apply(this, args);
- }
- };
- callee.ondisposeRemoveFunc = function(){
- if(this.__ondispose){
- const who = this;
- this.__ondispose.forEach(
- (v)=>{
- if('number'===typeof v){
- try{capi.wasm.uninstallFunction(v)}
- catch(e){/*ignore*/}
- }else{/*wasm function wrapper property*/
- delete who[v];
- }
- }
- );
- delete this.__ondispose;
- }
- };
- }/*static init*/
- const sigN = tgt.memberSignature(name),
- memKey = tgt.memberKey(name);
- //log("installMethod",tgt, name, sigN);
- if(!tgt.__ondispose){
- T.assert(undefined === tgt.ondispose);
- tgt.ondispose = [callee.ondisposeRemoveFunc];
- tgt.__ondispose = [];
- }
- const fProxy = callee.argcProxy(func, sigN);
- const pFunc = capi.wasm.installFunction(fProxy, tgt.memberSignature(name, true));
- tgt[memKey] = pFunc;
- /**
- ACHTUNG: function pointer IDs are from a different pool than
- allocation IDs, starting at 1 and incrementing in steps of 1,
- so if we set tgt[memKey] to those values, we'd very likely
- later misinterpret them as plain old pointer addresses unless
- unless we use some silly heuristic like "all values <5k are
- presumably function pointers," or actually perform a function
- lookup on every pointer to first see if it's a function. That
- would likely work just fine, but would be kludgy.
-
- It turns out that "all values less than X are functions" is
- essentially how it works in wasm: a function pointer is
- reported to the client as its index into the
- __indirect_function_table.
-
- So... once jaccwabyt can be told how to access the
- function table, it could consider all pointer values less
- than that table's size to be functions. As "real" pointer
- values start much, much higher than the function table size,
- that would likely work reasonably well. e.g. the object
- pointer address for sqlite3's default VFS is (in this local
- setup) 65104, whereas the function table has fewer than 600
- entries.
- */
- const wrapperKey = '$'+memKey;
- tgt[wrapperKey] = fProxy;
- tgt.__ondispose.push(pFunc, wrapperKey);
- //log("tgt.__ondispose =",tgt.__ondispose);
- return (n,f)=>callee(tgt, n, f);
- }/*installMethod*/;
-
- const installIOMethods = function instm(iom){
- (iom instanceof capi.sqlite3_io_methods) || toss("Invalid argument type.");
- if(!instm._requireFileArg){
- instm._requireFileArg = function(arg,methodName){
- arg = capi.sqlite3_file.resolveToInstance(arg);
- if(!arg){
- err("sqlite3_io_methods::xClose() was passed a non-sqlite3_file.");
- }
- return arg;
- };
- instm._methods = {
- // https://sqlite.org/c3ref/io_methods.html
- xClose: /*i(P)*/function(f){
- /* int (*xClose)(sqlite3_file*) */
- log("xClose(",f,")");
- if(!(f = instm._requireFileArg(f,'xClose'))) return capi.SQLITE_MISUSE;
- f.dispose(/*noting that f has externally-owned memory*/);
- return 0;
- },
- xRead: /*i(Ppij)*/function(f,dest,n,offset){
- /* int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst) */
- log("xRead(",arguments,")");
- if(!(f = instm._requireFileArg(f))) return capi.SQLITE_MISUSE;
- capi.wasm.heap8().fill(0, dest + offset, n);
- return 0;
- },
- xWrite: /*i(Ppij)*/function(f,dest,n,offset){
- /* int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst) */
- log("xWrite(",arguments,")");
- if(!(f=instm._requireFileArg(f,'xWrite'))) return capi.SQLITE_MISUSE;
- return 0;
- },
- xTruncate: /*i(Pj)*/function(f){
- /* int (*xTruncate)(sqlite3_file*, sqlite3_int64 size) */
- log("xTruncate(",arguments,")");
- if(!(f=instm._requireFileArg(f,'xTruncate'))) return capi.SQLITE_MISUSE;
- return 0;
- },
- xSync: /*i(Pi)*/function(f){
- /* int (*xSync)(sqlite3_file*, int flags) */
- log("xSync(",arguments,")");
- if(!(f=instm._requireFileArg(f,'xSync'))) return capi.SQLITE_MISUSE;
- return 0;
- },
- xFileSize: /*i(Pp)*/function(f,pSz){
- /* int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize) */
- log("xFileSize(",arguments,")");
- if(!(f=instm._requireFileArg(f,'xFileSize'))) return capi.SQLITE_MISUSE;
- capi.wasm.setMemValue(pSz, 0/*file size*/);
- return 0;
- },
- xLock: /*i(Pi)*/function(f){
- /* int (*xLock)(sqlite3_file*, int) */
- log("xLock(",arguments,")");
- if(!(f=instm._requireFileArg(f,'xLock'))) return capi.SQLITE_MISUSE;
- return 0;
- },
- xUnlock: /*i(Pi)*/function(f){
- /* int (*xUnlock)(sqlite3_file*, int) */
- log("xUnlock(",arguments,")");
- if(!(f=instm._requireFileArg(f,'xUnlock'))) return capi.SQLITE_MISUSE;
- return 0;
- },
- xCheckReservedLock: /*i(Pp)*/function(){
- /* int (*xCheckReservedLock)(sqlite3_file*, int *pResOut) */
- log("xCheckReservedLock(",arguments,")");
- return 0;
- },
- xFileControl: /*i(Pip)*/function(){
- /* int (*xFileControl)(sqlite3_file*, int op, void *pArg) */
- log("xFileControl(",arguments,")");
- return capi.SQLITE_NOTFOUND;
- },
- xSectorSize: /*i(P)*/function(){
- /* int (*xSectorSize)(sqlite3_file*) */
- log("xSectorSize(",arguments,")");
- return 0/*???*/;
- },
- xDeviceCharacteristics:/*i(P)*/function(){
- /* int (*xDeviceCharacteristics)(sqlite3_file*) */
- log("xDeviceCharacteristics(",arguments,")");
- return 0;
- }
- };
- }/*static init*/
- iom.$iVersion = 1;
- Object.keys(instm._methods).forEach(
- (k)=>installMethod(iom, k, instm._methods[k])
- );
- }/*installIOMethods()*/;
-
- const iom = new sqlite3_io_methods, sfile = new sqlite3_file;
- const err = console.error.bind(console);
- try {
- const IOM = sqlite3_io_methods, S3F = sqlite3_file;
- //log("iom proto",iom,iom.constructor.prototype);
- //log("sfile",sfile,sfile.constructor.prototype);
- T.assert(0===sfile.$pMethods).assert(iom.pointer > 0);
- //log("iom",iom);
- sfile.$pMethods = iom.pointer;
- T.assert(iom.pointer === sfile.$pMethods)
- .assert(IOM.resolveToInstance(iom))
- .assert(undefined ===IOM.resolveToInstance(sfile))
- .mustThrow(()=>IOM.resolveToInstance(0,true))
- .assert(S3F.resolveToInstance(sfile.pointer))
- .assert(undefined===S3F.resolveToInstance(iom))
- .assert(iom===IOM.resolveToInstance(sfile.$pMethods));
- T.assert(0===iom.$iVersion);
- installIOMethods(iom);
- T.assert(1===iom.$iVersion);
- //log("iom.__ondispose",iom.__ondispose);
- T.assert(Array.isArray(iom.__ondispose)).assert(iom.__ondispose.length>10);
- }finally{
- iom.dispose();
- T.assert(undefined === iom.__ondispose);
- }
-
- const dVfs = new sqlite3_vfs(capi.sqlite3_vfs_find(null));
- try {
- const SB = sqlite3.StructBinder;
- T.assert(dVfs instanceof SB.StructType)
- .assert(dVfs.pointer)
- .assert('sqlite3_vfs' === dVfs.structName)
- .assert(!!dVfs.structInfo)
- .assert(SB.StructType.hasExternalPointer(dVfs))
- .assert(dVfs.$iVersion>0)
- .assert('number'===typeof dVfs.$zName)
- .assert('number'===typeof dVfs.$xSleep)
- .assert(capi.wasm.functionEntry(dVfs.$xOpen))
- .assert(dVfs.memberIsString('zName'))
- .assert(dVfs.memberIsString('$zName'))
- .assert(!dVfs.memberIsString('pAppData'))
- .mustThrowMatching(()=>dVfs.memberToJsString('xSleep'),
- /Invalid member type signature for C-string/)
- .mustThrowMatching(()=>dVfs.memberSignature('nope'), /nope is not a mapped/)
- .assert('string' === typeof dVfs.memberToJsString('zName'))
- .assert(dVfs.memberToJsString('zName')===dVfs.memberToJsString('$zName'))
- ;
- log("Default VFS: @",dVfs.pointer);
- Object.keys(sqlite3_vfs.structInfo.members).forEach(function(mname){
- const mk = sqlite3_vfs.memberKey(mname), mbr = sqlite3_vfs.structInfo.members[mname],
- addr = dVfs[mk], prefix = 'defaultVfs.'+mname;
- if(1===mbr.signature.length){
- let sep = '?', val = undefined;
- switch(mbr.signature[0]){
- // TODO: move this into an accessor, e.g. getPreferredValue(member)
- case 'i': case 'j': case 'f': case 'd': sep = '='; val = dVfs[mk]; break
- case 'p': case 'P': sep = '@'; val = dVfs[mk]; break;
- case 's': sep = '=';
- //val = capi.wasm.UTF8ToString(addr);
- val = dVfs.memberToJsString(mname);
- break;
- }
- log(prefix, sep, val);
- }
- else{
- log(prefix," = funcptr @",addr, capi.wasm.functionEntry(addr));
- }
- });
- }finally{
- dVfs.dispose();
- T.assert(undefined===dVfs.pointer);
- }
- }/*testSqliteStructs()*/;
-
- const testWasmUtil = function(DB,S){
- const w = S.capi.wasm;
- /**
- Maintenance reminder: the rest of this function is part of the
- upstream Jaccwabyt tree.
- */
- const chr = (x)=>x.charCodeAt(0);
- log("heap getters...");
- {
- const li = [8, 16, 32];
- if(w.bigIntEnabled) li.push(64);
- for(const n of li){
- const bpe = n/8;
- const s = w.heapForSize(n,false);
- T.assert(bpe===s.BYTES_PER_ELEMENT).
- assert(w.heapForSize(s.constructor) === s);
- const u = w.heapForSize(n,true);
- T.assert(bpe===u.BYTES_PER_ELEMENT).
- assert(s!==u).
- assert(w.heapForSize(u.constructor) === u);
- }
- }
-
- log("jstrlen()...");
- {
- T.assert(3 === w.jstrlen("abc")).assert(4 === w.jstrlen("äbc"));
- }
-
- log("jstrcpy()...");
- {
- const fillChar = 10;
- let ua = new Uint8Array(8), rc,
- refill = ()=>ua.fill(fillChar);
- refill();
- rc = w.jstrcpy("hello", ua);
- T.assert(6===rc).assert(0===ua[5]).assert(chr('o')===ua[4]);
- refill();
- ua[5] = chr('!');
- rc = w.jstrcpy("HELLO", ua, 0, -1, false);
- T.assert(5===rc).assert(chr('!')===ua[5]).assert(chr('O')===ua[4]);
- refill();
- rc = w.jstrcpy("the end", ua, 4);
- //log("rc,ua",rc,ua);
- T.assert(4===rc).assert(0===ua[7]).
- assert(chr('e')===ua[6]).assert(chr('t')===ua[4]);
- refill();
- rc = w.jstrcpy("the end", ua, 4, -1, false);
- T.assert(4===rc).assert(chr(' ')===ua[7]).
- assert(chr('e')===ua[6]).assert(chr('t')===ua[4]);
- refill();
- rc = w.jstrcpy("", ua, 0, 1, true);
- //log("rc,ua",rc,ua);
- T.assert(1===rc).assert(0===ua[0]);
- refill();
- rc = w.jstrcpy("x", ua, 0, 1, true);
- //log("rc,ua",rc,ua);
- T.assert(1===rc).assert(0===ua[0]);
- refill();
- rc = w.jstrcpy('äbä', ua, 0, 1, true);
- T.assert(1===rc, 'Must not write partial multi-byte char.')
- .assert(0===ua[0]);
- refill();
- rc = w.jstrcpy('äbä', ua, 0, 2, true);
- T.assert(1===rc, 'Must not write partial multi-byte char.')
- .assert(0===ua[0]);
- refill();
- rc = w.jstrcpy('äbä', ua, 0, 2, false);
- T.assert(2===rc).assert(fillChar!==ua[1]).assert(fillChar===ua[2]);
- }/*jstrcpy()*/
-
- log("cstrncpy()...");
- {
- const scope = w.scopedAllocPush();
- try {
- let cStr = w.scopedAllocCString("hello");
- const n = w.cstrlen(cStr);
- let cpy = w.scopedAlloc(n+10);
- let rc = w.cstrncpy(cpy, cStr, n+10);
- T.assert(n+1 === rc).
- assert("hello" === w.cstringToJs(cpy)).
- assert(chr('o') === w.getMemValue(cpy+n-1)).
- assert(0 === w.getMemValue(cpy+n));
- let cStr2 = w.scopedAllocCString("HI!!!");
- rc = w.cstrncpy(cpy, cStr2, 3);
- T.assert(3===rc).
- assert("HI!lo" === w.cstringToJs(cpy)).
- assert(chr('!') === w.getMemValue(cpy+2)).
- assert(chr('l') === w.getMemValue(cpy+3));
- }finally{
- w.scopedAllocPop(scope);
- }
- }
-
- log("jstrToUintArray()...");
- {
- let a = w.jstrToUintArray("hello", false);
- T.assert(5===a.byteLength).assert(chr('o')===a[4]);
- a = w.jstrToUintArray("hello", true);
- T.assert(6===a.byteLength).assert(chr('o')===a[4]).assert(0===a[5]);
- a = w.jstrToUintArray("äbä", false);
- T.assert(5===a.byteLength).assert(chr('b')===a[2]);
- a = w.jstrToUintArray("äbä", true);
- T.assert(6===a.byteLength).assert(chr('b')===a[2]).assert(0===a[5]);
- }
-
- log("allocCString()...");
- {
- const cstr = w.allocCString("hällo, world");
- const n = w.cstrlen(cstr);
- T.assert(13 === n)
- .assert(0===w.getMemValue(cstr+n))
- .assert(chr('d')===w.getMemValue(cstr+n-1));
- }
-
- log("scopedAlloc() and friends...");
- {
- const alloc = w.alloc, dealloc = w.dealloc;
- w.alloc = w.dealloc = null;
- T.assert(!w.scopedAlloc.level)
- .mustThrowMatching(()=>w.scopedAlloc(1), /^No scopedAllocPush/)
- .mustThrowMatching(()=>w.scopedAllocPush(), /missing alloc/);
- w.alloc = alloc;
- T.mustThrowMatching(()=>w.scopedAllocPush(), /missing alloc/);
- w.dealloc = dealloc;
- T.mustThrowMatching(()=>w.scopedAllocPop(), /^Invalid state/)
- .mustThrowMatching(()=>w.scopedAlloc(1), /^No scopedAllocPush/)
- .mustThrowMatching(()=>w.scopedAlloc.level=0, /read-only/);
- const asc = w.scopedAllocPush();
- let asc2;
- try {
- const p1 = w.scopedAlloc(16),
- p2 = w.scopedAlloc(16);
- T.assert(1===w.scopedAlloc.level)
- .assert(Number.isFinite(p1))
- .assert(Number.isFinite(p2))
- .assert(asc[0] === p1)
- .assert(asc[1]===p2);
- asc2 = w.scopedAllocPush();
- const p3 = w.scopedAlloc(16);
- T.assert(2===w.scopedAlloc.level)
- .assert(Number.isFinite(p3))
- .assert(2===asc.length)
- .assert(p3===asc2[0]);
-
- const [z1, z2, z3] = w.scopedAllocPtr(3);
- T.assert('number'===typeof z1).assert(z2>z1).assert(z3>z2)
- .assert(0===w.getMemValue(z1,'i32'), 'allocPtr() must zero the targets')
- .assert(0===w.getMemValue(z3,'i32'));
- }finally{
- // Pop them in "incorrect" order to make sure they behave:
- w.scopedAllocPop(asc);
- T.assert(0===asc.length);
- T.mustThrowMatching(()=>w.scopedAllocPop(asc),
- /^Invalid state object/);
- if(asc2){
- T.assert(2===asc2.length,'Should be p3 and z1');
- w.scopedAllocPop(asc2);
- T.assert(0===asc2.length);
- T.mustThrowMatching(()=>w.scopedAllocPop(asc2),
- /^Invalid state object/);
- }
- }
- T.assert(0===w.scopedAlloc.level);
- w.scopedAllocCall(function(){
- T.assert(1===w.scopedAlloc.level);
- const [cstr, n] = w.scopedAllocCString("hello, world", true);
- T.assert(12 === n)
- .assert(0===w.getMemValue(cstr+n))
- .assert(chr('d')===w.getMemValue(cstr+n-1));
- });
- }/*scopedAlloc()*/
-
- log("xCall()...");
- {
- const pJson = w.xCall('jaccwabyt_test_ctype_json');
- T.assert(Number.isFinite(pJson)).assert(w.cstrlen(pJson)>300);
- }
-
- log("xWrap()...");
- {
- //int jaccwabyt_test_intptr(int * p);
- //int64_t jaccwabyt_test_int64_max(void)
- //int64_t jaccwabyt_test_int64_min(void)
- //int64_t jaccwabyt_test_int64_times2(int64_t x)
- //void jaccwabyt_test_int64_minmax(int64_t * min, int64_t *max)
- //int64_t jaccwabyt_test_int64ptr(int64_t * p)
- //const char * jaccwabyt_test_ctype_json(void)
- T.mustThrowMatching(()=>w.xWrap('jaccwabyt_test_ctype_json',null,'i32'),
- /requires 0 arg/).
- assert(w.xWrap.resultAdapter('i32') instanceof Function).
- assert(w.xWrap.argAdapter('i32') instanceof Function);
- let fw = w.xWrap('jaccwabyt_test_ctype_json','string');
- T.mustThrowMatching(()=>fw(1), /requires 0 arg/);
- let rc = fw();
- T.assert('string'===typeof rc).assert(rc.length>300);
- rc = w.xCallWrapped('jaccwabyt_test_ctype_json','*');
- T.assert(rc>0 && Number.isFinite(rc));
- rc = w.xCallWrapped('jaccwabyt_test_ctype_json','string');
- T.assert('string'===typeof rc).assert(rc.length>300);
- fw = w.xWrap('jaccwabyt_test_str_hello', 'string:free',['i32']);
- rc = fw(0);
- T.assert('hello'===rc);
- rc = fw(1);
- T.assert(null===rc);
-
- w.xWrap.resultAdapter('thrice', (v)=>3n*BigInt(v));
- w.xWrap.argAdapter('twice', (v)=>2n*BigInt(v));
- fw = w.xWrap('jaccwabyt_test_int64_times2','thrice','twice');
- rc = fw(1);
- T.assert(12n===rc);
-
- w.scopedAllocCall(function(){
- let pI1 = w.scopedAlloc(8), pI2 = pI1+4;
- w.setMemValue(pI1, 0,'*')(pI2, 0, '*');
- let f = w.xWrap('jaccwabyt_test_int64_minmax',undefined,['i64*','i64*']);
- let r1 = w.getMemValue(pI1, 'i64'), r2 = w.getMemValue(pI2, 'i64');
- T.assert(!Number.isSafeInteger(r1)).assert(!Number.isSafeInteger(r2));
- });
- }
- }/*testWasmUtil()*/;
-
-
- /**
- Tests for sqlite3.capi.wasm.pstack().
- */
- const testPstack = function(db,sqlite3){
- const w = sqlite3.capi.wasm, P = w.pstack;
- const isAllocErr = (e)=>e instanceof sqlite3.WasmAllocError;
- const stack = P.pointer;
- T.assert(0===stack % 8 /* must be 8-byte aligned */);
- try{
- const remaining = P.remaining;
- log("pstack quota, remaining",P.quota,remaining);
- T.assert(P.quota >= 4096)
- .assert(remaining === P.quota)
- .mustThrowMatching(()=>P.alloc(0), isAllocErr)
- .mustThrowMatching(()=>P.alloc(-1), isAllocErr);
- let p1 = P.alloc(12);
- T.assert(p1 === stack - 16/*8-byte aligned*/)
- .assert(P.pointer === p1);
- let p2 = P.alloc(7);
- T.assert(p2 === p1-8/*8-byte aligned, stack grows downwards*/)
- .mustThrowMatching(()=>P.alloc(remaining), isAllocErr)
- .assert(24 === stack - p2)
- .assert(P.pointer === p2);
- let n = remaining - (stack - p2);
- let p3 = P.alloc(n);
- T.assert(p3 === stack-remaining)
- .mustThrowMatching(()=>P.alloc(1), isAllocErr);
- }finally{
- P.restore(stack);
- }
-
- T.assert(P.pointer === stack);
- try {
- const [p1, p2, p3] = P.allocChunks(3,4);
- T.assert(P.pointer === stack-16/*always rounded to multiple of 8*/)
- .assert(p2 === p1 + 4)
- .assert(p3 === p2 + 4);
- T.mustThrowMatching(()=>P.allocChunks(1024, 1024 * 16),
- (e)=>e instanceof sqlite3.WasmAllocError)
- }finally{
- P.restore(stack);
- }
-
- T.assert(P.pointer === stack);
- try {
- let [p1, p2, p3] = P.allocPtr(3,false);
- let sPos = stack-16/*always rounded to multiple of 8*/;
- T.assert(P.pointer === sPos)
- .assert(p2 === p1 + 4)
- .assert(p3 === p2 + 4);
- [p1, p2, p3] = P.allocPtr(3);
- T.assert(P.pointer === sPos-24/*3 x 8 bytes*/)
- .assert(p2 === p1 + 8)
- .assert(p3 === p2 + 8);
- p1 = P.allocPtr();
- T.assert('number'===typeof p1);
- }finally{
- P.restore(stack);
- }
- }/*testPstack()*/;
-
- const clearKvvfs = function(){
- const sz = sqlite3.capi.sqlite3_web_kvvfs_size();
- const n = sqlite3.capi.sqlite3_web_kvvfs_clear('');
- log("Cleared kvvfs local/sessionStorage:",
- n,"entries totaling approximately",sz,"bytes.");
- };
-
- const runTests = function(_sqlite3){
- sqlite3 = _sqlite3;
- const capi = sqlite3.capi,
- oo = sqlite3.oo1,
- wasm = capi.wasm;
- log("Loaded module:",capi.sqlite3_libversion(), capi.sqlite3_sourceid());
- log("Build options:",wasm.compileOptionUsed());
- capi.sqlite3_wasmfs_opfs_dir()/*will install OPFS if available, plus a and non-locking VFS*/;
- if(1){
- /* Let's grab those last few lines of test coverage for
- sqlite3-api.js... */
- const rc = wasm.compileOptionUsed(['COMPILER']);
- T.assert(1 === rc.COMPILER);
- const obj = {COMPILER:undefined};
- wasm.compileOptionUsed(obj);
- T.assert(1 === obj.COMPILER);
- }
- log("WASM heap size =",wasm.heap8().length);
- //log("capi.wasm.exports.__indirect_function_table",capi.wasm.exports.__indirect_function_table);
-
- const wasmCtypes = wasm.ctype;
- //log("wasmCtypes",wasmCtypes);
- T.assert(wasmCtypes.structs[0].name==='sqlite3_vfs').
- assert(wasmCtypes.structs[0].members.szOsFile.sizeof>=4).
- assert(wasmCtypes.structs[1/*sqlite3_io_methods*/
- ].members.xFileSize.offset>0);
- //log(wasmCtypes.structs[0].name,"members",wasmCtypes.structs[0].members);
- [ /* Spot-check a handful of constants to make sure they got installed... */
- 'SQLITE_SCHEMA','SQLITE_NULL','SQLITE_UTF8',
- 'SQLITE_STATIC', 'SQLITE_DIRECTONLY',
- 'SQLITE_OPEN_CREATE', 'SQLITE_OPEN_DELETEONCLOSE'
- ].forEach(function(k){
- T.assert('number' === typeof capi[k]);
- });
- [/* Spot-check a few of the WASM API methods. */
- 'alloc', 'dealloc', 'installFunction'
- ].forEach(function(k){
- T.assert(capi.wasm[k] instanceof Function);
- });
-
- let dbName = "/testing1.sqlite3";
- let vfsName = undefined;
- if(capi.sqlite3_web_db_uses_vfs(0,"kvvfs")){
- dbName = "local";
- vfsName = 'kvvfs';
- logHtml("Found kvvfs. Clearing db(s) from sessionStorage and localStorage",
- "and selecting kvvfs-friendly db name:",dbName);
- clearKvvfs();
- }
- const db = new oo.DB(dbName,'c',vfsName), startTime = performance.now();
- log("db is kvvfs?",capi.sqlite3_web_db_uses_vfs(db.pointer,"kvvfs"));
- try {
- log("db.filename =",db.filename,"db.fileName() =",db.getFilename());
- const banner1 = '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>',
- banner2 = '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<';
- [
- testWasmUtil, testBasicSanity, testUDF,
- testAttach, testIntPtr, testStructStuff,
- testSqliteStructs, testPstack
- ].forEach((f)=>{
- const t = T.counter, n = performance.now();
- logHtml(banner1,"Running",f.name+"()...");
- f(db, sqlite3);
- logHtml(banner2,f.name+"():",T.counter - t,'tests in',(performance.now() - n),"ms");
- });
- }finally{
- db.close();
- if('kvvfs'===vfsName) clearKvvfs();
- }
- logHtml("Total Test count:",T.counter,"in",(performance.now() - startTime),"ms");
- log('capi.wasm.exports',capi.wasm.exports);
- };
-
- self.sqlite3TestModule.initSqlite3().then((S)=>{
- runTests(S);
- });
-})();