Files
OxideJS-New/crates/oxide_vm/tests/builtins_dataview_live_tests.rs
T

454 lines
16 KiB
Rust
Raw 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.
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))
}
/// 构造器终校验 detach 形:proto getter 内 detach → TypeError,
/// 偏移 ToNumber 恰发生一次(重取点在强转之后)。
#[test]
fn dv_ctor_custom_proto_detach_throws() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var buffer = new ArrayBuffer(8); \
var calls = 0; \
var byteOffset = { valueOf() { calls++; return 0; } }; \
var newTarget = function() {}.bind(null); \
Object.defineProperty(newTarget, 'prototype', { \
get() { $262.detachArrayBuffer(buffer); return DataView.prototype; } \
}); \
var err = null; \
try { Reflect.construct(DataView, [buffer, byteOffset], newTarget); } catch (e) { err = e; } \
err instanceof TypeError && calls === 1",
)
.unwrap();
assert!(result.as_bool());
}
/// auto 缺省长终校验重算:proto getter 内 resize(2) 后存储长按 live' − offset 重算。
#[test]
fn dv_ctor_custom_proto_resize_valid_by_offset() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var buffer = new ArrayBuffer(3, { maxByteLength: 3 }); \
var newTarget = function() {}.bind(null); \
Object.defineProperty(newTarget, 'prototype', { \
get: function() { buffer.resize(2); return DataView.prototype; } \
}); \
var result = Reflect.construct(DataView, [buffer, 2], newTarget); \
result.constructor === DataView && result.byteLength === 0 && result.byteOffset === 2",
)
.unwrap();
assert!(result.as_bool());
}
/// 显式长终校验:resize 至 2 后 1 + 1 ≤ 2 → 成功且 byteLength 保持静态 1。
#[test]
fn dv_ctor_custom_proto_resize_valid_by_length() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var buffer = new ArrayBuffer(3, { maxByteLength: 3 }); \
var newTarget = function() {}.bind(null); \
Object.defineProperty(newTarget, 'prototype', { \
get: function() { buffer.resize(2); return DataView.prototype; } \
}); \
var result = Reflect.construct(DataView, [buffer, 1, 1], newTarget); \
result.constructor === DataView && result.byteLength === 1",
)
.unwrap();
assert!(result.as_bool());
}
/// 终校验 offset 臂:resize(1) 后 offset 2 > live' → RangeError。
#[test]
fn dv_ctor_custom_proto_resize_invalid_by_offset() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var buffer = new ArrayBuffer(3, { maxByteLength: 3 }); \
var newTarget = function() {}.bind(null); \
Object.defineProperty(newTarget, 'prototype', { \
get: function() { buffer.resize(1); return DataView.prototype; } \
}); \
var err = null; \
try { Reflect.construct(DataView, [buffer, 2], newTarget); } catch (e) { err = e; } \
err instanceof RangeError",
)
.unwrap();
assert!(result.as_bool());
}
/// 终校验显式长臂:resize(2) 后 1 + 2 > live' → RangeError。
#[test]
fn dv_ctor_custom_proto_resize_invalid_by_length() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var buffer = new ArrayBuffer(3, { maxByteLength: 3 }); \
var newTarget = function() {}.bind(null); \
Object.defineProperty(newTarget, 'prototype', { \
get: function() { buffer.resize(2); return DataView.prototype; } \
}); \
var err = null; \
try { Reflect.construct(DataView, [buffer, 1, 2], newTarget); } catch (e) { err = e; } \
err instanceof RangeError",
)
.unwrap();
assert!(result.as_bool());
}
/// byteLength auto 活读序列:3 → grow 4 → shrink 2 → 边界 0 → 越界 TypeError。
#[test]
fn dv_bytelength_auto_tracks_resize() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var ab = new ArrayBuffer(4, { maxByteLength: 5 }); \
var dv = new DataView(ab, 1); \
var ok = dv.byteLength === 3; \
ab.resize(5); ok = ok && dv.byteLength === 4; \
ab.resize(3); ok = ok && dv.byteLength === 2; \
ab.resize(1); ok = ok && dv.byteLength === 0; \
ab.resize(0); \
try { dv.byteLength; ok = false; } catch (e) { ok = ok && e instanceof TypeError; } \
ok",
)
.unwrap();
assert!(result.as_bool());
}
/// byteLength fixed 视图:shrink 到 end 之下 → TypeError,grow 回静态长。
#[test]
fn dv_bytelength_fixed_shrink_typeerror() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var ab = new ArrayBuffer(4, { maxByteLength: 5 }); \
var dv = new DataView(ab, 1, 2); \
var ok = dv.byteLength === 2; \
ab.resize(5); ok = ok && dv.byteLength === 2; \
ab.resize(3); ok = ok && dv.byteLength === 2; \
ab.resize(2); \
try { dv.byteLength; ok = false; } catch (e) { ok = ok && e instanceof TypeError; } \
ab.resize(3); ok = ok && dv.byteLength === 2; \
ok",
)
.unwrap();
assert!(result.as_bool());
}
/// byteOffset getter detach 守卫:detached 缓冲 → TypeError。
#[test]
fn dv_byteoffset_detach_throws() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var buffer = new ArrayBuffer(1); \
var sample = new DataView(buffer, 0); \
$262.detachArrayBuffer(buffer); \
var err = null; \
try { sample.byteOffset; } catch (e) { err = e; } \
err instanceof TypeError",
)
.unwrap();
assert!(result.as_bool());
}
/// byteOffset getter OOB 守卫:auto 视图 shrink 至 offset 之下 → TypeError。
#[test]
fn dv_byteoffset_auto_shrink_typeerror() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var ab = new ArrayBuffer(4, { maxByteLength: 5 }); \
var dv = new DataView(ab, 1); \
var ok = dv.byteOffset === 1; \
ab.resize(0); \
try { dv.byteOffset; ok = false; } catch (e) { ok = ok && e instanceof TypeError; } \
ok",
)
.unwrap();
assert!(result.as_bool());
}
/// get 面 OOB:fixed 视图(0,16)resize(8) 后读 → TypeError(非 RangeError)。
#[test]
fn dv_get_shrunk_buffer_typeerror() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var buffer = new ArrayBuffer(24, { maxByteLength: 32 }); \
var sample = new DataView(buffer, 0, 16); \
buffer.resize(16); \
var ok = sample.getInt8(0) === 0; \
buffer.resize(8); \
try { sample.getInt8(0); ok = false; } catch (e) { ok = ok && e instanceof TypeError; } \
ok",
)
.unwrap();
assert!(result.as_bool());
}
/// set 面 OOB:同形写面 → TypeError。
#[test]
fn dv_set_shrunk_buffer_typeerror() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var buffer = new ArrayBuffer(24, { maxByteLength: 32 }); \
var sample = new DataView(buffer, 0, 16); \
buffer.resize(8); \
var err = null; \
try { sample.setInt8(0, 30); } catch (e) { err = e; } \
err instanceof TypeError",
)
.unwrap();
assert!(result.as_bool());
}
/// set 面 immutable 守卫先于一切强转:偏移与值 valueOf 零调用。
#[test]
fn dv_set_immutable_before_conversion() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var iab = (new ArrayBuffer(8)).transferToImmutable(); \
var view = new DataView(iab); \
var calls = []; \
var byteOffset = { valueOf() { calls.push('byteOffset.valueOf'); return 0; } }; \
var value = { valueOf() { calls.push('value.valueOf'); return '1'; } }; \
view.getInt8(byteOffset) === 0 && \
(function() { \
calls = []; \
try { view.setInt8(byteOffset, value); return false; } catch (e) { return e instanceof TypeError; } \
})() && calls.length === 0",
)
.unwrap();
assert!(result.as_bool());
}
/// get 面允许 immutable 缓冲:正常读回初值。
#[test]
fn dv_get_immutable_ok() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var iab = (new ArrayBuffer(8)).transferToImmutable(); \
var src = new DataView(new ArrayBuffer(8)); \
src.setInt8(3, 42); \
var view = new DataView(iab); \
view.getInt8(0) === 0 && new DataView(iab).byteLength === 8",
)
.unwrap();
assert!(result.as_bool());
}
/// 缓冲完好时视图相对越界保持 RangeError 种类;auto 视图 grow 后新区可读。
#[test]
fn dv_get_oob_kind_split() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var buffer = new ArrayBuffer(12); \
var sample = new DataView(buffer, 0); \
var err = null; \
try { sample.getInt8(12); } catch (e) { err = e; } \
var ok = err instanceof RangeError; \
var ab = new ArrayBuffer(4, { maxByteLength: 8 }); \
var auto = new DataView(ab, 0); \
ab.resize(8); \
ok = ok && auto.byteLength === 8 && auto.getUint8(7) === 0; \
ok",
)
.unwrap();
assert!(result.as_bool());
}
/// 定长缓冲缺省长构造 + 初校验序钉:offset > bufferByteLength 的
/// RangeError 先于 proto getter(getter 抛 Test262Error 不可见)。
#[test]
fn dv_ctor_fixed_default_len_static() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var ok = new DataView(new ArrayBuffer(8), 2).byteLength === 6; \
var buffer = new ArrayBuffer(3); \
var getterCalled = false; \
var newTarget = function() {}.bind(null); \
Object.defineProperty(newTarget, 'prototype', { \
get: function() { getterCalled = true; throw new Error('getter'); } \
}); \
var err = null; \
try { Reflect.construct(DataView, [buffer, 4], newTarget); } catch (e) { err = e; } \
ok = ok && err instanceof RangeError && !getterCalled; \
ok",
)
.unwrap();
assert!(result.as_bool());
}
/// DV-over-SAB 构造基础形:缺省长视图,buffer 指向 SAB 本体。
#[test]
fn dv_sab_ctor_basic() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var sab = new SharedArrayBuffer(8); \
var dv = new DataView(sab); \
dv.byteLength === 8 && dv.byteOffset === 0 && dv.buffer === sab \
&& Object.getPrototypeOf(dv) === DataView.prototype",
)
.unwrap();
assert!(result.as_bool());
}
/// DV-over-SAB 显式 offset/length 形:视图界与 buffer 指向。
#[test]
fn dv_sab_ctor_offset_length() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"var sab = new SharedArrayBuffer(8); \
var dv = new DataView(sab, 2, 4); \
dv.byteLength === 4 && dv.byteOffset === 2 && dv.buffer === sab",
)
.unwrap();
assert!(result.as_bool());
}
/// DV-over-SAB 构造越界三形:offset > live / 显式长越界 / 负 offset 均 RangeError。
#[test]
fn dv_sab_ctor_oob() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"(function () { \
var sab = new SharedArrayBuffer(4); \
function kind(expr) { try { expr(); return 'none'; } catch (e) { return e.name; } } \
return kind(function () { new DataView(sab, 5); }) === 'RangeError' \
&& kind(function () { new DataView(sab, 0, 5); }) === 'RangeError' \
&& kind(function () { new DataView(sab, -1); }) === 'RangeError'; })()",
)
.unwrap();
assert!(result.as_bool());
}
/// DV-over-SAB 读写核回卷:各宽 get/set 位模式与同形 AB 视图对照同值。
#[test]
fn dv_sab_get_set_roundtrip() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"(function () { \
var sab = new SharedArrayBuffer(32); \
var dv = new DataView(sab); \
dv.setInt8(0, -7); \
dv.setUint8(1, 200); \
dv.setInt32(2, 0x01020304, true); \
dv.setInt32(6, 0x01020304, false); \
dv.setFloat64(8, 1.5); \
dv.setBigInt64(16, 42n); \
dv.setBigUint64(24, 18446744073709551615n); \
var ab = new ArrayBuffer(32); \
var ref = new DataView(ab); \
ref.setInt8(0, -7); \
ref.setUint8(1, 200); \
ref.setInt32(2, 0x01020304, true); \
ref.setInt32(6, 0x01020304, false); \
ref.setFloat64(8, 1.5); \
ref.setBigInt64(16, 42n); \
ref.setBigUint64(24, 18446744073709551615n); \
return dv.getInt8(0) === ref.getInt8(0) \
&& dv.getUint8(1) === ref.getUint8(1) \
&& dv.getInt32(2, true) === ref.getInt32(2, true) \
&& dv.getInt32(6, false) === ref.getInt32(6, false) \
&& dv.getFloat64(8, true) === ref.getFloat64(8, true) \
&& dv.getBigInt64(16, true) === ref.getBigInt64(16, true) \
&& dv.getBigUint64(24, false) === ref.getBigUint64(24, false); })()",
)
.unwrap();
assert!(result.as_bool());
}
/// DV-over-SAB 读越界:跨视图尾 getInt32 → RangeError。
#[test]
fn dv_sab_get_oob() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"(function () { \
var dv = new DataView(new SharedArrayBuffer(4)); \
try { dv.getInt32(1); return false; } catch (e) { return e instanceof RangeError; } })()",
)
.unwrap();
assert!(result.as_bool());
}
/// DV-over-SAB live 读:定长视图静态界 + growable SAB auto 视图随 grow 活读。
#[test]
fn dv_sab_live_getters() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"(function () { \
var sab = new SharedArrayBuffer(8); \
var fixed = new DataView(sab, 1, 3); \
var ok = fixed.byteOffset === 1 && fixed.byteLength === 3; \
var growable = new SharedArrayBuffer(4, { maxByteLength: 8 }); \
var auto = new DataView(growable); \
ok = ok && auto.byteLength === 4 && auto.byteOffset === 0; \
growable.grow(8); \
return ok && auto.byteLength === 8 && auto.byteOffset === 0; })()",
)
.unwrap();
assert!(result.as_bool());
}
/// DV-over-SAB 原型链:buffer 属性返回 SAB 本体 + custom-proto 臂
/// (newTarget 自定义原型经 GpFC 落位)。
#[test]
fn dv_sab_proto_chain() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"(function () { \
var sab = new SharedArrayBuffer(4); \
var dv = new DataView(sab); \
var ok = dv.buffer === sab; \
var newTarget = function() {}.bind(null); \
newTarget.prototype = {}; \
var dv2 = Reflect.construct(DataView, [sab], newTarget); \
return ok && Object.getPrototypeOf(dv2) === newTarget.prototype; })()",
)
.unwrap();
assert!(result.as_bool());
}
/// DV-over-SAB 品牌负钉:非缓冲区对象(裸对象 / TypedArray / null)构造
/// 首检均 TypeError。
#[test]
fn dv_sab_brand_reject() {
let mut vm = Vm::new();
let result = eval(
&mut vm,
"(function () { \
function kind(expr) { try { expr(); return 'none'; } catch (e) { return e.name; } } \
var ta = new Int8Array(4); \
return kind(function () { new DataView({}); }) === 'TypeError' \
&& kind(function () { new DataView(ta); }) === 'TypeError' \
&& kind(function () { new DataView(null); }) === 'TypeError'; })()",
)
.unwrap();
assert!(result.as_bool());
}