Index: test/cctest/test-api.cc |
=================================================================== |
--- test/cctest/test-api.cc (revision 8993) |
+++ test/cctest/test-api.cc (working copy) |
@@ -1318,7 +1318,293 @@ |
CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue()); |
} |
+int do_nothing_call_count = 0; |
+int foo_setter_call_count = 0; |
+int bar_setter_call_count = 0; |
+static v8::Handle<v8::Value> AccessorGetterFoo(Local<String> property, |
+ const AccessorInfo& info) { |
+ return v8::String::New("fooget"); |
+} |
+ |
+static void AccessorSetterFoo(Local<String> property, |
+ Local<Value> value, |
+ const AccessorInfo& info) { |
+ foo_setter_call_count++; |
+ String::AsciiValue name(property); |
+ CHECK_EQ(*name, "foo"); |
+ return; |
+} |
+ |
+static v8::Handle<v8::Value> AccessorGetterBar(Local<String> property, |
+ const AccessorInfo& info) { |
+ return v8::String::New("barget"); |
+} |
+ |
+static void AccessorSetterBar(Local<String> property, |
+ Local<Value> value, |
+ const AccessorInfo& info) { |
+ bar_setter_call_count++; |
+ String::AsciiValue name(property); |
+ CHECK_EQ(*name, "bar"); |
+ return; |
+} |
+ |
+static v8::Handle<Value> DoNothingGetterHandler(Local<String> name, |
+ const AccessorInfo& info) { |
+ do_nothing_call_count++; |
+ return v8::Handle<Value>(); |
+} |
+ |
+THREADED_TEST(NamedPropertyHandlerWalkingUpPrototypeChain) { |
+ do_nothing_call_count = 0; |
+ foo_setter_call_count = 0; |
+ bar_setter_call_count = 0; |
+ v8::HandleScope scope; |
+ v8::Handle<v8::FunctionTemplate> grandparent = v8::FunctionTemplate::New(); |
+ v8::Handle<v8::FunctionTemplate> parent = v8::FunctionTemplate::New(); |
+ v8::Handle<v8::FunctionTemplate> child = v8::FunctionTemplate::New(); |
+ parent->Inherit(grandparent); |
+ child->Inherit(parent); |
+ child->InstanceTemplate()->SetNamedPropertyHandler(DoNothingGetterHandler, |
+ 0, 0, 0, 0, |
+ v8_str("data")); |
+ grandparent->PrototypeTemplate()->SetAccessor(v8::String::New("foo"), |
+ AccessorGetterFoo, |
+ AccessorSetterFoo); |
+ parent->PrototypeTemplate()->SetAccessor(v8::String::New("bar"), |
+ AccessorGetterBar, |
+ AccessorSetterBar); |
+ |
+ LocalContext env; |
+ env->Global()->Set(v8_str("obj"), |
+ child->GetFunction()->NewInstance()); |
+ CHECK_EQ(do_nothing_call_count, 0); |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.foo")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 1); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "fooget"); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.bar")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 2); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "barget"); |
+ } |
+ { |
+ v8::Handle<Value> result = v8_compile("obj.foo = 1")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 2); // shoudn't change |
+ CHECK_EQ(foo_setter_call_count, 1); |
+ CHECK_EQ(result->Int32Value(), 1); |
+ } |
+ { |
+ v8::Handle<Value> result = v8_compile("obj.bar = 2")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 2); // shoudn't change |
+ CHECK_EQ(bar_setter_call_count, 1); |
+ CHECK_EQ(result->Int32Value(), 2); |
+ } |
+ // The values should not be on the instance (for Accessors) |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.foo")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 3); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "fooget"); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.bar")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 4); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "barget"); |
+ } |
+} |
+ |
+int catch_all_propety_call_count = 0; |
+ |
+static v8::Handle<Value> CatchAllPropertyHandler(Local<String> name, |
+ const AccessorInfo& info) { |
+ catch_all_propety_call_count++; |
+ CHECK_EQ(v8_str("SOMETHING"), info.Data()); |
+ return v8::String::New("GOTCHA"); |
+} |
+ |
+int baz_setter_call_count = 0; |
+ |
+static v8::Handle<v8::Value> AccessorGetterBaz(Local<String> property, |
+ const AccessorInfo& info) { |
+ return v8::String::New("bazget"); |
+} |
+ |
+static void AccessorSetterBaz(Local<String> property, |
+ Local<Value> value, |
+ const AccessorInfo& info) { |
+ baz_setter_call_count++; |
+ String::AsciiValue name(property); |
+ CHECK_EQ(*name, "baz"); |
+ return; |
+} |
+ |
+THREADED_TEST(WalkingUpPrototypeChainWithNamedPropertyHandlerOnPrototype) { |
+ do_nothing_call_count = 0; |
+ catch_all_propety_call_count = 0; |
+ foo_setter_call_count = 0; |
+ bar_setter_call_count = 0; |
+ baz_setter_call_count = 0; |
+ v8::HandleScope scope; |
+ v8::Handle<v8::FunctionTemplate> grandgrandparent = |
+ v8::FunctionTemplate::New(); |
+ v8::Handle<v8::FunctionTemplate> grandparent = v8::FunctionTemplate::New(); |
+ v8::Handle<v8::FunctionTemplate> parent = v8::FunctionTemplate::New(); |
+ v8::Handle<v8::FunctionTemplate> child = v8::FunctionTemplate::New(); |
+ grandparent->Inherit(grandgrandparent); |
+ parent->Inherit(grandparent); |
+ child->Inherit(parent); |
+ child->InstanceTemplate()->SetNamedPropertyHandler(DoNothingGetterHandler, |
+ 0, 0, 0, 0, |
+ v8_str("data")); |
+ grandparent->PrototypeTemplate()->SetNamedPropertyHandler(CatchAllPropertyHandler, |
+ 0, 0, 0, 0, |
+ v8_str("SOMETHING")); |
+ grandgrandparent->PrototypeTemplate()->SetAccessor(v8::String::New("baz"), |
+ AccessorGetterBaz, |
+ AccessorSetterBaz); |
+ grandparent->PrototypeTemplate()->SetAccessor(v8::String::New("foo"), |
+ AccessorGetterFoo, |
+ AccessorSetterFoo); |
+ parent->PrototypeTemplate()->SetAccessor(v8::String::New("bar"), |
+ AccessorGetterBar, |
+ AccessorSetterBar); |
+ |
+ LocalContext env; |
+ env->Global()->Set(v8_str("obj"), |
+ child->GetFunction()->NewInstance()); |
+ CHECK_EQ(do_nothing_call_count, 0); |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.foo")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 1); |
+ CHECK_EQ(catch_all_propety_call_count, 1); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "GOTCHA"); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.bar")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 2); |
+ CHECK_EQ(catch_all_propety_call_count, 1); // shoudn't get called |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "barget"); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.baz")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 3); |
+ CHECK_EQ(catch_all_propety_call_count, 2); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "GOTCHA"); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.foo = 1")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 3); // shoudn't change |
+ CHECK_EQ(catch_all_propety_call_count, 2); |
+ CHECK_EQ(foo_setter_call_count, 1); |
+ CHECK_EQ(result->Int32Value(), 1); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.bar = 2")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 3); |
+ CHECK_EQ(catch_all_propety_call_count, 2); |
+ CHECK_EQ(bar_setter_call_count, 1); |
+ CHECK_EQ(result->Int32Value(), 2); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.baz = 3")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 3); |
+ CHECK_EQ(catch_all_propety_call_count, 2); |
+ CHECK_EQ(baz_setter_call_count, 1); |
+ CHECK_EQ(result->Int32Value(), 3); |
+ } |
+ // The values should not be on the instance (for Accessors) |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.foo")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 4); |
+ CHECK_EQ(catch_all_propety_call_count, 3); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "GOTCHA"); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.bar")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 5); |
+ CHECK_EQ(catch_all_propety_call_count, 3); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "barget"); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.baz")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 6); |
+ CHECK_EQ(catch_all_propety_call_count, 4); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "GOTCHA"); |
+ } |
+} |
+ |
+THREADED_TEST(NamedPropertyHandlerPropertyNotOnPrototype) { |
+ do_nothing_call_count = 0; |
+ foo_setter_call_count = 0; |
+ bar_setter_call_count = 0; |
+ v8::HandleScope scope; |
+ v8::Handle<v8::FunctionTemplate> grandparent = v8::FunctionTemplate::New(); |
+ v8::Handle<v8::FunctionTemplate> parent = v8::FunctionTemplate::New(); |
+ v8::Handle<v8::FunctionTemplate> child = v8::FunctionTemplate::New(); |
+ parent->Inherit(grandparent); |
+ child->Inherit(parent); |
+ child->InstanceTemplate()->SetNamedPropertyHandler(DoNothingGetterHandler, |
+ 0, 0, 0, 0, |
+ v8_str("data")); |
+ grandparent->PrototypeTemplate()->SetAccessor(v8::String::New("foo"), |
+ AccessorGetterFoo, |
+ AccessorSetterFoo); |
+ parent->PrototypeTemplate()->SetAccessor(v8::String::New("bar"), |
+ AccessorGetterBar, |
+ AccessorSetterBar); |
+ |
+ LocalContext env; |
+ env->Global()->Set(v8_str("obj"), |
+ child->GetFunction()->NewInstance()); |
+ CHECK_EQ(do_nothing_call_count, 0); |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.a")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 1); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "undefined"); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.b")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 2); |
+ String::AsciiValue Result(result); |
+ CHECK_EQ(*Result, "undefined"); |
+ } |
+ { |
+ v8::Handle<Value> result = v8_compile("obj.a = 1;")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 2); // shoudn't change |
+ CHECK_EQ(result->Int32Value(), 1); |
+ } |
+ { |
+ v8::Handle<Value> result = v8_compile("obj.b = 2;")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 2); // shoudn't change |
+ CHECK_EQ(result->Int32Value(), 2); |
+ } |
+ // The values should be on the instance (not handled by Accessors) |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.a")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 3); |
+ CHECK_EQ(result->Int32Value(), 1); |
+ } |
+ { |
+ v8::Handle<v8::Value> result = v8_compile("obj.b")->Run(); |
+ CHECK_EQ(do_nothing_call_count, 4); |
+ CHECK_EQ(result->Int32Value(), 2); |
+ } |
+} |
+ |
+ |
int echo_indexed_call_count = 0; |
@@ -1331,6 +1617,7 @@ |
} |
+ |
THREADED_TEST(IndexedPropertyHandlerGetter) { |
v8::HandleScope scope; |
v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); |