Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1256)

Unified Diff: test/cctest/test-api.cc

Issue 2244123005: [api] Add PropertyDescriptor and DefineProperty(). (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Add test that shows need for has_attribute() functions Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« src/api.cc ('K') | « src/counters.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/cctest/test-api.cc
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 484d2f32264643d36cb29130e0e3259061185f06..09875b9de3403ee0906ad3f23236f8bd43536d3f 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -16004,6 +16004,242 @@ TEST(DefineOwnProperty) {
}
}
+TEST(DefineProperty) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope handle_scope(isolate);
+
+ CompileRun(
+ "var a = {};"
+ "var b = [];"
+ "Object.defineProperty(a, 'foo', {value: 23});"
+ "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
+
+ v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
+ env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked());
+ v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(
+ env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked());
+
+ const v8::PropertyDescriptor desc = v8::PropertyDescriptor(v8_num(42), true);
+ {
+ // Use a data descriptor.
+
+ // Can't change a non-configurable property.
+ v8::TryCatch try_catch(isolate);
+ CHECK(!obj->DefineProperty(env.local(), v8_str("foo"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("foo")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
+
+ // Change configurable property
+ CHECK(obj->DefineProperty(env.local(), v8_str("bar"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ val = obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
+
+ {
+ // Set a regular property.
+ v8::TryCatch try_catch(isolate);
+ CHECK(obj->DefineProperty(env.local(), v8_str("blub"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
+
+ {
+ // Set an indexed property.
+ v8::TryCatch try_catch(isolate);
+ CHECK(obj->DefineProperty(env.local(), v8_str("1"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
+
+ {
+ // No special case when changing array length.
+ v8::TryCatch try_catch(isolate);
+ CHECK(arr->DefineProperty(env.local(), v8_str("length"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ {
+ // Special cases for arrays: index exceeds the array's length.
+ v8::TryCatch try_catch(isolate);
+ CHECK(arr->DefineProperty(env.local(), v8_str("100"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(101U, arr->Length());
+ v8::Local<v8::Value> val = arr->Get(env.local(), 100).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+
+ // Set an existing entry.
+ CHECK(arr->DefineProperty(env.local(), v8_str("0"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ val = arr->Get(env.local(), 0).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ }
+
+ {
+ // Use a generic descriptor.
+ const v8::PropertyDescriptor desc = v8::PropertyDescriptor();
+
+ v8::TryCatch try_catch(isolate);
+ CHECK(
+ obj->DefineProperty(env.local(), v8_str("generic"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("generic")).ToLocalChecked();
+ CHECK(val->IsUndefined());
+
+ obj->Set(env.local(), v8_str("generic"), v8_num(1)).FromJust();
+ CHECK(!try_catch.HasCaught());
+
+ val = obj->Get(env.local(), v8_str("generic")).ToLocalChecked();
+ CHECK(val->IsUndefined());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ {
+ // Use a data descriptor with empty handle.
+ const v8::PropertyDescriptor desc =
+ v8::PropertyDescriptor(v8::Local<v8::Value>(), true);
+
+ v8::TryCatch try_catch(isolate);
+ CHECK(
+ obj->DefineProperty(env.local(), v8_str("generic"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("generic")).ToLocalChecked();
+ CHECK(val->IsUndefined());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ {
+ // Use a descriptor with attribute == v8::ReadOnly.
+ const v8::PropertyDescriptor desc = v8::PropertyDescriptor(
+ v8_num(42), true, true, true, true, true, false, true);
+
+ v8::TryCatch try_catch(isolate);
+ CHECK(obj->DefineProperty(env.local(), v8_str("lala"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("lala")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
+ CHECK_EQ(
+ v8::ReadOnly,
+ obj->GetPropertyAttributes(env.local(), v8_str("lala")).FromJust());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ {
+ // Use an accessor descriptor with empty handles.
+ const v8::PropertyDescriptor desc = v8::PropertyDescriptor(
+ v8::Local<v8::Function>(), true, v8::Local<v8::Function>(), true);
+
+ v8::TryCatch try_catch(isolate);
+ CHECK(obj->DefineProperty(env.local(), v8_str("undef_accessor"), &desc)
+ .FromJust());
+ CHECK(!try_catch.HasCaught());
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("undef_accessor")).ToLocalChecked();
+ CHECK(val->IsUndefined());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ {
+ // Use an accessor descriptor.
+ CompileRun(
+ "var set = function(x) {this.val = 2*x;};"
+ "var get = function() {return this.val || 0;};");
+
+ v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
+ env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
+ v8::Local<v8::Function> set = v8::Local<v8::Function>::Cast(
+ env->Global()->Get(env.local(), v8_str("set")).ToLocalChecked());
+ const v8::PropertyDescriptor desc =
+ v8::PropertyDescriptor(get, true, set, true);
+
+ v8::TryCatch try_catch(isolate);
+ CHECK(obj->DefineProperty(env.local(), v8_str("twice"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+
+ v8::Local<v8::Value> val =
+ obj->Get(env.local(), v8_str("twice")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(0.0, val->NumberValue(env.local()).FromJust());
+ CHECK(!try_catch.HasCaught());
+
+ obj->Set(env.local(), v8_str("twice"), v8_num(7)).FromJust();
+ CHECK(!try_catch.HasCaught());
+
+ val = obj->Get(env.local(), v8_str("twice")).ToLocalChecked();
+ CHECK(val->IsNumber());
+ CHECK_EQ(14.0, val->NumberValue(env.local()).FromJust());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ {
+ // Re-define a property
+ // desc = {value: 42, enumerable: true}
+ const v8::PropertyDescriptor desc =
+ v8::PropertyDescriptor(v8_num(42), false, true, true);
+ v8::TryCatch try_catch(isolate);
+ CHECK(
+ obj->DefineProperty(env.local(), v8_str("has_enum"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+
+ // desc = {enumerable: true}
+ // successful because has_enumerable with same value as existing descriptor
+ const v8::PropertyDescriptor desc_true =
+ v8::PropertyDescriptor(v8::Local<v8::Value>(), false, true, true);
+ CHECK(obj->DefineProperty(env.local(), v8_str("has_enum"), &desc_true)
+ .FromJust());
+ CHECK(!try_catch.HasCaught());
+
+ // desc = {}
+ // successful because !has_enumerable
+ const v8::PropertyDescriptor desc_empty = v8::PropertyDescriptor();
+ CHECK(obj->DefineProperty(env.local(), v8_str("has_enum"), &desc_empty)
+ .FromJust());
+ CHECK(!try_catch.HasCaught());
+
+ // desc = {enumerable: false}
+ const v8::PropertyDescriptor desc_false =
+ v8::PropertyDescriptor(v8::Local<v8::Value>(), false, false, true);
+ // not be successful, because we cannot overwrite enumerable
+ CHECK(!obj->DefineProperty(env.local(), v8_str("has_enum"), &desc_false)
+ .FromJust());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ CompileRun("Object.freeze(a);");
+ {
+ // Can't change non-extensible objects.
+ v8::TryCatch try_catch(isolate);
+ CHECK(!obj->DefineProperty(env.local(), v8_str("baz"), &desc).FromJust());
+ CHECK(!try_catch.HasCaught());
+ }
+
+ v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
+ templ->SetAccessCheckCallback(AccessAlwaysBlocked);
+ v8::Local<v8::Object> access_checked =
+ templ->NewInstance(env.local()).ToLocalChecked();
+ {
+ v8::TryCatch try_catch(isolate);
+ CHECK(access_checked->DefineProperty(env.local(), v8_str("foo"), &desc)
+ .IsNothing());
+ CHECK(try_catch.HasCaught());
+ }
+}
THREADED_TEST(GetCurrentContextWhenNotInContext) {
i::Isolate* isolate = CcTest::i_isolate();
@@ -23339,6 +23575,191 @@ TEST(EventLogging) {
CHECK_EQ(1, last_event_status);
}
+TEST(PropertyDescriptor) {
+ LocalContext context;
+ v8::Isolate* isolate = context->GetIsolate();
+ v8::HandleScope scope(isolate);
+
+ // empty descriptor
+ v8::PropertyDescriptor desc;
+ CHECK(!desc.has_value());
+ CHECK(desc.value() == v8::Local<v8::Value>());
+ CHECK(!desc.has_set());
+ CHECK(!desc.has_get());
+ CHECK(!desc.enumerable());
+ CHECK(!desc.has_enumerable());
+ CHECK(!desc.configurable());
+ CHECK(!desc.has_configurable());
+ CHECK(!desc.writable());
+ CHECK(!desc.has_writable());
+
+ // data descriptor
+ desc = v8::PropertyDescriptor(v8_num(42), true);
+ CHECK(desc.value() == v8_num(42));
+ CHECK(desc.has_value());
+ CHECK(!desc.has_set());
+ CHECK(!desc.has_get());
+ CHECK(!desc.enumerable());
+ CHECK(!desc.has_enumerable());
+ CHECK(!desc.configurable());
+ CHECK(!desc.has_configurable());
+ CHECK(!desc.writable());
+ CHECK(!desc.has_writable());
+
+ // data descriptor
+ desc = v8::PropertyDescriptor(v8_num(42), false, true);
+ CHECK(desc.value() == v8_num(42));
+ CHECK(!desc.has_value());
+ CHECK(!desc.has_set());
+ CHECK(!desc.has_get());
+ CHECK(desc.enumerable());
+ CHECK(!desc.has_enumerable());
+ CHECK(!desc.configurable());
+ CHECK(!desc.has_configurable());
+ CHECK(!desc.writable());
+ CHECK(!desc.has_writable());
+
+ // data descriptor
+ desc = v8::PropertyDescriptor(v8_num(42), false, false, true);
+ CHECK(desc.value() == v8_num(42));
+ CHECK(!desc.has_value());
+ CHECK(!desc.has_set());
+ CHECK(!desc.has_get());
+ CHECK(!desc.enumerable());
+ CHECK(desc.has_enumerable());
+ CHECK(!desc.configurable());
+ CHECK(!desc.has_configurable());
+ CHECK(!desc.writable());
+ CHECK(!desc.has_writable());
+
+ // data descriptor
+ desc = v8::PropertyDescriptor(v8_num(42), false, false, false, true);
+ CHECK(desc.value() == v8_num(42));
+ CHECK(!desc.has_value());
+ CHECK(!desc.has_set());
+ CHECK(!desc.has_get());
+ CHECK(!desc.enumerable());
+ CHECK(!desc.has_enumerable());
+ CHECK(desc.configurable());
+ CHECK(!desc.has_configurable());
+ CHECK(!desc.writable());
+ CHECK(!desc.has_writable());
+
+ // data descriptor
+ desc = v8::PropertyDescriptor(v8_num(42), false, false, false, false, true);
+ CHECK(desc.value() == v8_num(42));
+ CHECK(!desc.has_value());
+ CHECK(!desc.has_set());
+ CHECK(!desc.has_get());
+ CHECK(!desc.enumerable());
+ CHECK(!desc.has_enumerable());
+ CHECK(!desc.configurable());
+ CHECK(desc.has_configurable());
+ CHECK(!desc.writable());
+ CHECK(!desc.has_writable());
+
+ // data descriptor
+ desc = v8::PropertyDescriptor(v8_num(42), false, false, false, false, false,
+ true);
+ CHECK(desc.value() == v8_num(42));
+ CHECK(!desc.has_value());
+ CHECK(!desc.has_set());
+ CHECK(!desc.has_get());
+ CHECK(!desc.enumerable());
+ CHECK(!desc.has_enumerable());
+ CHECK(!desc.configurable());
+ CHECK(!desc.has_configurable());
+ CHECK(desc.writable());
+ CHECK(!desc.has_writable());
+
+ // data descriptor
+ desc = v8::PropertyDescriptor(v8_num(42), false, false, false, false, false,
+ false, true);
+ CHECK(desc.value() == v8_num(42));
+ CHECK(!desc.has_value());
+ CHECK(!desc.has_set());
+ CHECK(!desc.has_get());
+ CHECK(!desc.enumerable());
+ CHECK(!desc.has_enumerable());
+ CHECK(!desc.configurable());
+ CHECK(!desc.has_configurable());
+ CHECK(!desc.writable());
+ CHECK(desc.has_writable());
+
+ // data descriptor
+ desc = v8::PropertyDescriptor(v8::Local<v8::Value>(), false, false, false,
+ false, false, false, true);
+ CHECK(!desc.has_value());
+ CHECK(!desc.has_set());
+ CHECK(!desc.has_get());
+ CHECK(!desc.has_enumerable());
+ CHECK(!desc.has_configurable());
+ CHECK(desc.has_writable());
+ CHECK(!desc.writable());
+
+ // accessor descriptor
+ LocalContext env;
+
+ CompileRun(
+ "var set = function() {return 43;};"
+ "var get = function() {return 42;};");
+
+ v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
+ env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
+ v8::Local<v8::Function> set = v8::Local<v8::Function>::Cast(
+ env->Global()->Get(env.local(), v8_str("set")).ToLocalChecked());
+ desc =
+ v8::PropertyDescriptor(get, false, set, true, false, false, false, true);
+ CHECK(!desc.has_value());
+ CHECK(desc.get() == get);
+ CHECK(!desc.has_get());
+ CHECK(desc.set() == set);
+ CHECK(desc.has_set());
+ CHECK(!desc.enumerable());
+ CHECK(!desc.has_enumerable());
+ CHECK(!desc.configurable());
+ CHECK(desc.has_configurable());
+ CHECK(!desc.writable());
+ CHECK(!desc.has_writable());
+
+ // accessor descriptor with Proxy
+ CompileRun(
+ "var set = new Proxy(function() {}, {});"
+ "var get = function() {return 42;};");
+
+ get = v8::Local<v8::Function>::Cast(
+ env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
+ set = v8::Local<v8::Function>::Cast(
+ env->Global()->Get(env.local(), v8_str("set")).ToLocalChecked());
+ desc =
+ v8::PropertyDescriptor(get, false, set, true, false, false, false, true);
+ CHECK(!desc.has_value());
+ CHECK(desc.get() == get);
+ CHECK(!desc.has_get());
+ CHECK(desc.set() == set);
+ CHECK(desc.has_set());
+ CHECK(!desc.enumerable());
+ CHECK(!desc.has_enumerable());
+ CHECK(!desc.configurable());
+ CHECK(desc.has_configurable());
+ CHECK(!desc.writable());
+ CHECK(!desc.has_writable());
+
+ // accessor descriptor with empty function handle
+ get = v8::Local<v8::Function>();
+ desc = v8::PropertyDescriptor(get, false);
+ CHECK(!desc.has_value());
+ CHECK(desc.get() == get);
+ CHECK(!desc.has_get());
+ CHECK(desc.set() == v8::Local<v8::Function>());
+ CHECK(!desc.has_set());
+ CHECK(!desc.enumerable());
+ CHECK(!desc.has_enumerable());
+ CHECK(!desc.configurable());
+ CHECK(!desc.has_configurable());
+ CHECK(!desc.writable());
+ CHECK(!desc.has_writable());
+}
TEST(Promises) {
LocalContext context;
« src/api.cc ('K') | « src/counters.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698