Files
OxideJS-New/crates/oxide_vm/tests/global_builtin_writable_tests.rs

128 lines
4.7 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 可写 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");
}