| Index: test/mjsunit/function-bind.js
|
| ===================================================================
|
| --- test/mjsunit/function-bind.js (revision 9808)
|
| +++ test/mjsunit/function-bind.js (working copy)
|
| @@ -29,29 +29,31 @@
|
|
|
| // Simple tests.
|
| function foo(x, y, z) {
|
| - return x + y + z;
|
| + return [this, arguments.length, x];
|
| }
|
|
|
| +assertEquals(3, foo.length);
|
| +
|
| var f = foo.bind(foo);
|
| -assertEquals(3, f(1, 1, 1));
|
| +assertEquals([foo, 3, 1], f(1, 2, 3));
|
| assertEquals(3, f.length);
|
|
|
| -f = foo.bind(foo, 2);
|
| -assertEquals(4, f(1, 1));
|
| +f = foo.bind(foo, 1);
|
| +assertEquals([foo, 3, 1], f(2, 3));
|
| assertEquals(2, f.length);
|
|
|
| -f = foo.bind(foo, 2, 2);
|
| -assertEquals(5, f(1));
|
| +f = foo.bind(foo, 1, 2);
|
| +assertEquals([foo, 3, 1], f(3));
|
| assertEquals(1, f.length);
|
|
|
| -f = foo.bind(foo, 2, 2, 2);
|
| -assertEquals(6, f());
|
| +f = foo.bind(foo, 1, 2, 3);
|
| +assertEquals([foo, 3, 1], f());
|
| assertEquals(0, f.length);
|
|
|
| // Test that length works correctly even if more than the actual number
|
| // of arguments are given when binding.
|
| f = foo.bind(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
| -assertEquals(6, f());
|
| +assertEquals([foo, 9, 1], f());
|
| assertEquals(0, f.length);
|
|
|
| // Use a different bound object.
|
| @@ -78,65 +80,98 @@
|
| // When only giving the thisArg, any number of binds should have
|
| // the same effect.
|
| f = foo.bind(foo);
|
| -assertEquals(3, f(1, 1, 1));
|
| -f = foo.bind(foo).bind(foo).bind(foo).bind(foo);
|
| -assertEquals(3, f(1, 1, 1));
|
| +assertEquals([foo, 3, 1], f(1, 2, 3));
|
| +
|
| +var not_foo = {};
|
| +f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo);
|
| +assertEquals([foo, 3, 1], f(1, 2, 3));
|
| assertEquals(3, f.length);
|
|
|
| // Giving bound parameters should work at any place in the chain.
|
| -f = foo.bind(foo, 1).bind(foo).bind(foo).bind(foo);
|
| -assertEquals(3, f(1, 1));
|
| +f = foo.bind(foo, 1).bind(not_foo).bind(not_foo).bind(not_foo);
|
| +assertEquals([foo, 3, 1], f(2, 3));
|
| assertEquals(2, f.length);
|
|
|
| -f = foo.bind(foo).bind(foo, 1).bind(foo).bind(foo);
|
| -assertEquals(3, f(1, 1));
|
| +f = foo.bind(foo).bind(not_foo, 1).bind(not_foo).bind(not_foo);
|
| +assertEquals([foo, 3, 1], f(2, 3));
|
| assertEquals(2, f.length);
|
|
|
| -f = foo.bind(foo).bind(foo).bind(foo,1 ).bind(foo);
|
| -assertEquals(3, f(1, 1));
|
| +f = foo.bind(foo).bind(not_foo).bind(not_foo,1 ).bind(not_foo);
|
| +assertEquals([foo, 3, 1], f(2, 3));
|
| assertEquals(2, f.length);
|
|
|
| -f = foo.bind(foo).bind(foo).bind(foo).bind(foo, 1);
|
| -assertEquals(3, f(1, 1));
|
| +f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo, 1);
|
| +assertEquals([foo, 3, 1], f(2, 3));
|
| assertEquals(2, f.length);
|
|
|
| -// Several parameters can be given, and given in different bind invokations.
|
| -f = foo.bind(foo, 1, 1).bind(foo).bind(foo).bind(foo);
|
| -assertEquals(3, f(1));
|
| +// Several parameters can be given, and given in different bind invocations.
|
| +f = foo.bind(foo, 1, 2).bind(not_foo).bind(not_foo).bind(not_foo);
|
| +assertEquals([foo, 3, 1], f(3));
|
| assertEquals(1, f.length);
|
|
|
| -f = foo.bind(foo).bind(foo, 1, 1).bind(foo).bind(foo);
|
| -assertEquals(3, f(1));
|
| +f = foo.bind(foo).bind(not_foo, 1, 2).bind(not_foo).bind(not_foo);
|
| +assertEquals([foo, 3, 1], f(1));
|
| assertEquals(1, f.length);
|
|
|
| -f = foo.bind(foo).bind(foo, 1, 1).bind(foo).bind(foo);
|
| -assertEquals(3, f(1));
|
| +f = foo.bind(foo).bind(not_foo, 1, 2).bind(not_foo).bind(not_foo);
|
| +assertEquals([foo, 3, 1], f(3));
|
| assertEquals(1, f.length);
|
|
|
| -f = foo.bind(foo).bind(foo).bind(foo, 1, 1).bind(foo);
|
| -assertEquals(3, f(1));
|
| +f = foo.bind(foo).bind(not_foo).bind(not_foo, 1, 2).bind(not_foo);
|
| +assertEquals([foo, 3, 1], f(1));
|
| assertEquals(1, f.length);
|
|
|
| -f = foo.bind(foo).bind(foo).bind(foo).bind(foo, 1, 1);
|
| -assertEquals(3, f(1));
|
| +f = foo.bind(foo).bind(not_foo).bind(not_foo).bind(not_foo, 1, 2);
|
| +assertEquals([foo, 3, 1], f(3));
|
| assertEquals(1, f.length);
|
|
|
| -f = foo.bind(foo, 1).bind(foo, 1).bind(foo).bind(foo);
|
| -assertEquals(3, f(1));
|
| +f = foo.bind(foo, 1).bind(not_foo, 2).bind(not_foo).bind(not_foo);
|
| +assertEquals([foo, 3, 1], f(3));
|
| assertEquals(1, f.length);
|
|
|
| -f = foo.bind(foo, 1).bind(foo).bind(foo, 1).bind(foo);
|
| -assertEquals(3, f(1));
|
| +f = foo.bind(foo, 1).bind(not_foo).bind(not_foo, 2).bind(not_foo);
|
| +assertEquals([foo, 3, 1], f(3));
|
| assertEquals(1, f.length);
|
|
|
| -f = foo.bind(foo, 1).bind(foo).bind(foo).bind(foo, 1);
|
| -assertEquals(3, f(1));
|
| +f = foo.bind(foo, 1).bind(not_foo).bind(not_foo).bind(not_foo, 2);
|
| +assertEquals([foo, 3, 1], f(3));
|
| assertEquals(1, f.length);
|
|
|
| -f = foo.bind(foo).bind(foo, 1).bind(foo).bind(foo, 1);
|
| -assertEquals(3, f(1));
|
| +f = foo.bind(foo).bind(not_foo, 1).bind(not_foo).bind(not_foo, 2);
|
| +assertEquals([foo, 3, 1], f(3));
|
| assertEquals(1, f.length);
|
|
|
| +// The wrong number of arguments can be given to bound functions too.
|
| +f = foo.bind(foo);
|
| +assertEquals(3, f.length);
|
| +assertEquals([foo, 0, undefined], f());
|
| +assertEquals([foo, 1, 1], f(1));
|
| +assertEquals([foo, 2, 1], f(1, 2));
|
| +assertEquals([foo, 3, 1], f(1, 2, 3));
|
| +assertEquals([foo, 4, 1], f(1, 2, 3, 4));
|
| +
|
| +f = foo.bind(foo, 1);
|
| +assertEquals(2, f.length);
|
| +assertEquals([foo, 1, 1], f());
|
| +assertEquals([foo, 2, 1], f(2));
|
| +assertEquals([foo, 3, 1], f(2, 3));
|
| +assertEquals([foo, 4, 1], f(2, 3, 4));
|
| +
|
| +f = foo.bind(foo, 1, 2);
|
| +assertEquals(1, f.length);
|
| +assertEquals([foo, 2, 1], f());
|
| +assertEquals([foo, 3, 1], f(3));
|
| +assertEquals([foo, 4, 1], f(3, 4));
|
| +
|
| +f = foo.bind(foo, 1, 2, 3);
|
| +assertEquals(0, f.length);
|
| +assertEquals([foo, 3, 1], f());
|
| +assertEquals([foo, 4, 1], f(4));
|
| +
|
| +f = foo.bind(foo, 1, 2, 3, 4);
|
| +assertEquals(0, f.length);
|
| +assertEquals([foo, 4, 1], f());
|
| +
|
| // Test constructor calls.
|
|
|
| function bar(x, y, z) {
|
| @@ -171,13 +206,91 @@
|
|
|
|
|
| // Test bind chains when used as a constructor.
|
| -
|
| f = bar.bind(bar, 1).bind(bar, 2).bind(bar, 3);
|
| obj2 = new f();
|
| assertEquals(1, obj2.x);
|
| assertEquals(2, obj2.y);
|
| assertEquals(3, obj2.z);
|
|
|
| -// Test instanceof obj2 is bar, not f.
|
| +// Test obj2 is instanceof both bar and f.
|
| assertTrue(obj2 instanceof bar);
|
| -assertFalse(obj2 instanceof f);
|
| +assertTrue(obj2 instanceof f);
|
| +
|
| +// This-args are not relevant to instanceof.
|
| +f = bar.bind(foo.prototype, 1).
|
| + bind(String.prototype, 2).
|
| + bind(Function.prototype, 3);
|
| +var obj3 = new f();
|
| +assertTrue(obj3 instanceof bar);
|
| +assertTrue(obj3 instanceof f);
|
| +assertFalse(obj3 instanceof foo);
|
| +assertFalse(obj3 instanceof Function);
|
| +assertFalse(obj3 instanceof String);
|
| +
|
| +// thisArg is converted to object.
|
| +f = foo.bind(undefined);
|
| +assertEquals([this, 0, undefined], f());
|
| +
|
| +f = foo.bind(null);
|
| +assertEquals([this, 0, undefined], f());
|
| +
|
| +f = foo.bind(42);
|
| +assertEquals([Object(42), 0, undefined], f());
|
| +
|
| +f = foo.bind("foo");
|
| +assertEquals([Object("foo"), 0, undefined], f());
|
| +
|
| +f = foo.bind(true);
|
| +assertEquals([Object(true), 0, undefined], f());
|
| +
|
| +// Strict functions don't convert thisArg.
|
| +function soo(x, y, z) {
|
| + "use strict";
|
| + return [this, arguments.length, x];
|
| +}
|
| +
|
| +var s = soo.bind(undefined);
|
| +assertEquals([undefined, 0, undefined], s());
|
| +
|
| +s = soo.bind(null);
|
| +assertEquals([null, 0, undefined], s());
|
| +
|
| +s = soo.bind(42);
|
| +assertEquals([42, 0, undefined], s());
|
| +
|
| +s = soo.bind("foo");
|
| +assertEquals(["foo", 0, undefined], s());
|
| +
|
| +s = soo.bind(true);
|
| +assertEquals([true, 0, undefined], s());
|
| +
|
| +// Test that .arguments and .caller are poisoned according to the ES5 spec.
|
| +
|
| +// Check that property descriptors are correct (unconfigurable, unenumerable,
|
| +// and both get and set is the ThrowTypeError function).
|
| +var cdesc = Object.getOwnPropertyDescriptor(f, "caller");
|
| +var adesc = Object.getOwnPropertyDescriptor(f, "arguments");
|
| +
|
| +assertFalse(cdesc.enumerable);
|
| +assertFalse(cdesc.configurable);
|
| +
|
| +assertFalse(adesc.enumerable);
|
| +assertFalse(adesc.configurable);
|
| +
|
| +assertSame(cdesc.get, cdesc.set);
|
| +assertSame(cdesc.get, adesc.get);
|
| +assertSame(cdesc.get, adesc.set);
|
| +
|
| +assertTrue(cdesc.get instanceof Function);
|
| +assertEquals(0, cdesc.get.length);
|
| +assertThrows(cdesc.get, TypeError);
|
| +
|
| +assertThrows(function() { return f.caller; }, TypeError);
|
| +assertThrows(function() { f.caller = 42; }, TypeError);
|
| +assertThrows(function() { return f.arguments; }, TypeError);
|
| +assertThrows(function() { f.arguments = 42; }, TypeError);
|
| +
|
| +// Shouldn't throw. Accessing the functions caller must throw if
|
| +// the caller is strict and the callee isn't. A bound function is built-in,
|
| +// but not considered strict.
|
| +(function foo() { return foo.caller; }).bind()();
|
|
|