Index: test/cctest/test-api.cc |
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc |
index 4d5df48d41fd5e1d0973d692426101dea4f8c204..cac27a688fedfb8423794477627c5ed542507e9f 100644 |
--- a/test/cctest/test-api.cc |
+++ b/test/cctest/test-api.cc |
@@ -80,6 +80,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); |
@@ -1296,6 +1301,196 @@ 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) { |
Rico
2011/09/26 08:45:10
indention
ulan
2011/09/26 09:15:18
Done.
|
+ 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) { |
Rico
2011/09/26 08:45:10
indention and put value on seperate line
ulan
2011/09/26 09:15:18
Done.
|
+ Handle<Object> self = info.This(); |
+ self->Set(String::Concat(v8_str("accessor_"), name), value); |
+} |
+ |
+Handle<Value> EmptyInterceptorGetter(Local<String> name, |
+ const AccessorInfo& info) { |
Rico
2011/09/26 08:45:10
indention
ulan
2011/09/26 09:15:18
Done.
|
+ 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_' |
Rico
2011/09/26 08:45:10
Capitalize I at start of comment
Rico
2011/09/26 08:45:10
period at the end of comment
ulan
2011/09/26 09:15:18
Done.
ulan
2011/09/26 09:15:18
Done.
|
+ String::AsciiValue ascii(name); |
+ char* name_str = *ascii; |
+ char prefix[] = "interceptor_"; |
+ int i; |
+ for (i = 0; name_str[i] && prefix[i]; ++i) |
Rico
2011/09/26 08:45:10
Please add {} around body when not on single line
ulan
2011/09/26 09:15:18
Done.
|
+ 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 |
Rico
2011/09/26 08:45:10
Capital I at start of comment, period at the end
ulan
2011/09/26 09:15:18
Done.
|
+ 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, |
Rico
2011/09/26 08:45:10
Indention
ulan
2011/09/26 09:15:18
Done.
|
+ 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 interceptor |
+ ExpectInt32("child.interceptor_age", 9999); |
+ // the last i goes to 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 accessor |
+ ExpectInt32("child.accessor_age", 10000); |
+ // the last i goes to 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 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 interceptor |
+ ExpectInt32("child.interceptor_age", 9999); |
+} |
THREADED_TEST(NamedPropertyHandlerGetter) { |
echo_named_call_count = 0; |