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.

346 lines
9.0 KiB

// return value does not matter
function retUndef(val, key, obj) {
print(typeof this, this, typeof val, val, typeof key, key, typeof obj, obj);
}
function test(this_value, args) {
var t;
try {
t = Array.prototype.forEach.apply(this_value, args);
print(typeof t, t);
} catch (e) {
print(e.name);
}
}
/*===
basic
undefined undefined
object [object global] number 1 number 0 object 1
undefined undefined
object [object global] number 1 number 0 object 1,2
object [object global] number 2 number 1 object 1,2
undefined undefined
object [object global] number 1 number 0 object 1,2,3,4,5
object [object global] number 2 number 1 object 1,2,3,4,5
object [object global] number 3 number 2 object 1,2,3,4,5
object [object global] number 4 number 3 object 1,2,3,4,5
object [object global] number 5 number 4 object 1,2,3,4,5
undefined undefined
object [object global] number 1 number 0 object 1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3
object [object global] number 2 number 50 object 1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3
object [object global] number 3 number 100 object 1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3
undefined undefined
object [object global] string foo number 0 object [object Object]
object [object global] string bar number 5 object [object Object]
object [object global] string quux number 20 object [object Object]
undefined undefined
callback 0
callback 1
callback 2
callback 3
callback 4
callback 5
callback 6
callback 7
callback 8
callback 9
undefined undefined
callback 1
CallbackError
nonstrict object
nonstrict object
nonstrict object
undefined undefined
nonstrict object
nonstrict object
nonstrict object
undefined undefined
nonstrict object
nonstrict object
nonstrict object
undefined undefined
strict undefined undefined
strict undefined undefined
strict undefined undefined
undefined undefined
strict object null
strict object null
strict object null
undefined undefined
strict string foo
strict string foo
strict string foo
undefined undefined
===*/
print('basic');
function basicTest() {
var obj;
var count;
// simple cases
test([], [ retUndef ]);
test([1], [ retUndef ]);
test([1,2], [ retUndef ]);
// dense
test([1,2,3,4,5], [ retUndef ]);
// sparse
obj = [1];
obj[100] = 3;
obj[50] = 2;
test(obj, [ retUndef ]);
// non-array
obj = { '0': 'foo', '5': 'bar', '20': 'quux', '100': 'baz', length: 35 };
test(obj, [ retUndef ]);
// return value doesn't matter, return value is not coerced
count = 3;
test([1,2,3,4,5,6,7,8,9,10], [ function(val, key, obj) {
print('callback', key); if (count == 0) { return 0; }; count--; return 1;
}]);
// error in callback propagates outwards
test([1,2,3], [ function(val, key, obj) {
var e;
print('callback', val);
e = new Error('callback error');
e.name = 'CallbackError';
throw e;
}]);
// this binding, non-strict callbacks gets a coerced binding
test([1,2,3], [ function(val, key, obj) {
print('nonstrict', typeof this);
}]);
test([1,2,3], [ function(val, key, obj) {
print('nonstrict', typeof this);
}, null]);
test([1,2,3], [ function(val, key, obj) {
print('nonstrict', typeof this);
}, 'foo']);
test([1,2,3], [ function(val, key, obj) {
'use strict';
print('strict', typeof this, this);
}]);
test([1,2,3], [ function(val, key, obj) {
'use strict';
print('strict', typeof this, this);
}, null]); // Note: typeof null -> 'object'
test([1,2,3], [ function(val, key, obj) {
'use strict';
print('strict', typeof this, this);
}, 'foo']);
}
try {
basicTest();
} catch (e) {
print(e);
}
/*===
mutation
foo 0 foo,bar,quux
bar 1 foo,bar,quux,baz
quux 2 foo,bar,quux,baz
undefined undefined
foo 0 foo,bar,quux
quux 2 foo,,quux
undefined undefined
foo 0 [object Object]
bar 1 [object Object]
quux 2 [object Object]
undefined undefined
foo 0 [object Object]
quux 2 [object Object]
undefined undefined
===*/
print('mutation');
function mutationTest() {
var obj;
// added element not recognized
obj = [ 'foo', 'bar', 'quux' ];
test(obj, [ function (val, key, obj) {
print(val, key, obj);
obj[3] = 'baz';
}]);
// deleted element not processed
obj = [ 'foo', 'bar', 'quux' ];
test(obj, [ function (val, key, obj) {
print(val, key, obj);
delete obj[1];
}]);
// same for non-array
obj = { '0': 'foo', '1': 'bar', '2': 'quux', '3': 'baz', length: 3 };
test(obj, [ function (val, key, obj) {
print(val, key, obj);
obj[4] = 'quuux';
obj.length = 10;
}]);
obj = { '0': 'foo', '1': 'bar', '2': 'quux', '3': 'baz', length: 3 };
test(obj, [ function (val, key, obj) {
print(val, key, obj);
delete obj[3]; delete obj[1];
obj.length = 0;
}]);
}
try {
mutationTest();
} catch (e) {
print(e);
}
/*===
coercion
TypeError
TypeError
undefined undefined
undefined undefined
undefined undefined
object [object global] string f number 0 object foo
object [object global] string o number 1 object foo
object [object global] string o number 2 object foo
undefined undefined
object [object global] number 1 number 0 object 1,2,3
object [object global] number 2 number 1 object 1,2,3
object [object global] number 3 number 2 object 1,2,3
undefined undefined
undefined undefined
object [object global] string foo number 0 object [object Object]
object [object global] string bar number 1 object [object Object]
object [object global] string quux number 2 object [object Object]
undefined undefined
object [object global] string foo number 0 object [object Object]
object [object global] string bar number 1 object [object Object]
object [object global] string quux number 2 object [object Object]
undefined undefined
object [object global] string foo number 0 object [object Object]
object [object global] string bar number 1 object [object Object]
object [object global] string quux number 2 object [object Object]
object [object global] string baz number 3 object [object Object]
undefined undefined
length valueOf
object [object global] string foo number 0 object [object Object]
object [object global] string bar number 1 object [object Object]
object [object global] string quux number 2 object [object Object]
undefined undefined
length valueOf
TypeError
callback 1 0 1,2,3,4,5,6,7,8,9,10
callback 2 1 1,2,3,4,5,6,7,8,9,10
callback 3 2 1,2,3,4,5,6,7,8,9,10
callback 4 3 1,2,3,4,5,6,7,8,9,10
callback 5 4 1,2,3,4,5,6,7,8,9,10
callback 6 5 1,2,3,4,5,6,7,8,9,10
callback 7 6 1,2,3,4,5,6,7,8,9,10
callback 8 7 1,2,3,4,5,6,7,8,9,10
callback 9 8 1,2,3,4,5,6,7,8,9,10
callback 10 9 1,2,3,4,5,6,7,8,9,10
undefined undefined
===*/
print('coercion');
function coercionTest() {
var obj;
// this
test(undefined, [ retUndef ]);
test(null, [ retUndef ]);
test(true, [ retUndef ]);
test(false, [ retUndef ]);
test(123, [ retUndef ]);
test('foo', [ retUndef ]);
test([1,2,3], [ retUndef ]);
test({ foo: 1, bar: 2 }, [ retUndef ]);
// length
obj = { '0': 'foo', '1': 'bar', '2': 'quux', '3': 'baz', '4': 'quux', length: '3.9' };
test(obj, [ retUndef ]);
obj = { '0': 'foo', '1': 'bar', '2': 'quux', '3': 'baz', '4': 'quux', length: 256*256*256*256 + 3.9 }; // coerces to 3
test(obj, [ retUndef ]);
obj = { '0': 'foo', '1': 'bar', '2': 'quux', '3': 'baz', '4': 'quux', length: -256*256*256*256 + 3.9 }; // coerces to 4
test(obj, [ retUndef ]);
obj = { '0': 'foo', '1': 'bar', '2': 'quux', 'length': {
toString: function() {
print('length toString');
return 4;
},
valueOf: function() {
print('length valueOf');
return 3;
}
}};
test(obj, [ retUndef ]);
// callable check is done after length coercion
obj = { '0': 'foo', '1': 'bar', '2': 'quux', 'length': {
toString: function() {
print('length toString');
return 4;
},
valueOf: function() {
print('length valueOf');
return 3;
}
}};
test(obj, [ null ]);
// callback return value does not matter; no boolean coercion happens for forEach
test([1,2,3,4,5,6,7,8,9,10], [ function (val, key, obj) {
print('callback', val, key, obj);
if (key == 0) { return 1.0; } /*true*/
else if (key == 1) { return 'foo'; } /*true*/
else if (key == 2) {
// Note: object is always 'true', no coercion related calls are made
return {
toString: function() { print('callback retval toString'); return 0; },
valueOf: function() { print('callback retval valueOf'); return key == 1 ? '' /*false*/ : 'foo' /*true*/; }
};
} else {
return ''; /*false*/
}
} ]);
}
try {
coercionTest();
} catch (e) {
print(e);
}