mirror of https://github.com/boa-dev/boa.git
Browse Source
* Implement Reflect built-in object * Use receiver in get and set * Implement Reflect.construct with newTarget Co-authored-by: tofpie <tofpie@users.noreply.github.com>pull/1170/head
tofpie
4 years ago
committed by
GitHub
7 changed files with 626 additions and 54 deletions
@ -0,0 +1,385 @@ |
|||||||
|
//! This module implements the global `Reflect` object.
|
||||||
|
//!
|
||||||
|
//! The `Reflect` global object is a built-in object that provides methods for interceptable
|
||||||
|
//! JavaScript operations.
|
||||||
|
//!
|
||||||
|
//! More information:
|
||||||
|
//! - [ECMAScript reference][spec]
|
||||||
|
//! - [MDN documentation][mdn]
|
||||||
|
//!
|
||||||
|
//! [spec]: https://tc39.es/ecma262/#sec-reflect-object
|
||||||
|
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect
|
||||||
|
|
||||||
|
use crate::{ |
||||||
|
builtins::{self, BuiltIn}, |
||||||
|
object::{Object, ObjectData, ObjectInitializer}, |
||||||
|
property::{Attribute, DataDescriptor}, |
||||||
|
BoaProfiler, Context, Result, Value, |
||||||
|
}; |
||||||
|
|
||||||
|
#[cfg(test)] |
||||||
|
mod tests; |
||||||
|
|
||||||
|
/// Javascript `Reflect` object.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
||||||
|
pub(crate) struct Reflect; |
||||||
|
|
||||||
|
impl BuiltIn for Reflect { |
||||||
|
const NAME: &'static str = "Reflect"; |
||||||
|
|
||||||
|
fn attribute() -> Attribute { |
||||||
|
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE |
||||||
|
} |
||||||
|
|
||||||
|
fn init(context: &mut Context) -> (&'static str, Value, Attribute) { |
||||||
|
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); |
||||||
|
|
||||||
|
let to_string_tag = context.well_known_symbols().to_string_tag_symbol(); |
||||||
|
|
||||||
|
let object = ObjectInitializer::new(context) |
||||||
|
.function(Self::apply, "apply", 3) |
||||||
|
.function(Self::construct, "construct", 2) |
||||||
|
.function(Self::define_property, "defineProperty", 3) |
||||||
|
.function(Self::delete_property, "deleteProperty", 2) |
||||||
|
.function(Self::get, "get", 2) |
||||||
|
.function( |
||||||
|
Self::get_own_property_descriptor, |
||||||
|
"getOwnPropertyDescriptor", |
||||||
|
2, |
||||||
|
) |
||||||
|
.function(Self::get_prototype_of, "getPrototypeOf", 1) |
||||||
|
.function(Self::has, "has", 2) |
||||||
|
.function(Self::is_extensible, "isExtensible", 1) |
||||||
|
.function(Self::own_keys, "ownKeys", 1) |
||||||
|
.function(Self::prevent_extensions, "preventExtensions", 1) |
||||||
|
.function(Self::set, "set", 3) |
||||||
|
.function(Self::set_prototype_of, "setPrototypeOf", 3) |
||||||
|
.property( |
||||||
|
to_string_tag, |
||||||
|
Reflect::NAME, |
||||||
|
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, |
||||||
|
) |
||||||
|
.build(); |
||||||
|
(Self::NAME, object.into(), Self::attribute()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Reflect { |
||||||
|
/// Calls a target function with arguments.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.apply
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/apply
|
||||||
|
pub(crate) fn apply(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
||||||
|
let undefined = Value::undefined(); |
||||||
|
let target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be a function"))?; |
||||||
|
let this_arg = args.get(1).unwrap_or(&undefined); |
||||||
|
let args_list = args |
||||||
|
.get(2) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("args list must be an object"))?; |
||||||
|
|
||||||
|
if !target.is_callable() { |
||||||
|
return context.throw_type_error("target must be a function"); |
||||||
|
} |
||||||
|
let args = args_list.create_list_from_array_like(&[], context)?; |
||||||
|
target.call(this_arg, &args, context) |
||||||
|
} |
||||||
|
|
||||||
|
/// Calls a target function as a constructor with arguments.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.construct
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct
|
||||||
|
pub(crate) fn construct(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
||||||
|
let target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be a function"))?; |
||||||
|
let args_list = args |
||||||
|
.get(1) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("args list must be an object"))?; |
||||||
|
|
||||||
|
if !target.is_constructable() { |
||||||
|
return context.throw_type_error("target must be a constructor"); |
||||||
|
} |
||||||
|
|
||||||
|
let new_target = if let Some(new_target) = args.get(2) { |
||||||
|
if new_target.as_object().map(|o| o.is_constructable()) != Some(true) { |
||||||
|
return context.throw_type_error("newTarget must be constructor"); |
||||||
|
} |
||||||
|
new_target.clone() |
||||||
|
} else { |
||||||
|
target.clone().into() |
||||||
|
}; |
||||||
|
|
||||||
|
let args = args_list.create_list_from_array_like(&[], context)?; |
||||||
|
target.construct(&args, new_target, context) |
||||||
|
} |
||||||
|
|
||||||
|
/// Defines a property on an object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.defineProperty
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/defineProperty
|
||||||
|
pub(crate) fn define_property( |
||||||
|
_: &Value, |
||||||
|
args: &[Value], |
||||||
|
context: &mut Context, |
||||||
|
) -> Result<Value> { |
||||||
|
let undefined = Value::undefined(); |
||||||
|
let mut target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be an object"))?; |
||||||
|
let key = args.get(1).unwrap_or(&undefined).to_property_key(context)?; |
||||||
|
let prop_desc = args |
||||||
|
.get(2) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("property descriptor must be an object"))? |
||||||
|
.to_property_descriptor(context)?; |
||||||
|
|
||||||
|
target |
||||||
|
.define_own_property(key, prop_desc, context) |
||||||
|
.map(|b| b.into()) |
||||||
|
} |
||||||
|
|
||||||
|
/// Defines a property on an object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.deleteproperty
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/deleteProperty
|
||||||
|
pub(crate) fn delete_property( |
||||||
|
_: &Value, |
||||||
|
args: &[Value], |
||||||
|
context: &mut Context, |
||||||
|
) -> Result<Value> { |
||||||
|
let undefined = Value::undefined(); |
||||||
|
let mut target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be an object"))?; |
||||||
|
let key = args.get(1).unwrap_or(&undefined).to_property_key(context)?; |
||||||
|
|
||||||
|
Ok(target.delete(&key).into()) |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets a property of an object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.get
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/get
|
||||||
|
pub(crate) fn get(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
||||||
|
let undefined = Value::undefined(); |
||||||
|
let target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be an object"))?; |
||||||
|
let key = args.get(1).unwrap_or(&undefined).to_property_key(context)?; |
||||||
|
let receiver = if let Some(receiver) = args.get(2).cloned() { |
||||||
|
receiver |
||||||
|
} else { |
||||||
|
target.clone().into() |
||||||
|
}; |
||||||
|
target.get(&key, receiver, context) |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets a property of an object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.getownpropertydescriptor
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/getOwnPropertyDescriptor
|
||||||
|
pub(crate) fn get_own_property_descriptor( |
||||||
|
_: &Value, |
||||||
|
args: &[Value], |
||||||
|
context: &mut Context, |
||||||
|
) -> Result<Value> { |
||||||
|
match args.get(0) { |
||||||
|
Some(v) if v.is_object() => (), |
||||||
|
_ => return context.throw_type_error("target must be an object"), |
||||||
|
} |
||||||
|
// This function is the same as Object.prototype.getOwnPropertyDescriptor, that why
|
||||||
|
// it is invoked here.
|
||||||
|
builtins::object::Object::get_own_property_descriptor(&Value::undefined(), args, context) |
||||||
|
} |
||||||
|
|
||||||
|
/// Gets the prototype of an object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.getprototypeof
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/getPrototypeOf
|
||||||
|
pub(crate) fn get_prototype_of( |
||||||
|
_: &Value, |
||||||
|
args: &[Value], |
||||||
|
context: &mut Context, |
||||||
|
) -> Result<Value> { |
||||||
|
let target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be an object"))?; |
||||||
|
Ok(target.get_prototype_of()) |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns `true` if the object has the property, `false` otherwise.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.has
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/has
|
||||||
|
pub(crate) fn has(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
||||||
|
let target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be an object"))?; |
||||||
|
let key = args |
||||||
|
.get(1) |
||||||
|
.unwrap_or(&Value::undefined()) |
||||||
|
.to_property_key(context)?; |
||||||
|
Ok(target.has_property(&key).into()) |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns `true` if the object is extensible, `false` otherwise.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.isextensible
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/isExtensible
|
||||||
|
pub(crate) fn is_extensible(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
||||||
|
let target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be an object"))?; |
||||||
|
Ok(target.is_extensible().into()) |
||||||
|
} |
||||||
|
|
||||||
|
/// Returns an array of object own property keys.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.ownkeys
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/ownKeys
|
||||||
|
pub(crate) fn own_keys(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
||||||
|
let target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be an object"))?; |
||||||
|
let array_prototype = context.standard_objects().array_object().prototype(); |
||||||
|
let result: Value = |
||||||
|
Object::with_prototype(array_prototype.into(), ObjectData::Array).into(); |
||||||
|
result.set_property( |
||||||
|
"length", |
||||||
|
DataDescriptor::new( |
||||||
|
0, |
||||||
|
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT, |
||||||
|
), |
||||||
|
); |
||||||
|
|
||||||
|
let keys = target.own_property_keys(); |
||||||
|
for (i, k) in keys.iter().enumerate() { |
||||||
|
result.set_field(i, k, context)?; |
||||||
|
} |
||||||
|
|
||||||
|
Ok(result) |
||||||
|
} |
||||||
|
|
||||||
|
/// Prevents new properties from ever being added to an object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.preventextensions
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/preventExtensions
|
||||||
|
pub(crate) fn prevent_extensions( |
||||||
|
_: &Value, |
||||||
|
args: &[Value], |
||||||
|
context: &mut Context, |
||||||
|
) -> Result<Value> { |
||||||
|
let mut target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be an object"))?; |
||||||
|
|
||||||
|
Ok(target.prevent_extensions().into()) |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets a property of an object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.set
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/set
|
||||||
|
pub(crate) fn set(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
||||||
|
let undefined = Value::undefined(); |
||||||
|
let mut target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be an object"))?; |
||||||
|
let key = args.get(1).unwrap_or(&undefined).to_property_key(context)?; |
||||||
|
let value = args.get(2).unwrap_or(&undefined); |
||||||
|
let receiver = if let Some(receiver) = args.get(3).cloned() { |
||||||
|
receiver |
||||||
|
} else { |
||||||
|
target.clone().into() |
||||||
|
}; |
||||||
|
Ok(target.set(key, value.clone(), receiver, context)?.into()) |
||||||
|
} |
||||||
|
|
||||||
|
/// Sets the prototype of an object.
|
||||||
|
///
|
||||||
|
/// More information:
|
||||||
|
/// - [ECMAScript reference][spec]
|
||||||
|
/// - [MDN documentation][mdn]
|
||||||
|
///
|
||||||
|
/// [spec]: https://tc39.es/ecma262/#sec-reflect.setprototypeof
|
||||||
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/setPrototypeOf
|
||||||
|
pub(crate) fn set_prototype_of( |
||||||
|
_: &Value, |
||||||
|
args: &[Value], |
||||||
|
context: &mut Context, |
||||||
|
) -> Result<Value> { |
||||||
|
let undefined = Value::undefined(); |
||||||
|
let mut target = args |
||||||
|
.get(0) |
||||||
|
.and_then(|v| v.as_object()) |
||||||
|
.ok_or_else(|| context.construct_type_error("target must be an object"))?; |
||||||
|
let proto = args.get(1).unwrap_or(&undefined); |
||||||
|
if !proto.is_null() && !proto.is_object() { |
||||||
|
return context.throw_type_error("proto must be an object or null"); |
||||||
|
} |
||||||
|
Ok(target.set_prototype_of(proto.clone()).into()) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,191 @@ |
|||||||
|
use crate::{forward, Context}; |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn apply() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
var called = {}; |
||||||
|
function f(n) { called.result = n }; |
||||||
|
Reflect.apply(f, undefined, [42]); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "called.result"), "42"); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn construct() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
var called = {}; |
||||||
|
function f(n) { called.result = n }; |
||||||
|
Reflect.construct(f, [42]); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "called.result"), "42"); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn define_property() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
let obj = {}; |
||||||
|
Reflect.defineProperty(obj, 'p', { value: 42 }); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "obj.p"), "42"); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn delete_property() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
let obj = { p: 42 }; |
||||||
|
let deleted = Reflect.deleteProperty(obj, 'p'); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "obj.p"), "undefined"); |
||||||
|
assert_eq!(forward(&mut context, "deleted"), "true"); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn get() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
let obj = { p: 42 } |
||||||
|
let p = Reflect.get(obj, 'p'); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "p"), "42"); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn get_own_property_descriptor() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
let obj = { p: 42 }; |
||||||
|
let desc = Reflect.getOwnPropertyDescriptor(obj, 'p'); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "desc.value"), "42"); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn get_prototype_of() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
function F() { this.p = 42 }; |
||||||
|
let f = new F(); |
||||||
|
let proto = Reflect.getPrototypeOf(f); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "proto.constructor.name"), "\"F\""); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn has() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
let obj = { p: 42 }; |
||||||
|
let hasP = Reflect.has(obj, 'p'); |
||||||
|
let hasP2 = Reflect.has(obj, 'p2'); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "hasP"), "true"); |
||||||
|
assert_eq!(forward(&mut context, "hasP2"), "false"); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn is_extensible() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
let obj = { p: 42 }; |
||||||
|
let isExtensible = Reflect.isExtensible(obj); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "isExtensible"), "true"); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn own_keys() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
let obj = { p: 42 }; |
||||||
|
let ownKeys = Reflect.ownKeys(obj); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "ownKeys"), r#"[ "p" ]"#); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn prevent_extensions() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
let obj = { p: 42 }; |
||||||
|
let r = Reflect.preventExtensions(obj); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "r"), "true"); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn set() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
let obj = {}; |
||||||
|
Reflect.set(obj, 'p', 42); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "obj.p"), "42"); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn set_prototype_of() { |
||||||
|
let mut context = Context::new(); |
||||||
|
|
||||||
|
let init = r#" |
||||||
|
function F() { this.p = 42 }; |
||||||
|
let obj = {} |
||||||
|
Reflect.setPrototypeOf(obj, F); |
||||||
|
let p = Reflect.getPrototypeOf(obj); |
||||||
|
"#; |
||||||
|
|
||||||
|
forward(&mut context, init); |
||||||
|
|
||||||
|
assert_eq!(forward(&mut context, "p.name"), "\"F\""); |
||||||
|
} |
Loading…
Reference in new issue