diff options
author | abarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-12 00:41:27 +0000 |
---|---|---|
committer | abarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-12 00:41:27 +0000 |
commit | e87f312c1a96c95046034585561932bfa4aae2d4 (patch) | |
tree | 4b73e5ff782b9103ac9d282d8eda720c6f14adce /gin | |
parent | 23cd38f16a09b542cb40f9d69f5ba86aca868c8b (diff) | |
download | chromium_src-e87f312c1a96c95046034585561932bfa4aae2d4.zip chromium_src-e87f312c1a96c95046034585561932bfa4aae2d4.tar.gz chromium_src-e87f312c1a96c95046034585561932bfa4aae2d4.tar.bz2 |
Begin implementing V8 bindings for Mojo
This CL contains the beginnings of JavaScript bindings for the core Mojo
system. The approach in this CL is to bind as close to the "metal" as possible
so as to self-host as much as possiblem in the VM. I've tried to avoid
retaining any state on the C++ side of the bindings, but I didn't quite succeed
because V8 requires embedders to retain state in order to access the memory
that backs ArrayBuffers.
In this CL, I've added some basic bindings for the symbols exported by core.h.
Specifically, I've created bindings for CreateMessagePipe, Close, Wait,
WaitMany, WriteMessage, and ReadMessage.
R=aa@chromium.org, darin@chromium.org
BUG=317398
Review URL: https://codereview.chromium.org/59153005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@234347 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gin')
-rw-r--r-- | gin/arguments.cc | 36 | ||||
-rw-r--r-- | gin/arguments.h | 54 | ||||
-rw-r--r-- | gin/array_buffer.cc | 93 | ||||
-rw-r--r-- | gin/array_buffer.h | 45 | ||||
-rw-r--r-- | gin/converter.cc | 36 | ||||
-rw-r--r-- | gin/converter.h | 24 | ||||
-rw-r--r-- | gin/dictionary.cc | 40 | ||||
-rw-r--r-- | gin/dictionary.h | 50 | ||||
-rw-r--r-- | gin/gin.gyp | 29 | ||||
-rw-r--r-- | gin/per_isolate_data.cc | 14 | ||||
-rw-r--r-- | gin/per_isolate_data.h | 6 | ||||
-rw-r--r-- | gin/runner.cc | 2 | ||||
-rw-r--r-- | gin/test/gtest.cc | 76 | ||||
-rw-r--r-- | gin/test/gtest.h | 16 |
14 files changed, 473 insertions, 48 deletions
diff --git a/gin/arguments.cc b/gin/arguments.cc new file mode 100644 index 0000000..15802b8 --- /dev/null +++ b/gin/arguments.cc @@ -0,0 +1,36 @@ +// Copyright 2013 The Chromium 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 "gin/arguments.h" + +#include <sstream> +#include "gin/converter.h" + +namespace gin { + +Arguments::Arguments(const v8::FunctionCallbackInfo<v8::Value>& info) + : isolate_(info.GetIsolate()), + info_(info), + next_(0), + insufficient_arguments_(false) { +} + +Arguments::~Arguments() { +} + +void Arguments::ThrowError() { + if (insufficient_arguments_) + return ThrowTypeError("Insufficient number of arguments."); + + std::stringstream stream; + stream << "Error processing argument " << next_ - 1 << "."; + ThrowTypeError(stream.str()); +} + +void Arguments::ThrowTypeError(const std::string& message) { + isolate_->ThrowException(v8::Exception::TypeError( + StringToV8(isolate_, message))); +} + +} // namespace gin diff --git a/gin/arguments.h b/gin/arguments.h new file mode 100644 index 0000000..c5335cc --- /dev/null +++ b/gin/arguments.h @@ -0,0 +1,54 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_ARGUMENTS_H_ +#define GIN_ARGUMENTS_H_ + +#include "base/basictypes.h" +#include "gin/converter.h" + +namespace gin { + +class Arguments { + public: + explicit Arguments(const v8::FunctionCallbackInfo<v8::Value>& info); + ~Arguments(); + + template<typename T> + bool Holder(T* out) { + return ConvertFromV8(info_.Holder(), out); + } + + template<typename T> + bool GetNext(T* out) { + if (next_ >= info_.Length()) { + insufficient_arguments_ = true; + return false; + } + v8::Handle<v8::Value> val = info_[next_++]; + return ConvertFromV8(val, out); + } + + template<typename T> + void Return(T val) { + info_.GetReturnValue().Set(ConvertToV8(isolate_, val)); + } + + void ThrowError(); + void ThrowTypeError(const std::string& message); + + v8::Isolate* isolate() const { return isolate_; } + + private: + v8::Isolate* isolate_; + const v8::FunctionCallbackInfo<v8::Value>& info_; + int next_; + bool insufficient_arguments_; + + DISALLOW_COPY_AND_ASSIGN(Arguments); +}; + +} // namespace gin + +#endif // GIN_ARGUMENTS_H_ diff --git a/gin/array_buffer.cc b/gin/array_buffer.cc index e8236fc..43dd8da 100644 --- a/gin/array_buffer.cc +++ b/gin/array_buffer.cc @@ -32,7 +32,7 @@ ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() { return instance; } -// BufferView::Private -------------------------------------------------------- +// ArrayBuffer::Private ------------------------------------------------------- // This class exists to solve a tricky lifetime problem. The V8 API doesn't // want to expose a direct view into the memory behind an array buffer because @@ -42,18 +42,18 @@ ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() { // we're done with it and when V8 is done with it. // // To determine whether we're done with the memory, every view we have into -// the array buffer takes a reference to the BufferView::Private object that +// the array buffer takes a reference to the ArrayBuffer::Private object that // actually owns the memory. To determine when V8 is done with the memory, we // open a weak handle to the ArrayBuffer object. When we receive the weak // callback, we know the object is about to be garbage collected and we can // drop V8's implied reference to the memory. // -// The final subtlety is that we need every BufferView into the same array -// buffer to AddRef the same BufferView::Private. To make that work, we store a -// pointer to the BufferView::Private object in an internal field of the +// The final subtlety is that we need every ArrayBuffer into the same array +// buffer to AddRef the same ArrayBuffer::Private. To make that work, we store +// a pointer to the ArrayBuffer::Private object in an internal field of the // ArrayBuffer object. // -class BufferView::Private { +class ArrayBuffer::Private { public: static scoped_refptr<Private> From(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array); @@ -77,7 +77,7 @@ class BufferView::Private { size_t length_; }; -scoped_refptr<BufferView::Private> BufferView::Private::From( +scoped_refptr<ArrayBuffer::Private> ArrayBuffer::Private::From( v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array) { if (array->IsExternal()) { return make_scoped_refptr(static_cast<Private*>( @@ -86,18 +86,18 @@ scoped_refptr<BufferView::Private> BufferView::Private::From( return make_scoped_refptr(new Private(isolate, array)); } -void BufferView::Private::AddRef() { +void ArrayBuffer::Private::AddRef() { ++ref_count_; } -void BufferView::Private::Release() { +void ArrayBuffer::Private::Release() { if (--ref_count_) return; delete this; } -BufferView::Private::Private(v8::Isolate* isolate, - v8::Handle<v8::ArrayBuffer> array) +ArrayBuffer::Private::Private(v8::Isolate* isolate, + v8::Handle<v8::ArrayBuffer> array) : ref_count_(0), array_buffer_(isolate, array) { // Take ownership of the array buffer. @@ -111,40 +111,73 @@ BufferView::Private::Private(v8::Isolate* isolate, array_buffer_.SetWeak(this, WeakCallback); } -BufferView::Private::~Private() { +ArrayBuffer::Private::~Private() { ArrayBufferAllocator::SharedInstance()->Free(buffer_, length_); } -void BufferView::Private::WeakCallback( +void ArrayBuffer::Private::WeakCallback( const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data) { Private* parameter = data.GetParameter(); parameter->array_buffer_.Reset(); - parameter->Release(); // Balanced in BufferView::Private::Private. + parameter->Release(); // Balanced in ArrayBuffer::Private::Private. } -// BufferView ----------------------------------------------------------------- +// ArrayBuffer ---------------------------------------------------------------- -BufferView::BufferView(v8::Isolate* isolate, - v8::Handle<v8::ArrayBufferView> view) { - Initialize(isolate, view->Buffer()); - uint8_t* ptr = static_cast<uint8_t*>(bytes_); - bytes_ = static_cast<void*>(ptr + view->ByteOffset()); - num_bytes_ = view->ByteLength(); +ArrayBuffer::ArrayBuffer(v8::Isolate* isolate) + : isolate_(isolate), + bytes_(0), + num_bytes_(0) { } -BufferView::BufferView(v8::Isolate* isolate, - v8::Handle<v8::ArrayBuffer> array) { - Initialize(isolate, array); +ArrayBuffer::ArrayBuffer(v8::Isolate* isolate, + v8::Handle<v8::ArrayBuffer> array) + : isolate_(isolate) { + private_ = ArrayBuffer::Private::From(isolate_, array); + bytes_ = private_->buffer(); + num_bytes_ = private_->length(); } -BufferView::~BufferView() { +ArrayBuffer::~ArrayBuffer() { } -void BufferView::Initialize(v8::Isolate* isolate, - v8::Handle<v8::ArrayBuffer> array) { - private_ = BufferView::Private::From(isolate, array); - bytes_ = private_->buffer(); - num_bytes_ = private_->length(); +// Converter<ArrayBuffer> ----------------------------------------------------- + +bool Converter<ArrayBuffer>::FromV8(v8::Handle<v8::Value> val, + ArrayBuffer* out) { + if (!val->IsArrayBuffer()) + return false; + *out = ArrayBuffer(out->isolate(), v8::Handle<v8::ArrayBuffer>::Cast(val)); + return true; +} + +// ArrayBufferView ------------------------------------------------------------ + +ArrayBufferView::ArrayBufferView(v8::Isolate* isolate) + : array_buffer_(isolate), + offset_(0), + num_bytes_(0) { +} + +ArrayBufferView::ArrayBufferView(v8::Isolate* isolate, + v8::Handle<v8::ArrayBufferView> view) + : array_buffer_(isolate, view->Buffer()), + offset_(view->ByteOffset()), + num_bytes_(view->ByteLength()) { +} + +ArrayBufferView::~ArrayBufferView() { +} + +// Converter<ArrayBufferView> ------------------------------------------------- + +bool Converter<ArrayBufferView>::FromV8(v8::Handle<v8::Value> val, + ArrayBufferView* out) { + if (!val->IsArrayBufferView()) + return false; + *out = ArrayBufferView(out->isolate(), + v8::Handle<v8::ArrayBufferView>::Cast(val)); + return true; } } // namespace gin diff --git a/gin/array_buffer.h b/gin/array_buffer.h index b48a687..a645431 100644 --- a/gin/array_buffer.h +++ b/gin/array_buffer.h @@ -8,6 +8,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" // For scoped_refptr only! +#include "gin/converter.h" #include "v8/include/v8.h" namespace gin { @@ -21,25 +22,57 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { static ArrayBufferAllocator* SharedInstance(); }; -class BufferView { +class ArrayBuffer { public: - BufferView(v8::Isolate* isolate, v8::Handle<v8::ArrayBufferView> view); - BufferView(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> buffer); - ~BufferView(); + explicit ArrayBuffer(v8::Isolate* isolate); + ArrayBuffer(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> buffer); + ~ArrayBuffer(); void* bytes() const { return bytes_; } size_t num_bytes() const { return num_bytes_; } + v8::Isolate* isolate() const { return isolate_; } + private: class Private; - void Initialize(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> buffer); - + v8::Isolate* isolate_; scoped_refptr<Private> private_; void* bytes_; size_t num_bytes_; }; +template<> +struct Converter<ArrayBuffer> { + static bool FromV8(v8::Handle<v8::Value> val, + ArrayBuffer* out); +}; + +class ArrayBufferView { + public: + explicit ArrayBufferView(v8::Isolate* isolate); + ArrayBufferView(v8::Isolate* isolate, v8::Handle<v8::ArrayBufferView> view); + ~ArrayBufferView(); + + void* bytes() const { + return static_cast<uint8_t*>(array_buffer_.bytes()) + offset_; + } + size_t num_bytes() const { return num_bytes_; } + + v8::Isolate* isolate() const { return array_buffer_.isolate(); } + + private: + ArrayBuffer array_buffer_; + size_t offset_; + size_t num_bytes_; +}; + +template<> +struct Converter<ArrayBufferView> { + static bool FromV8(v8::Handle<v8::Value> val, + ArrayBufferView* out); +}; + } // namespace gin #endif // GIN_ARRAY_BUFFER_H_ diff --git a/gin/converter.cc b/gin/converter.cc index 6b30985..8f9d0ab 100644 --- a/gin/converter.cc +++ b/gin/converter.cc @@ -49,6 +49,30 @@ bool Converter<uint32_t>::FromV8(Handle<Value> val, uint32_t* out) { return true; } +Handle<Value> Converter<int64_t>::ToV8(Isolate* isolate, int64_t val) { + return Number::New(isolate, static_cast<double>(val)).As<Value>(); +} + +bool Converter<int64_t>::FromV8(Handle<Value> val, int64_t* out) { + if (!val->IsNumber()) + return false; + // Even though IntegerValue returns int64_t, JavaScript cannot represent + // the full precision of int64_t, which means some rounding might occur. + *out = val->IntegerValue(); + return true; +} + +Handle<Value> Converter<uint64_t>::ToV8(Isolate* isolate, uint64_t val) { + return Number::New(isolate, static_cast<double>(val)).As<Value>(); +} + +bool Converter<uint64_t>::FromV8(Handle<Value> val, uint64_t* out) { + if (!val->IsNumber()) + return false; + *out = static_cast<uint64_t>(val->IntegerValue()); + return true; +} + Handle<Value> Converter<double>::ToV8(Isolate* isolate, double val) { return Number::New(isolate, val).As<Value>(); } @@ -87,7 +111,8 @@ bool Converter<Handle<Function> >::FromV8(Handle<Value> val, return true; } -Handle<Value> Converter<Handle<Object> >::ToV8(Handle<Object> val) { +Handle<Value> Converter<Handle<Object> >::ToV8(v8::Isolate* isolate, + Handle<Object> val) { return val.As<Value>(); } @@ -99,4 +124,13 @@ bool Converter<Handle<Object> >::FromV8(Handle<Value> val, return true; } +v8::Handle<v8::String> StringToSymbol(v8::Isolate* isolate, + const std::string& val) { + return String::NewFromUtf8(isolate, + val.data(), + String::kInternalizedString, + val.length()); +} + + } // namespace gin diff --git a/gin/converter.h b/gin/converter.h index eb84be2..551849b 100644 --- a/gin/converter.h +++ b/gin/converter.h @@ -40,6 +40,24 @@ struct Converter<uint32_t> { }; template<> +struct Converter<int64_t> { + // Warning: JavaScript cannot represent 64 integers precisely. + static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, + int64_t val); + static bool FromV8(v8::Handle<v8::Value> val, + int64_t* out); +}; + +template<> +struct Converter<uint64_t> { + // Warning: JavaScript cannot represent 64 integers precisely. + static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, + uint64_t val); + static bool FromV8(v8::Handle<v8::Value> val, + uint64_t* out); +}; + +template<> struct Converter<double> { static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, double val); @@ -63,7 +81,8 @@ struct Converter<v8::Handle<v8::Function> > { template<> struct Converter<v8::Handle<v8::Object> > { - static v8::Handle<v8::Value> ToV8(v8::Handle<v8::Object> val); + static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, + v8::Handle<v8::Object> val); static bool FromV8(v8::Handle<v8::Value> val, v8::Handle<v8::Object>* out); }; @@ -111,6 +130,9 @@ inline v8::Handle<v8::String> StringToV8( return ConvertToV8(isolate, input).As<v8::String>(); } +v8::Handle<v8::String> StringToSymbol(v8::Isolate* isolate, + const std::string& val); + template<typename T> bool ConvertFromV8(v8::Handle<v8::Value> input, T* result) { return Converter<T>::FromV8(input, result); diff --git a/gin/dictionary.cc b/gin/dictionary.cc new file mode 100644 index 0000000..0da85af --- /dev/null +++ b/gin/dictionary.cc @@ -0,0 +1,40 @@ +// Copyright 2013 The Chromium 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 "gin/dictionary.h" + +namespace gin { + +Dictionary::Dictionary(v8::Isolate* isolate) + : isolate_(isolate) { +} + +Dictionary::Dictionary(v8::Isolate* isolate, + v8::Handle<v8::Object> object) + : isolate_(isolate), + object_(object) { +} + +Dictionary::~Dictionary() { +} + +Dictionary Dictionary::CreateEmpty(v8::Isolate* isolate) { + Dictionary dictionary(isolate); + dictionary.object_ = v8::Object::New(); + return dictionary; +} + +v8::Handle<v8::Value> Converter<Dictionary>::ToV8(v8::Isolate* isolate, + Dictionary val) { + return val.object_; +} + +bool FromV8(v8::Handle<v8::Value> val, Dictionary* out) { + if (!val->IsObject()) + return false; + *out = Dictionary(out->isolate(), v8::Handle<v8::Object>::Cast(val)); + return true; +} + +} // namespace gin diff --git a/gin/dictionary.h b/gin/dictionary.h new file mode 100644 index 0000000..f011779 --- /dev/null +++ b/gin/dictionary.h @@ -0,0 +1,50 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_DICTIONARY_H_ +#define GIN_DICTIONARY_H_ + +#include "gin/converter.h" + +namespace gin { + +class Dictionary { + public: + explicit Dictionary(v8::Isolate* isolate); + Dictionary(v8::Isolate* isolate, v8::Handle<v8::Object> object); + ~Dictionary(); + + static Dictionary CreateEmpty(v8::Isolate* isolate); + + template<typename T> + bool Get(const std::string& key, T* out) { + v8::Handle<v8::Value> val = object_->Get(StringToV8(isolate_, key)); + return ConvertFromV8(val, out); + } + + template<typename T> + bool Set(const std::string& key, T val) { + return object_->Set(StringToV8(isolate_, key), ConvertToV8(isolate_, val)); + } + + v8::Isolate* isolate() const { return isolate_; } + + private: + friend struct Converter<Dictionary>; + + v8::Isolate* isolate_; + v8::Handle<v8::Object> object_; +}; + +template<> +struct Converter<Dictionary> { + static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate, + Dictionary val); + static bool FromV8(v8::Handle<v8::Value> val, + Dictionary* out); +}; + +} // namespace gin + +#endif // GIN_DICTIONARY_H_ diff --git a/gin/gin.gyp b/gin/gin.gyp index ca133dd..ed76f09 100644 --- a/gin/gin.gyp +++ b/gin/gin.gyp @@ -20,10 +20,14 @@ '../v8/tools/gyp/v8.gyp:v8', ], 'sources': [ + 'arguments.cc', + 'arguments.h', 'array_buffer.cc', 'array_buffer.h', 'converter.cc', 'converter.h', + 'dictionary.cc', + 'dictionary.h', 'initialize.cc', 'initialize.h', 'per_isolate_data.cc', @@ -35,18 +39,35 @@ ], }, { - 'target_name': 'gin_unittests', - 'type': 'executable', + 'target_name': 'gin_test', + 'type': 'static_library', 'dependencies': [ '../base/base.gyp:base', - '../base/base.gyp:run_all_unittests', + '../testing/gtest.gyp:gtest', + 'gin', + ], + 'export_dependent_settings': [ + '../base/base.gyp:base', '../testing/gtest.gyp:gtest', 'gin', ], 'sources': [ + 'test/gtest.cc', + 'test/gtest.h', 'test/v8_test.cc', - 'test/run_all_unittests.cc', + 'test/v8_test.h', + ], + }, + { + 'target_name': 'gin_unittests', + 'type': 'executable', + 'dependencies': [ + '../base/base.gyp:run_all_unittests', + 'gin_test', + ], + 'sources': [ 'converter_unittest.cc', + 'test/run_all_unittests.cc', 'runner_unittest.cc', ], }, diff --git a/gin/per_isolate_data.cc b/gin/per_isolate_data.cc index 1320904..56b2c53 100644 --- a/gin/per_isolate_data.cc +++ b/gin/per_isolate_data.cc @@ -25,9 +25,17 @@ PerIsolateData* PerIsolateData::From(Isolate* isolate) { return static_cast<PerIsolateData*>(isolate->GetData()); } -void PerIsolateData::RegisterObjectTemplate( - WrapperInfo* info, Local<ObjectTemplate> object_template) { - object_templates_[info] = Eternal<ObjectTemplate>(isolate_, object_template); +void PerIsolateData::SetObjectTemplate(WrapperInfo* info, + Local<ObjectTemplate> templ) { + object_templates_[info] = Eternal<ObjectTemplate>(isolate_, templ); +} + +v8::Local<v8::ObjectTemplate> PerIsolateData::GetObjectTemplate( + WrapperInfo* info) { + ObjectTemplateMap::iterator it = object_templates_.find(info); + if (it == object_templates_.end()) + return v8::Local<v8::ObjectTemplate>(); + return it->second.Get(isolate_); } } // namespace gin diff --git a/gin/per_isolate_data.h b/gin/per_isolate_data.h index 72467b8..c92e9f3 100644 --- a/gin/per_isolate_data.h +++ b/gin/per_isolate_data.h @@ -20,8 +20,10 @@ class PerIsolateData { static PerIsolateData* From(v8::Isolate* isolate); - void RegisterObjectTemplate(WrapperInfo* info, - v8::Local<v8::ObjectTemplate> object_template); + void SetObjectTemplate(WrapperInfo* info, + v8::Local<v8::ObjectTemplate> object_template); + + v8::Local<v8::ObjectTemplate> GetObjectTemplate(WrapperInfo* info); private: typedef std::map< diff --git a/gin/runner.cc b/gin/runner.cc index cf98399..ec701b7 100644 --- a/gin/runner.cc +++ b/gin/runner.cc @@ -44,7 +44,7 @@ void Runner::Run(Handle<Script> script) { } v8::Handle<v8::Function> Runner::GetMain() { - Handle<Value> property = global()->Get(StringToV8(isolate_, "main")); + Handle<Value> property = global()->Get(StringToSymbol(isolate_, "main")); if (property.IsEmpty()) return v8::Handle<v8::Function>(); Handle<Function> main; diff --git a/gin/test/gtest.cc b/gin/test/gtest.cc new file mode 100644 index 0000000..2d77563 --- /dev/null +++ b/gin/test/gtest.cc @@ -0,0 +1,76 @@ +// Copyright 2013 The Chromium 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 "gin/test/gtest.h" + +#include "gin/arguments.h" +#include "gin/converter.h" +#include "gin/per_isolate_data.h" +#include "gin/wrapper_info.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gin { + +namespace { + +void ExpectTrue(const v8::FunctionCallbackInfo<v8::Value>& info) { + Arguments args(info); + + bool value = false; + std::string description; + + if (!args.GetNext(&value) || + !args.GetNext(&description)) { + return args.ThrowError(); + } + + EXPECT_TRUE(value) << description; +} + +void ExpectFalse(const v8::FunctionCallbackInfo<v8::Value>& info) { + Arguments args(info); + + bool value = false; + std::string description; + + if (!args.GetNext(&value) || + !args.GetNext(&description)) { + return args.ThrowError(); + } + + EXPECT_FALSE(value) << description; +} + +void ExpectEqual(const v8::FunctionCallbackInfo<v8::Value>& info) { + Arguments args(info); + + std::string description; + if (!ConvertFromV8(info[2], &description)) + return args.ThrowTypeError("Expected description."); + + EXPECT_TRUE(info[0]->StrictEquals(info[1])) << description; +} + +WrapperInfo g_gtest_wrapper_info = {}; + +} + +v8::Local<v8::ObjectTemplate> GetGTestTemplate(v8::Isolate* isolate) { + PerIsolateData* data = PerIsolateData::From(isolate); + v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate( + &g_gtest_wrapper_info); + if (templ.IsEmpty()) { + templ = v8::ObjectTemplate::New(); + templ->Set(StringToSymbol(isolate, "expectTrue"), + v8::FunctionTemplate::New(ExpectTrue)); + templ->Set(StringToSymbol(isolate, "expectFalse"), + v8::FunctionTemplate::New(ExpectFalse)); + templ->Set(StringToSymbol(isolate, "expectEqual"), + v8::FunctionTemplate::New(ExpectEqual)); + data->SetObjectTemplate(&g_gtest_wrapper_info, templ); + } + return templ; +} + +} // namespace gin diff --git a/gin/test/gtest.h b/gin/test/gtest.h new file mode 100644 index 0000000..e4ad534 --- /dev/null +++ b/gin/test/gtest.h @@ -0,0 +1,16 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_TEST_GTEST_H_ +#define GIN_TEST_GTEST_H_ + +#include "v8/include/v8.h" + +namespace gin { + +v8::Local<v8::ObjectTemplate> GetGTestTemplate(v8::Isolate* isolate); + +} // namespace gin + +#endif // GIN_TEST_GTEST_H_ |