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.

450 lines
17 KiB

// FIXME: util
function printDesc(obj, key) {
var pd = Object.getOwnPropertyDescriptor(obj, key);
if (!pd) {
print(key, 'nonexistent');
return;
}
print(key,
'value=' + pd.value,
'writable=' + pd.writable,
'enumerable=' + pd.enumerable,
'configurable=' + pd.configurable,
'get=' + typeof pd.get,
'set=' + typeof pd.set);
}
function dumpValue(v) {
var i, n;
var tmp = [];
if (v === undefined) {
return 'undefined';
} else if (v === null) {
return 'null';
}
n = Math.floor(v.length);
for (i = 0; i < n; i++) {
if (v.hasOwnProperty(i)) {
tmp.push(v[i]);
} else {
tmp.push('nonexistent');
}
}
return typeof v + ' ' + v.length + ' ' + tmp.join(',');
}
function test(this_value, args, no_pre_post) {
var t;
if (args === undefined) {
args = [];
}
try {
if (!no_pre_post) {
print('pre', dumpValue(this_value));
}
t = Array.prototype.unshift.apply(this_value, args);
print(typeof t, t);
} catch (e) {
print(e.name);
}
if (!no_pre_post) {
print('post', dumpValue(this_value));
}
}
/*===
basic
pre object 0
number 0
post object 0
pre object 1 1
number 1
post object 1 1
pre object 2 1,2
number 2
post object 2 1,2
pre object 3 1,2,3
number 3
post object 3 1,2,3
pre object 0
number 1
post object 1 foo
pre object 1 1
number 2
post object 2 foo,1
pre object 2 1,2
number 3
post object 3 foo,1,2
pre object 3 1,2,3
number 4
post object 4 foo,1,2,3
pre object 0
number 2
post object 2 foo,bar
pre object 1 1
number 3
post object 3 foo,bar,1
pre object 2 1,2
number 4
post object 4 foo,bar,1,2
pre object 3 1,2,3
number 5
post object 5 foo,bar,1,2,3
pre object 0
number 3
post object 3 foo,bar,quux
pre object 1 1
number 4
post object 4 foo,bar,quux,1
pre object 2 1,2
number 5
post object 5 foo,bar,quux,1,2
pre object 3 1,2,3
number 6
post object 6 foo,bar,quux,1,2,3
pre object 101 1,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,2,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,3
number 103
post object 103 foo,bar,1,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,2,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,3
pre object 101 1,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,2,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,3
number 102
post object 102 foo,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,baz,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,quux,1,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,2,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,nonexistent,3
pre object 3 1,2,3
number 5
post object 5 foo,bar,1,2,3
pre object 3 1,2,3
number 5
post object 5 foo,bar,1,2,3
pre object 10 nonexistent,nonexistent,3,nonexistent,nonexistent,6,nonexistent,nonexistent,nonexistent,nonexistent
number 12
post object 12 foo,bar,nonexistent,nonexistent,3,nonexistent,nonexistent,6,nonexistent,nonexistent,nonexistent,nonexistent
false undefined
pre object undefined
number 0
post object 0
true 0
===*/
print('basic');
function basicTest() {
var obj, obj2;
// basic dense array tests
test([]);
test([1]);
test([1,2]);
test([1,2,3]);
test([], ['foo']);
test([1], ['foo']);
test([1,2], ['foo']);
test([1,2,3], ['foo']);
test([], ['foo','bar']);
test([1], ['foo','bar']);
test([1,2], ['foo','bar']);
test([1,2,3], ['foo','bar']);
test([], ['foo','bar','quux']);
test([1], ['foo','bar','quux']);
test([1,2], ['foo','bar','quux']);
test([1,2,3], ['foo','bar','quux']);
// sparse array tests
obj=[1]; obj[100]=3; obj[50]=2;
test(obj, ['foo', 'bar']);
obj=[1]; obj[100]=3; obj[50]=2;
obj2=['foo']; obj2[100]='quux'; obj2[50]='baz';
test(obj, [obj2]); // obj2 is inserted "as is"
// non-array tests
obj = { '0': '1', '1': '2', '2': '3', length: 3 }; // basic
test(obj, ['foo','bar']);
obj = { '0': '1', '1': '2', '2': '3', '3': 'out-4', '4': 'out-5', '5': 'out-6', length: 3 }; // out of length range elements
test(obj, ['foo','bar']);
obj = { '2': '3', '5': '6', length: 10 }; // sparse this
test(obj, ['foo','bar']);
// if a non-array has no 'length', it will be treated like zero length
// (ToUint32(undefined) = 0); in particular, step 10 writes a length field
// to the object
obj = {};
print(obj.hasOwnProperty('length'), obj.length);
test(obj);
print(obj.hasOwnProperty('length'), obj.length);
}
try {
basicTest();
} catch (e) {
print(e);
}
/*===
attributes
2 getter
3 getter
pre object 4 1,2,3,4
3 getter
2 getter
3 setter 2
2 setter 1
number 6
2 getter
3 getter
post object 6 foo,bar,1,2,3,4
2 getter
3 getter
6 foo bar 1 2 3 4
length value=6 writable=true enumerable=true configurable=true get=undefined set=undefined
0 value=foo writable=true enumerable=false configurable=false get=undefined set=undefined
1 value=bar writable=true enumerable=true configurable=true get=undefined set=undefined
2 value=undefined writable=undefined enumerable=false configurable=false get=function set=function
3 value=undefined writable=undefined enumerable=true configurable=true get=function set=function
4 value=3 writable=true enumerable=true configurable=true get=undefined set=undefined
5 value=4 writable=true enumerable=true configurable=true get=undefined set=undefined
pre object 6 1,2,nonexistent,4,nonexistent,6
number 9
post object 9 foo,bar,quux,1,2,nonexistent,4,nonexistent,6
9 foo bar quux 1 2 undefined 4 undefined 6
length value=9 writable=true enumerable=true configurable=true get=undefined set=undefined
0 value=foo writable=true enumerable=false configurable=true get=undefined set=undefined
1 value=bar writable=true enumerable=false configurable=true get=undefined set=undefined
2 value=quux writable=true enumerable=true configurable=true get=undefined set=undefined
3 value=1 writable=true enumerable=false configurable=true get=undefined set=undefined
4 value=2 writable=true enumerable=true configurable=true get=undefined set=undefined
5 nonexistent
6 value=4 writable=true enumerable=true configurable=true get=undefined set=undefined
7 nonexistent
8 value=6 writable=true enumerable=true configurable=true get=undefined set=undefined
===*/
print('attributes');
function attributesTest() {
var obj;
// Step 6 makes room for unshifted value by copying values upwards,
// but values in the empty space are not [[Delete]]'d, so the slots
// will retain their attributes (and e.g. accessors remain accessors).
// The elements can also be non-configurable because they're not deleted.
obj = {}
obj.my2 = 3;
obj.my3 = 4;
Object.defineProperties(obj, {
'0': { value: 1, writable: true, enumerable: false, configurable: false },
'1': { value: 2, writable: true, enumerable: true, configurable: true },
'2': { get: function() { print('2 getter'); return this.my2; },
set: function(v) { print('2 setter', v); this.my2 = v; },
enumerable: false, configurable: false },
'3': { get: function() { print('3 getter'); return this.my3; },
set: function(v) { print('3 setter', v); this.my3 = v; },
enumerable: true, configurable: true }
});
obj.length = 4;
test(obj, ['foo','bar']);
print(obj.length, obj[0], obj[1], obj[2], obj[3], obj[4], obj[5]);
printDesc(obj, 'length');
printDesc(obj, '0');
printDesc(obj, '1');
printDesc(obj, '2');
printDesc(obj, '3');
printDesc(obj, '4');
printDesc(obj, '5');
// Step 6 copies values upwards by the required amount, e.g. if 3 values
// are unshifted, len-1 is copied to len+2, len-2 is copied to len+1,
// and so on, '0' is copied to '3'. If the source exists, a [[Get]]+[[Put]]
// sequence is used; otherwise a [[Delete]] is used. When both the source
// and destination exist, the destination will retain its attributes.
//
// As above, the elements in the "room" for unshift are not [[Delete]]'d,
// so they retain their attributes.
obj = {}
Object.defineProperties(obj, {
// 0->3: both exist
// 1->4: source exists, target does not
// 2->5: source does not exist, target does
// 3->6: source exists, target does not
// 4->7: neither exist
// 5->8: source exists, target does not
'0': { value: 1, writable: true, enumerable: false, configurable: true },
'1': { value: 2, writable: true, enumerable: false, configurable: true },
// 2 does not exist
'3': { value: 4, writable: true, enumerable: false, configurable: true },
// 4 does not exist
'5': { value: 6, writable: true, enumerable: false, configurable: true },
});
obj.length = 6;
test(obj, ['foo','bar','quux']);
print(obj.length, obj[0], obj[1], obj[2], obj[3], obj[4], obj[5], obj[6], obj[7], obj[8]);
printDesc(obj, 'length');
for (i = 0; i < 9; i++) {
printDesc(obj, String(i));
}
}
try {
attributesTest();
} catch (e) {
print(e);
}
/*===
mutation
===*/
print('mutation');
function mutationTest() {
// FIXME
}
try {
mutationTest();
} catch (e) {
print(e);
}
/*===
protected
false undefined
pre object undefined
TypeError
post object undefined
false undefined
===*/
print('protected');
function protectedTest() {
var obj;
// non-extensible object without 'length'; a 'length' property
// cannot be added
obj = {};
Object.preventExtensions(obj);
print(obj.hasOwnProperty('length'), obj.length);
test(obj);
print(obj.hasOwnProperty('length'), obj.length);
// FIXME: copy loop, side effects
// FIXME: copy loop, protected
// final length is not updated until step 10 (mostly matters for
// non-arrays)
}
try {
protectedTest();
} catch (e) {
print(e.name);
}
/*===
coercion
pre undefined
TypeError
post undefined
pre null
TypeError
post null
pre boolean undefined
number 0
post boolean undefined
pre boolean undefined
number 0
post boolean undefined
pre number undefined
number 0
post number undefined
pre string 3 f,o,o
TypeError
post string 3 f,o,o
pre object 2 1,2
number 2
post object 2 1,2
pre object undefined
number 0
post object 0
string 3.9 foo bar quux baz undefined undefined undefined
number 5
number 5 1 2 foo bar quux undefined undefined
number 4294967299.9 foo bar quux baz undefined undefined undefined
number 5
number 5 1 2 foo bar quux undefined undefined
number -4294967292.1 foo bar quux baz undefined undefined undefined
number 6
number 6 1 2 foo bar quux baz undefined
length toString
object 3 foo bar quux baz undefined undefined undefined
length valueOf
number 5
number 5 1 2 foo bar quux undefined undefined
===*/
print('coercion');
function coercionTest() {
var obj;
// this coercion
test(undefined);
test(null);
test(true);
test(false);
test(123);
test('foo'); // TypeError, because attempt to write non-writable length must fail
test([1,2]);
test({ foo: 1, bar: 2 });
// length coercion
obj = { '0': 'foo', '1': 'bar', '2': 'quux', '3': 'baz', length: '3.9' };
print(typeof obj.length, obj.length, obj[0], obj[1], obj[2], obj[3], obj[4], obj[5], obj[6]);
test(obj, [1,2], true);
print(typeof obj.length, obj.length, obj[0], obj[1], obj[2], obj[3], obj[4], obj[5], obj[6]);
obj = { '0': 'foo', '1': 'bar', '2': 'quux', '3': 'baz', length: 256*256*256*256 + 3.9 };
print(typeof obj.length, obj.length, obj[0], obj[1], obj[2], obj[3], obj[4], obj[5], obj[6]);
test(obj, [1,2], true);
print(typeof obj.length, obj.length, obj[0], obj[1], obj[2], obj[3], obj[4], obj[5], obj[6]);
obj = { '0': 'foo', '1': 'bar', '2': 'quux', '3': 'baz', length: -256*256*256*256 + 3.9 };
print(typeof obj.length, obj.length, obj[0], obj[1], obj[2], obj[3], obj[4], obj[5], obj[6]);
test(obj, [1,2], true);
print(typeof obj.length, obj.length, obj[0], obj[1], obj[2], obj[3], obj[4], obj[5], obj[6]);
obj = { '0': 'foo', '1': 'bar', '2': 'quux', '3': 'baz', length: {
toString: function() { print('length toString'); return 3; },
valueOf: function() { print('length valueOf'); return 3; },
} };
print(typeof obj.length, obj.length, obj[0], obj[1], obj[2], obj[3], obj[4], obj[5], obj[6]);
test(obj, [1,2], true);
print(typeof obj.length, obj.length, obj[0], obj[1], obj[2], obj[3], obj[4], obj[5], obj[6]);
}
try {
coercionTest();
} catch (e) {
print(e.name);
}