summaryrefslogtreecommitdiffstats
path: root/gin
diff options
context:
space:
mode:
Diffstat (limited to 'gin')
-rw-r--r--gin/arguments.cc36
-rw-r--r--gin/arguments.h54
-rw-r--r--gin/array_buffer.cc93
-rw-r--r--gin/array_buffer.h45
-rw-r--r--gin/converter.cc36
-rw-r--r--gin/converter.h24
-rw-r--r--gin/dictionary.cc40
-rw-r--r--gin/dictionary.h50
-rw-r--r--gin/gin.gyp29
-rw-r--r--gin/per_isolate_data.cc14
-rw-r--r--gin/per_isolate_data.h6
-rw-r--r--gin/runner.cc2
-rw-r--r--gin/test/gtest.cc76
-rw-r--r--gin/test/gtest.h16
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_