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(); |
+} |