Source code
Revision control
Copy as Markdown
Other Tools
// |reftest| skip-if(!Object.prototype.toSource)
var BUGNUMBER = 1317400;
var summary = "Function string representation in Object.prototype.toSource";
print(BUGNUMBER + ": " + summary);
// Methods.
assertEq(({ foo(){} }).toSource(),
"({foo(){}})");
assertEq(({ *foo(){} }).toSource(),
"({*foo(){}})");
assertEq(({ async foo(){} }).toSource(),
"({async foo(){}})");
assertEq(({ 1(){} }).toSource(),
"({1(){}})");
// Methods with more spacing.
// Spacing is kept.
assertEq(({ foo (){} }).toSource(),
"({foo (){}})");
assertEq(({ foo () {} }).toSource(),
"({foo () {}})");
// Methods with computed name.
// Method syntax is composed.
let name = "foo";
assertEq(({ [name](){} }).toSource(),
"({foo(){}})");
assertEq(({ *[name](){} }).toSource(),
"({*foo(){}})");
assertEq(({ async [name](){} }).toSource(),
"({async foo(){}})");
assertEq(({ [ Symbol.iterator ](){} }).toSource(),
"({[Symbol.iterator](){}})");
// Accessors.
assertEq(({ get foo(){} }).toSource(),
"({get foo(){}})");
assertEq(({ set foo(v){} }).toSource(),
"({set foo(v){}})");
// Accessors with computed name.
// Method syntax is composed.
assertEq(({ get [name](){} }).toSource(),
"({get foo(){}})");
assertEq(({ set [name](v){} }).toSource(),
"({set foo(v){}})");
assertEq(({ get [ Symbol.iterator ](){} }).toSource(),
"({get [Symbol.iterator](){}})");
assertEq(({ set [ Symbol.iterator ](v){} }).toSource(),
"({set [Symbol.iterator](v){}})");
// Getter and setter with same name.
// Getter always comes before setter.
assertEq(({ get foo(){}, set foo(v){} }).toSource(),
"({get foo(){}, set foo(v){}})");
assertEq(({ set foo(v){}, get foo(){} }).toSource(),
"({get foo(){}, set foo(v){}})");
// Normal properties.
assertEq(({ foo: function(){} }).toSource(),
"({foo:(function(){})})");
assertEq(({ foo: function bar(){} }).toSource(),
"({foo:(function bar(){})})");
assertEq(({ foo: function*(){} }).toSource(),
"({foo:(function*(){})})");
assertEq(({ foo: async function(){} }).toSource(),
"({foo:(async function(){})})");
// Normal properties with computed name.
assertEq(({ [ Symbol.iterator ]: function(){} }).toSource(),
"({[Symbol.iterator]:(function(){})})");
// Dynamically defined properties with function expression.
// Never become a method syntax.
let obj = {};
obj.foo = function() {};
assertEq(obj.toSource(),
"({foo:(function() {})})");
obj = {};
Object.defineProperty(obj, "foo", {value: function() {}});
assertEq(obj.toSource(),
"({})");
obj = {};
Object.defineProperty(obj, "foo", {value: function() {}, enumerable: true});
assertEq(obj.toSource(),
"({foo:(function() {})})");
obj = {};
Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true});
assertEq(obj.toSource(),
"({foo:(function bar() {})})");
obj = {};
Object.defineProperty(obj, Symbol.iterator, {value: function() {}, enumerable: true});
assertEq(obj.toSource(),
"({[Symbol.iterator]:(function() {})})");
// Dynamically defined property with other object's method.
// Method syntax is composed.
let method = ({foo() {}}).foo;
obj = {};
Object.defineProperty(obj, "foo", {value: method, enumerable: true});
assertEq(obj.toSource(),
"({foo() {}})");
obj = {};
Object.defineProperty(obj, "bar", {value: method, enumerable: true});
assertEq(obj.toSource(),
"({bar() {}})");
method = ({*foo() {}}).foo;
obj = {};
Object.defineProperty(obj, "bar", {value: method, enumerable: true});
assertEq(obj.toSource(),
"({*bar() {}})");
method = ({async foo() {}}).foo;
obj = {};
Object.defineProperty(obj, "bar", {value: method, enumerable: true});
assertEq(obj.toSource(),
"({async bar() {}})");
// Dynamically defined accessors.
// Accessor syntax is composed.
obj = {};
Object.defineProperty(obj, "foo", {get: function() {}, enumerable: true});
assertEq(obj.toSource(),
"({get foo() {}})");
obj = {};
Object.defineProperty(obj, "foo", {set: function() {}, enumerable: true});
assertEq(obj.toSource(),
"({set foo() {}})");
obj = {};
Object.defineProperty(obj, Symbol.iterator, {get: function() {}, enumerable: true});
assertEq(obj.toSource(),
"({get [Symbol.iterator]() {}})");
obj = {};
Object.defineProperty(obj, Symbol.iterator, {set: function() {}, enumerable: true});
assertEq(obj.toSource(),
"({set [Symbol.iterator]() {}})");
// Dynamically defined accessors with other object's accessors.
// Accessor syntax is composed.
let accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get;
obj = {};
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
assertEq(obj.toSource(),
"({get foo() {}})");
accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get;
obj = {};
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
assertEq(obj.toSource(),
"({get foo() {}})");
accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set;
obj = {};
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
assertEq(obj.toSource(),
"({get foo(v) {}})");
accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set;
obj = {};
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
assertEq(obj.toSource(),
"({get foo(v) {}})");
accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get;
obj = {};
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
assertEq(obj.toSource(),
"({set foo() {}})");
accessor = Object.getOwnPropertyDescriptor({ get bar() {} }, "bar").get;
obj = {};
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
assertEq(obj.toSource(),
"({set foo() {}})");
accessor = Object.getOwnPropertyDescriptor({ set foo(v) {} }, "foo").set;
obj = {};
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
assertEq(obj.toSource(),
"({set foo(v) {}})");
accessor = Object.getOwnPropertyDescriptor({ set bar(v) {} }, "bar").set;
obj = {};
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
assertEq(obj.toSource(),
"({set foo(v) {}})");
// Methods with proxy.
// Treated as normal property.
method = ({foo() {}}).foo;
let handler = {
get(that, name) {
if (name == "toSource") {
return function() {
return that.toSource();
};
}
return that[name];
}
};
let proxy = new Proxy(method, handler);
obj = {};
Object.defineProperty(obj, "foo", {value: proxy, enumerable: true});
assertEq(obj.toSource(),
"({foo:foo() {}})");
// Accessors with proxy.
// Accessor syntax is composed.
accessor = Object.getOwnPropertyDescriptor({ get foo() {} }, "foo").get;
proxy = new Proxy(accessor, handler);
obj = {};
Object.defineProperty(obj, "foo", {get: proxy, enumerable: true});
assertEq(obj.toSource(),
"({get foo() {}})");
obj = {};
Object.defineProperty(obj, "foo", {set: proxy, enumerable: true});
assertEq(obj.toSource(),
"({set foo() {}})");
// Methods from other global.
// Treated as normal property in the cross-compartment case.
let g = newGlobal();
method = g.eval("({ foo() {} }).foo");
obj = {};
Object.defineProperty(obj, "foo", {value: method, enumerable: true});
assertEq((obj.toSource() === "({foo:foo() {}})" ||
obj.toSource() === "({foo() {}})"),
true);
// Accessors from other global.
// Accessor syntax is composed.
accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get");
obj = {};
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
assertEq(obj.toSource(),
"({get foo() {}})");
accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get");
obj = {};
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
assertEq(obj.toSource(),
"({get foo() {}})");
accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set");
obj = {};
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
assertEq(obj.toSource(),
"({get foo(v) {}})");
accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set");
obj = {};
Object.defineProperty(obj, "foo", {get: accessor, enumerable: true});
assertEq(obj.toSource(),
"({get foo(v) {}})");
accessor = g.eval("Object.getOwnPropertyDescriptor({ get foo() {} }, 'foo').get");
obj = {};
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
assertEq(obj.toSource(),
"({set foo() {}})");
accessor = g.eval("Object.getOwnPropertyDescriptor({ get bar() {} }, 'bar').get");
obj = {};
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
assertEq(obj.toSource(),
"({set foo() {}})");
accessor = g.eval("Object.getOwnPropertyDescriptor({ set foo(v) {} }, 'foo').set");
obj = {};
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
assertEq(obj.toSource(),
"({set foo(v) {}})");
accessor = g.eval("Object.getOwnPropertyDescriptor({ set bar(v) {} }, 'bar').set");
obj = {};
Object.defineProperty(obj, "foo", {set: accessor, enumerable: true});
assertEq(obj.toSource(),
"({set foo(v) {}})");
// **** Some weird cases ****
// Accessors with generator or async.
obj = {};
Object.defineProperty(obj, "foo", {get: function*() {}, enumerable: true});
assertEq(obj.toSource(),
"({get foo() {}})");
obj = {};
Object.defineProperty(obj, "foo", {set: async function() {}, enumerable: true});
assertEq(obj.toSource(),
"({set foo() {}})");
// Modified toSource.
obj = { foo() {} };
obj.foo.toSource = () => "hello";
assertEq(obj.toSource(),
"({hello})");
obj = { foo() {} };
obj.foo.toSource = () => "bar() {}";
assertEq(obj.toSource(),
"({bar() {}})");
// Modified toSource with different method name.
obj = {};
Object.defineProperty(obj, "foo", {value: function bar() {}, enumerable: true});
obj.foo.toSource = () => "hello";
assertEq(obj.toSource(),
"({foo:hello})");
obj = {};
Object.defineProperty(obj, "foo", {value: function* bar() {}, enumerable: true});
obj.foo.toSource = () => "hello";
assertEq(obj.toSource(),
"({foo:hello})");
obj = {};
Object.defineProperty(obj, "foo", {value: async function bar() {}, enumerable: true});
obj.foo.toSource = () => "hello";
assertEq(obj.toSource(),
"({foo:hello})");
if (typeof reportCompare === "function")
reportCompare(true, true);