| Index: test/cctest/test-api.cc
|
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
| index def80fd93abe5c26450d37ae0b170a679a5fc9e3..6d3fad922f96d4908f9bcaa2f47c8aa10456f4d2 100644
|
| --- a/test/cctest/test-api.cc
|
| +++ b/test/cctest/test-api.cc
|
| @@ -15046,3 +15046,107 @@ THREADED_TEST(Regress93759) {
|
|
|
| context.Dispose();
|
| }
|
| +
|
| +
|
| +static void TestReceiver(Local<Value> expected_result,
|
| + Local<Value> expected_receiver,
|
| + const char* code) {
|
| + Local<Value> result = CompileRun(code);
|
| + CHECK(result->IsObject());
|
| + CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
|
| + CHECK(expected_result->Equals(result->ToObject()->Get(0)));
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(ForeignFunctionReceiver) {
|
| + HandleScope scope;
|
| +
|
| + // Create two contexts with different "id" properties ('i' and 'o').
|
| + // Call a function both from its own context and from a the foreign
|
| + // context, and see what "this" is bound to (returning both "this"
|
| + // and "this.id" for comparison).
|
| +
|
| + Persistent<Context> foreign_context = v8::Context::New();
|
| + foreign_context->Enter();
|
| + Local<Value> foreign_function =
|
| + CompileRun("function func() { return { 0: this.id, "
|
| + " 1: this, "
|
| + " toString: function() { "
|
| + " return this[0];"
|
| + " }"
|
| + " };"
|
| + "}"
|
| + "var id = 'i';"
|
| + "func;");
|
| + CHECK(foreign_function->IsFunction());
|
| + foreign_context->Exit();
|
| +
|
| + LocalContext context;
|
| +
|
| + Local<String> password = v8_str("Password");
|
| + // Don't get hit by security checks when accessing foreign_context's
|
| + // global receiver (aka. global proxy).
|
| + context->SetSecurityToken(password);
|
| + foreign_context->SetSecurityToken(password);
|
| +
|
| + Local<String> i = v8_str("i");
|
| + Local<String> o = v8_str("o");
|
| + Local<String> id = v8_str("id");
|
| +
|
| + CompileRun("function ownfunc() { return { 0: this.id, "
|
| + " 1: this, "
|
| + " toString: function() { "
|
| + " return this[0];"
|
| + " }"
|
| + " };"
|
| + "}"
|
| + "var id = 'o';"
|
| + "ownfunc");
|
| + context->Global()->Set(v8_str("func"), foreign_function);
|
| +
|
| + // Sanity check the contexts.
|
| + CHECK(i->Equals(foreign_context->Global()->Get(id)));
|
| + CHECK(o->Equals(context->Global()->Get(id)));
|
| +
|
| + // Checking local function's receiver.
|
| + // Calling function using its call/apply methods.
|
| + TestReceiver(o, context->Global(), "ownfunc.call()");
|
| + TestReceiver(o, context->Global(), "ownfunc.apply()");
|
| + // Making calls through built-in functions.
|
| + TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
|
| + CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
|
| + CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
|
| + CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
|
| + // Calling with environment record as base.
|
| + TestReceiver(o, context->Global(), "ownfunc()");
|
| + // Calling with no base.
|
| + TestReceiver(o, context->Global(), "(1,ownfunc)()");
|
| +
|
| + // Checking foreign function return value.
|
| + // Calling function using its call/apply methods.
|
| + TestReceiver(i, foreign_context->Global(), "func.call()");
|
| + TestReceiver(i, foreign_context->Global(), "func.apply()");
|
| + // Calling function using another context's call/apply methods.
|
| + TestReceiver(i, foreign_context->Global(),
|
| + "Function.prototype.call.call(func)");
|
| + TestReceiver(i, foreign_context->Global(),
|
| + "Function.prototype.call.apply(func)");
|
| + TestReceiver(i, foreign_context->Global(),
|
| + "Function.prototype.apply.call(func)");
|
| + TestReceiver(i, foreign_context->Global(),
|
| + "Function.prototype.apply.apply(func)");
|
| + // Making calls through built-in functions.
|
| + TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
|
| + // ToString(func()) is func()[0], i.e., the returned this.id.
|
| + CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
|
| + CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
|
| + CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
|
| +
|
| + // TODO(1547): Make the following also return "i".
|
| + // Calling with environment record as base.
|
| + TestReceiver(o, context->Global(), "func()");
|
| + // Calling with no base.
|
| + TestReceiver(o, context->Global(), "(1,func)()");
|
| +
|
| + foreign_context.Dispose();
|
| +}
|
|
|