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 MyObject : public Wrappable<MyObject> { 19 public: 20 static WrapperInfo kWrapperInfo; 21 22 static gin::Handle<MyObject> Create(v8::Isolate* isolate) { 23 return CreateHandle(isolate, new MyObject()); 24 } 25 26 int value() const { return value_; } 27 void set_value(int value) { value_ = value; } 28 29 private: 30 MyObject() : value_(0) {} 31 virtual ~MyObject() {} 32 33 int value_; 34 }; 35 36 class MyObject2 : public Wrappable<MyObject2> { 37 public: 38 static WrapperInfo kWrapperInfo; 39 }; 40 41 class MyObjectBlink : public Wrappable<MyObjectBlink> { 42 public: 43 static WrapperInfo kWrapperInfo; 44 }; 45 46 WrapperInfo MyObject::kWrapperInfo = { kEmbedderNativeGin }; 47 WrapperInfo MyObject2::kWrapperInfo = { kEmbedderNativeGin }; 48 WrapperInfo MyObjectBlink::kWrapperInfo = { kEmbedderNativeGin }; 49 50 void RegisterTemplates(v8::Isolate* isolate) { 51 PerIsolateData* data = PerIsolateData::From(isolate); 52 DCHECK(data->GetObjectTemplate(&MyObject::kWrapperInfo).IsEmpty()); 53 54 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplateBuilder(isolate) 55 .SetProperty("value", &MyObject::value, &MyObject::set_value) 56 .Build(); 57 templ->SetInternalFieldCount(kNumberOfInternalFields); 58 data->SetObjectTemplate(&MyObject::kWrapperInfo, templ); 59 60 templ = v8::ObjectTemplate::New(isolate); 61 templ->SetInternalFieldCount(kNumberOfInternalFields); 62 data->SetObjectTemplate(&MyObject2::kWrapperInfo, templ); 63 64 templ = v8::ObjectTemplate::New(isolate); 65 templ->SetInternalFieldCount(kNumberOfInternalFields); 66 data->SetObjectTemplate(&MyObjectBlink::kWrapperInfo, templ); 67 } 68 69 typedef V8Test WrappableTest; 70 71 TEST_F(WrappableTest, WrapAndUnwrap) { 72 v8::Isolate* isolate = instance_->isolate(); 73 v8::HandleScope handle_scope(isolate); 74 75 RegisterTemplates(isolate); 76 Handle<MyObject> obj = MyObject::Create(isolate); 77 78 v8::Handle<v8::Value> wrapper = ConvertToV8(isolate, obj.get()); 79 EXPECT_FALSE(wrapper.IsEmpty()); 80 81 MyObject* unwrapped = NULL; 82 EXPECT_TRUE(ConvertFromV8(isolate, wrapper, &unwrapped)); 83 EXPECT_EQ(obj.get(), unwrapped); 84 } 85 86 TEST_F(WrappableTest, UnwrapFailures) { 87 v8::Isolate* isolate = instance_->isolate(); 88 v8::HandleScope handle_scope(isolate); 89 90 RegisterTemplates(isolate); 91 92 // Something that isn't an object. 93 v8::Handle<v8::Value> thing = v8::Number::New(42); 94 MyObject* unwrapped = NULL; 95 EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped)); 96 EXPECT_FALSE(unwrapped); 97 98 // An object that's not wrapping anything. 99 thing = v8::Object::New(isolate); 100 EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped)); 101 EXPECT_FALSE(unwrapped); 102 103 // An object that's wrapping a C++ object from Blink. 104 thing.Clear(); 105 thing = ConvertToV8(isolate, new MyObjectBlink()); 106 EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped)); 107 EXPECT_FALSE(unwrapped); 108 109 // An object that's wrapping a C++ object of the wrong type. 110 thing.Clear(); 111 thing = ConvertToV8(isolate, new MyObject2()); 112 EXPECT_FALSE(ConvertFromV8(isolate, thing, &unwrapped)); 113 EXPECT_FALSE(unwrapped); 114 } 115 116 TEST_F(WrappableTest, GetAndSetProperty) { 117 v8::Isolate* isolate = instance_->isolate(); 118 v8::HandleScope handle_scope(isolate); 119 120 RegisterTemplates(isolate); 121 gin::Handle<MyObject> obj = MyObject::Create(isolate); 122 123 obj->set_value(42); 124 EXPECT_EQ(42, obj->value()); 125 126 v8::Handle<v8::String> source = StringToV8(isolate, 127 "(function (obj) {" 128 " if (obj.value !== 42) throw 'FAIL';" 129 " else obj.value = 191; })"); 130 EXPECT_FALSE(source.IsEmpty()); 131 132 gin::TryCatch try_catch; 133 v8::Handle<v8::Script> script = v8::Script::New(source); 134 EXPECT_FALSE(script.IsEmpty()); 135 v8::Handle<v8::Value> val = script->Run(); 136 EXPECT_FALSE(val.IsEmpty()); 137 v8::Handle<v8::Function> func; 138 EXPECT_TRUE(ConvertFromV8(isolate, val, &func)); 139 v8::Handle<v8::Value> argv[] = { 140 ConvertToV8(isolate, obj.get()), 141 }; 142 func->Call(v8::Undefined(isolate), 1, argv); 143 EXPECT_FALSE(try_catch.HasCaught()); 144 EXPECT_EQ("", try_catch.GetStackTrace()); 145 146 EXPECT_EQ(191, obj->value()); 147 } 148 149 } // namespace gin 150