fix tests; add comprehensive tests for functions and fix bugs in the mach VM regarding them.

This commit is contained in:
2026-02-24 17:41:18 -06:00
parent c2f57d1dae
commit 33d9013409
6 changed files with 1009 additions and 14 deletions

View File

@@ -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);