| Index: test/cctest/test-api.cc
|
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
| index 23ceee2411a3ecc97ec3c89c903861802a1ce0cd..17fd226ee05a01c90870a50e14254b124439020e 100644
|
| --- a/test/cctest/test-api.cc
|
| +++ b/test/cctest/test-api.cc
|
| @@ -81,6 +81,11 @@ static void ExpectString(const char* code, const char* expected) {
|
| CHECK_EQ(expected, *ascii);
|
| }
|
|
|
| +static void ExpectInt32(const char* code, int expected) {
|
| + Local<Value> result = CompileRun(code);
|
| + CHECK(result->IsInt32());
|
| + CHECK_EQ(expected, result->Int32Value());
|
| +}
|
|
|
| static void ExpectBoolean(const char* code, bool expected) {
|
| Local<Value> result = CompileRun(code);
|
| @@ -1297,6 +1302,197 @@ static v8::Handle<Value> EchoNamedProperty(Local<String> name,
|
| return name;
|
| }
|
|
|
| +// Helper functions for Interceptor/Accessor interaction tests
|
| +
|
| +Handle<Value> SimpleAccessorGetter(Local<String> name,
|
| + const AccessorInfo& info) {
|
| + Handle<Object> self = info.This();
|
| + return self->Get(String::Concat(v8_str("accessor_"), name));
|
| +}
|
| +
|
| +void SimpleAccessorSetter(Local<String> name, Local<Value> value,
|
| + const AccessorInfo& info) {
|
| + Handle<Object> self = info.This();
|
| + self->Set(String::Concat(v8_str("accessor_"), name), value);
|
| +}
|
| +
|
| +Handle<Value> EmptyInterceptorGetter(Local<String> name,
|
| + const AccessorInfo& info) {
|
| + return Handle<Value>();
|
| +}
|
| +
|
| +Handle<Value> EmptyInterceptorSetter(Local<String> name,
|
| + Local<Value> value,
|
| + const AccessorInfo& info) {
|
| + return Handle<Value>();
|
| +}
|
| +
|
| +Handle<Value> InterceptorGetter(Local<String> name,
|
| + const AccessorInfo& info) {
|
| + // Intercept names that start with 'interceptor_'.
|
| + String::AsciiValue ascii(name);
|
| + char* name_str = *ascii;
|
| + char prefix[] = "interceptor_";
|
| + int i;
|
| + for (i = 0; name_str[i] && prefix[i]; ++i) {
|
| + if (name_str[i] != prefix[i]) return Handle<Value>();
|
| + }
|
| + Handle<Object> self = info.This();
|
| + return self->GetHiddenValue(v8_str(name_str + i));
|
| +}
|
| +
|
| +Handle<Value> InterceptorSetter(Local<String> name,
|
| + Local<Value> value,
|
| + const AccessorInfo& info) {
|
| + // Intercept accesses that set certain integer values.
|
| + if (value->IsInt32() && value->Int32Value() < 10000) {
|
| + Handle<Object> self = info.This();
|
| + self->SetHiddenValue(name, value);
|
| + return value;
|
| + }
|
| + return Handle<Value>();
|
| +}
|
| +
|
| +void AddAccessor(Handle<FunctionTemplate> templ,
|
| + Handle<String> name,
|
| + v8::AccessorGetter getter,
|
| + v8::AccessorSetter setter) {
|
| + templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
|
| +}
|
| +
|
| +void AddInterceptor(Handle<FunctionTemplate> templ,
|
| + v8::NamedPropertyGetter getter,
|
| + v8::NamedPropertySetter setter) {
|
| + templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
|
| +}
|
| +
|
| +THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
|
| + v8::HandleScope scope;
|
| + Handle<FunctionTemplate> parent = FunctionTemplate::New();
|
| + Handle<FunctionTemplate> child = FunctionTemplate::New();
|
| + child->Inherit(parent);
|
| + AddAccessor(parent, v8_str("age"),
|
| + SimpleAccessorGetter, SimpleAccessorSetter);
|
| + AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
|
| + LocalContext env;
|
| + env->Global()->Set(v8_str("Child"), child->GetFunction());
|
| + CompileRun("var child = new Child;"
|
| + "child.age = 10;");
|
| + ExpectBoolean("child.hasOwnProperty('age')", false);
|
| + ExpectInt32("child.age", 10);
|
| + ExpectInt32("child.accessor_age", 10);
|
| +}
|
| +
|
| +THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
|
| + v8::HandleScope scope;
|
| + Handle<FunctionTemplate> parent = FunctionTemplate::New();
|
| + Handle<FunctionTemplate> child = FunctionTemplate::New();
|
| + child->Inherit(parent);
|
| + AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
|
| + LocalContext env;
|
| + env->Global()->Set(v8_str("Child"), child->GetFunction());
|
| + CompileRun("var child = new Child;"
|
| + "var parent = child.__proto__;"
|
| + "Object.defineProperty(parent, 'age', "
|
| + " {get: function(){ return this.accessor_age; }, "
|
| + " set: function(v){ this.accessor_age = v; }, "
|
| + " enumerable: true, configurable: true});"
|
| + "child.age = 10;");
|
| + ExpectBoolean("child.hasOwnProperty('age')", false);
|
| + ExpectInt32("child.age", 10);
|
| + ExpectInt32("child.accessor_age", 10);
|
| +}
|
| +
|
| +THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
|
| + v8::HandleScope scope;
|
| + Handle<FunctionTemplate> parent = FunctionTemplate::New();
|
| + Handle<FunctionTemplate> child = FunctionTemplate::New();
|
| + child->Inherit(parent);
|
| + AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
|
| + LocalContext env;
|
| + env->Global()->Set(v8_str("Child"), child->GetFunction());
|
| + CompileRun("var child = new Child;"
|
| + "var parent = child.__proto__;"
|
| + "parent.name = 'Alice';");
|
| + ExpectBoolean("child.hasOwnProperty('name')", false);
|
| + ExpectString("child.name", "Alice");
|
| + CompileRun("child.name = 'Bob';");
|
| + ExpectString("child.name", "Bob");
|
| + ExpectBoolean("child.hasOwnProperty('name')", true);
|
| + ExpectString("parent.name", "Alice");
|
| +}
|
| +
|
| +THREADED_TEST(SwitchFromInterceptorToAccessor) {
|
| + v8::HandleScope scope;
|
| + Handle<FunctionTemplate> parent = FunctionTemplate::New();
|
| + Handle<FunctionTemplate> child = FunctionTemplate::New();
|
| + child->Inherit(parent);
|
| + AddAccessor(parent, v8_str("age"),
|
| + SimpleAccessorGetter, SimpleAccessorSetter);
|
| + AddInterceptor(child, InterceptorGetter, InterceptorSetter);
|
| + LocalContext env;
|
| + env->Global()->Set(v8_str("Child"), child->GetFunction());
|
| + CompileRun("var child = new Child;"
|
| + "function setAge(i){ child.age = i; };"
|
| + "for(var i = 0; i <= 10000; i++) setAge(i);");
|
| + // All i < 10000 go to the interceptor.
|
| + ExpectInt32("child.interceptor_age", 9999);
|
| + // The last i goes to the accessor.
|
| + ExpectInt32("child.accessor_age", 10000);
|
| +}
|
| +
|
| +THREADED_TEST(SwitchFromAccessorToInterceptor) {
|
| + v8::HandleScope scope;
|
| + Handle<FunctionTemplate> parent = FunctionTemplate::New();
|
| + Handle<FunctionTemplate> child = FunctionTemplate::New();
|
| + child->Inherit(parent);
|
| + AddAccessor(parent, v8_str("age"),
|
| + SimpleAccessorGetter, SimpleAccessorSetter);
|
| + AddInterceptor(child, InterceptorGetter, InterceptorSetter);
|
| + LocalContext env;
|
| + env->Global()->Set(v8_str("Child"), child->GetFunction());
|
| + CompileRun("var child = new Child;"
|
| + "function setAge(i){ child.age = i; };"
|
| + "for(var i = 20000; i >= 9999; i--) setAge(i);");
|
| + // All i >= 10000 go to the accessor.
|
| + ExpectInt32("child.accessor_age", 10000);
|
| + // The last i goes to the interceptor.
|
| + ExpectInt32("child.interceptor_age", 9999);
|
| +}
|
| +
|
| +THREADED_TEST(SwitchFromInterceptorToProperty) {
|
| + v8::HandleScope scope;
|
| + Handle<FunctionTemplate> parent = FunctionTemplate::New();
|
| + Handle<FunctionTemplate> child = FunctionTemplate::New();
|
| + child->Inherit(parent);
|
| + AddInterceptor(child, InterceptorGetter, InterceptorSetter);
|
| + LocalContext env;
|
| + env->Global()->Set(v8_str("Child"), child->GetFunction());
|
| + CompileRun("var child = new Child;"
|
| + "function setAge(i){ child.age = i; };"
|
| + "for(var i = 0; i <= 10000; i++) setAge(i);");
|
| + // All i < 10000 go to the interceptor.
|
| + ExpectInt32("child.interceptor_age", 9999);
|
| + // The last i goes to child's own property.
|
| + ExpectInt32("child.age", 10000);
|
| +}
|
| +
|
| +THREADED_TEST(SwitchFromPropertyToInterceptor) {
|
| + v8::HandleScope scope;
|
| + Handle<FunctionTemplate> parent = FunctionTemplate::New();
|
| + Handle<FunctionTemplate> child = FunctionTemplate::New();
|
| + child->Inherit(parent);
|
| + AddInterceptor(child, InterceptorGetter, InterceptorSetter);
|
| + LocalContext env;
|
| + env->Global()->Set(v8_str("Child"), child->GetFunction());
|
| + CompileRun("var child = new Child;"
|
| + "function setAge(i){ child.age = i; };"
|
| + "for(var i = 20000; i >= 9999; i--) setAge(i);");
|
| + // All i >= 10000 go to child's own property.
|
| + ExpectInt32("child.age", 10000);
|
| + // The last i goes to the interceptor.
|
| + ExpectInt32("child.interceptor_age", 9999);
|
| +}
|
|
|
| THREADED_TEST(NamedPropertyHandlerGetter) {
|
| echo_named_call_count = 0;
|
|
|