mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
161 lines
6.2 KiB
Rust
161 lines
6.2 KiB
Rust
use std::sync::Arc;
|
|
|
|
use oxide_compiler::compiler::Compiler;
|
|
use oxide_kernel::kernel::{KernelConfig, KernelCore};
|
|
use oxide_types::value::JsValue;
|
|
use oxide_vm::vm::Vm;
|
|
|
|
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
|
let allocator = oxide_parser::Allocator::default();
|
|
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
|
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
|
vm.run(&Arc::new(module))
|
|
}
|
|
|
|
/// 四弱族 stub 构造器原型链钉:prototype 为对象、原型链落 Object.prototype、
|
|
/// constructor 回指构造器本体;规范 25.1 的 %Proxy% 无 prototype 属性,不在名表。
|
|
#[test]
|
|
fn stub_ctor_prototype_chain_weak_family() {
|
|
let mut vm = Vm::new();
|
|
let result = eval(
|
|
&mut vm,
|
|
"(function () { \
|
|
var names = ['WeakMap', 'WeakSet', 'WeakRef', 'FinalizationRegistry']; \
|
|
for (var i = 0; i < names.length; i++) { \
|
|
var x = globalThis[names[i]]; \
|
|
if (typeof x.prototype !== 'object') { return false; } \
|
|
if (Object.getPrototypeOf(x.prototype) !== Object.prototype) { return false; } \
|
|
if (x.prototype.constructor !== x) { return false; } \
|
|
} \
|
|
return true; })()",
|
|
)
|
|
.unwrap();
|
|
assert!(result.as_bool());
|
|
}
|
|
|
|
/// 五 stub 构造器 length/name 值钉 + 非枚举钉:构造器面属性(length/name 五族、
|
|
/// prototype 四弱族)与原型对象自身属性均不泄漏进 Object.keys。
|
|
#[test]
|
|
fn stub_ctor_length_name_identity_non_enumerable() {
|
|
let mut vm = Vm::new();
|
|
let result = eval(
|
|
&mut vm,
|
|
"(function () { \
|
|
var names = ['Proxy', 'WeakMap', 'WeakSet', 'WeakRef', 'FinalizationRegistry']; \
|
|
var expect = { Proxy: 2, WeakMap: 0, WeakSet: 0, WeakRef: 1, FinalizationRegistry: 1 }; \
|
|
for (var i = 0; i < names.length; i++) { \
|
|
var name = names[i]; \
|
|
var x = globalThis[name]; \
|
|
if (x.length !== expect[name] || x.name !== name) { return false; } \
|
|
var keys = Object.keys(x); \
|
|
for (var k = 0; k < keys.length; k++) { \
|
|
if (keys[k] === 'length' || keys[k] === 'name' || keys[k] === 'prototype') { return false; } \
|
|
} \
|
|
if (x.prototype !== undefined && Object.keys(x.prototype).length !== 0) { return false; } \
|
|
} \
|
|
return true; })()",
|
|
)
|
|
.unwrap();
|
|
assert!(result.as_bool());
|
|
}
|
|
|
|
/// 四弱族原型对象 @@toStringTag 钉;Proxy 原型无规范 tag,不钉。
|
|
#[test]
|
|
fn weak_family_proto_to_string_tag() {
|
|
let mut vm = Vm::new();
|
|
let result = eval(
|
|
&mut vm,
|
|
"(function () { \
|
|
var names = ['WeakMap', 'WeakSet', 'WeakRef', 'FinalizationRegistry']; \
|
|
for (var i = 0; i < names.length; i++) { \
|
|
if (globalThis[names[i]].prototype[Symbol.toStringTag] !== names[i]) { return false; } \
|
|
} \
|
|
return true; })()",
|
|
)
|
|
.unwrap();
|
|
assert!(result.as_bool());
|
|
}
|
|
|
|
/// 原型成员读不抛钉:WeakMap 四方法已装为函数;其余弱族 stub 缺失方法
|
|
/// 读返 undefined(非对象 receiver 抛错形态消除);%Proxy% 无 prototype
|
|
/// 属性,钉其缺失。
|
|
#[test]
|
|
fn stub_proto_member_read_returns_undefined() {
|
|
let mut vm = Vm::new();
|
|
let result = eval(
|
|
&mut vm,
|
|
"(function () { \
|
|
return typeof WeakMap.prototype.get === 'function' \
|
|
&& typeof WeakMap.prototype.set === 'function' \
|
|
&& typeof WeakMap.prototype.has === 'function' \
|
|
&& typeof WeakMap.prototype.delete === 'function' \
|
|
&& typeof WeakSet.prototype.add === 'undefined' \
|
|
&& typeof WeakRef.prototype.deref === 'undefined' \
|
|
&& typeof FinalizationRegistry.prototype.register === 'undefined' \
|
|
&& Proxy.prototype === undefined; })()",
|
|
)
|
|
.unwrap();
|
|
assert!(result.as_bool());
|
|
}
|
|
|
|
/// 构造体不回归钉:三弱族 stub 构造调用仍抛 TypeError(消息含 "… is not
|
|
/// implemented");WeakMap 与 Proxy 已落地真构造器,不在此列。
|
|
#[test]
|
|
fn stub_ctor_call_still_throws_not_implemented() {
|
|
let mut vm = Vm::new();
|
|
let result = eval(
|
|
&mut vm,
|
|
"(function () { \
|
|
function probe(ctor, args, name) { \
|
|
try { Reflect.construct(ctor, args, ctor); } \
|
|
catch (e) { return e instanceof TypeError && e.message.indexOf(name + ' is not implemented') === 0; } \
|
|
return false; \
|
|
} \
|
|
return probe(WeakSet, [], 'WeakSet') \
|
|
&& probe(WeakRef, [{}], 'WeakRef') \
|
|
&& probe(FinalizationRegistry, [function () {}], 'FinalizationRegistry'); })()",
|
|
)
|
|
.unwrap();
|
|
assert!(result.as_bool());
|
|
}
|
|
|
|
/// isConstructor 探测臂钉:Reflect.construct 以 stub 作 newTarget 经真 prototype
|
|
/// 走通(构造体抛错由空函数体规避),结果恒 true。
|
|
#[test]
|
|
fn stub_ctor_is_constructor_probe_true() {
|
|
let mut vm = Vm::new();
|
|
let result = eval(
|
|
&mut vm,
|
|
"(function () { \
|
|
function isCtor(f) { \
|
|
try { Reflect.construct(function () {}, [], f); } catch (e) { return false; } \
|
|
return true; \
|
|
} \
|
|
return isCtor(Proxy) && isCtor(WeakMap) && isCtor(WeakSet) \
|
|
&& isCtor(WeakRef) && isCtor(FinalizationRegistry); })()",
|
|
)
|
|
.unwrap();
|
|
assert!(result.as_bool());
|
|
}
|
|
|
|
/// GC 边钉:低阈值 + 长循环触发执行期回收后,stub 原型对象经 stub 属性边存活,
|
|
/// 原型链与 constructor 回指身份不变。
|
|
#[test]
|
|
fn stub_proto_survives_runtime_gc() {
|
|
let mut config = KernelConfig::minimal();
|
|
config.set_session_gc_threshold(4096);
|
|
let mut vm = Vm::with_kernel_core(KernelCore::new(config));
|
|
let result = eval(
|
|
&mut vm,
|
|
"(function () { \
|
|
var p = WeakMap.prototype; \
|
|
var c = p.constructor; \
|
|
var s; \
|
|
for (var i = 0; i < 500000; i++) { s = 'str' + i; } \
|
|
return p === WeakMap.prototype && c === WeakMap \
|
|
&& Object.getPrototypeOf(p) === Object.prototype; })()",
|
|
)
|
|
.unwrap();
|
|
assert!(result.as_bool());
|
|
}
|