mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
128 lines
4.7 KiB
Rust
128 lines
4.7 KiB
Rust
//! 可写 builtin 全局双写(镜像槽 + 全局对象属性)回归测试。
|
||
//!
|
||
//! 规范可写全局(11 个 w:true 函数 + 48 个构造器/命名空间 + globalThis + 宿主名,
|
||
//! 描述符 {writable:true, enumerable:false, configurable:true})的标识符写须同步
|
||
//! 全局对象属性,裸读(镜像)与 globalThis 反射(属性)不失步。覆盖:简单/复合/
|
||
//! 更新/逻辑赋值、for-in/for-of 标识符目标、解构两臂、局部遮蔽不误伤、strict 可写
|
||
//! put 成功、eval 路径与 TypedArray 宿主名抽样。
|
||
|
||
use std::sync::Arc;
|
||
|
||
use oxide_compiler::compiler::Compiler;
|
||
use oxide_compiler::DefaultCompilerService;
|
||
use oxide_parser::Allocator;
|
||
use oxide_vm::vm::Vm;
|
||
|
||
fn eval_truthy(source: &str) {
|
||
let allocator = Allocator::default();
|
||
let program = oxide_parser::parse(&allocator, source).expect("parse");
|
||
let module = Compiler::new().compile(&program).expect("compile");
|
||
let mut vm = Vm::new();
|
||
vm.set_compiler_service(Arc::new(DefaultCompilerService));
|
||
let result = vm.run(&Arc::new(module)).expect("run");
|
||
assert!(result.is_bool() && result.as_bool(), "expected true, got: {result:?}\nsource: {source}");
|
||
}
|
||
|
||
// ── 简单赋值:镜像与属性同步落值 ──
|
||
#[test]
|
||
fn simple_assign_math_dual_writes() {
|
||
eval_truthy("var m = Math; Math = 5; Math === 5 && globalThis.Math === 5 && m !== 5");
|
||
}
|
||
|
||
#[test]
|
||
fn simple_assign_writable_names_dual_write() {
|
||
for name in ["Object", "JSON", "Symbol", "Promise"] {
|
||
let src = format!("var m = {name}; {name} = 5; {name} === 5 && globalThis.{name} === 5");
|
||
eval_truthy(&src);
|
||
}
|
||
}
|
||
|
||
// ── w:true 函数族:strict 下可写 put 成功(无 TypeError) ──
|
||
#[test]
|
||
fn strict_writable_function_put_succeeds() {
|
||
eval_truthy("'use strict'; parseInt = 42; parseInt === 42 && globalThis.parseInt === 42");
|
||
}
|
||
|
||
#[test]
|
||
fn sloppy_writable_function_put_succeeds() {
|
||
eval_truthy("parseInt = 42; parseInt === 42 && globalThis.parseInt === 42");
|
||
}
|
||
|
||
#[test]
|
||
fn uri_family_dual_write() {
|
||
eval_truthy("var m = encodeURI; encodeURI = 1; encodeURI === 1 && globalThis.encodeURI === 1");
|
||
}
|
||
|
||
// ── 复合/更新/逻辑赋值:RMW 新值两侧同步 ──
|
||
#[test]
|
||
fn compound_assign_dual_writes() {
|
||
eval_truthy("var m = Math; Math = 5; Math += 1; Math === 6 && globalThis.Math === 6");
|
||
}
|
||
|
||
#[test]
|
||
fn update_assign_dual_writes() {
|
||
eval_truthy("var m = Math; Math = 5; var r = (Math++); r === 5 && Math === 6 && globalThis.Math === 6");
|
||
}
|
||
|
||
#[test]
|
||
fn logical_assign_dual_writes() {
|
||
// ||=:LHS falsy 触发 put;??=:LHS nullish 触发 put。
|
||
eval_truthy("var m = Math; Math = 0; Math ||= 9; Math === 9 && globalThis.Math === 9");
|
||
eval_truthy("var m = Math; Math = null; Math ??= 2; Math === 2 && globalThis.Math === 2");
|
||
}
|
||
|
||
#[test]
|
||
fn logical_assign_short_circuit_no_put() {
|
||
// 短路未通过不发生 put(&&= 遇 falsy、??= 遇非 nullish):值与属性均保持。
|
||
eval_truthy("var m = Math; Math = 0; Math &&= 1; Math === 0 && globalThis.Math === 0");
|
||
eval_truthy("var m = Math; Math = 5; Math ??= 2; Math === 5 && globalThis.Math === 5");
|
||
}
|
||
|
||
// ── for-in/for-of 标识符目标:迭代值两侧同步 ──
|
||
#[test]
|
||
fn for_in_target_dual_writes() {
|
||
eval_truthy("var m = Math; Math = 5; for (Math in {a:1,b:2}) {} Math === 'b' && globalThis.Math === 'b'");
|
||
}
|
||
|
||
#[test]
|
||
fn for_of_target_dual_writes() {
|
||
eval_truthy("var m = Math; for (Math of [1,2]) {} Math === 2 && globalThis.Math === 2");
|
||
}
|
||
|
||
// ── 解构赋值两臂:值两侧同步 ──
|
||
#[test]
|
||
fn destructure_assign_dual_writes() {
|
||
eval_truthy("var m = Math; ({Math} = {Math: 1}); Math === 1 && globalThis.Math === 1");
|
||
eval_truthy("var m = Math; ([Math = 1] = [2]); Math === 2 && globalThis.Math === 2");
|
||
}
|
||
|
||
// ── 局部遮蔽不误伤:函数内 var 同名写不触全局 ──
|
||
#[test]
|
||
fn local_shadow_not_dual_written() {
|
||
eval_truthy(
|
||
"var m = Math; function g(){ var Math = 7; return Math; } \
|
||
g() === 7 && Math === m && globalThis.Math === m",
|
||
);
|
||
}
|
||
|
||
// ── globalThis 自身可写:镜像与属性同步 ──
|
||
#[test]
|
||
fn global_this_self_dual_writes() {
|
||
eval_truthy(
|
||
"var m = globalThis; globalThis = 1; \
|
||
globalThis === 1 && Object.getOwnPropertyDescriptor(m, 'globalThis').value === 1",
|
||
);
|
||
}
|
||
|
||
// ── 宿主名(TypedArray 抽象运算对象)同双写面 ──
|
||
#[test]
|
||
fn typed_array_host_name_dual_writes() {
|
||
eval_truthy("var m = TypedArray; TypedArray = 1; TypedArray === 1 && globalThis.TypedArray === 1");
|
||
}
|
||
|
||
// ── eval 路径:同一 emit 管线双写同效(外层镜像预载不重载,只钉属性面) ──
|
||
#[test]
|
||
fn eval_code_dual_writes_property() {
|
||
eval_truthy("eval('Math = 5'); globalThis.Math === 5");
|
||
}
|