fix tests; add comprehensive tests for functions and fix bugs in the mach VM regarding them.
This commit is contained in:
@@ -267,6 +267,19 @@ JS_BOOL JS_IsBlob(JSValue v);
|
||||
JS_BOOL JS_IsText(JSValue v);
|
||||
JS_BOOL JS_IsStone(JSValue v);
|
||||
|
||||
/* Sensory function wrappers (require JSContext for string inspection) */
|
||||
JS_BOOL JS_IsDigit(JSContext *ctx, JSValue val);
|
||||
JS_BOOL JS_IsLetter(JSContext *ctx, JSValue val);
|
||||
JS_BOOL JS_IsLower(JSContext *ctx, JSValue val);
|
||||
JS_BOOL JS_IsUpper(JSContext *ctx, JSValue val);
|
||||
JS_BOOL JS_IsWhitespace(JSContext *ctx, JSValue val);
|
||||
JS_BOOL JS_IsCharacter(JSContext *ctx, JSValue val);
|
||||
JS_BOOL JS_IsFit(JSContext *ctx, JSValue val);
|
||||
JS_BOOL JS_IsData(JSValue val);
|
||||
static inline JS_BOOL JS_IsTrue(JSValue v) { return v == JS_TRUE; }
|
||||
static inline JS_BOOL JS_IsFalse(JSValue v) { return v == JS_FALSE; }
|
||||
JS_BOOL JS_IsActor(JSContext *ctx, JSValue val);
|
||||
|
||||
/* ============================================================
|
||||
GC References — no-ops with copying GC
|
||||
============================================================ */
|
||||
@@ -559,6 +572,14 @@ JSValue JS_CellObject (JSContext *ctx, JSValue proto, JSValue props);
|
||||
/* Format */
|
||||
JSValue JS_CellFormat (JSContext *ctx, JSValue text, JSValue collection, JSValue transformer);
|
||||
|
||||
/* Additional cell functions */
|
||||
JSValue JS_CellLogical (JSContext *ctx, JSValue val);
|
||||
JSValue JS_CellEvery (JSContext *ctx, JSValue arr, JSValue pred);
|
||||
JSValue JS_CellSome (JSContext *ctx, JSValue arr, JSValue pred);
|
||||
JSValue JS_CellStartsWith (JSContext *ctx, JSValue text, JSValue prefix);
|
||||
JSValue JS_CellEndsWith (JSContext *ctx, JSValue text, JSValue suffix);
|
||||
JSValue JS_CellNormalize (JSContext *ctx, JSValue text);
|
||||
|
||||
/* Output helpers */
|
||||
void JS_PrintText (JSContext *ctx, JSValue val);
|
||||
void JS_PrintTextLn (JSContext *ctx, JSValue val);
|
||||
|
||||
@@ -2486,14 +2486,32 @@ vm_dispatch:
|
||||
VM_CASE(MACH_IS_WS): {
|
||||
JSValue v = frame->slots[b];
|
||||
int result = 0;
|
||||
if (MIST_IsImmediateASCII(v) && MIST_GetImmediateASCIILen(v) == 1) {
|
||||
int ch = MIST_GetImmediateASCIIChar(v, 0);
|
||||
result = (ch == ' ' || ch == '\t' || ch == '\n'
|
||||
|| ch == '\r' || ch == '\f' || ch == '\v');
|
||||
} else if (mist_is_text(v) && js_string_value_len(v) == 1) {
|
||||
uint32_t ch = js_string_value_get(v, 0);
|
||||
result = (ch == ' ' || ch == '\t' || ch == '\n'
|
||||
|| ch == '\r' || ch == '\f' || ch == '\v');
|
||||
if (MIST_IsImmediateASCII(v)) {
|
||||
int len = MIST_GetImmediateASCIILen(v);
|
||||
if (len > 0) {
|
||||
result = 1;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int ch = MIST_GetImmediateASCIIChar(v, i);
|
||||
if (!(ch == ' ' || ch == '\t' || ch == '\n'
|
||||
|| ch == '\r' || ch == '\f' || ch == '\v')) {
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mist_is_text(v)) {
|
||||
int len = js_string_value_len(v);
|
||||
if (len > 0) {
|
||||
result = 1;
|
||||
for (int i = 0; i < len; i++) {
|
||||
uint32_t ch = js_string_value_get(v, i);
|
||||
if (!(ch == ' ' || ch == '\t' || ch == '\n'
|
||||
|| ch == '\r' || ch == '\f' || ch == '\v')) {
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
frame->slots[a] = JS_NewBool(ctx, result);
|
||||
VM_BREAK();
|
||||
|
||||
136
source/runtime.c
136
source/runtime.c
@@ -11503,15 +11503,20 @@ static JSValue js_cell_is_upper (JSContext *ctx, JSValue this_val, int argc, JSV
|
||||
return JS_NewBool (ctx, c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
/* is_whitespace(val) - check if value is a single whitespace character */
|
||||
/* is_whitespace(val) - check if all characters are whitespace (non-empty) */
|
||||
static JSValue js_cell_is_whitespace (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||
if (argc < 1) return JS_FALSE;
|
||||
JSValue val = argv[0];
|
||||
if (!JS_IsText (val)) return JS_FALSE;
|
||||
if (js_string_value_len (val) != 1) return JS_FALSE;
|
||||
uint32_t c = js_string_value_get (val, 0);
|
||||
return JS_NewBool (ctx, c == ' ' || c == '\t' || c == '\n'
|
||||
|| c == '\r' || c == '\f' || c == '\v');
|
||||
int len = js_string_value_len (val);
|
||||
if (len == 0) return JS_FALSE;
|
||||
for (int i = 0; i < len; i++) {
|
||||
uint32_t c = js_string_value_get (val, i);
|
||||
if (!(c == ' ' || c == '\t' || c == '\n'
|
||||
|| c == '\r' || c == '\f' || c == '\v'))
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* is_proto(val, master) - check if val has master in prototype chain */
|
||||
@@ -11571,6 +11576,47 @@ static JSValue js_cell_logical(JSContext *ctx, JSValue this_val, int argc, JSVal
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
/* realloc wrapper for unicode_normalize */
|
||||
static void *normalize_realloc(void *opaque, void *ptr, size_t size) {
|
||||
(void)opaque;
|
||||
if (size == 0) {
|
||||
pjs_free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
return pjs_realloc(ptr, size);
|
||||
}
|
||||
|
||||
/* normalize(text) — NFC normalization */
|
||||
static JSValue js_cell_normalize(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||
if (argc < 1) return JS_NULL;
|
||||
JSValue val = argv[0];
|
||||
if (!JS_IsText(val)) return JS_NULL;
|
||||
int len = js_string_value_len(val);
|
||||
if (len == 0) return JS_NewString(ctx, "");
|
||||
uint32_t *src = pjs_malloc(len * sizeof(uint32_t));
|
||||
if (!src) return JS_EXCEPTION;
|
||||
for (int i = 0; i < len; i++)
|
||||
src[i] = js_string_value_get(val, i);
|
||||
uint32_t *dst = NULL;
|
||||
int dst_len = unicode_normalize(&dst, src, len, UNICODE_NFC, NULL,
|
||||
normalize_realloc);
|
||||
pjs_free(src);
|
||||
if (dst_len < 0) {
|
||||
pjs_free(dst);
|
||||
return JS_NULL;
|
||||
}
|
||||
JSText *str = js_alloc_string(ctx, dst_len);
|
||||
if (!str) {
|
||||
pjs_free(dst);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
for (int i = 0; i < dst_len; i++)
|
||||
string_put(str, i, dst[i]);
|
||||
str->length = dst_len;
|
||||
pjs_free(dst);
|
||||
return pretext_end(ctx, str);
|
||||
}
|
||||
|
||||
/* starts_with(str, prefix) — search(str, prefix) == 0 */
|
||||
static JSValue js_cell_starts_with(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||
if (argc < 2) return JS_NULL;
|
||||
@@ -11616,6 +11662,85 @@ static JSValue js_cell_some(JSContext *ctx, JSValue this_val, int argc, JSValue
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* C API: Type-check wrappers for sensory functions */
|
||||
JS_BOOL JS_IsDigit (JSContext *ctx, JSValue val) {
|
||||
JSValue r = js_cell_is_digit (ctx, JS_NULL, 1, &val);
|
||||
return JS_VALUE_GET_BOOL (r);
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsLetter (JSContext *ctx, JSValue val) {
|
||||
JSValue r = js_cell_is_letter (ctx, JS_NULL, 1, &val);
|
||||
return JS_VALUE_GET_BOOL (r);
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsLower (JSContext *ctx, JSValue val) {
|
||||
JSValue r = js_cell_is_lower (ctx, JS_NULL, 1, &val);
|
||||
return JS_VALUE_GET_BOOL (r);
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsUpper (JSContext *ctx, JSValue val) {
|
||||
JSValue r = js_cell_is_upper (ctx, JS_NULL, 1, &val);
|
||||
return JS_VALUE_GET_BOOL (r);
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsWhitespace (JSContext *ctx, JSValue val) {
|
||||
JSValue r = js_cell_is_whitespace (ctx, JS_NULL, 1, &val);
|
||||
return JS_VALUE_GET_BOOL (r);
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsCharacter (JSContext *ctx, JSValue val) {
|
||||
JSValue r = js_cell_is_character (ctx, JS_NULL, 1, &val);
|
||||
return JS_VALUE_GET_BOOL (r);
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsFit (JSContext *ctx, JSValue val) {
|
||||
JSValue r = js_cell_is_fit (ctx, JS_NULL, 1, &val);
|
||||
return JS_VALUE_GET_BOOL (r);
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsData (JSValue val) {
|
||||
return !JS_IsNull (val) && !JS_IsFunction (val);
|
||||
}
|
||||
|
||||
JS_BOOL JS_IsActor (JSContext *ctx, JSValue val) {
|
||||
JSValue r = js_cell_is_actor (ctx, JS_NULL, 1, &val);
|
||||
return JS_VALUE_GET_BOOL (r);
|
||||
}
|
||||
|
||||
/* C API: logical(val) */
|
||||
JSValue JS_CellLogical (JSContext *ctx, JSValue val) {
|
||||
return js_cell_logical (ctx, JS_NULL, 1, &val);
|
||||
}
|
||||
|
||||
/* C API: every(arr, pred) */
|
||||
JSValue JS_CellEvery (JSContext *ctx, JSValue arr, JSValue pred) {
|
||||
JSValue argv[2] = { arr, pred };
|
||||
return js_cell_every (ctx, JS_NULL, 2, argv);
|
||||
}
|
||||
|
||||
/* C API: some(arr, pred) */
|
||||
JSValue JS_CellSome (JSContext *ctx, JSValue arr, JSValue pred) {
|
||||
JSValue argv[2] = { arr, pred };
|
||||
return js_cell_some (ctx, JS_NULL, 2, argv);
|
||||
}
|
||||
|
||||
/* C API: starts_with(text, prefix) */
|
||||
JSValue JS_CellStartsWith (JSContext *ctx, JSValue text, JSValue prefix) {
|
||||
JSValue argv[2] = { text, prefix };
|
||||
return js_cell_starts_with (ctx, JS_NULL, 2, argv);
|
||||
}
|
||||
|
||||
/* C API: ends_with(text, suffix) */
|
||||
JSValue JS_CellEndsWith (JSContext *ctx, JSValue text, JSValue suffix) {
|
||||
JSValue argv[2] = { text, suffix };
|
||||
return js_cell_ends_with (ctx, JS_NULL, 2, argv);
|
||||
}
|
||||
|
||||
/* C API: normalize(text) */
|
||||
JSValue JS_CellNormalize (JSContext *ctx, JSValue text) {
|
||||
return js_cell_normalize (ctx, JS_NULL, 1, &text);
|
||||
}
|
||||
|
||||
static void js_set_global_cfunc(JSContext *ctx, const char *name, JSCFunction *func, int length) {
|
||||
JSGCRef ref;
|
||||
JS_PushGCRef(ctx, &ref);
|
||||
@@ -11740,6 +11865,7 @@ static void JS_AddIntrinsicBaseObjects (JSContext *ctx) {
|
||||
js_set_global_cfunc(ctx, "ends_with", js_cell_ends_with, 2);
|
||||
js_set_global_cfunc(ctx, "every", js_cell_every, 2);
|
||||
js_set_global_cfunc(ctx, "some", js_cell_some, 2);
|
||||
js_set_global_cfunc(ctx, "normalize", js_cell_normalize, 1);
|
||||
|
||||
/* fn record with apply property */
|
||||
{
|
||||
|
||||
488
source/suite.c
488
source/suite.c
@@ -2187,6 +2187,424 @@ TEST(wota_encode_blob) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Sensory Function C API Tests
|
||||
============================================================================ */
|
||||
|
||||
TEST(is_true_true) {
|
||||
ASSERT(JS_IsTrue(JS_TRUE));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_true_false) {
|
||||
ASSERT(!JS_IsTrue(JS_FALSE));
|
||||
ASSERT(!JS_IsTrue(JS_NewInt32(ctx, 1)));
|
||||
ASSERT(!JS_IsTrue(JS_NULL));
|
||||
ASSERT(!JS_IsTrue(JS_NewString(ctx, "true")));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_false_false) {
|
||||
ASSERT(JS_IsFalse(JS_FALSE));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_false_other) {
|
||||
ASSERT(!JS_IsFalse(JS_TRUE));
|
||||
ASSERT(!JS_IsFalse(JS_NewInt32(ctx, 0)));
|
||||
ASSERT(!JS_IsFalse(JS_NULL));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_data_values) {
|
||||
ASSERT(JS_IsData(JS_NewInt32(ctx, 42)));
|
||||
ASSERT(JS_IsData(JS_NewString(ctx, "hello")));
|
||||
ASSERT(JS_IsData(JS_TRUE));
|
||||
ASSERT(JS_IsData(JS_NewArray(ctx)));
|
||||
ASSERT(JS_IsData(JS_NewObject(ctx)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_data_non_data) {
|
||||
ASSERT(!JS_IsData(JS_NULL));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_fit_integers) {
|
||||
ASSERT(JS_IsFit(ctx, JS_NewInt32(ctx, 0)));
|
||||
ASSERT(JS_IsFit(ctx, JS_NewInt32(ctx, 42)));
|
||||
ASSERT(JS_IsFit(ctx, JS_NewInt32(ctx, -100)));
|
||||
ASSERT(JS_IsFit(ctx, JS_NewFloat64(ctx, 3.0)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_fit_non_fit) {
|
||||
ASSERT(!JS_IsFit(ctx, JS_NewFloat64(ctx, 3.5)));
|
||||
ASSERT(!JS_IsFit(ctx, JS_NewString(ctx, "3")));
|
||||
ASSERT(!JS_IsFit(ctx, JS_NULL));
|
||||
ASSERT(!JS_IsFit(ctx, JS_TRUE));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_character_single) {
|
||||
ASSERT(JS_IsCharacter(ctx, JS_NewString(ctx, "a")));
|
||||
ASSERT(JS_IsCharacter(ctx, JS_NewString(ctx, "Z")));
|
||||
ASSERT(JS_IsCharacter(ctx, JS_NewString(ctx, "5")));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_character_non_char) {
|
||||
ASSERT(!JS_IsCharacter(ctx, JS_NewString(ctx, "ab")));
|
||||
ASSERT(!JS_IsCharacter(ctx, JS_NewString(ctx, "")));
|
||||
ASSERT(!JS_IsCharacter(ctx, JS_NewInt32(ctx, 65)));
|
||||
ASSERT(!JS_IsCharacter(ctx, JS_NULL));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_digit_digits) {
|
||||
ASSERT(JS_IsDigit(ctx, JS_NewString(ctx, "0")));
|
||||
ASSERT(JS_IsDigit(ctx, JS_NewString(ctx, "9")));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_digit_non_digit) {
|
||||
ASSERT(!JS_IsDigit(ctx, JS_NewString(ctx, "a")));
|
||||
ASSERT(!JS_IsDigit(ctx, JS_NewString(ctx, "55")));
|
||||
ASSERT(!JS_IsDigit(ctx, JS_NewInt32(ctx, 5)));
|
||||
ASSERT(!JS_IsDigit(ctx, JS_NULL));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_letter_letters) {
|
||||
ASSERT(JS_IsLetter(ctx, JS_NewString(ctx, "a")));
|
||||
ASSERT(JS_IsLetter(ctx, JS_NewString(ctx, "Z")));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_letter_non_letter) {
|
||||
ASSERT(!JS_IsLetter(ctx, JS_NewString(ctx, "5")));
|
||||
ASSERT(!JS_IsLetter(ctx, JS_NewString(ctx, "ab")));
|
||||
ASSERT(!JS_IsLetter(ctx, JS_NewInt32(ctx, 65)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_lower_lowercase) {
|
||||
ASSERT(JS_IsLower(ctx, JS_NewString(ctx, "a")));
|
||||
ASSERT(JS_IsLower(ctx, JS_NewString(ctx, "z")));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_lower_non_lower) {
|
||||
ASSERT(!JS_IsLower(ctx, JS_NewString(ctx, "A")));
|
||||
ASSERT(!JS_IsLower(ctx, JS_NewString(ctx, "5")));
|
||||
ASSERT(!JS_IsLower(ctx, JS_NewString(ctx, "ab")));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_upper_uppercase) {
|
||||
ASSERT(JS_IsUpper(ctx, JS_NewString(ctx, "A")));
|
||||
ASSERT(JS_IsUpper(ctx, JS_NewString(ctx, "Z")));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_upper_non_upper) {
|
||||
ASSERT(!JS_IsUpper(ctx, JS_NewString(ctx, "a")));
|
||||
ASSERT(!JS_IsUpper(ctx, JS_NewString(ctx, "5")));
|
||||
ASSERT(!JS_IsUpper(ctx, JS_NewString(ctx, "AB")));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_whitespace_single) {
|
||||
ASSERT(JS_IsWhitespace(ctx, JS_NewString(ctx, " ")));
|
||||
ASSERT(JS_IsWhitespace(ctx, JS_NewString(ctx, "\t")));
|
||||
ASSERT(JS_IsWhitespace(ctx, JS_NewString(ctx, "\n")));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_whitespace_multi) {
|
||||
ASSERT(JS_IsWhitespace(ctx, JS_NewString(ctx, " ")));
|
||||
ASSERT(JS_IsWhitespace(ctx, JS_NewString(ctx, "\r\n")));
|
||||
ASSERT(JS_IsWhitespace(ctx, JS_NewString(ctx, " \t\n")));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_whitespace_non_ws) {
|
||||
ASSERT(!JS_IsWhitespace(ctx, JS_NewString(ctx, "a")));
|
||||
ASSERT(!JS_IsWhitespace(ctx, JS_NewString(ctx, "")));
|
||||
ASSERT(!JS_IsWhitespace(ctx, JS_NewInt32(ctx, 32)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(is_actor_non_actor) {
|
||||
ASSERT(!JS_IsActor(ctx, JS_NewObject(ctx)));
|
||||
ASSERT(!JS_IsActor(ctx, JS_NULL));
|
||||
ASSERT(!JS_IsActor(ctx, JS_NewInt32(ctx, 42)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Logical, Whole, Fraction C API Tests
|
||||
============================================================================ */
|
||||
|
||||
TEST(logical_zero) {
|
||||
JSValue r = JS_CellLogical(ctx, JS_NewInt32(ctx, 0));
|
||||
ASSERT_FALSE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(logical_one) {
|
||||
JSValue r = JS_CellLogical(ctx, JS_NewInt32(ctx, 1));
|
||||
ASSERT_TRUE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(logical_false) {
|
||||
JSValue r = JS_CellLogical(ctx, JS_FALSE);
|
||||
ASSERT_FALSE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(logical_true) {
|
||||
JSValue r = JS_CellLogical(ctx, JS_TRUE);
|
||||
ASSERT_TRUE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(logical_string_false) {
|
||||
JSValue r = JS_CellLogical(ctx, JS_NewString(ctx, "false"));
|
||||
ASSERT_FALSE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(logical_string_true) {
|
||||
JSValue r = JS_CellLogical(ctx, JS_NewString(ctx, "true"));
|
||||
ASSERT_TRUE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(logical_null) {
|
||||
JSValue r = JS_CellLogical(ctx, JS_NULL);
|
||||
ASSERT_FALSE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(logical_invalid) {
|
||||
JSValue r = JS_CellLogical(ctx, JS_NewInt32(ctx, 42));
|
||||
ASSERT_NULL(r);
|
||||
r = JS_CellLogical(ctx, JS_NewString(ctx, "maybe"));
|
||||
ASSERT_NULL(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(whole_positive) {
|
||||
JSValue r = JS_CellWhole(ctx, JS_NewFloat64(ctx, 3.7));
|
||||
ASSERT_FLOAT(r, 3.0, 0.001);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(whole_negative) {
|
||||
JSValue r = JS_CellWhole(ctx, JS_NewFloat64(ctx, -3.7));
|
||||
ASSERT_FLOAT(r, -3.0, 0.001);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(whole_integer) {
|
||||
JSValue r = JS_CellWhole(ctx, JS_NewInt32(ctx, 42));
|
||||
ASSERT_FLOAT(r, 42.0, 0.001);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(whole_non_number) {
|
||||
JSValue r = JS_CellWhole(ctx, JS_NewString(ctx, "hi"));
|
||||
ASSERT_NULL(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(fraction_positive) {
|
||||
JSValue r = JS_CellFraction(ctx, JS_NewFloat64(ctx, 3.7));
|
||||
ASSERT_FLOAT(r, 0.7, 0.001);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(fraction_negative) {
|
||||
JSValue r = JS_CellFraction(ctx, JS_NewFloat64(ctx, -3.7));
|
||||
ASSERT_FLOAT(r, -0.7, 0.001);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(fraction_integer) {
|
||||
JSValue r = JS_CellFraction(ctx, JS_NewInt32(ctx, 42));
|
||||
ASSERT_FLOAT(r, 0.0, 0.001);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(fraction_non_number) {
|
||||
JSValue r = JS_CellFraction(ctx, JS_NewString(ctx, "hi"));
|
||||
ASSERT_NULL(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
StartsWith / EndsWith C API Tests
|
||||
============================================================================ */
|
||||
|
||||
TEST(starts_with_match) {
|
||||
JSValue r = JS_CellStartsWith(ctx, JS_NewString(ctx, "hello world"), JS_NewString(ctx, "hello"));
|
||||
ASSERT_TRUE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(starts_with_no_match) {
|
||||
JSValue r = JS_CellStartsWith(ctx, JS_NewString(ctx, "hello world"), JS_NewString(ctx, "world"));
|
||||
ASSERT_FALSE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(starts_with_empty) {
|
||||
JSValue r = JS_CellStartsWith(ctx, JS_NewString(ctx, "hello"), JS_NewString(ctx, ""));
|
||||
ASSERT_TRUE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(ends_with_match) {
|
||||
JSValue r = JS_CellEndsWith(ctx, JS_NewString(ctx, "hello world"), JS_NewString(ctx, "world"));
|
||||
ASSERT_TRUE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(ends_with_no_match) {
|
||||
JSValue r = JS_CellEndsWith(ctx, JS_NewString(ctx, "hello world"), JS_NewString(ctx, "hello"));
|
||||
ASSERT_FALSE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(ends_with_full_match) {
|
||||
JSValue r = JS_CellEndsWith(ctx, JS_NewString(ctx, "test"), JS_NewString(ctx, "test"));
|
||||
ASSERT_TRUE(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Normalize C API Tests
|
||||
============================================================================ */
|
||||
|
||||
TEST(normalize_ascii) {
|
||||
JSValue r = JS_CellNormalize(ctx, JS_NewString(ctx, "hello"));
|
||||
ASSERT_STR(r, "hello");
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(normalize_non_text) {
|
||||
JSValue r = JS_CellNormalize(ctx, JS_NewInt32(ctx, 42));
|
||||
ASSERT_NULL(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(normalize_null) {
|
||||
JSValue r = JS_CellNormalize(ctx, JS_NULL);
|
||||
ASSERT_NULL(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(normalize_empty) {
|
||||
JSValue r = JS_CellNormalize(ctx, JS_NewString(ctx, ""));
|
||||
ASSERT_STR(r, "");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Format C API Tests
|
||||
============================================================================ */
|
||||
|
||||
TEST(format_array_placeholder) {
|
||||
JS_FRAME(ctx);
|
||||
JS_ROOT(arr, JS_NewArray(ctx));
|
||||
JSValue a = JS_NewString(ctx, "world");
|
||||
JS_SetPropertyNumber(ctx, arr.val, 0, a);
|
||||
JSValue r = JS_CellFormat(ctx, JS_NewString(ctx, "hello {0}"), arr.val, JS_NULL);
|
||||
ASSERT_STR(r, "hello world");
|
||||
JS_RETURN(JS_NewInt32(ctx, 1));
|
||||
}
|
||||
|
||||
TEST(format_record_placeholder) {
|
||||
JS_FRAME(ctx);
|
||||
JS_ROOT(rec, JS_NewObject(ctx));
|
||||
JSValue name = JS_NewString(ctx, "world");
|
||||
JS_SetPropertyStr(ctx, rec.val, "name", name);
|
||||
JSValue r = JS_CellFormat(ctx, JS_NewString(ctx, "hello {name}"), rec.val, JS_NULL);
|
||||
ASSERT_STR(r, "hello world");
|
||||
JS_RETURN(JS_NewInt32(ctx, 1));
|
||||
}
|
||||
|
||||
TEST(format_missing_key) {
|
||||
JS_FRAME(ctx);
|
||||
JS_ROOT(rec, JS_NewObject(ctx));
|
||||
JSValue r = JS_CellFormat(ctx, JS_NewString(ctx, "hello {name}"), rec.val, JS_NULL);
|
||||
ASSERT_STR(r, "hello null");
|
||||
JS_RETURN(JS_NewInt32(ctx, 1));
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Object C API Tests
|
||||
============================================================================ */
|
||||
|
||||
TEST(cell_object_null_null) {
|
||||
JSValue r = JS_CellObject(ctx, JS_NULL, JS_NULL);
|
||||
ASSERT_NULL(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(cell_object_copy) {
|
||||
JS_FRAME(ctx);
|
||||
JS_ROOT(orig, JS_NewObject(ctx));
|
||||
JS_SetPropertyStr(ctx, orig.val, "x", JS_NewInt32(ctx, 1));
|
||||
JSValue copy = JS_CellObject(ctx, orig.val, JS_NULL);
|
||||
ASSERT(JS_IsRecord(copy));
|
||||
JSValue x = JS_GetPropertyStr(ctx, copy, "x");
|
||||
ASSERT_INT(x, 1);
|
||||
JS_RETURN(JS_NewInt32(ctx, 1));
|
||||
}
|
||||
|
||||
TEST(cell_object_merge) {
|
||||
JS_FRAME(ctx);
|
||||
JS_ROOT(a, JS_NewObject(ctx));
|
||||
JS_SetPropertyStr(ctx, a.val, "x", JS_NewInt32(ctx, 1));
|
||||
JS_ROOT(b, JS_NewObject(ctx));
|
||||
JS_SetPropertyStr(ctx, b.val, "y", JS_NewInt32(ctx, 2));
|
||||
JSValue merged = JS_CellObject(ctx, a.val, b.val);
|
||||
ASSERT(JS_IsRecord(merged));
|
||||
JSValue x = JS_GetPropertyStr(ctx, merged, "x");
|
||||
JSValue y = JS_GetPropertyStr(ctx, merged, "y");
|
||||
ASSERT_INT(x, 1);
|
||||
ASSERT_INT(y, 2);
|
||||
JS_RETURN(JS_NewInt32(ctx, 1));
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Splat C API Tests
|
||||
============================================================================ */
|
||||
|
||||
TEST(cell_splat_non_object) {
|
||||
JSValue r = JS_CellSplat(ctx, JS_NewInt32(ctx, 42));
|
||||
ASSERT_NULL(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(cell_splat_null) {
|
||||
JSValue r = JS_CellSplat(ctx, JS_NULL);
|
||||
ASSERT_NULL(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(cell_splat_record) {
|
||||
JS_FRAME(ctx);
|
||||
JS_ROOT(obj, JS_NewObject(ctx));
|
||||
JS_SetPropertyStr(ctx, obj.val, "x", JS_NewInt32(ctx, 1));
|
||||
JSValue r = JS_CellSplat(ctx, obj.val);
|
||||
ASSERT(JS_IsRecord(r));
|
||||
JS_RETURN(JS_NewInt32(ctx, 1));
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
MAIN TEST RUNNER
|
||||
============================================================================ */
|
||||
@@ -2408,6 +2826,76 @@ int run_c_test_suite(JSContext *ctx)
|
||||
RUN_TEST(wota_encode_nested_array);
|
||||
RUN_TEST(wota_encode_blob);
|
||||
|
||||
printf("\nSensory Function C API:\n");
|
||||
RUN_TEST(is_true_true);
|
||||
RUN_TEST(is_true_false);
|
||||
RUN_TEST(is_false_false);
|
||||
RUN_TEST(is_false_other);
|
||||
RUN_TEST(is_data_values);
|
||||
RUN_TEST(is_data_non_data);
|
||||
RUN_TEST(is_fit_integers);
|
||||
RUN_TEST(is_fit_non_fit);
|
||||
RUN_TEST(is_character_single);
|
||||
RUN_TEST(is_character_non_char);
|
||||
RUN_TEST(is_digit_digits);
|
||||
RUN_TEST(is_digit_non_digit);
|
||||
RUN_TEST(is_letter_letters);
|
||||
RUN_TEST(is_letter_non_letter);
|
||||
RUN_TEST(is_lower_lowercase);
|
||||
RUN_TEST(is_lower_non_lower);
|
||||
RUN_TEST(is_upper_uppercase);
|
||||
RUN_TEST(is_upper_non_upper);
|
||||
RUN_TEST(is_whitespace_single);
|
||||
RUN_TEST(is_whitespace_multi);
|
||||
RUN_TEST(is_whitespace_non_ws);
|
||||
RUN_TEST(is_actor_non_actor);
|
||||
|
||||
printf("\nLogical/Whole/Fraction:\n");
|
||||
RUN_TEST(logical_zero);
|
||||
RUN_TEST(logical_one);
|
||||
RUN_TEST(logical_false);
|
||||
RUN_TEST(logical_true);
|
||||
RUN_TEST(logical_string_false);
|
||||
RUN_TEST(logical_string_true);
|
||||
RUN_TEST(logical_null);
|
||||
RUN_TEST(logical_invalid);
|
||||
RUN_TEST(whole_positive);
|
||||
RUN_TEST(whole_negative);
|
||||
RUN_TEST(whole_integer);
|
||||
RUN_TEST(whole_non_number);
|
||||
RUN_TEST(fraction_positive);
|
||||
RUN_TEST(fraction_negative);
|
||||
RUN_TEST(fraction_integer);
|
||||
RUN_TEST(fraction_non_number);
|
||||
|
||||
printf("\nStartsWith/EndsWith:\n");
|
||||
RUN_TEST(starts_with_match);
|
||||
RUN_TEST(starts_with_no_match);
|
||||
RUN_TEST(starts_with_empty);
|
||||
RUN_TEST(ends_with_match);
|
||||
RUN_TEST(ends_with_no_match);
|
||||
RUN_TEST(ends_with_full_match);
|
||||
|
||||
printf("\nNormalize:\n");
|
||||
RUN_TEST(normalize_ascii);
|
||||
RUN_TEST(normalize_non_text);
|
||||
RUN_TEST(normalize_null);
|
||||
RUN_TEST(normalize_empty);
|
||||
|
||||
printf("\nFormat:\n");
|
||||
RUN_TEST(format_array_placeholder);
|
||||
RUN_TEST(format_record_placeholder);
|
||||
RUN_TEST(format_missing_key);
|
||||
|
||||
printf("\nObject:\n");
|
||||
RUN_TEST(cell_object_null_null);
|
||||
RUN_TEST(cell_object_copy);
|
||||
RUN_TEST(cell_object_merge);
|
||||
|
||||
printf("\nSplat:\n");
|
||||
RUN_TEST(cell_splat_non_object);
|
||||
RUN_TEST(cell_splat_null);
|
||||
RUN_TEST(cell_splat_record);
|
||||
|
||||
printf("\n=================================\n");
|
||||
printf("Results: %d passed, %d failed\n", tests_passed, tests_failed);
|
||||
|
||||
Reference in New Issue
Block a user