mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 11:11:11 +08:00
feat: Math.sumPrecise 精确和与 isArray 原型链补全
This commit is contained in:
@@ -55,6 +55,7 @@ pub fn bind_math(core: &Arc<KernelCore>, session: &KernelSession, global: &mut J
|
||||
("f16round", oxide_builtins::math::math_f16round::<crate::vm::Vm>, 1),
|
||||
("fround", oxide_builtins::math::math_fround::<crate::vm::Vm>, 1),
|
||||
("log1p", oxide_builtins::math::math_log1p::<crate::vm::Vm>, 1),
|
||||
("sumPrecise", oxide_builtins::math::math_sum_precise::<crate::vm::Vm>, 1),
|
||||
);
|
||||
|
||||
for (name, val) in [
|
||||
|
||||
@@ -441,3 +441,20 @@ fn array_iteration_dense_elements_read_correct() {
|
||||
let (vm, result) = eval("[1,2,3].slice(1).join(',')").unwrap();
|
||||
assert_eq!(to_str(&vm, result), "2,3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_is_array_accepts_array_prototype() {
|
||||
// %Array.prototype% 本体走恒等臂判真。
|
||||
let (_vm, result) = eval("Array.isArray(Array.prototype)").unwrap();
|
||||
assert_eq!(result, JsValue::bool(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_is_array_rejects_prototype_inherited_object() {
|
||||
// 原型继承自 Array.prototype 的普通对象无 array 标记,恒等臂不得翻转。
|
||||
let (_vm, result) = eval("Array.isArray(Object.create(Array.prototype))").unwrap();
|
||||
assert_eq!(result, JsValue::bool(false));
|
||||
|
||||
let (_vm, result) = eval("Array.isArray([])").unwrap();
|
||||
assert_eq!(result, JsValue::bool(true));
|
||||
}
|
||||
|
||||
@@ -212,3 +212,102 @@ fn math_constant_sqrt2() {
|
||||
let result = eval(&mut vm, "Math.SQRT2").unwrap();
|
||||
assert!((result.as_double() - std::f64::consts::SQRT_2).abs() < 0.0001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn math_sum_precise_basic() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "Math.sumPrecise([1, 2, 3])").unwrap();
|
||||
assert!((result.as_double() - 6.0).abs() < 1e-9);
|
||||
|
||||
// 精确和:f64 逐次累加 0.1+0.1 恰好得 0.2,此例钉位宽边界外的尾差路径。
|
||||
let result = eval(&mut vm, "Math.sumPrecise([0.1, 0.1])").unwrap();
|
||||
assert_eq!(result.as_double(), 0.2);
|
||||
|
||||
// 大指数对精确抵消。
|
||||
let result = eval(&mut vm, "Math.sumPrecise([1e308, -1e308])").unwrap();
|
||||
assert_eq!(result.as_double(), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn math_sum_precise_zero_sign() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "Object.is(Math.sumPrecise([]), -0)").unwrap();
|
||||
assert_eq!(result, JsValue::bool(true));
|
||||
|
||||
let result = eval(&mut vm, "Object.is(Math.sumPrecise([-0]), -0)").unwrap();
|
||||
assert_eq!(result, JsValue::bool(true));
|
||||
|
||||
// -0 后跟 +0:终态 finite,精确和 0 → +0。
|
||||
let result = eval(&mut vm, "Object.is(Math.sumPrecise([-0, 0]), 0)").unwrap();
|
||||
assert_eq!(result, JsValue::bool(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn math_sum_precise_nan_and_infinity() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "Number.isNaN(Math.sumPrecise([NaN]))").unwrap();
|
||||
assert_eq!(result, JsValue::bool(true));
|
||||
|
||||
// 异号无穷互抵 → NaN。
|
||||
let result = eval(&mut vm, "Number.isNaN(Math.sumPrecise([Infinity, -Infinity]))").unwrap();
|
||||
assert_eq!(result, JsValue::bool(true));
|
||||
|
||||
let result = eval(&mut vm, "Math.sumPrecise([Infinity, Infinity])").unwrap();
|
||||
assert_eq!(result.as_double(), f64::INFINITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn math_sum_precise_type_errors() {
|
||||
let mut vm = Vm::new();
|
||||
// RequireObjectCoercible 与不可迭代两种 TypeError 形态。
|
||||
let result = eval(&mut vm, "try { Math.sumPrecise() } catch (e) { e.name }").unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap(), "TypeError");
|
||||
|
||||
let result = eval(&mut vm, "try { Math.sumPrecise({}) } catch (e) { e.name }").unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap(), "TypeError");
|
||||
|
||||
// 非 Number 元素:抛 TypeError 且不触发任何强转(coercions 保持 0)。
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () {
|
||||
var c = 0;
|
||||
var r = '';
|
||||
var o = { valueOf: function () { c++ } };
|
||||
try { Math.sumPrecise([o]) } catch (e) { r = e.name + ':' + c; }
|
||||
return r;
|
||||
})()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap(), "TypeError:0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn math_sum_precise_closes_iterator_once() {
|
||||
let mut vm = Vm::new();
|
||||
// 元素非 Number:next 恰一次、return 恰一次(IteratorClose 序位)。
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(function () {
|
||||
var next = 0, ret = 0;
|
||||
var iterable = {
|
||||
[Symbol.iterator]: function () {
|
||||
return {
|
||||
next: function () { next++; return { done: false, value: {} }; },
|
||||
return: function () { ret++; return {}; }
|
||||
};
|
||||
}
|
||||
};
|
||||
try { Math.sumPrecise(iterable) } catch (e) {}
|
||||
return next + ':' + ret;
|
||||
})()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap(), "1:1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn math_sum_precise_descriptor() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(&mut vm, "Math.sumPrecise.length + '|' + Math.sumPrecise.name").unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap(), "1|sumPrecise");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user