mirror of https://github.com/svaarala/duktape.git
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.
335 lines
8.6 KiB
335 lines
8.6 KiB
// XXX: 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);
|
|
}
|
|
|