mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-27 20:41:58 +03:00
Move the rest of testing1.js into tester1.js and eliminate the dependency on jaccwabyt_test.c. Extend the list of default config-related #defines in sqlite3-wasm.c and reorganize them for maintainability.
FossilOrigin-Name: 4e2a8aff2dd4b6e148f45184e2523ebe47815257eca97fa3d32bcbf9625f0def
This commit is contained in:
@ -68,14 +68,10 @@ SQLITE_OPT = \
|
||||
-DSQLITE_TEMP_STORE=3 \
|
||||
-DSQLITE_OS_KV_OPTIONAL=1 \
|
||||
'-DSQLITE_DEFAULT_UNIX_VFS="unix-none"' \
|
||||
-DSQLITE_USE_URI=1
|
||||
#SQLITE_OPT += -DSQLITE_ENABLE_MEMSYS5
|
||||
# ^^^ MEMSYS5 is hypothetically useful for non-Emscripten builds but
|
||||
# requires adding more infrastructure and fixing one spot in the
|
||||
# sqlite3 internals which calls malloc() early on.
|
||||
|
||||
# SQLITE_OMIT_LOAD_EXTENSION: if this is true, sqlite3_vfs::xDlOpen
|
||||
# and friends may be NULL.
|
||||
-DSQLITE_USE_URI=1 \
|
||||
-DSQLITE_WASM_ENABLE_C_TESTS
|
||||
# ^^^ most flags are set in sqlite3-wasm.c but we need them
|
||||
# made explicit here for building speedtest1.c.
|
||||
|
||||
ifneq (,$(filter release,$(MAKECMDGOALS)))
|
||||
emcc_opt ?= -Oz -flto
|
||||
@ -128,8 +124,7 @@ else
|
||||
$(info Development build. Use '$(MAKE) release' for a smaller release build.)
|
||||
endif
|
||||
|
||||
EXPORTED_FUNCTIONS.api.in := $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api \
|
||||
$(dir.jacc)/jaccwabyt_test.exports
|
||||
EXPORTED_FUNCTIONS.api.in := $(dir.api)/EXPORTED_FUNCTIONS.sqlite3-api
|
||||
|
||||
EXPORTED_FUNCTIONS.api: $(EXPORTED_FUNCTIONS.api.in) $(MAKEFILE)
|
||||
cat $(EXPORTED_FUNCTIONS.api.in) > $@
|
||||
@ -294,12 +289,6 @@ sqlite3-wasm.o := $(dir.api)/sqlite3-wasm.o
|
||||
$(sqlite3-wasm.o): emcc.cflags += $(SQLITE_OPT)
|
||||
$(sqlite3-wasm.o): $(dir.top)/sqlite3.c
|
||||
sqlite3-wasm.c := $(dir.api)/sqlite3-wasm.c
|
||||
jaccwabyt_test.c := $(dir.jacc)/jaccwabyt_test.c
|
||||
# ^^^ FIXME (how?): jaccwabyt_test.c is only needed for the test apps,
|
||||
# so we don't really want to include it in release builds. However, we
|
||||
# want to test the release builds with those apps, so we cannot simply
|
||||
# elide that file in release builds. That component is critical to the
|
||||
# VFS bindings so needs to be tested along with the core APIs.
|
||||
########################################################################
|
||||
# call-wasm-c-compile sets up build rules
|
||||
# for $1.o. $1 must be the name of a C file (with extension).
|
||||
@ -310,7 +299,7 @@ $$($(1).o): $$(MAKEFILE) $(1)
|
||||
$$(emcc.bin) $$(emcc_opt_full) $$(emcc.flags) $$(emcc.cflags) -c $(1) -o $$@
|
||||
CLEAN_FILES += $$($(1).o)
|
||||
endef
|
||||
$(foreach c,$(sqlite3-wasm.c) $(jaccwabyt_test.c),$(eval $(call call-wasm-c-compile,$(c))))
|
||||
$(foreach c,$(sqlite3-wasm.c),$(eval $(call call-wasm-c-compile,$(c))))
|
||||
$(eval $(call call-make-pre-js,sqlite3))
|
||||
$(sqlite3.js): $(MAKEFILE) $(sqlite3.wasm.obj) \
|
||||
EXPORTED_FUNCTIONS.api \
|
||||
@ -401,7 +390,7 @@ speedtest1.wasm := $(subst .js,.wasm,$(speedtest1.js))
|
||||
speedtest1.cflags := \
|
||||
-I. -I.. -I$(dir.top) \
|
||||
-DSQLITE_SPEEDTEST1_WASM
|
||||
speedtest1.cs := $(speedtest1.c) $(sqlite3-wasm.c) $(jaccwabyt_test.c)
|
||||
speedtest1.cs := $(speedtest1.c) $(sqlite3-wasm.c)
|
||||
$(speedtest1.js): emcc.cflags+=
|
||||
# speedtest1 notes re. sqlite3-wasm.o vs sqlite3-wasm.c: building against
|
||||
# the latter (predictably) results in a slightly faster binary, but we're
|
||||
|
@ -592,9 +592,15 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
*/
|
||||
capi.sqlite3_web_rc_str = (rc)=>__rcMap[rc];
|
||||
/* Bind all registered C-side structs... */
|
||||
const notThese = Object.assign(Object.create(null),{
|
||||
// Structs NOT to register
|
||||
WasmTestStruct: true
|
||||
});
|
||||
for(const s of wasm.ctype.structs){
|
||||
if(!notThese[s.name]){
|
||||
capi[s.name] = sqlite3.StructBinder(s);
|
||||
}
|
||||
}
|
||||
}/*end C constant imports*/
|
||||
|
||||
if( util.isMainWindow()
|
||||
|
@ -806,12 +806,16 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
- (optionsObject)
|
||||
|
||||
In the final two cases, the function must be defined as the
|
||||
'callback' property of the options object. In the final
|
||||
`callback` property of the options object (optionally called
|
||||
`xFunc` to align with the C API documentation). In the final
|
||||
case, the function's name must be the 'name' property.
|
||||
|
||||
This can only be used to create scalar functions, not
|
||||
aggregate or window functions. UDFs cannot be removed from
|
||||
a DB handle after they're added.
|
||||
This can currently only be used to create scalar functions, not
|
||||
aggregate or window functions (requires only a bit of
|
||||
refactoring to support aggregates and window functions).
|
||||
|
||||
UDFs cannot currently be removed from a DB handle after they're
|
||||
added.
|
||||
|
||||
On success, returns this object. Throws on error.
|
||||
|
||||
@ -848,18 +852,22 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
- .deterministic = SQLITE_DETERMINISTIC
|
||||
- .directOnly = SQLITE_DIRECTONLY
|
||||
- .innocuous = SQLITE_INNOCUOUS
|
||||
|
||||
TODO: for the (optionsObject) form, accept callbacks for
|
||||
aggregate and window functions.
|
||||
|
||||
*/
|
||||
createFunction: function f(name, callback,opt){
|
||||
createFunction: function f(name, callback, opt){
|
||||
switch(arguments.length){
|
||||
case 1: /* (optionsObject) */
|
||||
opt = name;
|
||||
name = opt.name;
|
||||
callback = opt.callback;
|
||||
callback = opt.xFunc || opt.callback;
|
||||
break;
|
||||
case 2: /* (name, callback|optionsObject) */
|
||||
if(!(callback instanceof Function)){
|
||||
opt = callback;
|
||||
callback = opt.callback;
|
||||
callback = opt.xFunc || opt.callback;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
|
@ -949,7 +949,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
return rc;
|
||||
},
|
||||
/**
|
||||
A convenience wrapper for allocChunks() which sizes each chunks
|
||||
A convenience wrapper for allocChunks() which sizes each chunk
|
||||
as either 8 bytes (safePtrSize is truthy) or wasm.ptrSizeof (if
|
||||
safePtrSize is falsy).
|
||||
|
||||
|
@ -14,6 +14,16 @@
|
||||
*/
|
||||
|
||||
#define SQLITE_WASM
|
||||
#ifdef SQLITE_WASM_ENABLE_C_TESTS
|
||||
/*
|
||||
** Functions blocked off by SQLITE_WASM_TESTS are intended solely for
|
||||
** use in unit/regression testing. They may be safely omitted from
|
||||
** client-side builds.
|
||||
*/
|
||||
# define SQLITE_WASM_TESTS 1
|
||||
#else
|
||||
# define SQLITE_WASM_TESTS 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Threading and file locking: JS is single-threaded. Each Worker
|
||||
@ -32,34 +42,20 @@
|
||||
** locking, and any similar future filesystems, threading and file
|
||||
** locking support are unnecessary in the wasm build.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Undefine any SQLITE_... config flags which we specifically do not
|
||||
** want undefined. Please keep these alphabetized.
|
||||
*/
|
||||
#undef SQLITE_OMIT_DESERIALIZE
|
||||
#ifndef SQLITE_DEFAULT_UNIX_VFS
|
||||
# define SQLITE_DEFAULT_UNIX_VFS "unix-none"
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
# define SQLITE_OMIT_DEPRECATED
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
# define SQLITE_OMIT_LOAD_EXTENSION
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
# define SQLITE_OMIT_SHARED_CACHE
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
# define SQLITE_OMIT_UTF16
|
||||
#endif
|
||||
#ifndef SQLITE_OS_KV_OPTIONAL
|
||||
# define SQLITE_OS_KV_OPTIONAL 1
|
||||
#endif
|
||||
#ifndef SQLITE_TEMP_STORE
|
||||
# define SQLITE_TEMP_STORE 3
|
||||
#endif
|
||||
#ifndef SQLITE_THREADSAFE
|
||||
# define SQLITE_THREADSAFE 0
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
# define SQLITE_OMIT_WAL
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Define any SQLITE_... config defaults we want if they aren't
|
||||
** overridden by the builder. Please keep these alphabetized.
|
||||
*/
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_DEFAULT_... */
|
||||
#ifndef SQLITE_DEFAULT_CACHE_SIZE
|
||||
/*
|
||||
** The OPFS impls benefit tremendously from an increased cache size
|
||||
@ -71,14 +67,78 @@
|
||||
*/
|
||||
# define SQLITE_DEFAULT_CACHE_SIZE -16777216
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/*
|
||||
** TODO: experiment with this when back on the opfs-capable machine.
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_PAGE_SIZE
|
||||
#if 0 && !defined(SQLITE_DEFAULT_PAGE_SIZE)
|
||||
/* TODO: experiment with this. */
|
||||
# define SQLITE_DEFAULT_PAGE_SIZE 8192 /*4096*/
|
||||
#endif
|
||||
#ifndef SQLITE_DEFAULT_UNIX_VFS
|
||||
# define SQLITE_DEFAULT_UNIX_VFS "unix-none"
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_ENABLE_... */
|
||||
#ifndef SQLITE_ENABLE_BYTECODE_VTAB
|
||||
# define SQLITE_ENABLE_BYTECODE_VTAB 1
|
||||
#endif
|
||||
#ifndef SQLITE_ENABLE_DBPAGE_VTAB
|
||||
# define SQLITE_ENABLE_DBPAGE_VTAB 1
|
||||
#endif
|
||||
#ifndef SQLITE_ENABLE_DBSTAT_VTAB
|
||||
# define SQLITE_ENABLE_DBSTAT_VTAB 1
|
||||
#endif
|
||||
#ifndef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
# define SQLITE_ENABLE_EXPLAIN_COMMENTS 1
|
||||
#endif
|
||||
#ifndef SQLITE_ENABLE_FTS4
|
||||
# define SQLITE_ENABLE_FTS4 1
|
||||
#endif
|
||||
#ifndef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
# define SQLITE_ENABLE_OFFSET_SQL_FUNC 1
|
||||
#endif
|
||||
#ifndef SQLITE_ENABLE_RTREE
|
||||
# define SQLITE_ENABLE_RTREE 1
|
||||
#endif
|
||||
#ifndef SQLITE_ENABLE_STMTVTAB
|
||||
# define SQLITE_ENABLE_STMTVTAB 1
|
||||
#endif
|
||||
#ifndef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
# define SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_O... */
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
# define SQLITE_OMIT_DEPRECATED 1
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
# define SQLITE_OMIT_LOAD_EXTENSION 1
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
# define SQLITE_OMIT_SHARED_CACHE 1
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
# define SQLITE_OMIT_UTF16 1
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
# define SQLITE_OMIT_WAL 1
|
||||
#endif
|
||||
#ifndef SQLITE_OS_KV_OPTIONAL
|
||||
# define SQLITE_OS_KV_OPTIONAL 1
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_T... */
|
||||
#ifndef SQLITE_TEMP_STORE
|
||||
# define SQLITE_TEMP_STORE 3
|
||||
#endif
|
||||
#ifndef SQLITE_THREADSAFE
|
||||
# define SQLITE_THREADSAFE 0
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
/* SQLITE_USE_... */
|
||||
#ifndef SQLITE_USE_URI
|
||||
# define SQLITE_USE_URI 1
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
@ -89,11 +149,11 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
** SQLITE_WASM_KEEP is identical to EMSCRIPTEN_KEEPALIVE but is not
|
||||
** Emscripten-specific. It explicitly marks functions for export into
|
||||
** the target wasm file without requiring explicit listing of those
|
||||
** functions in Emscripten's -sEXPORTED_FUNCTIONS=... list (or
|
||||
** equivalent in other build platforms). Any function with neither
|
||||
** SQLITE_WASM_KEEP is functionally identical to EMSCRIPTEN_KEEPALIVE
|
||||
** but is not Emscripten-specific. It explicitly marks functions for
|
||||
** export into the target wasm file without requiring explicit listing
|
||||
** of those functions in Emscripten's -sEXPORTED_FUNCTIONS=... list
|
||||
** (or equivalent in other build platforms). Any function with neither
|
||||
** this attribute nor which is listed as an explicit export will not
|
||||
** be exported from the wasm file (but may still be used internally
|
||||
** within the wasm file).
|
||||
@ -256,6 +316,28 @@ int sqlite3_wasm_db_error(sqlite3*db, int err_code, const char *zMsg){
|
||||
return err_code;
|
||||
}
|
||||
|
||||
#if SQLITE_WASM_TESTS
|
||||
struct WasmTestStruct {
|
||||
int v4;
|
||||
void * ppV;
|
||||
const char * cstr;
|
||||
int64_t v8;
|
||||
void (*xFunc)(void*);
|
||||
};
|
||||
typedef struct WasmTestStruct WasmTestStruct;
|
||||
SQLITE_WASM_KEEP
|
||||
void sqlite3_wasm_test_struct(WasmTestStruct * s){
|
||||
if(s){
|
||||
s->v4 *= 2;
|
||||
s->v8 = s->v4 * 2;
|
||||
s->ppV = s;
|
||||
s->cstr = __FILE__;
|
||||
if(s->xFunc) s->xFunc(s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif /* SQLITE_WASM_TESTS */
|
||||
|
||||
/*
|
||||
** This function is NOT part of the sqlite3 public API. It is strictly
|
||||
** for use by the sqlite project's own JS/WASM bindings. Unlike the
|
||||
@ -692,6 +774,19 @@ const char * sqlite3_wasm_enum_json(void){
|
||||
M(xDelete,"i(ss)");
|
||||
M(nKeySize,"i");
|
||||
} _StructBinder;
|
||||
#undef CurrentStruct
|
||||
|
||||
#if SQLITE_WASM_TESTS
|
||||
#define CurrentStruct WasmTestStruct
|
||||
StructBinder {
|
||||
M(v4,"i");
|
||||
M(cstr,"s");
|
||||
M(ppV,"p");
|
||||
M(v8,"j");
|
||||
M(xFunc,"v(p)");
|
||||
} _StructBinder;
|
||||
#undef CurrentStruct
|
||||
#endif
|
||||
|
||||
} out( "]"/*structs*/);
|
||||
|
||||
@ -926,4 +1021,56 @@ int sqlite3_wasm_init_wasmfs(const char *zUnused){
|
||||
}
|
||||
#endif /* __EMSCRIPTEN__ && SQLITE_WASM_WASMFS */
|
||||
|
||||
#if SQLITE_WASM_TESTS
|
||||
|
||||
SQLITE_WASM_KEEP
|
||||
int sqlite3_wasm_test_intptr(int * p){
|
||||
return *p = *p * 2;
|
||||
}
|
||||
|
||||
SQLITE_WASM_KEEP
|
||||
int64_t sqlite3_wasm_test_int64_max(void){
|
||||
return (int64_t)0x7fffffffffffffff;
|
||||
}
|
||||
|
||||
SQLITE_WASM_KEEP
|
||||
int64_t sqlite3_wasm_test_int64_min(void){
|
||||
return ~sqlite3_wasm_test_int64_max();
|
||||
}
|
||||
|
||||
SQLITE_WASM_KEEP
|
||||
int64_t sqlite3_wasm_test_int64_times2(int64_t x){
|
||||
return x * 2;
|
||||
}
|
||||
|
||||
SQLITE_WASM_KEEP
|
||||
void sqlite3_wasm_test_int64_minmax(int64_t * min, int64_t *max){
|
||||
*max = sqlite3_wasm_test_int64_max();
|
||||
*min = sqlite3_wasm_test_int64_min();
|
||||
/*printf("minmax: min=%lld, max=%lld\n", *min, *max);*/
|
||||
}
|
||||
|
||||
SQLITE_WASM_KEEP
|
||||
int64_t sqlite3_wasm_test_int64ptr(int64_t * p){
|
||||
/*printf("sqlite3_wasm_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
|
||||
return *p = *p * 2;
|
||||
}
|
||||
|
||||
SQLITE_WASM_KEEP
|
||||
void sqlite3_wasm_test_stack_overflow(int recurse){
|
||||
if(recurse) sqlite3_wasm_test_stack_overflow(recurse);
|
||||
}
|
||||
|
||||
/* For testing the 'string-free' whwasmutil.xWrap() conversion. */
|
||||
SQLITE_WASM_KEEP
|
||||
char * sqlite3_wasm_test_str_hello(int fail){
|
||||
char * s = fail ? 0 : (char *)malloc(6);
|
||||
if(s){
|
||||
memcpy(s, "hello", 5);
|
||||
s[5] = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
#endif /* SQLITE_WASM_TESTS */
|
||||
|
||||
#undef SQLITE_WASM_KEEP
|
||||
|
@ -2,7 +2,6 @@ body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
white-space: break-spaces;
|
||||
}
|
||||
textarea {
|
||||
font-family: monospace;
|
||||
|
@ -1255,12 +1255,13 @@ self.WhWasmUtilInstaller = function(target){
|
||||
Would that be too much magic concentrated in one place, ready to
|
||||
backfire?
|
||||
*/
|
||||
xcv.arg.string = xcv.arg['pointer'] = xcv.arg['*'] = function(v){
|
||||
xcv.arg.string = xcv.arg.utf8 = xcv.arg['pointer'] = xcv.arg['*']
|
||||
= function(v){
|
||||
if('string'===typeof v) return target.scopedAllocCString(v);
|
||||
return v ? xcv.arg[ptrIR](v) : null;
|
||||
};
|
||||
xcv.result.string = (i)=>target.cstringToJs(i);
|
||||
xcv.result['string:free'] = (i)=>{
|
||||
xcv.result.string = xcv.result.utf8 = (i)=>target.cstringToJs(i);
|
||||
xcv.result['string:free'] = xcv.result['utf8:free'] = (i)=>{
|
||||
try { return i ? target.cstringToJs(i) : null }
|
||||
finally{ target.dealloc(i) }
|
||||
};
|
||||
@ -1374,31 +1375,33 @@ self.WhWasmUtilInstaller = function(target){
|
||||
|
||||
Non-numeric conversions include:
|
||||
|
||||
- `string` (args): has two different semantics in order to
|
||||
accommodate various uses of certain C APIs (e.g. output-style
|
||||
strings)...
|
||||
- `string` or `utf8` (args): has two different semantics in order
|
||||
to accommodate various uses of certain C APIs
|
||||
(e.g. output-style strings)...
|
||||
|
||||
- If the arg is a string, it creates a _temporary_ C-string to
|
||||
pass to the exported function, cleaning it up before the
|
||||
wrapper returns. If a long-lived C-string pointer is
|
||||
required, that requires client-side code to create the
|
||||
string, then pass its pointer to the function.
|
||||
- If the arg is a string, it creates a _temporary_
|
||||
UTF-8-encoded C-string to pass to the exported function,
|
||||
cleaning it up before the wrapper returns. If a long-lived
|
||||
C-string pointer is required, that requires client-side code
|
||||
to create the string, then pass its pointer to the function.
|
||||
|
||||
- Else the arg is assumed to be a pointer to a string the
|
||||
client has already allocated and it's passed on as
|
||||
a WASM pointer.
|
||||
|
||||
- `string` (results): treats the result value as a const C-string,
|
||||
copies it to a JS string, and returns that JS string.
|
||||
- `string` or `utf8` (results): treats the result value as a
|
||||
const C-string, encoded as UTF-8, copies it to a JS string,
|
||||
and returns that JS string.
|
||||
|
||||
- `string:free` (results): treats the result value as a non-const
|
||||
C-string, ownership of which has just been transfered to the
|
||||
caller. It copies the C-string to a JS string, frees the
|
||||
C-string, and returns the JS string. If such a result value is
|
||||
NULL, the JS result is `null`. Achtung: when using an API which
|
||||
returns results from a specific allocator, e.g. `my_malloc()`,
|
||||
this conversion _is not legal_. Instead, an equivalent conversion
|
||||
which uses the appropriate deallocator is required. For example:
|
||||
- `string:free` or `utf8:free) (results): treats the result value
|
||||
as a non-const UTF-8 C-string, ownership of which has just been
|
||||
transfered to the caller. It copies the C-string to a JS
|
||||
string, frees the C-string, and returns the JS string. If such
|
||||
a result value is NULL, the JS result is `null`. Achtung: when
|
||||
using an API which returns results from a specific allocator,
|
||||
e.g. `my_malloc()`, this conversion _is not legal_. Instead, an
|
||||
equivalent conversion which uses the appropriate deallocator is
|
||||
required. For example:
|
||||
|
||||
```js
|
||||
target.xWrap.resultAdaptor('string:my_free',(i)=>{
|
||||
|
@ -41,6 +41,15 @@
|
||||
</div>
|
||||
<div>The tests and demos...
|
||||
<ul id='test-list'>
|
||||
<li>Core-most tests
|
||||
<ul>
|
||||
<li><a href='tester1.html'>tester1</a>: Core unit and
|
||||
regression tests for the various APIs and surrounding
|
||||
utility code.</li>
|
||||
<li><a href='tester1.html'>tester1-worker</a>: same thing
|
||||
but running in a Worker.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>High-level apps and demos...
|
||||
<ul>
|
||||
<li><a href='fiddle/fiddle.html'>fiddle</a> is an HTML front-end
|
||||
@ -68,7 +77,6 @@
|
||||
</li>
|
||||
<li>The obligatory "misc." category...
|
||||
<ul>
|
||||
<li><a href='testing1.html'>testing1</a>: sanity tests of the core APIs and surrounding utility code.</li>
|
||||
<li><a href='testing2.html'>testing2</a>: Worker-based test of OO API #1.</li>
|
||||
<li><a href='testing-worker1-promiser.html'>testing-worker1-promiser</a>:
|
||||
tests for the Promise-based wrapper of the Worker-based API.</li>
|
||||
|
@ -1,178 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <string.h> /* memset() */
|
||||
#include <stddef.h> /* offsetof() */
|
||||
#include <stdio.h> /* snprintf() */
|
||||
#include <stdint.h> /* int64_t */
|
||||
/*#include <stdlib.h>*/ /* malloc/free(), needed for emscripten exports. */
|
||||
extern void * malloc(size_t);
|
||||
extern void free(void *);
|
||||
|
||||
/*
|
||||
** 2022-06-25
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
***********************************************************************
|
||||
**
|
||||
** Utility functions for use with the emscripten/WASM bits. These
|
||||
** functions ARE NOT part of the sqlite3 public API. They are strictly
|
||||
** for internal use by the JS/WASM bindings.
|
||||
**
|
||||
** This file is intended to be WASM-compiled together with sqlite3.c,
|
||||
** e.g.:
|
||||
**
|
||||
** emcc ... sqlite3.c wasm_util.c
|
||||
*/
|
||||
|
||||
/*
|
||||
** Experimenting with output parameters.
|
||||
*/
|
||||
int jaccwabyt_test_intptr(int * p){
|
||||
if(1==((int)p)%3){
|
||||
/* kludge to get emscripten to export malloc() and free() */;
|
||||
free(malloc(0));
|
||||
}
|
||||
return *p = *p * 2;
|
||||
}
|
||||
int64_t jaccwabyt_test_int64_max(void){
|
||||
return (int64_t)0x7fffffffffffffff;
|
||||
}
|
||||
int64_t jaccwabyt_test_int64_min(void){
|
||||
return ~jaccwabyt_test_int64_max();
|
||||
}
|
||||
int64_t jaccwabyt_test_int64_times2(int64_t x){
|
||||
return x * 2;
|
||||
}
|
||||
|
||||
void jaccwabyt_test_int64_minmax(int64_t * min, int64_t *max){
|
||||
*max = jaccwabyt_test_int64_max();
|
||||
*min = jaccwabyt_test_int64_min();
|
||||
/*printf("minmax: min=%lld, max=%lld\n", *min, *max);*/
|
||||
}
|
||||
int64_t jaccwabyt_test_int64ptr(int64_t * p){
|
||||
/*printf("jaccwabyt_test_int64ptr( @%lld = 0x%llx )\n", (int64_t)p, *p);*/
|
||||
return *p = *p * 2;
|
||||
}
|
||||
|
||||
void jaccwabyt_test_stack_overflow(int recurse){
|
||||
if(recurse) jaccwabyt_test_stack_overflow(recurse);
|
||||
}
|
||||
|
||||
struct WasmTestStruct {
|
||||
int v4;
|
||||
void * ppV;
|
||||
const char * cstr;
|
||||
int64_t v8;
|
||||
void (*xFunc)(void*);
|
||||
};
|
||||
typedef struct WasmTestStruct WasmTestStruct;
|
||||
void jaccwabyt_test_struct(WasmTestStruct * s){
|
||||
if(s){
|
||||
s->v4 *= 2;
|
||||
s->v8 = s->v4 * 2;
|
||||
s->ppV = s;
|
||||
s->cstr = __FILE__;
|
||||
if(s->xFunc) s->xFunc(s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/** For testing the 'string-free' whwasmutil.xWrap() conversion. */
|
||||
char * jaccwabyt_test_str_hello(int fail){
|
||||
char * s = fail ? 0 : (char *)malloc(6);
|
||||
if(s){
|
||||
memcpy(s, "hello", 5);
|
||||
s[5] = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
** Returns a NUL-terminated string containing a JSON-format metadata
|
||||
** regarding C structs, for use with the StructBinder API. The
|
||||
** returned memory is static and is only written to the first time
|
||||
** this is called.
|
||||
*/
|
||||
const char * jaccwabyt_test_ctype_json(void){
|
||||
static char strBuf[1024 * 8] = {0};
|
||||
int n = 0, structCount = 0, groupCount = 0;
|
||||
char * pos = &strBuf[1] /* skip first byte for now to help protect
|
||||
against a small race condition */;
|
||||
char const * const zEnd = pos + sizeof(strBuf);
|
||||
if(strBuf[0]) return strBuf;
|
||||
/* Leave first strBuf[0] at 0 until the end to help guard against a
|
||||
tiny race condition. If this is called twice concurrently, they
|
||||
might end up both writing to strBuf, but they'll both write the
|
||||
same thing, so that's okay. If we set byte 0 up front then the
|
||||
2nd instance might return a partially-populated string. */
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// First we need to build up our macro framework...
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Core output macros...
|
||||
#define lenCheck assert(pos < zEnd - 100)
|
||||
#define outf(format,...) \
|
||||
pos += snprintf(pos, ((size_t)(zEnd - pos)), format, __VA_ARGS__); \
|
||||
lenCheck
|
||||
#define out(TXT) outf("%s",TXT)
|
||||
#define CloseBrace(LEVEL) \
|
||||
assert(LEVEL<5); memset(pos, '}', LEVEL); pos+=LEVEL; lenCheck
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Macros for emitting StructBinder descriptions...
|
||||
#define StructBinder__(TYPE) \
|
||||
n = 0; \
|
||||
outf("%s{", (structCount++ ? ", " : "")); \
|
||||
out("\"name\": \"" # TYPE "\","); \
|
||||
outf("\"sizeof\": %d", (int)sizeof(TYPE)); \
|
||||
out(",\"members\": {");
|
||||
#define StructBinder_(T) StructBinder__(T)
|
||||
// ^^^ indirection needed to expand CurrentStruct
|
||||
#define StructBinder StructBinder_(CurrentStruct)
|
||||
#define _StructBinder CloseBrace(2)
|
||||
#define M(MEMBER,SIG) \
|
||||
outf("%s\"%s\": " \
|
||||
"{\"offset\":%d,\"sizeof\": %d,\"signature\":\"%s\"}", \
|
||||
(n++ ? ", " : ""), #MEMBER, \
|
||||
(int)offsetof(CurrentStruct,MEMBER), \
|
||||
(int)sizeof(((CurrentStruct*)0)->MEMBER), \
|
||||
SIG)
|
||||
// End of macros
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
out("\"structs\": ["); {
|
||||
|
||||
#define CurrentStruct WasmTestStruct
|
||||
StructBinder {
|
||||
M(v4,"i");
|
||||
M(cstr,"s");
|
||||
M(ppV,"p");
|
||||
M(v8,"j");
|
||||
M(xFunc,"v(p)");
|
||||
} _StructBinder;
|
||||
#undef CurrentStruct
|
||||
|
||||
} out( "]"/*structs*/);
|
||||
out("}"/*top-level object*/);
|
||||
*pos = 0;
|
||||
strBuf[0] = '{'/*end of the race-condition workaround*/;
|
||||
return strBuf;
|
||||
#undef DefGroup
|
||||
#undef Def
|
||||
#undef _DefGroup
|
||||
#undef StructBinder
|
||||
#undef StructBinder_
|
||||
#undef StructBinder__
|
||||
#undef M
|
||||
#undef _StructBinder
|
||||
#undef CurrentStruct
|
||||
#undef CloseBrace
|
||||
#undef out
|
||||
#undef outf
|
||||
#undef lenCheck
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
_jaccwabyt_test_intptr
|
||||
_jaccwabyt_test_int64ptr
|
||||
_jaccwabyt_test_int64_max
|
||||
_jaccwabyt_test_int64_min
|
||||
_jaccwabyt_test_int64_minmax
|
||||
_jaccwabyt_test_int64_times2
|
||||
_jaccwabyt_test_struct
|
||||
_jaccwabyt_test_ctype_json
|
||||
_jaccwabyt_test_stack_overflow
|
||||
_jaccwabyt_test_str_hello
|
@ -43,8 +43,8 @@
|
||||
const isWorker = ()=>!isUIThread();
|
||||
/* Predicate for tests/groups. */
|
||||
const testIsTodo = ()=>false;
|
||||
const haveJaccwabytTests = function(){
|
||||
return !!wasm.exports.jaccwabyt_test_int64_max;
|
||||
const haveWasmCTests = function(){
|
||||
return !!wasm.exports.sqlite3_wasm_test_int64_max;
|
||||
};
|
||||
const mapToString = (v)=>{
|
||||
switch(typeof v){
|
||||
@ -283,6 +283,7 @@
|
||||
// End of infrastructure setup. Now define the tests...
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
T.g('Basic sanity checks')
|
||||
.t('Namespace object checks', function(sqlite3){
|
||||
const wasmCtypes = wasm.ctype;
|
||||
@ -310,13 +311,656 @@
|
||||
.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));
|
||||
})
|
||||
////////////////////////////////////////////////////////////////////
|
||||
;/*end of basic sanity checks*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
T.g('C/WASM Utilities')
|
||||
.t('sqlite3.capi.wasm', function(sqlite3){
|
||||
const w = wasm;
|
||||
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('sqlite3_wasm_enum_json');
|
||||
T.assert(Number.isFinite(pJson)).assert(w.cstrlen(pJson)>300);
|
||||
}
|
||||
|
||||
//log("xWrap()...");
|
||||
{
|
||||
T.mustThrowMatching(()=>w.xWrap('sqlite3_libversion',null,'i32'),
|
||||
/requires 0 arg/).
|
||||
assert(w.xWrap.resultAdapter('i32') instanceof Function).
|
||||
assert(w.xWrap.argAdapter('i32') instanceof Function);
|
||||
let fw = w.xWrap('sqlite3_libversion','utf8');
|
||||
T.mustThrowMatching(()=>fw(1), /requires 0 arg/);
|
||||
let rc = fw();
|
||||
T.assert('string'===typeof rc).assert(rc.length>5);
|
||||
rc = w.xCallWrapped('sqlite3_wasm_enum_json','*');
|
||||
T.assert(rc>0 && Number.isFinite(rc));
|
||||
rc = w.xCallWrapped('sqlite3_wasm_enum_json','utf8');
|
||||
T.assert('string'===typeof rc).assert(rc.length>300);
|
||||
if(haveWasmCTests()){
|
||||
fw = w.xWrap('sqlite3_wasm_test_str_hello', 'utf8:free',['i32']);
|
||||
rc = fw(0);
|
||||
T.assert('hello'===rc);
|
||||
rc = fw(1);
|
||||
T.assert(null===rc);
|
||||
|
||||
if(w.bigIntEnabled){
|
||||
w.xWrap.resultAdapter('thrice', (v)=>3n*BigInt(v));
|
||||
w.xWrap.argAdapter('twice', (v)=>2n*BigInt(v));
|
||||
fw = w.xWrap('sqlite3_wasm_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('sqlite3_wasm_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));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}/*WhWasmUtil*/)
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
.t('sqlite3.StructBinder (jaccwabyt)', function(sqlite3){
|
||||
const S = sqlite3, W = S.capi.wasm;
|
||||
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 = S.StructBinder.StructType;
|
||||
const K = S.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 WTStructDesc =
|
||||
W.ctype.structs.filter((e)=>'WasmTestStruct'===e.name)[0];
|
||||
const autoResolvePtr = true /* EXPERIMENTAL */;
|
||||
if(autoResolvePtr){
|
||||
WTStructDesc.members.ppV.signature = 'P';
|
||||
}
|
||||
const WTStruct = S.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('sqlite3_wasm_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){
|
||||
tossQuietly("Testing exception propagation.");
|
||||
}
|
||||
}
|
||||
wts.$v4 = 10; wts.$v8 = 20;
|
||||
wts.$xFunc = W.installFunction(wtsFunc, wts.memberSignature('xFunc'))
|
||||
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();
|
||||
}
|
||||
}/*StructBinder*/)
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
.t('sqlite3.StructBinder part 2', function(sqlite3){
|
||||
// https://www.sqlite.org/c3ref/vfs.html
|
||||
// https://www.sqlite.org/c3ref/io_methods.html
|
||||
const W = 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 = 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);
|
||||
}
|
||||
}/*StructBinder part 2*/)
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
.t('sqlite3.capi.wasm.pstack', function(sqlite3){
|
||||
const w = sqlite3.capi.wasm, P = w.pstack;
|
||||
const isAllocErr = (e)=>e instanceof sqlite3.WasmAllocError;
|
||||
@ -373,7 +1017,9 @@
|
||||
P.restore(stack);
|
||||
}
|
||||
}/*pstack tests*/)
|
||||
;/*end of basic sanity checks*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
;/*end of C/WASM utils checks*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
T.g('sqlite3.oo1 sanity checks')
|
||||
@ -389,6 +1035,8 @@
|
||||
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(
|
||||
@ -436,6 +1084,8 @@
|
||||
T.assert(!st.pointer)
|
||||
.assert(0===this.db.openStatementCount());
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
.t('Table t', function(sqlite3){
|
||||
const db = this.db;
|
||||
let list = [];
|
||||
@ -488,8 +1138,8 @@
|
||||
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');
|
||||
if(capi.wasm.bigIntEnabled && haveWasmCTests()){
|
||||
const mI = capi.wasm.xCall('sqlite3_wasm_test_int64_max');
|
||||
const b = BigInt(Number.MAX_SAFE_INTEGER * 2);
|
||||
T.assert(b === db.selectValue("SELECT "+b)).
|
||||
assert(b === db.selectValue("SELECT ?", b)).
|
||||
@ -521,6 +1171,7 @@
|
||||
}
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
.t('Scalar UDFs', function(sqlite3){
|
||||
const db = this.db;
|
||||
db.createFunction("foo",(pCx,a,b)=>a+b);
|
||||
@ -574,16 +1225,19 @@
|
||||
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 = [];
|
||||
@ -624,9 +1278,10 @@
|
||||
T.mustThrow(()=>db.exec("select * from foo.bar"));
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
.t({
|
||||
name: 'Jaccwabyt-specific int-pointer tests (if compiled in)',
|
||||
predicate: haveJaccwabytTests,
|
||||
name: 'C-side WASM tests (if compiled in)',
|
||||
predicate: haveWasmCTests,
|
||||
test: function(){
|
||||
const w = wasm, db = this.db;
|
||||
const stack = w.scopedAllocPush();
|
||||
@ -636,7 +1291,7 @@
|
||||
try{
|
||||
ptrInt = w.scopedAlloc(4);
|
||||
w.setMemValue(ptrInt,origValue, ptrValType);
|
||||
const cf = w.xGet('jaccwabyt_test_intptr');
|
||||
const cf = w.xGet('sqlite3_wasm_test_intptr');
|
||||
const oldPtrInt = ptrInt;
|
||||
//log('ptrInt',ptrInt);
|
||||
//log('getMemValue(ptrInt)',w.getMemValue(ptrInt));
|
||||
@ -658,14 +1313,14 @@
|
||||
//log("getMemValue(pi64)",v64());
|
||||
T.assert(v64() == o64);
|
||||
//T.assert(o64 === w.getMemValue(pi64, ptrType64));
|
||||
const cf64w = w.xGet('jaccwabyt_test_int64ptr');
|
||||
const cf64w = w.xGet('sqlite3_wasm_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');
|
||||
const biTimes2 = w.xGet('sqlite3_wasm_test_int64_times2');
|
||||
T.assert(BigInt(2 * o64) ===
|
||||
biTimes2(BigInt(o64)/*explicit conv. required to avoid TypeError
|
||||
in the call :/ */));
|
||||
@ -676,13 +1331,13 @@
|
||||
w.setMemValue(pMin, 0, ptrType64);
|
||||
w.setMemValue(pMax, 0, ptrType64);
|
||||
const minMaxI64 = [
|
||||
w.xCall('jaccwabyt_test_int64_min'),
|
||||
w.xCall('jaccwabyt_test_int64_max')
|
||||
w.xCall('sqlite3_wasm_test_int64_min'),
|
||||
w.xCall('sqlite3_wasm_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);
|
||||
w.xCall('sqlite3_wasm_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));
|
||||
@ -733,8 +1388,8 @@
|
||||
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.");
|
||||
if(haveWasmCTests()){
|
||||
log("sqlite3_wasm_test_...() APIs are available.");
|
||||
}
|
||||
TestUtil.runTests(sqlite3);
|
||||
});
|
||||
|
1169
ext/wasm/testing1.js
1169
ext/wasm/testing1.js
File diff suppressed because it is too large
Load Diff
34
manifest
34
manifest
@ -1,5 +1,5 @@
|
||||
C Optimize\sthe\sIS\sNULL\sand\sIS\sNOT\sNULL\soperators\sso\sthat\sthey\savoid\sloading\nlarge\sstrings\sor\sblobs\soff\sof\sdisk\sif\sall\sit\sneeds\sto\sknow\sis\swhether\sor\nnot\sthe\sstring\sor\sblob\sis\sNULL.
|
||||
D 2022-10-13T15:09:44.252
|
||||
C Move\sthe\srest\sof\stesting1.js\sinto\stester1.js\sand\seliminate\sthe\sdependency\son\sjaccwabyt_test.c.\sExtend\sthe\slist\sof\sdefault\sconfig-related\s#defines\sin\ssqlite3-wasm.c\sand\sreorganize\sthem\sfor\smaintainability.
|
||||
D 2022-10-13T16:48:35.302
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -473,7 +473,7 @@ F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
||||
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
|
||||
F ext/wasm/EXPORTED_RUNTIME_METHODS.fiddle 0e88c8cfc3719e4b7e74980d9da664c709e68acf863e48386cda376edfd3bfb0
|
||||
F ext/wasm/GNUmakefile 8ab74ed186a15d956a21b28fa0800b84af2b8a289392ae2dff8126ff033bd3f9
|
||||
F ext/wasm/GNUmakefile 4ec270532b921c7c4b437fbdb06f6a0ce41f3bd874395ce70dbc933c8553efa9
|
||||
F ext/wasm/README.md 1e5b28158b74ab3ffc9d54fcbc020f0bbeb82c2ff8bbd904214c86c70e8a3066
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 89983a8d122c35a90c65ec667844b95a78bcd04f3198a99c1e0c8368c1a0b03a
|
||||
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
|
||||
@ -484,19 +484,19 @@ F ext/wasm/api/post-js-footer.js b64319261d920211b8700004d08b956a6c285f3b0bba814
|
||||
F ext/wasm/api/post-js-header.js 2e5c886398013ba2af88028ecbced1e4b22dc96a86467f1ecc5ba9e64ef90a8b
|
||||
F ext/wasm/api/pre-js.js 2db711eb637991b383fc6b5c0f3df65ec48a7201e5730e304beba8de2d3f9b0b
|
||||
F ext/wasm/api/sqlite3-api-cleanup.js 5d22d1d3818ecacb23bfa223d5970cd0617d8cdbb48c8bc4bbd463f05b021a99
|
||||
F ext/wasm/api/sqlite3-api-glue.js 3b2a43c7b2ceb2b60f5f4a1afefbd93508c2fe0f2e667eea278afe570be4b606
|
||||
F ext/wasm/api/sqlite3-api-oo1.js ac1e08d36bdfb5aa0a2d75b7d4c892fd51819d34c932370c3282810672bcc086
|
||||
F ext/wasm/api/sqlite3-api-glue.js 842dc03783aecc951a543a209523343a6fda9af258fb0bee08e8cc2dc3c4d8ae
|
||||
F ext/wasm/api/sqlite3-api-oo1.js 00f5cfce0989d2e08d7b21765d703c69234245d03a0cce8fcb32ccfcd53ffdbb
|
||||
F ext/wasm/api/sqlite3-api-opfs.js 5a8ab3b76880c8ada8710ca9ba1ca5b160872edfd8bd5322e4f179a7f41cc616
|
||||
F ext/wasm/api/sqlite3-api-prologue.js 5c56056810333974c971f6310c5c9698cf7ca8b06f6d2f1986cec819d0f5bbad
|
||||
F ext/wasm/api/sqlite3-api-prologue.js b7c82a22d50658a48463fa646a23135273bc2cfa843aedda32627ff281c12e4d
|
||||
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
|
||||
F ext/wasm/api/sqlite3-wasm.c 4c131945ced4b08a694d287abcdb066b896d961ef79ee5241805ecc37e83d63a
|
||||
F ext/wasm/batch-runner.html cf1a410c92bad50fcec2ddc71390b4e9df63a6ea1bef12a5163a66a0af4d78d9
|
||||
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 12bd88c69eea1b61649ad9add3ff24f0fbc3b79a7616d74ab3997b7271cd8482
|
||||
F ext/wasm/common/whwasmutil.js bc8522a071f4754af7b50f53807b95f691d2f9e44fc3b3e8c65dff6ef2485c0d
|
||||
F ext/wasm/common/testing.css 53394885077edd3db22d2a0896192334dfc06fb3d1da0b646eb12a332d22f18e
|
||||
F ext/wasm/common/whwasmutil.js 50d2ede0b0fa01c1d467e1801fab79f5e46bb02bcbd2b0232e4fdc6090a47818
|
||||
F ext/wasm/demo-123-worker.html e50b51dc7271b9d3cc830cb7c2fba294d622f56b7acb199f7257d11195a63d49
|
||||
F ext/wasm/demo-123.html 7c239c9951d1b113f9f532969ac039294cf1dcfee2b3ae0a2c1ed2b3d59f8dfa
|
||||
F ext/wasm/demo-123.js d563cf9d725692ccd940c46df1c026d87863e0544942a2ba2015f17fba3f6f74
|
||||
@ -507,11 +507,9 @@ F ext/wasm/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d695
|
||||
F ext/wasm/fiddle/fiddle-worker.js 531859a471924a0ea48afa218e6877f0c164ca324d51e15843ed6ecc1c65c7ee
|
||||
F ext/wasm/fiddle/fiddle.html 5daf54e8f3d7777cbb1ca4f93affe28858dbfff25841cb4ab81d694efed28ec2
|
||||
F ext/wasm/fiddle/fiddle.js 974b995119ac443685d7d94d3b3c58c6a36540e9eb3fed7069d5653284071715
|
||||
F ext/wasm/index.html 63b370619e4f849ac76f1baed435c05edc29dbb6795bc7c1c935561ff667dd27
|
||||
F ext/wasm/index.html 9ae9f9629310ed3ee88901aa14e20195815583806af245da08c2ecb43ced2243
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 0d7f32817456a0f3937fcfd934afeb32154ca33580ab264dab6c285e6dbbd215
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 9aa6951b529a8b29f578ec8f0355713c39584c92cf1708f63ba0cf917cb5b68e
|
||||
F ext/wasm/jaccwabyt/jaccwabyt_test.c 39e4b865a33548f943e2eb9dd0dc8d619a80de05d5300668e9960fff30d0d36f
|
||||
F ext/wasm/jaccwabyt/jaccwabyt_test.exports 5ff001ef975c426ffe88d7d8a6e96ec725e568d2c2307c416902059339c06f19
|
||||
F ext/wasm/scratchpad-wasmfs-main.html 20cf6f1a8f368e70d01e8c17200e3eaa90f1c8e1029186d836d14b83845fbe06
|
||||
F ext/wasm/scratchpad-wasmfs-main.js 1aa32c1035cf1440a226a28fefcbb5762fbbcb020ccbe5895f8736d701695c63
|
||||
F ext/wasm/speedtest1-wasmfs.html bc28eb29b69a73864b8d7aae428448f8b7e1de81d8bfb9bba99541322054dbd0
|
||||
@ -528,11 +526,10 @@ F ext/wasm/test-opfs-vfs.html eb69dda21eb414b8f5e3f7c1cc0f774103cc9c0f87b2d28a33
|
||||
F ext/wasm/test-opfs-vfs.js 56c3d725044c668fa7910451e96c1195d25ad95825f9ac79f747a7759d1973d0
|
||||
F ext/wasm/tester1-worker.html 0af7a22025ff1da72a84765d64f8f221844a57c6e6e314acf3a30f176101fd3f
|
||||
F ext/wasm/tester1.html fde0e0bdeaaa2c39877c749dc86a8c1c306f771c3d75b89a6289a5ed11243e9d
|
||||
F ext/wasm/tester1.js d25cf7615bd39ab9ab4be2f231fecf1fff1378227e695083dc35adc4fdff668e
|
||||
F ext/wasm/tester1.js d6a66fc36c7571b8050314b6d0e93e69cd6def88df14fb3ef2403e7aa244ec36
|
||||
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 2034cf6972ab1506e75e41e532ca7cd3060e194c37edab3ff65d00d8a8af8ba2
|
||||
F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3
|
||||
F ext/wasm/testing2.js 88f40ef3cd8201bdadd120a711c36bbf0ce56cc0eab1d5e7debb71fed7822494
|
||||
F ext/wasm/wasmfs.make 3cce1820006196de140f90f2da4b4ea657083fb5bfee7d125be43f7a85748c8f
|
||||
@ -2034,9 +2031,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 043e76e6166da5cf8e213cce46aaccb1f910e1fdbdb5556576eafb81b3bc5faa 5e9c67ba18b701aabbb0546acdfc532c9e8f0d27fb0a2c899415a5c47096c90b
|
||||
R c0d9c663bdd4b8318254b199c65d7e13
|
||||
T +closed 5e9c67ba18b701aabbb0546acdfc532c9e8f0d27fb0a2c899415a5c47096c90b
|
||||
U drh
|
||||
Z 57cc74128fdf4ddaf1ca461d6df422e4
|
||||
P cb94350185f555c333b628ee846c47bcc9df5f76bb82de569b8322f30dbbe1bc
|
||||
R 32dab828066657d904ede486bb592456
|
||||
U stephan
|
||||
Z 3fd1b23c49b42c2df54d60ffd9b89d7f
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
cb94350185f555c333b628ee846c47bcc9df5f76bb82de569b8322f30dbbe1bc
|
||||
4e2a8aff2dd4b6e148f45184e2523ebe47815257eca97fa3d32bcbf9625f0def
|
Reference in New Issue
Block a user