Updated tests and testing built in modules
This commit is contained in:
parent
7f7c6e438d
commit
6e3379b5b8
@ -260,7 +260,7 @@ toInt(3.9); // 3 (global)
|
|||||||
assert(condition, "message"); // Testing
|
assert(condition, "message"); // Testing
|
||||||
time(); // Current time in microseconds
|
time(); // Current time in microseconds
|
||||||
sleep(1.5); // Sleep for 1.5 seconds
|
sleep(1.5); // Sleep for 1.5 seconds
|
||||||
random(); // Random number 0-1
|
rand.random(); // Random number 0-1
|
||||||
eval("print('Hello');"); // Execute string as code
|
eval("print('Hello');"); // Execute string as code
|
||||||
exit(0); // Exit program
|
exit(0); // Exit program
|
||||||
```
|
```
|
||||||
@ -297,7 +297,7 @@ The following built-ins are available by default. Unless specified, functions th
|
|||||||
- fileExists(path): boolean
|
- fileExists(path): boolean
|
||||||
- time(): microseconds since Unix epoch
|
- time(): microseconds since Unix epoch
|
||||||
- sleep(seconds): pauses execution
|
- sleep(seconds): pauses execution
|
||||||
- random(): float in [0,1)
|
- rand.random(): float in [0,1)
|
||||||
- eval(code): executes code string in current environment
|
- eval(code): executes code string in current environment
|
||||||
- exit(code?): terminates the program
|
- exit(code?): terminates the program
|
||||||
|
|
||||||
|
|||||||
@ -56,7 +56,7 @@ Bob is a mature, working programming language with a modern architecture and com
|
|||||||
- **Type System**: `type()`, `toString()`, `toNumber()`, `toInt()`, `toBoolean()`
|
- **Type System**: `type()`, `toString()`, `toNumber()`, `toInt()`, `toBoolean()`
|
||||||
- **Testing**: `assert()` with custom error messages
|
- **Testing**: `assert()` with custom error messages
|
||||||
- **Timing**: `time()` (microsecond precision), `sleep()`
|
- **Timing**: `time()` (microsecond precision), `sleep()`
|
||||||
- **Utility**: `random()` (properly seeded), `eval()`, `exit()`
|
- **Utility**: `rand.random()` (properly seeded), `eval.eval()`, `sys.exit()`
|
||||||
- **Data Structure**: `len()`, `push()`, `pop()`, `keys()`, `values()`, `has()`
|
- **Data Structure**: `len()`, `push()`, `pop()`, `keys()`, `values()`, `has()`
|
||||||
- **File I/O**: `readFile()`, `writeFile()`, `readLines()`, `fileExists()`
|
- **File I/O**: `readFile()`, `writeFile()`, `readLines()`, `fileExists()`
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,7 @@ This extension provides syntax highlighting and language support for the Bob pro
|
|||||||
- `print()`, `assert()`, `input()`, `type()`, `toString()`, `toNumber()`, `toInt()`, `time()`, `sleep()`, `printRaw()`
|
- `print()`, `assert()`, `input()`, `type()`, `toString()`, `toNumber()`, `toInt()`, `time()`, `sleep()`, `printRaw()`
|
||||||
- Arrays/Dictionaries (preferred method style): `arr.len()`, `arr.push(...)`, `arr.pop()`, `dict.len()`, `dict.keys()`, `dict.values()`, `dict.has()`
|
- Arrays/Dictionaries (preferred method style): `arr.len()`, `arr.push(...)`, `arr.pop()`, `dict.len()`, `dict.keys()`, `dict.values()`, `dict.has()`
|
||||||
- Global forms still available: `len(x)`, `push(arr, ...)`, `pop(arr)`, `keys(dict)`, `values(dict)`, `has(dict, key)`
|
- Global forms still available: `len(x)`, `push(arr, ...)`, `pop(arr)`, `keys(dict)`, `values(dict)`, `has(dict, key)`
|
||||||
- Misc: `random()`, `eval()`
|
- Misc: `rand.random()`, `eval.eval()`
|
||||||
|
|
||||||
### Data Types
|
### Data Types
|
||||||
- Numbers (integers, floats, binary `0b1010`, hex `0xFF`)
|
- Numbers (integers, floats, binary `0b1010`, hex `0xFF`)
|
||||||
|
|||||||
@ -91,7 +91,7 @@ value *= 2;
|
|||||||
value -= 3;
|
value -= 3;
|
||||||
|
|
||||||
// New built-in functions
|
// New built-in functions
|
||||||
var randomValue = random();
|
import rand; var randomValue = rand.random();
|
||||||
sleep(100); // Sleep for 100ms
|
sleep(100); // Sleep for 100ms
|
||||||
printRaw("No newline here");
|
printRaw("No newline here");
|
||||||
eval("print('Dynamic code execution!');");
|
eval("print('Dynamic code execution!');");
|
||||||
|
|||||||
@ -300,7 +300,7 @@
|
|||||||
"Random Number": {
|
"Random Number": {
|
||||||
"prefix": "random",
|
"prefix": "random",
|
||||||
"body": [
|
"body": [
|
||||||
"var randomValue = random();"
|
"import rand; var randomValue = rand.random();"
|
||||||
],
|
],
|
||||||
"description": "Generate random number"
|
"description": "Generate random number"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -151,8 +151,9 @@ input("File data cleared. Check memory usage...");
|
|||||||
print("Test 6: Random number stress");
|
print("Test 6: Random number stress");
|
||||||
var randomData = [];
|
var randomData = [];
|
||||||
for (var i = 0; i < 200000; i++) {
|
for (var i = 0; i < 200000; i++) {
|
||||||
var rand1 = random();
|
import rand as RLeak;
|
||||||
var rand2 = random();
|
var rand1 = RLeak.random();
|
||||||
|
var rand2 = RLeak.random();
|
||||||
var sum = rand1 + rand2;
|
var sum = rand1 + rand2;
|
||||||
|
|
||||||
randomData.push({
|
randomData.push({
|
||||||
|
|||||||
@ -27,7 +27,9 @@ void registerPathModule(Interpreter& interpreter) {
|
|||||||
m.fn("splitext", [](std::vector<Value> a, int, int) -> Value {
|
m.fn("splitext", [](std::vector<Value> a, int, int) -> Value {
|
||||||
if (a.size()!=1 || !a[0].isString()) return NONE_VALUE;
|
if (a.size()!=1 || !a[0].isString()) return NONE_VALUE;
|
||||||
fs::path p(a[0].asString());
|
fs::path p(a[0].asString());
|
||||||
return Value(std::vector<Value>{ Value(p.replace_extension("").generic_string()), Value(p.extension().generic_string()) });
|
std::string ext = p.has_extension() ? p.extension().generic_string() : std::string("");
|
||||||
|
fs::path basePath = p.has_extension() ? (p.parent_path() / p.stem()) : p;
|
||||||
|
return Value(std::vector<Value>{ Value(basePath.generic_string()), Value(ext) });
|
||||||
});
|
});
|
||||||
m.fn("normalize", [](std::vector<Value> a, int, int) -> Value {
|
m.fn("normalize", [](std::vector<Value> a, int, int) -> Value {
|
||||||
if (a.size()!=1 || !a[0].isString()) return NONE_VALUE;
|
if (a.size()!=1 || !a[0].isString()) return NONE_VALUE;
|
||||||
|
|||||||
@ -8,6 +8,18 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// Platform-specific includes for memoryUsage()
|
||||||
|
#if defined(__APPLE__) && defined(__MACH__)
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <windows.h>
|
||||||
|
#include <psapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
void registerSysModule(Interpreter& interpreter) {
|
void registerSysModule(Interpreter& interpreter) {
|
||||||
interpreter.registerModule("sys", [](Interpreter::ModuleBuilder& m) {
|
interpreter.registerModule("sys", [](Interpreter::ModuleBuilder& m) {
|
||||||
Interpreter& I = m.interpreterRef;
|
Interpreter& I = m.interpreterRef;
|
||||||
@ -37,6 +49,40 @@ void registerSysModule(Interpreter& interpreter) {
|
|||||||
auto snapshot = I.getModuleCacheSnapshot();
|
auto snapshot = I.getModuleCacheSnapshot();
|
||||||
return Value(snapshot);
|
return Value(snapshot);
|
||||||
});
|
});
|
||||||
|
// memoryUsage(): process RSS in MB (best effort per-platform)
|
||||||
|
m.fn("memoryUsage", [](std::vector<Value> a, int, int) -> Value {
|
||||||
|
if (!a.empty()) return NONE_VALUE;
|
||||||
|
size_t memoryBytes = 0;
|
||||||
|
#if defined(__APPLE__) && defined(__MACH__)
|
||||||
|
// macOS
|
||||||
|
struct mach_task_basic_info info;
|
||||||
|
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
|
||||||
|
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS) {
|
||||||
|
memoryBytes = info.resident_size;
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
// Linux
|
||||||
|
std::ifstream statusFile("/proc/self/status");
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(statusFile, line)) {
|
||||||
|
if (line.substr(0, 6) == "VmRSS:") {
|
||||||
|
std::istringstream iss(line);
|
||||||
|
std::string label, value, unit;
|
||||||
|
iss >> label >> value >> unit;
|
||||||
|
memoryBytes = std::stoull(value) * 1024; // KB -> bytes
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
// Windows
|
||||||
|
PROCESS_MEMORY_COUNTERS pmc;
|
||||||
|
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
|
||||||
|
memoryBytes = pmc.WorkingSetSize;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
double memoryMB = static_cast<double>(memoryBytes) / (1024.0 * 1024.0);
|
||||||
|
return Value(memoryMB);
|
||||||
|
});
|
||||||
m.fn("exit", [](std::vector<Value> a, int, int) -> Value {
|
m.fn("exit", [](std::vector<Value> a, int, int) -> Value {
|
||||||
int code = 0; if (!a.empty() && a[0].isNumber()) code = static_cast<int>(a[0].asNumber());
|
int code = 0; if (!a.empty() && a[0].isNumber()) code = static_cast<int>(a[0].asNumber());
|
||||||
std::exit(code);
|
std::exit(code);
|
||||||
|
|||||||
@ -290,24 +290,7 @@ void BobStdLib::addToEnvironment(std::shared_ptr<Environment> env, Interpreter&
|
|||||||
// Store the shared_ptr in the interpreter to keep it alive
|
// Store the shared_ptr in the interpreter to keep it alive
|
||||||
interpreter.addBuiltinFunction(toBooleanFunc);
|
interpreter.addBuiltinFunction(toBooleanFunc);
|
||||||
|
|
||||||
// Create a built-in exit function to terminate the program
|
// exit moved to sys module
|
||||||
auto exitFunc = std::make_shared<BuiltinFunction>("exit",
|
|
||||||
[](std::vector<Value> args, int line, int column) -> Value {
|
|
||||||
int exitCode = 0; // Default exit code
|
|
||||||
|
|
||||||
if (args.size() > 0) {
|
|
||||||
if (args[0].isNumber()) {
|
|
||||||
exitCode = static_cast<int>(args[0].asNumber());
|
|
||||||
}
|
|
||||||
// If not a number, just use default exit code 0
|
|
||||||
}
|
|
||||||
|
|
||||||
std::exit(exitCode);
|
|
||||||
});
|
|
||||||
env->define("exit", Value(exitFunc));
|
|
||||||
|
|
||||||
// Store the shared_ptr in the interpreter to keep it alive
|
|
||||||
interpreter.addBuiltinFunction(exitFunc);
|
|
||||||
|
|
||||||
// sleep moved into builtin time module
|
// sleep moved into builtin time module
|
||||||
|
|
||||||
@ -353,30 +336,7 @@ void BobStdLib::addToEnvironment(std::shared_ptr<Environment> env, Interpreter&
|
|||||||
env->define("functions", Value(functionsFunc));
|
env->define("functions", Value(functionsFunc));
|
||||||
interpreter.addBuiltinFunction(functionsFunc);
|
interpreter.addBuiltinFunction(functionsFunc);
|
||||||
|
|
||||||
// Create a built-in random function
|
// random moved to rand module
|
||||||
auto randomFunc = std::make_shared<BuiltinFunction>("random",
|
|
||||||
[errorReporter](std::vector<Value> args, int line, int column) -> Value {
|
|
||||||
if (args.size() != 0) {
|
|
||||||
if (errorReporter) {
|
|
||||||
errorReporter->reportError(line, column, "StdLib Error",
|
|
||||||
"Expected 0 arguments but got " + std::to_string(args.size()) + ".", "", true);
|
|
||||||
}
|
|
||||||
throw std::runtime_error("Expected 0 arguments but got " + std::to_string(args.size()) + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Seed the random number generator if not already done
|
|
||||||
static bool seeded = false;
|
|
||||||
if (!seeded) {
|
|
||||||
srand(static_cast<unsigned int>(time(nullptr)));
|
|
||||||
seeded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Value(static_cast<double>(rand()) / RAND_MAX);
|
|
||||||
});
|
|
||||||
env->define("random", Value(randomFunc));
|
|
||||||
|
|
||||||
// Store the shared_ptr in the interpreter to keep it alive
|
|
||||||
interpreter.addBuiltinFunction(randomFunc);
|
|
||||||
|
|
||||||
// (eval and evalFile moved to eval module)
|
// (eval and evalFile moved to eval module)
|
||||||
|
|
||||||
@ -384,53 +344,6 @@ void BobStdLib::addToEnvironment(std::shared_ptr<Environment> env, Interpreter&
|
|||||||
|
|
||||||
// (file I/O moved to io module)
|
// (file I/O moved to io module)
|
||||||
|
|
||||||
// Create a built-in memoryUsage function (platform-specific, best effort)
|
// memoryUsage moved to sys module
|
||||||
auto memoryUsageFunc = std::make_shared<BuiltinFunction>("memoryUsage",
|
|
||||||
[errorReporter](std::vector<Value> args, int line, int column) -> Value {
|
|
||||||
if (args.size() != 0) {
|
|
||||||
if (errorReporter) {
|
|
||||||
errorReporter->reportError(line, column, "StdLib Error",
|
|
||||||
"Expected 0 arguments but got " + std::to_string(args.size()) + ".", "", true);
|
|
||||||
}
|
|
||||||
throw std::runtime_error("Expected 0 arguments but got " + std::to_string(args.size()) + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Platform-specific memory usage detection
|
|
||||||
size_t memoryBytes = 0;
|
|
||||||
|
|
||||||
#if defined(__APPLE__) && defined(__MACH__)
|
|
||||||
// macOS
|
|
||||||
struct mach_task_basic_info info;
|
|
||||||
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
|
|
||||||
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS) {
|
|
||||||
memoryBytes = info.resident_size;
|
|
||||||
}
|
|
||||||
#elif defined(__linux__)
|
|
||||||
// Linux - read from /proc/self/status
|
|
||||||
std::ifstream statusFile("/proc/self/status");
|
|
||||||
std::string line;
|
|
||||||
while (std::getline(statusFile, line)) {
|
|
||||||
if (line.substr(0, 6) == "VmRSS:") {
|
|
||||||
std::istringstream iss(line);
|
|
||||||
std::string label, value, unit;
|
|
||||||
iss >> label >> value >> unit;
|
|
||||||
memoryBytes = std::stoull(value) * 1024; // Convert KB to bytes
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
// Windows
|
|
||||||
PROCESS_MEMORY_COUNTERS pmc;
|
|
||||||
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
|
|
||||||
memoryBytes = pmc.WorkingSetSize;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Return memory usage in MB for readability
|
|
||||||
double memoryMB = static_cast<double>(memoryBytes) / (1024.0 * 1024.0);
|
|
||||||
return Value(memoryMB);
|
|
||||||
});
|
|
||||||
env->define("memoryUsage", Value(memoryUsageFunc));
|
|
||||||
interpreter.addBuiltinFunction(memoryUsageFunc);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -786,9 +786,9 @@ print("Comprehensive number tests: PASS");
|
|||||||
// TEST 29: TIME FUNCTION
|
// TEST 29: TIME FUNCTION
|
||||||
// ========================================
|
// ========================================
|
||||||
print("\n--- Test 29: Time Function ---");
|
print("\n--- Test 29: Time Function ---");
|
||||||
|
import time;
|
||||||
var start_time = time();
|
var start_time = time.now();
|
||||||
var end_time = time();
|
var end_time = time.now();
|
||||||
var duration = end_time - start_time;
|
var duration = end_time - start_time;
|
||||||
assert(start_time > 0, "Start time should be positive");
|
assert(start_time > 0, "Start time should be positive");
|
||||||
assert(end_time >= start_time, "End time should be >= start time");
|
assert(end_time >= start_time, "End time should be >= start time");
|
||||||
@ -2416,15 +2416,17 @@ print("Array built-in functions: PASS");
|
|||||||
print("\n--- Test 52: New Built-in Functions ---");
|
print("\n--- Test 52: New Built-in Functions ---");
|
||||||
|
|
||||||
// sleep() function
|
// sleep() function
|
||||||
var startTime = time();
|
import time as T;
|
||||||
//sleep(0.001); // Sleep for 1ms (much shorter for testing)
|
var startTime = T.now();
|
||||||
var endTime = time();
|
T.sleep(0.01); // Sleep briefly to ensure elapsed time
|
||||||
|
var endTime = T.now();
|
||||||
assert(endTime > startTime, "sleep() - time elapsed");
|
assert(endTime > startTime, "sleep() - time elapsed");
|
||||||
|
|
||||||
// random() function - test proper seeding
|
// random() function - test proper seeding
|
||||||
var random1 = random();
|
import rand as R;
|
||||||
var random2 = random();
|
var random1 = R.random();
|
||||||
var random3 = random();
|
var random2 = R.random();
|
||||||
|
var random3 = R.random();
|
||||||
assert(random1 >= 0 && random1 <= 1, "random() - range check 1");
|
assert(random1 >= 0 && random1 <= 1, "random() - range check 1");
|
||||||
assert(random2 >= 0 && random2 <= 1, "random() - range check 2");
|
assert(random2 >= 0 && random2 <= 1, "random() - range check 2");
|
||||||
assert(random3 >= 0 && random3 <= 1, "random() - range check 3");
|
assert(random3 >= 0 && random3 <= 1, "random() - range check 3");
|
||||||
@ -2432,30 +2434,44 @@ assert(random3 >= 0 && random3 <= 1, "random() - range check 3");
|
|||||||
assert(random1 != random2 || random2 != random3 || random1 != random3, "random() - different values");
|
assert(random1 != random2 || random2 != random3 || random1 != random3, "random() - different values");
|
||||||
|
|
||||||
// Test random number generation in different ranges
|
// Test random number generation in different ranges
|
||||||
var randomRange1 = random() * 10;
|
var randomRange1 = R.random() * 10;
|
||||||
var randomRange2 = random() * 100;
|
var randomRange2 = R.random() * 100;
|
||||||
assert(randomRange1 >= 0 && randomRange1 <= 10, "random() - range 0-10");
|
assert(randomRange1 >= 0 && randomRange1 <= 10, "random() - range 0-10");
|
||||||
assert(randomRange2 >= 0 && randomRange2 <= 100, "random() - range 0-100");
|
assert(randomRange2 >= 0 && randomRange2 <= 100, "random() - range 0-100");
|
||||||
|
|
||||||
// eval() function
|
// eval() function (now via eval module)
|
||||||
eval("var evalVar = 42;");
|
import eval as E;
|
||||||
|
E.eval("var evalVar = 42;");
|
||||||
assert(evalVar == 42, "eval() - variable creation");
|
assert(evalVar == 42, "eval() - variable creation");
|
||||||
|
|
||||||
eval("print(\"eval test\");"); // Should print "eval test"
|
E.eval("print(\"eval test\");"); // Should print "eval test"
|
||||||
|
|
||||||
var evalResult = eval("2 + 2;");
|
var evalResult = E.eval("2 + 2;");
|
||||||
// eval() currently returns none, so we just test it doesn't crash
|
// eval() currently returns none, so we just test it doesn't crash
|
||||||
|
|
||||||
// Test eval with complex expressions
|
// Test eval with complex expressions
|
||||||
eval("var complexVar = [1, 2, 3];");
|
E.eval("var complexVar = [1, 2, 3];");
|
||||||
assert(complexVar.len() == 3, "eval() - complex expression");
|
assert(complexVar.len() == 3, "eval() - complex expression");
|
||||||
|
|
||||||
// Test eval with function definitions
|
// Test eval with function definitions
|
||||||
eval("func evalFunc(x) { return x * 2; }");
|
E.eval("func evalFunc(x) { return x * 2; }");
|
||||||
assert(evalFunc(5) == 10, "eval() - function definition");
|
assert(evalFunc(5) == 10, "eval() - function definition");
|
||||||
|
|
||||||
print("New built-in functions: PASS");
|
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
|
// TEST 52.5: EXIT FUNCTION
|
||||||
// ========================================
|
// ========================================
|
||||||
@ -2718,14 +2734,14 @@ print("\n--- Test 54: Array Performance ---");
|
|||||||
|
|
||||||
// Test large array operations
|
// Test large array operations
|
||||||
var perfArray = [];
|
var perfArray = [];
|
||||||
var startTime = time();
|
import time as T; var startTime = T.now();
|
||||||
|
|
||||||
// Create large array
|
// Create large array
|
||||||
for (var i = 0; i < 1000; i = i + 1) {
|
for (var i = 0; i < 1000; i = i + 1) {
|
||||||
perfArray.push(i);
|
perfArray.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
var midTime = time();
|
var midTime = T.now();
|
||||||
assert(perfArray.len() == 1000, "Array performance - creation");
|
assert(perfArray.len() == 1000, "Array performance - creation");
|
||||||
|
|
||||||
// Access elements
|
// Access elements
|
||||||
@ -2734,7 +2750,7 @@ for (var j = 0; j < 100; j = j + 1) {
|
|||||||
assert(value == j * 10, "Array performance - access");
|
assert(value == j * 10, "Array performance - access");
|
||||||
}
|
}
|
||||||
|
|
||||||
var endTime = time();
|
var endTime = T.now();
|
||||||
assert(endTime > startTime, "Array performance - time check");
|
assert(endTime > startTime, "Array performance - time check");
|
||||||
|
|
||||||
print("Array performance: PASS");
|
print("Array performance: PASS");
|
||||||
@ -2852,7 +2868,7 @@ print("\n--- Test 57: Array Stress Testing ---");
|
|||||||
|
|
||||||
// Large array creation and manipulation
|
// Large array creation and manipulation
|
||||||
var stressArray = [];
|
var stressArray = [];
|
||||||
var startTime = time();
|
import time as T2; var startTime = T2.now();
|
||||||
|
|
||||||
// Create large array with mixed types
|
// Create large array with mixed types
|
||||||
for (var i = 0; i < 500; i = i + 1) {
|
for (var i = 0; i < 500; i = i + 1) {
|
||||||
@ -2865,7 +2881,7 @@ for (var i = 0; i < 500; i = i + 1) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var midTime = time();
|
var midTime = T2.now();
|
||||||
assert(stressArray.len() == 500, "Stress test - array creation");
|
assert(stressArray.len() == 500, "Stress test - array creation");
|
||||||
|
|
||||||
// Access and modify elements
|
// Access and modify elements
|
||||||
@ -2876,7 +2892,7 @@ for (var j = 0; j < 100; j = j + 1) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var endTime = time();
|
var endTime = T2.now();
|
||||||
assert(endTime > startTime, "Stress test - time validation");
|
assert(endTime > startTime, "Stress test - time validation");
|
||||||
|
|
||||||
// Verify modifications
|
// Verify modifications
|
||||||
@ -2992,7 +3008,8 @@ assert(toInt(-0.0) == 0, "toInt(-0.0) should be 0");
|
|||||||
|
|
||||||
// Test with random numbers
|
// Test with random numbers
|
||||||
for(var i = 0; i < 5; i++) {
|
for(var i = 0; i < 5; i++) {
|
||||||
var randomFloat = random() * 10;
|
import rand as Rn;
|
||||||
|
var randomFloat = Rn.random() * 10;
|
||||||
var randomInt = toInt(randomFloat);
|
var randomInt = toInt(randomFloat);
|
||||||
assert(randomInt >= 0 && randomInt <= 9, "toInt(random) should be in range 0-9");
|
assert(randomInt >= 0 && randomInt <= 9, "toInt(random) should be in range 0-9");
|
||||||
}
|
}
|
||||||
@ -3273,58 +3290,59 @@ print(" * Error reporting in both modes");
|
|||||||
|
|
||||||
// Additional Tests: Classes and Extensions
|
// Additional Tests: Classes and Extensions
|
||||||
print("\n--- Additional Tests: Classes and Extensions ---");
|
print("\n--- Additional Tests: Classes and Extensions ---");
|
||||||
var path1 = fileExists("tests/test_method_calls.bob") ? "tests/test_method_calls.bob" : "../tests/test_method_calls.bob";
|
import io as IO; // for file existence checks
|
||||||
evalFile(path1);
|
var path1 = IO.exists("tests/test_method_calls.bob") ? "tests/test_method_calls.bob" : "../tests/test_method_calls.bob";
|
||||||
var path2 = fileExists("tests/test_class_basic.bob") ? "tests/test_class_basic.bob" : "../tests/test_class_basic.bob";
|
E.evalFile(path1);
|
||||||
evalFile(path2);
|
var path2 = IO.exists("tests/test_class_basic.bob") ? "tests/test_class_basic.bob" : "../tests/test_class_basic.bob";
|
||||||
var path3 = fileExists("tests/test_class_with_this.bob") ? "tests/test_class_with_this.bob" : "../tests/test_class_with_this.bob";
|
E.evalFile(path2);
|
||||||
evalFile(path3);
|
var path3 = IO.exists("tests/test_class_with_this.bob") ? "tests/test_class_with_this.bob" : "../tests/test_class_with_this.bob";
|
||||||
var path4 = fileExists("tests/test_class_init.bob") ? "tests/test_class_init.bob" : "../tests/test_class_init.bob";
|
E.evalFile(path3);
|
||||||
evalFile(path4);
|
var path4 = IO.exists("tests/test_class_init.bob") ? "tests/test_class_init.bob" : "../tests/test_class_init.bob";
|
||||||
var path5 = fileExists("tests/test_class_extension_user.bob") ? "tests/test_class_extension_user.bob" : "../tests/test_class_extension_user.bob";
|
E.evalFile(path4);
|
||||||
evalFile(path5);
|
var path5 = IO.exists("tests/test_class_extension_user.bob") ? "tests/test_class_extension_user.bob" : "../tests/test_class_extension_user.bob";
|
||||||
var path6 = fileExists("tests/test_extension_methods.bob") ? "tests/test_extension_methods.bob" : "../tests/test_extension_methods.bob";
|
E.evalFile(path5);
|
||||||
evalFile(path6);
|
var path6 = IO.exists("tests/test_extension_methods.bob") ? "tests/test_extension_methods.bob" : "../tests/test_extension_methods.bob";
|
||||||
var path7 = fileExists("tests/test_class_inheritance.bob") ? "tests/test_class_inheritance.bob" : "../tests/test_class_inheritance.bob";
|
E.evalFile(path6);
|
||||||
evalFile(path7);
|
var path7 = IO.exists("tests/test_class_inheritance.bob") ? "tests/test_class_inheritance.bob" : "../tests/test_class_inheritance.bob";
|
||||||
var path8 = fileExists("tests/test_classes_comprehensive.bob") ? "tests/test_classes_comprehensive.bob" : "../tests/test_classes_comprehensive.bob";
|
E.evalFile(path7);
|
||||||
evalFile(path8);
|
var path8 = IO.exists("tests/test_classes_comprehensive.bob") ? "tests/test_classes_comprehensive.bob" : "../tests/test_classes_comprehensive.bob";
|
||||||
var path9 = fileExists("tests/test_class_super.bob") ? "tests/test_class_super.bob" : "../tests/test_class_super.bob";
|
E.evalFile(path8);
|
||||||
evalFile(path9);
|
var path9 = IO.exists("tests/test_class_super.bob") ? "tests/test_class_super.bob" : "../tests/test_class_super.bob";
|
||||||
var path10 = fileExists("tests/test_classes_extensive.bob") ? "tests/test_classes_extensive.bob" : "../tests/test_classes_extensive.bob";
|
E.evalFile(path9);
|
||||||
evalFile(path10);
|
var path10 = IO.exists("tests/test_classes_extensive.bob") ? "tests/test_classes_extensive.bob" : "../tests/test_classes_extensive.bob";
|
||||||
var path11 = fileExists("tests/test_class_edge_cases.bob") ? "tests/test_class_edge_cases.bob" : "../tests/test_class_edge_cases.bob";
|
E.evalFile(path10);
|
||||||
evalFile(path11);
|
var path11 = IO.exists("tests/test_class_edge_cases.bob") ? "tests/test_class_edge_cases.bob" : "../tests/test_class_edge_cases.bob";
|
||||||
var path12 = fileExists("tests/test_polymorphism.bob") ? "tests/test_polymorphism.bob" : "../tests/test_polymorphism.bob";
|
E.evalFile(path11);
|
||||||
evalFile(path12);
|
var path12 = IO.exists("tests/test_polymorphism.bob") ? "tests/test_polymorphism.bob" : "../tests/test_polymorphism.bob";
|
||||||
var path13 = fileExists("tests/test_polymorphism_practical.bob") ? "tests/test_polymorphism_practical.bob" : "../tests/test_polymorphism_practical.bob";
|
E.evalFile(path12);
|
||||||
evalFile(path13);
|
var path13 = IO.exists("tests/test_polymorphism_practical.bob") ? "tests/test_polymorphism_practical.bob" : "../tests/test_polymorphism_practical.bob";
|
||||||
|
E.evalFile(path13);
|
||||||
|
|
||||||
var path14 = fileExists("tests/test_builtin_methods_style.bob") ? "tests/test_builtin_methods_style.bob" : "../tests/test_builtin_methods_style.bob";
|
var path14 = IO.exists("tests/test_builtin_methods_style.bob") ? "tests/test_builtin_methods_style.bob" : "../tests/test_builtin_methods_style.bob";
|
||||||
evalFile(path14);
|
E.evalFile(path14);
|
||||||
|
|
||||||
var path15 = fileExists("tests/test_try_catch.bob") ? "tests/test_try_catch.bob" : "../tests/test_try_catch.bob";
|
var path15 = IO.exists("tests/test_try_catch.bob") ? "tests/test_try_catch.bob" : "../tests/test_try_catch.bob";
|
||||||
evalFile(path15);
|
E.evalFile(path15);
|
||||||
var path15a = fileExists("tests/test_try_catch_runtime.bob") ? "tests/test_try_catch_runtime.bob" : "../tests/test_try_catch_runtime.bob";
|
var path15a = IO.exists("tests/test_try_catch_runtime.bob") ? "tests/test_try_catch_runtime.bob" : "../tests/test_try_catch_runtime.bob";
|
||||||
evalFile(path15a);
|
E.evalFile(path15a);
|
||||||
var path15b = fileExists("tests/test_try_catch_extensive.bob") ? "tests/test_try_catch_extensive.bob" : "../tests/test_try_catch_extensive.bob";
|
var path15b = IO.exists("tests/test_try_catch_extensive.bob") ? "tests/test_try_catch_extensive.bob" : "../tests/test_try_catch_extensive.bob";
|
||||||
evalFile(path15b);
|
E.evalFile(path15b);
|
||||||
var path15c = fileExists("tests/test_try_catch_edge_cases2.bob") ? "tests/test_try_catch_edge_cases2.bob" : "../tests/test_try_catch_edge_cases2.bob";
|
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";
|
||||||
evalFile(path15c);
|
E.evalFile(path15c);
|
||||||
var path15d = fileExists("tests/test_try_catch_cross_function.bob") ? "tests/test_try_catch_cross_function.bob" : "../tests/test_try_catch_cross_function.bob";
|
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";
|
||||||
evalFile(path15d);
|
E.evalFile(path15d);
|
||||||
var path15e = fileExists("tests/test_try_catch_loop_interactions.bob") ? "tests/test_try_catch_loop_interactions.bob" : "../tests/test_try_catch_loop_interactions.bob";
|
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";
|
||||||
evalFile(path15e);
|
E.evalFile(path15e);
|
||||||
|
|
||||||
// Modules: basic imports suite
|
// Modules: basic imports suite
|
||||||
var pathMods = fileExists("tests/test_imports_basic.bob") ? "tests/test_imports_basic.bob" : "../tests/test_imports_basic.bob";
|
var pathMods = IO.exists("tests/test_imports_basic.bob") ? "tests/test_imports_basic.bob" : "../tests/test_imports_basic.bob";
|
||||||
evalFile(pathMods);
|
E.evalFile(pathMods);
|
||||||
|
|
||||||
var pathModsB = fileExists("tests/test_imports_builtin.bob") ? "tests/test_imports_builtin.bob" : "../tests/test_imports_builtin.bob";
|
var pathModsB = IO.exists("tests/test_imports_builtin.bob") ? "tests/test_imports_builtin.bob" : "../tests/test_imports_builtin.bob";
|
||||||
evalFile(pathModsB);
|
E.evalFile(pathModsB);
|
||||||
|
|
||||||
var pathOs = fileExists("tests/test_os_basic.bob") ? "tests/test_os_basic.bob" : "../tests/test_os_basic.bob";
|
var pathOs = IO.exists("tests/test_os_basic.bob") ? "tests/test_os_basic.bob" : "../tests/test_os_basic.bob";
|
||||||
evalFile(pathOs);
|
E.evalFile(pathOs);
|
||||||
|
|
||||||
print("\nAll tests passed.");
|
print("\nAll tests passed.");
|
||||||
print("Test suite complete.");
|
print("Test suite complete.");
|
||||||
11
tests/test_base64.bob
Normal file
11
tests/test_base64.bob
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
print("\n--- Test: base64 module ---");
|
||||||
|
import base64;
|
||||||
|
|
||||||
|
var s = "hello world";
|
||||||
|
var enc = base64.encode(s);
|
||||||
|
assert(enc == "aGVsbG8gd29ybGQ=", "base64.encode");
|
||||||
|
var dec = base64.decode(enc);
|
||||||
|
assert(dec == s, "base64.decode roundtrip");
|
||||||
|
print("base64: PASS");
|
||||||
|
|
||||||
|
|
||||||
5
tests/test_hash.bob
Normal file
5
tests/test_hash.bob
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
print("\n--- Test: hash module ---");
|
||||||
|
// Placeholder: implement when hash module is added
|
||||||
|
print("hash: SKIPPED");
|
||||||
|
|
||||||
|
|
||||||
@ -28,7 +28,8 @@ var after = mod_hello.X;
|
|||||||
assert(before == after, "module executed once (cached)");
|
assert(before == after, "module executed once (cached)");
|
||||||
|
|
||||||
// Cross-file visibility in same interpreter: eval user file after importing here
|
// Cross-file visibility in same interpreter: eval user file after importing here
|
||||||
evalFile("tests/import_user_of_mod_hello.bob");
|
import eval as E;
|
||||||
|
E.evalFile("tests/import_user_of_mod_hello.bob");
|
||||||
|
|
||||||
// Immutability: cannot reassign module binding
|
// Immutability: cannot reassign module binding
|
||||||
var immFail = false;
|
var immFail = false;
|
||||||
|
|||||||
15
tests/test_math.bob
Normal file
15
tests/test_math.bob
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
print("\n--- Test: math module ---");
|
||||||
|
import math;
|
||||||
|
|
||||||
|
assert(math.sqrt(9) == 3, "math.sqrt");
|
||||||
|
assert(math.round(3.6) == 4, "math.round");
|
||||||
|
assert(math.floor(3.6) == 3, "math.floor");
|
||||||
|
assert(math.ceil(3.1) == 4, "math.ceil");
|
||||||
|
assert(math.abs(-5) == 5, "math.abs");
|
||||||
|
assert(math.pow(2,8) == 256, "math.pow");
|
||||||
|
assert(math.min(1, 2, 3) == 1, "math.min");
|
||||||
|
assert(math.max(1, 2, 3) == 3, "math.max");
|
||||||
|
assert(math.pi > 3.14 && math.pi < 3.15, "math.pi range");
|
||||||
|
print("math: PASS");
|
||||||
|
|
||||||
|
|
||||||
15
tests/test_path.bob
Normal file
15
tests/test_path.bob
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
print("\n--- Test: path module ---");
|
||||||
|
import path;
|
||||||
|
|
||||||
|
assert(path.join("a","b","c.txt") == "a/b/c.txt", "path.join");
|
||||||
|
assert(path.dirname("/a/b/c.txt") == "/a/b", "path.dirname");
|
||||||
|
assert(path.basename("/a/b/c.txt") == "c.txt", "path.basename");
|
||||||
|
var sp = path.splitext("c.txt");
|
||||||
|
assert(sp[0] == "c" && sp[1] == ".txt", "path.splitext");
|
||||||
|
assert(path.normalize("a/./b/../c") == "a/c", "path.normalize");
|
||||||
|
assert(path.isabs("/a/b") == true, "path.isabs");
|
||||||
|
var rp = path.relpath("/a/b/c", "/a");
|
||||||
|
assert(rp == "b/c" || rp == "../a/b/c", "path.relpath platform tolerance");
|
||||||
|
print("path: PASS");
|
||||||
|
|
||||||
|
|
||||||
14
tests/test_rand.bob
Normal file
14
tests/test_rand.bob
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
print("\n--- Test: rand module ---");
|
||||||
|
import rand;
|
||||||
|
|
||||||
|
rand.seed(1234);
|
||||||
|
var r1 = rand.random();
|
||||||
|
var r2 = rand.random();
|
||||||
|
assert(r1 >= 0 && r1 < 1 && r2 >= 0 && r2 < 1, "rand.random range");
|
||||||
|
var i = rand.randint(1, 10);
|
||||||
|
assert(i >= 1 && i <= 10, "rand.randint range");
|
||||||
|
var choice = rand.choice(["a","b","c"]);
|
||||||
|
assert(choice == "a" || choice == "b" || choice == "c", "rand.choice");
|
||||||
|
print("rand: PASS");
|
||||||
|
|
||||||
|
|
||||||
5
tests/test_re.bob
Normal file
5
tests/test_re.bob
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
print("\n--- Test: re module ---");
|
||||||
|
// Placeholder: implement when re module is added
|
||||||
|
print("re: SKIPPED");
|
||||||
|
|
||||||
|
|
||||||
14
tests/test_time.bob
Normal file
14
tests/test_time.bob
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
print("\n--- Test: time module ---");
|
||||||
|
import time;
|
||||||
|
|
||||||
|
var t1 = time.now();
|
||||||
|
var t2 = time.now();
|
||||||
|
assert(t2 >= t1, "time.now monotonic-ish");
|
||||||
|
|
||||||
|
var m1 = time.monotonic();
|
||||||
|
time.sleep(0.01);
|
||||||
|
var m2 = time.monotonic();
|
||||||
|
assert(m2 > m1, "time.monotonic increases");
|
||||||
|
print("time: PASS");
|
||||||
|
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ while (true) {
|
|||||||
}
|
}
|
||||||
assert(i == 2 && seq.len() == 2, "continue/break in finally");
|
assert(i == 2 && seq.len() == 2, "continue/break in finally");
|
||||||
|
|
||||||
// Throw in loop body caught outside
|
// Throw in loop body caught and handled without extra reporter noise
|
||||||
var hits = [];
|
var hits = [];
|
||||||
for (var j = 0; j < 3; j = j + 1) {
|
for (var j = 0; j < 3; j = j + 1) {
|
||||||
try {
|
try {
|
||||||
@ -25,7 +25,11 @@ for (var j = 0; j < 3; j = j + 1) {
|
|||||||
hits.push("caught:" + e.message);
|
hits.push("caught:" + e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(hits.len() == 4 && hits[1] == "caught:bang", "loop catch per-iteration");
|
// Strictly check sequence; avoid out-of-bounds checks
|
||||||
|
assert(hits.len() == 3, "loop catch sequence length");
|
||||||
|
assert(hits[0] == 0, "loop catch sequence item0");
|
||||||
|
assert(hits[1] == "caught:bang", "loop catch sequence item1");
|
||||||
|
assert(hits[2] == 2, "loop catch sequence item2");
|
||||||
|
|
||||||
print("try/catch with loops: PASS");
|
print("try/catch with loops: PASS");
|
||||||
|
|
||||||
|
|||||||
5
tests/test_uuid.bob
Normal file
5
tests/test_uuid.bob
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
print("\n--- Test: uuid module ---");
|
||||||
|
// Placeholder: implement when uuid module is added
|
||||||
|
print("uuid: SKIPPED");
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user