2017-03-29 11:03:38 +00:00
|
|
|
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "include/v8.h"
|
|
|
|
#include "test/unittests/test-utils.h"
|
|
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
using InterceptorTest = TestWithContext;
|
|
|
|
|
|
|
|
void NamedGetter(Local<Name> property,
|
|
|
|
const PropertyCallbackInfo<Value>& info) {}
|
|
|
|
|
|
|
|
TEST_F(InterceptorTest, FreezeApiObjectWithInterceptor) {
|
|
|
|
TryCatch try_catch(isolate());
|
|
|
|
|
|
|
|
Local<FunctionTemplate> tmpl = FunctionTemplate::New(isolate());
|
|
|
|
tmpl->InstanceTemplate()->SetHandler(
|
|
|
|
NamedPropertyHandlerConfiguration(NamedGetter));
|
|
|
|
|
|
|
|
Local<Function> ctor = tmpl->GetFunction(context()).ToLocalChecked();
|
|
|
|
Local<Object> obj = ctor->NewInstance(context()).ToLocalChecked();
|
|
|
|
ASSERT_TRUE(
|
|
|
|
obj->SetIntegrityLevel(context(), IntegrityLevel::kFrozen).IsNothing());
|
|
|
|
ASSERT_TRUE(try_catch.HasCaught());
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
2018-08-09 09:18:08 +00:00
|
|
|
|
|
|
|
namespace internal {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class InterceptorLoggingTest : public TestWithNativeContext {
|
|
|
|
public:
|
2018-09-13 10:07:40 +00:00
|
|
|
InterceptorLoggingTest() = default;
|
2018-08-09 09:18:08 +00:00
|
|
|
|
|
|
|
static const int kTestIndex = 0;
|
|
|
|
|
|
|
|
static void NamedPropertyGetter(Local<v8::Name> name,
|
|
|
|
const v8::PropertyCallbackInfo<Value>& info) {
|
|
|
|
LogCallback(info, "named getter");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NamedPropertySetter(Local<v8::Name> name, Local<v8::Value> value,
|
|
|
|
const v8::PropertyCallbackInfo<Value>& info) {
|
|
|
|
LogCallback(info, "named setter");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NamedPropertyQuery(
|
|
|
|
Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) {
|
|
|
|
LogCallback(info, "named query");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NamedPropertyDeleter(
|
|
|
|
Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
|
|
|
|
LogCallback(info, "named deleter");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NamedPropertyEnumerator(
|
|
|
|
const v8::PropertyCallbackInfo<Array>& info) {
|
|
|
|
LogCallback(info, "named enumerator");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NamedPropertyDefiner(
|
|
|
|
Local<v8::Name> name, const v8::PropertyDescriptor& desc,
|
|
|
|
const v8::PropertyCallbackInfo<Value>& info) {
|
|
|
|
LogCallback(info, "named definer");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NamedPropertyDescriptor(
|
|
|
|
Local<v8::Name> name, const v8::PropertyCallbackInfo<Value>& info) {
|
|
|
|
LogCallback(info, "named descriptor");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void IndexedPropertyGetter(
|
|
|
|
uint32_t index, const v8::PropertyCallbackInfo<Value>& info) {
|
|
|
|
LogCallback(info, "indexed getter");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void IndexedPropertySetter(
|
|
|
|
uint32_t index, Local<v8::Value> value,
|
|
|
|
const v8::PropertyCallbackInfo<Value>& info) {
|
|
|
|
LogCallback(info, "indexed setter");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void IndexedPropertyQuery(
|
|
|
|
uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
|
|
|
|
LogCallback(info, "indexed query");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void IndexedPropertyDeleter(
|
|
|
|
uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
|
|
|
|
LogCallback(info, "indexed deleter");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void IndexedPropertyEnumerator(
|
|
|
|
const v8::PropertyCallbackInfo<Array>& info) {
|
|
|
|
LogCallback(info, "indexed enumerator");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void IndexedPropertyDefiner(
|
|
|
|
uint32_t index, const v8::PropertyDescriptor& desc,
|
|
|
|
const v8::PropertyCallbackInfo<Value>& info) {
|
|
|
|
LogCallback(info, "indexed definer");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void IndexedPropertyDescriptor(
|
|
|
|
uint32_t index, const v8::PropertyCallbackInfo<Value>& info) {
|
|
|
|
LogCallback(info, "indexed descriptor");
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
static void LogCallback(const v8::PropertyCallbackInfo<T>& info,
|
|
|
|
const char* callback_name) {
|
|
|
|
InterceptorLoggingTest* test = reinterpret_cast<InterceptorLoggingTest*>(
|
|
|
|
info.This()->GetAlignedPointerFromInternalField(kTestIndex));
|
|
|
|
test->Log(callback_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Log(const char* callback_name) {
|
|
|
|
if (log_is_empty_) {
|
|
|
|
log_is_empty_ = false;
|
|
|
|
} else {
|
|
|
|
log_ << ", ";
|
|
|
|
}
|
|
|
|
log_ << callback_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void SetUp() override {
|
|
|
|
// Set up the object that supports full interceptors.
|
|
|
|
v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(v8_isolate());
|
|
|
|
templ->SetInternalFieldCount(1);
|
|
|
|
templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
|
|
|
|
NamedPropertyGetter, NamedPropertySetter, NamedPropertyQuery,
|
|
|
|
NamedPropertyDeleter, NamedPropertyEnumerator, NamedPropertyDefiner,
|
|
|
|
NamedPropertyDescriptor));
|
|
|
|
templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
|
|
|
|
IndexedPropertyGetter, IndexedPropertySetter, IndexedPropertyQuery,
|
|
|
|
IndexedPropertyDeleter, IndexedPropertyEnumerator,
|
|
|
|
IndexedPropertyDefiner, IndexedPropertyDescriptor));
|
|
|
|
v8::Local<v8::Object> instance =
|
|
|
|
templ->NewInstance(context()).ToLocalChecked();
|
|
|
|
instance->SetAlignedPointerInInternalField(kTestIndex, this);
|
|
|
|
SetGlobalProperty("obj", instance);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Run(const char* script) {
|
|
|
|
log_is_empty_ = true;
|
|
|
|
log_.str(std::string());
|
|
|
|
log_.clear();
|
|
|
|
|
|
|
|
RunJS(script);
|
|
|
|
return log_.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool log_is_empty_ = false;
|
|
|
|
std::stringstream log_;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(InterceptorLoggingTest, DispatchTest) {
|
|
|
|
EXPECT_EQ(Run("for (var p in obj) {}"),
|
|
|
|
"indexed enumerator, named enumerator");
|
|
|
|
EXPECT_EQ(Run("Object.keys(obj)"), "indexed enumerator, named enumerator");
|
|
|
|
|
|
|
|
EXPECT_EQ(Run("obj.foo"), "named getter");
|
|
|
|
EXPECT_EQ(Run("obj[42]"), "indexed getter");
|
|
|
|
|
|
|
|
EXPECT_EQ(Run("obj.foo = null"), "named setter");
|
|
|
|
EXPECT_EQ(Run("obj[42] = null"), "indexed setter");
|
|
|
|
|
|
|
|
EXPECT_EQ(Run("Object.getOwnPropertyDescriptor(obj, 'foo')"),
|
|
|
|
"named descriptor");
|
|
|
|
|
|
|
|
EXPECT_EQ(Run("Object.getOwnPropertyDescriptor(obj, 42)"),
|
|
|
|
"indexed descriptor");
|
|
|
|
|
|
|
|
EXPECT_EQ(Run("Object.defineProperty(obj, 'foo', {value: 42})"),
|
|
|
|
"named descriptor, named definer, named setter");
|
|
|
|
EXPECT_EQ(Run("Object.defineProperty(obj, 'foo', {get(){} })"),
|
|
|
|
"named descriptor, named definer");
|
|
|
|
EXPECT_EQ(Run("Object.defineProperty(obj, 'foo', {set(value){}})"),
|
|
|
|
"named descriptor, named definer");
|
|
|
|
EXPECT_EQ(Run("Object.defineProperty(obj, 'foo', {get(){}, set(value){}})"),
|
|
|
|
"named descriptor, named definer");
|
|
|
|
|
|
|
|
EXPECT_EQ(Run("Object.defineProperty(obj, 42, {value: 'foo'})"),
|
|
|
|
"indexed descriptor, "
|
|
|
|
// then attempt definer first and fallback to setter.
|
|
|
|
"indexed definer, indexed setter");
|
|
|
|
|
|
|
|
EXPECT_EQ(Run("Object.prototype.propertyIsEnumerable.call(obj, 'a')"),
|
|
|
|
"named query");
|
|
|
|
EXPECT_EQ(Run("Object.prototype.propertyIsEnumerable.call(obj, 42)"),
|
|
|
|
"indexed query");
|
|
|
|
|
|
|
|
EXPECT_EQ(Run("Object.prototype.hasOwnProperty.call(obj, 'a')"),
|
|
|
|
"named query");
|
|
|
|
// TODO(cbruni): Fix once hasOnwProperty is fixed (https://crbug.com/872628)
|
|
|
|
EXPECT_EQ(Run("Object.prototype.hasOwnProperty.call(obj, '42')"), "");
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
} // namespace internal
|
2017-03-29 11:03:38 +00:00
|
|
|
} // namespace v8
|