Index: extensions/renderer/api_binding_unittest.cc |
diff --git a/extensions/renderer/api_binding_unittest.cc b/extensions/renderer/api_binding_unittest.cc |
index e231d8864b9f5ccd5cbbc1b1c585e36266ac8305..ede48cb1bf051899fa80d5c54ffe90a0b1670fce 100644 |
--- a/extensions/renderer/api_binding_unittest.cc |
+++ b/extensions/renderer/api_binding_unittest.cc |
@@ -10,6 +10,7 @@ |
#include "content/public/child/v8_value_converter.h" |
#include "extensions/renderer/api_binding.h" |
#include "extensions/renderer/api_binding_test_util.h" |
+#include "extensions/renderer/api_event_handler.h" |
#include "extensions/renderer/api_request_handler.h" |
#include "gin/converter.h" |
#include "gin/public/context_holder.h" |
@@ -131,8 +132,36 @@ class APIBindingTest : public gin::V8Test { |
void TearDown() override { |
request_handler_.reset(); |
+ |
+ v8::Global<v8::Context> weak_context(instance_->isolate(), context_); |
+ weak_context.SetWeak(); |
+ |
holder_.reset(); |
- gin::V8Test::TearDown(); |
+ |
+ // NOTE: We explicitly do NOT call gin::V8Test::TearDown() here because we |
+ // do intermittent validation by doing a garbage collection after context |
+ // destruction and ensuring the context is fully released (which wouldn't |
+ // happen in cycles). |
+ // TODO(devlin): It might be time to move off V8Test if we're doing this. |
+ { |
+ v8::HandleScope handle_scope(instance_->isolate()); |
+ v8::Local<v8::Context>::New(instance_->isolate(), context_)->Exit(); |
+ context_.Reset(); |
+ } |
+ |
+ // Garbage collect everything so that we find any issues where we might be |
+ // double-freeing. |
+ // '5' is a magic number stolen from Blink; arbitrarily large enough to |
+ // hopefully clean up all the various paths. |
+ for (int i = 0; i < 5; i++) { |
+ instance_->isolate()->RequestGarbageCollectionForTesting( |
+ v8::Isolate::kFullGarbageCollection); |
+ } |
+ |
+ ASSERT_TRUE(weak_context.IsEmpty()); |
+ |
+ instance_->isolate()->Exit(); |
+ instance_.reset(); |
} |
void ExpectPass(v8::Local<v8::Object> object, |
@@ -202,7 +231,7 @@ TEST_F(APIBindingTest, Test) { |
ASSERT_TRUE(functions); |
ArgumentSpec::RefMap refs; |
APIBinding binding( |
- "test", *functions, nullptr, |
+ "test", *functions, nullptr, nullptr, |
base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
&refs); |
EXPECT_TRUE(refs.empty()); |
@@ -213,8 +242,11 @@ TEST_F(APIBindingTest, Test) { |
v8::Local<v8::Context> context = |
v8::Local<v8::Context>::New(isolate, context_); |
+ APIEventHandler event_handler( |
+ base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
v8::Local<v8::Object> binding_object = |
- binding.CreateInstance(context, isolate, base::Bind(&AllowAllAPIs)); |
+ binding.CreateInstance(context, isolate, &event_handler, |
+ base::Bind(&AllowAllAPIs)); |
ExpectPass(binding_object, "obj.oneString('foo');", "['foo']"); |
ExpectPass(binding_object, "obj.oneString('');", "['']"); |
@@ -304,7 +336,7 @@ TEST_F(APIBindingTest, TypeRefsTest) { |
ASSERT_TRUE(types); |
ArgumentSpec::RefMap refs; |
APIBinding binding( |
- "test", *functions, types.get(), |
+ "test", *functions, types.get(), nullptr, |
base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
&refs); |
EXPECT_EQ(2u, refs.size()); |
@@ -317,8 +349,11 @@ TEST_F(APIBindingTest, TypeRefsTest) { |
v8::Local<v8::Context> context = |
v8::Local<v8::Context>::New(isolate, context_); |
+ APIEventHandler event_handler( |
+ base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
v8::Local<v8::Object> binding_object = |
- binding.CreateInstance(context, isolate, base::Bind(&AllowAllAPIs)); |
+ binding.CreateInstance(context, isolate, &event_handler, |
+ base::Bind(&AllowAllAPIs)); |
ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo'})", |
"[{'prop1':'foo'}]"); |
@@ -351,7 +386,7 @@ TEST_F(APIBindingTest, RestrictedAPIs) { |
ASSERT_TRUE(functions); |
ArgumentSpec::RefMap refs; |
APIBinding binding( |
- "test", *functions, nullptr, |
+ "test", *functions, nullptr, nullptr, |
base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
&refs); |
@@ -368,8 +403,11 @@ TEST_F(APIBindingTest, RestrictedAPIs) { |
return name == "test.allowedOne" || name == "test.allowedTwo"; |
}; |
+ APIEventHandler event_handler( |
+ base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
v8::Local<v8::Object> binding_object = |
- binding.CreateInstance(context, isolate, base::Bind(is_available)); |
+ binding.CreateInstance(context, isolate, &event_handler, |
+ base::Bind(is_available)); |
auto is_defined = [&binding_object, context](const std::string& name) { |
v8::Local<v8::Value> val = |
@@ -384,4 +422,48 @@ TEST_F(APIBindingTest, RestrictedAPIs) { |
EXPECT_FALSE(is_defined("restrictedTwo")); |
} |
+// Tests that events specified in the API are created as properties of the API |
+// object. |
+TEST_F(APIBindingTest, TestEventCreation) { |
+ const char kEvents[] = "[{'name': 'onFoo'}, {'name': 'onBar'}]"; |
+ std::unique_ptr<base::ListValue> events = ListValueFromString(kEvents); |
+ ASSERT_TRUE(events); |
+ std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); |
+ ASSERT_TRUE(functions); |
+ ArgumentSpec::RefMap refs; |
+ APIBinding binding( |
+ "test", *functions, nullptr, events.get(), |
+ base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
+ &refs); |
+ |
+ v8::Isolate* isolate = instance_->isolate(); |
+ v8::HandleScope handle_scope(isolate); |
+ v8::Local<v8::Context> context = |
+ v8::Local<v8::Context>::New(isolate, context_); |
+ |
+ APIEventHandler event_handler( |
+ base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
+ v8::Local<v8::Object> binding_object = |
+ binding.CreateInstance(context, isolate, &event_handler, |
+ base::Bind(&AllowAllAPIs)); |
+ |
+ // Event behavior is tested in the APIEventHandler unittests as well as the |
+ // APIBindingsSystem tests, so we really only need to check that the events |
+ // are being initialized on the object. |
+ v8::Maybe<bool> has_on_foo = |
+ binding_object->Has(context, gin::StringToV8(isolate, "onFoo")); |
+ EXPECT_TRUE(has_on_foo.IsJust()); |
+ EXPECT_TRUE(has_on_foo.FromJust()); |
+ |
+ v8::Maybe<bool> has_on_bar = |
+ binding_object->Has(context, gin::StringToV8(isolate, "onBar")); |
+ EXPECT_TRUE(has_on_bar.IsJust()); |
+ EXPECT_TRUE(has_on_bar.FromJust()); |
+ |
+ v8::Maybe<bool> has_on_baz = |
+ binding_object->Has(context, gin::StringToV8(isolate, "onBaz")); |
+ EXPECT_TRUE(has_on_baz.IsJust()); |
+ EXPECT_FALSE(has_on_baz.FromJust()); |
+} |
+ |
} // namespace extensions |