mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 18:51:13 +08:00
feat: WeakMap 构造体与四方法本体落地及 stub 剥离
This commit is contained in:
@@ -76,41 +76,45 @@ fn weak_family_proto_to_string_tag() {
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// 原型成员读不抛钉:缺失方法读返 undefined(非对象 receiver 抛错形态消除);
|
||||
/// %Proxy% 无 prototype 属性,钉其缺失。
|
||||
/// 原型成员读不抛钉: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 === 'undefined' \
|
||||
&& typeof WeakSet.prototype.add === 'undefined' \
|
||||
&& typeof WeakRef.prototype.deref === 'undefined' \
|
||||
&& typeof FinalizationRegistry.prototype.register === 'undefined' \
|
||||
&& Proxy.prototype === undefined; })()",
|
||||
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")。
|
||||
/// 构造体不回归钉:四 stub 构造调用仍抛 TypeError(消息含 "… is not
|
||||
/// implemented");WeakMap 已落地真构造器,不在此列。
|
||||
#[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(WeakMap, [], 'WeakMap') \
|
||||
&& probe(WeakSet, [], 'WeakSet') \
|
||||
&& probe(WeakRef, [{}], 'WeakRef') \
|
||||
&& probe(FinalizationRegistry, [function () {}], 'FinalizationRegistry') \
|
||||
&& probe(Proxy, [ {}, {} ], 'Proxy'); })()",
|
||||
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') \
|
||||
&& probe(Proxy, [ {}, {} ], 'Proxy'); })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
//! WeakMap 构造体与四方法钉:NewTarget 抛面、iterable 协议步序、品牌三分枝
|
||||
//! (set/delete 对非 WeakMap this 抛 TypeError,get/has 静默返 undefined/false)、
|
||||
//! 键面(对象/symbol 可弱持,原始值 set 抛、get/has/delete 静默)。
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use oxide_compiler::compiler::Compiler;
|
||||
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))
|
||||
}
|
||||
|
||||
/// 构造体身份钉:new 形态实例原型链落 WeakMap.prototype、instanceof 成立;
|
||||
/// 普通调用(无 NewTarget)抛 TypeError。
|
||||
#[test]
|
||||
fn weakmap_ctor_instance_and_newtarget_throw() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var m = new WeakMap(); \
|
||||
if (Object.getPrototypeOf(m) !== WeakMap.prototype) { return false; } \
|
||||
if (!(m instanceof WeakMap)) { return false; } \
|
||||
if (WeakMap.name !== 'WeakMap' || WeakMap.length !== 0) { return false; } \
|
||||
try { WeakMap(); return false; } \
|
||||
catch (e) { if (!(e instanceof TypeError)) { return false; } } \
|
||||
try { WeakMap([]); return false; } \
|
||||
catch (e) { if (!(e instanceof TypeError)) { return false; } } \
|
||||
return true; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// iterable 协议钉:对象键与 symbol 键逐元素 set;空可迭代不调用原型 set
|
||||
/// (覆写计数器探针);对象形态 entry({0,1} 属性)同命中。
|
||||
#[test]
|
||||
fn weakmap_ctor_iterable_protocol() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var k1 = {}, k2 = {}, ks = Symbol('key'); \
|
||||
var m = new WeakMap([[k1, 'a'], [k2, 'b'], [ks, 's']]); \
|
||||
if (m.get(k1) !== 'a' || m.get(k2) !== 'b' || m.get(ks) !== 's') { return false; } \
|
||||
var count = 0; \
|
||||
var saved = WeakMap.prototype.set; \
|
||||
WeakMap.prototype.set = function () { count += 1; }; \
|
||||
try { \
|
||||
new WeakMap([]); \
|
||||
} finally { \
|
||||
WeakMap.prototype.set = saved; \
|
||||
} \
|
||||
if (count !== 0) { return false; } \
|
||||
var m2 = new WeakMap([{0: k1, 1: 'c'}]); \
|
||||
return m2.get(k1) === 'c'; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// iterable 失败面钉:set 方法读取出抛原样透传;set 不可调用抛 TypeError;
|
||||
/// 元素非对象抛 TypeError;set 抛错时迭代器经 IteratorClose 恰好关闭一次。
|
||||
#[test]
|
||||
fn weakmap_ctor_iterable_failure_branches() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var getter = Object.getOwnPropertyDescriptor(WeakMap.prototype, 'set'); \
|
||||
Object.defineProperty(WeakMap.prototype, 'set', { \
|
||||
get: function () { throw new RangeError('boom'); }, \
|
||||
configurable: true \
|
||||
}); \
|
||||
try { new WeakMap([]); return false; } \
|
||||
catch (e) { if (!(e instanceof RangeError)) { return false; } } \
|
||||
finally { Object.defineProperty(WeakMap.prototype, 'set', getter); } \
|
||||
WeakMap.prototype.set = 'not a function'; \
|
||||
try { new WeakMap([[{}, 1]]); return false; } \
|
||||
catch (e) { if (!(e instanceof TypeError)) { return false; } } \
|
||||
finally { delete WeakMap.prototype.set; } \
|
||||
try { new WeakMap([42]); return false; } \
|
||||
catch (e) { if (!(e instanceof TypeError)) { return false; } } \
|
||||
var closed = 0; \
|
||||
var k = {}; \
|
||||
var it = { \
|
||||
n: 0, \
|
||||
next: function () { \
|
||||
this.n += 1; \
|
||||
if (this.n === 1) { return { value: [k, 1], done: false }; } \
|
||||
return { done: true }; \
|
||||
}, \
|
||||
return: function () { closed += 1; } \
|
||||
}; \
|
||||
var iterable = {}; \
|
||||
iterable[Symbol.iterator] = function () { return it; }; \
|
||||
WeakMap.prototype.set = function () { throw new Error('x'); }; \
|
||||
try { new WeakMap(iterable); } catch (e) {} \
|
||||
delete WeakMap.prototype.set; \
|
||||
return closed === 1; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// 品牌守卫钉:四方法对非 WeakMap this(plain 对象 / Map 对象 / 各原始 this)
|
||||
/// 均抛 TypeError(`RequireInternalSlot` 语义);合法 this 下未命中键静默返
|
||||
/// undefined/false 且 set 返回 this。
|
||||
#[test]
|
||||
fn weakmap_method_brand_guard() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var bad = [{}, new Map(), undefined, null, true, 's', 5, Symbol('t')]; \
|
||||
for (var i = 0; i < bad.length; i++) { \
|
||||
try { WeakMap.prototype.set.call(bad[i], {}, 1); return 'set-' + i; } \
|
||||
catch (e) { if (!(e instanceof TypeError)) { return 'set-kind-' + i; } } \
|
||||
try { WeakMap.prototype.delete.call(bad[i], {}); return 'del-' + i; } \
|
||||
catch (e) { if (!(e instanceof TypeError)) { return 'del-kind-' + i; } } \
|
||||
try { WeakMap.prototype.get.call(bad[i], {}); return 'get-' + i; } \
|
||||
catch (e) { if (!(e instanceof TypeError)) { return 'get-kind-' + i; } } \
|
||||
try { WeakMap.prototype.has.call(bad[i], {}); return 'has-' + i; } \
|
||||
catch (e) { if (!(e instanceof TypeError)) { return 'has-kind-' + i; } } \
|
||||
} \
|
||||
var m = new WeakMap(); \
|
||||
if (WeakMap.prototype.set.call(m, {}, 'v') !== m) { return 'returns-this'; } \
|
||||
if (m.get({}) !== undefined) { return 'fresh-get'; } \
|
||||
if (m.has({}) !== false) { return 'fresh-has'; } \
|
||||
if (m.delete({}) !== false) { return 'fresh-delete'; } \
|
||||
return true; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(result, JsValue::bool(true));
|
||||
}
|
||||
|
||||
/// 键面钉:原始值键 set 抛 TypeError;symbol 键经 set/get/has/delete 全链
|
||||
/// 成立(弱键 symbol 臂);原始值键 get/has/delete 静默。
|
||||
#[test]
|
||||
fn weakmap_key_surface_object_and_symbol() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () { \
|
||||
var m = new WeakMap(); \
|
||||
var badKeys = [1, '', undefined, null, true]; \
|
||||
for (var i = 0; i < badKeys.length; i++) { \
|
||||
try { m.set(badKeys[i], 1); return 'set-' + i; } \
|
||||
catch (e) { if (!(e instanceof TypeError)) { return 'set-kind-' + i; } } \
|
||||
if (m.get(badKeys[i]) !== undefined) { return 'get-' + i; } \
|
||||
if (m.has(badKeys[i]) !== false) { return 'has-' + i; } \
|
||||
if (m.delete(badKeys[i]) !== false) { return 'del-' + i; } \
|
||||
} \
|
||||
var s = Symbol('k'); \
|
||||
m.set(s, 'v'); \
|
||||
if (m.get(s) !== 'v' || !m.has(s)) { return 'symbol-roundtrip'; } \
|
||||
m.set(s, 'v2'); \
|
||||
if (m.get(s) !== 'v2') { return 'symbol-overwrite'; } \
|
||||
if (m.delete(s) !== true || m.has(s)) { return 'symbol-delete'; } \
|
||||
return true; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(result, JsValue::bool(true));
|
||||
}
|
||||
Reference in New Issue
Block a user