From b0a3b041eb959265f916f0ee18eab4455ed56367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Sat, 27 Jun 2026 15:24:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=20Object.entries/val?= =?UTF-8?q?ues/is/getOwnPropertyDescriptor/hasOwnProperty/propertyIsEnumer?= =?UTF-8?q?able=20=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/object.rs | 12 ++++-- .../tests/object_boundary_tests.rs | 40 +++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/crates/oxide_builtins/src/object.rs b/crates/oxide_builtins/src/object.rs index 064e8df..4284fc2 100644 --- a/crates/oxide_builtins/src/object.rs +++ b/crates/oxide_builtins/src/object.rs @@ -140,8 +140,11 @@ pub fn object_assign(vm: &mut H, args: &[u8]) -> NativeResult { } pub fn object_is(vm: &mut H, args: &[u8]) -> NativeResult { - let lhs = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; - let rhs = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() }; + if args.len() < 3 { + return NativeResult::Err(crate::error::create_type_error(vm, "Object.is called with insufficient arguments")); + } + let lhs = vm.reg(args[1]); + let rhs = vm.reg(args[2]); NativeResult::Ok(JsValue::bool(oxide_runtime_api::same_value(lhs, rhs))) } @@ -230,7 +233,10 @@ pub fn object_define_property(vm: &mut H, args: &[u8]) -> NativeResul pub fn object_get_own_property_descriptor(vm: &mut H, args: &[u8]) -> NativeResult { if args.len() < 3 { - return NativeResult::Err(JsValue::undefined()); + return NativeResult::Err(crate::error::create_type_error( + vm, + "Object.getOwnPropertyDescriptor called on non-object", + )); } let obj_val = vm.reg(args[1]); if !obj_val.is_object() { diff --git a/crates/oxide_builtins/tests/object_boundary_tests.rs b/crates/oxide_builtins/tests/object_boundary_tests.rs index 9475bb9..c8f3a80 100644 --- a/crates/oxide_builtins/tests/object_boundary_tests.rs +++ b/crates/oxide_builtins/tests/object_boundary_tests.rs @@ -196,3 +196,43 @@ fn test_from_entries_empty_array() { let (_vm, result) = eval("Object.fromEntries([])").unwrap(); assert!(result.is_object(), "fromEntries([]) should return an empty object"); } + +#[test] +fn test_object_is_nan() { + let (_vm, result) = eval("Object.is(NaN, NaN)").unwrap(); + assert!(result.is_bool() && result.as_bool()); +} + +#[test] +fn test_object_is_signed_zero() { + let (_vm, result) = eval("Object.is(0, -0)").unwrap(); + assert!(result.is_bool() && !result.as_bool()); +} + +#[test] +fn test_entries_returns_key_value_pairs() { + let (_vm, result) = eval("var o = {a:1, b:2}; Object.entries(o).length").unwrap(); + assert!(result.is_int() || result.is_double()); +} + +#[test] +fn test_values_returns_array() { + let (_vm, result) = eval("var o = {a:1, b:2}; Object.values(o).length").unwrap(); + assert!(result.is_int() || result.is_double()); +} + +#[test] +fn test_get_own_property_descriptor_no_args_type_error() { + assert!(eval("Object.getOwnPropertyDescriptor()").is_err()); +} + +#[test] +fn test_has_own_property_non_object_this_type_error() { + assert!(eval("Object.prototype.hasOwnProperty.call(42, 'x')").is_err()); +} + +#[test] +fn test_property_is_enumerable_own_property() { + let (_vm, result) = eval("var o = {x: 1}; o.propertyIsEnumerable('x')").unwrap(); + assert!(result.is_bool() && result.as_bool()); +}