Home | History | Annotate | Download | only in gin
      1 // Copyright 2013 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 "base/logging.h"
      6 #include "gin/arguments.h"
      7 #include "gin/handle.h"
      8 #include "gin/object_template_builder.h"
      9 #include "gin/per_isolate_data.h"
     10 #include "gin/public/isolate_holder.h"
     11 #include "gin/test/v8_test.h"
     12 #include "gin/try_catch.h"
     13 #include "gin/wrappable.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace gin {
     17 
     18 class BaseClass {
     19  public:
     20   BaseClass() : value_(23) {}
     21   virtual ~BaseClass() {}
     22 
     23  private:
     24   int value_;
     25 
     26   DISALLOW_COPY_AND_ASSIGN(BaseClass);
     27 };
     28 
     29 class MyObject : public BaseClass,
     30                  public Wrappable<MyObject> {
     31  public:
     32   static WrapperInfo kWrapperInfo;
     33 
     34   static gin::Handle<MyObject> Create(v8::Isolate* isolate) {
     35     return CreateHandle(isolate, new MyObject());
     36   }
     37 
     38   int value() const { return value_; }
     39   void set_value(int value) { value_ = value; }
     40 
     41  protected:
     42   MyObject() : value_(0) {}
     43   virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
     44       v8::Isolate* isolate) OVERRIDE;
     45   virtual ~MyObject() {}
     46 
     47  private:
     48   int value_;
     49 };
     50 
     51 class MyObjectSubclass : public MyObject {
     52  public:
     53   static gin::Handle<MyObjectSubclass> Create(v8::Isolate* isolate) {
     54     return CreateHandle(isolate, new MyObjectSubclass());
     55   }
     56 
     57   void SayHello(const std::string& name) {
     58     result = std::string("Hello, ") + name;
     59   }
     60 
     61   std::string result;
     62 
     63  private:
     64   virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
     65       v8::Isolate* isolate) OVERRIDE {
     66     return MyObject::GetObjectTemplateBuilder(isolate)
     67         .SetMethod("sayHello", &MyObjectSubclass::SayHello);
     68   }
     69 
     70   MyObjectSubclass() {
     71   }
     72 
     73   virtual ~MyObjectSubclass() {
     74   }
     75 };
     76 
     77 class MyCallableObject : public Wrappable<MyCallableObject> {
     78  public:
     79   static WrapperInfo kWrapperInfo;
     80 
     81   static gin::Handle<MyCallableObject> Create(v8::Isolate* isolate) {
     82     return CreateHandle(isolate, new MyCallableObject());
     83   }
     84 
     85   int result() { return result_; }
     86 
     87  private:
     88   virtual ObjectTemplateBuilder GetObjectTemplateBuilder(
     89       v8::Isolate* isolate) OVERRIDE {
     90     return Wrappable<MyCallableObject>::GetObjectTemplateBuilder(isolate)
     91         .SetCallAsFunctionHandler(&MyCallableObject::Call);
     92   }
     93 
     94   MyCallableObject() : result_(0) {
     95   }
     96 
     97   virtual ~MyCallableObject() {
     98   }
     99 
    100   void Call(int val, const gin::Arguments& arguments) {
    101     if (arguments.IsConstructCall())
    102       arguments.ThrowTypeError("Cannot be called as constructor.");
    103     else
    104       result_ = val;
    105   }
    106 
    107   int result_;
    108 };
    109 
    110 class MyObject2 : public Wrappable<MyObject2> {
    111  public:
    112   static WrapperInfo kWrapperInfo;
    113 };
    114 
    115 class MyObjectBlink : public Wrappable<MyObjectBlink> {
    116  public:
    117   static WrapperInfo kWrapperInfo;
    118 };
    119 
    120 WrapperInfo MyObject::kWrapperInfo = { kEmbedderNativeGin };
    121 ObjectTemplateBuilder MyObject::GetObjectTemplateBuilder(v8::Isolate* isolate) {
    122   return Wrappable<MyObject>::GetObjectTemplateBuilder(isolate)
    123       .SetProperty("value", &MyObject::value, &MyObject::set_value);
    124 }
    125 
    126 WrapperInfo MyCallableObject::kWrapperInfo = { kEmbedderNativeGin };
    127 WrapperInfo MyObject2::kWrapperInfo = { kEmbedderNativeGin };
    128 WrapperInfo MyObjectBlink::kWrapperInfo = { kEmbedderNativeGin };
    129 
    130 typedef V8Test WrappableTest;
    131 
    132 TEST_F(WrappableTest, WrapAndUnwrap) {
    133   v8::Isolate* isolate = instance_->isolate();
    134   v8::HandleScope handle_scope(isolate);
    135 
    136   Handle<MyObject> obj = MyObject::Create(isolate);
    137 
    138   v8::Handle<v8::Value> wrapper = ConvertToV8(isolate, obj.get());
    139   EXPECT_FALSE(wrapper.IsEmpty());
    140 
    141   MyObject* unwrapped = NULL;
    142   EXPECT_TRUE(ConvertFromV8(isolate, wrapper, &unwrapped));
    143   EXPECT_EQ(obj.get(), unwrapped);
    144 }
    145 
    146 TEST_F(WrappableTest, UnwrapFailures) {
    147   v8::Isolate* isolate = instance_->isolate();
    148   v8::HandleScope handle_scope(isolate);
    149 
    150   // Something that isn't an object.
    151   v8::Handle<v8::Value> thing = v8::Number::New(isolate, 42);
    152   MyObject* unwrapped = NULL;
    153   EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped));
    154   EXPECT_FALSE(unwrapped);
    155 
    156   // An object that's not wrapping anything.
    157   thing = v8::Object::New(isolate);
    158   EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped));
    159   EXPECT_FALSE(unwrapped);
    160 
    161   // An object that's wrapping a C++ object from Blink.
    162   thing.Clear();
    163   thing = ConvertToV8(isolate, new MyObjectBlink());
    164   EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped));
    165   EXPECT_FALSE(unwrapped);
    166 
    167   // An object that's wrapping a C++ object of the wrong type.
    168   thing.Clear();
    169   thing = ConvertToV8(isolate, new MyObject2());
    170   EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped));
    171   EXPECT_FALSE(unwrapped);
    172 }
    173 
    174 TEST_F(WrappableTest, GetAndSetProperty) {
    175   v8::Isolate* isolate = instance_->isolate();
    176   v8::HandleScope handle_scope(isolate);
    177 
    178   gin::Handle<MyObject> obj = MyObject::Create(isolate);
    179 
    180   obj->set_value(42);
    181   EXPECT_EQ(42, obj->value());
    182 
    183   v8::Handle<v8::String> source = StringToV8(isolate,
    184       "(function (obj) {"
    185       "   if (obj.value !== 42) throw 'FAIL';"
    186       "   else obj.value = 191; })");
    187   EXPECT_FALSE(source.IsEmpty());
    188 
    189   gin::TryCatch try_catch;
    190   v8::Handle<v8::Script> script = v8::Script::Compile(source);
    191   EXPECT_FALSE(script.IsEmpty());
    192   v8::Handle<v8::Value> val = script->Run();
    193   EXPECT_FALSE(val.IsEmpty());
    194   v8::Handle<v8::Function> func;
    195   EXPECT_TRUE(ConvertFromV8(isolate, val, &func));
    196   v8::Handle<v8::Value> argv[] = {
    197     ConvertToV8(isolate, obj.get()),
    198   };
    199   func->Call(v8::Undefined(isolate), 1, argv);
    200   EXPECT_FALSE(try_catch.HasCaught());
    201   EXPECT_EQ("", try_catch.GetStackTrace());
    202 
    203   EXPECT_EQ(191, obj->value());
    204 }
    205 
    206 TEST_F(WrappableTest, WrappableSubclass) {
    207   v8::Isolate* isolate = instance_->isolate();
    208   v8::HandleScope handle_scope(isolate);
    209 
    210   gin::Handle<MyObjectSubclass> object(MyObjectSubclass::Create(isolate));
    211   v8::Handle<v8::String> source = StringToV8(isolate,
    212                                              "(function(obj) {"
    213                                              "obj.sayHello('Lily');"
    214                                              "})");
    215   gin::TryCatch try_catch;
    216   v8::Handle<v8::Script> script = v8::Script::Compile(source);
    217   v8::Handle<v8::Value> val = script->Run();
    218   v8::Handle<v8::Function> func;
    219   EXPECT_TRUE(ConvertFromV8(isolate, val, &func));
    220   v8::Handle<v8::Value> argv[] = {
    221     ConvertToV8(isolate, object.get())
    222   };
    223   func->Call(v8::Undefined(isolate), 1, argv);
    224   EXPECT_FALSE(try_catch.HasCaught());
    225   EXPECT_EQ("Hello, Lily", object->result);
    226 }
    227 
    228 TEST_F(WrappableTest, CallAsFunction) {
    229   v8::Isolate* isolate = instance_->isolate();
    230   v8::HandleScope handle_scope(isolate);
    231 
    232   gin::Handle<MyCallableObject> object(MyCallableObject::Create(isolate));
    233   EXPECT_EQ(0, object->result());
    234   v8::Handle<v8::String> source = StringToV8(isolate,
    235                                              "(function(obj) {"
    236                                              "obj(42);"
    237                                              "})");
    238   gin::TryCatch try_catch;
    239   v8::Handle<v8::Script> script = v8::Script::Compile(source);
    240   v8::Handle<v8::Value> val = script->Run();
    241   v8::Handle<v8::Function> func;
    242   EXPECT_TRUE(ConvertFromV8(isolate, val, &func));
    243   v8::Handle<v8::Value> argv[] = {
    244     ConvertToV8(isolate, object.get())
    245   };
    246   func->Call(v8::Undefined(isolate), 1, argv);
    247   EXPECT_FALSE(try_catch.HasCaught());
    248   EXPECT_EQ(42, object->result());
    249 }
    250 
    251 TEST_F(WrappableTest, CallAsConstructor) {
    252   v8::Isolate* isolate = instance_->isolate();
    253   v8::HandleScope handle_scope(isolate);
    254 
    255   gin::Handle<MyCallableObject> object(MyCallableObject::Create(isolate));
    256   EXPECT_EQ(0, object->result());
    257   v8::Handle<v8::String> source = StringToV8(isolate,
    258                                              "(function(obj) {"
    259                                              "new obj(42);"
    260                                              "})");
    261   gin::TryCatch try_catch;
    262   v8::Handle<v8::Script> script = v8::Script::Compile(source);
    263   v8::Handle<v8::Value> val = script->Run();
    264   v8::Handle<v8::Function> func;
    265   EXPECT_TRUE(ConvertFromV8(isolate, val, &func));
    266   v8::Handle<v8::Value> argv[] = {
    267     ConvertToV8(isolate, object.get())
    268   };
    269   func->Call(v8::Undefined(isolate), 1, argv);
    270   EXPECT_TRUE(try_catch.HasCaught());
    271 }
    272 
    273 }  // namespace gin
    274