1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-27 20:41:58 +03:00

Port the first 180-odd unit tests from testing1.* into the new tester1.*. Fix a stray-keystroke-induced typo which broke pstack.allocChunks().

FossilOrigin-Name: ef689e33e464829f5cbe4ca24a53d9dba59abe74d3d80a37a91b93a4eccccf2d
This commit is contained in:
stephan
2022-10-13 08:03:31 +00:00
parent 1ffb6be119
commit d85d08398d
8 changed files with 591 additions and 46 deletions

View File

@ -941,8 +941,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
*/
allocChunks: (n,sz)=>{
const mem = wasm.pstack.alloc(n * sz);
const r
= [];
const rc = [];
let i = 0, offset = 0;
for(; i < n; offset = (sz * ++i)){
rc.push(mem + offset);

View File

@ -36,9 +36,13 @@ span.labeled-input {
background-color: yellow;
}
.warning { color: firebrick; }
.green { color: darkgreen; }
.group-start { color: blue; }
.group-end { color: blue; }
.input-wrapper { white-space: nowrap; }
#test-output {
border: 1px inset;
border-radius: 0.25em;
padding: 0.25em;
/*max-height: 30em;*/
overflow: auto;

View File

@ -15,12 +15,14 @@
</head>
<body>
<h1>sqlite3 WASM/JS tester #1 (Worker thread)</h1>
<div id='test-output'></div>
<script>(function(){
const logTarget = document.querySelector('#test-output');
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);
logTarget.append(ln);
};
const w = new Worker("tester1.js");
w.onmessage = function({data}){

View File

@ -15,6 +15,7 @@
</head>
<body>
<h1>sqlite3 WASM/JS tester #1 (UI thread)</h1>
<div id='test-output'></div>
<script src="sqlite3.js"></script>
<script src="tester1.js"></script>
</body>

View File

@ -11,6 +11,23 @@
***********************************************************************
Main functional and regression tests for the sqlite3 WASM API.
This mini-framework works like so:
This script adds a series of test groups, each of which contains an
arbitrary number of tests, into a queue. After loading of the
sqlite3 WASM/JS module is complete, that queue is processed. If any
given test fails, the whole thing fails. This script is built such
that it can run from the main UI thread or worker thread. Test
groups and individual tests can be assigned a predicate function
which determines whether to run them or not, and this is
specifically intended to be used to toggle certain tests on or off
for the main/worker threads.
Each test group defines a state object which gets applied as each
test function's `this`. Test functions can use that to, e.g., set up
a db in an early test and close it in a later test. Each test gets
passed the sqlite3 namespace object as its only argument.
*/
'use strict';
(function(){
@ -19,8 +36,16 @@
on whether we are running in a worker thread or
the main (UI) thread.
*/
let logHtml;
let logClass;
/* Predicate for tests/groups. */
const isUIThread = ()=>(self.window===self && self.document);
/* Predicate for tests/groups. */
const isWorker = ()=>!isUIThread();
/* Predicate for tests/groups. */
const testIsTodo = ()=>false;
const haveJaccwabytTests = function(){
return !!wasm.exports.jaccwabyt_test_int64_max;
};
const mapToString = (v)=>{
switch(typeof v){
case 'number': case 'string': case 'boolean':
@ -29,20 +54,28 @@
default: break;
}
if(null===v) return 'null';
if(v instanceof Error){
v = {
message: v.message,
stack: v.stack,
errorClass: v.name
};
}
return JSON.stringify(v,undefined,2);
};
const normalizeArgs = (args)=>args.map(mapToString);
if( isUIThread() ){
console.log("Running UI thread.");
logHtml = function(cssClass,...args){
console.log("Running in UI thread.");
const logTarget = document.querySelector('#test-output');
logClass = 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);
logTarget.append(ln);
};
}else{ /* Worker thread */
console.log("Running Worker thread.");
logHtml = function(cssClass,...args){
logClass = function(cssClass,...args){
postMessage({
type:'log',
payload:{cssClass, args: normalizeArgs(args)}
@ -51,21 +84,24 @@
}
const log = (...args)=>{
//console.log(...args);
logHtml('',...args);
logClass('',...args);
}
const warn = (...args)=>{
console.warn(...args);
logHtml('warning',...args);
logClass('warning',...args);
}
const error = (...args)=>{
console.error(...args);
logHtml('error',...args);
logClass('error',...args);
};
const toss = (...args)=>{
error(...args);
throw new Error(args.join(' '));
};
const tossQuietly = (...args)=>{
throw new Error(args.join(' '));
};
/**
Helpers for writing sqlite3-specific tests.
@ -74,6 +110,8 @@
/** Running total of the number of tests run via
this API. */
counter: 0,
/* Separator line for log messages. */
separator: '------------------------------------------------------------',
/**
If expr is a function, it is called and its result
is returned, coerced to a bool, else expr, coerced to
@ -155,32 +193,531 @@
if(!this.toBool(expr)) throw new Error(msg || "throwUnless() failed");
return this;
},
TestGroup: class {
constructor(name){
eqApprox: (v1,v2,factor=0.05)=>(v1>=(v2-factor) && v1<=(v2+factor)),
TestGroup: (function(){
let groupCounter = 0;
const TestGroup = function(name, predicate){
this.number = ++groupCounter;
this.name = name;
this.predicate = predicate;
this.tests = [];
};
TestGroup.prototype = {
addTest: function(testObj){
this.tests.push(testObj);
return this;
},
run: async function(sqlite3){
if(this.predicate && !this.predicate()){
log("SKIPPING test group #"+this.number,this.name);
return;
}
push(name,callback){
log(TestUtil.separator);
logClass('group-start',"Group #"+this.number+':',this.name);
const indent = '....';
const assertCount = TestUtil.counter;
const groupState = Object.create(null);
const skipped = [];
for(let i in this.tests){
const t = this.tests[i];
const n = this.number+"."+i;
if(t.predicate && !t.predicate()){
logClass('warning',indent, n+': SKIPPING',t.name);
skipped.push( n+': '+t.name );
}else{
const tc = TestUtil.counter
log(indent, n+":", t.name);
await t.test.call(groupState, sqlite3);
//log(indent, indent, 'assertion count:',TestUtil.counter - tc);
}
}/*TestGroup*/,
}
logClass('green',
"Group #"+this.number,"assertion count:",(TestUtil.counter - assertCount));
if(skipped.length){
log("SKIPPED test(s) in group",this.number+":",skipped);
}
}
};
return TestGroup;
})()/*TestGroup*/,
testGroups: [],
currentTestGroup: undefined,
addGroup: function(name){
if(this.testGroups[name]){
toss("Test group already exists:",name);
}
addGroup: function(name, predicate){
this.testGroups.push( this.currentTestGroup = new this.TestGroup(name) );
return this;
},
addTest: function(name, callback){
this.currentTestGroup.push(name, callback);
let predicate;
if(1===arguments.length){
const opt = arguments[0];
predicate = opt.predicate;
name = opt.name;
callback = opt.test;
}
this.currentTestGroup.addTest({
name, predicate, test: callback
});
return this;
},
runTests: function(){
toss("TODO: runTests()");
runTests: async function(sqlite3){
return new Promise(async function(pok,pnok){
try {
for(let g of this.testGroups){
await g.run(sqlite3);
}
log(TestUtil.separator);
log("Done running tests. Total assertion count:",TestUtil.counter);
pok();
}catch(e){
error(e);
pnok(e);
}
}.bind(this));
}
}/*TestUtil*/;
const T = TestUtil;
T.g = T.addGroup;
T.t = T.addTest;
let capi, wasm/*assigned after module init*/;
////////////////////////////////////////////////////////////////////////
// End of infrastructure setup. Now define the tests...
////////////////////////////////////////////////////////////////////////
T.g('Basic sanity checks')
.t('Namespace object checks', function(sqlite3){
const wasmCtypes = wasm.ctype;
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);
[ /* 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((k)=>T.assert('number' === typeof capi[k]));
[/* Spot-check a few of the WASM API methods. */
'alloc', 'dealloc', 'installFunction'
].forEach((k)=>T.assert(wasm[k] instanceof Function));
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');
try {
throw new sqlite3.WasmAllocError;
}catch(e){
T.assert(e instanceof Error)
.assert(e instanceof sqlite3.WasmAllocError);
}
})
.t('strglob/strlike', function(sqlite3){
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));
})
.t('sqlite3.capi.wasm.pstack', function(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;
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);
}
}/*pstack tests*/)
;/*end of basic sanity checks*/
////////////////////////////////////////////////////////////////////////
T.g('sqlite3.oo1 sanity checks')
.t('Create db', function(sqlite3){
const db = this.db = new sqlite3.oo1.DB();
T.assert(Number.isInteger(db.pointer)).
mustThrowMatching(()=>db.pointer=1, /read-only/).
assert(0===sqlite3.capi.sqlite3_extended_result_codes(db.pointer,1)).
assert('main'===db.dbName(0));
// Custom db error message handling via sqlite3_prepare_v2/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"));
})
.t('DB.Stmt sanity checks', function(S){
let pId;
let st = this.db.prepare(
new TextEncoder('utf-8').encode("select 3 as a")
);
//debug("statement =",st);
try {
T.assert(Number.isInteger(st.pointer))
.mustThrowMatching(()=>st.pointer=1, /read-only/)
.assert(1===this.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===this.db.openStatementCount());
})
.t('Table t', function(sqlite3){
const db = this.db;
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 && haveJaccwabytTests()){
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)));
}
let 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 {
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('Scalar UDFs', function(sqlite3){
const db = this.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
});
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(T.eqApprox(3.1,db.selectValue("select 3.0 + 0.1"))).
assert(T.eqApprox(1.3,db.selectValue("select asis(1 + 0.3)")));
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]);
})
.t({
name: 'Aggregate UDFs (tests are TODO)',
predicate: testIsTodo
})
.t({
name: 'Window UDFs (tests are TODO)',
predicate: testIsTodo
})
.t("ATTACH", function(){
const db = this.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]));
};
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", ()=>{
tossQuietly("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"));
})
.t({
name: 'Jaccwabyt-specific int-pointer tests (if compiled in)',
predicate: haveJaccwabytTests,
test: function(){
const w = wasm, db = this.db;
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){
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);
}
}
}/* jaccwabyt-specific tests */)
.t('Close db', function(){
T.assert(this.db).assert(Number.isInteger(this.db.pointer));
wasm.exports.sqlite3_wasm_db_reset(this.db.pointer);
this.db.close();
T.assert(!this.db.pointer);
})
;/* end of oo1 checks */
////////////////////////////////////////////////////////////////////////
log("Loading and initializing sqlite3 WASM module...");
if(!isUIThread()){
importScripts("sqlite3.js");
@ -190,11 +727,15 @@
printErr: error
}).then(function(sqlite3){
//console.log('sqlite3 =',sqlite3);
log("Done initializing. Running tests...");
try {
TestUtil.runTests();
}catch(e){
error("Tests failed:",e.message);
log("Done initializing WASM/JS bits. Running tests...");
capi = sqlite3.capi;
wasm = capi.wasm;
log("sqlite3 version:",capi.sqlite3_libversion(),
capi.sqlite3_sourceid());
log("BigInt/int64 support is",(wasm.bigIntEnabled ? "enabled" : "disabled"));
if(haveJaccwabytTests()){
log("Jaccwabyt test C code found. Jaccwabyt-specific low-level tests.");
}
TestUtil.runTests(sqlite3);
});
})();

View File

@ -94,7 +94,6 @@
"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*/],
multi: true,
saveSql: list,
bind: [5,6]
});
@ -258,7 +257,6 @@
"insert into foo.bar(a) values(1),(2),(3);",
"select a from foo.bar order by a;"
].join('')),
multi: true,
rowMode: 0,
resultRows
});

View File

@ -1,5 +1,5 @@
C Updates\sto\sthe\sfuzzer\squery\sinvariant\schecker\s-\stracking\schanges\smade\nover\sin\sdbsqlfuzz.
D 2022-10-12T18:40:25.766
C Port\sthe\sfirst\s180-odd\sunit\stests\sfrom\stesting1.*\sinto\sthe\snew\stester1.*.\sFix\sa\sstray-keystroke-induced\stypo\swhich\sbroke\spstack.allocChunks().
D 2022-10-13T08:03:31.255
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -487,7 +487,7 @@ F ext/wasm/api/sqlite3-api-cleanup.js 5d22d1d3818ecacb23bfa223d5970cd0617d8cdbb4
F ext/wasm/api/sqlite3-api-glue.js 3b2a43c7b2ceb2b60f5f4a1afefbd93508c2fe0f2e667eea278afe570be4b606
F ext/wasm/api/sqlite3-api-oo1.js ac1e08d36bdfb5aa0a2d75b7d4c892fd51819d34c932370c3282810672bcc086
F ext/wasm/api/sqlite3-api-opfs.js 5a8ab3b76880c8ada8710ca9ba1ca5b160872edfd8bd5322e4f179a7f41cc616
F ext/wasm/api/sqlite3-api-prologue.js daf288df965cab1e8eabee4451f6ba3beb03d5a579722b0b0f90e5203962f515
F ext/wasm/api/sqlite3-api-prologue.js 5c56056810333974c971f6310c5c9698cf7ca8b06f6d2f1986cec819d0f5bbad
F ext/wasm/api/sqlite3-api-worker1.js 7f4f46cb6b512a48572d7567233896e6a9c46570c44bdc3d13419730c7c221c8
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c a321f12ceedac8611c1377ccfb5df0c0547bd9395f7fd7613827de365d994948
@ -495,7 +495,7 @@ F ext/wasm/batch-runner.html cf1a410c92bad50fcec2ddc71390b4e9df63a6ea1bef12a5163
F ext/wasm/batch-runner.js 5bae81684728b6be157d1f92b39824153f0fd019345b39f2ab8930f7ee2a57d8
F ext/wasm/common/SqliteTestUtil.js 647bf014bd30bdd870a7e9001e251d12fc1c9ec9ce176a1004b838a4b33c5c05
F ext/wasm/common/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f
F ext/wasm/common/testing.css bd6b23c4666be765139c1e50569cac301d949d5e251f7ad442376995ec5aa39a
F ext/wasm/common/testing.css 12bd88c69eea1b61649ad9add3ff24f0fbc3b79a7616d74ab3997b7271cd8482
F ext/wasm/common/whwasmutil.js bc8522a071f4754af7b50f53807b95f691d2f9e44fc3b3e8c65dff6ef2485c0d
F ext/wasm/demo-123-worker.html e50b51dc7271b9d3cc830cb7c2fba294d622f56b7acb199f7257d11195a63d49
F ext/wasm/demo-123.html 7c239c9951d1b113f9f532969ac039294cf1dcfee2b3ae0a2c1ed2b3d59f8dfa
@ -526,13 +526,13 @@ 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/tester1-worker.html 0af7a22025ff1da72a84765d64f8f221844a57c6e6e314acf3a30f176101fd3f
F ext/wasm/tester1.html fde0e0bdeaaa2c39877c749dc86a8c1c306f771c3d75b89a6289a5ed11243e9d
F ext/wasm/tester1.js d25cf7615bd39ab9ab4be2f231fecf1fff1378227e695083dc35adc4fdff668e
F ext/wasm/testing-worker1-promiser.html 6eaec6e04a56cf24cf4fa8ef49d78ce8905dde1354235c9125dca6885f7ce893
F ext/wasm/testing-worker1-promiser.js bd788e33c1807e0a6dda9c9a9d784bd3350ca49c9dd8ae2cc8719b506b6e013e
F ext/wasm/testing1.html 50575755e43232dbe4c2f97c9086b3118eb91ec2ee1fae931e6d7669fb17fcae
F ext/wasm/testing1.js 15fc3dca6b2fc22c1458cca2cc2c484281dfc91f01c048ad4e38d5d3924ea961
F ext/wasm/testing1.js 2034cf6972ab1506e75e41e532ca7cd3060e194c37edab3ff65d00d8a8af8ba2
F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3
F ext/wasm/testing2.js 88f40ef3cd8201bdadd120a711c36bbf0ce56cc0eab1d5e7debb71fed7822494
F ext/wasm/wasmfs.make 3cce1820006196de140f90f2da4b4ea657083fb5bfee7d125be43f7a85748c8f
@ -2034,8 +2034,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 368fa6b25bc803ded7c1a0184615980902657879370caec22ceea42496ec0566
R b6417444abfe9dc882e90feaa0e7d85d
U drh
Z 6e9d8b3a258c07649344995d3cb09455
P 4ca16a304ad10fbb48f78b4384b347fe883e1a4f222f113ac981e89845c3e113
R 624f8080126a42bc3dcbc00f2cc651c0
U stephan
Z 26dc7314d65c80886c8a3b55a6ce8b4e
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
4ca16a304ad10fbb48f78b4384b347fe883e1a4f222f113ac981e89845c3e113
ef689e33e464829f5cbe4ca24a53d9dba59abe74d3d80a37a91b93a4eccccf2d