Browse Source

Fix: Make Object.toString() spec compliant*

Test: Add testing of Object.toString(), need update once
Function.prototype.call is implemented

* not fully because Arguments Exotic Objects are not yet implemented
pull/737/head
RageKnify 4 years ago
parent
commit
5e3db42e63
  1. 30
      boa/src/builtins/object/mod.rs
  2. 42
      boa/src/builtins/object/tests.rs

30
boa/src/builtins/object/mod.rs

@ -115,9 +115,33 @@ impl Object {
/// [spec]: https://tc39.es/ecma262/#sec-object.prototype.tostring /// [spec]: https://tc39.es/ecma262/#sec-object.prototype.tostring
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
pub fn to_string(_: &Value, _: &[Value], _: &mut Context) -> Result<Value> { pub fn to_string(this: &Value, _: &[Value], ctx: &mut Context) -> Result<Value> {
// FIXME: it should not display the object. if this.is_undefined() {
Ok("[object Object]".into()) Ok("[object Undefined]".into())
} else if this.is_null() {
Ok("[object Null]".into())
} else {
let gc_o = this.to_object(ctx)?;
let o = gc_o.borrow();
let builtin_tag = match &o.data {
ObjectData::Array => "Array",
// TODO: Arguments Exotic Objects are currently not supported
ObjectData::Function(_) => "Function",
ObjectData::Error => "Error",
ObjectData::Boolean(_) => "Boolean",
ObjectData::Number(_) => "Number",
ObjectData::String(_) => "String",
ObjectData::Date(_) => "Date",
ObjectData::RegExp(_) => "RegExp",
_ => "Object",
};
let tag = o.get(&ctx.well_known_symbols().to_string_tag_symbol().into());
let tag_str = tag.as_string().map(|s| s.as_str()).unwrap_or(builtin_tag);
Ok(format!("[object {}]", tag_str).into())
}
} }
/// `Object.prototype.hasOwnPrototype( property )` /// `Object.prototype.hasOwnPrototype( property )`

42
boa/src/builtins/object/tests.rs

@ -55,7 +55,7 @@ fn object_create_with_number() {
#[test] #[test]
#[ignore] #[ignore]
// to test on __proto__ somehow. __proto__ getter is not working as expected currently // TODO: to test on __proto__ somehow. __proto__ getter is not working as expected currently
fn object_create_with_function() { fn object_create_with_function() {
let mut engine = Context::new(); let mut engine = Context::new();
@ -135,3 +135,43 @@ fn object_property_is_enumerable() {
); );
assert_eq!(forward(&mut engine, r#"x.propertyIsEnumerable()"#), "false",) assert_eq!(forward(&mut engine, r#"x.propertyIsEnumerable()"#), "false",)
} }
#[test]
fn object_to_string() {
let mut ctx = Context::new();
let init = r#"
let u = undefined;
let n = null;
let a = [];
Array.prototype.toString = Object.prototype.toString;
let f = () => {};
Function.prototype.toString = Object.prototype.toString;
let b = Boolean();
Boolean.prototype.toString = Object.prototype.toString;
let i = Number(42);
Number.prototype.toString = Object.prototype.toString;
let s = String('boa');
String.prototype.toString = Object.prototype.toString;
let d = new Date(Date.now());
Date.prototype.toString = Object.prototype.toString;
let re = /boa/;
RegExp.prototype.toString = Object.prototype.toString;
"#;
eprintln!("{}", forward(&mut ctx, init));
// TODO: need Function.prototype.call to be implemented
// assert_eq!(
// forward(&mut ctx, "Object.prototype.toString.call(u)"),
// "\"[object Undefined]\""
// );
// assert_eq!(
// forward(&mut ctx, "Object.prototype.toString.call(n)"),
// "\"[object Null]\""
// );
assert_eq!(forward(&mut ctx, "a.toString()"), "\"[object Array]\"");
assert_eq!(forward(&mut ctx, "f.toString()"), "\"[object Function]\"");
assert_eq!(forward(&mut ctx, "b.toString()"), "\"[object Boolean]\"");
assert_eq!(forward(&mut ctx, "i.toString()"), "\"[object Number]\"");
assert_eq!(forward(&mut ctx, "s.toString()"), "\"[object String]\"");
assert_eq!(forward(&mut ctx, "d.toString()"), "\"[object Date]\"");
assert_eq!(forward(&mut ctx, "re.toString()"), "\"[object RegExp]\"");
}

Loading…
Cancel
Save