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