2 Commits

Author SHA1 Message Date
John Alanbrook
a74231563a further loading 2026-02-08 22:26:13 -06:00
John Alanbrook
6799d90a7d engine is at least running 2026-02-08 11:09:01 -06:00
27 changed files with 39843 additions and 40257 deletions

View File

@@ -49,9 +49,13 @@ function ends_with(str, suffix) {
return search(str, suffix, -length(suffix)) != null
}
print("engine: loading js")
var js = use_embed('js')
print("engine: loading fd")
var fd = use_embed('fd')
print("engine: loaded fd")
print("engine: getting home")
// Get the shop path from HOME environment
var home = os.getenv('HOME') || os.getenv('USERPROFILE')
if (!home) {
@@ -76,34 +80,49 @@ function use_core(path) {
if (use_cache[cache_key])
return use_cache[cache_key];
print(`engine: use_core('${path}') - embed`)
var sym = use_embed(replace(path, '/', '_'))
// Core scripts are in packages/core/
var file_path = core_path + '/' + path + MOD_EXT
if (fd.is_file(file_path)) {
print(`engine: use_core('${path}') - loading script`)
var script_blob = fd.slurp(file_path)
var script = text(script_blob)
var mod = `(function setup_module(use){${script}})`
var fn = mach_eval('core:' + path, mod)
if (fn == null) {
print(`engine: use_core('${path}') - mach_eval returned null!`)
return null
}
print(`engine: use_core('${path}') - calling (fn type: ${typeof(fn)})`)
var result = call(fn,sym, [use_core])
print(`engine: use_core('${path}') - done`)
use_cache[cache_key] = result;
return result;
}
print(`engine: use_core('${path}') - using embed directly`)
use_cache[cache_key] = sym;
return sym;
}
print("engine: loading blob")
var blob = use_core('blob')
print("engine: loaded blob")
function actor() {
}
print("engine: loading actor")
var actor_mod = use_core('actor')
print("engine: loading wota")
var wota = use_core('wota')
print("engine: loading nota")
var nota = use_core('nota')
print("engine: loaded nota")
function is_actor(value) {
return is_object(value) && value[ACTORDATA]
@@ -191,10 +210,15 @@ function actor_die(err)
print("engine: setting up actor_die")
actor_mod.on_exception(actor_die)
print("engine: setting cell args")
print(`engine: init is ${init}`)
_cell.args = init != null ? init : {}
print("engine: args set")
_cell.id = "newguy"
print("engine: id set")
function create_actor(desc = {id:guid()}) {
var actor = {}
@@ -202,19 +226,25 @@ function create_actor(desc = {id:guid()}) {
return actor
}
print("engine: creating $_")
var $_ = {}
print("engine: creating self actor")
$_.self = create_actor()
print("engine: setting os props")
os.use_cache = use_cache
os.global_shop_path = shop_path
os.$_ = $_
print("engine: os props set")
print("engine: loading shop")
var shop = use_core('internal/shop')
print("engine: loaded shop, loading json")
var json = use_core('json')
var time = use_core('time')
print("engine: loading pronto")
var pronto = use_core('pronto')
print("engine: loaded pronto")
var fallback = pronto.fallback
var parallel = pronto.parallel
var race = pronto.race

View File

@@ -75,7 +75,11 @@ static const JSCFunctionListEntry js_kim_funcs[] = {
JSValue js_kim_use(JSContext *js)
{
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_kim_funcs, countof(js_kim_funcs));
return mod;
JSGCRef mod_ref;
JS_PushGCRef(js, &mod_ref);
mod_ref.val = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod_ref.val, js_kim_funcs, countof(js_kim_funcs));
JSValue result = mod_ref.val;
JS_PopGCRef(js, &mod_ref);
return result;
}

View File

@@ -578,8 +578,12 @@ static const JSCFunctionListEntry js_os_funcs[] = {
JSValue js_os_use(JSContext *js) {
JS_NewClassID(&js_dylib_class_id);
JS_NewClass(js, js_dylib_class_id, &js_dylib_class);
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js,mod,js_os_funcs,countof(js_os_funcs));
return mod;
JSGCRef mod_ref;
JS_PushGCRef(js, &mod_ref);
mod_ref.val = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod_ref.val, js_os_funcs, countof(js_os_funcs));
JSValue result = mod_ref.val;
JS_PopGCRef(js, &mod_ref);
return result;
}

View File

@@ -172,7 +172,11 @@ static const JSCFunctionListEntry js_os_funcs[] = {
};
JSValue js_os_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_os_funcs, countof(js_os_funcs));
return mod;
JSGCRef mod_ref;
JS_PushGCRef(js, &mod_ref);
mod_ref.val = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod_ref.val, js_os_funcs, countof(js_os_funcs));
JSValue result = mod_ref.val;
JS_PopGCRef(js, &mod_ref);
return result;
}

View File

@@ -172,7 +172,11 @@ static const JSCFunctionListEntry js_os_funcs[] = {
};
JSValue js_os_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_os_funcs, countof(js_os_funcs));
return mod;
JSGCRef mod_ref;
JS_PushGCRef(js, &mod_ref);
mod_ref.val = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod_ref.val, js_os_funcs, countof(js_os_funcs));
JSValue result = mod_ref.val;
JS_PopGCRef(js, &mod_ref);
return result;
}

View File

@@ -1,5 +1,6 @@
print("shop: starting")
var toml = use('toml')
print("shop: loaded toml")
var json = use('json')
var fd = use('fd')
var http = use('http')
@@ -142,8 +143,10 @@ function package_in_shop(package) {
function abs_path_to_package(package_dir)
{
if (!fd.is_file(package_dir + '/cell.toml'))
throw Error('Not a valid package directory (no cell.toml): ' + package_dir)
if (!fd.is_file(package_dir + '/cell.toml')) {
log.error('Not a valid package directory (no cell.toml): ' + package_dir)
disrupt
}
var packages_prefix = get_packages_dir() + '/'
var core_dir = packages_prefix + core_package
@@ -175,14 +178,15 @@ function abs_path_to_package(package_dir)
return package_dir
// For local directories (e.g., linked targets), read the package name from cell.toml
try {
var toml_pkg = null
var read_toml = function() {
var content = text(fd.slurp(package_dir + '/cell.toml'))
var cfg = toml.decode(content)
if (cfg.package)
return cfg.package
} catch (e) {
// Fall through
}
toml_pkg = cfg.package
} disruption {}
read_toml()
if (toml_pkg) return toml_pkg
return null
}
@@ -299,12 +303,14 @@ Shop.resolve_package_info = function(pkg) {
// Verify if a package name is valid and return status
Shop.verify_package_name = function(pkg) {
if (!pkg) throw Error("Empty package name")
if (pkg == 'local') throw Error("local is not a valid package name")
if (pkg == 'core') throw Error("core is not a valid package name")
if (search(pkg, '://') != null)
throw Error(`Invalid package name: ${pkg}; did you mean ${array(pkg, '://')[1]}?`)
if (!pkg) { log.error("Empty package name"); disrupt }
if (pkg == 'local') { log.error("local is not a valid package name"); disrupt }
if (pkg == 'core') { log.error("core is not a valid package name"); disrupt }
if (search(pkg, '://') != null) {
log.error(`Invalid package name: ${pkg}; did you mean ${array(pkg, '://')[1]}?`)
disrupt
}
}
// Convert module package to download URL
@@ -441,7 +447,7 @@ ${script}
// Resolve module function, hashing it in the process
// path is the exact path to the script file
function resolve_mod_fn(path, pkg) {
if (!fd.is_file(path)) throw Error(`path ${path} is not a file`)
if (!fd.is_file(path)) { log.error(`path ${path} is not a file`); disrupt }
var file_info = Shop.file_info(path)
var file_pkg = file_info.package
@@ -576,32 +582,38 @@ Shop.open_package_dylib = function(pkg) {
var toml_path = pkg_dir + '/cell.toml'
if (fd.is_file(toml_path)) {
try {
var read_toml_disrupted = false
var do_read_toml = function() {
var content = text(fd.slurp(toml_path))
var cfg = toml.decode(content)
if (cfg.dependencies) {
arrfor(array(cfg.dependencies), function(alias, i) {
var dep_pkg = cfg.dependencies[alias]
try {
var open_dep = function() {
Shop.open_package_dylib(dep_pkg)
} catch (dep_e) {
// Dependency dylib load failed, continue with others
}
} disruption {}
open_dep()
})
}
} catch (e) {
// Error reading toml, continue
} disruption {
read_toml_disrupted = true
}
do_read_toml()
}
var dl_path = get_lib_path(pkg)
if (fd.is_file(dl_path)) {
if (!open_dls[dl_path]) {
try {
var open_disrupted = false
var do_open = function() {
open_dls[dl_path] = os.dylib_open(dl_path)
} catch (e) {
} disruption {
open_disrupted = true
}
do_open()
if (open_disrupted) {
dylib_visited[pkg] = false
throw e
disrupt
}
}
}
@@ -836,14 +848,14 @@ function execute_module(info)
// C only
used = call_c_module(c_resolve)
} else {
throw Error(`Module ${info.path} could not be found`)
log.error(`Module ${info.path} could not be found`); disrupt
}
// if (is_function(used))
// throw Error('C module loader returned a function; did you forget to call it?')
if (!used)
throw Error(`Module ${info} returned null`)
log.error(`Module ${info} returned null`); disrupt
// stone(used)
return used
@@ -852,16 +864,20 @@ function execute_module(info)
function get_module(path, package_context) {
var info = resolve_module_info(path, package_context)
if (!info)
throw Error(`Module ${path} could not be found in ${package_context}`)
if (!info) {
log.error(`Module ${path} could not be found in ${package_context}`)
disrupt
}
return execute_module(info)
}
Shop.use = function use(path, package_context) {
var info = resolve_module_info(path, package_context)
if (!info)
throw Error(`Module ${path} could not be found in ${package_context}`)
if (!info) {
log.error(`Module ${path} could not be found in ${package_context}`)
disrupt
}
if (use_cache[info.cache_key])
return use_cache[info.cache_key]
@@ -889,13 +905,20 @@ function fetch_remote_hash(pkg) {
if (!api_url) return null
try {
var result = null
var fetch_disrupted = false
var do_fetch = function() {
var resp = http.fetch(api_url)
return Shop.extract_commit_hash(pkg, text(resp))
} catch (e) {
result = Shop.extract_commit_hash(pkg, text(resp))
} disruption {
fetch_disrupted = true
}
do_fetch()
if (fetch_disrupted) {
log.console("Warning: Could not check for updates for " + pkg)
return null
}
return result
}
// Download a zip for a package at a specific commit and cache it
@@ -909,14 +932,20 @@ function download_zip(pkg, commit_hash) {
return null
}
try {
var zip_blob = http.fetch(download_url)
var zip_blob = null
var dl_disrupted = false
var do_download = function() {
zip_blob = http.fetch(download_url)
fd.slurpwrite(cache_path, zip_blob)
return zip_blob
} catch (e) {
log.error("Download failed for " + pkg + ": " + e)
} disruption {
dl_disrupted = true
}
do_download()
if (dl_disrupted) {
log.error("Download failed for " + pkg)
return null
}
return zip_blob
}
// Get zip from cache, returns null if not cached
@@ -1027,8 +1056,7 @@ Shop.extract = function(pkg) {
var zip_blob = get_package_zip(pkg)
if (!zip_blob)
throw Error("No zip blob available for " + pkg)
if (!zip_blob) { log.error("No zip blob available for " + pkg); disrupt }
// Extract zip for remote package
install_zip(zip_blob, target_dir)
@@ -1113,7 +1141,7 @@ Shop.update = function(pkg) {
function install_zip(zip_blob, target_dir) {
var zip = miniz.read(zip_blob)
if (!zip) throw Error("Failed to read zip archive")
if (!zip) { log.error("Failed to read zip archive"); disrupt }
if (fd.is_link(target_dir)) fd.unlink(target_dir)
if (fd.is_dir(target_dir)) fd.rmdir(target_dir, 1)
@@ -1165,14 +1193,14 @@ Shop.get = function(pkg) {
if (!lock[pkg]) {
var info = Shop.resolve_package_info(pkg)
if (!info) {
throw Error("Invalid package: " + pkg)
log.error("Invalid package: " + pkg); disrupt
}
var commit = null
if (info != 'local') {
commit = fetch_remote_hash(pkg)
if (!commit) {
throw Error("Could not resolve commit for " + pkg)
log.error("Could not resolve commit for " + pkg); disrupt
}
}

View File

@@ -11,12 +11,13 @@ function is_valid_package(dir) {
// Get current package name from cell.toml or null
function get_current_package_name() {
if (!is_valid_package('.')) return null
try {
var pkg_name = 'local'
var do_load = function() {
var config = pkg.load_config(null)
return config.package || 'local'
} catch (e) {
return 'local'
}
if (config.package) pkg_name = config.package
} disruption {}
do_load()
return pkg_name
}
// Get the directory for a package

81
link.cm
View File

@@ -65,13 +65,18 @@ Link.load = function() {
link_cache = {}
return link_cache
}
try {
var load_disrupted = false
var do_load = function() {
var content = text(fd.slurp(path))
var cfg = toml.decode(content)
link_cache = cfg.links || {}
} catch (e) {
log.console("Warning: Failed to load link.toml: " + e)
} disruption {
load_disrupted = true
}
do_load()
if (load_disrupted) {
log.console("Warning: Failed to load link.toml")
link_cache = {}
}
return link_cache
@@ -90,14 +95,16 @@ Link.add = function(canonical, target, shop) {
// Validate canonical package exists in shop
var lock = shop.load_lock()
if (!lock[canonical]) {
throw Error('Package ' + canonical + ' is not installed. Install it first with: cell get ' + canonical)
log.error('Package ' + canonical + ' is not installed. Install it first with: cell get ' + canonical)
disrupt
}
// Validate target is a valid package
if (starts_with(target, '/')) {
// Local path - must have cell.toml
if (!fd.is_file(target + '/cell.toml')) {
throw Error('Target ' + target + ' is not a valid package (no cell.toml)')
log.error('Target ' + target + ' is not a valid package (no cell.toml)')
disrupt
}
} else {
// Remote package target - ensure it's installed
@@ -116,7 +123,8 @@ Link.add = function(canonical, target, shop) {
var target_path = starts_with(target, '/') ? target : get_package_abs_dir(target)
var toml_path = target_path + '/cell.toml'
if (fd.is_file(toml_path)) {
try {
var read_deps_disrupted = false
var do_read_deps = function() {
var content = text(fd.slurp(toml_path))
var cfg = toml.decode(content)
if (cfg.dependencies) {
@@ -128,16 +136,24 @@ Link.add = function(canonical, target, shop) {
return
}
// Install the dependency if not already in shop
try {
var install_disrupted = false
var do_install = function() {
shop.get(dep_locator)
shop.extract(dep_locator)
} catch (e) {
log.console(` Warning: Could not install dependency ${dep_locator}: ${e.message}`)
log.error(e)
} disruption {
install_disrupted = true
}
do_install()
if (install_disrupted) {
log.console(` Warning: Could not install dependency ${dep_locator}`)
}
})
}
} catch (e) {
} disruption {
read_deps_disrupted = true
}
do_read_deps()
if (read_deps_disrupted) {
log.console(` Warning: Could not read dependencies from ${toml_path}`)
}
}
@@ -149,14 +165,14 @@ Link.add = function(canonical, target, shop) {
Link.remove = function(canonical) {
var links = Link.load()
if (!links[canonical]) return false
// Remove the symlink if it exists
var target_dir = get_package_abs_dir(canonical)
if (fd.is_link(target_dir)) {
fd.unlink(target_dir)
log.console("Removed symlink at " + target_dir)
}
delete links[canonical]
Link.save(links)
log.console("Unlinked " + canonical)
@@ -172,7 +188,7 @@ Link.clear = function() {
fd.unlink(target_dir)
}
})
Link.save({})
log.console("Cleared all links")
return true
@@ -186,25 +202,25 @@ Link.sync_one = function(canonical, target, shop) {
// Ensure parent directories exist
var parent = fd.dirname(target_dir)
ensure_dir(parent)
// Check current state
var current_link = null
if (fd.is_link(target_dir)) {
current_link = fd.readlink(target_dir)
}
// If already correctly linked, nothing to do
if (current_link == link_target) {
return true
}
// Remove existing file/dir/link
if (fd.is_link(target_dir)) {
fd.unlink(target_dir)
} else if (fd.is_dir(target_dir)) {
fd.rmdir(target_dir, 1)
}
// Create symlink
fd.symlink(link_target, target_dir)
return true
@@ -218,7 +234,9 @@ Link.sync_all = function(shop) {
arrfor(array(links), function(canonical) {
var target = links[canonical]
try {
var sync_disrupted = false
var sync_error_msg = ""
var do_sync = function() {
// Validate target exists
var link_target = resolve_link_target(target)
if (!fd.is_dir(link_target)) {
@@ -234,7 +252,8 @@ Link.sync_all = function(shop) {
// Install dependencies of the linked package
var toml_path = link_target + '/cell.toml'
try {
var read_deps_disrupted = false
var do_read_deps = function() {
var content = text(fd.slurp(toml_path))
var cfg = toml.decode(content)
if (cfg.dependencies) {
@@ -245,21 +264,25 @@ Link.sync_all = function(shop) {
return
}
// Install the dependency if not already in shop
try {
var install_dep = function() {
shop.get(dep_locator)
shop.extract(dep_locator)
} catch (e) {
// Silently continue - dependency may already be installed
}
} disruption {}
install_dep()
})
}
} catch (e) {
// Could not read dependencies - continue anyway
} disruption {
read_deps_disrupted = true
}
do_read_deps()
count++
} catch (e) {
push(errors, canonical + ': ' + e.message)
} disruption {
sync_disrupted = true
}
do_sync()
if (sync_disrupted) {
push(errors, canonical + ': sync failed')
}
})

View File

@@ -44,12 +44,7 @@ src += [ # core
'wildmatch.c',
'qjs_actor.c',
'miniz.c',
'runtime.c',
'cell_js.c',
'tokenize.c',
'parse.c',
'mach.c',
'mcode.c',
'quickjs.c',
'libregexp.c', 'libunicode.c', 'cutils.c', 'dtoa.c'
]

View File

@@ -51,7 +51,8 @@ package.load_config = function(name)
return config_cache[config_path]
if (!fd.is_file(config_path)) {
throw Error(`${config_path} does not exist`)
log.error(`${config_path} does not exist`)
disrupt
}
var content = text(fd.slurp(config_path))
@@ -158,19 +159,20 @@ package.split_alias = function(name, path)
var parts = array(path, '/')
var first_part = parts[0]
try {
var split_result = null
var do_split = function() {
var config = package.load_config(name)
if (!config) return null
if (!config) return
var deps = config.dependencies
if (deps && deps[first_part]) {
var dep_locator = deps[first_part]
var remaining_path = text(array(parts, 1), '/')
return { package: dep_locator, path: remaining_path }
split_result = { package: dep_locator, path: remaining_path }
}
} catch (e) {
// Config doesn't exist or couldn't be loaded
}
} disruption {}
do_split()
if (split_result) return split_result
return null
}

View File

@@ -3,6 +3,8 @@
// Based on Douglas Crockford's parseq, adapted for Cell.
// Time is in seconds.
function safe_call(fn, arg) { fn(arg) } disruption {}
function make_reason(factory, excuse, evidence) {
def reason = Error(`pronto.${factory}${excuse ? ': ' + excuse : ''}`)
reason.evidence = evidence
@@ -15,12 +17,12 @@ function is_requestor(fn) {
function check_requestors(list, factory) {
if (!is_array(list) || some(list, r => !is_requestor(r)))
throw make_reason(factory, 'Bad requestor array.', list)
disrupt
}
function check_callback(cb, factory) {
if (!is_function(cb) || length(cb) != 2)
throw make_reason(factory, 'Not a callback.', cb)
disrupt
}
// fallback(requestor_array)
@@ -28,7 +30,7 @@ function check_callback(cb, factory) {
function fallback(requestor_array) {
def factory = 'fallback'
if (!is_array(requestor_array) || length(requestor_array) == 0)
throw make_reason(factory, 'Empty requestor array.')
disrupt
check_requestors(requestor_array, factory)
return function fallback_requestor(callback, value) {
@@ -40,7 +42,7 @@ function fallback(requestor_array) {
function cancel(reason) {
cancelled = true
if (current_cancel) {
try { current_cancel(reason) } catch (_) {}
safe_call(current_cancel, reason)
current_cancel = null
}
}
@@ -55,7 +57,8 @@ function fallback(requestor_array) {
def requestor = requestor_array[index]
index += 1
try {
var requestor_disrupted = false
var start_requestor = function() {
current_cancel = requestor(function(val, reason) {
if (cancelled) return
current_cancel = null
@@ -65,7 +68,11 @@ function fallback(requestor_array) {
try_next()
}
}, value)
} catch (ex) {
} disruption {
requestor_disrupted = true
}
start_requestor()
if (requestor_disrupted) {
try_next()
}
}
@@ -80,7 +87,7 @@ function fallback(requestor_array) {
function parallel(requestor_array, throttle, need) {
def factory = 'parallel'
if (!is_array(requestor_array))
throw make_reason(factory, 'Not an array.', requestor_array)
disrupt
check_requestors(requestor_array, factory)
def length = length(requestor_array)
@@ -89,10 +96,10 @@ function parallel(requestor_array, throttle, need) {
if (need == null) need = length
if (!is_number(need) || need < 0 || need > length)
throw make_reason(factory, 'Bad need.', need)
disrupt
if (throttle != null && (!is_number(throttle) || throttle < 1))
throw make_reason(factory, 'Bad throttle.', throttle)
disrupt
return function parallel_requestor(callback, value) {
check_callback(callback, factory)
@@ -107,7 +114,8 @@ function parallel(requestor_array, throttle, need) {
if (finished) return
finished = true
arrfor(cancel_list, c => {
try { if (is_function(c)) c(reason) } catch (_) {}
var do_cancel = function() { if (is_function(c)) c(reason) } disruption {}
do_cancel()
})
}
@@ -117,7 +125,9 @@ function parallel(requestor_array, throttle, need) {
next_index += 1
def requestor = requestor_array[idx]
try {
var requestor_disrupted = false
var requestor_ex = null
var run_requestor = function() {
cancel_list[idx] = requestor(function(val, reason) {
if (finished) return
cancel_list[idx] = null
@@ -142,11 +152,15 @@ function parallel(requestor_array, throttle, need) {
start_one()
}, value)
} catch (ex) {
} disruption {
requestor_disrupted = true
}
run_requestor()
if (requestor_disrupted) {
failures += 1
if (failures > length - need) {
cancel(ex)
callback(null, ex)
cancel(requestor_ex)
callback(null, requestor_ex)
return
}
start_one()
@@ -166,16 +180,16 @@ function parallel(requestor_array, throttle, need) {
function race(requestor_array, throttle, need) {
def factory = 'race'
if (!is_array(requestor_array) || length(requestor_array) == 0)
throw make_reason(factory, 'Empty requestor array.')
disrupt
check_requestors(requestor_array, factory)
def length = length(requestor_array)
if (need == null) need = 1
if (!is_number(need) || need < 1 || need > length)
throw make_reason(factory, 'Bad need.', need)
disrupt
if (throttle != null && (!is_number(throttle) || throttle < 1))
throw make_reason(factory, 'Bad throttle.', throttle)
disrupt
return function race_requestor(callback, value) {
check_callback(callback, factory)
@@ -190,7 +204,8 @@ function race(requestor_array, throttle, need) {
if (finished) return
finished = true
arrfor(cancel_list, c => {
try { if (is_function(c)) c(reason) } catch (_) {}
var do_cancel = function() { if (is_function(c)) c(reason) } disruption {}
do_cancel()
})
}
@@ -200,7 +215,9 @@ function race(requestor_array, throttle, need) {
next_index += 1
def requestor = requestor_array[idx]
try {
var requestor_disrupted = false
var requestor_ex = null
var run_requestor = function() {
cancel_list[idx] = requestor(function(val, reason) {
if (finished) return
cancel_list[idx] = null
@@ -228,11 +245,15 @@ function race(requestor_array, throttle, need) {
start_one()
}, value)
} catch (ex) {
} disruption {
requestor_disrupted = true
}
run_requestor()
if (requestor_disrupted) {
failures += 1
if (failures > length - need) {
cancel(ex)
callback(null, ex)
cancel(requestor_ex)
callback(null, requestor_ex)
return
}
start_one()
@@ -251,7 +272,7 @@ function race(requestor_array, throttle, need) {
function sequence(requestor_array) {
def factory = 'sequence'
if (!is_array(requestor_array))
throw make_reason(factory, 'Not an array.', requestor_array)
disrupt
check_requestors(requestor_array, factory)
if (length(requestor_array) == 0)
@@ -266,7 +287,7 @@ function sequence(requestor_array) {
function cancel(reason) {
cancelled = true
if (current_cancel) {
try { current_cancel(reason) } catch (_) {}
safe_call(current_cancel, reason)
current_cancel = null
}
}
@@ -281,7 +302,9 @@ function sequence(requestor_array) {
def requestor = requestor_array[index]
index += 1
try {
var requestor_disrupted = false
var requestor_ex = null
var run_requestor = function() {
current_cancel = requestor(function(result, reason) {
if (cancelled) return
current_cancel = null
@@ -291,8 +314,12 @@ function sequence(requestor_array) {
run_next(result)
}
}, val)
} catch (ex) {
callback(null, ex)
} disruption {
requestor_disrupted = true
}
run_requestor()
if (requestor_disrupted) {
callback(null, requestor_ex)
}
}
@@ -306,15 +333,21 @@ function sequence(requestor_array) {
function requestorize(unary) {
def factory = 'requestorize'
if (!is_function(unary))
throw make_reason(factory, 'Not a function.', unary)
disrupt
return function requestorized(callback, value) {
check_callback(callback, factory)
try {
var call_disrupted = false
var call_ex = null
var do_call = function() {
def result = unary(value)
callback(result == null ? true : result)
} catch (ex) {
callback(null, ex)
} disruption {
call_disrupted = true
}
do_call()
if (call_disrupted) {
callback(null, call_ex)
}
}
}

View File

@@ -210,31 +210,54 @@ void script_startup(cell_rt *prt)
return;
}
// Create hidden environment
JSValue hidden_env = JS_NewObject(js);
JS_SetPropertyStr(js, hidden_env, "os", js_os_use(js));
JS_SetPropertyStr(js, hidden_env, "json", js_json_use(js));
JS_SetPropertyStr(js, hidden_env, "nota", js_nota_use(js));
JS_SetPropertyStr(js, hidden_env, "wota", js_wota_use(js));
// Create hidden environment (GC-protected to survive allocations)
JSGCRef env_ref;
JS_PushGCRef(js, &env_ref);
env_ref.val = JS_NewObject(js);
// Create modules with GC rooting
JSGCRef os_ref, json_ref, nota_ref, wota_ref;
JS_PushGCRef(js, &os_ref);
JS_PushGCRef(js, &json_ref);
JS_PushGCRef(js, &nota_ref);
JS_PushGCRef(js, &wota_ref);
os_ref.val = js_os_use(js);
json_ref.val = js_json_use(js);
nota_ref.val = js_nota_use(js);
wota_ref.val = js_wota_use(js);
// Set properties on env (SetPropertyStr internally roots its args)
JS_SetPropertyStr(js, env_ref.val, "os", os_ref.val);
JS_SetPropertyStr(js, env_ref.val, "json", json_ref.val);
JS_SetPropertyStr(js, env_ref.val, "nota", nota_ref.val);
JS_SetPropertyStr(js, env_ref.val, "wota", wota_ref.val);
JS_PopGCRef(js, &wota_ref);
JS_PopGCRef(js, &nota_ref);
JS_PopGCRef(js, &json_ref);
JS_PopGCRef(js, &os_ref);
crt->actor_sym_ref.val = JS_NewObject(js);
JS_SetPropertyStr(js, hidden_env, "actorsym", JS_DupValue(js, crt->actor_sym_ref.val));
JS_SetPropertyStr(js, env_ref.val, "actorsym", JS_DupValue(js, crt->actor_sym_ref.val));
// Always set init (even if null)
if (crt->init_wota) {
JS_SetPropertyStr(js, hidden_env, "init", wota2value(js, crt->init_wota));
JSValue init_val = wota2value(js, crt->init_wota);
JS_SetPropertyStr(js, env_ref.val, "init", init_val);
free(crt->init_wota);
crt->init_wota = NULL;
} else {
JS_SetPropertyStr(js, hidden_env, "init", JS_NULL);
JS_SetPropertyStr(js, env_ref.val, "init", JS_NULL);
}
if (core_path) {
JS_SetPropertyStr(js, hidden_env, "core_path", JS_NewString(js, core_path));
JSValue path_val = JS_NewString(js, core_path);
JS_SetPropertyStr(js, env_ref.val, "core_path", path_val);
}
// Stone the environment
hidden_env = JS_Stone(js, hidden_env);
JSValue hidden_env = JS_Stone(js, env_ref.val);
JS_PopGCRef(js, &env_ref);
// Run through MACH VM
crt->state = ACTOR_RUNNING;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

38487
source/quickjs.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

92
test.ce
View File

@@ -29,12 +29,13 @@ function is_valid_package(dir) {
// Get current package name from cell.toml or null
function get_current_package_name() {
if (!is_valid_package('.')) return null
try {
var pkg_name = 'local'
var do_load = function() {
var config = pkg.load_config(null)
return config.package || 'local'
} catch (e) {
return 'local'
}
if (config.package) pkg_name = config.package
} disruption {}
do_load()
return pkg_name
}
// Parse arguments
@@ -229,21 +230,48 @@ function spawn_actor_test(test_info) {
actor: null
}
try {
var spawn_disrupted = false
var do_spawn = function() {
// Spawn the actor test - it should send back results
var actor_path = text(test_info.path, 0, -3) // remove .ce
entry.actor = $start(actor_path)
push(pending_actor_tests, entry)
} catch (e) {
} disruption {
spawn_disrupted = true
}
do_spawn()
if (spawn_disrupted) {
entry.status = "failed"
entry.error = { message: `Failed to spawn actor: ${e}` }
entry.error = { message: `Failed to spawn actor: ${test_name}` }
entry.duration_ns = 0
push(actor_test_results, entry)
log.console(` FAIL ${test_name}: `)
log.error(e)
log.console(` FAIL ${test_name}`)
}
}
// Test runner with disruption support
var test_passed = true
var test_error_msg = ""
var test_error_stack = ""
var run_test = function(fn) {
test_passed = true
test_error_msg = ""
test_error_stack = ""
var ret = fn()
if (is_text(ret)) {
test_passed = false
test_error_msg = ret
} else if (ret && (is_text(ret.message) || is_proto(ret, Error))) {
test_passed = false
test_error_msg = ret.message || text(ret)
if (ret.stack) test_error_stack = ret.stack
}
} disruption {
test_passed = false
if (test_error_msg == "") test_error_msg = "test disrupted"
}
function run_tests(package_name, specific_test) {
var prefix = get_pkg_dir(package_name)
var tests_dir = prefix + '/tests'
@@ -293,7 +321,9 @@ function run_tests(package_name, specific_test) {
failed: 0
}
try {
var load_disrupted = false
var load_error_msg = ""
var do_load = function() {
var test_mod
// For local packages (null), use the current directory as package context
var use_pkg = package_name ? package_name : fd.realpath('.')
@@ -322,34 +352,23 @@ function run_tests(package_name, specific_test) {
}
var start_time = time.number()
try {
var ret = t.fn()
if (is_text(ret)) {
throw Error(ret)
} else if (ret && (is_text(ret.message) || is_proto(ret, Error))) {
throw ret
}
run_test(t.fn)
if (test_passed) {
test_entry.status = "passed"
log.console(` PASS ${t.name}`)
pkg_result.passed++
file_result.passed++
} catch (e) {
} else {
test_entry.status = "failed"
test_entry.error = {
message: e,
stack: e.stack || ""
message: test_error_msg
}
if (e.name) test_entry.error.name = e.name
if (test_error_stack) test_entry.error.stack = test_error_stack
if (is_object(e) && e.message) {
test_entry.error.message = e.message
}
log.console(` FAIL ${t.name} ${test_entry.error.message}`)
if (test_entry.error.stack) {
log.console(` ${text(array(test_entry.error.stack, '\n'), '\n ')}`)
log.console(` FAIL ${t.name} ${test_error_msg}`)
if (test_error_stack) {
log.console(` ${text(array(test_error_stack, '\n'), '\n ')}`)
}
pkg_result.failed++
@@ -365,15 +384,18 @@ function run_tests(package_name, specific_test) {
}
}
}
} catch (e) {
log.console(` Error loading ${f}: ${e}`)
var test_entry = {
} disruption {
load_disrupted = true
}
do_load()
if (load_disrupted) {
log.console(` Error loading ${f}`)
var test_entry = {
package: pkg_result.package,
test: "load_module",
status: "failed",
duration_ns: 0,
error: { message: `Error loading module: ${e}` }
error: { message: `Error loading module: ${f}` }
}
push(file_result.tests, test_entry)
pkg_result.failed++

View File

@@ -4,64 +4,65 @@ var os = use('os');
function assert(condition, message) {
if (!condition) {
throw Error(message || "Assertion failed");
return message || "Assertion failed"
}
}
function assertEqual(actual, expected, message) {
if (actual != expected) {
throw Error(message || "Expected " + expected + ", got " + actual);
return message || "Expected " + expected + ", got " + actual
}
}
function should_disrupt(fn) {
var caught = false
var wrapper = function() { fn() } disruption { caught = true }
wrapper()
return caught
}
return {
test_create_empty_blob: function() {
var b = Blob();
assertEqual(length(b), 0, "Empty blob should have length 0");
return assertEqual(length(b), 0, "Empty blob should have length 0")
},
test_create_blob_with_capacity: function() {
var b = Blob(100);
assertEqual(length(b), 0, "New blob with capacity should still have length 0");
return assertEqual(length(b), 0, "New blob with capacity should still have length 0")
},
test_write_and_read_single_bit: function() {
var b = Blob();
b.write_bit(true);
b.write_bit(false);
b.write_bit(1);
b.write_bit(0);
assertEqual(length(b), 4, "Should have 4 bits after writing");
var r = assertEqual(length(b), 4, "Should have 4 bits after writing")
if (r) return r
stone(b);
assertEqual(b.read_logical(0), true, "First bit should be true");
assertEqual(b.read_logical(1), false, "Second bit should be false");
assertEqual(b.read_logical(2), true, "Third bit should be true (1)");
assertEqual(b.read_logical(3), false, "Fourth bit should be false (0)");
r = assertEqual(b.read_logical(0), true, "First bit should be true")
if (r) return r
r = assertEqual(b.read_logical(1), false, "Second bit should be false")
if (r) return r
r = assertEqual(b.read_logical(2), true, "Third bit should be true (1)")
if (r) return r
return assertEqual(b.read_logical(3), false, "Fourth bit should be false (0)")
},
test_out_of_range_read_throws_error: function() {
var b = Blob();
b.write_bit(true);
stone(b);
var threw = false;
try {
b.read_logical(100);
} catch (e) {
threw = true;
}
assert(threw, "Out of range read should throw");
threw = false;
try {
b.read_logical(-1);
} catch (e) {
threw = true;
}
assert(threw, "Negative index read should throw");
if (!should_disrupt(function() { b.read_logical(100) }))
return "Out of range read should disrupt"
if (!should_disrupt(function() { b.read_logical(-1) }))
return "Negative index read should disrupt"
},
test_write_and_read_numbers: function() {
var b = Blob();
b.write_number(3.14159);
@@ -69,41 +70,48 @@ return {
b.write_number(0);
b.write_number(1e20);
stone(b);
assertEqual(b.read_number(0), 3.14159, "First number should match");
assertEqual(b.read_number(64), -42, "Second number should match");
assertEqual(b.read_number(128), 0, "Third number should match");
assertEqual(b.read_number(192), 1e20, "Fourth number should match");
var r = assertEqual(b.read_number(0), 3.14159, "First number should match")
if (r) return r
r = assertEqual(b.read_number(64), -42, "Second number should match")
if (r) return r
r = assertEqual(b.read_number(128), 0, "Third number should match")
if (r) return r
return assertEqual(b.read_number(192), 1e20, "Fourth number should match")
},
test_write_and_read_text: function() {
var b = Blob();
b.write_text("Hello");
b.write_text("World");
b.write_text("🎉");
stone(b);
assertEqual(b.read_text(0), "Hello", "First text should match");
return assertEqual(b.read_text(0), "Hello", "First text should match")
},
test_write_and_read_blobs: function() {
var b1 = Blob();
b1.write_bit(true);
b1.write_bit(false);
b1.write_bit(true);
var b2 = Blob(10);
b2.write_blob(b1);
b2.write_bit(false);
assertEqual(length(b2), 4, "Combined blob should have 4 bits");
var r = assertEqual(length(b2), 4, "Combined blob should have 4 bits")
if (r) return r
stone(b2);
assertEqual(b2.read_logical(0), true);
assertEqual(b2.read_logical(1), false);
assertEqual(b2.read_logical(2), true);
assertEqual(b2.read_logical(3), false);
r = assertEqual(b2.read_logical(0), true)
if (r) return r
r = assertEqual(b2.read_logical(1), false)
if (r) return r
r = assertEqual(b2.read_logical(2), true)
if (r) return r
return assertEqual(b2.read_logical(3), false)
},
test_blob_copy_constructor: function() {
var b1 = Blob();
b1.write_bit(true);
@@ -111,249 +119,219 @@ return {
b1.write_bit(true);
b1.write_bit(true);
stone(b1);
var b2 = Blob(b1);
stone(b2);
assertEqual(length(b2), 4, "Copied blob should have same length");
assertEqual(b2.read_logical(0), true);
assertEqual(b2.read_logical(3), true);
var r = assertEqual(length(b2), 4, "Copied blob should have same length")
if (r) return r
r = assertEqual(b2.read_logical(0), true)
if (r) return r
return assertEqual(b2.read_logical(3), true)
},
test_blob_partial_copy_constructor: function() {
var b1 = Blob();
for (var i = 0; i < 10; i++) {
b1.write_bit(i % 2 == 0);
}
stone(b1);
var b2 = Blob(b1, 2, 7);
stone(b2);
assertEqual(length(b2), 5, "Partial copy should have 5 bits");
assertEqual(b2.read_logical(0), true);
assertEqual(b2.read_logical(2), true);
var r = assertEqual(length(b2), 5, "Partial copy should have 5 bits")
if (r) return r
r = assertEqual(b2.read_logical(0), true)
if (r) return r
return assertEqual(b2.read_logical(2), true)
},
test_create_blob_with_fill: function() {
var b1 = Blob(8, true);
var b2 = Blob(8, false);
stone(b1);
stone(b2);
for (var i = 0; i < 8; i++) {
assertEqual(b1.read_logical(i), true, "Bit " + i + " should be true");
assertEqual(b2.read_logical(i), false, "Bit " + i + " should be false");
var r = assertEqual(b1.read_logical(i), true, "Bit " + i + " should be true")
if (r) return r
r = assertEqual(b2.read_logical(i), false, "Bit " + i + " should be false")
if (r) return r
}
},
test_create_blob_with_random_function: function() {
var sequence = [true, false, true, true, false];
var index = 0;
var b = Blob(5, function() {
return sequence[index++] ? 1 : 0;
});
stone(b);
for (var i = 0; i < 5; i++) {
assertEqual(b.read_logical(i), sequence[i], "Bit " + i + " should match sequence");
var r = assertEqual(b.read_logical(i), sequence[i], "Bit " + i + " should match sequence")
if (r) return r
}
},
test_write_pad_and_check_padding: function() {
var b = Blob();
b.write_bit(true);
b.write_bit(false);
b.write_bit(true);
b.write_pad(8);
assertEqual(length(b), 8, "Should be padded to 8 bits");
var r = assertEqual(length(b), 8, "Should be padded to 8 bits")
if (r) return r
stone(b);
assert(b['pad?'](3, 8), "Should detect valid padding at position 3");
assert(!b['pad?'](2, 8), "Should detect invalid padding at position 2");
r = assert(b['pad?'](3, 8), "Should detect valid padding at position 3")
if (r) return r
return assert(!b['pad?'](2, 8), "Should detect invalid padding at position 2")
},
test_read_blob_from_stone_blob: function() {
var b1 = Blob();
for (var i = 0; i < 16; i++) {
b1.write_bit(i % 3 == 0);
}
stone(b1);
var b2 = b1.read_blob(4, 12);
stone(b2);
assertEqual(length(b2), 8, "Read blob should have 8 bits");
assertEqual(b2.read_logical(2), true);
assertEqual(b2.read_logical(5), true);
var r = assertEqual(length(b2), 8, "Read blob should have 8 bits")
if (r) return r
r = assertEqual(b2.read_logical(2), true)
if (r) return r
return assertEqual(b2.read_logical(5), true)
},
test_stone_blob_is_immutable: function() {
var b = Blob();
b.write_bit(true);
stone(b);
var threw = false;
try {
b.write_bit(false);
} catch (e) {
threw = true;
}
assert(threw, "Writing to stone blob should throw error");
if (!should_disrupt(function() { b.write_bit(false) }))
return "Writing to stone blob should disrupt"
},
test_multiple_stone_calls_are_safe: function() {
var b = Blob();
b.write_bit(true);
assert(!stone.p(b), "Blob should not be a stone before stone() call");
var r = assert(!stone.p(b), "Blob should not be a stone before stone() call")
if (r) return r
stone(b);
assert(stone.p(b), "Blob should be a stone after stone() call");
r = assert(stone.p(b), "Blob should be a stone after stone() call")
if (r) return r
stone(b);
assertEqual(b.read_logical(0), true, "Blob data should remain intact");
assert(b.stone == null, "blob.stone should not be available as a method");
r = assertEqual(b.read_logical(0), true, "Blob data should remain intact")
if (r) return r
return assert(b.stone == null, "blob.stone should not be available as a method")
},
test_invalid_constructor_arguments: function() {
var threw = false;
try {
var b = Blob("invalid");
} catch (e) {
threw = true;
}
assert(threw, "Invalid constructor arguments should throw");
if (!should_disrupt(function() { Blob("invalid") }))
return "Invalid constructor arguments should disrupt"
},
test_write_bit_validation: function() {
var b = Blob();
b.write_bit(0);
b.write_bit(1);
var threw = false;
try {
b.write_bit(2);
} catch (e) {
threw = true;
}
assert(threw, "write_bit with value 2 should throw");
if (!should_disrupt(function() { b.write_bit(2) }))
return "write_bit with value 2 should disrupt"
},
test_complex_data_round_trip: function() {
var b = Blob();
b.write_text("Test");
b.write_number(123.456);
b.write_bit(true);
b.write_bit(false);
b.write_number(-999.999);
var originalLength = length(b);
stone(b);
var b2 = Blob(b);
stone(b2);
assertEqual(length(b2), originalLength, "Copy should have same length");
assertEqual(b2.read_text(0), "Test", "First text should match");
var r = assertEqual(length(b2), originalLength, "Copy should have same length")
if (r) return r
return assertEqual(b2.read_text(0), "Test", "First text should match")
},
test_zero_capacity_blob: function() {
var b = Blob(0);
assertEqual(length(b), 0, "Zero capacity blob should have length 0");
var r = assertEqual(length(b), 0, "Zero capacity blob should have length 0")
if (r) return r
b.write_bit(true);
assertEqual(length(b), 1, "Should expand when writing");
return assertEqual(length(b), 1, "Should expand when writing")
},
test_large_blob_handling: function() {
var b = Blob();
var testSize = 1000;
for (var i = 0; i < testSize; i++) {
b.write_bit(i % 7 == 0);
}
assertEqual(length(b), testSize, "Should have " + testSize + " bits");
var r = assertEqual(length(b), testSize, "Should have " + testSize + " bits")
if (r) return r
stone(b);
assertEqual(b.read_logical(0), true, "Bit 0 should be true");
assertEqual(b.read_logical(7), true, "Bit 7 should be true");
assertEqual(b.read_logical(14), true, "Bit 14 should be true");
assertEqual(b.read_logical(15), false, "Bit 15 should be false");
r = assertEqual(b.read_logical(0), true, "Bit 0 should be true")
if (r) return r
r = assertEqual(b.read_logical(7), true, "Bit 7 should be true")
if (r) return r
r = assertEqual(b.read_logical(14), true, "Bit 14 should be true")
if (r) return r
return assertEqual(b.read_logical(15), false, "Bit 15 should be false")
},
test_non_stone_blob_read_methods_should_throw: function() {
var b = Blob();
b.write_bit(true);
b.write_number(42);
b.write_text("test");
var threw = false;
try {
b.read_logical(0);
} catch (e) {
threw = true;
}
assert(threw, "read_logical on non-stone blob should throw");
threw = false;
try {
b.read_number(0);
} catch (e) {
threw = true;
}
assert(threw, "read_number on non-stone blob should throw");
threw = false;
try {
b.read_text(0);
} catch (e) {
threw = true;
}
assert(threw, "read_text on non-stone blob should throw");
threw = false;
try {
b.read_blob(0, 10);
} catch (e) {
threw = true;
}
assert(threw, "read_blob on non-stone blob should throw");
threw = false;
try {
b['pad?'](0, 8);
} catch (e) {
threw = true;
}
assert(threw, "pad? on non-stone blob should throw");
if (!should_disrupt(function() { b.read_logical(0) }))
return "read_logical on non-stone blob should disrupt"
if (!should_disrupt(function() { b.read_number(0) }))
return "read_number on non-stone blob should disrupt"
if (!should_disrupt(function() { b.read_text(0) }))
return "read_text on non-stone blob should disrupt"
if (!should_disrupt(function() { b.read_blob(0, 10) }))
return "read_blob on non-stone blob should disrupt"
if (!should_disrupt(function() { b['pad?'](0, 8) }))
return "pad? on non-stone blob should disrupt"
},
test_empty_text_write_and_read: function() {
var b = Blob();
b.write_text("");
stone(b);
assertEqual(b.read_text(0), "", "Empty string should round-trip");
return assertEqual(b.read_text(0), "", "Empty string should round-trip")
},
test_invalid_read_positions: function() {
var b = Blob();
b.write_number(42);
stone(b);
var threw = false;
try {
b.read_number(-10);
} catch (e) {
threw = true;
}
assert(threw, "Negative position should throw");
threw = false;
try {
b.read_number(1000);
} catch (e) {
threw = true;
}
assert(threw, "Position beyond length should throw");
if (!should_disrupt(function() { b.read_number(-10) }))
return "Negative position should disrupt"
if (!should_disrupt(function() { b.read_number(1000) }))
return "Position beyond length should disrupt"
}
}

View File

@@ -1,5 +1,5 @@
return {
test_disrupt: function() {
throw 1
disrupt
}
}

View File

@@ -2,85 +2,101 @@ var fd = use("fd")
var miniz = use("miniz")
var utf8 = use("utf8")
function safe_unlink(p) { fd.unlink(p) } disruption {}
return {
create_and_read_zip: function() {
var ZIP_PATH = "miniz_test.zip"
var SOURCE_PATH = "miniz_source.txt"
var ENTRY_PATH = "sample/hello.txt"
var PAYLOAD = "Miniz integration test payload."
function write_text_file(path, text) {
var handle = fd.open(path, "w")
fd.write(handle, text)
fd.close(handle)
}
try {
var error_msg = null
var do_test = function() {
write_text_file(SOURCE_PATH, PAYLOAD)
var source_blob = fd.slurp(SOURCE_PATH)
var writer = miniz.write(ZIP_PATH)
writer.add_file(ENTRY_PATH, source_blob)
writer = null
var zip_blob = fd.slurp(ZIP_PATH)
var reader = miniz.read(zip_blob)
if (!reader.exists(ENTRY_PATH))
throw "entry missing in archive"
var extracted_blob = reader.slurp(ENTRY_PATH)
var extracted_text = utf8.decode(extracted_blob)
if (extracted_text != PAYLOAD)
throw "extracted text mismatch"
} finally {
try { fd.unlink(ZIP_PATH) } catch(e) {}
try { fd.unlink(SOURCE_PATH) } catch(e) {}
error_msg = "entry missing in archive"
if (!error_msg) {
var extracted_blob = reader.slurp(ENTRY_PATH)
var extracted_text = utf8.decode(extracted_blob)
if (extracted_text != PAYLOAD)
error_msg = "extracted text mismatch"
}
} disruption {
if (!error_msg) error_msg = "test disrupted"
}
do_test()
safe_unlink(ZIP_PATH)
safe_unlink(SOURCE_PATH)
if (error_msg) return error_msg
},
list_and_count: function() {
var ZIP_PATH = "miniz_list_test.zip"
var ENTRY1 = "file1.txt"
var ENTRY2 = "dir/file2.txt"
try {
var error_msg = null
var do_test = function() {
var writer = miniz.write(ZIP_PATH)
writer.add_file(ENTRY1, utf8.encode("content1"))
writer.add_file(ENTRY2, utf8.encode("content2"))
writer = null
var zip_blob = fd.slurp(ZIP_PATH)
var reader = miniz.read(zip_blob)
var listed = reader.list()
if (length(listed) != reader.count())
throw "list/count mismatch"
if (length(listed) != 2)
throw "unexpected entry count"
} finally {
try { fd.unlink(ZIP_PATH) } catch(e) {}
error_msg = "list/count mismatch"
if (!error_msg && length(listed) != 2)
error_msg = "unexpected entry count"
} disruption {
if (!error_msg) error_msg = "test disrupted"
}
do_test()
safe_unlink(ZIP_PATH)
if (error_msg) return error_msg
},
exists_check: function() {
var ZIP_PATH = "miniz_exists_test.zip"
var ENTRY_PATH = "existing.txt"
try {
var error_msg = null
var do_test = function() {
var writer = miniz.write(ZIP_PATH)
writer.add_file(ENTRY_PATH, utf8.encode("data"))
writer = null
var zip_blob = fd.slurp(ZIP_PATH)
var reader = miniz.read(zip_blob)
if (!reader.exists(ENTRY_PATH))
throw "existing entry not found"
if (reader.exists("nonexistent.txt"))
throw "nonexistent entry reported as existing"
} finally {
try { fd.unlink(ZIP_PATH) } catch(e) {}
error_msg = "existing entry not found"
if (!error_msg && reader.exists("nonexistent.txt"))
error_msg = "nonexistent entry reported as existing"
} disruption {
if (!error_msg) error_msg = "test disrupted"
}
do_test()
safe_unlink(ZIP_PATH)
if (error_msg) return error_msg
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
var cmds = {
stop: $stop,
disrupt: _ => {
$delay(_ => { throw Error() }, 0.5)
$delay(_ => { disrupt }, 0.5)
}
}

View File

@@ -1,5 +1,10 @@
try {
var load_disrupted = false
var do_load = function() {
var u = use('tests/use')
} catch(e) {
log.console(e)
} disruption {
load_disrupted = true
}
do_load()
if (load_disrupted) {
log.console("use self-load disrupted")
}