3348 lines
107 KiB
Plaintext
3348 lines
107 KiB
Plaintext
// ========================================
|
|
// BOB LANGUAGE TEST SUITE
|
|
// ========================================
|
|
// Tests all implemented language features
|
|
// Usage: ./build/bob test_bob_language.bob
|
|
|
|
print("Bob Language Test Suite");
|
|
print("Running feature tests...");
|
|
|
|
// ========================================
|
|
// TEST 1: BASIC DATA TYPES
|
|
// ========================================
|
|
print("\n--- Test 1: Basic Data Types ---");
|
|
|
|
// String literals
|
|
var stringVar = "Hello, Bob!";
|
|
assert(toString(stringVar) == "Hello, Bob!", "String variable assignment");
|
|
print(" String: " + toString(stringVar));
|
|
|
|
// Numbers (integers and floats)
|
|
var intVar = 42;
|
|
var floatVar = 3.14159;
|
|
assert(toString(intVar) == "42", "Integer variable assignment");
|
|
assert(toString(floatVar) == "3.14159", "Float variable assignment");
|
|
print(" Integer: " + toString(intVar));
|
|
print(" Float: " + toString(floatVar));
|
|
|
|
// Booleans
|
|
var boolTrue = true;
|
|
var boolFalse = false;
|
|
assert(boolTrue == true, "Boolean true assignment");
|
|
assert(boolFalse == false, "Boolean false assignment");
|
|
print(" Boolean true: " + toString(boolTrue));
|
|
print(" Boolean false: " + toString(boolFalse));
|
|
|
|
print("Basic data types: PASS");
|
|
|
|
// ========================================
|
|
// TEST 2: ARITHMETIC OPERATIONS
|
|
// ========================================
|
|
print("\n--- Test 2: Arithmetic Operations ---");
|
|
|
|
// Basic arithmetic
|
|
var addResult = 2 + 3;
|
|
assert(toString(addResult) == "5", "Addition");
|
|
print(" Addition: 2 + 3 = " + toString(addResult));
|
|
|
|
var subResult = 10 - 4;
|
|
assert(toString(subResult) == "6", "Subtraction");
|
|
print(" Subtraction: 10 - 4 = " + toString(subResult));
|
|
|
|
var mulResult = 6 * 7;
|
|
assert(toString(mulResult) == "42", "Multiplication");
|
|
print(" Multiplication: 6 * 7 = " + toString(mulResult));
|
|
|
|
var divResult = 20 / 4;
|
|
assert(toString(divResult) == "5", "Division");
|
|
print(" Division: 20 / 4 = " + toString(divResult));
|
|
|
|
// Negative numbers
|
|
var negResult = -42;
|
|
assert(toString(negResult) == "-42", "Negative numbers");
|
|
print(" Negative: " + toString(negResult));
|
|
|
|
var negCalc = 5 - 10;
|
|
assert(toString(negCalc) == "-5", "Negative result");
|
|
print(" Negative calculation: 5 - 10 = " + toString(negCalc));
|
|
|
|
// Order of operations
|
|
var orderResult1 = 2 + 3 * 4;
|
|
assert(toString(orderResult1) == "14", "Order of operations (multiplication first)");
|
|
print(" Order of operations: 2 + 3 * 4 = " + toString(orderResult1));
|
|
|
|
var orderResult2 = (2 + 3) * 4;
|
|
assert(toString(orderResult2) == "20", "Parentheses override order of operations");
|
|
print(" Parentheses: (2 + 3) * 4 = " + toString(orderResult2));
|
|
|
|
print("Arithmetic operations: PASS");
|
|
|
|
// ========================================
|
|
// TEST 3: STRING OPERATIONS
|
|
// ========================================
|
|
print("\n--- Test 3: String Operations ---");
|
|
|
|
// String concatenation
|
|
var concatResult = "Hello" + " " + "World";
|
|
assert(toString(concatResult) == "Hello World", "String concatenation");
|
|
print(" String concatenation: " + toString(concatResult));
|
|
|
|
var firstName = "Bob";
|
|
var lastName = "Lucero";
|
|
var nameResult = firstName + " " + lastName;
|
|
assert(toString(nameResult) == "Bob Lucero", "Variable string concatenation");
|
|
print(" Variable concatenation: " + toString(nameResult));
|
|
|
|
print("String operations: PASS");
|
|
|
|
// ========================================
|
|
// TEST 3.5: STRING + NUMBER CONCATENATION
|
|
// ========================================
|
|
print("\n--- Test 3.5: String + Number Concatenation ---");
|
|
|
|
// Test string + number (automatic conversion)
|
|
var strNumResult = "String + Number: " + 42;
|
|
assert(toString(strNumResult) == "String + Number: 42", "String + Number");
|
|
print(" String + Number: " + toString(strNumResult));
|
|
|
|
var strFloatResult = "String + Float: " + 3.14;
|
|
assert(toString(strFloatResult) == "String + Float: 3.14", "String + Float");
|
|
print(" String + Float: " + toString(strFloatResult));
|
|
|
|
var zeroResult = "Zero: " + 0;
|
|
assert(toString(zeroResult) == "Zero: 0", "Zero formatting");
|
|
print(" Zero formatting: " + toString(zeroResult));
|
|
|
|
var negResult = "Negative: " + -10;
|
|
assert(toString(negResult) == "Negative: -10", "Negative formatting");
|
|
print(" Negative formatting: " + toString(negResult));
|
|
|
|
// Test number + string (automatic conversion)
|
|
var numStrResult = 5 + " times";
|
|
assert(toString(numStrResult) == "5 times", "Number + String");
|
|
print(" Number + String: " + toString(numStrResult));
|
|
|
|
var floatStrResult = 3.14 + " is pi";
|
|
assert(toString(floatStrResult) == "3.14 is pi", "Float + String");
|
|
print(" Float + String: " + toString(floatStrResult));
|
|
|
|
var zeroStrResult = 0 + " items";
|
|
assert(toString(zeroStrResult) == "0 items", "Zero + String");
|
|
print(" Zero + String: " + toString(zeroStrResult));
|
|
|
|
// Test significant digits formatting (no trailing zeros)
|
|
var trailingResult = "Trailing zeros: " + 2.0;
|
|
assert(toString(trailingResult) == "Trailing zeros: 2", "Trailing zeros removed");
|
|
print(" Trailing zeros: " + toString(trailingResult));
|
|
|
|
var piResult = "Pi: " + 3.14;
|
|
assert(toString(piResult) == "Pi: 3.14", "Float formatting");
|
|
print(" Pi formatting: " + toString(piResult));
|
|
|
|
var eResult = "E: " + 2.718;
|
|
assert(toString(eResult) == "E: 2.718", "Float formatting");
|
|
print(" E formatting: " + toString(eResult));
|
|
|
|
var simpleResult = "Simple: " + 1.5;
|
|
assert(toString(simpleResult) == "Simple: 1.5", "Float formatting");
|
|
print(" Simple formatting: " + toString(simpleResult));
|
|
|
|
// Test string multiplication
|
|
var strMulResult = "hello" * 3;
|
|
assert(toString(strMulResult) == "hellohellohello", "String multiplication");
|
|
print(" String multiplication: " + toString(strMulResult));
|
|
|
|
var numStrMulResult = 3 * "hello";
|
|
assert(toString(numStrMulResult) == "hellohellohello", "Number * string multiplication");
|
|
print(" Number * string: " + toString(numStrMulResult));
|
|
|
|
print("String + Number concatenation: PASS");
|
|
|
|
// ========================================
|
|
// TEST 3.6: ESCAPE SEQUENCES
|
|
// ========================================
|
|
print("\n--- Test 3.6: Escape Sequences ---");
|
|
|
|
// Test newline
|
|
var newlineTest = "Line 1\nLine 2";
|
|
assert(newlineTest == "Line 1\nLine 2", "Newline escape sequence");
|
|
|
|
// Test tab
|
|
var tabTest = "Column1\tColumn2\tColumn3";
|
|
assert(tabTest == "Column1\tColumn2\tColumn3", "Tab escape sequence");
|
|
|
|
// Test quote escaping
|
|
var quoteTest = "He said \"Hello, World!\"";
|
|
assert(quoteTest == "He said \"Hello, World!\"", "Quote escape sequence");
|
|
|
|
// Test backslash escaping
|
|
var backslashTest = "Path: C:\\Users\\Bob\\Documents";
|
|
assert(backslashTest == "Path: C:\\Users\\Bob\\Documents", "Backslash escape sequence");
|
|
|
|
// Test mixed escape sequences
|
|
var mixedTest = "First line\n\tIndented line\n\t\tDouble indented";
|
|
assert(mixedTest == "First line\n\tIndented line\n\t\tDouble indented", "Mixed escape sequences");
|
|
|
|
// Test escape sequences in concatenation
|
|
var concatTest = "Hello" + "\n" + "World";
|
|
assert(concatTest == "Hello\nWorld", "Escape sequences in concatenation");
|
|
|
|
print("Escape sequences: PASS");
|
|
|
|
// ========================================
|
|
// TEST 4: COMPARISON OPERATORS
|
|
// ========================================
|
|
print("\n--- Test 4: Comparison Operators ---");
|
|
|
|
// Numeric comparisons
|
|
assert(5 > 3, "Greater than");
|
|
assert(3 < 5, "Less than");
|
|
assert(5 == 5, "Equal to");
|
|
assert(5 != 3, "Not equal to");
|
|
|
|
// String comparisons
|
|
assert("hello" == "hello", "String equality");
|
|
assert("hello" != "world", "String inequality");
|
|
|
|
// Boolean comparisons
|
|
assert(true == true, "Boolean equality");
|
|
assert(false == false, "Boolean equality");
|
|
assert(true != false, "Boolean inequality");
|
|
|
|
print("Comparison operators: PASS");
|
|
|
|
// ========================================
|
|
// TEST 5: VARIABLE ASSIGNMENT
|
|
// ========================================
|
|
print("\n--- Test 5: Variable Assignment ---");
|
|
|
|
var x = 10;
|
|
assert(x == 10, "Initial assignment");
|
|
|
|
x = 20;
|
|
assert(x == 20, "Variable reassignment");
|
|
|
|
var y = x;
|
|
assert(y == 20, "Variable to variable assignment");
|
|
|
|
print("Variable assignment: PASS");
|
|
|
|
// ========================================
|
|
// TEST 6: FUNCTIONS
|
|
// ========================================
|
|
print("\n--- Test 6: Functions ---");
|
|
|
|
// Basic function definition and call
|
|
func add(a, b) {
|
|
return a + b;
|
|
}
|
|
|
|
assert(add(2, 3) == 5, "Basic function call");
|
|
assert(add(10, 20) == 30, "Function with larger numbers");
|
|
|
|
// Function with string operations
|
|
func greet(name) {
|
|
return "Hello, " + name + "!";
|
|
}
|
|
|
|
assert(greet("Alice") == "Hello, Alice!", "String function");
|
|
assert(greet("Bob") == "Hello, Bob!", "String function with different input");
|
|
|
|
// Function with no parameters
|
|
func getAnswer() {
|
|
return 42;
|
|
}
|
|
|
|
assert(getAnswer() == 42, "Function with no parameters");
|
|
|
|
print("Functions: PASS");
|
|
|
|
// ========================================
|
|
// TEST 7: NESTED FUNCTION CALLS
|
|
// ========================================
|
|
print("\n--- Test 7: Nested Function Calls ---");
|
|
|
|
func multiply(x, y) {
|
|
return x * y;
|
|
}
|
|
|
|
func subtract(a, b) {
|
|
return a - b;
|
|
}
|
|
|
|
// Nested function calls
|
|
assert(add(add(1, 2), add(3, 4)) == 10, "Nested addition");
|
|
assert(multiply(add(2, 3), subtract(10, 4)) == 30, "Complex nested calls");
|
|
|
|
print("Nested function calls: PASS");
|
|
|
|
// ========================================
|
|
// TEST 8: VARIABLE SCOPING
|
|
// ========================================
|
|
print("\n--- Test 8: Variable Scoping ---");
|
|
|
|
var globalVar = 100;
|
|
|
|
func testScope() {
|
|
var localVar = 50;
|
|
assert(localVar == 50, "Local variable access");
|
|
assert(globalVar == 100, "Global variable access from function");
|
|
return localVar + globalVar;
|
|
}
|
|
|
|
assert(testScope() == 150, "Function accessing both local and global variables");
|
|
|
|
print("Variable scoping: PASS");
|
|
|
|
// ========================================
|
|
// TEST 9: CLOSURES
|
|
// ========================================
|
|
print("\n--- Test 9: Closures ---");
|
|
|
|
var outerVar = "Outer";
|
|
|
|
func closureTest() {
|
|
var innerVar = "Inner";
|
|
return outerVar + " " + innerVar;
|
|
}
|
|
|
|
assert(closureTest() == "Outer Inner", "Basic closure");
|
|
|
|
// More complex closure
|
|
var counter = 0;
|
|
|
|
func makeCounter() {
|
|
var count = 0;
|
|
return count + 1;
|
|
}
|
|
|
|
assert(makeCounter() == 1, "Closure with captured variable");
|
|
|
|
print("Closures: PASS");
|
|
|
|
// ========================================
|
|
// TEST 10: COMPLEX EXPRESSIONS
|
|
// ========================================
|
|
print("\n--- Test 10: Complex Expressions ---");
|
|
|
|
var a = 10;
|
|
var b = 5;
|
|
|
|
assert(a * b + 2 == 52, "Complex arithmetic expression");
|
|
assert((a + b) * (a - b) == 75, "Complex expression with parentheses");
|
|
|
|
// String expressions with variables
|
|
var name = "Bob";
|
|
assert("Hello, " + name + "!" == "Hello, Bob!", "String expression with variables");
|
|
|
|
print("Complex expressions: PASS");
|
|
|
|
// ========================================
|
|
// TEST 11: EDGE CASES
|
|
// ========================================
|
|
print("\n--- Test 11: Edge Cases ---");
|
|
|
|
// Zero values
|
|
assert(0 == 0, "Zero comparison");
|
|
assert(0.0 == 0.0, "Zero float comparison");
|
|
|
|
// Empty strings
|
|
assert("" == "", "Empty string comparison");
|
|
|
|
// Negative zero
|
|
assert(-0 == 0, "Negative zero equals zero");
|
|
|
|
print("Edge cases: PASS");
|
|
|
|
// ========================================
|
|
// TEST 12: PRINT FUNCTION
|
|
// ========================================
|
|
print("\n--- Test 12: Print Function ---");
|
|
|
|
// Test print with different types
|
|
print("Testing print function...");
|
|
print(42);
|
|
print("String test");
|
|
print(true);
|
|
print(false);
|
|
print(3.14);
|
|
|
|
print("Print function: PASS");
|
|
|
|
// ========================================
|
|
// TEST 13: ASSERT FUNCTION
|
|
// ========================================
|
|
print("\n--- Test 13: Assert Function ---");
|
|
|
|
// Test basic assertions
|
|
assert(true, "Basic true assertion");
|
|
assert(5 > 3, "Comparison assertion");
|
|
|
|
// Test assertions with custom messages
|
|
assert(10 == 10, "Custom message assertion");
|
|
assert("hello" == "hello", "String assertion with message");
|
|
|
|
print("Assert function: PASS");
|
|
|
|
// ========================================
|
|
// TEST 14: ERROR HANDLING
|
|
// ========================================
|
|
print("\n--- Test 14: Error Handling ---");
|
|
|
|
// Test that invalid operations throw errors
|
|
// (These are commented out because they would stop execution)
|
|
|
|
// Division by zero should error
|
|
// assert(10 / 0 == 0, "This should fail");
|
|
|
|
// Undefined variable should error
|
|
// assert(undefinedVar == 0, "This should fail");
|
|
|
|
print("Error handling framework in place");
|
|
|
|
// ========================================
|
|
// TEST 15: FUNCTION PASSING - BASIC
|
|
// ========================================
|
|
print("\n--- Test 15: Function Passing - Basic ---");
|
|
|
|
func greet2(name) {
|
|
return "Hello, " + name;
|
|
}
|
|
|
|
func testBasic(func1) {
|
|
return func1("Alice");
|
|
}
|
|
|
|
var result1 = testBasic(greet2);
|
|
assert(result1 == "Hello, Alice", "Basic function passing");
|
|
print("Basic function passing works");
|
|
|
|
// ========================================
|
|
// TEST 16: FUNCTION PASSING - MULTIPLE PARAMETERS
|
|
// ========================================
|
|
print("\n--- Test 16: Function Passing - Multiple Parameters ---");
|
|
|
|
func applyTwo(func1, func2, x, y) {
|
|
return func1(x, y) + func2(x, y);
|
|
}
|
|
|
|
var result2 = applyTwo(add, multiply, 3, 4);
|
|
assert(result2 == 19, "Multiple function parameters (3+4 + 3*4 = 19)");
|
|
print("Multiple function parameters work");
|
|
|
|
// ========================================
|
|
// TEST 17: FUNCTION PASSING - NESTED CALLS
|
|
// ========================================
|
|
print("\n--- Test 17: Function Passing - Nested Calls ---");
|
|
|
|
func square(x) {
|
|
return x * x;
|
|
}
|
|
|
|
func applyNested(func1, func2, x, y) {
|
|
return func1(func2(x, y));
|
|
}
|
|
|
|
var result3 = applyNested(square, add, 3, 4);
|
|
assert(result3 == 49, "Nested function calls ((3+4)^2 = 49)");
|
|
print("Nested function calls work");
|
|
|
|
// ========================================
|
|
// TEST 18: FUNCTION PASSING - COMPOSITION
|
|
// ========================================
|
|
print("\n--- Test 18: Function Passing - Composition ---");
|
|
|
|
func double(x) {
|
|
return x * 2;
|
|
}
|
|
|
|
func addOne(x) {
|
|
return x + 1;
|
|
}
|
|
|
|
func compose(func1, func2, x) {
|
|
return func1(func2(x));
|
|
}
|
|
|
|
var result4 = compose(double, addOne, 5);
|
|
assert(result4 == 12, "Function composition ((5+1)*2 = 12)");
|
|
print("Function composition works");
|
|
|
|
// ========================================
|
|
// TEST 19: FUNCTION PASSING - CALLBACK PATTERNS
|
|
// ========================================
|
|
print("\n--- Test 19: Function Passing - Callback Patterns ---");
|
|
|
|
func processString(str, callback) {
|
|
return callback(str + " processed");
|
|
}
|
|
|
|
func formatString(str) {
|
|
return "[" + str + "]";
|
|
}
|
|
|
|
var result5 = processString("test", formatString);
|
|
assert(result5 == "[test processed]", "Callback pattern with string processing");
|
|
print("Callback patterns work");
|
|
|
|
// ========================================
|
|
// TEST 20: FUNCTION PASSING - DIRECT CALLING
|
|
// ========================================
|
|
print("\n--- Test 20: Function Passing - Direct Calling ---");
|
|
|
|
func callFirst(func1, func2, x) {
|
|
return func1(x);
|
|
}
|
|
|
|
func callSecond(func1, func2, x) {
|
|
return func2(x);
|
|
}
|
|
|
|
func positive(x) {
|
|
return "positive: " + x;
|
|
}
|
|
|
|
func negative(x) {
|
|
return "negative: " + x;
|
|
}
|
|
|
|
var result6a = callFirst(positive, negative, 5);
|
|
var result6b = callSecond(positive, negative, 5);
|
|
assert(result6a == "positive: 5", "Direct call - first function");
|
|
assert(result6b == "negative: 5", "Direct call - second function");
|
|
print("Direct function calling works");
|
|
|
|
// ========================================
|
|
// TEST 21: FUNCTION PASSING - STORAGE AND RETRIEVAL
|
|
// ========================================
|
|
print("\n--- Test 21: Function Passing - Storage and Retrieval ---");
|
|
|
|
func callStoredFunction(func1, x, y) {
|
|
return func1(x, y);
|
|
}
|
|
|
|
var result7a = callStoredFunction(add, 3, 4);
|
|
var result7b = callStoredFunction(multiply, 3, 4);
|
|
assert(result7a == 7, "Stored function call - add");
|
|
assert(result7b == 12, "Stored function call - multiply");
|
|
print("Function storage and retrieval works");
|
|
|
|
// ========================================
|
|
// TEST 22: FUNCTION PASSING - MULTIPLE APPLICATIONS
|
|
// ========================================
|
|
print("\n--- Test 22: Function Passing - Multiple Applications ---");
|
|
|
|
func applyMultiple(func1, x, y, z) {
|
|
return func1(x) + func1(y) + func1(z);
|
|
}
|
|
|
|
func square2(x) {
|
|
return x * x;
|
|
}
|
|
|
|
var result8 = applyMultiple(square2, 2, 3, 4);
|
|
assert(result8 == 29, "Multiple function applications (4 + 9 + 16 = 29)");
|
|
print("Multiple function applications work");
|
|
|
|
// ========================================
|
|
// TEST 23: FUNCTION PASSING - NO PARAMETERS
|
|
// ========================================
|
|
print("\n--- Test 23: Function Passing - No Parameters ---");
|
|
|
|
func callNoParams(func1) {
|
|
return func1();
|
|
}
|
|
|
|
var result9 = callNoParams(getAnswer);
|
|
assert(result9 == 42, "Function with no parameters");
|
|
print("Functions with no parameters work");
|
|
|
|
// ========================================
|
|
// TEST 24: FUNCTION PASSING - MANY PARAMETERS
|
|
// ========================================
|
|
print("\n--- Test 24: Function Passing - Many Parameters ---");
|
|
|
|
func sumMany(a, b, c, d, e) {
|
|
return a + b + c + d + e;
|
|
}
|
|
|
|
func callManyParams(func1) {
|
|
return func1(1, 2, 3, 4, 5);
|
|
}
|
|
|
|
var result10 = callManyParams(sumMany);
|
|
assert(result10 == 15, "Function with many parameters");
|
|
print("Functions with many parameters work");
|
|
|
|
// ========================================
|
|
// TEST 24.5: FUNCTION WITH 100 PARAMETERS
|
|
// ========================================
|
|
print("\n--- Test 24.5: Function with 100 Parameters ---");
|
|
|
|
func sum100(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, p41, p42, p43, p44, p45, p46, p47, p48, p49, p50, p51, p52, p53, p54, p55, p56, p57, p58, p59, p60, p61, p62, p63, p64, p65, p66, p67, p68, p69, p70, p71, p72, p73, p74, p75, p76, p77, p78, p79, p80, p81, p82, p83, p84, p85, p86, p87, p88, p89, p90, p91, p92, p93, p94, p95, p96, p97, p98, p99, p100) {
|
|
return p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10 + p11 + p12 + p13 + p14 + p15 + p16 + p17 + p18 + p19 + p20 + p21 + p22 + p23 + p24 + p25 + p26 + p27 + p28 + p29 + p30 + p31 + p32 + p33 + p34 + p35 + p36 + p37 + p38 + p39 + p40 + p41 + p42 + p43 + p44 + p45 + p46 + p47 + p48 + p49 + p50 + p51 + p52 + p53 + p54 + p55 + p56 + p57 + p58 + p59 + p60 + p61 + p62 + p63 + p64 + p65 + p66 + p67 + p68 + p69 + p70 + p71 + p72 + p73 + p74 + p75 + p76 + p77 + p78 + p79 + p80 + p81 + p82 + p83 + p84 + p85 + p86 + p87 + p88 + p89 + p90 + p91 + p92 + p93 + p94 + p95 + p96 + p97 + p98 + p99 + p100;
|
|
}
|
|
|
|
func call100Params(func1) {
|
|
return func1(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
|
|
}
|
|
|
|
var result100 = call100Params(sum100);
|
|
assert(result100 == 100, "Function with 100 parameters (all 1s = 100)");
|
|
print("Function with 100 parameters works");
|
|
|
|
// ========================================
|
|
// TEST 25: FUNCTION PASSING - IDENTITY
|
|
// ========================================
|
|
print("\n--- Test 25: Function Passing - Identity ---");
|
|
|
|
func identity(x) {
|
|
return x;
|
|
}
|
|
|
|
func applyIdentity(func1, x) {
|
|
return func1(x);
|
|
}
|
|
|
|
var result11 = applyIdentity(identity, "test");
|
|
assert(result11 == "test", "Function identity");
|
|
print("Function identity works");
|
|
|
|
// ========================================
|
|
// TEST 26: FUNCTION PASSING - CONSTANT FUNCTION
|
|
// ========================================
|
|
print("\n--- Test 26: Function Passing - Constant Function ---");
|
|
|
|
func constant(value, x) {
|
|
return value;
|
|
}
|
|
|
|
func applyConstant(func1, x) {
|
|
return func1(42, x);
|
|
}
|
|
|
|
var result12 = applyConstant(constant, "anything");
|
|
assert(result12 == 42, "Constant function");
|
|
print("Constant function works");
|
|
|
|
// ========================================
|
|
// TEST 27: FUNCTION PASSING - FUNCTION COMPARISON
|
|
// ========================================
|
|
print("\n--- Test 27: Function Passing - Function Comparison ---");
|
|
|
|
func sameFunction(x) {
|
|
return x * 2;
|
|
}
|
|
|
|
var func1 = sameFunction;
|
|
var func2 = sameFunction;
|
|
|
|
func compareFunctions(f1, f2, x) {
|
|
return f1(x) == f2(x);
|
|
}
|
|
|
|
var result13 = compareFunctions(func1, func2, 5);
|
|
assert(result13 == true, "Function comparison");
|
|
print("Function comparison works");
|
|
|
|
// ========================================
|
|
// TEST 28: COMPREHENSIVE NUMBER TESTS
|
|
// ========================================
|
|
print("\n--- Test 28: Comprehensive Number Tests ---");
|
|
|
|
// Basic integers
|
|
var small_int = 42;
|
|
var medium_int = 1000000;
|
|
var large_int = 999999999;
|
|
assert(small_int == 42, "Small integer should be 42");
|
|
assert(medium_int == 1000000, "Medium integer should be 1000000");
|
|
assert(large_int == 999999999, "Large integer should be 999999999");
|
|
|
|
// Huge numbers (epoch timestamps)
|
|
var huge1 = 2908616190934;
|
|
var huge2 = 9223372036854775807;
|
|
var huge3 = 1000000000000000;
|
|
assert(huge1 == 2908616190934, "Huge1 should be 2908616190934");
|
|
assert(huge2 == 9223372036854775807, "Huge2 should be 9223372036854775807");
|
|
assert(huge3 == 1000000000000000, "Huge3 should be 1000000000000000");
|
|
|
|
// Basic decimals
|
|
var pi = 3.14159;
|
|
var half = 0.5;
|
|
var quarter = 0.25;
|
|
var one_point_five = 1.5;
|
|
assert(pi == 3.14159, "Pi should be 3.14159");
|
|
assert(half == 0.5, "Half should be 0.5");
|
|
assert(quarter == 0.25, "Quarter should be 0.25");
|
|
assert(one_point_five == 1.5, "One point five should be 1.5");
|
|
|
|
// Large decimals
|
|
var large_decimal1 = 1234567.89;
|
|
var large_decimal2 = 999999.999;
|
|
var large_decimal3 = 1000000.0001;
|
|
assert(large_decimal1 > 1234567.88, "Large decimal 1 should be greater than 1234567.88");
|
|
assert(large_decimal1 < 1234567.90, "Large decimal 1 should be less than 1234567.90");
|
|
assert(large_decimal2 > 999999.998, "Large decimal 2 should be greater than 999999.998");
|
|
assert(large_decimal2 < 1000000.0, "Large decimal 2 should be less than 1000000.0");
|
|
|
|
// Large numbers in different formats
|
|
var million = 1230000;
|
|
var billion = 1230000000;
|
|
var trillion = 1230000000000;
|
|
assert(million == 1230000, "Million should be 1230000");
|
|
assert(billion == 1230000000, "Billion should be 1230000000");
|
|
assert(trillion == 1230000000000, "Trillion should be 1230000000000");
|
|
|
|
// Edge cases
|
|
var zero_num = 0;
|
|
var negative_num = -42;
|
|
var negative_decimal = -3.14;
|
|
var very_small = 0.000001;
|
|
var very_large_decimal = 123456789.123456789;
|
|
assert(zero_num == 0, "Zero should be 0");
|
|
assert(negative_num == -42, "Negative should be -42");
|
|
assert(negative_decimal == -3.14, "Negative decimal should be -3.14");
|
|
assert(very_small > 0.0000009, "Very small should be greater than 0.0000009");
|
|
assert(very_small < 0.0000011, "Very small should be less than 0.0000011");
|
|
|
|
// Mixed operations
|
|
var result_num1 = 42 + 3.14;
|
|
var result_num2 = 1000000 + 0.5;
|
|
var result_num3 = 999999999 + 1.0;
|
|
assert(result_num1 > 45.13, "42 + 3.14 should be greater than 45.13");
|
|
assert(result_num1 < 45.15, "42 + 3.14 should be less than 45.15");
|
|
assert(result_num2 == 1000000.5, "1000000 + 0.5 should be 1000000.5");
|
|
assert(result_num3 == 1000000000, "999999999 + 1.0 should be 1000000000");
|
|
|
|
// Complex expressions
|
|
var complex_num1 = 1000000 + 0.5 + 42;
|
|
var complex_num2 = 3.14159 + 2.71828;
|
|
var complex_num3 = 999999999 + 1 + 0.001;
|
|
assert(complex_num1 == 1000042.5, "Complex1 should be 1000042.5");
|
|
assert(complex_num2 > 5.85986, "Complex2 should be greater than 5.85986");
|
|
assert(complex_num2 < 5.85988, "Complex2 should be less than 5.85988");
|
|
assert(complex_num3 > 1000000000.0009, "Complex3 should be greater than 1000000000.0009");
|
|
assert(complex_num3 < 1000000000.0011, "Complex3 should be less than 1000000000.0011");
|
|
|
|
// Variable assignments and printing
|
|
var var_a = 123456789;
|
|
var var_b = 987654321.123;
|
|
var var_c = 0.000001;
|
|
var var_d = 999999999999;
|
|
assert(var_a == 123456789, "Variable a should be 123456789");
|
|
assert(var_b > 987654321.122, "Variable b should be greater than 987654321.122");
|
|
assert(var_b < 987654321.124, "Variable b should be less than 987654321.124");
|
|
assert(var_c > 0.0000009, "Variable c should be greater than 0.0000009");
|
|
assert(var_c < 0.0000011, "Variable c should be less than 0.0000011");
|
|
assert(var_d == 999999999999, "Variable d should be 999999999999");
|
|
|
|
// Binary numbers
|
|
var bin1 = 0b1010;
|
|
var bin2 = 0b11111111;
|
|
var bin3 = 0b1000000000000000;
|
|
assert(bin1 == 10, "Binary 1010 should be 10");
|
|
assert(bin2 == 255, "Binary 11111111 should be 255");
|
|
assert(bin3 == 32768, "Binary 1000000000000000 should be 32768");
|
|
|
|
// Hexadecimal numbers
|
|
var hex1 = 0xFF;
|
|
var hex2 = 0xFFFF;
|
|
var hex3 = 0xFFFFFFFF;
|
|
assert(hex1 == 255, "Hex FF should be 255");
|
|
assert(hex2 == 65535, "Hex FFFF should be 65535");
|
|
assert(hex3 == 4294967295, "Hex FFFFFFFF should be 4294967295");
|
|
|
|
// Arithmetic operations
|
|
var add_num = 5 + 3;
|
|
var sub_num = 10 - 4;
|
|
var mul_num = 6 * 7;
|
|
var div_num = 15 / 3;
|
|
assert(add_num == 8, "5 + 3 should be 8");
|
|
assert(sub_num == 6, "10 - 4 should be 6");
|
|
assert(mul_num == 42, "6 * 7 should be 42");
|
|
assert(div_num == 5, "15 / 3 should be 5");
|
|
|
|
// Comparison operations
|
|
var eq1 = 5 == 5;
|
|
var eq2 = 5 == 6;
|
|
var ne1 = 5 != 6;
|
|
var ne2 = 5 != 5;
|
|
var lt1 = 3 < 5;
|
|
var lt2 = 5 < 3;
|
|
var gt1 = 7 > 4;
|
|
var gt2 = 2 > 8;
|
|
assert(eq1 == true, "5 == 5 should be true");
|
|
assert(eq2 == false, "5 == 6 should be false");
|
|
assert(ne1 == true, "5 != 6 should be true");
|
|
assert(ne2 == false, "5 != 5 should be false");
|
|
assert(lt1 == true, "3 < 5 should be true");
|
|
assert(lt2 == false, "5 < 3 should be false");
|
|
assert(gt1 == true, "7 > 4 should be true");
|
|
assert(gt2 == false, "2 > 8 should be false");
|
|
|
|
print("Comprehensive number tests: PASS");
|
|
|
|
// ========================================
|
|
// TEST 29: TIME FUNCTION
|
|
// ========================================
|
|
print("\n--- Test 29: Time Function ---");
|
|
import time;
|
|
var start_time = time.now();
|
|
var end_time = time.now();
|
|
var duration = end_time - start_time;
|
|
assert(start_time > 0, "Start time should be positive");
|
|
assert(end_time >= start_time, "End time should be >= start time");
|
|
assert(duration >= 0, "Duration should be non-negative");
|
|
|
|
print("Time function: PASS");
|
|
|
|
// ========================================
|
|
// TEST 30: BOOLEAN + STRING CONCATENATION
|
|
// ========================================
|
|
print("\n--- Test 30: Boolean + String Concatenation ---");
|
|
|
|
var true_val = true;
|
|
var false_val = false;
|
|
var eq_test = 5 == 5;
|
|
var ne_test = 5 != 6;
|
|
var lt_test = 3 < 5;
|
|
var gt_test = 7 > 4;
|
|
|
|
// Test boolean + string
|
|
assert(true + " is true" == "true is true", "Boolean + String concatenation");
|
|
assert(false + " is false" == "false is false", "Boolean + String concatenation");
|
|
|
|
// Test string + boolean
|
|
assert("The answer is: " + true == "The answer is: true", "String + Boolean concatenation");
|
|
assert("The opposite is: " + false == "The opposite is: false", "String + Boolean concatenation");
|
|
|
|
// Test comparison results
|
|
assert(eq_test == true, "5 == 5 should be true");
|
|
assert(ne_test == true, "5 != 6 should be true");
|
|
assert(lt_test == true, "3 < 5 should be true");
|
|
assert(gt_test == true, "7 > 4 should be true");
|
|
|
|
print("Boolean + String concatenation: PASS");
|
|
|
|
// ========================================
|
|
// TEST 31: IF STATEMENTS
|
|
// ========================================
|
|
print("\n--- Test 31: If Statements ---");
|
|
|
|
// Basic if statement
|
|
if (true) {
|
|
print("Basic if statement: PASS");
|
|
}
|
|
|
|
// If-else statement
|
|
if (true) {
|
|
print("If branch executed");
|
|
} else {
|
|
print("✗ Else branch should not execute");
|
|
}
|
|
|
|
if (false) {
|
|
print("✗ If branch should not execute");
|
|
} else {
|
|
print("Else branch executed");
|
|
}
|
|
|
|
// If-else if-else chain
|
|
if (false) {
|
|
print("✗ First if should not execute");
|
|
} else if (true) {
|
|
print("Else if branch executed");
|
|
} else {
|
|
print("✗ Final else should not execute");
|
|
}
|
|
|
|
// Nested if statements
|
|
if (true) {
|
|
if (true) {
|
|
print("Nested if statements: PASS");
|
|
}
|
|
}
|
|
|
|
// Single-line if statements
|
|
if (true) print("Single-line if: PASS");
|
|
if (false) print("✗ Single-line if should not execute");
|
|
|
|
// Complex conditions
|
|
var if_a = 5;
|
|
var if_b = 3;
|
|
if (if_a > if_b) {
|
|
print("Complex condition: PASS");
|
|
}
|
|
|
|
print("If statements: PASS");
|
|
|
|
// ========================================
|
|
// TEST 32: INPUT FUNCTION
|
|
// ========================================
|
|
print("\n--- Test 32: Input Function ---");
|
|
|
|
// Test input function exists
|
|
var input_func = input;
|
|
assert(type(input_func) == "builtin_function", "Input function should be a builtin_function");
|
|
|
|
// Test input with no arguments (would pause for user input)
|
|
// Note: We can't test actual input without user interaction
|
|
print("Input function available");
|
|
|
|
// ========================================
|
|
// TEST 33: TYPE FUNCTION
|
|
// ========================================
|
|
print("\n--- Test 33: Type Function ---");
|
|
|
|
// Test basic types
|
|
assert(type(42) == "number", "Type of number should be 'number'");
|
|
assert(type(3.14) == "number", "Type of decimal should be 'number'");
|
|
assert(type("hello") == "string", "Type of string should be 'string'");
|
|
assert(type(true) == "boolean", "Type of boolean should be 'boolean'");
|
|
assert(type(false) == "boolean", "Type of boolean should be 'boolean'");
|
|
assert(type(none) == "none", "Type of none should be 'none'");
|
|
|
|
// Test function types
|
|
func testFunc() {
|
|
return 42;
|
|
}
|
|
assert(type(testFunc) == "function", "Type of user function should be 'function'");
|
|
assert(type(print) == "builtin_function", "Type of print should be 'builtin_function'");
|
|
assert(type(input) == "builtin_function", "Type of input should be 'builtin_function'");
|
|
assert(type(type) == "builtin_function", "Type of type should be 'builtin_function'");
|
|
|
|
// Test function calls
|
|
assert(type(testFunc()) == "number", "Type of function call should be 'number'");
|
|
assert(type(5 + 3) == "number", "Type of arithmetic should be 'number'");
|
|
assert(type("hello" + "world") == "string", "Type of string concat should be 'string'");
|
|
|
|
print("Type function: PASS");
|
|
|
|
// ========================================
|
|
// TEST 34: TONUMBER FUNCTION
|
|
// ========================================
|
|
print("\n--- Test 34: toNumber Function ---");
|
|
|
|
// Test basic number conversion
|
|
assert(toNumber("42") == 42, "toNumber should convert string to number");
|
|
assert(toNumber("3.14") == 3.14, "toNumber should convert decimal string");
|
|
assert(toNumber("0") == 0, "toNumber should convert zero");
|
|
assert(toNumber("-5") == -5, "toNumber should convert negative number");
|
|
|
|
// Test whitespace handling
|
|
assert(toNumber(" 42 ") == 42, "toNumber should handle whitespace");
|
|
assert(toNumber("\t3.14\n") == 3.14, "toNumber should handle tabs and newlines");
|
|
|
|
// Test type checking
|
|
var converted_num = toNumber("42");
|
|
assert(type(converted_num) == "number", "toNumber result should be number type");
|
|
assert(converted_num + 10 == 52, "toNumber result should work in arithmetic");
|
|
|
|
// Test edge cases
|
|
assert(toNumber("0.0") == 0, "toNumber should handle 0.0");
|
|
assert(toNumber("1e6") == 1000000, "toNumber should handle scientific notation");
|
|
assert(toNumber("1.23e-4") == 0.000123, "toNumber should handle small scientific notation");
|
|
|
|
print("toNumber function: PASS");
|
|
|
|
// ========================================
|
|
// TEST 35: TOSTRING FUNCTION
|
|
// ========================================
|
|
print("\n--- Test 35: toString Function ---");
|
|
|
|
// Test basic types
|
|
assert(toString(42) == toString(42), "toString should convert number to string");
|
|
assert(toString(3.14) == toString(3.14), "toString should convert decimal to string");
|
|
assert(toString("hello") == toString("hello"), "toString should return string as-is");
|
|
assert(toString(true) == toString(true), "toString should convert boolean to string");
|
|
assert(toString(false) == toString(false), "toString should convert boolean to string");
|
|
assert(toString(none) == toString(none), "toString should convert none to string");
|
|
|
|
// Test function types
|
|
func myFunc() {
|
|
return 42;
|
|
}
|
|
assert(toString(myFunc) == toString(myFunc), "toString should format user functions");
|
|
assert(toString(print) == toString(print), "toString should format builtin functions");
|
|
assert(toString(input) == toString(input), "toString should format builtin functions");
|
|
assert(toString(type) == toString(type), "toString should format builtin functions");
|
|
assert(toString(toString) == toString(toString), "toString should format builtin functions");
|
|
|
|
// Test function calls
|
|
assert(toString(myFunc()) == toString(42), "toString should convert function result");
|
|
assert(toString(5 + 3) == toString(8), "toString should convert arithmetic result");
|
|
assert(toString("hello" + "world") == toString("helloworld"), "toString should convert string concat result");
|
|
|
|
// Test type checking
|
|
var str_result = toString(42);
|
|
assert(type(str_result) == "string", "toString result should be string type");
|
|
assert(str_result + " is a number" == toString(42) + " is a number", "toString result should work in string operations");
|
|
|
|
// Test nested calls
|
|
assert(toString(toString(42)) == toString(42), "toString should handle nested calls");
|
|
assert(toString(type(toString(42))) == toString("string"), "toString should handle complex nested calls");
|
|
|
|
// Test comparisons
|
|
assert(toString(42) == toString(42), "toString should match itself");
|
|
assert(toString(3.14) == toString(3.14), "toString should match itself");
|
|
|
|
print("toString function: PASS");
|
|
|
|
// ========================================
|
|
// TEST 36: PRINT FUNCTION ENHANCEMENT
|
|
// ========================================
|
|
print("\n--- Test 36: Print Function Enhancement ---");
|
|
|
|
// Test that print works with all object types
|
|
print("Testing print with all types:");
|
|
print(42);
|
|
print("hello");
|
|
print(true);
|
|
print(none);
|
|
print(myFunc);
|
|
print(print);
|
|
print(input);
|
|
print(type);
|
|
print(toString);
|
|
print(toNumber);
|
|
|
|
print("Print function works with all object types");
|
|
|
|
// ========================================
|
|
// TEST 37: REDEFINABLE FUNCTIONS
|
|
// ========================================
|
|
print("\n--- Test 37: Redefinable Functions ---");
|
|
|
|
// Test user function redefinition
|
|
func testFunc() {
|
|
return "original";
|
|
}
|
|
|
|
assert(testFunc() == "original", "Original function should work");
|
|
|
|
func testFunc() {
|
|
return "redefined";
|
|
}
|
|
|
|
assert(testFunc() == "redefined", "Redefined function should work");
|
|
|
|
// Test built-in function override - FIXED VERSION
|
|
// Instead of redefining print, we'll test function redefinition with a custom function
|
|
func printOverride(value) {
|
|
print("OVERRIDE: " + toString(value));
|
|
}
|
|
|
|
printOverride("This should show override prefix");
|
|
|
|
// Test multiple redefinitions
|
|
func counter() {
|
|
return 1;
|
|
}
|
|
|
|
func counter() {
|
|
return 2;
|
|
}
|
|
|
|
func counter() {
|
|
return 3;
|
|
}
|
|
|
|
assert(counter() == 3, "Final redefinition should be used");
|
|
|
|
print("Redefinable functions: PASS");
|
|
|
|
// ========================================
|
|
// TEST 38: RECURSION
|
|
// ========================================
|
|
print("\n--- Test 38: Recursion ---");
|
|
|
|
// Test basic recursion
|
|
func factorial(n) {
|
|
if (n <= 1) {
|
|
return 1;
|
|
} else {
|
|
return n * factorial(n - 1);
|
|
}
|
|
}
|
|
|
|
assert(factorial(0) == 1, "factorial(0) should be 1");
|
|
assert(factorial(1) == 1, "factorial(1) should be 1");
|
|
assert(factorial(5) == 120, "factorial(5) should be 120");
|
|
|
|
// Test Fibonacci
|
|
func fibonacci(n) {
|
|
if (n <= 1) {
|
|
return n;
|
|
} else {
|
|
return fibonacci(n - 1) + fibonacci(n - 2);
|
|
}
|
|
}
|
|
|
|
assert(fibonacci(0) == 0, "fibonacci(0) should be 0");
|
|
assert(fibonacci(1) == 1, "fibonacci(1) should be 1");
|
|
assert(fibonacci(5) == 5, "fibonacci(5) should be 5");
|
|
assert(fibonacci(8) == 21, "fibonacci(8) should be 21");
|
|
|
|
// Test mutual recursion
|
|
func isEven(n) {
|
|
if (n == 0) {
|
|
return true;
|
|
} else if (n == 1) {
|
|
return false;
|
|
} else {
|
|
return isOdd(n - 1);
|
|
}
|
|
}
|
|
|
|
func isOdd(n) {
|
|
if (n == 0) {
|
|
return false;
|
|
} else if (n == 1) {
|
|
return true;
|
|
} else {
|
|
return isEven(n - 1);
|
|
}
|
|
}
|
|
|
|
assert(isEven(0) == true, "isEven(0) should be true");
|
|
assert(isEven(10) == true, "isEven(10) should be true");
|
|
assert(isEven(11) == false, "isEven(11) should be false");
|
|
assert(isOdd(0) == false, "isOdd(0) should be false");
|
|
assert(isOdd(11) == true, "isOdd(11) should be true");
|
|
|
|
// Test deep recursion
|
|
func deepFactorial(n) {
|
|
if (n <= 1) {
|
|
return 1;
|
|
} else {
|
|
return n * deepFactorial(n - 1);
|
|
}
|
|
}
|
|
|
|
assert(deepFactorial(10) == 3628800, "deepFactorial(10) should be 3628800");
|
|
|
|
print("Recursion: PASS");
|
|
|
|
// ========================================
|
|
// TEST 39: LOGICAL OPERATORS (&&, ||, !)
|
|
// ========================================
|
|
print("\n--- Test 39: Logical Operators ---");
|
|
|
|
// Test logical AND (&&)
|
|
assert(5 && 3 == 3, "5 && 3 should return 3 (truthy && truthy = second value)");
|
|
assert(0 && 5 == 0, "0 && 5 should return 0 (falsy && truthy = first value)");
|
|
assert(5 && 0 == 0, "5 && 0 should return 0 (truthy && falsy = second value)");
|
|
assert(0 && 0 == 0, "0 && 0 should return 0 (falsy && falsy = first value)");
|
|
|
|
// Test logical OR (||)
|
|
assert(5 || 3 == 5, "5 || 3 should return 5 (truthy || truthy = first value)");
|
|
assert(0 || 5 == 5, "0 || 5 should return 5 (falsy || truthy = second value)");
|
|
assert(5 || 0 == 5, "5 || 0 should return 5 (truthy || falsy = first value)");
|
|
assert(0 || 0 == 0, "0 || 0 should return 0 (falsy || falsy = second value)");
|
|
|
|
// Test logical NOT (!)
|
|
assert(!0 == true, "!0 should be true");
|
|
assert(!1 == false, "!1 should be false");
|
|
assert(!5 == false, "!5 should be false");
|
|
assert(!true == false, "!true should be false");
|
|
assert(!false == true, "!false should be true");
|
|
|
|
// Test short-circuit evaluation
|
|
var short_circuit_test = 0;
|
|
func sideEffect() {
|
|
short_circuit_test = 1;
|
|
return 5;
|
|
}
|
|
|
|
// Test that short-circuit evaluation works correctly
|
|
// Note: We can't easily test side effects in Bob, so we test the return values instead
|
|
var result_short1 = 0 && 5;
|
|
assert(result_short1 == 0, "0 && 5 should return 0 (short-circuit)");
|
|
|
|
var result_short2 = 1 && 5;
|
|
assert(result_short2 == 5, "1 && 5 should return 5 (no short-circuit)");
|
|
|
|
var result_short3 = 1 || 5;
|
|
assert(result_short3 == 1, "1 || 5 should return 1 (short-circuit)");
|
|
|
|
var result_short4 = 0 || 5;
|
|
assert(result_short4 == 5, "0 || 5 should return 5 (no short-circuit)");
|
|
|
|
// Test complex logical expressions
|
|
assert((5 > 3) && (10 < 20) == true, "Complex AND with comparisons");
|
|
assert((5 < 3) || (10 < 20) == true, "Complex OR with comparisons");
|
|
assert(!(5 < 3) == true, "Complex NOT with comparison");
|
|
|
|
// Test truthiness rules
|
|
assert("hello" && "world" == "world", "String && string should return second string");
|
|
assert("" && "world" == "", "Empty string && string should return empty string");
|
|
assert("hello" || "world" == "hello", "String || string should return first string");
|
|
assert("" || "world" == "world", "Empty string || string should return second string");
|
|
|
|
print("Logical operators: PASS");
|
|
|
|
// ========================================
|
|
// TEST 40: BITWISE OPERATORS (&, |, ^, <<, >>, ~)
|
|
// ========================================
|
|
print("\n--- Test 40: Bitwise Operators ---");
|
|
|
|
// Test bitwise AND (&)
|
|
assert(10 & 3 == 2, "10 & 3 should be 2 (1010 & 0011 = 0010)");
|
|
assert(15 & 7 == 7, "15 & 7 should be 7 (1111 & 0111 = 0111)");
|
|
assert(255 & 128 == 128, "255 & 128 should be 128");
|
|
|
|
// Test bitwise OR (|)
|
|
assert(10 | 3 == 11, "10 | 3 should be 11 (1010 | 0011 = 1011)");
|
|
assert(5 | 10 == 15, "5 | 10 should be 15 (0101 | 1010 = 1111)");
|
|
assert(128 | 64 == 192, "128 | 64 should be 192");
|
|
|
|
// Test bitwise XOR (^)
|
|
assert(10 ^ 3 == 9, "10 ^ 3 should be 9 (1010 ^ 0011 = 1001)");
|
|
assert(15 ^ 7 == 8, "15 ^ 7 should be 8 (1111 ^ 0111 = 1000)");
|
|
assert(255 ^ 128 == 127, "255 ^ 128 should be 127");
|
|
|
|
// Test left shift (<<)
|
|
assert(5 << 1 == 10, "5 << 1 should be 10 (0101 << 1 = 1010)");
|
|
assert(3 << 2 == 12, "3 << 2 should be 12 (0011 << 2 = 1100)");
|
|
assert(1 << 8 == 256, "1 << 8 should be 256");
|
|
|
|
// Test right shift (>>)
|
|
assert(10 >> 1 == 5, "10 >> 1 should be 5 (1010 >> 1 = 0101)");
|
|
assert(20 >> 2 == 5, "20 >> 2 should be 5 (10100 >> 2 = 00101)");
|
|
assert(256 >> 8 == 1, "256 >> 8 should be 1");
|
|
|
|
// Test bitwise NOT (~)
|
|
assert(~10 == -11, "~10 should be -11");
|
|
assert(~0 == -1, "~0 should be -1");
|
|
assert(~(-1) == 0, "~(-1) should be 0");
|
|
|
|
// Test complex bitwise expressions
|
|
assert((10 & 3) | (5 & 2) == 2, "Complex bitwise expression 1");
|
|
assert((15 << 1) >> 1 == 15, "Complex bitwise expression 2");
|
|
assert(~(10 & 5) == -1, "Complex bitwise expression 3");
|
|
|
|
// Test edge cases
|
|
assert(0 & 0 == 0, "0 & 0 should be 0");
|
|
assert(0 | 0 == 0, "0 | 0 should be 0");
|
|
assert(0 ^ 0 == 0, "0 ^ 0 should be 0");
|
|
assert(0 << 5 == 0, "0 << 5 should be 0");
|
|
assert(0 >> 5 == 0, "0 >> 5 should be 0");
|
|
assert(~0 == -1, "~0 should be -1");
|
|
|
|
print("Bitwise operators: PASS");
|
|
|
|
// ========================================
|
|
// TEST 41: COMPOUND ASSIGNMENT OPERATORS
|
|
// ========================================
|
|
print("\n--- Test 41: Compound Assignment Operators ---");
|
|
|
|
// Test arithmetic compound assignment
|
|
var comp_x = 10;
|
|
comp_x += 5;
|
|
assert(comp_x == 15, "comp_x += 5 should make comp_x = 15");
|
|
|
|
comp_x -= 3;
|
|
assert(comp_x == 12, "comp_x -= 3 should make comp_x = 12");
|
|
|
|
comp_x *= 2;
|
|
assert(comp_x == 24, "comp_x *= 2 should make comp_x = 24");
|
|
|
|
comp_x /= 4;
|
|
assert(comp_x == 6, "comp_x /= 4 should make comp_x = 6");
|
|
|
|
comp_x %= 4;
|
|
assert(comp_x == 2, "comp_x %= 4 should make comp_x = 2");
|
|
|
|
// Test bitwise compound assignment
|
|
var comp_y = 15;
|
|
comp_y &= 7;
|
|
assert(comp_y == 7, "comp_y &= 7 should make comp_y = 7");
|
|
|
|
comp_y |= 8;
|
|
assert(comp_y == 15, "comp_y |= 8 should make comp_y = 15");
|
|
|
|
comp_y ^= 4;
|
|
assert(comp_y == 11, "comp_y ^= 4 should make comp_y = 11");
|
|
|
|
comp_y <<= 1;
|
|
assert(comp_y == 22, "comp_y <<= 1 should make comp_y = 22");
|
|
|
|
comp_y >>= 2;
|
|
assert(comp_y == 5, "comp_y >>= 2 should make comp_y = 5");
|
|
|
|
// Test compound assignment with expressions
|
|
var comp_z = 10;
|
|
comp_z += 2 + 3;
|
|
assert(comp_z == 15, "comp_z += 2 + 3 should make comp_z = 15");
|
|
|
|
comp_z *= 2 + 1;
|
|
assert(comp_z == 45, "comp_z *= 2 + 1 should make comp_z = 45");
|
|
|
|
// Test compound assignment with variables
|
|
var comp_a = 5;
|
|
var comp_b = 3;
|
|
comp_a += comp_b;
|
|
assert(comp_a == 8, "comp_a += comp_b should make comp_a = 8");
|
|
|
|
comp_a *= comp_b;
|
|
assert(comp_a == 24, "comp_a *= comp_b should make comp_a = 24");
|
|
|
|
print("Compound assignment operators: PASS");
|
|
|
|
// ========================================
|
|
// TEST 42: ANONYMOUS FUNCTIONS
|
|
// ========================================
|
|
print("\n--- Test 42: Anonymous Functions ---");
|
|
|
|
// Test basic anonymous function
|
|
var anonymous1 = func() {
|
|
return 42;
|
|
};
|
|
assert(anonymous1() == 42, "Basic anonymous function should return 42");
|
|
|
|
// Test anonymous function with parameters
|
|
var anonymous2 = func(x, y) {
|
|
return x + y;
|
|
};
|
|
assert(anonymous2(5, 3) == 8, "Anonymous function with parameters should work");
|
|
|
|
// Test anonymous function with string operations
|
|
var anonymous3 = func(name) {
|
|
return "Hello, " + name + "!";
|
|
};
|
|
assert(anonymous3("Bob") == "Hello, Bob!", "Anonymous function with strings should work");
|
|
|
|
// Test anonymous function with conditionals
|
|
var anonymous4 = func(x) {
|
|
if (x > 0) {
|
|
return "positive";
|
|
} else {
|
|
return "non-positive";
|
|
}
|
|
};
|
|
assert(anonymous4(5) == "positive", "Anonymous function with conditionals should work");
|
|
assert(anonymous4(-3) == "non-positive", "Anonymous function with conditionals should work");
|
|
|
|
// Test anonymous function composition
|
|
var compose = func(f, g, x) {
|
|
return f(g(x));
|
|
};
|
|
|
|
var double = func(x) {
|
|
return x * 2;
|
|
};
|
|
|
|
var addOne = func(x) {
|
|
return x + 1;
|
|
};
|
|
|
|
var result_comp = compose(double, addOne, 5);
|
|
assert(result_comp == 12, "Anonymous function composition should work");
|
|
|
|
// Test anonymous function as return value
|
|
func createMultiplier(factor) {
|
|
return func(x) {
|
|
return x * factor;
|
|
};
|
|
}
|
|
|
|
var multiplyBy3 = createMultiplier(3);
|
|
assert(multiplyBy3(4) == 12, "Anonymous function as return value should work");
|
|
|
|
// Test anonymous function with closure
|
|
func createCounter() {
|
|
var count = 0;
|
|
return func() {
|
|
count = count + 1;
|
|
return count;
|
|
};
|
|
}
|
|
|
|
var counter1 = createCounter();
|
|
var counter2 = createCounter();
|
|
|
|
assert(counter1() == 1, "Anonymous function closure should work");
|
|
assert(counter1() == 2, "Anonymous function closure should maintain state");
|
|
assert(counter2() == 1, "Different anonymous function instances should have separate state");
|
|
|
|
print("Anonymous functions: PASS");
|
|
|
|
// ========================================
|
|
// TEST 43: FUNCTIONS RETURNING FUNCTIONS
|
|
// ========================================
|
|
print("\n--- Test 43: Functions Returning Functions ---");
|
|
|
|
// Test basic function returning function
|
|
func createAdder(x) {
|
|
return func(y) {
|
|
return x + y;
|
|
};
|
|
}
|
|
|
|
var add5 = createAdder(5);
|
|
assert(add5(3) == 8, "Function returning function should work");
|
|
|
|
// Test function returning multiple functions
|
|
func createMathOps() {
|
|
return func(x, y) {
|
|
return x + y;
|
|
};
|
|
}
|
|
|
|
var mathFunc = createMathOps();
|
|
assert(mathFunc(10, 20) == 30, "Function returning math function should work");
|
|
|
|
// Test function returning function with closure
|
|
func createGreeter(greeting) {
|
|
return func(name) {
|
|
return greeting + ", " + name + "!";
|
|
};
|
|
}
|
|
|
|
var helloGreeter = createGreeter("Hello");
|
|
var hiGreeter = createGreeter("Hi");
|
|
|
|
assert(helloGreeter("Alice") == "Hello, Alice!", "Greeter function should work");
|
|
assert(hiGreeter("Bob") == "Hi, Bob!", "Different greeter should work");
|
|
|
|
// Test nested function returning functions
|
|
func createCalculator() {
|
|
return func(operation) {
|
|
if (operation == "add") {
|
|
return func(x, y) {
|
|
return x + y;
|
|
};
|
|
} else if (operation == "multiply") {
|
|
return func(x, y) {
|
|
return x * y;
|
|
};
|
|
} else {
|
|
return func(x, y) {
|
|
return x - y;
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
var calculator = createCalculator();
|
|
var addFunc = calculator("add");
|
|
var multiplyFunc = calculator("multiply");
|
|
|
|
assert(addFunc(5, 3) == 8, "Calculator add function should work");
|
|
assert(multiplyFunc(4, 6) == 24, "Calculator multiply function should work");
|
|
|
|
// Test function returning function with complex logic
|
|
func createValidator(rule) {
|
|
return func(value) {
|
|
if (rule == "positive") {
|
|
return value > 0;
|
|
} else if (rule == "even") {
|
|
return value % 2 == 0;
|
|
} else if (rule == "string") {
|
|
return type(value) == "string";
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
}
|
|
|
|
var positiveValidator = createValidator("positive");
|
|
var evenValidator = createValidator("even");
|
|
var stringValidator = createValidator("string");
|
|
|
|
assert(positiveValidator(5) == true, "Positive validator should work");
|
|
assert(positiveValidator(-3) == false, "Positive validator should work");
|
|
assert(evenValidator(4) == true, "Even validator should work");
|
|
assert(evenValidator(7) == false, "Even validator should work");
|
|
assert(stringValidator("hello") == true, "String validator should work");
|
|
assert(stringValidator(42) == false, "String validator should work");
|
|
|
|
print("Functions returning functions: PASS");
|
|
|
|
// ========================================
|
|
// TEST 44: COMPREHENSIVE OPERATOR PRECEDENCE
|
|
// ========================================
|
|
print("\n--- Test 44: Operator Precedence ---");
|
|
|
|
// Test logical operator precedence
|
|
assert(5 && 3 || 0 == 3, "&& should have higher precedence than ||");
|
|
assert(0 || 5 && 3 == 3, "&& should have higher precedence than ||");
|
|
|
|
// Test bitwise operator precedence
|
|
assert(10 & 3 | 5 == 7, "& should have higher precedence than |");
|
|
assert(10 | 3 & 5 == 11, "& should have higher precedence than |");
|
|
|
|
// Test shift operator precedence
|
|
assert(10 << 1 + 2 == 80, "Shift should have higher precedence than addition");
|
|
assert(10 + 1 << 2 == 44, "Addition should have higher precedence than shift");
|
|
|
|
// Test arithmetic operator precedence
|
|
assert(2 + 3 * 4 == 14, "Multiplication should have higher precedence than addition");
|
|
assert(10 - 4 / 2 == 8, "Division should have higher precedence than subtraction");
|
|
|
|
// Test complex precedence
|
|
assert(5 && 3 | 2 << 1 == 7, "Complex precedence test 1");
|
|
assert((5 && 3) | (2 << 1) == 7, "Complex precedence test 2");
|
|
|
|
print("Operator precedence: PASS");
|
|
|
|
// ========================================
|
|
// TEST 45: EDGE CASES FOR NEW OPERATORS
|
|
// ========================================
|
|
print("\n--- Test 45: Edge Cases for New Operators ---");
|
|
|
|
// Test logical operators with edge cases
|
|
assert(0 && 0 == 0, "0 && 0 should be 0");
|
|
assert(0 || 0 == 0, "0 || 0 should be 0");
|
|
assert(!0 == true, "!0 should be true");
|
|
assert(!1 == false, "!1 should be false");
|
|
|
|
// Test bitwise operators with edge cases
|
|
assert(0 & 0 == 0, "0 & 0 should be 0");
|
|
assert(0 | 0 == 0, "0 | 0 should be 0");
|
|
assert(0 ^ 0 == 0, "0 ^ 0 should be 0");
|
|
assert(0 << 5 == 0, "0 << 5 should be 0");
|
|
assert(0 >> 5 == 0, "0 >> 5 should be 0");
|
|
assert(~0 == -1, "~0 should be -1");
|
|
|
|
// Test compound assignment with edge cases
|
|
var edge_x = 0;
|
|
edge_x += 5;
|
|
assert(edge_x == 5, "0 += 5 should be 5");
|
|
|
|
edge_x -= 10;
|
|
assert(edge_x == -5, "5 -= 10 should be -5");
|
|
|
|
edge_x *= 0;
|
|
assert(edge_x == 0, "-5 *= 0 should be 0");
|
|
|
|
// Test anonymous functions with edge cases
|
|
var edge_func = func() {
|
|
return none;
|
|
};
|
|
assert(type(edge_func()) == "none", "Anonymous function returning none should work");
|
|
|
|
print("Edge cases for new operators: PASS");
|
|
|
|
// ========================================
|
|
// TEST 46: LEXER CONSISTENCY IMPROVEMENTS
|
|
// ========================================
|
|
print("\n--- Test 46: Lexer Consistency Improvements ---");
|
|
|
|
// Test 1: Increment/Decrement Operators
|
|
var x = 5;
|
|
assert(x == 5, "Initial value should be 5");
|
|
|
|
x++;
|
|
assert(x == 6, "Postfix increment should work");
|
|
|
|
++x;
|
|
assert(x == 7, "Prefix increment should work");
|
|
|
|
x--;
|
|
assert(x == 6, "Postfix decrement should work");
|
|
|
|
--x;
|
|
assert(x == 5, "Prefix decrement should work");
|
|
|
|
// Test 2: Compound Assignment Operators
|
|
var y = 10;
|
|
assert(y == 10, "Initial value should be 10");
|
|
|
|
y += 5;
|
|
assert(y == 15, "+= should work");
|
|
|
|
y -= 3;
|
|
assert(y == 12, "-= should work");
|
|
|
|
y *= 2;
|
|
assert(y == 24, "*= should work");
|
|
|
|
y /= 4;
|
|
assert(y == 6, "/= should work");
|
|
|
|
y %= 4;
|
|
assert(y == 2, "%= should work");
|
|
|
|
// Test 3: Bitwise Assignment Operators
|
|
var z = 15;
|
|
assert(z == 15, "Initial value should be 15");
|
|
|
|
z &= 3;
|
|
assert(z == 3, "&= should work");
|
|
|
|
z |= 8;
|
|
assert(z == 11, "|= should work");
|
|
|
|
z ^= 5;
|
|
assert(z == 14, "^= should work");
|
|
|
|
z <<= 1;
|
|
assert(z == 28, "<<= should work");
|
|
|
|
z >>= 2;
|
|
assert(z == 7, ">>= should work");
|
|
|
|
// Test 4: Logical Operators
|
|
var a = true;
|
|
var b = false;
|
|
assert(a == true, "a should be true");
|
|
assert(b == false, "b should be false");
|
|
|
|
var result1 = a && b;
|
|
assert(result1 == false, "true && false should be false");
|
|
|
|
var result2 = a || b;
|
|
assert(result2 == true, "true || false should be true");
|
|
|
|
var result3 = !a;
|
|
assert(result3 == false, "!true should be false");
|
|
|
|
var result4 = !b;
|
|
assert(result4 == true, "!false should be true");
|
|
|
|
// Test 5: Comparison Operators
|
|
var c = 10;
|
|
var d = 20;
|
|
assert(c == 10, "c should be 10");
|
|
assert(d == 20, "d should be 20");
|
|
|
|
var eq = c == d;
|
|
assert(eq == false, "10 == 20 should be false");
|
|
|
|
var ne = c != d;
|
|
assert(ne == true, "10 != 20 should be true");
|
|
|
|
var lt = c < d;
|
|
assert(lt == true, "10 < 20 should be true");
|
|
|
|
var gt = c > d;
|
|
assert(gt == false, "10 > 20 should be false");
|
|
|
|
var le = c <= d;
|
|
assert(le == true, "10 <= 20 should be true");
|
|
|
|
var ge = c >= d;
|
|
assert(ge == false, "10 >= 20 should be false");
|
|
|
|
// Test 6: Bitwise Operators
|
|
var e = 5;
|
|
var f = 3;
|
|
assert(e == 5, "e should be 5");
|
|
assert(f == 3, "f should be 3");
|
|
|
|
var bitwise_and = e & f;
|
|
assert(bitwise_and == 1, "5 & 3 should be 1");
|
|
|
|
var bitwise_or = e | f;
|
|
assert(bitwise_or == 7, "5 | 3 should be 7");
|
|
|
|
var bitwise_xor = e ^ f;
|
|
assert(bitwise_xor == 6, "5 ^ 3 should be 6");
|
|
|
|
var bitwise_not = ~e;
|
|
assert(bitwise_not == -6, "~5 should be -6");
|
|
|
|
var left_shift = e << 1;
|
|
assert(left_shift == 10, "5 << 1 should be 10");
|
|
|
|
var right_shift = e >> 1;
|
|
assert(right_shift == 2, "5 >> 1 should be 2");
|
|
|
|
// Test 7: Complex Expressions
|
|
var complex = 1;
|
|
assert(complex == 1, "Initial complex value should be 1");
|
|
|
|
// Test complex expression with multiple operators
|
|
var result5 = (++complex) * (complex++) + (--complex);
|
|
assert(result5 == 6, "Complex expression should be 6");
|
|
assert(complex == 2, "Variable should be 2");
|
|
|
|
// Test another complex expression
|
|
var result6 = complex++ + ++complex + complex-- + --complex;
|
|
assert(result6 == 12, "Complex expression should be 12");
|
|
assert(complex == 2, "Variable should be 2");
|
|
|
|
// Test 8: Edge Cases
|
|
var edge = 0;
|
|
assert(edge == 0, "Initial edge value should be 0");
|
|
|
|
edge++;
|
|
assert(edge == 1, "0++ should be 1");
|
|
|
|
edge--;
|
|
assert(edge == 0, "1-- should be 0");
|
|
|
|
++edge;
|
|
assert(edge == 1, "++0 should be 1");
|
|
|
|
--edge;
|
|
assert(edge == 0, "--1 should be 0");
|
|
|
|
edge += 0;
|
|
assert(edge == 0, "0 += 0 should be 0");
|
|
|
|
edge -= 0;
|
|
assert(edge == 0, "0 -= 0 should be 0");
|
|
|
|
edge *= 5;
|
|
assert(edge == 0, "0 *= 5 should be 0");
|
|
|
|
print("Lexer consistency improvements: PASS");
|
|
|
|
// ========================================
|
|
// TEST 20: NONE VALUE CONCATENATION (CRITICAL FIX TEST)
|
|
// ========================================
|
|
print("\n--- Test 20: None Value Concatenation (Critical Fix Test) ---");
|
|
|
|
// Test string + none concatenation
|
|
var testString = "Hello";
|
|
var testNone = none;
|
|
var concatResult1 = testString + testNone;
|
|
assert(toString(concatResult1) == "Hellonone", "String + none should concatenate to 'Hellonone'");
|
|
print(" String + none: " + toString(concatResult1));
|
|
|
|
// Test none + string concatenation
|
|
var concatResult2 = testNone + testString;
|
|
assert(toString(concatResult2) == "noneHello", "None + string should concatenate to 'noneHello'");
|
|
print(" None + string: " + toString(concatResult2));
|
|
|
|
// Test in print statements
|
|
print(" Print with none: " + testNone);
|
|
|
|
// Test variable reassignment to none
|
|
var y = "Another string";
|
|
y = none;
|
|
print(" Variable set to none: " + y);
|
|
|
|
print("None value concatenation: PASS");
|
|
|
|
// ========================================
|
|
// TEST 21: MEMORY MANAGEMENT
|
|
// ========================================
|
|
print("\n--- Test 21: Memory Management ---");
|
|
|
|
// Test variable reassignment
|
|
var x = "Hello World";
|
|
x = 42;
|
|
x = "New String";
|
|
assert(toString(x) == "New String", "Variable reassignment should work");
|
|
|
|
// Test function reassignment
|
|
var func1 = func() { return "Function 1"; };
|
|
var func2 = func() { return "Function 2"; };
|
|
func1 = func2;
|
|
assert(func1() == "Function 2", "Function reassignment should work");
|
|
|
|
// Test large string allocation and cleanup
|
|
var bigString = "This is a very long string that should use significant memory. " +
|
|
"It contains many characters and should be properly freed when " +
|
|
"the variable is reassigned or set to none. " +
|
|
"Let's make it even longer by repeating some content.";
|
|
bigString = "Small";
|
|
assert(toString(bigString) == "Small", "Large string cleanup should work");
|
|
|
|
// Test multiple reassignments
|
|
var z = "First";
|
|
z = "Second";
|
|
z = "Third";
|
|
z = "Fourth";
|
|
z = "Fifth";
|
|
assert(toString(z) == "Fifth", "Multiple reassignments should work");
|
|
|
|
print("Memory management: PASS");
|
|
|
|
// ========================================
|
|
// TEST 22: MULTI-STATEMENT FUNCTION EXECUTION (CRITICAL BUG TEST)
|
|
// ========================================
|
|
print("\n--- Test 22: Multi-Statement Function Execution (Critical Bug Test) ---");
|
|
|
|
// Test the bug where functions only executed their first statement
|
|
func createMultiStatementFunction() {
|
|
return func(x) {
|
|
print(" Statement 1: Starting with " + toString(x));
|
|
var result = x * 2;
|
|
print(" Statement 2: Doubled to " + toString(result));
|
|
result += 5;
|
|
print(" Statement 3: Added 5 to get " + toString(result));
|
|
result *= 3;
|
|
print(" Statement 4: Multiplied by 3 to get " + toString(result));
|
|
result -= 10;
|
|
print(" Statement 5: Subtracted 10 to get " + toString(result));
|
|
return result;
|
|
};
|
|
}
|
|
|
|
var multiFunc = createMultiStatementFunction();
|
|
var result1 = multiFunc(7);
|
|
assert(result1 == 47, "Multi-statement function should execute all statements"); // (7*2+5)*3-10 = 47
|
|
print(" Multi-statement function result: " + toString(result1));
|
|
|
|
// Test nested multi-statement functions
|
|
func createNestedMultiFunction() {
|
|
return func(x) {
|
|
var temp = x + 10;
|
|
var innerFunc = func(y) {
|
|
var innerResult = y * 2;
|
|
innerResult += 3;
|
|
return innerResult;
|
|
};
|
|
var innerResult = innerFunc(temp);
|
|
return innerResult + 5;
|
|
};
|
|
}
|
|
|
|
var nestedFunc = createNestedMultiFunction();
|
|
var result2 = nestedFunc(5);
|
|
assert(result2 == 38, "Nested multi-statement functions should work"); // ((5+10)*2+3)+5 = 38
|
|
print(" Nested multi-statement function result: " + toString(result2));
|
|
|
|
print("Multi-statement function execution: PASS");
|
|
|
|
// ========================================
|
|
// TEST 46: WHILE LOOPS
|
|
// ========================================
|
|
print("\n--- Test 46: While Loops ---");
|
|
|
|
// Basic while loop
|
|
var counter = 0;
|
|
while (counter < 5) {
|
|
counter = counter + 1;
|
|
}
|
|
assert(counter == 5, "Basic while loop should increment counter to 5");
|
|
print(" Basic while loop: PASS");
|
|
|
|
// While loop with break (using return)
|
|
func countToThree() {
|
|
var i = 0;
|
|
while (true) {
|
|
i = i + 1;
|
|
if (i > 3) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
assert(countToThree() == 4, "While loop with return should work");
|
|
print(" While loop with return: PASS");
|
|
|
|
// While loop with condition
|
|
var sum = 0;
|
|
var num = 1;
|
|
while (num <= 10) {
|
|
sum = sum + num;
|
|
num = num + 1;
|
|
}
|
|
assert(sum == 55, "While loop should sum numbers 1 to 10");
|
|
print(" While loop summation: PASS");
|
|
|
|
// Nested while loops
|
|
var outer = 0;
|
|
var inner = 0;
|
|
while (outer < 3) {
|
|
inner = 0;
|
|
while (inner < 2) {
|
|
inner = inner + 1;
|
|
}
|
|
outer = outer + 1;
|
|
}
|
|
assert(outer == 3, "Nested while loops should work");
|
|
assert(inner == 2, "Inner loop should complete");
|
|
print(" Nested while loops: PASS");
|
|
|
|
// While loop with false condition (should not execute)
|
|
var neverExecuted = 0;
|
|
while (false) {
|
|
neverExecuted = neverExecuted + 1;
|
|
}
|
|
assert(neverExecuted == 0, "While loop with false condition should not execute");
|
|
print(" While loop with false condition: PASS");
|
|
|
|
// While loop with complex condition
|
|
var x = 10;
|
|
var y = 0;
|
|
while (x > 0 && y < 5) {
|
|
x = x - 1;
|
|
y = y + 1;
|
|
}
|
|
assert(x == 5, "Complex condition while loop should work");
|
|
assert(y == 5, "Complex condition while loop should work");
|
|
print(" While loop with complex condition: PASS");
|
|
|
|
print("While loops: PASS");
|
|
|
|
// ========================================
|
|
// TEST 47: FOR LOOPS
|
|
// ========================================
|
|
print("\n--- Test 47: For Loops ---");
|
|
|
|
// Basic for loop
|
|
var forSum = 0;
|
|
for (var i = 1; i <= 5; i = i + 1) {
|
|
forSum = forSum + i;
|
|
}
|
|
assert(forSum == 15, "Basic for loop should sum 1 to 5");
|
|
print(" Basic for loop: PASS");
|
|
|
|
// For loop with no initializer
|
|
var j = 0;
|
|
for (; j < 3; j = j + 1) {
|
|
// Empty body
|
|
}
|
|
assert(j == 3, "For loop with no initializer should work");
|
|
print(" For loop with no initializer: PASS");
|
|
|
|
// For loop with no condition (infinite loop with break)
|
|
func countToTwo() {
|
|
var k = 0;
|
|
for (; ; k = k + 1) {
|
|
if (k >= 2) {
|
|
return k;
|
|
}
|
|
}
|
|
}
|
|
assert(countToTwo() == 2, "For loop with no condition should work");
|
|
print(" For loop with no condition: PASS");
|
|
|
|
// For loop with no increment
|
|
var m = 0;
|
|
var n = 0;
|
|
for (n = 0; n < 3; ) {
|
|
m = m + 1;
|
|
n = n + 1;
|
|
}
|
|
assert(m == 3, "For loop with no increment should work");
|
|
assert(n == 3, "For loop with no increment should work");
|
|
print(" For loop with no increment: PASS");
|
|
|
|
// Nested for loops
|
|
var total = 0;
|
|
for (var a = 0; a < 2; a = a + 1) {
|
|
for (var b = 0; b < 3; b = b + 1) {
|
|
total = total + 1;
|
|
}
|
|
}
|
|
assert(total == 6, "Nested for loops should work");
|
|
print(" Nested for loops: PASS");
|
|
|
|
// For loop with expression initializer
|
|
var result = 0;
|
|
for (var temp = 2 * 3; temp > 0; temp = temp - 1) {
|
|
result = result + temp;
|
|
}
|
|
assert(result == 21, "For loop with expression initializer should work"); // 6 + 5 + 4 + 3 + 2 + 1 = 21
|
|
print(" For loop with expression initializer: PASS");
|
|
|
|
// For loop with complex increment
|
|
var complexSum = 0;
|
|
for (var i = 0; i < 10; i = i + 2) {
|
|
complexSum = complexSum + i;
|
|
}
|
|
assert(complexSum == 20, "For loop with complex increment should work"); // 0 + 2 + 4 + 6 + 8 = 20
|
|
print(" For loop with complex increment: PASS");
|
|
|
|
// For loop with function calls
|
|
func getNext(i) {
|
|
return i + 1;
|
|
}
|
|
|
|
var funcSum = 0;
|
|
for (var i = 0; i < 4; i = getNext(i)) {
|
|
funcSum = funcSum + i;
|
|
}
|
|
assert(funcSum == 6, "For loop with function calls should work"); // 0 + 1 + 2 + 3 = 6
|
|
print(" For loop with function calls: PASS");
|
|
|
|
print("For loops: PASS");
|
|
|
|
// ========================================
|
|
// TEST 48: CRITICAL LOOP EDGE CASES
|
|
// ========================================
|
|
print("\n--- Test 48: Critical Loop Edge Cases ---");
|
|
|
|
// Edge case 1: Empty loop bodies
|
|
var emptyWhileCounter = 0;
|
|
while (emptyWhileCounter < 3) {
|
|
emptyWhileCounter = emptyWhileCounter + 1;
|
|
}
|
|
assert(emptyWhileCounter == 3, "Empty while loop body should still increment counter");
|
|
|
|
var emptyForCounter = 0;
|
|
for (var i = 0; i < 3; i = i + 1) {
|
|
// Empty body
|
|
}
|
|
assert(i == 3, "Empty for loop body should still increment counter");
|
|
|
|
// Edge case 2: Loops with only break/continue
|
|
var breakOnlyCounter = 0;
|
|
while (true) {
|
|
breakOnlyCounter = breakOnlyCounter + 1;
|
|
if (breakOnlyCounter == 5) {
|
|
break;
|
|
}
|
|
}
|
|
assert(breakOnlyCounter == 5, "Loop with only break should work");
|
|
|
|
var continueOnlyCounter = 0;
|
|
var continueOnlySum = 0;
|
|
for (var j = 0; j < 10; j = j + 1) {
|
|
if (j < 5) {
|
|
continue;
|
|
}
|
|
continueOnlySum = continueOnlySum + j;
|
|
}
|
|
assert(continueOnlySum == 35, "Loop with only continue should sum 5+6+7+8+9=35");
|
|
|
|
// Edge case 3: Nested break/continue with multiple levels
|
|
var nestedBreakLevel1 = 0;
|
|
var nestedBreakLevel2 = 0;
|
|
for (var a = 0; a < 3; a = a + 1) {
|
|
nestedBreakLevel1 = nestedBreakLevel1 + 1;
|
|
for (var b = 0; b < 3; b = b + 1) {
|
|
nestedBreakLevel2 = nestedBreakLevel2 + 1;
|
|
if (a == 1 && b == 1) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
assert(nestedBreakLevel1 == 3, "Nested break should not affect outer loop");
|
|
assert(nestedBreakLevel2 == 8, "Nested break should only break inner loop (3+3+2=8)");
|
|
|
|
// Edge case 4: Loops with function calls that return early
|
|
func earlyReturnFunc(x) {
|
|
if (x == 3) {
|
|
return "early";
|
|
}
|
|
return "normal";
|
|
}
|
|
|
|
var earlyReturnCounter = 0;
|
|
var earlyReturnResults = "";
|
|
for (var k = 0; k < 5; k = k + 1) {
|
|
earlyReturnCounter = earlyReturnCounter + 1;
|
|
earlyReturnResults = earlyReturnResults + earlyReturnFunc(k);
|
|
}
|
|
assert(earlyReturnCounter == 5, "Loop should continue even with early returns in function calls");
|
|
assert(earlyReturnResults == "normalnormalnormalearlynormal", "Function calls with early returns should work in loops");
|
|
|
|
// Edge case 5: Loops with variable shadowing
|
|
var shadowVar = 10;
|
|
for (var shadowVar = 0; shadowVar < 3; shadowVar = shadowVar + 1) {
|
|
// Inner shadowVar shadows outer shadowVar
|
|
}
|
|
assert(shadowVar == 3, "Variable shadowing in for loop should work");
|
|
|
|
var shadowWhileVar = 20;
|
|
var shadowCounter = 0;
|
|
while (shadowCounter < 2) {
|
|
var shadowWhileVar = shadowCounter * 10;
|
|
shadowCounter = shadowCounter + 1;
|
|
}
|
|
assert(shadowWhileVar == 20, "Variable shadowing in while loop should not affect outer scope");
|
|
|
|
// Edge case 6: Loops with return statements in different contexts
|
|
func loopWithReturn() {
|
|
var returnCounter = 0;
|
|
for (var q = 0; q < 10; q = q + 1) {
|
|
returnCounter = returnCounter + 1;
|
|
if (q == 4) {
|
|
return returnCounter;
|
|
}
|
|
}
|
|
return returnCounter;
|
|
}
|
|
assert(loopWithReturn() == 5, "Loop with return should exit function early");
|
|
|
|
// Edge case 7: Loops with nested function definitions
|
|
var nestedFuncCounter = 0;
|
|
for (var r = 0; r < 3; r = r + 1) {
|
|
nestedFuncCounter = nestedFuncCounter + 1;
|
|
func nestedInLoop() {
|
|
return r * 2;
|
|
}
|
|
if (nestedInLoop() == 4) {
|
|
break;
|
|
}
|
|
}
|
|
assert(nestedFuncCounter == 3, "Loop with nested function definitions should work");
|
|
|
|
// Edge case 8: Loops with closures capturing loop variables
|
|
var closureResults = "";
|
|
for (var s = 0; s < 3; s = s + 1) {
|
|
var capturedVar = s;
|
|
func closure() {
|
|
return capturedVar;
|
|
}
|
|
closureResults = closureResults + toString(closure());
|
|
}
|
|
assert(closureResults == "012", "Loops with closures should capture variables correctly");
|
|
|
|
// Edge case 9: Loops with multiple continue statements
|
|
var multiContinueSum = 0;
|
|
for (var t = 0; t < 6; t = t + 1) {
|
|
if (t == 1) {
|
|
continue;
|
|
}
|
|
if (t == 3) {
|
|
continue;
|
|
}
|
|
if (t == 5) {
|
|
continue;
|
|
}
|
|
multiContinueSum = multiContinueSum + t;
|
|
}
|
|
assert(multiContinueSum == 6, "Loop with multiple continue statements should sum 0+2+4=6");
|
|
|
|
// Edge case 10: Loops with break/continue in conditional blocks
|
|
var conditionalBreakCounter = 0;
|
|
for (var p = 0; p < 10; p = p + 1) {
|
|
conditionalBreakCounter = conditionalBreakCounter + 1;
|
|
if (p % 2 == 0) {
|
|
if (p == 6) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (p == 7) {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
assert(conditionalBreakCounter == 7, "Loop with conditional break/continue should work");
|
|
|
|
print("Critical loop edge cases: PASS");
|
|
|
|
// ========================================
|
|
// TEST 49: DO-WHILE LOOPS
|
|
// ========================================
|
|
|
|
// Basic do-while loop
|
|
var i = 0;
|
|
do {
|
|
i = i + 1;
|
|
} while (i < 5);
|
|
assert(i == 5, "Basic do-while loop should increment to 5");
|
|
|
|
// Do-while with break
|
|
var j = 0;
|
|
do {
|
|
j = j + 1;
|
|
if (j == 3) {
|
|
break;
|
|
}
|
|
} while (j < 10);
|
|
assert(j == 3, "Do-while with break should stop at 3");
|
|
|
|
// Do-while with continue
|
|
var k = 0;
|
|
var sum = 0;
|
|
do {
|
|
k = k + 1;
|
|
if (k == 2) {
|
|
continue;
|
|
}
|
|
sum = sum + k;
|
|
} while (k < 5);
|
|
assert(sum == 13, "Do-while with continue should sum 1+3+4+5=13");
|
|
|
|
// Do-while with return in function
|
|
func doWhileReturn() {
|
|
var x = 0;
|
|
do {
|
|
x = x + 1;
|
|
if (x == 3) {
|
|
return x;
|
|
}
|
|
} while (x < 10);
|
|
return 0;
|
|
}
|
|
assert(doWhileReturn() == 3, "Do-while with return should return 3");
|
|
|
|
// Nested do-while loops
|
|
var outer = 0;
|
|
var inner = 0;
|
|
do {
|
|
outer = outer + 1;
|
|
inner = 0;
|
|
do {
|
|
inner = inner + 1;
|
|
} while (inner < 3);
|
|
} while (outer < 2);
|
|
assert(outer == 2, "Nested do-while outer should be 2");
|
|
assert(inner == 3, "Nested do-while inner should be 3");
|
|
|
|
// Do-while with complex condition
|
|
var a = 0;
|
|
var b = 5;
|
|
do {
|
|
a = a + 1;
|
|
b = b - 1;
|
|
} while (a < b);
|
|
assert(a == 3, "Do-while with complex condition a should be 3");
|
|
assert(b == 2, "Do-while with complex condition b should be 2");
|
|
|
|
// Do-while with function call in condition
|
|
func getValue() {
|
|
return 3;
|
|
}
|
|
|
|
var counter = 0;
|
|
do {
|
|
counter = counter + 1;
|
|
} while (counter < getValue());
|
|
assert(counter == 3, "Do-while with function call should count to 3");
|
|
|
|
// Do-while with empty body (should still execute once)
|
|
var empty = 0;
|
|
do {
|
|
empty = empty + 1;
|
|
} while (false);
|
|
assert(empty == 1, "Do-while with false condition should execute once");
|
|
|
|
// Do-while with break and continue
|
|
var complex = 0;
|
|
var result = 0;
|
|
do {
|
|
complex = complex + 1;
|
|
if (complex == 1) {
|
|
continue;
|
|
}
|
|
if (complex == 4) {
|
|
break;
|
|
}
|
|
result = result + complex;
|
|
} while (complex < 10);
|
|
assert(result == 5, "Do-while with break and continue should sum 2+3=5");
|
|
|
|
print("Do-while loops: PASS");
|
|
|
|
// ========================================
|
|
// TEST 50: TERNARY OPERATOR
|
|
// ========================================
|
|
|
|
// Basic ternary operator
|
|
var result1 = true ? 42 : 10;
|
|
assert(result1 == 42, "Basic ternary with true condition");
|
|
|
|
var result2 = false ? 42 : 10;
|
|
assert(result2 == 10, "Basic ternary with false condition");
|
|
|
|
// Ternary with expressions
|
|
var x = 5;
|
|
var y = 10;
|
|
var result3 = x > y ? "x is greater" : "y is greater";
|
|
assert(result3 == "y is greater", "Ternary with comparison expression");
|
|
|
|
// Ternary with function calls
|
|
func getValue() {
|
|
return 100;
|
|
}
|
|
|
|
func getOtherValue() {
|
|
return 200;
|
|
}
|
|
|
|
var result4 = x < y ? getValue() : getOtherValue();
|
|
assert(result4 == 100, "Ternary with function calls");
|
|
|
|
// Ternary with nested expressions
|
|
var result5 = x == 5 ? (y == 10 ? "both true" : "x true, y false") : "x false";
|
|
assert(result5 == "both true", "Nested ternary expressions");
|
|
|
|
// Ternary with different types
|
|
var result6 = true ? "string" : 42;
|
|
assert(result6 == "string", "Ternary with different types (string)");
|
|
|
|
var result7 = false ? "string" : 42;
|
|
assert(result7 == 42, "Ternary with different types (number)");
|
|
|
|
// Ternary with boolean expressions
|
|
var result8 = x > 0 && y > 0 ? "both positive" : "not both positive";
|
|
assert(result8 == "both positive", "Ternary with boolean expression");
|
|
|
|
// Ternary with arithmetic expressions
|
|
var result9 = x + y > 10 ? x * y : x + y;
|
|
assert(result9 == 50, "Ternary with arithmetic expressions");
|
|
|
|
// Ternary with variables
|
|
var a = 1;
|
|
var b = 2;
|
|
var c = 3;
|
|
var result10 = a < b ? c : a;
|
|
assert(result10 == 3, "Ternary with variables");
|
|
|
|
// Ternary with zero and negative values
|
|
var result11 = 0 ? "truthy" : "falsy";
|
|
assert(result11 == "falsy", "Ternary with zero (falsy)");
|
|
|
|
var result12 = -1 ? "truthy" : "falsy";
|
|
assert(result12 == "truthy", "Ternary with negative number (truthy)");
|
|
|
|
// Ternary with empty string
|
|
var result13 = "" ? "truthy" : "falsy";
|
|
assert(result13 == "falsy", "Ternary with empty string (falsy)");
|
|
|
|
// Ternary with none
|
|
var result14 = none ? "truthy" : "falsy";
|
|
assert(result14 == "falsy", "Ternary with none (falsy)");
|
|
|
|
// Ternary in assignment
|
|
var maxValue = x > y ? x : y;
|
|
assert(maxValue == 10, "Ternary in assignment");
|
|
|
|
// Ternary with complex conditions
|
|
var age = 25;
|
|
var status = age >= 18 ? "adult" : "minor";
|
|
assert(status == "adult", "Ternary with complex condition");
|
|
|
|
// Ternary with string concatenation
|
|
var message = x > 3 ? "x is " + toString(x) : "x is small";
|
|
assert(message == "x is 5", "Ternary with string concatenation");
|
|
|
|
// Ternary with multiple operators
|
|
var result15 = x > 0 && y > 0 && x < y ? "valid range" : "invalid range";
|
|
assert(result15 == "valid range", "Ternary with multiple operators");
|
|
|
|
print("Ternary operator: PASS");
|
|
|
|
// ========================================
|
|
// TEST 50: ARRAYS
|
|
// ========================================
|
|
print("\n--- Test 50: Arrays ---");
|
|
|
|
// Array creation
|
|
var emptyArray = [];
|
|
assert(emptyArray.len() == 0, "Empty array length");
|
|
|
|
var numberArray = [1, 2, 3, 4, 5];
|
|
assert(numberArray.len() == 5, "Number array length");
|
|
assert(numberArray[0] == 1, "Array indexing - first element");
|
|
assert(numberArray[4] == 5, "Array indexing - last element");
|
|
|
|
var mixedArray = [1, "hello", true, 3.14];
|
|
assert(mixedArray.len() == 4, "Mixed array length");
|
|
assert(mixedArray[0] == 1, "Mixed array - number");
|
|
assert(mixedArray[1] == "hello", "Mixed array - string");
|
|
assert(mixedArray[2] == true, "Mixed array - boolean");
|
|
assert(mixedArray[3] == 3.14, "Mixed array - float");
|
|
|
|
// Array assignment
|
|
numberArray[2] = 99;
|
|
assert(numberArray[2] == 99, "Array assignment");
|
|
|
|
mixedArray[1] = "world";
|
|
assert(mixedArray[1] == "world", "Array string assignment");
|
|
|
|
// Array operations
|
|
var testArray = [1, 2, 3];
|
|
testArray.push(4);
|
|
assert(testArray.len() == 4, "Array push - length");
|
|
assert(testArray[3] == 4, "Array push - value");
|
|
|
|
var poppedValue = testArray.pop();
|
|
assert(poppedValue == 4, "Array pop - returned value");
|
|
assert(testArray.len() == 3, "Array pop - length");
|
|
|
|
// Array with nested arrays
|
|
var nestedArray = [[1, 2], [3, 4], [5, 6]];
|
|
assert(nestedArray.len() == 3, "Nested array length");
|
|
assert(nestedArray[0][0] == 1, "Nested array indexing");
|
|
|
|
// Array with function calls
|
|
var funcArray = [func() { return 42; }, func() { return "hello"; }];
|
|
assert(funcArray.len() == 2, "Function array length");
|
|
assert(funcArray[0]() == 42, "Function array - first function");
|
|
assert(funcArray[1]() == "hello", "Function array - second function");
|
|
|
|
// Array edge cases
|
|
var singleElement = [42];
|
|
assert(singleElement.len() == 1, "Single element array");
|
|
assert(singleElement[0] == 42, "Single element access");
|
|
|
|
var largeArray = [];
|
|
for (var i = 0; i < 100; i = i + 1) {
|
|
largeArray.push(i);
|
|
}
|
|
assert(largeArray.len() == 100, "Large array creation");
|
|
assert(largeArray[50] == 50, "Large array access");
|
|
|
|
print("Arrays: PASS");
|
|
|
|
// ========================================
|
|
// TEST 51: ARRAY BUILT-IN FUNCTIONS
|
|
// ========================================
|
|
print("\n--- Test 51: Array Built-in Functions ---");
|
|
|
|
// len() function
|
|
var testLenArray = [1, 2, 3, 4, 5];
|
|
assert(testLenArray.len() == 5, "len() with array");
|
|
|
|
var emptyLenArray = [];
|
|
assert(emptyLenArray.len() == 0, "len() with empty array");
|
|
|
|
// len() with strings
|
|
assert("hello".len() == 5, "len() with string");
|
|
assert("".len() == 0, "len() with empty string");
|
|
|
|
// push() function
|
|
var pushArray = [1, 2, 3];
|
|
pushArray.push(4);
|
|
assert(pushArray.len() == 4, "push() - length check");
|
|
assert(pushArray[3] == 4, "push() - value check");
|
|
|
|
pushArray.push("hello");
|
|
assert(pushArray.len() == 5, "push() - mixed types");
|
|
assert(pushArray[4] == "hello", "push() - string value");
|
|
|
|
// pop() function
|
|
var popArray = [1, 2, 3, 4];
|
|
var popped1 = popArray.pop();
|
|
assert(popped1 == 4, "pop() - returned value");
|
|
assert(popArray.len() == 3, "pop() - length after pop");
|
|
|
|
var popped2 = popArray.pop();
|
|
assert(popped2 == 3, "pop() - second pop");
|
|
assert(popArray.len() == 2, "pop() - length after second pop");
|
|
|
|
// pop() edge cases
|
|
var singlePopArray = [42];
|
|
var singlePopped = singlePopArray.pop();
|
|
assert(singlePopped == 42, "pop() - single element");
|
|
assert(singlePopArray.len() == 0, "pop() - empty after single pop");
|
|
|
|
print("Array built-in functions: PASS");
|
|
|
|
// ========================================
|
|
// TEST 52: NEW BUILT-IN FUNCTIONS
|
|
// ========================================
|
|
print("\n--- Test 52: New Built-in Functions ---");
|
|
|
|
// sleep() function
|
|
import time as T;
|
|
var startTime = T.now();
|
|
T.sleep(0.01); // Sleep briefly to ensure elapsed time
|
|
var endTime = T.now();
|
|
assert(endTime > startTime, "sleep() - time elapsed");
|
|
|
|
// random() function - test proper seeding
|
|
import rand as R;
|
|
var random1 = R.random();
|
|
var random2 = R.random();
|
|
var random3 = R.random();
|
|
assert(random1 >= 0 && random1 <= 1, "random() - range check 1");
|
|
assert(random2 >= 0 && random2 <= 1, "random() - range check 2");
|
|
assert(random3 >= 0 && random3 <= 1, "random() - range check 3");
|
|
// Test that random numbers are different (proper seeding)
|
|
assert(random1 != random2 || random2 != random3 || random1 != random3, "random() - different values");
|
|
|
|
// Test random number generation in different ranges
|
|
var randomRange1 = R.random() * 10;
|
|
var randomRange2 = R.random() * 100;
|
|
assert(randomRange1 >= 0 && randomRange1 <= 10, "random() - range 0-10");
|
|
assert(randomRange2 >= 0 && randomRange2 <= 100, "random() - range 0-100");
|
|
|
|
// eval() function (now via eval module)
|
|
import eval as E;
|
|
E.eval("var evalVar = 42;");
|
|
assert(evalVar == 42, "eval() - variable creation");
|
|
|
|
E.eval("print(\"eval test\");"); // Should print "eval test"
|
|
|
|
var evalResult = E.eval("2 + 2;");
|
|
// eval() currently returns none, so we just test it doesn't crash
|
|
|
|
// Test eval with complex expressions
|
|
E.eval("var complexVar = [1, 2, 3];");
|
|
assert(complexVar.len() == 3, "eval() - complex expression");
|
|
|
|
// Test eval with function definitions
|
|
E.eval("func evalFunc(x) { return x * 2; }");
|
|
assert(evalFunc(5) == 10, "eval() - function definition");
|
|
|
|
print("New built-in functions: PASS");
|
|
|
|
// Module tests
|
|
import io as IO;
|
|
var p1 = IO.exists("tests/test_path.bob") ? "tests/test_path.bob" : "../tests/test_path.bob";
|
|
E.evalFile(p1);
|
|
var p2 = IO.exists("tests/test_base64.bob") ? "tests/test_base64.bob" : "../tests/test_base64.bob";
|
|
E.evalFile(p2);
|
|
var p3 = IO.exists("tests/test_math.bob") ? "tests/test_math.bob" : "../tests/test_math.bob";
|
|
E.evalFile(p3);
|
|
var p4 = IO.exists("tests/test_rand.bob") ? "tests/test_rand.bob" : "../tests/test_rand.bob";
|
|
E.evalFile(p4);
|
|
var p5 = IO.exists("tests/test_time.bob") ? "tests/test_time.bob" : "../tests/test_time.bob";
|
|
E.evalFile(p5);
|
|
|
|
// ========================================
|
|
// TEST 52.5: EXIT FUNCTION
|
|
// ========================================
|
|
print("\n--- Test 52.5: Exit Function ---");
|
|
|
|
// Test exit function (we'll test it doesn't crash, but won't actually exit)
|
|
// Note: We can't test the actual exit behavior without terminating the test suite
|
|
print(" exit() function available (tested by not crashing)");
|
|
|
|
// Test exit with different codes
|
|
// exit(0); // Would exit with success
|
|
// exit(1); // Would exit with error
|
|
// exit(42); // Would exit with custom code
|
|
|
|
print("Exit function: PASS");
|
|
|
|
// ========================================
|
|
// TEST 52.6: ENHANCED DICTIONARY TESTS
|
|
// ========================================
|
|
print("\n--- Test 52.6: Enhanced Dictionary Tests ---");
|
|
|
|
// Test dictionary with none values
|
|
var dictWithNone = {"name": "Bob", "age": none, "city": "SF"};
|
|
assert(dictWithNone.has("name"), "Dictionary has() - existing key");
|
|
assert(dictWithNone.has("age"), "Dictionary has() - none value");
|
|
assert(!dictWithNone.has("phone"), "Dictionary has() - missing key");
|
|
|
|
// Test setting keys to none
|
|
dictWithNone["age"] = none;
|
|
assert(dictWithNone["age"] == none, "Dictionary - setting key to none");
|
|
|
|
// Test dictionary with all none values
|
|
var allNoneDict = {"a": none, "b": none, "c": none};
|
|
var allKeys = ({"a": none, "b": none, "c": none}).keys();
|
|
var allValues = ({"a": none, "b": none, "c": none}).values();
|
|
assert(allKeys.len() == 3, "Dictionary - all none keys count");
|
|
assert(allValues.len() == 3, "Dictionary - all none values count");
|
|
|
|
// Test dictionary stress test
|
|
var stressDict = {};
|
|
for (var i = 0; i < 100; i = i + 1) {
|
|
stressDict["key" + toString(i)] = i;
|
|
}
|
|
assert(stressDict.keys().len() == 100, "Dictionary stress test - keys");
|
|
assert(stressDict.values().len() == 100, "Dictionary stress test - values");
|
|
|
|
print("Enhanced dictionary tests: PASS");
|
|
|
|
// ========================================
|
|
// TEST 52.7: DOT NOTATION AND PROPERTY ACCESS
|
|
// ========================================
|
|
print("\n--- Test 52.7: Dot Notation and Property Access ---");
|
|
|
|
// Basic dictionary property access (read)
|
|
var person = {"name": "Alice", "age": 30, "city": "NYC"};
|
|
assert(person.name == "Alice", "Basic dict property access - name");
|
|
assert(person.age == 30, "Basic dict property access - age");
|
|
assert(person.city == "NYC", "Basic dict property access - city");
|
|
print(" Basic dict property access: PASS");
|
|
|
|
// Dictionary property assignment (write)
|
|
var config = {"theme": "light", "lang": "en"};
|
|
config.theme = "dark";
|
|
config.lang = "es";
|
|
config.fontSize = 16; // New property
|
|
assert(config.theme == "dark", "Dict property assignment - theme");
|
|
assert(config.lang == "es", "Dict property assignment - lang");
|
|
assert(config.fontSize == 16, "Dict property assignment - new property");
|
|
print(" Dict property assignment: PASS");
|
|
|
|
// Array properties (read-only)
|
|
var arr = [10, 20, 30, 40, 50];
|
|
assert(arr.length == 5, "Array length property");
|
|
assert(arr.first == 10, "Array first property");
|
|
assert(arr.last == 50, "Array last property");
|
|
assert(arr.empty == false, "Array empty property");
|
|
print(" Array properties: PASS");
|
|
|
|
// Array edge cases
|
|
var emptyArr = [];
|
|
assert(emptyArr.length == 0, "Empty array length");
|
|
assert(emptyArr.first == none, "Empty array first");
|
|
assert(emptyArr.last == none, "Empty array last");
|
|
assert(emptyArr.empty == true, "Empty array empty");
|
|
print(" Array edge cases: PASS");
|
|
|
|
// Dictionary builtin properties
|
|
var dictWithProps = {"a": 1, "b": 2, "c": 3};
|
|
assert(dictWithProps.length == 3, "Dict builtin length property");
|
|
assert(dictWithProps.empty == false, "Dict builtin empty property");
|
|
var emptyDict = {};
|
|
assert(emptyDict.length == 0, "Empty dict length");
|
|
assert(emptyDict.empty == true, "Empty dict empty");
|
|
|
|
// Test dict.keys and dict.values properties
|
|
assert(dictWithProps.keys.len() == 3, "Dict keys property length");
|
|
assert(dictWithProps.values.len() == 3, "Dict values property length");
|
|
assert(emptyDict.keys.len() == 0, "Empty dict keys length");
|
|
assert(emptyDict.values.len() == 0, "Empty dict values length");
|
|
|
|
// Test equivalence with old functions
|
|
var testDict = {"x": 10, "y": 20};
|
|
assert(testDict.keys.len() == testDict.keys.len(), "Dict keys property works");
|
|
assert(testDict.values.len() == testDict.values.len(), "Dict values property works");
|
|
print(" Dict builtin properties: PASS");
|
|
|
|
// Nested property access and assignment
|
|
var nested = {
|
|
"database": {
|
|
"host": "localhost",
|
|
"port": 5432
|
|
}
|
|
};
|
|
assert(nested.database.host == "localhost", "Nested property access");
|
|
nested.database.port = 3306;
|
|
nested.database.ssl = true; // New nested property
|
|
assert(nested.database.port == 3306, "Nested property assignment");
|
|
assert(nested.database.ssl == true, "New nested property assignment");
|
|
print(" Nested properties: PASS");
|
|
|
|
// Property/bracket equivalence
|
|
assert(person.name == person["name"], "Property/bracket equivalence - name");
|
|
assert(config.theme == config["theme"], "Property/bracket equivalence - theme");
|
|
print(" Property/bracket equivalence: PASS");
|
|
|
|
print("Dot notation and property access: PASS");
|
|
|
|
// ========================================
|
|
// TEST 52.8: TAIL CALL OPTIMIZATION
|
|
// ========================================
|
|
print("\n--- Test 52.8: Tail Call Optimization ---");
|
|
|
|
// Test deep recursion that would stack overflow without TCO
|
|
func factorial(n, acc) {
|
|
if (n <= 1) {
|
|
return acc;
|
|
}
|
|
return factorial(n - 1, n * acc);
|
|
}
|
|
|
|
// Test with large number (would cause stack overflow without TCO)
|
|
var factResult = factorial(100, 1);
|
|
assert(factResult > 0, "TCO - factorial with large number");
|
|
|
|
// Test mutual recursion
|
|
func isEven(n) {
|
|
if (n == 0) return true;
|
|
if (n == 1) return false;
|
|
return isOdd(n - 1);
|
|
}
|
|
|
|
func isOdd(n) {
|
|
if (n == 0) return false;
|
|
if (n == 1) return true;
|
|
return isEven(n - 1);
|
|
}
|
|
|
|
assert(isEven(1000), "TCO - mutual recursion even");
|
|
assert(!isEven(1001), "TCO - mutual recursion odd");
|
|
assert(!isOdd(1000), "TCO - mutual recursion not odd");
|
|
assert(isOdd(1001), "TCO - mutual recursion is odd");
|
|
|
|
print("Tail call optimization: PASS");
|
|
|
|
// ========================================
|
|
// TEST 52.8: MEMORY MANAGEMENT
|
|
// ========================================
|
|
print("\n--- Test 52.8: Memory Management ---");
|
|
|
|
// Test large object creation and cleanup
|
|
for (var i = 0; i < 1000; i = i + 1) {
|
|
var largeArray = [];
|
|
for (var j = 0; j < 100; j = j + 1) {
|
|
largeArray.push("string" + toString(j));
|
|
}
|
|
|
|
var largeDict = {};
|
|
for (var k = 0; k < 100; k = k + 1) {
|
|
largeDict["key" + toString(k)] = "value" + toString(k);
|
|
}
|
|
}
|
|
|
|
// Test function cleanup
|
|
for (var i = 0; i < 1000; i = i + 1) {
|
|
func tempFunc(x) {
|
|
return x * 2;
|
|
}
|
|
var result = tempFunc(i);
|
|
assert(result == i * 2, "Memory management - function creation");
|
|
}
|
|
|
|
// Test thunk cleanup (TCO creates thunks)
|
|
func recursiveFunc(n) {
|
|
if (n <= 0) return 0;
|
|
return recursiveFunc(n - 1) + 1;
|
|
}
|
|
|
|
for (var i = 0; i < 100; i = i + 1) {
|
|
var result = recursiveFunc(100);
|
|
assert(result == 100, "Memory management - thunk cleanup");
|
|
}
|
|
|
|
print("Memory management: PASS");
|
|
|
|
// ========================================
|
|
// TEST 52.9: ERROR HANDLING IMPROVEMENTS
|
|
// ========================================
|
|
print("\n--- Test 52.9: Error Handling Improvements ---");
|
|
|
|
// Test that error messages are informative
|
|
// Note: We can't easily test error messages without causing errors,
|
|
// but we can test that the error system doesn't crash
|
|
|
|
// Test that undefined variables give proper errors
|
|
// var undefinedVar; // This would cause an error, which is expected
|
|
|
|
// Test that invalid operations give proper errors
|
|
// var invalidOp = 5 + "hello"; // This would cause an error, which is expected
|
|
|
|
// Test that the error reporter system works
|
|
print(" Error handling system available (tested by not crashing)");
|
|
|
|
print("Error handling improvements: PASS");
|
|
|
|
// ========================================
|
|
// TEST 52.10: INTERACTIVE MODE FEATURES
|
|
// ========================================
|
|
print("\n--- Test 52.10: Interactive Mode Features ---");
|
|
|
|
// Test that the language works in both file and interactive modes
|
|
// This is tested by the fact that we can run this test file
|
|
|
|
// Test that error reporting works in both modes
|
|
print(" Interactive mode features available (tested by not crashing)");
|
|
|
|
print("Interactive mode features: PASS");
|
|
|
|
// ========================================
|
|
// TEST 53: ARRAY ERROR HANDLING
|
|
// ========================================
|
|
print("\n--- Test 53: Array Error Handling ---");
|
|
|
|
var errorArray = [1, 2, 3];
|
|
|
|
// Test array bounds checking
|
|
// Note: These would cause runtime errors in the actual implementation
|
|
// For now, we test that the array operations work correctly
|
|
assert(errorArray.len() == 3, "Array bounds - valid length");
|
|
|
|
// Test with valid indices
|
|
assert(errorArray[0] == 1, "Array bounds - valid index 0");
|
|
assert(errorArray[2] == 3, "Array bounds - valid index 2");
|
|
|
|
print("Array error handling: PASS");
|
|
|
|
// ========================================
|
|
// TEST 54: ARRAY PERFORMANCE
|
|
// ========================================
|
|
print("\n--- Test 54: Array Performance ---");
|
|
|
|
// Test large array operations
|
|
var perfArray = [];
|
|
import time as T; var startTime = T.now();
|
|
|
|
// Create large array
|
|
for (var i = 0; i < 1000; i = i + 1) {
|
|
perfArray.push(i);
|
|
}
|
|
|
|
var midTime = T.now();
|
|
assert(perfArray.len() == 1000, "Array performance - creation");
|
|
|
|
// Access elements
|
|
for (var j = 0; j < 100; j = j + 1) {
|
|
var value = perfArray[j * 10];
|
|
assert(value == j * 10, "Array performance - access");
|
|
}
|
|
|
|
var endTime = T.now();
|
|
assert(endTime > startTime, "Array performance - time check");
|
|
|
|
print("Array performance: PASS");
|
|
|
|
// ========================================
|
|
// TEST 55: ARRAY WITH FUNCTIONS
|
|
// ========================================
|
|
print("\n--- Test 55: Array with Functions ---");
|
|
|
|
// Array of functions
|
|
var funcArray2 = [
|
|
func() { return 1; },
|
|
func() { return 2; },
|
|
func() { return 3; }
|
|
];
|
|
|
|
assert(funcArray2.len() == 3, "Function array length");
|
|
assert(funcArray2[0]() == 1, "Function array - call 1");
|
|
assert(funcArray2[1]() == 2, "Function array - call 2");
|
|
assert(funcArray2[2]() == 3, "Function array - call 3");
|
|
|
|
// Function that returns array
|
|
func createArray() {
|
|
return [1, 2, 3, 4, 5];
|
|
}
|
|
|
|
var returnedArray = createArray();
|
|
assert(returnedArray.len() == 5, "Function returning array");
|
|
assert(returnedArray[0] == 1, "Function returning array - first element");
|
|
|
|
// Function that modifies array
|
|
func modifyArray(arr) {
|
|
arr.push(999);
|
|
return arr;
|
|
}
|
|
|
|
var modArray = [1, 2, 3];
|
|
var modifiedArray = modifyArray(modArray);
|
|
assert(modifiedArray.len() == 4, "Function modifying array");
|
|
assert(modifiedArray[3] == 999, "Function modifying array - new value");
|
|
|
|
print("Array with functions: PASS");
|
|
|
|
// ========================================
|
|
// TEST 56: ARRAY EDGE CASES AND ADVANCED FEATURES
|
|
// ========================================
|
|
print("\n--- Test 56: Array Edge Cases and Advanced Features ---");
|
|
|
|
// Array with none values
|
|
var noneArray = [1, none, 3, none, 5];
|
|
assert(noneArray.len() == 5, "Array with none values - length");
|
|
// Note: Bob doesn't support comparing none values with ==
|
|
// We can test that the array contains the expected number of elements
|
|
var noneCount = 0;
|
|
for (var i = 0; i < noneArray.len(); i = i + 1) {
|
|
if (type(noneArray[i]) == "none") {
|
|
noneCount = noneCount + 1;
|
|
}
|
|
}
|
|
assert(noneCount == 2, "Array with none values - none count");
|
|
|
|
// Array with complex expressions
|
|
var complexArray = [1 + 1, 2 * 3, 10 / 2, 5 - 2];
|
|
assert(complexArray.len() == 4, "Complex array - length");
|
|
assert(complexArray[0] == 2, "Complex array - addition");
|
|
assert(complexArray[1] == 6, "Complex array - multiplication");
|
|
assert(complexArray[2] == 5, "Complex array - division");
|
|
assert(complexArray[3] == 3, "Complex array - subtraction");
|
|
|
|
// Array with string operations
|
|
var stringArray = ["hello" + " world", "test" * 2, "a" + "b" + "c"];
|
|
assert(stringArray.len() == 3, "String array - length");
|
|
assert(stringArray[0] == "hello world", "String array - concatenation");
|
|
assert(stringArray[1] == "testtest", "String array - multiplication");
|
|
assert(stringArray[2] == "abc", "String array - multiple concatenation");
|
|
|
|
// Array with function results
|
|
func getValue() { return 42; }
|
|
func getString() { return "hello"; }
|
|
|
|
var funcResultArray = [getValue(), getString(), 1 + 2];
|
|
assert(funcResultArray.len() == 3, "Function result array - length");
|
|
assert(funcResultArray[0] == 42, "Function result array - function call");
|
|
assert(funcResultArray[1] == "hello", "Function result array - string function");
|
|
assert(funcResultArray[2] == 3, "Function result array - expression");
|
|
|
|
// Array with ternary operators
|
|
var ternaryArray = [true ? 1 : 0, false ? "yes" : "no", 5 > 3 ? "big" : "small"];
|
|
assert(ternaryArray.len() == 3, "Ternary array - length");
|
|
assert(ternaryArray[0] == 1, "Ternary array - true condition");
|
|
assert(ternaryArray[1] == "no", "Ternary array - false condition");
|
|
assert(ternaryArray[2] == "big", "Ternary array - comparison condition");
|
|
|
|
// Array with nested arrays and operations
|
|
var nestedOpArray = [[1, 2], [3, 4], [5, 6]];
|
|
nestedOpArray[0][0] = 99;
|
|
assert(nestedOpArray[0][0] == 99, "Nested array operations - assignment");
|
|
|
|
// Array with push/pop in expressions
|
|
var exprArray = [1, 2, 3];
|
|
var pushResult = exprArray.push(4);
|
|
assert(exprArray.len() == 4, "Array push in expression");
|
|
assert(exprArray[3] == 4, "Array push result");
|
|
|
|
var popResult = exprArray.pop();
|
|
assert(popResult == 4, "Array pop result");
|
|
assert(exprArray.len() == 3, "Array length after pop");
|
|
|
|
print("Array edge cases and advanced features: PASS");
|
|
|
|
// ========================================
|
|
// TEST 57: ARRAY STRESS TESTING
|
|
// ========================================
|
|
print("\n--- Test 57: Array Stress Testing ---");
|
|
|
|
// Large array creation and manipulation
|
|
var stressArray = [];
|
|
import time as T2; var startTime = T2.now();
|
|
|
|
// Create large array with mixed types
|
|
for (var i = 0; i < 500; i = i + 1) {
|
|
if (i % 3 == 0) {
|
|
stressArray.push(i);
|
|
} else if (i % 3 == 1) {
|
|
stressArray.push("string" + toString(i));
|
|
} else {
|
|
stressArray.push(i > 250);
|
|
}
|
|
}
|
|
|
|
var midTime = T2.now();
|
|
assert(stressArray.len() == 500, "Stress test - array creation");
|
|
|
|
// Access and modify elements
|
|
for (var j = 0; j < 100; j = j + 1) {
|
|
var index = j * 5;
|
|
if (index < stressArray.len()) {
|
|
stressArray[index] = "modified" + toString(j);
|
|
}
|
|
}
|
|
|
|
var endTime = T2.now();
|
|
assert(endTime > startTime, "Stress test - time validation");
|
|
|
|
// Verify modifications
|
|
assert(stressArray[0] == "modified0", "Stress test - modification verification");
|
|
assert(stressArray[5] == "modified1", "Stress test - modification verification 2");
|
|
|
|
print("Array stress testing: PASS");
|
|
|
|
// ========================================
|
|
// ARRAY INCREMENT/DECREMENT
|
|
// ========================================
|
|
print("\n--- Test 58: Array Increment/Decrement ---");
|
|
var arr = [1, 2, 3, 4, 5];
|
|
print("Original array: " + arr);
|
|
|
|
// Test postfix increment
|
|
arr[0]++;
|
|
assert(arr[0] == 2, "Postfix increment failed");
|
|
|
|
// Test prefix increment
|
|
++arr[1];
|
|
assert(arr[1] == 3, "Prefix increment failed");
|
|
|
|
// Test postfix decrement
|
|
arr[2]--;
|
|
assert(arr[2] == 2, "Postfix decrement failed");
|
|
|
|
// Test prefix decrement
|
|
--arr[3];
|
|
assert(arr[3] == 3, "Prefix decrement failed");
|
|
|
|
print("Final array: " + arr);
|
|
assert(arr[4] == 5, "Unmodified element changed");
|
|
|
|
print("Array increment/decrement: PASS");
|
|
|
|
// ========================================
|
|
// CROSS-TYPE COMPARISON OPERATORS
|
|
// ========================================
|
|
print("\nTesting cross-type comparison operators...");
|
|
|
|
// Test none comparisons
|
|
var x = none;
|
|
assert(x == none, "none == none should be true");
|
|
assert(none == x, "none == x should be true");
|
|
assert(x != 42, "none != 42 should be true");
|
|
assert(42 != x, "42 != none should be true");
|
|
assert(x != "hello", "none != string should be true");
|
|
assert("hello" != x, "string != none should be true");
|
|
assert(x != true, "none != true should be true");
|
|
assert(true != x, "true != none should be true");
|
|
|
|
// Test number and boolean comparisons
|
|
assert(0 == false, "0 == false should be true");
|
|
assert(false == 0, "false == 0 should be true");
|
|
assert(1 == true, "1 == true should be true");
|
|
assert(true == 1, "true == 1 should be true");
|
|
assert(42 == true, "42 == true should be true");
|
|
assert(true == 42, "true == 42 should be true");
|
|
assert(0 != true, "0 != true should be true");
|
|
assert(true != 0, "true != 0 should be true");
|
|
|
|
// Test array comparisons
|
|
var arr1 = [1, 2, 3];
|
|
var arr2 = [1, 2, 3];
|
|
var arr3 = [1, 2, 4];
|
|
assert(arr1 == arr2, "Identical arrays should be equal");
|
|
assert(arr1 != arr3, "Different arrays should not be equal");
|
|
assert(arr1 != none, "Array != none should be true");
|
|
assert(none != arr1, "none != array should be true");
|
|
|
|
// Test function comparisons
|
|
func testFunc() { return 42; }
|
|
var func1 = testFunc;
|
|
var func2 = testFunc;
|
|
assert(func1 == func2, "Same function should be equal");
|
|
assert(func1 != none, "Function != none should be true");
|
|
assert(none != func1, "none != function should be true");
|
|
|
|
// Test mixed type comparisons that should return false
|
|
assert(42 != "42", "Number != string should be true");
|
|
assert("42" != 42, "String != number should be true");
|
|
assert(true != "true", "Boolean != string should be true");
|
|
assert("true" != true, "String != boolean should be true");
|
|
assert(arr1 != 42, "Array != number should be true");
|
|
assert(42 != arr1, "Number != array should be true");
|
|
|
|
print("Cross-type comparison operators: PASS");
|
|
|
|
// ========================================
|
|
// TEST 59: TOINT FUNCTION
|
|
// ========================================
|
|
print("\n--- Test 59: ToInt Function ---");
|
|
|
|
// Test positive floats
|
|
assert(toInt(3.7) == 3, "toInt(3.7) should be 3");
|
|
assert(toInt(3.2) == 3, "toInt(3.2) should be 3");
|
|
assert(toInt(3.0) == 3, "toInt(3.0) should be 3");
|
|
assert(toInt(3.99) == 3, "toInt(3.99) should be 3");
|
|
|
|
// Test negative floats
|
|
assert(toInt(-3.7) == -3, "toInt(-3.7) should be -3");
|
|
assert(toInt(-3.2) == -3, "toInt(-3.2) should be -3");
|
|
assert(toInt(-3.0) == -3, "toInt(-3.0) should be -3");
|
|
|
|
// Test large numbers
|
|
assert(toInt(123456.789) == 123456, "toInt(123456.789) should be 123456");
|
|
assert(toInt(-123456.789) == -123456, "toInt(-123456.789) should be -123456");
|
|
|
|
// Test zero
|
|
assert(toInt(0.0) == 0, "toInt(0.0) should be 0");
|
|
assert(toInt(-0.0) == 0, "toInt(-0.0) should be 0");
|
|
|
|
// Test with random numbers
|
|
for(var i = 0; i < 5; i++) {
|
|
import rand as Rn;
|
|
var randomFloat = Rn.random() * 10;
|
|
var randomInt = toInt(randomFloat);
|
|
assert(randomInt >= 0 && randomInt <= 9, "toInt(random) should be in range 0-9");
|
|
}
|
|
|
|
print("ToInt function: PASS");
|
|
|
|
// ========================================
|
|
// TEST 60: FLOAT ARRAY INDICES (AUTO-TRUNCATION)
|
|
// ========================================
|
|
print("\n--- Test 60: Float Array Indices (Auto-Truncation) ---");
|
|
|
|
var arr = [10, 20, 30, 40, 50];
|
|
|
|
// Test float indices that auto-truncate
|
|
assert(arr[3.14] == 40, "arr[3.14] should be arr[3] = 40");
|
|
assert(arr[3.99] == 40, "arr[3.99] should be arr[3] = 40");
|
|
assert(arr[2.5] == 30, "arr[2.5] should be arr[2] = 30");
|
|
assert(arr[1.1] == 20, "arr[1.1] should be arr[1] = 20");
|
|
assert(arr[0.9] == 10, "arr[0.9] should be arr[0] = 10");
|
|
|
|
// Test assignment with float indices
|
|
arr[3.14] = 999;
|
|
assert(arr[3] == 999, "arr[3.14] = 999 should set arr[3] = 999");
|
|
|
|
// Test increment/decrement with float indices
|
|
arr[2.5]++;
|
|
assert(arr[2] == 31, "arr[2.5]++ should increment arr[2]");
|
|
|
|
++arr[1.1];
|
|
assert(arr[1] == 21, "++arr[1.1] should increment arr[1]");
|
|
|
|
print("Float array indices (auto-truncation): PASS");
|
|
|
|
// ========================================
|
|
// TEST 61: ENHANCED ERROR REPORTING
|
|
// ========================================
|
|
print("\n--- Test 61: Enhanced Error Reporting ---");
|
|
|
|
// Test that compound assignment errors use correct operator names
|
|
// Note: These tests verify the error messages are descriptive
|
|
// The actual error throwing is tested in the interpreter
|
|
|
|
var testVar = 42;
|
|
|
|
// Test that undefined variables in compound assignment are caught
|
|
// This would throw an error with proper reporting
|
|
// testVar += undefinedVar; // Should use error reporter
|
|
|
|
print("Enhanced error reporting: PASS (manual verification required)");
|
|
|
|
|
|
// Test 67: Copy Behavior - Primitive Types (By Value)
|
|
print("Test 67: Copy Behavior - Primitive Types (By Value)");
|
|
var original_number = 42;
|
|
var copy_number = original_number;
|
|
copy_number = 99;
|
|
assert(original_number == 42);
|
|
assert(copy_number == 99);
|
|
|
|
var original_string = "hello";
|
|
var copy_string = original_string;
|
|
copy_string = "world";
|
|
assert(original_string == "hello");
|
|
assert(copy_string == "world");
|
|
|
|
var original_boolean = true;
|
|
var copy_boolean = original_boolean;
|
|
copy_boolean = false;
|
|
assert(original_boolean == true);
|
|
assert(copy_boolean == false);
|
|
print("Primitive types copy by value test complete");
|
|
|
|
// Test 68: Copy Behavior - Arrays and Dictionaries (By Reference)
|
|
print("Test 68: Copy Behavior - Arrays and Dictionaries (By Reference)");
|
|
var original_array = [1, 2, 3];
|
|
var copy_array = original_array;
|
|
copy_array[0] = 99;
|
|
assert(original_array[0] == 99);
|
|
assert(copy_array[0] == 99);
|
|
|
|
var original_dict = {"a": 1, "b": 2};
|
|
var copy_dict = original_dict;
|
|
copy_dict["a"] = 99;
|
|
assert(original_dict["a"] == 99);
|
|
assert(copy_dict["a"] == 99);
|
|
print("Complex types copy by reference test complete");
|
|
|
|
// Test 69: Copy Behavior - Mixed Types and Nested Structures
|
|
print("Test 69: Copy Behavior - Mixed Types and Nested Structures");
|
|
var mixed = {
|
|
"number": 42,
|
|
"string": "hello",
|
|
"array": [1, 2, 3],
|
|
"dict": {"x": 1}
|
|
};
|
|
var copy_mixed = mixed;
|
|
|
|
// Modify primitive in copy
|
|
copy_mixed["number"] = 99;
|
|
assert(mixed["number"] == 99); // Affects original
|
|
assert(copy_mixed["number"] == 99);
|
|
|
|
// Modify array in copy
|
|
copy_mixed["array"][0] = 999;
|
|
assert(mixed["array"][0] == 999); // Affects original
|
|
assert(copy_mixed["array"][0] == 999);
|
|
|
|
// Modify nested dict in copy
|
|
copy_mixed["dict"]["x"] = 999;
|
|
assert(mixed["dict"]["x"] == 999); // Affects original
|
|
assert(copy_mixed["dict"]["x"] == 999);
|
|
print("Mixed types and nested structures test complete");
|
|
|
|
// Test 70: Copy Behavior - Reassignment Breaks Reference
|
|
print("Test 70: Copy Behavior - Reassignment Breaks Reference");
|
|
var array1 = [1, 2, 3];
|
|
var array2 = array1;
|
|
array1 = [4, 5, 6]; // Reassign the variable
|
|
assert(array1[0] == 4);
|
|
assert(array2[0] == 1); // array2 still points to original
|
|
|
|
var reassign_dict1 = {"a": 1};
|
|
var reassign_dict2 = reassign_dict1;
|
|
reassign_dict1 = {"b": 2};
|
|
assert(reassign_dict1["b"] == 2);
|
|
assert(reassign_dict2["a"] == 1);
|
|
//print("Reassignment breaks reference test complete");
|
|
|
|
// Test 71: Copy Behavior - Function Parameters
|
|
//print("Test 71: Copy Behavior - Function Parameters");
|
|
func testArrayParam(arr) {
|
|
arr[0] = 999;
|
|
return arr[0];
|
|
}
|
|
|
|
func testDictParam(dict) {
|
|
dict["modified"] = true;
|
|
return dict["modified"];
|
|
}
|
|
|
|
var test_arr = [1, 2, 3];
|
|
var test_dict = {"original": true};
|
|
|
|
var result_arr = testArrayParam(test_arr);
|
|
var result_dict = testDictParam(test_dict);
|
|
|
|
assert(test_arr[0] == 999); // Original modified
|
|
assert(test_dict["modified"] == true); // Original modified
|
|
print("Function parameters copy behavior test complete");
|
|
|
|
// ========================================
|
|
// TEST SUMMARY
|
|
// ========================================
|
|
print("\nTest Summary:");
|
|
print("Features tested:");
|
|
print("- Basic data types (strings, numbers, booleans)");
|
|
print("- Arithmetic operations");
|
|
print("- String operations");
|
|
print("- String + Number concatenation (bidirectional)");
|
|
print("- String multiplication");
|
|
print("- Significant digits formatting");
|
|
print("- Escape sequences (\\n, \\t, \\\", \\\\)");
|
|
print("- Comparison operators");
|
|
print("- Variable assignment");
|
|
print("- Functions and return statements");
|
|
print("- Nested function calls");
|
|
print("- Variable scoping");
|
|
print("- Closures");
|
|
print("- Complex expressions");
|
|
print("- Edge cases");
|
|
print("- Print function");
|
|
print("- Assert function");
|
|
print("- Error handling");
|
|
print("- Function passing (13 comprehensive tests)");
|
|
print(" * Basic function passing");
|
|
print(" * Multiple function parameters");
|
|
print(" * Nested function calls");
|
|
print(" * Function composition");
|
|
print(" * Callback patterns");
|
|
print(" * Direct function calling");
|
|
print(" * Function storage and retrieval");
|
|
print(" * Multiple function applications");
|
|
print(" * Edge cases (no params, many params)");
|
|
print(" * Function identity");
|
|
print(" * Constant functions");
|
|
print(" * Function comparison");
|
|
print("- Comprehensive number system");
|
|
print(" * Huge numbers (epoch timestamps)");
|
|
print(" * Decimal precision handling");
|
|
print(" * Binary and hexadecimal numbers");
|
|
print(" * Edge cases and complex expressions");
|
|
print("- Time function (microsecond precision)");
|
|
print("- Boolean + String concatenation");
|
|
print("- Underscore support in variable names");
|
|
print("- If statements (if, else, else if chains)");
|
|
print("- Input function (user input capability)");
|
|
print("- Type function (runtime type checking)");
|
|
print("- toNumber function (string-to-number conversion)");
|
|
print("- toString function (universal string conversion)");
|
|
print("- Enhanced print function (works with all object types)");
|
|
print("- Redefinable functions (including built-in function override)");
|
|
print("- Recursion (factorial, fibonacci, mutual recursion, deep recursion)");
|
|
print("- Logical operators (&&, ||, !) with short-circuit evaluation");
|
|
print("- Bitwise operators (&, |, ^, <<, >>, ~)");
|
|
print("- Compound assignment operators (+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=)");
|
|
print("- Anonymous functions (func(...) { ... })");
|
|
print("- Functions returning functions");
|
|
print("- Operator precedence for all operators");
|
|
print("- Edge cases for all operators");
|
|
print("- Lexer consistency improvements");
|
|
print("- None value concatenation (string + none, none + string)");
|
|
print("- Memory management (variable reassignment, function reassignment, large string cleanup)");
|
|
print("- Multi-statement function execution");
|
|
print("- While loops (basic, nested, complex conditions, return breaks)");
|
|
print("- For loops (basic, nested, missing clauses, complex expressions)");
|
|
print("- Do-while loops (basic, nested, break, continue, return, complex conditions)");
|
|
print("- Critical loop edge cases (10 comprehensive scenarios)");
|
|
print("- Ternary operator (conditional expressions with ? and :)");
|
|
print("- Arrays (creation, indexing, assignment, operations)");
|
|
print("- Array built-in functions (len, push, pop)");
|
|
print("- Enhanced built-in functions (sleep, random, eval, exit)");
|
|
print(" * sleep() with proper timing");
|
|
print(" * random() with proper seeding and range testing");
|
|
print(" * eval() with complex expressions and function definitions");
|
|
print(" * exit() function availability");
|
|
print("- Array error handling and bounds checking");
|
|
print("- Array performance (large arrays, operations)");
|
|
print("- Array with functions (function arrays, functions returning arrays)");
|
|
print("- Array edge cases and advanced features (none values, complex expressions)");
|
|
print("- Array stress testing (large mixed-type arrays)");
|
|
print("- Array increment/decrement operators (++, --) on array elements");
|
|
print("- Cross-type comparison operators (==, !=)");
|
|
print(" * none comparisons (none == none, none != any)");
|
|
print(" * number and boolean comparisons (0 == false, 1 == true)");
|
|
print(" * array comparisons (deep equality)");
|
|
print(" * function comparisons (reference equality)");
|
|
print(" * mixed type comparisons (return false for incompatible types)");
|
|
print("- ToInt function (float-to-integer conversion)");
|
|
print("- Float array indices (auto-truncation like JavaScript/Lua)");
|
|
print("- Enhanced error reporting (correct operator names, error reporter system)");
|
|
print("- Dictionaries (creation, access, assignment, built-in functions)");
|
|
print(" * Dictionary literals with string keys");
|
|
print(" * Dictionary indexing and assignment");
|
|
print(" * Missing key handling (returns none)");
|
|
print(" * Built-in functions (keys, values, has)");
|
|
print(" * Nested dictionaries");
|
|
print(" * Mixed type values");
|
|
print(" * Dictionary stress testing");
|
|
print(" * Dictionary with none values");
|
|
print("- Dot notation and property access");
|
|
print(" * Dictionary property access (obj.prop)");
|
|
print(" * Dictionary property assignment (obj.prop = value)");
|
|
print(" * Nested property access (obj.a.b.c)");
|
|
print(" * Array builtin properties (length, first, last, empty)");
|
|
print(" * Dictionary builtin properties (length, empty, keys, values)");
|
|
print(" * Property/bracket notation equivalence");
|
|
print(" * User property precedence over builtins");
|
|
print("- Copy behavior (by value vs by reference)");
|
|
print(" * Primitive types copied by value (numbers, strings, booleans)");
|
|
print(" * Complex types copied by reference (arrays, dictionaries)");
|
|
print(" * Mixed types and nested structures");
|
|
print(" * Reassignment breaks reference links");
|
|
print(" * Function parameters follow same copy rules");
|
|
print("- Tail Call Optimization (TCO)");
|
|
print(" * Deep recursion without stack overflow");
|
|
print(" * Mutual recursion support");
|
|
print(" * Large factorial calculations");
|
|
print("- Advanced Memory Management");
|
|
print(" * Large object creation and cleanup");
|
|
print(" * Function cleanup");
|
|
print(" * Thunk cleanup (TCO system)");
|
|
print("- Error Handling Improvements");
|
|
print(" * Comprehensive error reporting");
|
|
print(" * Context-aware error messages");
|
|
print("- Interactive Mode Features");
|
|
print(" * REPL functionality");
|
|
print(" * Error reporting in both modes");
|
|
|
|
// Additional Tests: Classes and Extensions
|
|
print("\n--- Additional Tests: Classes and Extensions ---");
|
|
import io as IO; // for file existence checks
|
|
var path1 = IO.exists("tests/test_method_calls.bob") ? "tests/test_method_calls.bob" : "../tests/test_method_calls.bob";
|
|
E.evalFile(path1);
|
|
var path2 = IO.exists("tests/test_class_basic.bob") ? "tests/test_class_basic.bob" : "../tests/test_class_basic.bob";
|
|
E.evalFile(path2);
|
|
var path3 = IO.exists("tests/test_class_with_this.bob") ? "tests/test_class_with_this.bob" : "../tests/test_class_with_this.bob";
|
|
E.evalFile(path3);
|
|
var path4 = IO.exists("tests/test_class_init.bob") ? "tests/test_class_init.bob" : "../tests/test_class_init.bob";
|
|
E.evalFile(path4);
|
|
var path5 = IO.exists("tests/test_class_extension_user.bob") ? "tests/test_class_extension_user.bob" : "../tests/test_class_extension_user.bob";
|
|
E.evalFile(path5);
|
|
var path6 = IO.exists("tests/test_extension_methods.bob") ? "tests/test_extension_methods.bob" : "../tests/test_extension_methods.bob";
|
|
E.evalFile(path6);
|
|
var path7 = IO.exists("tests/test_class_inheritance.bob") ? "tests/test_class_inheritance.bob" : "../tests/test_class_inheritance.bob";
|
|
E.evalFile(path7);
|
|
var path8 = IO.exists("tests/test_classes_comprehensive.bob") ? "tests/test_classes_comprehensive.bob" : "../tests/test_classes_comprehensive.bob";
|
|
E.evalFile(path8);
|
|
var path9 = IO.exists("tests/test_class_super.bob") ? "tests/test_class_super.bob" : "../tests/test_class_super.bob";
|
|
E.evalFile(path9);
|
|
var path10 = IO.exists("tests/test_classes_extensive.bob") ? "tests/test_classes_extensive.bob" : "../tests/test_classes_extensive.bob";
|
|
E.evalFile(path10);
|
|
var path11 = IO.exists("tests/test_class_edge_cases.bob") ? "tests/test_class_edge_cases.bob" : "../tests/test_class_edge_cases.bob";
|
|
E.evalFile(path11);
|
|
var path12 = IO.exists("tests/test_polymorphism.bob") ? "tests/test_polymorphism.bob" : "../tests/test_polymorphism.bob";
|
|
E.evalFile(path12);
|
|
var path13 = IO.exists("tests/test_polymorphism_practical.bob") ? "tests/test_polymorphism_practical.bob" : "../tests/test_polymorphism_practical.bob";
|
|
E.evalFile(path13);
|
|
|
|
var path14 = IO.exists("tests/test_builtin_methods_style.bob") ? "tests/test_builtin_methods_style.bob" : "../tests/test_builtin_methods_style.bob";
|
|
E.evalFile(path14);
|
|
|
|
var path15 = IO.exists("tests/test_try_catch.bob") ? "tests/test_try_catch.bob" : "../tests/test_try_catch.bob";
|
|
E.evalFile(path15);
|
|
var path15a = IO.exists("tests/test_try_catch_runtime.bob") ? "tests/test_try_catch_runtime.bob" : "../tests/test_try_catch_runtime.bob";
|
|
E.evalFile(path15a);
|
|
var path15b = IO.exists("tests/test_try_catch_extensive.bob") ? "tests/test_try_catch_extensive.bob" : "../tests/test_try_catch_extensive.bob";
|
|
E.evalFile(path15b);
|
|
var path15c = IO.exists("tests/test_try_catch_edge_cases2.bob") ? "tests/test_try_catch_edge_cases2.bob" : "../tests/test_try_catch_edge_cases2.bob";
|
|
E.evalFile(path15c);
|
|
var path15d = IO.exists("tests/test_try_catch_cross_function.bob") ? "tests/test_try_catch_cross_function.bob" : "../tests/test_try_catch_cross_function.bob";
|
|
E.evalFile(path15d);
|
|
var path15e = IO.exists("tests/test_try_catch_loop_interactions.bob") ? "tests/test_try_catch_loop_interactions.bob" : "../tests/test_try_catch_loop_interactions.bob";
|
|
E.evalFile(path15e);
|
|
|
|
// Modules: basic imports suite
|
|
var pathMods = IO.exists("tests/test_imports_basic.bob") ? "tests/test_imports_basic.bob" : "../tests/test_imports_basic.bob";
|
|
E.evalFile(pathMods);
|
|
|
|
var pathModsB = IO.exists("tests/test_imports_builtin.bob") ? "tests/test_imports_builtin.bob" : "../tests/test_imports_builtin.bob";
|
|
E.evalFile(pathModsB);
|
|
|
|
var pathOs = IO.exists("tests/test_os_basic.bob") ? "tests/test_os_basic.bob" : "../tests/test_os_basic.bob";
|
|
E.evalFile(pathOs);
|
|
|
|
print("\nAll tests passed.");
|
|
print("Test suite complete."); |