mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
88 lines
3.6 KiB
Rust
88 lines
3.6 KiB
Rust
//! test262 宿主对象 `$262` 的最小绑定验证:对象存在、`global` 指向当前 realm
|
||
//! 全局、evalScript 可执行、未实现方法抛能力缺失错误。
|
||
|
||
use std::sync::Arc;
|
||
|
||
use oxide_compiler::compiler::Compiler;
|
||
use oxide_parser::Allocator;
|
||
use oxide_vm::vm::Vm;
|
||
|
||
/// 单测辅助:源串 → 结果串(字符串值解包实际内容,运行错误以 `vm error: ...` 呈现)。
|
||
fn eval(source: &str) -> String {
|
||
let allocator = Allocator::default();
|
||
let program = match oxide_parser::parse(&allocator, source) {
|
||
Ok(p) => p,
|
||
Err(e) => return format!("parse error: {}", e[0].message),
|
||
};
|
||
let module = match Compiler::new().compile(&program) {
|
||
Ok(m) => m,
|
||
Err(e) => return format!("compile error: {e}"),
|
||
};
|
||
let mut vm = Vm::new();
|
||
match vm.run(&Arc::new(module)) {
|
||
Ok(result) => vm.lookup_str(result).unwrap_or_else(|| format!("{result}")),
|
||
Err(e) => format!("vm error: {e}"),
|
||
}
|
||
}
|
||
|
||
/// `$262` 作为编译期已知全局绑定:typeof 为 object,`global` 即 globalThis。
|
||
#[test]
|
||
fn host_object_exists_and_exposes_global() {
|
||
assert_eq!(eval("typeof $262"), "object");
|
||
assert_eq!(eval("$262.global === globalThis"), "true");
|
||
}
|
||
|
||
/// `$262` 方法面:evalScript/gc 为可调用函数。
|
||
#[test]
|
||
fn host_methods_are_callable() {
|
||
assert_eq!(eval("typeof $262.evalScript"), "function");
|
||
assert_eq!(eval("typeof $262.gc"), "function");
|
||
assert_eq!(eval("typeof $262.detachArrayBuffer"), "function");
|
||
assert_eq!(eval("typeof $262.createRealm"), "function");
|
||
}
|
||
|
||
/// evalScript 以普通脚本执行并返回完成值:末条语句的正常完成值;顶层
|
||
/// `return` 在 Script goal 下是编译期 SyntaxError。
|
||
#[test]
|
||
fn eval_script_runs_code_and_returns_value() {
|
||
// 普通脚本语义:顶层语句的正常完成值即脚本完成值(var 声明语句本身完成值为
|
||
// undefined,末条表达式语句 `y` 完成值为 1)。
|
||
assert_eq!(eval("$262.evalScript('var y = 1; y')"), "1");
|
||
// Script goal 顶层 return 非法:编译期错误转 JS 层可捕获的 SyntaxError。
|
||
let r = eval("try { $262.evalScript('return 40 + 2'); 'no-throw' } catch (e) { e.name }");
|
||
assert_eq!(r, "SyntaxError");
|
||
}
|
||
|
||
/// evalScript 编译失败转 SyntaxError(可由 JS catch 捕获)。
|
||
#[test]
|
||
fn eval_script_syntax_error_is_catchable() {
|
||
let r = eval("try { $262.evalScript('if (') ; 'no-throw' } catch (e) { e.name }");
|
||
assert_eq!(r, "SyntaxError");
|
||
}
|
||
|
||
/// 未实现方法抛能力缺失错误(消息带 `not supported`),不抛 ReferenceError。
|
||
#[test]
|
||
fn unsupported_methods_throw_not_supported() {
|
||
let r = eval("try { $262.createRealm(); 'no-throw' } catch (e) { e.name + ':' + e.message }");
|
||
assert!(r.contains("TypeError"), "期望 TypeError,实际 {r}");
|
||
assert!(r.contains("not supported"), "期望能力缺失消息,实际 {r}");
|
||
|
||
let r = eval("try { $262.agent(); 'no-throw' } catch (e) { e.name + ':' + e.message }");
|
||
assert!(r.contains("TypeError"), "期望 TypeError,实际 {r}");
|
||
}
|
||
|
||
/// `detachArrayBuffer` 真实现钉:detach 后 `detached` 访问器读 true、
|
||
/// 非 ArrayBuffer 实参抛 TypeError。
|
||
#[test]
|
||
fn detach_array_buffer_detaches() {
|
||
assert_eq!(eval("var ab = new ArrayBuffer(8); $262.detachArrayBuffer(ab); ab.detached"), "true");
|
||
let r = eval("try { $262.detachArrayBuffer(1); 'no-throw' } catch (e) { e.name }");
|
||
assert_eq!(r, "TypeError");
|
||
}
|
||
|
||
/// `$262.gc()` 触发一次 session 回收且不抛错。
|
||
#[test]
|
||
fn gc_runs_without_error() {
|
||
assert_eq!(eval("$262.gc(); 'ok'"), "ok");
|
||
}
|