feat: 修复 Array.slice 负数索引处理,新增 Array push/pop/shift/unshift/slice 边界测试
This commit is contained in:
@@ -193,19 +193,19 @@ pub fn array_slice<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
builtins_debug!("Array.prototype.slice called with {} args", args.len());
|
builtins_debug!("Array.prototype.slice called with {} args", args.len());
|
||||||
let arr_ptr = array_ptr!(vm, args);
|
let arr_ptr = array_ptr!(vm, args);
|
||||||
let arr = unsafe { &*arr_ptr };
|
let arr = unsafe { &*arr_ptr };
|
||||||
let n = arr.prop_count() as usize;
|
let n = arr.prop_count() as isize;
|
||||||
let start = if args.len() > 1 {
|
let rel_start = if args.len() > 1 {
|
||||||
(vm.coerce_number_bounded(vm.reg(args[1])).unwrap_or(f64::NAN) as i32) as usize
|
oxide_runtime_api::to_integer_or_infinity(vm.reg(args[1])) as isize
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
let end = if args.len() > 2 {
|
let rel_end = if args.len() > 2 {
|
||||||
(vm.coerce_number_bounded(vm.reg(args[2])).unwrap_or(f64::NAN) as i32) as usize
|
oxide_runtime_api::to_integer_or_infinity(vm.reg(args[2])) as isize
|
||||||
} else {
|
} else {
|
||||||
n
|
n
|
||||||
};
|
};
|
||||||
let start = start.min(n);
|
let start = if rel_start < 0 { (n + rel_start).max(0) } else { rel_start.min(n) } as usize;
|
||||||
let end = end.min(n);
|
let end = if rel_end < 0 { (n + rel_end).max(0) } else { rel_end.min(n) } as usize;
|
||||||
let count = end.saturating_sub(start);
|
let count = end.saturating_sub(start);
|
||||||
|
|
||||||
let new_arr = create_new_array(vm, count);
|
let new_arr = create_new_array(vm, count);
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use oxide_compiler::compiler::Compiler;
|
||||||
|
use oxide_types::value::JsValue;
|
||||||
|
use oxide_vm::vm::Vm;
|
||||||
|
|
||||||
|
fn eval(source: &str) -> Result<(Vm, 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))?;
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = vm.run(&module)?;
|
||||||
|
Ok((vm, result))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_push_returns_new_length() {
|
||||||
|
let (_vm, result) = eval("var a = [1, 2]; a.push(3)").unwrap();
|
||||||
|
assert_eq!(result.as_int(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_push_multiple_args() {
|
||||||
|
let (_vm, result) = eval("var a = [1]; a.push(2, 3)").unwrap();
|
||||||
|
assert_eq!(result.as_int(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pop_empty_returns_undefined() {
|
||||||
|
let (_vm, result) = eval("[].pop()").unwrap();
|
||||||
|
assert!(result.is_undefined());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_pop_returns_last_element() {
|
||||||
|
let (_vm, result) = eval("[1, 2, 3].pop()").unwrap();
|
||||||
|
assert_eq!(result.as_int(), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_shift_empty_returns_undefined() {
|
||||||
|
let (_vm, result) = eval("[].shift()").unwrap();
|
||||||
|
assert!(result.is_undefined());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_shift_returns_first_element() {
|
||||||
|
let (_vm, result) = eval("[1, 2, 3].shift()").unwrap();
|
||||||
|
assert_eq!(result.as_int(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unshift_returns_new_length() {
|
||||||
|
let (_vm, result) = eval("var a = [3, 4]; a.unshift(1, 2)").unwrap();
|
||||||
|
assert_eq!(result.as_int(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_slice_negative_start() {
|
||||||
|
let (_vm, result) = eval("[1, 2, 3, 4].slice(-2).length").unwrap();
|
||||||
|
assert_eq!(result.as_int(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_slice_negative_end() {
|
||||||
|
let (_vm, result) = eval("[1, 2, 3].slice(0, -1).length").unwrap();
|
||||||
|
assert_eq!(result.as_int(), 2);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user