You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

336 lines
8.6 KiB

// FIXME: util
function formatValue(v) {
if (typeof v === 'function') {
// avoid implementation dependent string formatting
if (v.funcName) {
return '[function ' + v.funcName + ']';
} else {
return Object.prototype.toString.call(v);
}
}
if (typeof v === 'number') {
if (v === 0) {
if (1/v === Number.NEGATIVE_INFINITY) {
// format negative zero specially to detect them in the output
return '-0';
}
}
}
return String(v);
}
function getDesc(obj, prop) {
var pd;
if (typeof obj !== 'object' || obj === null) {
return prop + ': non-object (' + Object.prototype.toString.call(obj) + ')';
}
pd = Object.getOwnPropertyDescriptor(obj, prop);
if (pd === undefined) {
return prop + ': undefined';
}
return prop + ': ' +
'value=' + formatValue(pd.value) +
', writable=' + formatValue(pd.writable) +
', enumerable=' + formatValue(pd.enumerable) +
', configurable=' + formatValue(pd.configurable) +
', typeof(get)=' + formatValue(pd.get) +
', typeof(set)=' + formatValue(pd.set);
}
function printDesc(obj, prop) {
print(getDesc(obj, prop));
}
/*===
coercion
[object Undefined] [object Undefined] TypeError
[object Undefined] [object Object] TypeError
[object Null] [object Object] TypeError
[object Boolean] [object Object] TypeError
[object Boolean] [object Object] TypeError
[object Number] [object Object] TypeError
[object String] [object Object] TypeError
[object Array] [object Object] ok
[object Object] [object Object] ok
[object Object] [object Undefined] TypeError
[object Object] [object Undefined] TypeError
[object Object] [object Null] TypeError
[object Object] [object Boolean] ok
[object Object] [object Boolean] ok
[object Object] [object Number] ok
[object Object] [object String] ok
[object Object] [object Array] ok
[object Object] [object Object] ok
===*/
/* Test coercion of 'O' and 'Properties' arguments. */
print('coercion');
function coercionTest() {
function test(o, p, arg_count) {
var t;
try {
if (arg_count === 0) {
t = Object.defineProperties();
} else if (arg_count === 1) {
t = Object.defineProperties(o);
} else {
t = Object.defineProperties(o, p);
}
print(Object.prototype.toString.call(o),
Object.prototype.toString.call(p), 'ok');
} catch (e) {
print(Object.prototype.toString.call(o),
Object.prototype.toString.call(p), e.name);
}
}
// coercion of 'O'
test(undefined, undefined, 0);
test(undefined, {});
test(null, {});
test(true, {});
test(false, {});
test(123, {});
test('quux', {});
test([1,2], {});
test({ foo: 1, bar: 2 }, {});
// coercion of 'P'
test({}, undefined, 1);
test({}, undefined);
test({}, null);
test({}, true);
test({}, false);
test({}, 123);
test({}, ''); // <-- careful to avoid TypeError from ToPropertyDescriptor()
test({}, []); // (use empty string, array, object)
test({}, {}); //
// coercion of 'O' and 'P'; 'O' is checked first -- how to test this?
}
try {
coercionTest();
} catch (e) {
print(e);
}
/*===
proplist
prop1
prop2
proto-prop
proto-prop: undefined
nonenum-prop: undefined
prop1: value=prop1, writable=true, enumerable=true, configurable=true, typeof(get)=undefined, typeof(set)=undefined
prop2: value=prop2, writable=true, enumerable=true, configurable=true, typeof(get)=undefined, typeof(set)=undefined
prop1
prop2
===*/
/* Property list is created from own, enumerable properties of 'Properties'
* argument.
*
* This test expects enum order to match insertion order (but the testcase
* is not marked custom).
*/
print('proplist');
function propListTest() {
var proto = {};
var props;
var obj;
var i;
props = Object.create(proto);
// enumerable, but not 'own property'
Object.defineProperty(proto, 'proto-prop', {
value: { value: 'from-proto', writable: true, enumerable: true, configurable: true },
writable: true, enumerable: true, configurable: true
});
// own property but not enumerable
Object.defineProperty(props, 'nonenum-prop', {
value: { value: 'nonenum', writable: true, enumerable: true, configurable: true },
writable: true, enumerable: false, configurable: true
});
// own property, enumerable -> will appear
Object.defineProperty(props, 'prop1', {
value: { value: 'prop1', writable: true, enumerable: true, configurable: true },
writable: true, enumerable: true, configurable: true
});
Object.defineProperty(props, 'prop2', {
value: { value: 'prop2', writable: true, enumerable: true, configurable: true },
writable: false, enumerable: true, configurable: false
});
// for-in will enumerate also inherited properties
for (i in props) {
print(i);
}
obj = {};
Object.defineProperties(obj, props);
printDesc(obj, 'proto-prop');
printDesc(obj, 'nonenum-prop');
printDesc(obj, 'prop1');
printDesc(obj, 'prop2');
// prop1 and prop2 addition order should match order in 'props'
for (i in obj) {
print(i);
}
}
try {
propListTest();
} catch (e) {
print(e);
}
/*===
topropdesc
foo: value=2, writable=true, enumerable=true, configurable=true, typeof(get)=undefined, typeof(set)=undefined
TypeError
foo: value=1, writable=true, enumerable=true, configurable=true, typeof(get)=undefined, typeof(set)=undefined
===*/
/* All ToPropertyDescriptor() coercions and checks happen before any object
* properties/attributes are changed.
*/
print('topropdesc');
function toPropDescTest() {
var obj;
// base case: works
obj = { foo: 1 };
Object.defineProperties(obj, {
foo: { value: 2 }
});
printDesc(obj, 'foo');
// invalid desc -> nothing is changed
obj = { foo: 1 };
try {
Object.defineProperties(obj, {
foo: { value: 3 }, // ok
bar: { set: function(){}, value: 123 } // conflict
});
} catch (e) {
print(e.name);
}
printDesc(obj, 'foo');
}
try {
toPropDescTest();
} catch (e) {
print(e);
}
/*===
multiple
foo: value=1, writable=true, enumerable=true, configurable=true, typeof(get)=undefined, typeof(set)=undefined
bar: value=2, writable=false, enumerable=true, configurable=false, typeof(get)=undefined, typeof(set)=undefined
foo
bar
TypeError
foo: value=1, writable=true, enumerable=true, configurable=true, typeof(get)=undefined, typeof(set)=undefined
bar: value=immutable, writable=false, enumerable=false, configurable=false, typeof(get)=undefined, typeof(set)=undefined
foo
===*/
/* Multiple changes in one go. Note that since 'Properties' is an Object,
* the same property cannot be edited twice in one defineProperties() call.
*
* Unlike the ToPropertyDescriptor() step, the first TypeError (or other
* error) causes defineProperties() to bail out.
*/
print('multiple');
function multiplePropsTest() {
var obj;
var i;
// base case
obj = {};
Object.defineProperties(obj, {
foo: { value: 1, writable: true, enumerable: true, configurable: true },
bar: { value: 2, writable: false, enumerable: true, configurable: false }
});
printDesc(obj, 'foo');
printDesc(obj, 'bar');
for (i in obj) {
// demonstrate enum order
print(i);
}
// first edit bails out, so second one is not made
obj = {};
Object.defineProperty(obj, 'foo', {
value: 'configurable', writable: false, enumerable: false, configurable: true
});
Object.defineProperty(obj, 'bar', {
value: 'immutable', writable: false, enumerable: false, configurable: false
});
try {
Object.defineProperties(obj, {
foo: { value: 1, writable: true, enumerable: true, configurable: true },
bar: { value: 2, writable: false, enumerable: true, configurable: false }
});
} catch (e) {
print(e.name);
}
printDesc(obj, 'foo');
printDesc(obj, 'bar');
for (i in obj) {
// demonstrate enum order
print(i);
}
}
try {
multiplePropsTest();
} catch (e) {
print(e);
}
/*===
return
true
===*/
/* Return value is 'O'. */
print('return');
function returnValueTest() {
var obj = {};
var ret;
ret = Object.defineProperties(obj, {
foo: { value: 1, writable: true, enumerable: true, configurable: true }
});
print(ret === obj);
}
try {
returnValueTest();
} catch (e) {
print(e);
}