mirror of https://github.com/svaarala/duktape.git
Sami Vaarala
8 years ago
10 changed files with 499 additions and 3 deletions
@ -0,0 +1,91 @@ |
|||||
|
/* |
||||
|
* Test that .bind(), .call(), and .apply() can be used in various |
||||
|
* combinations. |
||||
|
*/ |
||||
|
|
||||
|
/*=== |
||||
|
[object global] 1 2 3 undefined undefined undefined undefined undefined undefined undefined |
||||
|
arguments: 3 1 2 3 undefined undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
mythis 101 102 undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
arguments: 2 101 102 undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
mythis 101 102 103 undefined undefined undefined undefined undefined undefined undefined |
||||
|
arguments: 3 101 102 103 undefined undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
mythis 101 102 103 104 undefined undefined undefined undefined undefined undefined |
||||
|
arguments: 4 101 102 103 104 undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
mythis 101 102 103 104 105 undefined undefined undefined undefined undefined |
||||
|
arguments: 5 101 102 103 104 105 undefined undefined undefined undefined undefined undefined undefined |
||||
|
mythis 101 102 103 104 105 106 undefined undefined undefined undefined |
||||
|
arguments: 6 101 102 103 104 105 106 undefined undefined undefined undefined undefined undefined |
||||
|
mythis 101 102 103 104 105 106 107 undefined undefined undefined |
||||
|
arguments: 7 101 102 103 104 105 106 107 undefined undefined undefined undefined undefined |
||||
|
boundcallthis 201 202 303 304 undefined undefined undefined undefined undefined undefined |
||||
|
arguments: 4 201 202 303 304 undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
boundcallthis 201 202 303 304 undefined undefined undefined undefined undefined undefined |
||||
|
arguments: 4 201 202 303 304 undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
mythis 101 202 203 304 305 undefined undefined undefined undefined undefined |
||||
|
arguments: 5 101 202 203 304 305 undefined undefined undefined undefined undefined undefined undefined |
||||
|
mythis 101 202 203 304 305 undefined undefined undefined undefined undefined |
||||
|
arguments: 5 101 202 203 304 305 undefined undefined undefined undefined undefined undefined undefined |
||||
|
boundapplythis 201 202 undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
arguments: 2 201 202 undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
boundapplythis 201 202 undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
arguments: 2 201 202 undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
mythis 101 202 203 undefined undefined undefined undefined undefined undefined undefined |
||||
|
arguments: 3 101 202 203 undefined undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
mythis 101 202 203 undefined undefined undefined undefined undefined undefined undefined |
||||
|
arguments: 3 101 202 203 undefined undefined undefined undefined undefined undefined undefined undefined undefined |
||||
|
===*/ |
||||
|
|
||||
|
function test() { |
||||
|
var f0 = function f0(a, b, c, d, e, f, g, h, i, j) { |
||||
|
print(this, a, b, c, d, e, f, g, h, i, j); |
||||
|
print('arguments:', arguments.length, |
||||
|
arguments[0], arguments[1], arguments[2], arguments[3], |
||||
|
arguments[4], arguments[5], arguments[6], arguments[7], |
||||
|
arguments[8], arguments[9], arguments[10], arguments[11]); |
||||
|
}; |
||||
|
|
||||
|
// Direct call.
|
||||
|
f0(1, 2, 3); |
||||
|
|
||||
|
// Bound call.
|
||||
|
var f1 = f0.bind('mythis', 101); |
||||
|
f1(102); |
||||
|
|
||||
|
// Bound call, call via .call().
|
||||
|
f1.call('callthis', 102, 103); |
||||
|
|
||||
|
// Bound call, call via .call(); but use .apply() to call .call().
|
||||
|
f1.call.apply(f1, [ 'callthis', 102, 103, 104 ]); |
||||
|
|
||||
|
// Bound call, call via .apply().
|
||||
|
f1.apply('applythis', [ 102, 103, 104, 105 ]); |
||||
|
|
||||
|
// Bound call, call via .apply(); but use .call() to call .apply().
|
||||
|
f1.apply.call(f1, 'applythis', [ 102, 103, 104, 105, 106 ]); |
||||
|
|
||||
|
// Bound call, call via .apply(); but use .apply() to call .apply().
|
||||
|
f1.apply.apply(f1, [ 'applythis', [ 102, 103, 104, 105, 106, 107 ] ]); |
||||
|
|
||||
|
// Use .bind() on .call().
|
||||
|
var f2 = f0.call.bind(f0, 'boundcallthis', 201, 202); |
||||
|
f2(303, 304); |
||||
|
f2.call('ignored', 303, 304); |
||||
|
var f3 = f1.call.bind(f1, 'boundcallthis', 202, 203); |
||||
|
f3(304, 305); |
||||
|
f3.apply('ignored', [ 304, 305 ]); |
||||
|
|
||||
|
// Use .bind() on .apply().
|
||||
|
var f4 = f0.apply.bind(f0, 'boundapplythis', [ 201, 202 ]); |
||||
|
f4(303, 304); |
||||
|
f4.call('ignored', 303, 304); // these args get ignored because they don't affect [ 201, 202 ]
|
||||
|
var f5 = f1.apply.bind(f1, 'boundapplythis', [ 202, 203 ]); |
||||
|
f5(304, 305); |
||||
|
f5.apply('ignored', [ 304, 305 ]); // same here, [ 304, 305 ] is ignored by .apply()
|
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
test(); |
||||
|
} catch (e) { |
||||
|
print(e.stack || e); |
||||
|
} |
@ -0,0 +1,33 @@ |
|||||
|
/*=== |
||||
|
f0 called |
||||
|
applythis arg-0 arg-1 arg-2 |
||||
|
500000 |
||||
|
arg-499998 |
||||
|
arg-499999 |
||||
|
undefined |
||||
|
done |
||||
|
===*/ |
||||
|
|
||||
|
function test() { |
||||
|
function f0(a, b, c) { |
||||
|
print('f0 called'); |
||||
|
print(this, a, b, c); |
||||
|
print(arguments.length); |
||||
|
print(arguments[499998]); |
||||
|
print(arguments[499999]); |
||||
|
print(arguments[500000]); |
||||
|
} |
||||
|
|
||||
|
var args = []; |
||||
|
while (args.length < 500000) { |
||||
|
args.push('arg-' + args.length); |
||||
|
} |
||||
|
|
||||
|
f0.apply('applythis', args); |
||||
|
print('done'); |
||||
|
} |
||||
|
try { |
||||
|
test(); |
||||
|
} catch (e) { |
||||
|
print(e.stack || e); |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
/*=== |
||||
|
0 |
||||
|
100000 |
||||
|
200000 |
||||
|
300000 |
||||
|
400000 |
||||
|
500000 |
||||
|
600000 |
||||
|
700000 |
||||
|
800000 |
||||
|
900000 |
||||
|
1000000 |
||||
|
done |
||||
|
===*/ |
||||
|
|
||||
|
function test(count) { |
||||
|
if ((count % 1e5) == 0) { |
||||
|
print(count); |
||||
|
} |
||||
|
if (count < 1e6) { |
||||
|
return test.apply(null, [ count + 1 ]); |
||||
|
} |
||||
|
return 'done'; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
print(test(0)); |
||||
|
} catch (e) { |
||||
|
print(e.stack || e); |
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
/*=== |
||||
|
f0 called |
||||
|
callthis arg-0 arg-1 arg-2 |
||||
|
500000 |
||||
|
arg-499998 |
||||
|
arg-499999 |
||||
|
undefined |
||||
|
done |
||||
|
===*/ |
||||
|
|
||||
|
function test() { |
||||
|
function f0(a, b, c) { |
||||
|
print('f0 called'); |
||||
|
print(this, a, b, c); |
||||
|
print(arguments.length); |
||||
|
print(arguments[499998]); |
||||
|
print(arguments[499999]); |
||||
|
print(arguments[500000]); |
||||
|
} |
||||
|
|
||||
|
var args = []; |
||||
|
while (args.length < 500000) { |
||||
|
args.push('arg-' + args.length); |
||||
|
} |
||||
|
|
||||
|
args.unshift('callthis'); |
||||
|
|
||||
|
// Call .call() via .apply() to ensure huge argument count makes it.
|
||||
|
f0.call.apply(f0, args); |
||||
|
print('done'); |
||||
|
} |
||||
|
try { |
||||
|
test(); |
||||
|
} catch (e) { |
||||
|
print(e.stack || e); |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
/*=== |
||||
|
0 |
||||
|
100000 |
||||
|
200000 |
||||
|
300000 |
||||
|
400000 |
||||
|
500000 |
||||
|
600000 |
||||
|
700000 |
||||
|
800000 |
||||
|
900000 |
||||
|
1000000 |
||||
|
done |
||||
|
===*/ |
||||
|
|
||||
|
function test(count) { |
||||
|
if ((count % 1e5) == 0) { |
||||
|
print(count); |
||||
|
} |
||||
|
if (count < 1e6) { |
||||
|
return test.call(null, count + 1); |
||||
|
} |
||||
|
return 'done'; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
print(test(0)); |
||||
|
} catch (e) { |
||||
|
print(e.stack || e); |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
/*=== |
||||
|
0 |
||||
|
100000 |
||||
|
200000 |
||||
|
300000 |
||||
|
400000 |
||||
|
500000 |
||||
|
600000 |
||||
|
700000 |
||||
|
800000 |
||||
|
900000 |
||||
|
1000000 |
||||
|
done |
||||
|
===*/ |
||||
|
|
||||
|
function test(count) { |
||||
|
if ((count % 1e5) == 0) { |
||||
|
print(count); |
||||
|
} |
||||
|
if (count < 1e6) { |
||||
|
return Reflect.apply(test, null, [ count + 1 ]); |
||||
|
} |
||||
|
return 'done'; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
print(test(0)); |
||||
|
} catch (e) { |
||||
|
print(e.stack || e); |
||||
|
} |
@ -0,0 +1,40 @@ |
|||||
|
/* |
||||
|
* Since Duktape 2.2 .call() and .apply() no longer visible in call stack. |
||||
|
*/ |
||||
|
|
||||
|
/*=== |
||||
|
f0 called |
||||
|
-1 act |
||||
|
-2 f0 |
||||
|
-3 f1 |
||||
|
-4 f2 |
||||
|
-5 f3 |
||||
|
-6 test |
||||
|
-7 global |
||||
|
===*/ |
||||
|
|
||||
|
function test() { |
||||
|
var f0 = function f0() { |
||||
|
print('f0 called'); |
||||
|
for (var i = -1; ; i--) { |
||||
|
var act = Duktape.act(i); |
||||
|
if (!act) { break; } |
||||
|
print(i, act.function.name); |
||||
|
} |
||||
|
}; |
||||
|
var f1 = function f1() { |
||||
|
Reflect.apply(f0, 'dummy'); |
||||
|
} |
||||
|
var f2 = function f2() { |
||||
|
f1.call('dummy'); |
||||
|
} |
||||
|
var f3 = function f3() { |
||||
|
f2.apply('dummy'); |
||||
|
} |
||||
|
f3(); |
||||
|
} |
||||
|
try { |
||||
|
test(); |
||||
|
} catch (e) { |
||||
|
print(e.stack || e); |
||||
|
} |
@ -0,0 +1,111 @@ |
|||||
|
/* |
||||
|
* Some tests for .call() and .apply() with missing arguments. |
||||
|
*/ |
||||
|
|
||||
|
/*=== |
||||
|
- Function.prototype.call() |
||||
|
undefined undefined undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis arg undefined undefined |
||||
|
- Function.prototype.apply() |
||||
|
undefined undefined undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis arg undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis foo bar undefined |
||||
|
mythis FOO BAR undefined |
||||
|
TypeError |
||||
|
- Reflect.apply() |
||||
|
TypeError |
||||
|
TypeError |
||||
|
undefined undefined undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis arg undefined undefined |
||||
|
mythis undefined undefined undefined |
||||
|
mythis foo bar undefined |
||||
|
mythis FOO BAR undefined |
||||
|
TypeError |
||||
|
done |
||||
|
===*/ |
||||
|
|
||||
|
function test() { |
||||
|
function func(a,b,c) { |
||||
|
'use strict'; // avoid 'this' coercion
|
||||
|
print(this, a, b, c); |
||||
|
} |
||||
|
|
||||
|
var dummyFunc = function dummy(a,b) {}; // length: 2
|
||||
|
dummyFunc[0] = 'FOO'; |
||||
|
dummyFunc[1] = 'BAR'; |
||||
|
dummyFunc[2] = 'QUUX'; |
||||
|
|
||||
|
// For .call() there are no required arguments.
|
||||
|
// This binding will be 'undefined'.
|
||||
|
print('- Function.prototype.call()'); |
||||
|
func.call(); |
||||
|
func.call('mythis'); |
||||
|
func.call('mythis', 'arg'); |
||||
|
|
||||
|
// For .apply() there are similarly no required arguments.
|
||||
|
// argArray can be null/undefined and is treated like empty
|
||||
|
// array. Array-like object is accepted (.length is respected);
|
||||
|
// other types cause a TypeError. A function is an acceptable
|
||||
|
// input because it's an object and even has a .length!
|
||||
|
print('- Function.prototype.apply()'); |
||||
|
func.apply(); |
||||
|
func.apply('mythis'); |
||||
|
func.apply('mythis', void 0); |
||||
|
func.apply('mythis', null); |
||||
|
func.apply('mythis', []); |
||||
|
func.apply('mythis', [ 'arg' ]); |
||||
|
func.apply('mythis', {}); // no .length -> same as []
|
||||
|
func.apply('mythis', { length: 2, 0: 'foo', 1: 'bar', 2: 'quux-ignored' }); |
||||
|
func.apply('mythis', dummyFunc); |
||||
|
try { |
||||
|
func.apply('mythis', 123); |
||||
|
} catch (e) { |
||||
|
print(e.name); |
||||
|
} |
||||
|
|
||||
|
// Reflect.apply() requires a callable first argument,
|
||||
|
// but is otherwise similar to Function.prototype.apply().
|
||||
|
print('- Reflect.apply()'); |
||||
|
try { |
||||
|
Reflect.apply(); |
||||
|
} catch (e) { |
||||
|
print(e.name); |
||||
|
} |
||||
|
try { |
||||
|
Reflect.apply(123); |
||||
|
} catch (e) { |
||||
|
print(e.name); |
||||
|
} |
||||
|
Reflect.apply(func); |
||||
|
Reflect.apply(func, 'mythis'); |
||||
|
Reflect.apply(func, 'mythis', void 0); |
||||
|
Reflect.apply(func, 'mythis', null); |
||||
|
Reflect.apply(func, 'mythis', []); |
||||
|
Reflect.apply(func, 'mythis', [ 'arg' ]); |
||||
|
Reflect.apply(func, 'mythis', {}); |
||||
|
Reflect.apply(func, 'mythis', { length: 2, 0: 'foo', 1: 'bar', 2: 'quux-ignored' }); |
||||
|
Reflect.apply(func, 'mythis', dummyFunc); |
||||
|
try { |
||||
|
Reflect.apply(func, 'mythis', 123); |
||||
|
} catch (e) { |
||||
|
print(e.name); |
||||
|
} |
||||
|
|
||||
|
print('done'); |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
test(); |
||||
|
} catch (e) { |
||||
|
print(e.stack || e); |
||||
|
} |
@ -0,0 +1,84 @@ |
|||||
|
/* |
||||
|
* Demonstrate that in Duktape 2.2 .call() and .apply() no longer |
||||
|
* consume native call stack when the resolved call is an Ecma-to-Ecma |
||||
|
* call. |
||||
|
* |
||||
|
* Can't test against a specific limit but the native stack limit is |
||||
|
* ~500 calls while the default call stack limit is ~10000 calls. |
||||
|
*/ |
||||
|
|
||||
|
/*=== |
||||
|
RangeError |
||||
|
true |
||||
|
RangeError |
||||
|
true |
||||
|
RangeError |
||||
|
true |
||||
|
RangeError |
||||
|
true |
||||
|
done |
||||
|
===*/ |
||||
|
|
||||
|
function test() { |
||||
|
var count; |
||||
|
function f1() { |
||||
|
count++; |
||||
|
f1(); // not a tail call
|
||||
|
void count; |
||||
|
} |
||||
|
function f2() { |
||||
|
count++; |
||||
|
f2.call(); // not a tail call
|
||||
|
void count; |
||||
|
} |
||||
|
function f3() { |
||||
|
count++; |
||||
|
f3.apply(); // not a tail call
|
||||
|
void count; |
||||
|
} |
||||
|
function f4() { |
||||
|
count++; |
||||
|
Reflect.apply(f4); // not a tail call
|
||||
|
void count; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
count = 0; |
||||
|
f1(); |
||||
|
} catch (e) { |
||||
|
print(e.name); |
||||
|
} |
||||
|
print(count > 2000); |
||||
|
|
||||
|
try { |
||||
|
count = 0; |
||||
|
f2(); |
||||
|
} catch (e) { |
||||
|
print(e.name); |
||||
|
} |
||||
|
print(count > 2000); |
||||
|
|
||||
|
try { |
||||
|
count = 0; |
||||
|
f3(); |
||||
|
} catch (e) { |
||||
|
print(e.name); |
||||
|
} |
||||
|
print(count > 2000); |
||||
|
|
||||
|
try { |
||||
|
count = 0; |
||||
|
f4(); |
||||
|
} catch (e) { |
||||
|
print(e.name); |
||||
|
} |
||||
|
print(count > 2000); |
||||
|
|
||||
|
print('done'); |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
test(); |
||||
|
} catch (e) { |
||||
|
print(e.stack || e); |
||||
|
} |
Loading…
Reference in new issue