// Comprehensive test suite for cell runtime stability // Tests all core features before implementing performance optimizations // (bytecode passes, ICs, quickening, tail call optimization) // return { // ============================================================================ // ARITHMETIC OPERATORS - Numbers // ============================================================================ test_number_addition: function() { if (1 + 2 != 3) throw "basic addition failed" if (0 + 0 != 0) throw "zero addition failed" if (-5 + 3 != -2) throw "negative addition failed" if (0.1 + 0.2 - 0.3 > 0.0001) throw "float addition precision issue" }, test_number_subtraction: function() { if (5 - 3 != 2) throw "basic subtraction failed" if (0 - 5 != -5) throw "zero subtraction failed" if (-5 - -3 != -2) throw "negative subtraction failed" }, test_number_multiplication: function() { if (3 * 4 != 12) throw "basic multiplication failed" if (0 * 100 != 0) throw "zero multiplication failed" if (-3 * 4 != -12) throw "negative multiplication failed" if (-3 * -4 != 12) throw "double negative multiplication failed" }, test_number_division: function() { if (12 / 4 != 3) throw "basic division failed" if (1 / 2 != 0.5) throw "fractional division failed" if (-12 / 4 != -3) throw "negative division failed" if (12 / -4 != -3) throw "division by negative failed" }, test_number_modulo: function() { if (10 % 3 != 1) throw "basic modulo failed" if (10 % 5 != 0) throw "even modulo failed" if (-10 % 3 != -1) throw "negative modulo failed" }, test_number_exponentiation: function() { if (2 ** 3 != 8) throw "basic exponentiation failed" if (5 ** 0 != 1) throw "zero exponent failed" if (2 ** -1 != 0.5) throw "negative exponent failed" }, // ============================================================================ // STRING OPERATORS // ============================================================================ test_string_plus_string_works: function() { var x = "hello" + " world" if (x != "hello world") throw "string + string should work" }, test_string_concatenation_empty: function() { if ("" + "" != "") throw "empty string concatenation failed" if ("hello" + "" != "hello") throw "concatenation with empty string failed" if ("" + "world" != "world") throw "empty + string failed" }, // ============================================================================ // TYPE MIXING SHOULD THROW // ============================================================================ test_number_plus_string_throws: function() { var caught = false try { var x = 1 + "hello" } catch (e) { caught = true } if (!caught) throw "number + string should throw" }, test_string_plus_number_throws: function() { var caught = false try { var x = "hello" + 1 } catch (e) { caught = true } if (!caught) throw "string + number should throw" }, test_object_plus_string_throws: function() { var caught = false try { var x = {} + "hello" } catch (e) { caught = true } if (!caught) throw "object + string should throw" }, test_string_plus_object_throws: function() { var caught = false try { var x = "hello" + {} } catch (e) { caught = true } if (!caught) throw "string + object should throw" }, test_array_plus_string_throws: function() { var caught = false try { var x = [] + "hello" } catch (e) { caught = true } if (!caught) throw "array + string should throw" }, test_string_plus_array_throws: function() { var caught = false try { var x = "hello" + [] } catch (e) { caught = true } if (!caught) throw "string + array should throw" }, test_boolean_plus_string_throws: function() { var caught = false try { var x = true + "hello" } catch (e) { caught = true } if (!caught) throw "boolean + string should throw" }, test_string_plus_boolean_throws: function() { var caught = false try { var x = "hello" + false } catch (e) { caught = true } if (!caught) throw "string + boolean should throw" }, test_null_plus_string_throws: function() { var caught = false try { var x = null + "hello" } catch (e) { caught = true } if (!caught) throw "null + string should throw" }, test_string_plus_null_throws: function() { var caught = false try { var x = "hello" + null } catch (e) { caught = true } if (!caught) throw "string + null should throw" }, // ============================================================================ // COMPARISON OPERATORS // ============================================================================ test_equality_numbers: function() { if (!(5 == 5)) throw "number equality failed" if (5 == 6) throw "number inequality detection failed" if (!(0 == 0)) throw "zero equality failed" if (!(-5 == -5)) throw "negative equality failed" }, test_inequality_numbers: function() { if (5 != 5) throw "number inequality failed" if (!(5 != 6)) throw "number difference detection failed" }, test_less_than: function() { if (!(3 < 5)) throw "less than failed" if (5 < 3) throw "not less than failed" if (5 < 5) throw "equal not less than failed" }, test_less_than_or_equal: function() { if (!(3 <= 5)) throw "less than or equal failed" if (!(5 <= 5)) throw "equal in less than or equal failed" if (6 <= 5) throw "not less than or equal failed" }, test_greater_than: function() { if (!(5 > 3)) throw "greater than failed" if (3 > 5) throw "not greater than failed" if (5 > 5) throw "equal not greater than failed" }, test_greater_than_or_equal: function() { if (!(5 >= 3)) throw "greater than or equal failed" if (!(5 >= 5)) throw "equal in greater than or equal failed" if (3 >= 5) throw "not greater than or equal failed" }, test_string_equality: function() { if (!("hello" == "hello")) throw "string equality failed" if ("hello" == "world") throw "string inequality detection failed" if (!("" == "")) throw "empty string equality failed" }, test_null_equality: function() { if (!(null == null)) throw "null equality failed" if (null == 0) throw "null should not equal 0" if (null == false) throw "null should not equal false" if (null == "") throw "null should not equal empty string" }, test_boolean_equality: function() { if (!(true == true)) throw "true equality failed" if (!(false == false)) throw "false equality failed" if (true == false) throw "boolean inequality detection failed" }, // ============================================================================ // LOGICAL OPERATORS // ============================================================================ test_logical_and: function() { if (!(true && true)) throw "true && true failed" if (true && false) throw "true && false failed" if (false && true) throw "false && true failed" if (false && false) throw "false && false failed" }, test_logical_or: function() { if (!(true || true)) throw "true || true failed" if (!(true || false)) throw "true || false failed" if (!(false || true)) throw "false || true failed" if (false || false) throw "false || false failed" }, test_logical_not: function() { if (!(!false)) throw "!false failed" if (!true) throw "!true failed" }, test_short_circuit_and: function() { var called = false var fn = function() { called = true; return true } var result = false && fn() if (called) throw "AND should short circuit" }, test_short_circuit_or: function() { var called = false var fn = function() { called = true; return false } var result = true || fn() if (called) throw "OR should short circuit" }, // ============================================================================ // BITWISE OPERATORS // ============================================================================ test_bitwise_and: function() { if ((5 & 3) != 1) throw "bitwise AND failed" if ((12 & 10) != 8) throw "bitwise AND failed" }, test_bitwise_or: function() { if ((5 | 3) != 7) throw "bitwise OR failed" if ((12 | 10) != 14) throw "bitwise OR failed" }, test_bitwise_xor: function() { if ((5 ^ 3) != 6) throw "bitwise XOR failed" if ((12 ^ 10) != 6) throw "bitwise XOR failed" }, test_bitwise_not: function() { if (~5 != -6) throw "bitwise NOT failed" if (~0 != -1) throw "bitwise NOT of zero failed" }, test_left_shift: function() { if ((5 << 2) != 20) throw "left shift failed" if ((1 << 3) != 8) throw "left shift failed" }, test_right_shift: function() { if ((20 >> 2) != 5) throw "right shift failed" if ((8 >> 3) != 1) throw "right shift failed" }, test_unsigned_right_shift: function() { if ((-1 >>> 1) != 2147483647) throw "unsigned right shift failed" }, // ============================================================================ // VARIABLE DECLARATIONS AND SCOPING // ============================================================================ test_var_declaration: function() { var x = 5 if (x != 5) throw "var declaration failed" }, test_var_reassignment: function() { var x = 5 x = 10 if (x != 10) throw "var reassignment failed" }, // ============================================================================ // VAR BLOCK SCOPING (var now behaves like let) // ============================================================================ test_var_block_scope_basic: function() { var x = 1 { var x = 2 if (x != 2) throw "var should be block scoped - inner scope failed" } if (x != 1) throw "var should be block scoped - outer scope affected" }, test_var_block_scope_if: function() { var x = 1 if (true) { var x = 2 if (x != 2) throw "var in if block should be scoped" } if (x != 1) throw "var in if block should not affect outer scope" }, test_var_block_scope_for: function() { var x = 1 for (var i = 0; i < 1; i = i + 1) { var x = 2 if (x != 2) throw "var in for block should be scoped" } if (x != 1) throw "var in for block should not affect outer scope" }, test_var_for_loop_iterator_scope: function() { var sum = 0 for (var i = 0; i < 3; i = i + 1) { sum = sum + i } if (sum != 3) throw "for loop should work with block scoped var" var caught = false try { var y = i } catch (e) { caught = true } if (!caught) throw "for loop iterator should not leak to outer scope" }, test_var_nested_blocks: function() { var x = 1 { var x = 2 { var x = 3 if (x != 3) throw "var in nested block level 2 failed" } if (x != 2) throw "var in nested block level 1 failed" } if (x != 1) throw "var in nested blocks outer scope failed" }, test_var_redeclaration_different_scope: function() { var x = 1 { var x = 2 } if (x != 1) throw "var in different scope should not affect outer" }, test_var_switch_scope: function() { var x = 1 switch (1) { case 1: var x = 2 if (x != 2) throw "var in switch should be block scoped" break } if (x != 1) throw "var in switch should not affect outer scope" }, test_var_while_scope: function() { var x = 1 var count = 0 while (count < 1) { var x = 2 if (x != 2) throw "var in while should be block scoped" count = count + 1 } if (x != 1) throw "var in while should not affect outer scope" }, test_var_no_initialization: function() { { var x if (x != null) throw "uninitialized var should be null" } }, test_multiple_var_declaration: function() { var a = 1, b = 2, c = 3 if (a != 1 || b != 2 || c != 3) throw "multiple var declaration failed" }, test_function_scope: function() { var outer = "outer" var fn = function() { var inner = "inner" return inner } if (fn() != "inner") throw "function scope failed" }, // ============================================================================ // FUNCTION CALLS // ============================================================================ test_function_call_no_args: function() { var fn = function() { return 42 } if (fn() != 42) throw "function call with no args failed" }, test_function_call_one_arg: function() { var fn = function(x) { return x * 2 } if (fn(5) != 10) throw "function call with one arg failed" }, test_function_call_multiple_args: function() { var fn = function(a, b, c) { return a + b + c } if (fn(1, 2, 3) != 6) throw "function call with multiple args failed" }, test_function_call_extra_args: function() { var fn = function(a, b) { return a + b } if (fn(1, 2, 3, 4) != 3) throw "function call with extra args failed" }, test_function_call_missing_args: function() { var fn = function(a, b, c) { return (a || 0) + (b || 0) + (c || 0) } if (fn(1) != 1) throw "function call with missing args failed" }, test_function_return: function() { var fn = function() { return 5 } if (fn() != 5) throw "function return failed" }, test_function_return_early: function() { var fn = function() { return 5 return 10 } if (fn() != 5) throw "early return failed" }, test_function_no_return: function() { var fn = function() { var x = 5 } if (fn() != null) throw "function with no return should return null" }, test_nested_function_calls: function() { var add = function(a, b) { return a + b } var mul = function(a, b) { return a * b } if (add(mul(2, 3), mul(4, 5)) != 26) throw "nested function calls failed" }, test_function_as_value: function() { var fn = function() { return 42 } var fn2 = fn if (fn2() != 42) throw "function as value failed" }, test_function_closure: function() { var outer = function(x) { return function(y) { return x + y } } var add5 = outer(5) if (add5(3) != 8) throw "closure failed" }, test_function_closure_mutation: function() { var counter = function() { var count = 0 return function() { count = count + 1 return count } } var c = counter() if (c() != 1) throw "closure mutation failed (1)" if (c() != 2) throw "closure mutation failed (2)" if (c() != 3) throw "closure mutation failed (3)" }, // ============================================================================ // RECURSION // ============================================================================ test_simple_recursion: function() { var factorial = function(n) { if (n <= 1) return 1 return n * factorial(n - 1) } if (factorial(5) != 120) throw "factorial recursion failed" }, test_mutual_recursion: function() { var isEven = function(n) { if (n == 0) return true return isOdd(n - 1) } var isOdd = function(n) { if (n == 0) return false return isEven(n - 1) } if (!isEven(4)) throw "mutual recursion even failed" if (isOdd(4)) throw "mutual recursion odd failed" }, test_deep_recursion: function() { var sum = function(n) { if (n == 0) return 0 return n + sum(n - 1) } if (sum(100) != 5050) throw "deep recursion failed" }, // ============================================================================ // ARRAYS // ============================================================================ test_array_literal: function() { var arr = [1, 2, 3] if (arr[0] != 1 || arr[1] != 2 || arr[2] != 3) throw "array literal failed" }, test_array_length: function() { var arr = [1, 2, 3, 4, 5] if (length(arr) != 5) throw "array length failed" }, test_array_empty: function() { var arr = [] if (length(arr) != 0) throw "empty array length failed" }, test_array_push: function() { var arr = [1, 2] push(arr, 3) if (length(arr) != 3) throw "array push length failed" if (arr[2] != 3) throw "array push value failed" }, test_array_pop: function() { var arr = [1, 2, 3] var val = pop(arr) if (val != 3) throw "array pop value failed" if (length(arr) != 2) throw "array pop length failed" }, test_array_index_access: function() { var arr = [10, 20, 30] if (arr[0] != 10) throw "array index 0 failed" if (arr[1] != 20) throw "array index 1 failed" if (arr[2] != 30) throw "array index 2 failed" }, test_array_index_assignment: function() { var arr = [1, 2, 3] arr[1] = 99 if (arr[1] != 99) throw "array index assignment failed" }, test_array_mixed_types: function() { var arr = [1, "hello", true, null, {}] if (arr[0] != 1) throw "mixed array number failed" if (arr[1] != "hello") throw "mixed array string failed" if (arr[2] != true) throw "mixed array boolean failed" if (arr[3] != null) throw "mixed array null failed" }, test_array_nested: function() { var arr = [[1, 2], [3, 4]] if (arr[0][0] != 1) throw "nested array access failed" if (arr[1][1] != 4) throw "nested array access failed" }, // ============================================================================ // OBJECTS // ============================================================================ test_object_literal: function() { var obj = {a: 1, b: 2} if (obj.a != 1 || obj.b != 2) throw "object literal failed" }, test_object_property_access: function() { var obj = {name: "Alice", age: 30} if (obj.name != "Alice") throw "object property access failed" if (obj.age != 30) throw "object property access failed" }, test_object_bracket_access: function() { var obj = {x: 10, y: 20} if (obj["x"] != 10) throw "object bracket access failed" if (obj["y"] != 20) throw "object bracket access failed" }, test_object_property_assignment: function() { var obj = {a: 1} obj.a = 99 if (obj.a != 99) throw "object property assignment failed" }, test_object_add_property: function() { var obj = {} obj.newProp = 42 if (obj.newProp != 42) throw "object add property failed" }, test_object_computed_property: function() { var key = "dynamicKey" var obj = {} obj[key] = 123 if (obj.dynamicKey != 123) throw "object computed property failed" }, test_object_nested: function() { var obj = {outer: {inner: 42}} if (obj.outer.inner != 42) throw "nested object access failed" }, test_object_method: function() { var obj = { value: 10, getValue: function() { return this.value } } if (obj.getValue() != 10) throw "object method failed" }, test_object_this_binding: function() { var obj = { x: 5, getX: function() { return this.x } } if (obj.getX() != 5) throw "this binding failed" }, // ============================================================================ // CONTROL FLOW - IF/ELSE // ============================================================================ test_if_true: function() { var x = 0 if (true) x = 1 if (x != 1) throw "if true failed" }, test_if_false: function() { var x = 0 if (false) x = 1 if (x != 0) throw "if false failed" }, test_if_else_true: function() { var x = 0 if (true) x = 1 else x = 2 if (x != 1) throw "if else true failed" }, test_if_else_false: function() { var x = 0 if (false) x = 1 else x = 2 if (x != 2) throw "if else false failed" }, test_if_else_if: function() { var x = 0 if (false) x = 1 else if (true) x = 2 else x = 3 if (x != 2) throw "if else if failed" }, test_nested_if: function() { var x = 0 if (true) { if (true) { x = 1 } } if (x != 1) throw "nested if failed" }, // ============================================================================ // CONTROL FLOW - WHILE LOOPS // ============================================================================ test_while_loop: function() { var i = 0 var sum = 0 while (i < 5) { sum = sum + i i = i + 1 } if (sum != 10) throw "while loop failed" }, test_while_never_executes: function() { var x = 0 while (false) { x = 1 } if (x != 0) throw "while never executes failed" }, test_while_break: function() { var i = 0 while (true) { if (i >= 5) break i = i + 1 } if (i != 5) throw "while break failed" }, test_while_continue: function() { var i = 0 var sum = 0 while (i < 10) { i = i + 1 if (i % 2 == 0) continue sum = sum + i } if (sum != 25) throw "while continue failed" }, // ============================================================================ // CONTROL FLOW - FOR LOOPS // ============================================================================ test_for_loop: function() { var sum = 0 for (var i = 0; i < 5; i = i + 1) { sum = sum + i } if (sum != 10) throw "for loop failed" }, test_for_loop_break: function() { var sum = 0 for (var i = 0; i < 10; i = i + 1) { if (i == 5) break sum = sum + i } if (sum != 10) throw "for loop break failed" }, test_for_loop_continue: function() { var sum = 0 for (var i = 0; i < 10; i = i + 1) { if (i % 2 == 0) continue sum = sum + i } if (sum != 25) throw "for loop continue failed" }, test_nested_for_loops: function() { var sum = 0 for (var i = 0; i < 3; i = i + 1) { for (var j = 0; j < 3; j = j + 1) { sum = sum + 1 } } if (sum != 9) throw "nested for loops failed" }, // ============================================================================ // CONTROL FLOW - SWITCH // ============================================================================ test_switch_case: function() { var x = 2 var result = 0 switch (x) { case 1: result = 10 break case 2: result = 20 break case 3: result = 30 break } if (result != 20) throw "switch case failed" }, test_switch_default: function() { var x = 99 var result = 0 switch (x) { case 1: result = 10 break default: result = -1 break } if (result != -1) throw "switch default failed" }, test_switch_fallthrough: function() { var x = 1 var result = 0 switch (x) { case 1: result = result + 1 case 2: result = result + 2 break case 3: result = result + 3 break } if (result != 3) throw "switch fallthrough failed" }, // ============================================================================ // ERROR HANDLING - TRY/CATCH // ============================================================================ test_try_catch: function() { var caught = false try { throw "error" } catch (e) { caught = true } if (!caught) throw "try catch failed" }, test_try_catch_error_value: function() { var errorMsg = null try { throw "my error" } catch (e) { errorMsg = e } if (errorMsg != "my error") throw "try catch error value failed" }, test_try_no_error: function() { var x = 0 try { x = 1 } catch (e) { x = 2 } if (x != 1) throw "try no error failed" }, test_nested_try_catch: function() { var x = 0 try { try { throw "inner" } catch (e) { x = 1 } x = 2 } catch (e) { x = 3 } if (x != 2) throw "nested try catch failed" }, test_try_catch_rethrow: function() { var outerCaught = false try { try { throw "error" } catch (e) { throw e } } catch (e) { outerCaught = true } if (!outerCaught) throw "try catch rethrow failed" }, // ============================================================================ // TYPE CHECKING WITH is_* FUNCTIONS // ============================================================================ test_is_number: function() { if (!is_number(42)) throw "is_number 42 failed" if (!is_number(3.14)) throw "is_number float failed" if (!is_number(-5)) throw "is_number negative failed" if (is_number("42")) throw "is_number string should be false" if (is_number(true)) throw "is_number boolean should be false" if (is_number(null)) throw "is_number null should be false" if (is_number({})) throw "is_number object should be false" if (is_number([])) throw "is_number array should be false" }, test_is_text: function() { if (!is_text("hello")) throw "is_text string failed" if (!is_text("")) throw "is_text empty string failed" if (is_text(42)) throw "is_text number should be false" if (is_text(true)) throw "is_text boolean should be false" if (is_text(null)) throw "is_text null should be false" if (is_text({})) throw "is_text object should be false" if (is_text([])) throw "is_text array should be false" }, test_is_logical: function() { if (!is_logical(true)) throw "is_logical true failed" if (!is_logical(false)) throw "is_logical false failed" if (is_logical(1)) throw "is_logical number should be false" if (is_logical("true")) throw "is_logical string should be false" if (is_logical(null)) throw "is_logical null should be false" if (is_logical({})) throw "is_logical object should be false" if (is_logical([])) throw "is_logical array should be false" }, test_is_object: function() { if (!is_object({})) throw "is_object empty object failed" if (!is_object({a: 1})) throw "is_object object failed" if (is_object([])) throw "is_object array should be false" if (is_object(null)) throw "is_object null should be false" if (is_object(42)) throw "is_object number should be false" if (is_object("hello")) throw "is_object string should be false" if (is_object(true)) throw "is_object boolean should be false" }, test_is_array: function() { if (!is_array([])) throw "is_array empty array failed" if (!is_array([1, 2, 3])) throw "is_array array failed" if (is_array({})) throw "is_array object should be false" if (is_array(null)) throw "is_array null should be false" if (is_array(42)) throw "is_array number should be false" if (is_array("hello")) throw "is_array string should be false" if (is_array(true)) throw "is_array boolean should be false" }, test_is_function: function() { if (!is_function(function(){})) throw "is_function function failed" var fn = function(x) { return x * 2 } if (!is_function(fn)) throw "is_function named function failed" if (is_function({})) throw "is_function object should be false" if (is_function([])) throw "is_function array should be false" if (is_function(null)) throw "is_function null should be false" if (is_function(42)) throw "is_function number should be false" if (is_function("hello")) throw "is_function string should be false" if (is_function(true)) throw "is_function boolean should be false" }, test_is_null: function() { if (!is_null(null)) throw "is_null null failed" if (is_null(0)) throw "is_null zero should be false" if (is_null(false)) throw "is_null false should be false" if (is_null("")) throw "is_null empty string should be false" if (is_null({})) throw "is_null object should be false" if (is_null([])) throw "is_null array should be false" var x if (!is_null(x)) throw "is_null undefined variable should be true" }, test_is_blob: function() { // Note: blob testing would require actual blob values // For now, just test that other types return false if (is_blob(null)) throw "is_blob null should be false" if (is_blob(42)) throw "is_blob number should be false" if (is_blob("hello")) throw "is_blob string should be false" if (is_blob(true)) throw "is_blob boolean should be false" if (is_blob({})) throw "is_blob object should be false" if (is_blob([])) throw "is_blob array should be false" if (is_blob(function(){})) throw "is_blob function should be false" }, test_is_proto: function() { var a = {} var b = meme(a) if (!is_proto(b, a)) throw "is_proto failed on meme" }, // ============================================================================ // GLOBAL FUNCTIONS - LENGTH // ============================================================================ test_length_string: function() { if (length("hello") != 5) throw "length string failed" if (length("") != 0) throw "length empty string failed" }, test_length_array: function() { if (length([1,2,3]) != 3) throw "length array failed" if (length([]) != 0) throw "length empty array failed" }, test_length_null: function() { if (length(null) != null) throw "length null failed" }, test_length_number: function() { if (length(123) != null) throw "length number should return null" }, // ============================================================================ // GLOBAL FUNCTIONS - REVERSE // ============================================================================ test_reverse_array: function() { var arr = [1, 2, 3, 4, 5] var rev = reverse(arr) if (rev[0] != 5) throw "reverse array first failed" if (rev[4] != 1) throw "reverse array last failed" if (length(rev) != 5) throw "reverse array length failed" }, test_reverse_empty_array: function() { var rev = reverse([]) if (length(rev) != 0) throw "reverse empty array failed" }, test_reverse_preserves_original: function() { var arr = [1, 2, 3] var rev = reverse(arr) if (arr[0] != 1) throw "reverse should not mutate original" }, // ============================================================================ // GLOBAL FUNCTIONS - MEME (PROTOTYPAL INHERITANCE) // ============================================================================ test_meme_basic: function() { var parent = {x: 10} var child = meme(parent) if (child.x != 10) throw "meme basic inheritance failed" }, test_meme_with_mixins: function() { var parent = {x: 10} var mixin = {y: 20} var child = meme(parent, mixin) if (child.x != 10) throw "meme with mixin parent prop failed" if (child.y != 20) throw "meme with mixin own prop failed" }, test_meme_override: function() { var parent = {x: 10} var child = meme(parent) child.x = 20 if (child.x != 20) throw "meme override failed" if (parent.x != 10) throw "meme should not mutate parent" }, test_meme_multiple_mixins: function() { var parent = {a: 1} var mixin1 = {b: 2} var mixin2 = {c: 3} var child = meme(parent, mixin1, mixin2) if (child.a != 1 || child.b != 2 || child.c != 3) throw "meme multiple mixins failed" }, // ============================================================================ // GLOBAL FUNCTIONS - PROTO // ============================================================================ test_proto_basic: function() { var parent = {x: 10} var child = meme(parent) var p = proto(child) if (p != parent) throw "proto basic failed" }, test_proto_object_literal: function() { var obj = {x: 10} var p = proto(obj) if (p != null) throw "proto of object literal should be null" }, test_proto_non_object: function() { if (proto(42) != null) throw "proto of number should return null" if (proto("hello") != null) throw "proto of string should return null" }, // ============================================================================ // GLOBAL FUNCTIONS - STONE (FREEZE) // ============================================================================ test_stone_object: function() { var obj = {x: 10} stone(obj) var caught = false try { obj.x = 20 } catch (e) { caught = true } if (!caught) throw "stone object should prevent modification" }, test_is_stone_frozen: function() { var obj = {x: 10} if (is_stone(obj)) throw "stone.p should return false before freezing" stone(obj) if (!is_stone(obj)) throw "stone.p should return true after freezing" }, test_stone_array: function() { var arr = [1, 2, 3] stone(arr) var caught = false try { arr[0] = 99 } catch (e) { caught = true } if (!caught) throw "stone array should prevent modification" }, // ============================================================================ // TERNARY OPERATOR // ============================================================================ test_ternary_true: function() { var x = true ? 1 : 2 if (x != 1) throw "ternary true failed" }, test_ternary_false: function() { var x = false ? 1 : 2 if (x != 2) throw "ternary false failed" }, test_ternary_nested: function() { var x = true ? (false ? 1 : 2) : 3 if (x != 2) throw "ternary nested failed" }, test_ternary_with_expressions: function() { var a = 5 var b = 10 var max = (a > b) ? a : b if (max != 10) throw "ternary with expressions failed" }, // ============================================================================ // UNARY OPERATORS // ============================================================================ test_unary_plus: function() { if (+5 != 5) throw "unary plus positive failed" if (+-5 != -5) throw "unary plus negative failed" }, test_unary_minus: function() { if (-5 != -5) throw "unary minus failed" if (-(-5) != 5) throw "double unary minus failed" }, test_increment_postfix: function() { var x = 5 var y = x++ if (y != 5) throw "postfix increment return value failed" if (x != 6) throw "postfix increment side effect failed" }, test_increment_prefix: function() { var x = 5 var y = ++x if (y != 6) throw "prefix increment return value failed" if (x != 6) throw "prefix increment side effect failed" }, test_decrement_postfix: function() { var x = 5 var y = x-- if (y != 5) throw "postfix decrement return value failed" if (x != 4) throw "postfix decrement side effect failed" }, test_decrement_prefix: function() { var x = 5 var y = --x if (y != 4) throw "prefix decrement return value failed" if (x != 4) throw "prefix decrement side effect failed" }, // ============================================================================ // COMPOUND ASSIGNMENT OPERATORS // ============================================================================ test_plus_equals: function() { var x = 5 x += 3 if (x != 8) throw "plus equals failed" }, test_minus_equals: function() { var x = 10 x -= 3 if (x != 7) throw "minus equals failed" }, test_times_equals: function() { var x = 4 x *= 3 if (x != 12) throw "times equals failed" }, test_divide_equals: function() { var x = 12 x /= 3 if (x != 4) throw "divide equals failed" }, test_modulo_equals: function() { var x = 10 x %= 3 if (x != 1) throw "modulo equals failed" }, // ============================================================================ // EDGE CASES AND SPECIAL VALUES // ============================================================================ test_infinity: function() { var inf = 1 / 0 if (!(inf > 1000000)) throw "infinity failed" if (!(-inf < -1000000)) throw "negative infinity failed" }, test_nan: function() { var nan = 0 / 0 if (nan == nan) throw "NaN should not equal itself" }, test_max_safe_integer: function() { var max = 9007199254740991 if (max + 1 - 1 != max) throw "max safe integer precision lost" }, test_min_safe_integer: function() { var min = -9007199254740991 if (min - 1 + 1 != min) throw "min safe integer precision lost" }, test_empty_string_falsy: function() { if ("") throw "empty string should be falsy" }, test_zero_falsy: function() { if (0) throw "zero should be falsy" }, test_null_falsy: function() { if (null) throw "null should be falsy" }, test_false_falsy: function() { if (false) throw "false should be falsy" }, test_nonempty_string_truthy: function() { if (!"hello") throw "non-empty string should be truthy" }, test_nonzero_number_truthy: function() { if (!42) throw "non-zero number should be truthy" }, test_object_truthy: function() { if (!{}) throw "empty object should be truthy" }, test_array_truthy: function() { if (![]) throw "empty array should be truthy" }, // ============================================================================ // OPERATOR PRECEDENCE // ============================================================================ test_precedence_multiply_add: function() { if (2 + 3 * 4 != 14) throw "multiply before add precedence failed" }, test_precedence_parentheses: function() { if ((2 + 3) * 4 != 20) throw "parentheses precedence failed" }, test_precedence_comparison_logical: function() { if (!(1 < 2 && 3 < 4)) throw "comparison before logical precedence failed" }, test_precedence_equality_logical: function() { if (!(1 == 1 || 2 == 3)) throw "equality before logical precedence failed" }, test_precedence_unary_multiplication: function() { if (-2 * 3 != -6) throw "unary before multiplication precedence failed" }, // ============================================================================ // COMMA OPERATOR // ============================================================================ test_comma_operator: function() { var x = (1, 2, 3) if (x != 3) throw "comma operator failed" }, test_comma_operator_with_side_effects: function() { var a = 0 var x = (a = 1, a = 2, a + 1) if (x != 3) throw "comma operator with side effects failed" if (a != 2) throw "comma operator side effects failed" }, // ============================================================================ // VARIABLE SHADOWING // ============================================================================ test_variable_shadowing_function: function() { var x = 10 var fn = function() { var x = 20 return x } if (fn() != 20) throw "function shadowing failed" if (x != 10) throw "outer variable after shadowing failed" }, test_variable_shadowing_nested: function() { var x = 10 var fn1 = function() { var x = 20 var fn2 = function() { var x = 30 return x } return fn2() + x } if (fn1() != 50) throw "nested shadowing failed" }, // ============================================================================ // FUNCTION ARITY // ============================================================================ test_function_length_property: function() { var fn0 = function() {} var fn1 = function(a) {} var fn2 = function(a, b) {} if (length(fn0) != 0) throw "function length 0 failed" if (length(fn1) != 1) throw "function length 1 failed" if (length(fn2) != 2) throw "function length 2 failed" }, // ============================================================================ // NULL AND UNDEFINED BEHAVIOR // ============================================================================ test_undefined_variable_is_null: function() { var x if (x != null) throw "undefined variable should be null" }, // ============================================================================ // NUMBERS - SPECIAL OPERATIONS // ============================================================================ test_number_toString_implicit: function() { var n = 42 var caught = false try { var result = n + "" } catch (e) { caught = true } if (!caught) throw "number + string should throw" }, test_number_division_by_zero: function() { var result = 1 / 0 if (!(result > 1000000)) throw "division by zero should give infinity" }, test_number_negative_division_by_zero: function() { var result = -1 / 0 if (!(result < -1000000)) throw "negative division by zero should give -infinity" }, test_zero_division_by_zero: function() { var result = 0 / 0 if (result == result) throw "0/0 should give NaN" }, // ============================================================================ // OBJECT PROPERTY EXISTENCE // ============================================================================ test_in_operator: function() { var obj = {a: 1, b: 2} if (!("a" in obj)) throw "in operator for existing property failed" if ("c" in obj) throw "in operator for non-existing property failed" }, test_in_operator_prototype: function() { var parent = {x: 10} var child = meme(parent) if (!("x" in child)) throw "in operator should find inherited property" }, // ============================================================================ // GLOBAL FUNCTIONS - LOGICAL // ============================================================================ test_logical_function_numbers: function() { if (logical(0) != false) throw "logical(0) should be false" if (logical(1) != true) throw "logical(1) should be true" }, test_logical_function_strings: function() { if (logical("false") != false) throw "logical('false') should be false" if (logical("true") != true) throw "logical('true') should be true" }, test_logical_function_booleans: function() { if (logical(false) != false) throw "logical(false) should be false" if (logical(true) != true) throw "logical(true) should be true" }, test_logical_function_null: function() { if (logical(null) != false) throw "logical(null) should be false" }, test_logical_function_invalid: function() { if (logical("invalid") != null) throw "logical(invalid) should return null" if (logical(42) != null) throw "logical(42) should return null" }, // ============================================================================ // ARRAY METHODS // ============================================================================ test_array_concat: function() { var arr1 = [1, 2] var arr2 = [3, 4] var combined = array(arr1, arr2) if (length(combined) != 4) throw "array concat length failed" if (combined[2] != 3) throw "array concat values failed" }, test_array_join: function() { var arr = ["a", "b", "c"] var str = text(arr, ",") if (str != "a,b,c") throw "array join with text() failed" }, test_text_array_join_numbers_throw: function() { var caught = false try { text([1, 2, 3], ",") } catch (e) { caught = true } if (!caught) throw "text([numbers], sep) should throw (no implicit coercion)" }, test_text_array_join_numbers_explicit: function() { var arr = array([1, 2, 3], x => text(x)) if (text(arr, ",") != "1,2,3") throw "explicit numeric join failed" }, // ============================================================================ // STRING METHODS // ============================================================================ test_string_substring: function() { var str = "hello" if (text(str, 1, 4) != "ell") throw "string substring failed" }, test_string_substring_first: function() { var str = "hello" if (text(str, 1) != "ello") throw "string substring first failed" }, test_string_substring_to_neg: function() { var str = "hello" if (text(str, 1, -2) != "el") throw "string substring to negative failed" }, test_string_slice: function() { var str = "hello" if (text(str, 1, 4) != "ell") throw "string slice failed" if (text(str, -2) != "lo") throw "string slice negative failed: " + text(str, -2) }, test_string_indexOf: function() { var str = "hello world" if (search(str, "world") != 6) throw "string search failed" if (search(str, "xyz") != null) throw "string search not found failed" }, test_string_toLowerCase: function() { var str = "HELLO" if (lower(str) != "hello") throw "string toLowerCase failed" }, test_string_toUpperCase: function() { var str = "hello" if (upper(str) != "HELLO") throw "string toUpperCase failed" }, test_string_split: function() { var str = "a,b,c" var parts = array(str, ",") if (length(parts) != 3) throw "string split length failed" if (parts[1] != "b") throw "string split values failed" }, null_access: function() { var val = {} var nn = val.a if (nn != null) throw "val.a should return null" }, // ============================================================================ // OBJECT-AS-KEY (Private Property Access) // ============================================================================ test_object_key_basic: function() { var k1 = {} var k2 = {} var o = {} o[k1] = 123 o[k2] = 456 if (o[k1] != 123) throw "object key k1 failed" if (o[k2] != 456) throw "object key k2 failed" }, test_object_key_new_object_different_key: function() { var k1 = {} var o = {} o[k1] = 123 if (o[{}] != null) throw "new object should be different key" }, test_object_key_in_operator: function() { var k1 = {} var o = {} o[k1] = 123 if (!(k1 in o)) throw "in operator should find object key" }, test_object_key_delete: function() { var k1 = {} var o = {} o[k1] = 123 delete o[k1] if ((k1 in o)) throw "delete should remove object key" }, test_object_key_no_string_collision: function() { var a = {} var b = {} var o = {} o[a] = 1 o[b] = 2 if (o[a] != 1) throw "object key a should be 1" if (o[b] != 2) throw "object key b should be 2" }, test_object_key_same_object_same_key: function() { var k = {} var o = {} o[k] = 100 o[k] = 200 if (o[k] != 200) throw "same object should be same key" }, test_object_key_computed_property: function() { var k = {} var o = {} o[k] = function() { return 42 } if (o[k]() != 42) throw "object key with function value failed" }, test_object_key_multiple_objects_multiple_keys: function() { var k1 = {} var k2 = {} var k3 = {} var o = {} o[k1] = "one" o[k2] = "two" o[k3] = "three" if (o[k1] != "one") throw "multiple keys k1 failed" if (o[k2] != "two") throw "multiple keys k2 failed" if (o[k3] != "three") throw "multiple keys k3 failed" }, test_object_key_with_string_keys: function() { var k = {} var o = {name: "test"} o[k] = "private" if (o.name != "test") throw "string key should still work" if (o[k] != "private") throw "object key should work with string keys" }, test_object_key_overwrite: function() { var k = {} var o = {} o[k] = 1 o[k] = 2 o[k] = 3 if (o[k] != 3) throw "object key overwrite failed" }, test_object_key_nested_objects: function() { var k1 = {} var k2 = {} var inner = {} inner[k2] = "nested" var outer = {} outer[k1] = inner if (outer[k1][k2] != "nested") throw "nested object keys failed" }, test_array_for: function() { var a = [1,2,3] arrfor(a, (x,i) => { if (x-1 != i) throw "array for failed" }) }, test_array_string_key_throws: function() { var a = [] var caught = false try { a["a"] = 1 } catch(e) { caught = true } if (!caught) throw "array should not be able to use string as key" }, test_array_object_key_throws: function() { var a = [] var b = {} var caught = false try { a[b] = 1 } catch(e) { caught = true } if (!caught) throw "array should not be able to use object as key" }, test_array_boolean_key_throws: function() { var a = [] var caught = false try { a[true] = 1 } catch(e) { caught = true } if (!caught) throw "array should not be able to use boolean as key" }, test_array_null_key_throws: function() { var a = [] var caught = false try { a[null] = 1 } catch(e) { caught = true } if (!caught) throw "array should not be able to use null as key" }, test_array_array_key_throws: function() { var a = [] var c = [] var caught = false try { a[c] = 1 } catch(e) { caught = true } if (!caught) throw "array should not be able to use array as key" }, test_obj_number_key_throws: function() { var a = {} var caught = false try { a[1] = 1 } catch(e) { caught = true } if (!caught) throw "object should not be able to use number as key" }, test_obj_array_key_throws: function() { var a = {} var c = [] var caught = false try { a[c] = 1 } catch(e) { caught = true } if (!caught) throw "object should not be able to use array as key" }, test_obj_boolean_key_throws: function() { var a = {} var caught = false try { a[true] = 1 } catch(e) { caught = true } if (!caught) throw "object should not be able to use boolean as key" }, test_obj_null_key_throws: function() { var a = {} var caught = false try { a[null] = 1 } catch(e) { caught = true } if (!caught) throw "object should not be able to use null as key" }, // ============================================================================ // RETRIEVAL WITH INVALID KEY RETURNS NULL (not throw) // ============================================================================ test_array_get_string_key_returns_null: function() { var a = [1, 2, 3] var result = a["x"] if (result != null) throw "array get with string key should return null" }, test_array_get_negative_index_returns_null: function() { var a = [1, 2, 3] var result = a[-1] if (result != null) throw "array get with negative index should return null" }, test_array_get_object_key_returns_null: function() { var a = [1, 2, 3] var k = {} var result = a[k] if (result != null) throw "array get with object key should return null" }, test_array_get_array_key_returns_null: function() { var a = [1, 2, 3] var result = a[[1, 2]] if (result != null) throw "array get with array key should return null" }, test_array_get_boolean_key_returns_null: function() { var a = [1, 2, 3] var result = a[true] if (result != null) throw "array get with boolean key should return null" }, test_array_get_null_key_returns_null: function() { var a = [1, 2, 3] var result = a[null] if (result != null) throw "array get with null key should return null" }, test_obj_get_number_key_returns_null: function() { var o = {a: 1} var result = o[5] if (result != null) throw "object get with number key should return null" }, test_obj_get_array_key_returns_null: function() { var o = {a: 1} var result = o[[1, 2]] if (result != null) throw "object get with array key should return null" }, test_obj_get_boolean_key_returns_null: function() { var o = {a: 1} var result = o[true] if (result != null) throw "object get with boolean key should return null" }, test_obj_get_null_key_returns_null: function() { var o = {a: 1} var result = o[null] if (result != null) throw "object get with null key should return null" }, // ============================================================================ // FUNCTION AS VALUE (not object) - functions should not have properties // ============================================================================ test_function_property_get_throws: function() { var fn = function(a, b) { return a + b } var arity = length(fn) if (arity != 2) throw "length of function should return its arity" }, test_function_property_set_throws: function() { var fn = function() {} var caught = false try { fn.foo = 123 } catch (e) { caught = true } if (!caught) throw "setting property on function should throw" }, test_function_bracket_access_throws: function() { var fn = function() {} var caught = false try { var x = fn["length"] } catch (e) { caught = true } if (!caught) throw "bracket access on function should throw" }, test_length_returns_function_arity: function() { var fn0 = function() { return 1 } var fn1 = function(a) { return a } var fn2 = function(a, b) { return a + b } var fn3 = function(a, b, c) { return a + b + c } if (length(fn0) != 0) throw "length(fn0) should be 0" if (length(fn1) != 1) throw "length(fn1) should be 1" if (length(fn2) != 2) throw "length(fn2) should be 2" if (length(fn3) != 3) throw "length(fn3) should be 3" }, test_text_returns_function_source: function() { var fn = function(x) { return x * 2 } var src = text(fn) if (search(src, "function") == null) throw "text(fn) should contain 'function'" if (search(src, "return") == null) throw "text(fn) should contain function body" }, test_call_invokes_function: function() { var fn = function(a, b) { return a + b } var result = call(fn, null, 3, 4) if (result != 7) throw "call(fn, null, 3, 4) should return 7" }, test_call_with_this_binding: function() { var obj = { value: 10 } var fn = function(x) { return this.value + x } var result = call(fn, obj, 5) if (result != 15) throw "call(fn, obj, 5) should return 15" }, test_call_no_args: function() { var fn = function() { return 42 } var result = call(fn, null) if (result != 42) throw "call(fn, null) should return 42" }, test_builtin_function_properties_still_work: function() { // Built-in functions like number, text, array should still have properties var min_result = min(5, 3) if (min_result != 3) throw "min should work" }, // ============================================================================ // FUNCTION PROXY - Method call sugar for bytecode functions // ============================================================================ test_function_proxy_basic: function() { var proxy = function(name, args) { return `called:${name}:${length(args)}` } var result = proxy.foo() if (result != "called:foo:0") throw "basic proxy call failed" }, test_function_proxy_with_one_arg: function() { var proxy = function(name, args) { return `${name}-${args[0]}` } var result = proxy.test("value") if (result != "test-value") throw "proxy with one arg failed" }, test_function_proxy_with_multiple_args: function() { var proxy = function(name, args) { var sum = 0 for (var i = 0; i < length(args); i++) { sum = sum + args[i] } return `${name}:${sum}` } var result = proxy.add(1, 2, 3, 4) if (result != "add:10") throw "proxy with multiple args failed" }, test_function_proxy_bracket_notation: function() { var proxy = function(name, args) { return `bracket:${name}` } var result = proxy["myMethod"]() if (result != "bracket:myMethod") throw "proxy bracket notation failed" }, test_function_proxy_dynamic_method_name: function() { var proxy = function(name, args) { return name } var methodName = "dynamic" var result = proxy[methodName]() if (result != "dynamic") throw "proxy dynamic method name failed" }, test_function_proxy_dispatch_to_record: function() { var my_record = { greet: function(name) { return `Hello, ${name}` }, add: function(a, b) { return a + b } } var proxy = function(name, args) { if (is_function(my_record[name])) { return apply(my_record[name], args) } throw `unknown method: ${name}` } if (proxy.greet("World") != "Hello, World") throw "proxy dispatch greet failed" if (proxy.add(3, 4) != 7) throw "proxy dispatch add failed" }, test_function_proxy_unknown_method_throws: function() { var proxy = function(name, args) { throw `no such method: ${name}` } var caught = false try { proxy.nonexistent() } catch (e) { caught = true if (search(e, "no such method") == null) throw "wrong error message" } if (!caught) throw "proxy should throw for unknown method" }, test_function_proxy_is_function: function() { var proxy = function(name, args) { return name } if (!is_function(proxy)) throw "proxy should be a function" }, test_function_proxy_length_is_2: function() { var proxy = function(name, args) { return name } if (length(proxy) != 2) throw "proxy function should have length 2" }, test_function_proxy_property_read_still_throws: function() { var fn = function() { return 1 } var caught = false try { var x = fn.someProp } catch (e) { caught = true } if (!caught) throw "reading property from function (not method call) should throw" }, test_function_proxy_nested_calls: function() { var outer = function(name, args) { if (name == "inner") { return args[0].double(5) } return "outer:" + name } var inner = function(name, args) { if (name == "double") { return args[0] * 2 } return "inner:" + name } var result = outer.inner(inner) if (result != 10) throw "nested proxy calls failed" }, test_function_proxy_returns_null: function() { var proxy = function(name, args) { return null } var result = proxy.anything() if (result != null) throw "proxy returning null failed" }, test_function_proxy_returns_object: function() { var proxy = function(name, args) { return {method: name, argCount: length(args)} } var result = proxy.test(1, 2, 3) if (result.method != "test") throw "proxy returning object method failed" if (result.argCount != 3) throw "proxy returning object argCount failed" }, test_function_proxy_returns_function: function() { var proxy = function(name, args) { return function() { return name } } var result = proxy.getFn() if (result() != "getFn") throw "proxy returning function failed" }, test_function_proxy_args_array_is_real_array: function() { var proxy = function(name, args) { if (!is_array(args)) throw "args should be array" push(args, 4) return length(args) } var result = proxy.test(1, 2, 3) if (result != 4) throw "proxy args should be modifiable array" }, test_function_proxy_no_this_binding: function() { var proxy = function(name, args) { return this } var result = proxy.test() if (result != null) throw "proxy should have null this" }, test_function_proxy_integer_bracket_key: function() { var proxy = function(name, args) { return `key:${name}` } var result = proxy[42]() if (result != "key:42") throw "proxy with integer bracket key failed" }, // ============================================================================ // REDUCE FUNCTION // ============================================================================ test_reduce_sum: function() { var arr = [1, 2, 3, 4, 5] var result = reduce(arr, (a, b) => a + b) if (result != 15) throw "reduce sum failed" }, test_reduce_product: function() { var arr = [1, 2, 3, 4, 5] var result = reduce(arr, (a, b) => a * b) if (result != 120) throw "reduce product failed" }, test_reduce_with_initial: function() { var arr = [1, 2, 3] var result = reduce(arr, (a, b) => a + b, 10) if (result != 16) throw "reduce with initial failed" }, test_reduce_with_initial_zero: function() { var arr = [1, 2, 3] var result = reduce(arr, (a, b) => a + b, 0) if (result != 6) throw "reduce with initial zero failed" }, test_reduce_empty_array_no_initial: function() { var arr = [] var result = reduce(arr, (a, b) => a + b) if (result != null) throw "reduce empty array without initial should return null" }, test_reduce_empty_array_with_initial: function() { var arr = [] var result = reduce(arr, (a, b) => a + b, 42) if (result != 42) throw "reduce empty array with initial should return initial" }, test_reduce_single_element_no_initial: function() { var arr = [42] var result = reduce(arr, (a, b) => a + b) if (result != 42) throw "reduce single element without initial failed" }, test_reduce_single_element_with_initial: function() { var arr = [5] var result = reduce(arr, (a, b) => a + b, 10) if (result != 15) throw "reduce single element with initial failed" }, test_reduce_reverse: function() { var arr = [1, 2, 3, 4] var result = reduce(arr, (a, b) => a - b, 0, true) if (result != -10) throw "reduce reverse failed: " + result }, test_reduce_string_concat: function() { var arr = ["a", "b", "c"] var result = reduce(arr, (a, b) => a + b) if (result != "abc") throw "reduce string concat failed" }, // ============================================================================ // SORT FUNCTION // ============================================================================ test_sort_numbers: function() { var arr = [3, 1, 4, 1, 5, 9, 2, 6] var sorted = sort(arr) if (sorted[0] != 1 || sorted[1] != 1 || sorted[2] != 2) throw "sort numbers failed" if (sorted[7] != 9) throw "sort numbers last element failed" }, test_sort_strings: function() { var arr = ["banana", "apple", "cherry"] var sorted = sort(arr) if (sorted[0] != "apple") throw "sort strings failed" if (sorted[2] != "cherry") throw "sort strings last failed" }, test_sort_preserves_original: function() { var arr = [3, 1, 2] var sorted = sort(arr) if (arr[0] != 3) throw "sort should not mutate original" }, test_sort_empty_array: function() { var arr = [] var sorted = sort(arr) if (length(sorted) != 0) throw "sort empty array failed" }, test_sort_single_element: function() { var arr = [42] var sorted = sort(arr) if (sorted[0] != 42) throw "sort single element failed" }, test_sort_by_field: function() { var arr = [ {name: "Charlie", age: 30}, {name: "Alice", age: 25}, {name: "Bob", age: 35} ] var sorted = sort(arr, "name") if (sorted[0].name != "Alice") throw "sort by field failed" if (sorted[2].name != "Charlie") throw "sort by field last failed" }, test_sort_by_index: function() { var arr = [[3, "c"], [1, "a"], [2, "b"]] var sorted = sort(arr, 0) if (sorted[0][1] != "a") throw "sort by index failed" }, test_sort_stable: function() { var arr = [ {name: "A", order: 1}, {name: "B", order: 1}, {name: "C", order: 1} ] var sorted = sort(arr, "order") if (sorted[0].name != "A" || sorted[1].name != "B" || sorted[2].name != "C") { throw "sort should be stable" } }, test_sort_negative_numbers: function() { var arr = [-5, 3, -1, 0, 2] var sorted = sort(arr) if (sorted[0] != -5 || sorted[4] != 3) throw "sort negative numbers failed" }, // ============================================================================ // FILTER FUNCTION // ============================================================================ test_filter_basic: function() { var arr = [1, 2, 3, 4, 5, 6] var evens = filter(arr, x => x % 2 == 0) if (length(evens) != 3) throw "filter basic length failed" if (evens[0] != 2 || evens[1] != 4 || evens[2] != 6) throw "filter basic values failed" }, test_filter_all_pass: function() { var arr = [2, 4, 6] var result = filter(arr, x => x % 2 == 0) if (length(result) != 3) throw "filter all pass failed" }, test_filter_none_pass: function() { var arr = [1, 3, 5] var result = filter(arr, x => x % 2 == 0) if (length(result) != 0) throw "filter none pass failed" }, test_filter_empty_array: function() { var arr = [] var result = filter(arr, x => true) if (length(result) != 0) throw "filter empty array failed" }, test_filter_with_index: function() { var arr = ["a", "b", "c", "d"] var result = filter(arr, (x, i) => i % 2 == 0) if (length(result) != 2) throw "filter with index length failed" if (result[0] != "a" || result[1] != "c") throw "filter with index values failed" }, test_filter_preserves_original: function() { var arr = [1, 2, 3] var result = filter(arr, x => x > 1) if (length(arr) != 3) throw "filter should not mutate original" }, test_filter_objects: function() { var arr = [{active: true}, {active: false}, {active: true}] var result = filter(arr, x => x.active) if (length(result) != 2) throw "filter objects failed" }, // ============================================================================ // FIND FUNCTION // ============================================================================ test_find_basic: function() { var arr = [1, 2, 3, 4, 5] var idx = find(arr, x => x > 3) if (idx != 3) throw "find basic failed" }, test_find_first_element: function() { var arr = [10, 2, 3] var idx = find(arr, x => x > 5) if (idx != 0) throw "find first element failed" }, test_find_last_element: function() { var arr = [1, 2, 10] var idx = find(arr, x => x > 5) if (idx != 2) throw "find last element failed" }, test_find_not_found: function() { var arr = [1, 2, 3] var idx = find(arr, x => x > 10) if (idx != null) throw "find not found should return null" }, test_find_empty_array: function() { var arr = [] var idx = find(arr, x => true) if (idx != null) throw "find in empty array should return null" }, test_find_by_value: function() { var arr = [10, 20, 30, 20] var idx = find(arr, 20) if (idx != 1) throw "find by value failed" }, test_find_reverse: function() { var arr = [10, 20, 30, 20] var idx = find(arr, 20, true) if (idx != 3) throw "find reverse failed" }, test_find_with_from: function() { var arr = [10, 20, 30, 20] var idx = find(arr, 20, false, 2) if (idx != 3) throw "find with from failed" }, test_find_with_index_callback: function() { var arr = ["a", "b", "c"] var idx = find(arr, (x, i) => i == 1) if (idx != 1) throw "find with index callback failed" }, // ============================================================================ // ABS FUNCTION // ============================================================================ test_abs_positive: function() { if (abs(5) != 5) throw "abs positive failed" }, test_abs_negative: function() { if (abs(-5) != 5) throw "abs negative failed" }, test_abs_zero: function() { if (abs(0) != 0) throw "abs zero failed" }, test_abs_float: function() { if (abs(-3.14) != 3.14) throw "abs float failed" }, test_abs_non_number: function() { if (abs("5") != null) throw "abs non-number should return null" if (abs(null) != null) throw "abs null should return null" }, // ============================================================================ // FLOOR FUNCTION // ============================================================================ test_floor_positive: function() { if (floor(3.7) != 3) throw "floor positive failed" }, test_floor_negative: function() { if (floor(-3.7) != -4) throw "floor negative failed" }, test_floor_integer: function() { if (floor(5) != 5) throw "floor integer failed" }, test_floor_zero: function() { if (floor(0) != 0) throw "floor zero failed" }, test_floor_with_place: function() { if (floor(12.3775, -2) != 12.37) throw "floor with place failed" }, test_floor_negative_with_place: function() { if (floor(-12.3775, -2) != -12.38) throw "floor negative with place failed" }, // ============================================================================ // CEILING FUNCTION // ============================================================================ test_ceiling_positive: function() { if (ceiling(3.2) != 4) throw "ceiling positive failed" }, test_ceiling_negative: function() { if (ceiling(-3.7) != -3) throw "ceiling negative failed" }, test_ceiling_integer: function() { if (ceiling(5) != 5) throw "ceiling integer failed" }, test_ceiling_zero: function() { if (ceiling(0) != 0) throw "ceiling zero failed" }, test_ceiling_with_place: function() { if (ceiling(12.3775, -2) != 12.38) throw "ceiling with place failed" }, test_ceiling_negative_with_place: function() { if (ceiling(-12.3775, -2) != -12.37) throw "ceiling negative with place failed" }, // ============================================================================ // ROUND FUNCTION // ============================================================================ test_round_down: function() { if (round(3.4) != 3) throw "round down failed" }, test_round_up: function() { if (round(3.6) != 4) throw "round up failed" }, test_round_half: function() { if (round(3.5) != 4) throw "round half failed" }, test_round_negative: function() { if (round(-3.5) != -3 && round(-3.5) != -4) throw "round negative failed" }, test_round_integer: function() { if (round(5) != 5) throw "round integer failed" }, test_round_with_places: function() { if (round(12.3775, -2) != 12.38) throw "round with places failed" }, test_round_to_tens: function() { if (round(12.3775, 1) != 10) throw "round to tens failed" }, // ============================================================================ // TRUNC FUNCTION // ============================================================================ test_trunc_positive: function() { if (trunc(3.7) != 3) throw "trunc positive failed" }, test_trunc_negative: function() { if (trunc(-3.7) != -3) throw "trunc negative failed" }, test_trunc_integer: function() { if (trunc(5) != 5) throw "trunc integer failed" }, test_trunc_zero: function() { if (trunc(0) != 0) throw "trunc zero failed" }, test_trunc_with_places: function() { if (trunc(12.3775, -2) != 12.37) throw "trunc with places failed" }, test_trunc_negative_with_places: function() { if (trunc(-12.3775, -2) != -12.37) throw "trunc negative with places failed" }, // ============================================================================ // SIGN FUNCTION // ============================================================================ test_sign_positive: function() { if (sign(5) != 1) throw "sign positive failed" }, test_sign_negative: function() { if (sign(-5) != -1) throw "sign negative failed" }, test_sign_zero: function() { if (sign(0) != 0) throw "sign zero failed" }, test_sign_float: function() { if (sign(0.001) != 1) throw "sign positive float failed" if (sign(-0.001) != -1) throw "sign negative float failed" }, test_sign_non_number: function() { if (sign("5") != null) throw "sign non-number should return null" }, // ============================================================================ // WHOLE AND FRACTION FUNCTIONS // ============================================================================ test_whole_positive: function() { if (whole(3.7) != 3) throw "whole positive failed" }, test_whole_negative: function() { if (whole(-3.7) != -3) throw "whole negative failed" }, test_whole_integer: function() { if (whole(5) != 5) throw "whole integer failed" }, test_whole_non_number: function() { if (whole("5") != null) throw "whole non-number should return null" }, test_fraction_positive: function() { var f = fraction(3.75) if (f < 0.74 || f > 0.76) throw "fraction positive failed: " + f }, test_fraction_negative: function() { var f = fraction(-3.75) if (f > -0.74 || f < -0.76) throw "fraction negative failed: " + f }, test_fraction_integer: function() { if (fraction(5) != 0) throw "fraction integer failed" }, test_fraction_non_number: function() { if (fraction("5") != null) throw "fraction non-number should return null" }, // ============================================================================ // NEG FUNCTION // ============================================================================ test_neg_positive: function() { if (neg(5) != -5) throw "neg positive failed" }, test_neg_negative: function() { if (neg(-5) != 5) throw "neg negative failed" }, test_neg_zero: function() { if (neg(0) != 0) throw "neg zero failed" }, test_neg_float: function() { if (neg(3.14) != -3.14) throw "neg float failed" }, test_neg_non_number: function() { if (neg("5") != null) throw "neg non-number should return null" }, // ============================================================================ // MODULO FUNCTION // ============================================================================ test_modulo_positive: function() { if (modulo(10, 3) != 1) throw "modulo positive failed" }, test_modulo_negative_dividend: function() { var result = modulo(-10, 3) if (result != 2) throw "modulo negative dividend failed: " + result }, test_modulo_negative_divisor: function() { var result = modulo(10, -3) if (result != -2) throw "modulo negative divisor failed: " + result }, test_modulo_both_negative: function() { var result = modulo(-10, -3) if (result != -1) throw "modulo both negative failed: " + result }, test_modulo_zero_dividend: function() { if (modulo(0, 5) != 0) throw "modulo zero dividend failed" }, test_modulo_zero_divisor: function() { if (modulo(10, 0) != null) throw "modulo zero divisor should return null" }, test_modulo_floats: function() { var result = modulo(5.5, 2) if (result < 1.4 || result > 1.6) throw "modulo floats failed: " + result }, // ============================================================================ // MIN AND MAX FUNCTIONS // ============================================================================ test_min_basic: function() { if (min(3, 5) != 3) throw "min basic failed" }, test_min_equal: function() { if (min(5, 5) != 5) throw "min equal failed" }, test_min_negative: function() { if (min(-3, -5) != -5) throw "min negative failed" }, test_min_mixed: function() { if (min(-3, 5) != -3) throw "min mixed failed" }, test_min_float: function() { if (min(3.14, 2.71) != 2.71) throw "min float failed" }, test_min_non_number: function() { if (min(3, "5") != null) throw "min non-number should return null" if (min("3", 5) != null) throw "min first non-number should return null" }, test_max_basic: function() { if (max(3, 5) != 5) throw "max basic failed" }, test_max_equal: function() { if (max(5, 5) != 5) throw "max equal failed" }, test_max_negative: function() { if (max(-3, -5) != -3) throw "max negative failed" }, test_max_mixed: function() { if (max(-3, 5) != 5) throw "max mixed failed" }, test_max_float: function() { if (max(3.14, 2.71) != 3.14) throw "max float failed" }, test_max_non_number: function() { if (max(3, "5") != null) throw "max non-number should return null" }, test_min_max_constrain: function() { var val = 8 var constrained = min(max(val, 0), 10) if (constrained != 8) throw "min max constrain in range failed" constrained = min(max(-5, 0), 10) if (constrained != 0) throw "min max constrain below failed" constrained = min(max(15, 0), 10) if (constrained != 10) throw "min max constrain above failed" }, // ============================================================================ // CODEPOINT FUNCTION // ============================================================================ test_codepoint_letter: function() { if (codepoint("A") != 65) throw "codepoint A failed" if (codepoint("a") != 97) throw "codepoint a failed" }, test_codepoint_digit: function() { if (codepoint("0") != 48) throw "codepoint 0 failed" }, test_codepoint_unicode: function() { if (codepoint("\u00E9") != 233) throw "codepoint unicode failed" }, test_codepoint_first_char: function() { if (codepoint("ABC") != 65) throw "codepoint should return first char" }, test_codepoint_empty: function() { if (codepoint("") != null) throw "codepoint empty should return null" }, test_codepoint_non_text: function() { if (codepoint(65) != null) throw "codepoint non-text should return null" }, // ============================================================================ // CHARACTER FUNCTION // ============================================================================ test_character_letter: function() { if (character(65) != "A") throw "character 65 failed" if (character(97) != "a") throw "character 97 failed" }, test_character_digit: function() { if (character(48) != "0") throw "character 48 failed" }, test_character_unicode: function() { if (character(233) != "\u00E9") throw "character unicode failed" }, test_character_from_text: function() { if (character("hello") != "h") throw "character from text failed" }, test_character_invalid: function() { if (character(-1) != "") throw "character negative should return empty" }, // ============================================================================ // SEARCH FUNCTION // ============================================================================ test_search_found: function() { if (search("hello world", "world") != 6) throw "search found failed" }, test_search_not_found: function() { if (search("hello world", "xyz") != null) throw "search not found should return null" }, test_search_beginning: function() { if (search("hello world", "hello") != 0) throw "search beginning failed" }, test_search_single_char: function() { if (search("hello", "l") != 2) throw "search single char failed" }, test_search_with_from: function() { if (search("hello hello", "hello", 1) != 6) throw "search with from failed" }, test_search_empty_pattern: function() { if (search("hello", "") != 0) throw "search empty pattern failed" }, test_search_negative_from: function() { var result = search("hello world", "world", -5) if (result != 6) throw "search negative from failed: " + result }, // ============================================================================ // REPLACE FUNCTION // ============================================================================ test_replace_basic: function() { var result = replace("hello world", "world", "universe") if (result != "hello universe") throw "replace basic failed" }, test_replace_not_found: function() { var result = replace("hello world", "xyz", "abc") if (result != "hello world") throw "replace not found should return original" }, test_replace_multiple: function() { var result = replace("banana", "a", "o") if (result != "bonono") throw "replace multiple failed: " + result }, test_replace_with_limit: function() { var result = replace("banana", "a", "o", 1) if (result != "bonana") throw "replace with limit failed: " + result }, test_replace_empty_target: function() { var result = replace("abc", "", "-") if (result != "-a-b-c-") throw "replace empty target failed: " + result }, test_replace_to_empty: function() { var result = replace("hello", "l", "") if (result != "heo") throw "replace to empty failed" }, test_replace_with_function: function() { var result = replace("hello", "l", (match, pos) => `[${pos}]`) if (result != "he[2][3]o") throw "replace with function failed: " + result }, test_replace_with_function_limit: function() { var result = replace("banana", "a", (match, pos) => `[${pos}]`, 2) if (result != "b[1]n[3]na") throw "replace with function limit failed: " + result }, test_replace_with_regex: function() { var result = replace("banana", /a/, "o") if (result != "bonono") throw "replace with regex failed" }, test_replace_with_regex_limit: function() { var result = replace("banana", /a/, "o", 2) if (result != "bonona") throw "replace with regex limit failed: " + result }, test_replace_with_regex_function: function() { var result = replace("hello", /l/, (match, pos) => `[${pos}]`) if (result != "he[2][3]o") throw "replace with regex function failed: " + result }, // ============================================================================ // TEXT FUNCTION (Conversion and Slicing) // ============================================================================ test_text_number_basic: function() { if (text(123) != "123") throw "text number basic failed" }, test_text_number_negative: function() { if (text(-456) != "-456") throw "text number negative failed" }, test_text_number_float: function() { var result = text(3.14) if (search(result, "3.14") != 0) throw "text number float failed" }, test_text_array_join_empty_sep: function() { var result = text(["a", "b", "c"], "") if (result != "abc") throw "text array join empty sep failed" }, test_text_slice_basic: function() { if (text("hello", 1, 4) != "ell") throw "text slice basic failed" }, test_text_slice_from_only: function() { if (text("hello", 2) != "llo") throw "text slice from only failed" }, test_text_slice_negative_from: function() { if (text("hello", -2) != "lo") throw "text slice negative from failed" }, test_text_slice_negative_to: function() { if (text("hello", 0, -2) != "hel") throw "text slice negative to failed" }, test_text_boolean: function() { if (text(true) != "true") throw "text true failed" if (text(false) != "false") throw "text false failed" }, test_text_null: function() { if (text(null) != "null") throw "text null failed" }, // ============================================================================ // NUMBER FUNCTION (Conversion) // ============================================================================ test_number_from_string: function() { if (number("123") != 123) throw "number from string failed" }, test_number_from_negative_string: function() { if (number("-456") != -456) throw "number from negative string failed" }, test_number_from_float_string: function() { if (number("3.14") != 3.14) throw "number from float string failed" }, test_number_invalid_string: function() { if (number("abc") != null) throw "number invalid string should return null" }, test_number_from_boolean: function() { if (number(true) != 1) throw "number from true failed" if (number(false) != 0) throw "number from false failed" }, test_number_from_number: function() { if (number(42) != 42) throw "number from number failed" }, test_number_with_radix: function() { if (number("FF", 16) != 255) throw "number hex failed" if (number("1010", 2) != 10) throw "number binary failed" }, test_number_leading_zeros: function() { if (number("007") != 7) throw "number leading zeros failed" }, // ============================================================================ // ARRAY FUNCTION (Creator and Slicing) // ============================================================================ test_array_create_with_length: function() { var arr = array(5) if (length(arr) != 5) throw "array create length failed" if (arr[0] != null) throw "array create should init to null" }, test_array_create_with_initial: function() { var arr = array(3, 42) if (arr[0] != 42 || arr[1] != 42 || arr[2] != 42) throw "array create with initial failed" }, test_array_create_with_function: function() { var arr = array(3, i => i * 2) if (arr[0] != 0 || arr[1] != 2 || arr[2] != 4) throw "array create with function failed" }, test_array_copy: function() { var orig = [1, 2, 3] var copy = array(orig) copy[0] = 99 if (orig[0] != 1) throw "array copy should not affect original" }, test_array_slice_basic: function() { var arr = [1, 2, 3, 4, 5] var sliced = array(arr, 1, 3) if (length(sliced) != 2) throw "array slice length failed" if (sliced[0] != 2 || sliced[1] != 3) throw "array slice values failed" }, test_array_slice_negative: function() { var arr = [1, 2, 3, 4, 5] var sliced = array(arr, -3) if (length(sliced) != 3) throw "array slice negative failed" if (sliced[0] != 3) throw "array slice negative value failed" }, test_array_from_object_keys: function() { var obj = {a: 1, b: 2, c: 3} var keys = array(obj) if (length(keys) != 3) throw "array from object keys length failed" }, test_array_from_text: function() { var arr = array("abc") if (length(arr) != 3) throw "array from text length failed" if (arr[0] != "a" || arr[1] != "b" || arr[2] != "c") throw "array from text values failed" }, test_array_split_text: function() { var arr = array("a,b,c", ",") if (length(arr) != 3) throw "array split text length failed" if (arr[1] != "b") throw "array split text value failed" }, // ============================================================================ // TRIM FUNCTION // ============================================================================ test_trim_spaces: function() { if (trim(" hello ") != "hello") throw "trim spaces failed" }, test_trim_tabs: function() { if (trim("\thello\t") != "hello") throw "trim tabs failed" }, test_trim_mixed: function() { if (trim(" \t hello \n ") != "hello") throw "trim mixed failed" }, test_trim_no_whitespace: function() { if (trim("hello") != "hello") throw "trim no whitespace failed" }, test_trim_empty: function() { if (trim("") != "") throw "trim empty failed" }, test_trim_all_whitespace: function() { if (trim(" ") != "") throw "trim all whitespace failed" }, // ============================================================================ // LOWER AND UPPER FUNCTIONS // ============================================================================ test_lower_basic: function() { if (lower("HELLO") != "hello") throw "lower basic failed" }, test_lower_mixed: function() { if (lower("HeLLo WoRLD") != "hello world") throw "lower mixed failed" }, test_lower_already_lower: function() { if (lower("hello") != "hello") throw "lower already lower failed" }, test_lower_with_numbers: function() { if (lower("ABC123") != "abc123") throw "lower with numbers failed" }, test_upper_basic: function() { if (upper("hello") != "HELLO") throw "upper basic failed" }, test_upper_mixed: function() { if (upper("HeLLo WoRLD") != "HELLO WORLD") throw "upper mixed failed" }, test_upper_already_upper: function() { if (upper("HELLO") != "HELLO") throw "upper already upper failed" }, test_upper_with_numbers: function() { if (upper("abc123") != "ABC123") throw "upper with numbers failed" }, // ============================================================================ // APPLY FUNCTION // ============================================================================ test_apply_basic: function() { var fn = function(a, b) { return a + b } var result = apply(fn, [3, 4]) if (result != 7) throw "apply basic failed" }, test_apply_no_args: function() { var fn = function() { return 42 } var result = apply(fn, []) if (result != 42) throw "apply no args failed" }, test_apply_single_arg: function() { var fn = function(x) { return x * 2 } var result = apply(fn, [5]) if (result != 10) throw "apply single arg failed" }, test_apply_many_args: function() { var fn = function(a, b, c, d) { return a + b + c + d } var result = apply(fn, [1, 2, 3, 4]) if (result != 10) throw "apply many args failed" }, test_apply_non_function: function() { var result = apply(42, [1, 2]) if (result != 42) throw "apply non-function should return first arg" }, // ============================================================================ // CALL FUNCTION (Additional Tests) // ============================================================================ test_call_many_args: function() { var fn = function(a, b, c, d) { return a * b + c * d } var result = call(fn, null, 2, 3, 4, 5) if (result != 26) throw "call many args failed" }, test_call_method_style: function() { var obj = { value: 10, multiply: function(x) { return this.value * x } } var result = call(obj.multiply, obj, 5) if (result != 50) throw "call method style failed" }, test_call_change_this: function() { var obj1 = { value: 10 } var obj2 = { value: 20 } var fn = function() { return this.value } if (call(fn, obj1) != 10) throw "call this obj1 failed" if (call(fn, obj2) != 20) throw "call this obj2 failed" }, // ============================================================================ // ARRFOR FUNCTION (Array For-Each) // ============================================================================ test_arrfor_basic: function() { var arr = [1, 2, 3] var sum = 0 arrfor(arr, x => { sum = sum + x }) if (sum != 6) throw "arrfor basic failed" }, test_arrfor_with_index: function() { var arr = ["a", "b", "c"] var indices = [] arrfor(arr, (x, i) => { push(indices, i) }) if (indices[0] != 0 || indices[2] != 2) throw "arrfor with index failed" }, test_arrfor_empty: function() { var called = false arrfor([], x => { called = true }) if (called) throw "arrfor empty should not call function" }, test_arrfor_mutation: function() { var arr = [1, 2, 3] var results = [] arrfor(arr, x => { push(results, x * 2) }) if (results[0] != 2 || results[1] != 4 || results[2] != 6) throw "arrfor mutation failed" }, // ============================================================================ // STONE FUNCTION (Additional Tests) // ============================================================================ test_stone_returns_value: function() { var obj = {x: 1} var result = stone(obj) if (result != obj) throw "stone should return the value" }, test_stone_idempotent: function() { var obj = {x: 1} stone(obj) stone(obj) if (!is_stone(obj)) throw "stone should be idempotent" }, // ============================================================================ // PROTO FUNCTION (Additional Tests) // ============================================================================ test_proto_chain: function() { var grandparent = {a: 1} var parent = meme(grandparent) var child = meme(parent) if (proto(child) != parent) throw "proto chain child->parent failed" if (proto(parent) != grandparent) throw "proto chain parent->grandparent failed" }, test_proto_array: function() { var arr = [1, 2, 3] var p = proto(arr) if (p == null) throw "proto of array should not be null" }, // ============================================================================ // MEME FUNCTION (Additional Tests) // ============================================================================ test_meme_method_inheritance: function() { var parent = { greet: function() { return "hello" } } var child = meme(parent) if (child.greet() != "hello") throw "meme method inheritance failed" }, test_meme_this_in_inherited_method: function() { var parent = { getValue: function() { return this.value } } var child = meme(parent) child.value = 42 if (child.getValue() != 42) throw "meme this in inherited method failed" }, test_meme_deep_chain: function() { var a = {x: 1} var b = meme(a) var c = meme(b) var d = meme(c) if (d.x != 1) throw "meme deep chain failed" }, // ============================================================================ // DELETE OPERATOR // ============================================================================ test_delete_property: function() { var obj = {a: 1, b: 2} delete obj.a if ("a" in obj) throw "delete property failed" if (obj.b != 2) throw "delete should not affect other properties" }, test_delete_array_element: function() { var arr = [1, 2, 3] var caught = false try { delete arr[1] } catch (e) { caught = true } if (!caught) throw "delete on array element should throw" }, test_delete_nonexistent: function() { var obj = {a: 1} delete obj.b if (obj.a != 1) throw "delete nonexistent should not affect object" }, // ============================================================================ // TYPEOF-LIKE BEHAVIOR // ============================================================================ test_is_integer: function() { if (!is_number(5) || 5 % 1 != 0) throw "is_integer positive failed" if (!is_number(-5) || -5 % 1 != 0) throw "is_integer negative failed" if (is_number(5.5) && 5.5 % 1 == 0) throw "is_integer float should not be integer" }, // ============================================================================ // ARRAY MAP-LIKE WITH ARRAY FUNCTION // ============================================================================ test_array_map_basic: function() { var arr = [1, 2, 3] var doubled = array(arr, x => x * 2) if (doubled[0] != 2 || doubled[1] != 4 || doubled[2] != 6) throw "array map basic failed" }, test_array_map_with_index: function() { var arr = ["a", "b", "c"] var result = array(arr, (x, i) => `${x}${i}`) if (result[0] != "a0" || result[1] != "b1") throw "array map with index failed" }, test_array_map_reverse: function() { var arr = [1, 2, 3] var result = array(arr, x => x * 2, true) if (result[0] != 6 || result[2] != 2) throw "array map reverse failed" }, test_array_map_with_exit: function() { var arr = [1, 2, 3, 4, 5] var result = array(arr, x => { if (x > 3) return null return x * 2 }, false, null) if (length(result) != 5) throw "array map with exit length unexpected" }, // ============================================================================ // ERROR OBJECTS // ============================================================================ test_error_creation: function() { var e = Error("test message") if (e.message != "test message") throw "Error creation failed" }, test_throw_error_object: function() { var caught = null try { throw Error("my error") } catch (e) { caught = e } if (!caught || caught.message != "my error") throw "throw Error object failed" }, // ============================================================================ // STRING METHOD EDGE CASES // ============================================================================ test_string_startsWith: function() { if (!starts_with("hello", "hel")) throw "startsWith match failed" if (starts_with("hello", "ell")) throw "startsWith no match failed" if (!starts_with("hello", "")) throw "startsWith empty should match" }, test_string_endsWith: function() { if (!ends_with("hello", "llo")) throw "endsWith match failed" if (ends_with("hello", "ell")) throw "endsWith no match failed" if (!ends_with("hello", "")) throw "endsWith empty should match" }, test_string_includes: function() { if (search("hello world", "world") == null) throw "includes match failed" if (search("hello", "xyz") != null) throw "includes no match failed" if (search("hello", "") == null) throw "includes empty should match" }, // ============================================================================ // ARRAY METHOD EDGE CASES // ============================================================================ test_array_includes: function() { var arr = [1, 2, 3] if (find(arr, 2) == null) throw "array includes match failed" if (find(arr, 5) != null) throw "array includes no match failed" }, test_array_every: function() { var arr = [2, 4, 6] if (!every(arr, x => x % 2 == 0)) throw "array every all pass failed" arr = [2, 3, 6] if (every(arr, x => x % 2 == 0)) throw "array every not all pass failed" }, test_array_some: function() { var arr = [1, 2, 3] if (!some(arr, x => x > 2)) throw "array some match failed" if (some(arr, x => x > 5)) throw "array some no match failed" }, // ============================================================================ // LOGICAL FUNCTION // ============================================================================ test_logical_zero: function() { if (logical(0) != false) throw "logical(0) should be false" }, test_logical_one: function() { if (logical(1) != true) throw "logical(1) should be true" }, test_logical_string_true: function() { if (logical("true") != true) throw "logical('true') should be true" }, test_logical_string_false: function() { if (logical("false") != false) throw "logical('false') should be false" }, test_logical_boolean_true: function() { if (logical(true) != true) throw "logical(true) should be true" }, test_logical_boolean_false: function() { if (logical(false) != false) throw "logical(false) should be false" }, test_logical_null: function() { if (logical(null) != false) throw "logical(null) should be false" }, test_logical_invalid: function() { if (logical("invalid") != null) throw "logical('invalid') should be null" if (logical(42) != null) throw "logical(42) should be null" if (logical({}) != null) throw "logical({}) should be null" }, // ============================================================================ // ADDITIONAL EDGE CASES // ============================================================================ test_nested_array_access: function() { var arr = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] if (arr[0][1][0] != 3) throw "nested array access failed" if (arr[1][1][1] != 8) throw "nested array access deep failed" }, test_nested_object_access: function() { var obj = {a: {b: {c: {d: 42}}}} if (obj.a.b.c.d != 42) throw "nested object access failed" }, test_mixed_nested_access: function() { var data = {users: [{name: "Alice"}, {name: "Bob"}]} if (data.users[1].name != "Bob") throw "mixed nested access failed" }, test_object_with_null_value: function() { var obj = {a: null, b: 2} if (obj.a != null) throw "object null value failed" if (!("a" in obj)) throw "object with null should have key" }, test_array_with_null_values: function() { var arr = [1, null, 3] if (arr[1] != null) throw "array null value failed" if (length(arr) != 3) throw "array with null length failed" }, test_function_returning_function: function() { var outer = function(x) { return function(y) { return function(z) { return x + y + z } } } if (outer(1)(2)(3) != 6) throw "function returning function failed" }, test_immediately_invoked_function: function() { var result = (function(x) { return x * 2 })(21) if (result != 42) throw "immediately invoked function failed" }, test_text_split_text: function() { var text = "hello world" var result = array(text, " ") if (length(result) != 2) throw "text split failed" if (result[0] != "hello") throw "text split failed" if (result[1] != "world") throw "text split failed" }, test_text_split_regex: function() { var text = "hello world" var result = array(text, /\s+/) if (length(result) != 2) throw "text split failed" if (result[0] != "hello") throw "text split failed" if (result[1] != "world") throw "text split failed" }, test_text_search_text: function() { var text = "hello world" var result = search(text, "world") if (result != 6) throw "text search failed" }, test_text_search_regex: function() { var text = "hello world" var result = search(text, /world/) if (result != 6) throw "text search failed" }, test_extract_basic_text: function() { var text = "hello world" var result = extract(text, "world") if (result[0] != "world") throw "extract basic text failed" }, test_extract_text_not_found: function() { var text = "hello world" var result = extract(text, "xyz") if (result != null) throw "extract not found should return null" }, test_extract_regex_basic: function() { var text = "hello world" var result = extract(text, /world/) if (result[0] != "world") throw "extract regex basic failed" }, test_extract_regex_with_capture_group: function() { var text = "hello world" var result = extract(text, /(\w+) (\w+)/) if (result[0] != "hello world") throw "extract regex full match failed" if (result[1] != "hello") throw "extract regex capture group 1 failed" if (result[2] != "world") throw "extract regex capture group 2 failed" }, test_extract_regex_digits: function() { var text = "abc123def456" var result = extract(text, /(\d+)/) if (result[0] != "123") throw "extract regex digits failed" if (result[1] != "123") throw "extract regex digits capture failed" }, test_extract_with_from: function() { var text = "hello hello world" var result = extract(text, "hello", 1) if (result[0] != "hello") throw "extract with from failed" }, test_extract_with_from_to: function() { var text = "hello world hello" var result = extract(text, "hello", 0, 10) if (result[0] != "hello") throw "extract with from to failed" }, test_extract_regex_case_insensitive: function() { var text = "Hello World" var result = extract(text, /hello/i) if (result[0] != "Hello") throw "extract regex case insensitive failed" }, // ============================================================================ // GC PATHOLOGICAL CASES // ============================================================================ test_gc_cycle_object_self: function() { var obj = {name: "root"} obj.self = obj if (obj.self != obj) throw "self cycle failed" }, test_gc_cycle_array_self: function() { var arr = [] for (var i = 0; i < 10; i++) { push(arr, arr) } if (arr[0] != arr) throw "array self cycle failed" }, test_gc_cycle_object_array_pair: function() { var obj = {kind: "node"} var arr = [obj] obj.arr = arr if (obj.arr[0] != obj) throw "object/array cycle failed" }, test_gc_shared_references: function() { var shared = {value: 42} var a = {ref: shared} var b = {ref: shared} if (a.ref != shared || b.ref != shared) throw "shared reference failed" }, test_gc_object_key_cycle: function() { var k = {} var v = {label: "value"} var o = {} o[k] = v v.back = o if (o[k].back != o) throw "object key cycle failed" }, test_gc_object_text_key_mix: function() { var obj = {} var key = "alpha" var inner = {token: "x"} obj[key] = inner obj["beta"] = [inner, obj] if (obj.alpha.token != "x") throw "text key value failed" if (obj.beta[1] != obj) throw "text key cycle failed" }, test_gc_array_object_key_mix: function() { var obj = {} var arr = [obj] obj[arr] = "anchor" obj.self = obj if (obj[arr] != "anchor") throw "array object key failed" if (arr[0] != obj) throw "array object mix failed" }, }