Line data Source code
1 : // Copyright 2017 the V8 project 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 "include/v8.h"
6 : #include "test/unittests/test-utils.h"
7 : #include "testing/gtest/include/gtest/gtest.h"
8 :
9 : namespace v8 {
10 : namespace {
11 :
12 : using InterceptorTest = TestWithContext;
13 :
14 0 : void NamedGetter(Local<Name> property,
15 0 : const PropertyCallbackInfo<Value>& info) {}
16 :
17 15419 : TEST_F(InterceptorTest, FreezeApiObjectWithInterceptor) {
18 2 : TryCatch try_catch(isolate());
19 :
20 1 : Local<FunctionTemplate> tmpl = FunctionTemplate::New(isolate());
21 2 : tmpl->InstanceTemplate()->SetHandler(
22 1 : NamedPropertyHandlerConfiguration(NamedGetter));
23 :
24 1 : Local<Function> ctor = tmpl->GetFunction(context()).ToLocalChecked();
25 : Local<Object> obj = ctor->NewInstance(context()).ToLocalChecked();
26 2 : ASSERT_TRUE(
27 : obj->SetIntegrityLevel(context(), IntegrityLevel::kFrozen).IsNothing());
28 2 : ASSERT_TRUE(try_catch.HasCaught());
29 : }
30 :
31 : } // namespace
32 :
33 : namespace internal {
34 : namespace {
35 :
36 2 : class InterceptorLoggingTest : public TestWithNativeContext {
37 : public:
38 2 : InterceptorLoggingTest() = default;
39 :
40 : static const int kTestIndex = 0;
41 :
42 1 : static void NamedPropertyGetter(Local<v8::Name> name,
43 : const v8::PropertyCallbackInfo<Value>& info) {
44 1 : LogCallback(info, "named getter");
45 1 : }
46 :
47 2 : static void NamedPropertySetter(Local<v8::Name> name, Local<v8::Value> value,
48 : const v8::PropertyCallbackInfo<Value>& info) {
49 2 : LogCallback(info, "named setter");
50 2 : }
51 :
52 2 : static void NamedPropertyQuery(
53 : Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) {
54 2 : LogCallback(info, "named query");
55 2 : }
56 :
57 0 : static void NamedPropertyDeleter(
58 : Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
59 0 : LogCallback(info, "named deleter");
60 0 : }
61 :
62 2 : static void NamedPropertyEnumerator(
63 : const v8::PropertyCallbackInfo<Array>& info) {
64 2 : LogCallback(info, "named enumerator");
65 2 : }
66 :
67 4 : static void NamedPropertyDefiner(
68 : Local<v8::Name> name, const v8::PropertyDescriptor& desc,
69 : const v8::PropertyCallbackInfo<Value>& info) {
70 4 : LogCallback(info, "named definer");
71 4 : }
72 :
73 5 : static void NamedPropertyDescriptor(
74 : Local<v8::Name> name, const v8::PropertyCallbackInfo<Value>& info) {
75 5 : LogCallback(info, "named descriptor");
76 5 : }
77 :
78 1 : static void IndexedPropertyGetter(
79 : uint32_t index, const v8::PropertyCallbackInfo<Value>& info) {
80 1 : LogCallback(info, "indexed getter");
81 1 : }
82 :
83 2 : static void IndexedPropertySetter(
84 : uint32_t index, Local<v8::Value> value,
85 : const v8::PropertyCallbackInfo<Value>& info) {
86 2 : LogCallback(info, "indexed setter");
87 2 : }
88 :
89 1 : static void IndexedPropertyQuery(
90 : uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
91 1 : LogCallback(info, "indexed query");
92 1 : }
93 :
94 0 : static void IndexedPropertyDeleter(
95 : uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
96 0 : LogCallback(info, "indexed deleter");
97 0 : }
98 :
99 2 : static void IndexedPropertyEnumerator(
100 : const v8::PropertyCallbackInfo<Array>& info) {
101 2 : LogCallback(info, "indexed enumerator");
102 2 : }
103 :
104 1 : static void IndexedPropertyDefiner(
105 : uint32_t index, const v8::PropertyDescriptor& desc,
106 : const v8::PropertyCallbackInfo<Value>& info) {
107 1 : LogCallback(info, "indexed definer");
108 1 : }
109 :
110 2 : static void IndexedPropertyDescriptor(
111 : uint32_t index, const v8::PropertyCallbackInfo<Value>& info) {
112 2 : LogCallback(info, "indexed descriptor");
113 2 : }
114 :
115 : template <class T>
116 25 : static void LogCallback(const v8::PropertyCallbackInfo<T>& info,
117 : const char* callback_name) {
118 : InterceptorLoggingTest* test = reinterpret_cast<InterceptorLoggingTest*>(
119 : info.This()->GetAlignedPointerFromInternalField(kTestIndex));
120 25 : test->Log(callback_name);
121 25 : }
122 :
123 25 : void Log(const char* callback_name) {
124 25 : if (log_is_empty_) {
125 16 : log_is_empty_ = false;
126 : } else {
127 9 : log_ << ", ";
128 : }
129 25 : log_ << callback_name;
130 25 : }
131 :
132 : protected:
133 1 : void SetUp() override {
134 : // Set up the object that supports full interceptors.
135 1 : v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(v8_isolate());
136 1 : templ->SetInternalFieldCount(1);
137 1 : templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
138 : NamedPropertyGetter, NamedPropertySetter, NamedPropertyQuery,
139 : NamedPropertyDeleter, NamedPropertyEnumerator, NamedPropertyDefiner,
140 1 : NamedPropertyDescriptor));
141 1 : templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
142 : IndexedPropertyGetter, IndexedPropertySetter, IndexedPropertyQuery,
143 : IndexedPropertyDeleter, IndexedPropertyEnumerator,
144 1 : IndexedPropertyDefiner, IndexedPropertyDescriptor));
145 : v8::Local<v8::Object> instance =
146 1 : templ->NewInstance(context()).ToLocalChecked();
147 1 : instance->SetAlignedPointerInInternalField(kTestIndex, this);
148 1 : SetGlobalProperty("obj", instance);
149 1 : }
150 :
151 17 : std::string Run(const char* script) {
152 17 : log_is_empty_ = true;
153 17 : log_.str(std::string());
154 17 : log_.clear();
155 :
156 : RunJS(script);
157 17 : return log_.str();
158 : }
159 :
160 : private:
161 : bool log_is_empty_ = false;
162 : std::stringstream log_;
163 : };
164 :
165 15418 : TEST_F(InterceptorLoggingTest, DispatchTest) {
166 2 : EXPECT_EQ(Run("for (var p in obj) {}"),
167 0 : "indexed enumerator, named enumerator");
168 2 : EXPECT_EQ(Run("Object.keys(obj)"), "indexed enumerator, named enumerator");
169 :
170 2 : EXPECT_EQ(Run("obj.foo"), "named getter");
171 2 : EXPECT_EQ(Run("obj[42]"), "indexed getter");
172 :
173 2 : EXPECT_EQ(Run("obj.foo = null"), "named setter");
174 2 : EXPECT_EQ(Run("obj[42] = null"), "indexed setter");
175 :
176 2 : EXPECT_EQ(Run("Object.getOwnPropertyDescriptor(obj, 'foo')"),
177 0 : "named descriptor");
178 :
179 2 : EXPECT_EQ(Run("Object.getOwnPropertyDescriptor(obj, 42)"),
180 0 : "indexed descriptor");
181 :
182 2 : EXPECT_EQ(Run("Object.defineProperty(obj, 'foo', {value: 42})"),
183 0 : "named descriptor, named definer, named setter");
184 2 : EXPECT_EQ(Run("Object.defineProperty(obj, 'foo', {get(){} })"),
185 0 : "named descriptor, named definer");
186 2 : EXPECT_EQ(Run("Object.defineProperty(obj, 'foo', {set(value){}})"),
187 0 : "named descriptor, named definer");
188 2 : EXPECT_EQ(Run("Object.defineProperty(obj, 'foo', {get(){}, set(value){}})"),
189 0 : "named descriptor, named definer");
190 :
191 2 : EXPECT_EQ(Run("Object.defineProperty(obj, 42, {value: 'foo'})"),
192 : "indexed descriptor, "
193 : // then attempt definer first and fallback to setter.
194 0 : "indexed definer, indexed setter");
195 :
196 2 : EXPECT_EQ(Run("Object.prototype.propertyIsEnumerable.call(obj, 'a')"),
197 0 : "named query");
198 2 : EXPECT_EQ(Run("Object.prototype.propertyIsEnumerable.call(obj, 42)"),
199 0 : "indexed query");
200 :
201 2 : EXPECT_EQ(Run("Object.prototype.hasOwnProperty.call(obj, 'a')"),
202 0 : "named query");
203 : // TODO(cbruni): Fix once hasOnwProperty is fixed (https://crbug.com/872628)
204 2 : EXPECT_EQ(Run("Object.prototype.hasOwnProperty.call(obj, '42')"), "");
205 1 : }
206 : } // namespace
207 : } // namespace internal
208 9249 : } // namespace v8
|