371 lines
11 KiB
JavaScript
371 lines
11 KiB
JavaScript
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.
|
|
|
|
let g = newGlobal();
|
|
|
|
method = g.eval("({ foo() {} }).foo");
|
|
|
|
obj = {};
|
|
Object.defineProperty(obj, "foo", {value: method, enumerable: true});
|
|
assertEq(obj.toSource(),
|
|
"({foo:foo() {}})");
|
|
|
|
// 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);
|