string + number throws
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
|
||||
var _keys = array
|
||||
var _create = meme
|
||||
var _getPrototypeOf = Object.getPrototypeOf
|
||||
var _assign = Object.assign
|
||||
var _isArray = function(val) { return isa(val, array) }
|
||||
var _values = Object.values
|
||||
@@ -86,4 +85,9 @@ object.values = function(obj)
|
||||
return _values(obj)
|
||||
}
|
||||
|
||||
object.assign = function(obj, ...args)
|
||||
{
|
||||
return _assign(obj, ...args)
|
||||
}
|
||||
|
||||
return object
|
||||
|
||||
116
source/quickjs.c
116
source/quickjs.c
@@ -14030,9 +14030,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
b = JS_VALUE_GET_FLOAT64(op2);
|
||||
res = __JS_NewFloat64(ctx, a + b);
|
||||
}
|
||||
/* 5) anything else → null */
|
||||
/* 5) anything else → throw */
|
||||
else {
|
||||
res = JS_NULL;
|
||||
JS_ThrowTypeError(ctx, "cannot concatenate with string");
|
||||
goto exception;
|
||||
}
|
||||
|
||||
sp[-2] = res;
|
||||
@@ -14081,9 +14082,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
: JS_VALUE_GET_FLOAT64(rhs);
|
||||
res = __JS_NewFloat64(ctx, a + b);
|
||||
}
|
||||
/* 5) anything else → null */
|
||||
/* 5) anything else → throw */
|
||||
else {
|
||||
res = JS_NULL;
|
||||
JS_ThrowTypeError(ctx, "cannot concatenate with string");
|
||||
goto exception;
|
||||
}
|
||||
|
||||
var_buf[idx] = res;
|
||||
@@ -17764,13 +17766,6 @@ static __exception int js_parse_object_literal(JSParseState *s)
|
||||
set_object_name_computed(s);
|
||||
emit_op(s, OP_define_array_el);
|
||||
emit_op(s, OP_drop);
|
||||
} else if (name == JS_ATOM___proto__) {
|
||||
if (has_proto) {
|
||||
js_parse_error(s, "duplicate __proto__ property name");
|
||||
goto fail;
|
||||
}
|
||||
emit_op(s, OP_set_proto);
|
||||
has_proto = TRUE;
|
||||
} else {
|
||||
set_object_name(s, name);
|
||||
emit_op(s, OP_define_field);
|
||||
@@ -28320,102 +28315,6 @@ static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj,
|
||||
return species;
|
||||
}
|
||||
|
||||
static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val)
|
||||
{
|
||||
JSValue val, ret;
|
||||
|
||||
val = JS_ToObject(ctx, this_val);
|
||||
if (JS_IsException(val))
|
||||
return val;
|
||||
ret = JS_GetPrototype(ctx, val);
|
||||
JS_FreeValue(ctx, val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val,
|
||||
JSValueConst proto)
|
||||
{
|
||||
if (JS_IsNull(this_val) || JS_IsNull(this_val))
|
||||
return JS_ThrowTypeErrorNotAnObject(ctx);
|
||||
if (!JS_IsObject(proto) && !JS_IsNull(proto))
|
||||
return JS_NULL;
|
||||
if (JS_SetPrototypeInternal(ctx, this_val, proto) < 0)
|
||||
return JS_EXCEPTION;
|
||||
else
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JSValue obj, v1;
|
||||
JSValueConst v;
|
||||
int res;
|
||||
|
||||
v = argv[0];
|
||||
if (!JS_IsObject(v))
|
||||
return JS_FALSE;
|
||||
obj = JS_ToObject(ctx, this_val);
|
||||
if (JS_IsException(obj))
|
||||
return JS_EXCEPTION;
|
||||
v1 = JS_DupValue(ctx, v);
|
||||
for(;;) {
|
||||
v1 = JS_GetPrototypeFree(ctx, v1);
|
||||
if (JS_IsException(v1))
|
||||
goto exception;
|
||||
if (JS_IsNull(v1)) {
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
|
||||
res = TRUE;
|
||||
break;
|
||||
}
|
||||
/* avoid infinite loop (possible with proxies) */
|
||||
if (js_poll_interrupts(ctx))
|
||||
goto exception;
|
||||
}
|
||||
JS_FreeValue(ctx, v1);
|
||||
JS_FreeValue(ctx, obj);
|
||||
return JS_NewBool(ctx, res);
|
||||
|
||||
exception:
|
||||
JS_FreeValue(ctx, v1);
|
||||
JS_FreeValue(ctx, obj);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JSValue obj = JS_NULL, res = JS_EXCEPTION;
|
||||
JSAtom prop;
|
||||
JSPropertyDescriptor desc;
|
||||
int has_prop;
|
||||
|
||||
prop = JS_ValueToAtom(ctx, argv[0]);
|
||||
if (unlikely(prop == JS_ATOM_NULL))
|
||||
goto exception;
|
||||
obj = JS_ToObject(ctx, this_val);
|
||||
if (JS_IsException(obj))
|
||||
goto exception;
|
||||
|
||||
has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
|
||||
if (has_prop < 0)
|
||||
goto exception;
|
||||
if (has_prop) {
|
||||
res = JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE);
|
||||
js_free_desc(ctx, &desc);
|
||||
} else {
|
||||
res = JS_FALSE;
|
||||
}
|
||||
|
||||
exception:
|
||||
JS_FreeAtom(ctx, prop);
|
||||
JS_FreeValue(ctx, obj);
|
||||
return res;
|
||||
}
|
||||
|
||||
static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv, int setter)
|
||||
{
|
||||
@@ -28493,9 +28392,6 @@ static const JSCFunctionListEntry js_object_proto_funcs[] = {
|
||||
JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString ),
|
||||
JS_CFUNC_DEF("valueOf", 0, js_object_valueOf ),
|
||||
JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty ),
|
||||
JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf ),
|
||||
JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable ),
|
||||
JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__ ),
|
||||
JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0 ),
|
||||
JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1 ),
|
||||
JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0 ),
|
||||
|
||||
234
test.ce
234
test.ce
@@ -1,4 +1,5 @@
|
||||
var shop = use('internal/shop')
|
||||
var pkg = use('package')
|
||||
var fd = use('fd')
|
||||
var time = use('time')
|
||||
var json = use('json')
|
||||
@@ -6,7 +7,8 @@ var utf8 = use('utf8')
|
||||
|
||||
if (!args) args = []
|
||||
|
||||
var target_pkg = null // null = current, otherwise canonical path
|
||||
var target_pkg = null // null = current package
|
||||
var target_test = null // null = all tests, otherwise specific test file
|
||||
var all_pkgs = false
|
||||
|
||||
// Actor test support
|
||||
@@ -14,41 +16,139 @@ def ACTOR_TEST_TIMEOUT = 30000 // 30 seconds timeout for actor tests
|
||||
var pending_actor_tests = []
|
||||
var actor_test_results = []
|
||||
|
||||
if (args.length > 0) {
|
||||
// Check if current directory is a valid cell package
|
||||
function is_valid_package(dir) {
|
||||
if (!dir) dir = '.'
|
||||
return fd.is_file(dir + '/cell.toml')
|
||||
}
|
||||
|
||||
// Get current package name from cell.toml or null
|
||||
function get_current_package_name() {
|
||||
if (!is_valid_package('.')) return null
|
||||
try {
|
||||
var config = pkg.load_config(null)
|
||||
return config.package || 'local'
|
||||
} catch (e) {
|
||||
return 'local'
|
||||
}
|
||||
}
|
||||
|
||||
// Parse arguments
|
||||
// Usage:
|
||||
// cell test - run all tests for current package
|
||||
// cell test tests/suite - run specific test file in current package
|
||||
// cell test all - run all tests for current package
|
||||
// cell test package <name> - run all tests for named package
|
||||
// cell test package <name> <test> - run specific test in named package
|
||||
// cell test package all - run all tests from all packages
|
||||
|
||||
function parse_args() {
|
||||
if (args.length == 0) {
|
||||
// cell test - run all tests for current package
|
||||
if (!is_valid_package('.')) {
|
||||
log.console('No cell.toml found in current directory')
|
||||
return false
|
||||
}
|
||||
target_pkg = null
|
||||
return true
|
||||
}
|
||||
|
||||
if (args[0] == 'all') {
|
||||
// cell test all - run all tests for current package
|
||||
if (!is_valid_package('.')) {
|
||||
log.console('No cell.toml found in current directory')
|
||||
return false
|
||||
}
|
||||
target_pkg = null
|
||||
return true
|
||||
}
|
||||
|
||||
if (args[0] == 'package') {
|
||||
if (args.length < 2) {
|
||||
log.console(`Usage: cell test package <name>`)
|
||||
$stop()
|
||||
return
|
||||
log.console('Usage: cell test package <name> [test]')
|
||||
log.console(' cell test package all')
|
||||
return false
|
||||
}
|
||||
|
||||
if (args[1] == 'all') {
|
||||
// cell test package all - run tests from all packages
|
||||
all_pkgs = true
|
||||
log.console('Testing all packages...')
|
||||
return true
|
||||
}
|
||||
|
||||
// cell test package <name> [test]
|
||||
var name = args[1]
|
||||
var resolved = shop.resolve_alias(name, null)
|
||||
|
||||
// Check if package exists in lock or is a local path
|
||||
var lock = shop.load_lock()
|
||||
if (lock[name]) {
|
||||
target_pkg = name
|
||||
} else if (name.startsWith('/') && is_valid_package(name)) {
|
||||
target_pkg = name
|
||||
} else {
|
||||
// Try to resolve as dependency alias from current package
|
||||
if (is_valid_package('.')) {
|
||||
var resolved = pkg.alias_to_package(null, name)
|
||||
if (resolved) {
|
||||
target_pkg = resolved.pkg
|
||||
log.console(`Testing package: ${resolved.alias} (${resolved.pkg})`)
|
||||
target_pkg = resolved
|
||||
} else {
|
||||
log.console(`Package not found: ${name}`)
|
||||
$stop()
|
||||
return
|
||||
return false
|
||||
}
|
||||
} else if (args[0] == 'all') {
|
||||
all_pkgs = true
|
||||
log.console(`Testing all packages...`)
|
||||
} else {
|
||||
log.console(`Usage: cell test [package <name> | all]`)
|
||||
log.console(`Package not found: ${name}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (args.length >= 3) {
|
||||
// cell test package <name> <test>
|
||||
target_test = args[2]
|
||||
}
|
||||
|
||||
log.console(`Testing package: ${target_pkg}`)
|
||||
return true
|
||||
}
|
||||
|
||||
// cell test tests/suite or cell test <path> - specific test file
|
||||
var test_path = args[0]
|
||||
|
||||
// Normalize path - add tests/ prefix if not present and doesn't start with /
|
||||
if (!test_path.startsWith('tests/') && !test_path.startsWith('/')) {
|
||||
// Check if file exists as-is first
|
||||
if (!fd.is_file(test_path + '.cm') && !fd.is_file(test_path)) {
|
||||
// Try with tests/ prefix
|
||||
if (fd.is_file('tests/' + test_path + '.cm') || fd.is_file('tests/' + test_path)) {
|
||||
test_path = 'tests/' + test_path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target_test = test_path
|
||||
target_pkg = null
|
||||
|
||||
if (!is_valid_package('.')) {
|
||||
log.console('No cell.toml found in current directory')
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if (!parse_args()) {
|
||||
$stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function ensure_dir(path) {
|
||||
if (fd.is_dir(path)) return true
|
||||
|
||||
var parts = path.split('/')
|
||||
var current = ''
|
||||
var current = path.startsWith('/') ? '/' : ''
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
if (parts[i] == '') continue
|
||||
current += `${parts[i]}/`
|
||||
current += parts[i] + '/'
|
||||
if (!fd.is_dir(current)) {
|
||||
fd.mkdir(current)
|
||||
}
|
||||
@@ -56,23 +156,46 @@ function ensure_dir(path) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Get the directory for a package
|
||||
function get_pkg_dir(package_name) {
|
||||
if (!package_name) {
|
||||
return fd.realpath('.')
|
||||
}
|
||||
if (package_name.startsWith('/')) {
|
||||
return package_name
|
||||
}
|
||||
return shop.get_package_dir(package_name)
|
||||
}
|
||||
|
||||
// Collect .ce actor tests from a package
|
||||
function collect_actor_tests(pkg) {
|
||||
var prefix = pkg ? shop.get_shop_path() + '/modules/' + pkg : (shop.get_current_package() || '.')
|
||||
function collect_actor_tests(package_name, specific_test) {
|
||||
var prefix = get_pkg_dir(package_name)
|
||||
var tests_dir = prefix + '/tests'
|
||||
|
||||
if (!fd.is_dir(tests_dir)) return []
|
||||
|
||||
var files = shop.list_files(pkg)
|
||||
var files = pkg.list_files(package_name)
|
||||
var actor_tests = []
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var f = files[i]
|
||||
// Check if file is in tests/ folder and is a .ce actor
|
||||
if (f.startsWith("tests/") && f.endsWith(".ce")) {
|
||||
// If specific test requested, filter
|
||||
if (specific_test) {
|
||||
var test_name = f.substring(0, f.length - 3) // remove .ce
|
||||
var match_name = specific_test
|
||||
if (!match_name.startsWith('tests/')) match_name = 'tests/' + match_name
|
||||
if (!match_name.endsWith('.ce')) match_name = match_name
|
||||
// Match without extension
|
||||
var test_base = test_name
|
||||
var match_base = match_name.endsWith('.ce') ? match_name.substring(0, match_name.length - 3) : match_name
|
||||
if (test_base != match_base) continue
|
||||
}
|
||||
|
||||
actor_tests.push({
|
||||
package: pkg || "local",
|
||||
package: package_name || "local",
|
||||
file: f,
|
||||
path: pkg ? `${prefix}/${f}` : f
|
||||
path: prefix + '/' + f
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -95,7 +218,6 @@ function spawn_actor_test(test_info) {
|
||||
|
||||
try {
|
||||
// Spawn the actor test - it should send back results
|
||||
// The actor receives $parent which it can use to send results
|
||||
var actor_path = test_info.path.substring(0, test_info.path.length - 3) // remove .ce
|
||||
entry.actor = $start(actor_path)
|
||||
pending_actor_tests.push(entry)
|
||||
@@ -109,12 +231,12 @@ function spawn_actor_test(test_info) {
|
||||
}
|
||||
}
|
||||
|
||||
function run_tests(pkg) {
|
||||
var prefix = pkg ? shop.get_shop_path() + '/modules/' + pkg : (shop.get_current_package() || '.')
|
||||
function run_tests(package_name, specific_test) {
|
||||
var prefix = get_pkg_dir(package_name)
|
||||
var tests_dir = prefix + '/tests'
|
||||
|
||||
var pkg_result = {
|
||||
package: pkg || "local",
|
||||
package: package_name || "local",
|
||||
files: [],
|
||||
total: 0,
|
||||
passed: 0,
|
||||
@@ -123,18 +245,27 @@ function run_tests(pkg) {
|
||||
|
||||
if (!fd.is_dir(tests_dir)) return pkg_result
|
||||
|
||||
var files = shop.list_files(pkg)
|
||||
var files = pkg.list_files(package_name)
|
||||
var test_files = []
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var f = files[i]
|
||||
// Check if file is in tests/ folder and is a .cm module (not .ce - those are actor tests)
|
||||
if (f.startsWith("tests/") && f.endsWith(".cm")) {
|
||||
// If specific test requested, filter
|
||||
if (specific_test) {
|
||||
var test_name = f.substring(0, f.length - 3) // remove .cm
|
||||
var match_name = specific_test
|
||||
if (!match_name.startsWith('tests/')) match_name = 'tests/' + match_name
|
||||
// Match without extension
|
||||
var match_base = match_name.endsWith('.cm') ? match_name.substring(0, match_name.length - 3) : match_name
|
||||
if (test_name != match_base) continue
|
||||
}
|
||||
test_files.push(f)
|
||||
}
|
||||
}
|
||||
|
||||
if (test_files.length > 0) {
|
||||
if (pkg) log.console(`Running tests for ${pkg}`)
|
||||
if (package_name) log.console(`Running tests for ${package_name}`)
|
||||
else log.console(`Running tests for local package`)
|
||||
}
|
||||
|
||||
@@ -151,11 +282,9 @@ function run_tests(pkg) {
|
||||
|
||||
try {
|
||||
var test_mod
|
||||
if (pkg) {
|
||||
test_mod = shop.use(mod_path, pkg)
|
||||
} else {
|
||||
test_mod = globalThis.use(mod_path)
|
||||
}
|
||||
// For local packages (null), use the current directory as package context
|
||||
var use_pkg = package_name ? package_name : fd.realpath('.')
|
||||
test_mod = shop.use(mod_path, use_pkg)
|
||||
|
||||
var tests = []
|
||||
if (typeof test_mod == 'function') {
|
||||
@@ -201,7 +330,6 @@ function run_tests(pkg) {
|
||||
}
|
||||
if (e.name) test_entry.error.name = e.name
|
||||
|
||||
// If it's an object but not a native Error, try to extract more info
|
||||
if (typeof e == 'object' && e.message) {
|
||||
test_entry.error.message = e.message
|
||||
}
|
||||
@@ -224,8 +352,6 @@ function run_tests(pkg) {
|
||||
|
||||
} catch (e) {
|
||||
log.console(` Error loading ${f}: ${e}`)
|
||||
// Treat load error as a file failure?
|
||||
// Or maybe add a dummy test entry for "load"
|
||||
var test_entry = {
|
||||
package: pkg_result.package,
|
||||
test: "load_module",
|
||||
@@ -247,19 +373,21 @@ var all_results = []
|
||||
var all_actor_tests = []
|
||||
|
||||
if (all_pkgs) {
|
||||
// Run local first
|
||||
all_results.push(run_tests(null))
|
||||
all_actor_tests = all_actor_tests.concat(collect_actor_tests(null))
|
||||
// Run local first if we're in a valid package
|
||||
if (is_valid_package('.')) {
|
||||
all_results.push(run_tests(null, null))
|
||||
all_actor_tests = all_actor_tests.concat(collect_actor_tests(null, null))
|
||||
}
|
||||
|
||||
// Then all dependencies
|
||||
var deps = shop.list_packages(null)
|
||||
for (var i = 0; i < deps.length; i++) {
|
||||
all_results.push(run_tests(deps[i]))
|
||||
all_actor_tests = all_actor_tests.concat(collect_actor_tests(deps[i]))
|
||||
// Then all packages in lock
|
||||
var packages = shop.list_packages()
|
||||
for (var i = 0; i < packages.length; i++) {
|
||||
all_results.push(run_tests(packages[i], null))
|
||||
all_actor_tests = all_actor_tests.concat(collect_actor_tests(packages[i], null))
|
||||
}
|
||||
} else {
|
||||
all_results.push(run_tests(target_pkg))
|
||||
all_actor_tests = all_actor_tests.concat(collect_actor_tests(target_pkg))
|
||||
all_results.push(run_tests(target_pkg, target_test))
|
||||
all_actor_tests = all_actor_tests.concat(collect_actor_tests(target_pkg, target_test))
|
||||
}
|
||||
|
||||
// Spawn actor tests if any
|
||||
@@ -271,10 +399,7 @@ if (all_actor_tests.length > 0) {
|
||||
}
|
||||
|
||||
// Handle messages from actor tests
|
||||
// Actor tests should send either a single result `{ type: "test_result", ... }`
|
||||
// or an array / object containing multiple results (e.g. {results:[...]})
|
||||
function handle_actor_message(msg) {
|
||||
// Find the pending test from this sender
|
||||
var sender = msg.$sender
|
||||
var found_idx = -1
|
||||
for (var i = 0; i < pending_actor_tests.length; i++) {
|
||||
@@ -284,7 +409,7 @@ function handle_actor_message(msg) {
|
||||
}
|
||||
}
|
||||
|
||||
if (found_idx == -1) return // Unknown sender
|
||||
if (found_idx == -1) return
|
||||
|
||||
var base_entry = pending_actor_tests[found_idx]
|
||||
pending_actor_tests.splice(found_idx, 1)
|
||||
@@ -292,7 +417,6 @@ function handle_actor_message(msg) {
|
||||
var end_time = time.number()
|
||||
var duration_ns = number.round((end_time - base_entry.start_time) * 1000000000)
|
||||
|
||||
// Normalize to an array of result objects
|
||||
var results = []
|
||||
if (isa(msg, array)) {
|
||||
results = msg
|
||||
@@ -375,7 +499,6 @@ function finalize_results() {
|
||||
// Add actor test results to all_results
|
||||
for (var i = 0; i < actor_test_results.length; i++) {
|
||||
var r = actor_test_results[i]
|
||||
// Find or create package result
|
||||
var pkg_result = null
|
||||
for (var j = 0; j < all_results.length; j++) {
|
||||
if (all_results[j].package == r.package) {
|
||||
@@ -388,7 +511,6 @@ function finalize_results() {
|
||||
all_results.push(pkg_result)
|
||||
}
|
||||
|
||||
// Find or create file result
|
||||
var file_result = null
|
||||
for (var j = 0; j < pkg_result.files.length; j++) {
|
||||
if (pkg_result.files[j].name == r.file) {
|
||||
@@ -429,7 +551,6 @@ function finalize_results() {
|
||||
|
||||
// If no actor tests, finalize immediately
|
||||
if (all_actor_tests.length == 0) {
|
||||
// Calculate totals
|
||||
var totals = { total: 0, passed: 0, failed: 0 }
|
||||
for (var i = 0; i < all_results.length; i++) {
|
||||
totals.total += all_results[i].total
|
||||
@@ -440,7 +561,6 @@ if (all_actor_tests.length == 0) {
|
||||
log.console(`----------------------------------------`)
|
||||
log.console(`Tests: ${totals.passed} passed, ${totals.failed} failed, ${totals.total} total`)
|
||||
} else {
|
||||
// Start timeout checker
|
||||
$delay(check_timeouts, 1000)
|
||||
}
|
||||
|
||||
@@ -451,7 +571,6 @@ function generate_reports(totals) {
|
||||
var report_dir = shop.get_reports_dir() + '/test_' + timestamp
|
||||
ensure_dir(report_dir)
|
||||
|
||||
// Generate test.txt
|
||||
var txt_report = `TEST REPORT
|
||||
Date: ${time.text(time.number())}
|
||||
Total: ${totals.total}, Passed: ${totals.passed}, Failed: ${totals.failed}
|
||||
@@ -508,7 +627,7 @@ Total: ${totals.total}, Passed: ${totals.passed}, Failed: ${totals.failed}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ensure_dir(report_dir)
|
||||
fd.slurpwrite(`${report_dir}/test.txt`, utf8.encode(txt_report))
|
||||
log.console(`Report written to ${report_dir}/test.txt`)
|
||||
|
||||
@@ -535,7 +654,6 @@ if (all_actor_tests.length == 0) {
|
||||
generate_reports(totals)
|
||||
$stop()
|
||||
} else {
|
||||
// Set up portal to receive messages from actor tests
|
||||
$portal(function(msg) {
|
||||
handle_actor_message(msg)
|
||||
})
|
||||
|
||||
12
time.cm
12
time.cm
@@ -56,7 +56,7 @@ time.timecode = function(t, fps = 24)
|
||||
time.monthdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
|
||||
// convert seconds-since-epoch → broken-down record
|
||||
function record(num = now(),
|
||||
function time_record(num = now(),
|
||||
zone = computer_zone(),
|
||||
dst = computer_dst())
|
||||
{
|
||||
@@ -109,7 +109,7 @@ function record(num = now(),
|
||||
return rec;
|
||||
}
|
||||
|
||||
function number(rec = now())
|
||||
function time_number(rec = now())
|
||||
{
|
||||
if (typeof rec == "number") return rec;
|
||||
|
||||
@@ -152,12 +152,12 @@ function number(rec = now())
|
||||
// text formatting
|
||||
var default_fmt = "vB mB d hh:nn:ss a z y c"; /* includes new DST token */
|
||||
|
||||
function text(num = now(),
|
||||
function time_text(num = now(),
|
||||
fmt = default_fmt,
|
||||
zone = computer_zone(),
|
||||
dst = computer_dst())
|
||||
{
|
||||
var rec = (typeof num == "number") ? record(num, zone, dst) : num;
|
||||
var rec = (typeof num == "number") ? time_record(num, zone, dst) : num;
|
||||
zone = rec.zone;
|
||||
dst = rec.dst;
|
||||
|
||||
@@ -190,7 +190,7 @@ function text(num = now(),
|
||||
fmt = fmt.replaceAll("ss", rec.second.toFixed(2).padStart(2, "0"));
|
||||
fmt = fmt.replaceAll("s", rec.second);
|
||||
fmt = fmt.replaceAll("x", dst ? "DST" : ""); /* new */
|
||||
fmt = fmt.replaceAll("z", (full_offset >= 0 ? "+" : "") + full_offset);
|
||||
fmt = fmt.replaceAll("z", (full_offset >= 0 ? "+" : "") + text(full_offset));
|
||||
fmt = fmt.replaceAll(/mm[^bB]/g, rec.month + 1);
|
||||
fmt = fmt.replaceAll(/m[^bB]/g, rec.month + 1);
|
||||
fmt = fmt.replaceAll(/v[^bB]/g, rec.weekday);
|
||||
@@ -202,4 +202,4 @@ function text(num = now(),
|
||||
return fmt;
|
||||
}
|
||||
|
||||
return { record, number, text };
|
||||
return { record: time_record, number: time_number, text: time_text };
|
||||
|
||||
Reference in New Issue
Block a user