blob: 74762741edcac1c30ef325ec38c27a9e47f35e2c [file] [log] [blame]
jbroman5967a862017-04-27 16:52:451// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "gin/data_object_builder.h"
6
7#include "base/bind.h"
Hans Wennborg5cd6d192020-06-18 11:14:568#include "base/logging.h"
jbroman5967a862017-04-27 16:52:459#include "gin/dictionary.h"
10#include "gin/public/isolate_holder.h"
11#include "gin/test/v8_test.h"
12
13namespace gin {
14namespace {
15
16using DataObjectBuilderTest = V8Test;
17
18// It should create ordinary data properties.
19TEST_F(DataObjectBuilderTest, CreatesDataProperties) {
20 v8::Isolate* isolate = instance_->isolate();
21 v8::HandleScope handle_scope(isolate);
22 v8::Local<v8::Context> context = context_.Get(isolate);
23
24 v8::Local<v8::Object> object =
25 DataObjectBuilder(isolate).Set("key", 42).Build();
26 ASSERT_TRUE(object->HasOwnProperty(context, StringToSymbol(isolate, "key"))
27 .ToChecked());
28
29 v8::Local<v8::Value> descriptor_object;
30 ASSERT_TRUE(
31 object->GetOwnPropertyDescriptor(context, StringToSymbol(isolate, "key"))
32 .ToLocal(&descriptor_object));
33 gin::Dictionary descriptor(isolate, descriptor_object.As<v8::Object>());
34
35 int32_t value = 0;
36 ASSERT_TRUE(descriptor.Get("value", &value));
37 EXPECT_EQ(42, value);
38
39 bool writable = false;
40 ASSERT_TRUE(descriptor.Get("writable", &writable));
41 EXPECT_TRUE(writable);
42
43 bool enumerable = false;
44 ASSERT_TRUE(descriptor.Get("enumerable", &enumerable));
45 EXPECT_TRUE(enumerable);
46
47 bool configurable = false;
48 ASSERT_TRUE(descriptor.Get("configurable", &configurable));
49 EXPECT_TRUE(configurable);
50}
51
52// It should not invoke setters on the prototype chain.
53TEST_F(DataObjectBuilderTest, DoesNotInvokeSetters) {
54 v8::Isolate* isolate = instance_->isolate();
55 v8::HandleScope handle_scope(isolate);
56 v8::Local<v8::Context> context = context_.Get(isolate);
57
58 // Install a setter on the object prototype.
59 v8::Local<v8::Value> object_constructor;
60 ASSERT_TRUE(context->Global()
61 ->Get(context, StringToSymbol(isolate, "Object"))
62 .ToLocal(&object_constructor));
63 v8::Local<v8::Value> object_prototype;
64 ASSERT_TRUE(object_constructor.As<v8::Function>()
65 ->Get(context, StringToSymbol(isolate, "prototype"))
66 .ToLocal(&object_prototype));
67 ASSERT_TRUE(
68 object_prototype.As<v8::Object>()
69 ->SetAccessor(context, StringToSymbol(isolate, "key"),
70 [](v8::Local<v8::Name>,
71 const v8::PropertyCallbackInfo<v8::Value>&) {},
72 [](v8::Local<v8::Name>, v8::Local<v8::Value>,
73 const v8::PropertyCallbackInfo<void>&) {
74 ADD_FAILURE() << "setter should not be invoked";
75 })
76 .ToChecked());
77
78 // Create an object.
79 DataObjectBuilder(isolate).Set("key", 42).Build();
80}
81
82// The internal handle is cleared when the builder is finished.
83// This makes the class harder to abuse, so that its methods cannot be used
84// after something may have modified the object in unexpected ways.
85#if DCHECK_IS_ON()
86TEST_F(DataObjectBuilderTest, UnusableAfterBuild) {
87 v8::Isolate* isolate = instance_->isolate();
88 v8::HandleScope handle_scope(isolate);
89
90 DataObjectBuilder builder(isolate);
91 EXPECT_FALSE(builder.Build().IsEmpty());
92
93 bool has_dcheck_failure = false;
tzik6934a312018-03-08 01:03:1694 logging::ScopedLogAssertHandler handler(base::BindRepeating(
jbroman5967a862017-04-27 16:52:4595 [](bool* flag, const char* file, int line, base::StringPiece message,
96 base::StringPiece stack_trace) { *flag = true; },
97 base::Unretained(&has_dcheck_failure)));
98 builder.Build();
99 EXPECT_TRUE(has_dcheck_failure);
100}
101#endif // DCHECK_IS_ON()
102
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.
106TEST_F(DataObjectBuilderTest, ReplacesExistingProperties) {
107 v8::Isolate* isolate = instance_->isolate();
108 v8::HandleScope handle_scope(isolate);
109
110 v8::Local<v8::Object> object =
111 DataObjectBuilder(isolate).Set("value", 42).Set("value", 55).Build();
112
113 gin::Dictionary dictionary(isolate, object);
114 int32_t value;
115 ASSERT_TRUE(dictionary.Get("value", &value));
116 EXPECT_EQ(55, value);
117}
118
Jeremy Romanf9a94382017-06-06 18:45:26119// It should work for array indices, too.
120TEST_F(DataObjectBuilderTest, CreatesDataPropertiesForIndices) {
121 v8::Isolate* isolate = instance_->isolate();
122 v8::HandleScope handle_scope(isolate);
123 v8::Local<v8::Context> context = context_.Get(isolate);
124
125 v8::Local<v8::Object> object = DataObjectBuilder(isolate)
126 .Set(42, base::StringPiece("forty-two"))
127 .Build();
128 ASSERT_TRUE(object->HasOwnProperty(context, 42).ToChecked());
129
130 v8::Local<v8::Value> descriptor_object;
131 ASSERT_TRUE(
132 object->GetOwnPropertyDescriptor(context, StringToSymbol(isolate, "42"))
133 .ToLocal(&descriptor_object));
134 gin::Dictionary descriptor(isolate, descriptor_object.As<v8::Object>());
135
136 std::string value;
137 ASSERT_TRUE(descriptor.Get("value", &value));
138 EXPECT_EQ("forty-two", value);
139
140 bool writable = false;
141 ASSERT_TRUE(descriptor.Get("writable", &writable));
142 EXPECT_TRUE(writable);
143
144 bool enumerable = false;
145 ASSERT_TRUE(descriptor.Get("enumerable", &enumerable));
146 EXPECT_TRUE(enumerable);
147
148 bool configurable = false;
149 ASSERT_TRUE(descriptor.Get("configurable", &configurable));
150 EXPECT_TRUE(configurable);
151}
152
jbroman5967a862017-04-27 16:52:45153} // namespace
154} // namespace gin