mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-26 03:31:12 +08:00
fix: Map/Set 键按 SameValueZero 值等值——运行期构造字符串/BigInt 键查找闭合
This commit is contained in:
@@ -131,3 +131,82 @@ fn map_new_mixed_array_and_object_entries() {
|
||||
let r = eval(&mut vm, "var m = new Map([['a',1],{0:'b',1:2}]); m.get('a') + '/' + m.get('b')").unwrap();
|
||||
assert_eq!(str_val(&vm, r), "1/2");
|
||||
}
|
||||
|
||||
// ── SameValueZero 键语义:运行期构造键(非常量池指针)与同值字面量互为同键 ──
|
||||
|
||||
#[test]
|
||||
fn map_runtime_string_key_get_by_literal() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(&mut vm, "var m = new Map(); m.set(String.fromCharCode(120), 1); m.get('x')").unwrap();
|
||||
assert_eq!(r.as_int(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_same_content_string_keys_merge() {
|
||||
// 同内容键 set 第二次是覆盖而非新增:size 保持 1、值更新。
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var m = new Map(); m.set('x', 1); m.set(String.fromCharCode(120), 2); m.size + ':' + m.get('x')",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(str_val(&vm, r), "1:2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_string_key_delete_by_runtime_key() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var m = new Map(); m.set('x', 1); m.delete(String.fromCharCode(120)); m.has('x')",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!r.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_bigint_key_same_value_different_boxes() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(&mut vm, "var m = new Map(); m.set(10n, 'v'); m.get(BigInt(10)) + '/' + m.has(11n)").unwrap();
|
||||
assert_eq!(str_val(&vm, r), "v/false");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_nan_and_zero_keys() {
|
||||
// NaN 同 NaN 键、0/-0 同键:两键共存,has 双向命中。
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var m = new Map(); m.set(NaN, 'n'); m.set(-0, 'z'); m.has(NaN) && m.has(0) && m.size === 2",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(r.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_object_key_identity() {
|
||||
// 对象键按引用相等:同对象命中,等值异对象 miss(get 回 undefined)。
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var o = {}; var m = new Map(); m.set(o, 1); m.get(o) === 1 && m.get({}) === undefined",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(r.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_many_runtime_string_keys() {
|
||||
// 键量越过小表线性探测阈值后查找走哈希索引,哈希与值等值的一致性在此兑现。
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var m = new Map(); \
|
||||
for (var i = 0; i < 200; i++) { m.set('k' + i, i); } \
|
||||
var bad = -1; \
|
||||
for (var i = 0; i < 200; i++) { if (m.get(String.fromCharCode(107) + i) !== i) { bad = i; break; } } \
|
||||
bad < 0 ? (m.size === 200 ? 'ok' : 'size') : 'bad:' + bad",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(str_val(&vm, r), "ok");
|
||||
}
|
||||
|
||||
@@ -139,3 +139,90 @@ fn set_new_delete() {
|
||||
let r = eval(&mut vm, "var s = new Set(); s.add(1); s.add(2); s.delete(1); s.has(1)").unwrap();
|
||||
assert!(!r.as_bool());
|
||||
}
|
||||
|
||||
// ── SameValueZero 键语义:运行期构造键(非常量池指针)与同值字面量互为同键 ──
|
||||
|
||||
#[test]
|
||||
fn set_runtime_string_key_lookup_by_literal() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(&mut vm, "var s = new Set(); s.add(String.fromCharCode(120)); s.has('x')").unwrap();
|
||||
assert!(r.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_literal_key_lookup_by_runtime() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(&mut vm, "var s = new Set(); s.add('x'); s.has(String.fromCharCode(120))").unwrap();
|
||||
assert!(r.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_runtime_concat_key_matches_literal() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(&mut vm, "var s = new Set(); s.add('a' + 'b'); s.has('ab') && !s.has('a')").unwrap();
|
||||
assert!(r.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_same_content_string_is_one_key() {
|
||||
// 同内容两构造(字面量 + 运行期拼接)只占一个键位。
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var s = new Set(); s.add('ab'); \
|
||||
s.add(String.fromCharCode(97) + String.fromCharCode(98)); s.size",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(r.as_double(), 1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_runtime_string_key_delete() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(&mut vm, "var s = new Set(); s.add('x'); s.delete(String.fromCharCode(120)); s.has('x')").unwrap();
|
||||
assert!(!r.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_many_runtime_string_keys_lookup() {
|
||||
// 键量越过小表线性探测阈值后查找走哈希索引,哈希与值等值的一致性在此兑现。
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var s = new Set(); \
|
||||
for (var i = 0; i < 200; i++) { s.add('k' + i); } \
|
||||
var bad = -1; \
|
||||
for (var i = 0; i < 200; i++) { if (!s.has(String.fromCharCode(107) + i)) { bad = i; break; } } \
|
||||
bad < 0 ? (s.size === 200 ? 'ok' : 'size') : 'bad:' + bad",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(vm.lookup_str(r).unwrap_or_default(), "ok");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_bigint_key_same_value_different_boxes() {
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(&mut vm, "var s = new Set([10n]); s.has(BigInt(10)) && !s.has(11n) && !s.has(10)").unwrap();
|
||||
assert!(r.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_nan_and_zero_key_semantics() {
|
||||
// NaN 同 NaN 键、0/-0 同键;NaN 与最小正非规格化数(2^-1074)不得同键。
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(
|
||||
&mut vm,
|
||||
"var s = new Set([NaN, 0]); \
|
||||
s.size === 2 && s.has(NaN) && s.has(-0) && !s.has(Math.pow(2, -1074))",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(r.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_object_key_identity() {
|
||||
// 对象键按引用相等:同对象命中,等值异对象不命中。
|
||||
let mut vm = Vm::new();
|
||||
let r = eval(&mut vm, "var o = { a: 1 }; var s = new Set(); s.add(o); s.has(o) && !s.has({ a: 1 })").unwrap();
|
||||
assert!(r.as_bool());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user