| Index: test/cctest/test-api.cc
|
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
| index 484d2f32264643d36cb29130e0e3259061185f06..50cae80c2be2b955ec87bb6a72677209c800c219 100644
|
| --- a/test/cctest/test-api.cc
|
| +++ b/test/cctest/test-api.cc
|
| @@ -16004,6 +16004,271 @@ TEST(DefineOwnProperty) {
|
| }
|
| }
|
|
|
| +TEST(DefineProperty) {
|
| + LocalContext env;
|
| + v8::Isolate* isolate = env->GetIsolate();
|
| + v8::HandleScope handle_scope(isolate);
|
| +
|
| + v8::Local<v8::Name> p;
|
| +
|
| + CompileRun(
|
| + "var a = {};"
|
| + "var b = [];"
|
| + "Object.defineProperty(a, 'v1', {value: 23});"
|
| + "Object.defineProperty(a, 'v2', {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.
|
| + p = v8_str("v1");
|
| + v8::TryCatch try_catch(isolate);
|
| + CHECK(!obj->DefineProperty(env.local(), p, desc).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
|
| + CHECK(val->IsNumber());
|
| + CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
|
| +
|
| + // Change configurable property
|
| + p = v8_str("v2");
|
| + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| + val = obj->Get(env.local(), p).ToLocalChecked();
|
| + CHECK(val->IsNumber());
|
| + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
|
| + }
|
| +
|
| + {
|
| + // Set a regular property.
|
| + p = v8_str("v3");
|
| + v8::TryCatch try_catch(isolate);
|
| + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| + v8::Local<v8::Value> val = obj->Get(env.local(), p).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();
|
| +
|
| + p = v8_str("v4");
|
| + v8::TryCatch try_catch(isolate);
|
| + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
|
| + CHECK(val->IsUndefined());
|
| +
|
| + obj->Set(env.local(), p, v8_num(1)).FromJust();
|
| + CHECK(!try_catch.HasCaught());
|
| +
|
| + val = obj->Get(env.local(), p).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(), p, desc).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| + v8::Local<v8::Value> val = obj->Get(env.local(), p).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);
|
| +
|
| + p = v8_str("v5");
|
| + v8::TryCatch try_catch(isolate);
|
| + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
|
| + CHECK(val->IsNumber());
|
| + CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
|
| + CHECK_EQ(v8::ReadOnly,
|
| + obj->GetPropertyAttributes(env.local(), p).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);
|
| +
|
| + p = v8_str("v6");
|
| + v8::TryCatch try_catch(isolate);
|
| + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| + v8::Local<v8::Value> val = obj->Get(env.local(), p).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);
|
| +
|
| + p = v8_str("v7");
|
| + v8::TryCatch try_catch(isolate);
|
| + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| +
|
| + v8::Local<v8::Value> val = obj->Get(env.local(), p).ToLocalChecked();
|
| + CHECK(val->IsNumber());
|
| + CHECK_EQ(0.0, val->NumberValue(env.local()).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| +
|
| + obj->Set(env.local(), p, v8_num(7)).FromJust();
|
| + CHECK(!try_catch.HasCaught());
|
| +
|
| + val = obj->Get(env.local(), p).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), true, true, true);
|
| +
|
| + p = v8_str("v8");
|
| + v8::TryCatch try_catch(isolate);
|
| + CHECK(obj->DefineProperty(env.local(), p, 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(), p, desc_true).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| +
|
| + // desc = {}
|
| + // successful because !has_enumerable
|
| + const v8::PropertyDescriptor desc_empty = v8::PropertyDescriptor();
|
| + CHECK(obj->DefineProperty(env.local(), p, 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 successful, because we cannot overwrite enumerable
|
| + CHECK(!obj->DefineProperty(env.local(), p, desc_false).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| + }
|
| +
|
| + {
|
| + // Re-define a property that has a getter
|
| + CompileRun("var get = function() {};");
|
| + v8::Local<v8::Function> get = v8::Local<v8::Function>::Cast(
|
| + env->Global()->Get(env.local(), v8_str("get")).ToLocalChecked());
|
| +
|
| + // desc = {get: function() {}}
|
| + const v8::PropertyDescriptor desc = v8::PropertyDescriptor(get, true);
|
| + v8::TryCatch try_catch(isolate);
|
| +
|
| + p = v8_str("v9");
|
| + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| +
|
| + // desc = {}
|
| + // successful because get not redefined
|
| + const v8::PropertyDescriptor desc_empty = v8::PropertyDescriptor();
|
| + CHECK(obj->DefineProperty(env.local(), p, desc_empty).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| +
|
| + // desc = {get: function() {}}
|
| + // successful because re-define with same value
|
| + CHECK(obj->DefineProperty(env.local(), p, desc).FromJust());
|
| + CHECK(!try_catch.HasCaught());
|
| +
|
| + // desc = {get: undefined}
|
| + const v8::PropertyDescriptor desc_undefined =
|
| + v8::PropertyDescriptor(v8::Local<v8::Value>(), true);
|
| + // not successful, because we cannot overwrite with undefined
|
| + CHECK(!obj->DefineProperty(env.local(), p, desc_undefined).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("v10"), 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("v11"), desc)
|
| + .IsNothing());
|
| + CHECK(try_catch.HasCaught());
|
| + }
|
| +}
|
|
|
| THREADED_TEST(GetCurrentContextWhenNotInContext) {
|
| i::Isolate* isolate = CcTest::i_isolate();
|
| @@ -23339,6 +23604,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;
|
|
|