1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gin/data_object_builder.h"
7 #include "base/check_op.h"
8 #include "base/debug/debugging_buildflags.h"
9 #include "base/functional/bind.h"
10 #include "base/logging.h"
11 #include "gin/dictionary.h"
12 #include "gin/public/isolate_holder.h"
13 #include "gin/test/v8_test.h"
14 #include "v8/include/v8-context.h"
15 #include "v8/include/v8-function.h"
20 using DataObjectBuilderTest = V8Test;
22 // It should create ordinary data properties.
23 TEST_F(DataObjectBuilderTest, CreatesDataProperties) {
24 v8::Isolate* isolate = instance_->isolate();
25 v8::HandleScope handle_scope(isolate);
26 v8::Local<v8::Context> context = context_.Get(isolate);
28 v8::Local<v8::Object> object =
29 DataObjectBuilder(isolate).Set("key", 42).Build();
30 ASSERT_TRUE(object->HasOwnProperty(context, StringToSymbol(isolate, "key"))
33 v8::Local<v8::Value> descriptor_object;
35 object->GetOwnPropertyDescriptor(context, StringToSymbol(isolate, "key"))
36 .ToLocal(&descriptor_object));
37 gin::Dictionary descriptor(isolate, descriptor_object.As<v8::Object>());
40 ASSERT_TRUE(descriptor.Get("value", &value));
43 bool writable = false;
44 ASSERT_TRUE(descriptor.Get("writable", &writable));
45 EXPECT_TRUE(writable);
47 bool enumerable = false;
48 ASSERT_TRUE(descriptor.Get("enumerable", &enumerable));
49 EXPECT_TRUE(enumerable);
51 bool configurable = false;
52 ASSERT_TRUE(descriptor.Get("configurable", &configurable));
53 EXPECT_TRUE(configurable);
56 // It should not invoke setters on the prototype chain.
57 TEST_F(DataObjectBuilderTest, DoesNotInvokeSetters) {
58 v8::Isolate* isolate = instance_->isolate();
59 v8::HandleScope handle_scope(isolate);
60 v8::Local<v8::Context> context = context_.Get(isolate);
62 // Install a setter on the object prototype.
63 v8::Local<v8::Value> object_constructor;
64 ASSERT_TRUE(context->Global()
65 ->Get(context, StringToSymbol(isolate, "Object"))
66 .ToLocal(&object_constructor));
67 v8::Local<v8::Value> object_prototype;
68 ASSERT_TRUE(object_constructor.As<v8::Function>()
69 ->Get(context, StringToSymbol(isolate, "prototype"))
70 .ToLocal(&object_prototype));
72 object_prototype.As<v8::Object>()
73 ->SetAccessor(context, StringToSymbol(isolate, "key"),
74 [](v8::Local<v8::Name>,
75 const v8::PropertyCallbackInfo<v8::Value>&) {},
76 [](v8::Local<v8::Name>, v8::Local<v8::Value>,
77 const v8::PropertyCallbackInfo<void>&) {
78 ADD_FAILURE() << "setter should not be invoked";
83 DataObjectBuilder(isolate).Set("key", 42).Build();
86 // The internal handle is cleared when the builder is finished.
87 // This makes the class harder to abuse, so that its methods cannot be used
88 // after something may have modified the object in unexpected ways.
89 // TODO(pbos): Consider making this a CHECK and test this everywhere.
90 #if DCHECK_IS_ON() && !BUILDFLAG(DCHECK_IS_CONFIGURABLE)
91 TEST_F(DataObjectBuilderTest, UnusableAfterBuild) {
92 v8::Isolate* isolate = instance_->isolate();
93 v8::HandleScope handle_scope(isolate);
95 DataObjectBuilder builder(isolate);
96 EXPECT_FALSE(builder.Build().IsEmpty());
98 EXPECT_DEATH_IF_SUPPORTED(builder.Build(),
99 "Check failed: !object_.IsEmpty\\(\\)");
101 #endif // DCHECK_IS_ON()
103 // As is the normal behaviour of CreateDataProperty, new data properties should
104 // replace existing ones. Since no non-configurable ones are present, nor should
105 // the object be non-extensible, this should work.
106 TEST_F(DataObjectBuilderTest, ReplacesExistingProperties) {
107 v8::Isolate* isolate = instance_->isolate();
108 v8::HandleScope handle_scope(isolate);
110 v8::Local<v8::Object> object =
111 DataObjectBuilder(isolate).Set("value", 42).Set("value", 55).Build();
113 gin::Dictionary dictionary(isolate, object);
115 ASSERT_TRUE(dictionary.Get("value", &value));
116 EXPECT_EQ(55, value);
119 // It should work for array indices, too.
120 TEST_F(DataObjectBuilderTest, CreatesDataPropertiesForIndices) {
121 v8::Isolate* isolate = instance_->isolate();
122 v8::HandleScope handle_scope(isolate);
123 v8::Local<v8::Context> context = context_.Get(isolate);
125 v8::Local<v8::Object> object = DataObjectBuilder(isolate)
126 .Set(42, base::StringPiece("forty-two"))
128 ASSERT_TRUE(object->HasOwnProperty(context, 42).ToChecked());
130 v8::Local<v8::Value> descriptor_object;
132 object->GetOwnPropertyDescriptor(context, StringToSymbol(isolate, "42"))
133 .ToLocal(&descriptor_object));
134 gin::Dictionary descriptor(isolate, descriptor_object.As<v8::Object>());
137 ASSERT_TRUE(descriptor.Get("value", &value));
138 EXPECT_EQ("forty-two", value);
140 bool writable = false;
141 ASSERT_TRUE(descriptor.Get("writable", &writable));
142 EXPECT_TRUE(writable);
144 bool enumerable = false;
145 ASSERT_TRUE(descriptor.Get("enumerable", &enumerable));
146 EXPECT_TRUE(enumerable);
148 bool configurable = false;
149 ASSERT_TRUE(descriptor.Get("configurable", &configurable));
150 EXPECT_TRUE(configurable);