| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/bind.h" | 5 #include "base/bind.h" |
| 6 #include "base/memory/ptr_util.h" | 6 #include "base/memory/ptr_util.h" |
| 7 #include "base/stl_util.h" | 7 #include "base/stl_util.h" |
| 8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
| 9 #include "base/values.h" | 9 #include "base/values.h" |
| 10 #include "content/public/child/v8_value_converter.h" | 10 #include "content/public/child/v8_value_converter.h" |
| 11 #include "extensions/renderer/api_binding.h" | 11 #include "extensions/renderer/api_binding.h" |
| 12 #include "extensions/renderer/api_binding_test_util.h" | 12 #include "extensions/renderer/api_binding_test_util.h" |
| 13 #include "extensions/renderer/api_event_handler.h" |
| 13 #include "extensions/renderer/api_request_handler.h" | 14 #include "extensions/renderer/api_request_handler.h" |
| 14 #include "gin/converter.h" | 15 #include "gin/converter.h" |
| 15 #include "gin/public/context_holder.h" | 16 #include "gin/public/context_holder.h" |
| 16 #include "gin/public/isolate_holder.h" | 17 #include "gin/public/isolate_holder.h" |
| 17 #include "gin/test/v8_test.h" | 18 #include "gin/test/v8_test.h" |
| 18 #include "gin/try_catch.h" | 19 #include "gin/try_catch.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
| 20 #include "v8/include/v8.h" | 21 #include "v8/include/v8.h" |
| 21 | 22 |
| 22 namespace extensions { | 23 namespace extensions { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 v8::HandleScope handle_scope(instance_->isolate()); | 125 v8::HandleScope handle_scope(instance_->isolate()); |
| 125 holder_ = base::MakeUnique<gin::ContextHolder>(instance_->isolate()); | 126 holder_ = base::MakeUnique<gin::ContextHolder>(instance_->isolate()); |
| 126 holder_->SetContext( | 127 holder_->SetContext( |
| 127 v8::Local<v8::Context>::New(instance_->isolate(), context_)); | 128 v8::Local<v8::Context>::New(instance_->isolate(), context_)); |
| 128 request_handler_ = base::MakeUnique<APIRequestHandler>( | 129 request_handler_ = base::MakeUnique<APIRequestHandler>( |
| 129 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); | 130 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
| 130 } | 131 } |
| 131 | 132 |
| 132 void TearDown() override { | 133 void TearDown() override { |
| 133 request_handler_.reset(); | 134 request_handler_.reset(); |
| 135 |
| 136 v8::Global<v8::Context> weak_context(instance_->isolate(), context_); |
| 137 weak_context.SetWeak(); |
| 138 |
| 134 holder_.reset(); | 139 holder_.reset(); |
| 135 gin::V8Test::TearDown(); | 140 |
| 141 // NOTE: We explicitly do NOT call gin::V8Test::TearDown() here because we |
| 142 // do intermittent validation by doing a garbage collection after context |
| 143 // destruction and ensuring the context is fully released (which wouldn't |
| 144 // happen in cycles). |
| 145 // TODO(devlin): It might be time to move off V8Test if we're doing this. |
| 146 { |
| 147 v8::HandleScope handle_scope(instance_->isolate()); |
| 148 v8::Local<v8::Context>::New(instance_->isolate(), context_)->Exit(); |
| 149 context_.Reset(); |
| 150 } |
| 151 |
| 152 // Garbage collect everything so that we find any issues where we might be |
| 153 // double-freeing. |
| 154 // '5' is a magic number stolen from Blink; arbitrarily large enough to |
| 155 // hopefully clean up all the various paths. |
| 156 for (int i = 0; i < 5; i++) { |
| 157 instance_->isolate()->RequestGarbageCollectionForTesting( |
| 158 v8::Isolate::kFullGarbageCollection); |
| 159 } |
| 160 |
| 161 ASSERT_TRUE(weak_context.IsEmpty()); |
| 162 |
| 163 instance_->isolate()->Exit(); |
| 164 instance_.reset(); |
| 136 } | 165 } |
| 137 | 166 |
| 138 void ExpectPass(v8::Local<v8::Object> object, | 167 void ExpectPass(v8::Local<v8::Object> object, |
| 139 const std::string& script_source, | 168 const std::string& script_source, |
| 140 const std::string& expected_json_arguments_single_quotes) { | 169 const std::string& expected_json_arguments_single_quotes) { |
| 141 RunTest(object, script_source, true, | 170 RunTest(object, script_source, true, |
| 142 ReplaceSingleQuotes(expected_json_arguments_single_quotes), | 171 ReplaceSingleQuotes(expected_json_arguments_single_quotes), |
| 143 std::string()); | 172 std::string()); |
| 144 } | 173 } |
| 145 | 174 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 } | 224 } |
| 196 | 225 |
| 197 arguments_.reset(); | 226 arguments_.reset(); |
| 198 } | 227 } |
| 199 | 228 |
| 200 TEST_F(APIBindingTest, Test) { | 229 TEST_F(APIBindingTest, Test) { |
| 201 std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); | 230 std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); |
| 202 ASSERT_TRUE(functions); | 231 ASSERT_TRUE(functions); |
| 203 ArgumentSpec::RefMap refs; | 232 ArgumentSpec::RefMap refs; |
| 204 APIBinding binding( | 233 APIBinding binding( |
| 205 "test", *functions, nullptr, | 234 "test", *functions, nullptr, nullptr, |
| 206 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), | 235 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
| 207 &refs); | 236 &refs); |
| 208 EXPECT_TRUE(refs.empty()); | 237 EXPECT_TRUE(refs.empty()); |
| 209 | 238 |
| 210 v8::Isolate* isolate = instance_->isolate(); | 239 v8::Isolate* isolate = instance_->isolate(); |
| 211 | 240 |
| 212 v8::HandleScope handle_scope(isolate); | 241 v8::HandleScope handle_scope(isolate); |
| 213 v8::Local<v8::Context> context = | 242 v8::Local<v8::Context> context = |
| 214 v8::Local<v8::Context>::New(isolate, context_); | 243 v8::Local<v8::Context>::New(isolate, context_); |
| 215 | 244 |
| 245 APIEventHandler event_handler( |
| 246 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
| 216 v8::Local<v8::Object> binding_object = | 247 v8::Local<v8::Object> binding_object = |
| 217 binding.CreateInstance(context, isolate, base::Bind(&AllowAllAPIs)); | 248 binding.CreateInstance(context, isolate, &event_handler, |
| 249 base::Bind(&AllowAllAPIs)); |
| 218 | 250 |
| 219 ExpectPass(binding_object, "obj.oneString('foo');", "['foo']"); | 251 ExpectPass(binding_object, "obj.oneString('foo');", "['foo']"); |
| 220 ExpectPass(binding_object, "obj.oneString('');", "['']"); | 252 ExpectPass(binding_object, "obj.oneString('');", "['']"); |
| 221 ExpectFailure(binding_object, "obj.oneString(1);", kError); | 253 ExpectFailure(binding_object, "obj.oneString(1);", kError); |
| 222 ExpectFailure(binding_object, "obj.oneString();", kError); | 254 ExpectFailure(binding_object, "obj.oneString();", kError); |
| 223 ExpectFailure(binding_object, "obj.oneString({});", kError); | 255 ExpectFailure(binding_object, "obj.oneString({});", kError); |
| 224 ExpectFailure(binding_object, "obj.oneString('foo', 'bar');", kError); | 256 ExpectFailure(binding_object, "obj.oneString('foo', 'bar');", kError); |
| 225 | 257 |
| 226 ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]"); | 258 ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]"); |
| 227 ExpectPass(binding_object, "obj.stringAndInt('foo', -1);", "['foo',-1]"); | 259 ExpectPass(binding_object, "obj.stringAndInt('foo', -1);", "['foo',-1]"); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 " }]" | 329 " }]" |
| 298 "}]"; | 330 "}]"; |
| 299 | 331 |
| 300 std::unique_ptr<base::ListValue> functions = | 332 std::unique_ptr<base::ListValue> functions = |
| 301 ListValueFromString(kRefFunctions); | 333 ListValueFromString(kRefFunctions); |
| 302 ASSERT_TRUE(functions); | 334 ASSERT_TRUE(functions); |
| 303 std::unique_ptr<base::ListValue> types = ListValueFromString(kTypes); | 335 std::unique_ptr<base::ListValue> types = ListValueFromString(kTypes); |
| 304 ASSERT_TRUE(types); | 336 ASSERT_TRUE(types); |
| 305 ArgumentSpec::RefMap refs; | 337 ArgumentSpec::RefMap refs; |
| 306 APIBinding binding( | 338 APIBinding binding( |
| 307 "test", *functions, types.get(), | 339 "test", *functions, types.get(), nullptr, |
| 308 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), | 340 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
| 309 &refs); | 341 &refs); |
| 310 EXPECT_EQ(2u, refs.size()); | 342 EXPECT_EQ(2u, refs.size()); |
| 311 EXPECT_TRUE(base::ContainsKey(refs, "refObj")); | 343 EXPECT_TRUE(base::ContainsKey(refs, "refObj")); |
| 312 EXPECT_TRUE(base::ContainsKey(refs, "refEnum")); | 344 EXPECT_TRUE(base::ContainsKey(refs, "refEnum")); |
| 313 | 345 |
| 314 v8::Isolate* isolate = instance_->isolate(); | 346 v8::Isolate* isolate = instance_->isolate(); |
| 315 | 347 |
| 316 v8::HandleScope handle_scope(isolate); | 348 v8::HandleScope handle_scope(isolate); |
| 317 v8::Local<v8::Context> context = | 349 v8::Local<v8::Context> context = |
| 318 v8::Local<v8::Context>::New(isolate, context_); | 350 v8::Local<v8::Context>::New(isolate, context_); |
| 319 | 351 |
| 352 APIEventHandler event_handler( |
| 353 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
| 320 v8::Local<v8::Object> binding_object = | 354 v8::Local<v8::Object> binding_object = |
| 321 binding.CreateInstance(context, isolate, base::Bind(&AllowAllAPIs)); | 355 binding.CreateInstance(context, isolate, &event_handler, |
| 356 base::Bind(&AllowAllAPIs)); |
| 322 | 357 |
| 323 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo'})", | 358 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo'})", |
| 324 "[{'prop1':'foo'}]"); | 359 "[{'prop1':'foo'}]"); |
| 325 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 2})", | 360 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 2})", |
| 326 "[{'prop1':'foo','prop2':2}]"); | 361 "[{'prop1':'foo','prop2':2}]"); |
| 327 ExpectFailure(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 'a'})", | 362 ExpectFailure(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 'a'})", |
| 328 kError); | 363 kError); |
| 329 ExpectPass(binding_object, "obj.takesRefEnum('alpha')", "['alpha']"); | 364 ExpectPass(binding_object, "obj.takesRefEnum('alpha')", "['alpha']"); |
| 330 ExpectPass(binding_object, "obj.takesRefEnum('beta')", "['beta']"); | 365 ExpectPass(binding_object, "obj.takesRefEnum('beta')", "['beta']"); |
| 331 ExpectFailure(binding_object, "obj.takesRefEnum('gamma')", kError); | 366 ExpectFailure(binding_object, "obj.takesRefEnum('gamma')", kError); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 344 " 'parameters': []" | 379 " 'parameters': []" |
| 345 "}, {" | 380 "}, {" |
| 346 " 'name': 'restrictedTwo'," | 381 " 'name': 'restrictedTwo'," |
| 347 " 'parameters': []" | 382 " 'parameters': []" |
| 348 "}]"; | 383 "}]"; |
| 349 std::unique_ptr<base::ListValue> functions = | 384 std::unique_ptr<base::ListValue> functions = |
| 350 ListValueFromString(kRestrictedFunctions); | 385 ListValueFromString(kRestrictedFunctions); |
| 351 ASSERT_TRUE(functions); | 386 ASSERT_TRUE(functions); |
| 352 ArgumentSpec::RefMap refs; | 387 ArgumentSpec::RefMap refs; |
| 353 APIBinding binding( | 388 APIBinding binding( |
| 354 "test", *functions, nullptr, | 389 "test", *functions, nullptr, nullptr, |
| 355 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), | 390 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
| 356 &refs); | 391 &refs); |
| 357 | 392 |
| 358 v8::Isolate* isolate = instance_->isolate(); | 393 v8::Isolate* isolate = instance_->isolate(); |
| 359 v8::HandleScope handle_scope(isolate); | 394 v8::HandleScope handle_scope(isolate); |
| 360 v8::Local<v8::Context> context = | 395 v8::Local<v8::Context> context = |
| 361 v8::Local<v8::Context>::New(isolate, context_); | 396 v8::Local<v8::Context>::New(isolate, context_); |
| 362 | 397 |
| 363 auto is_available = [](const std::string& name) { | 398 auto is_available = [](const std::string& name) { |
| 364 std::set<std::string> functions = {"test.allowedOne", "test.allowedTwo", | 399 std::set<std::string> functions = {"test.allowedOne", "test.allowedTwo", |
| 365 "test.restrictedOne", | 400 "test.restrictedOne", |
| 366 "test.restrictedTwo"}; | 401 "test.restrictedTwo"}; |
| 367 EXPECT_TRUE(functions.count(name)); | 402 EXPECT_TRUE(functions.count(name)); |
| 368 return name == "test.allowedOne" || name == "test.allowedTwo"; | 403 return name == "test.allowedOne" || name == "test.allowedTwo"; |
| 369 }; | 404 }; |
| 370 | 405 |
| 406 APIEventHandler event_handler( |
| 407 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
| 371 v8::Local<v8::Object> binding_object = | 408 v8::Local<v8::Object> binding_object = |
| 372 binding.CreateInstance(context, isolate, base::Bind(is_available)); | 409 binding.CreateInstance(context, isolate, &event_handler, |
| 410 base::Bind(is_available)); |
| 373 | 411 |
| 374 auto is_defined = [&binding_object, context](const std::string& name) { | 412 auto is_defined = [&binding_object, context](const std::string& name) { |
| 375 v8::Local<v8::Value> val = | 413 v8::Local<v8::Value> val = |
| 376 GetPropertyFromObject(binding_object, context, name); | 414 GetPropertyFromObject(binding_object, context, name); |
| 377 EXPECT_FALSE(val.IsEmpty()); | 415 EXPECT_FALSE(val.IsEmpty()); |
| 378 return !val->IsUndefined() && !val->IsNull(); | 416 return !val->IsUndefined() && !val->IsNull(); |
| 379 }; | 417 }; |
| 380 | 418 |
| 381 EXPECT_TRUE(is_defined("allowedOne")); | 419 EXPECT_TRUE(is_defined("allowedOne")); |
| 382 EXPECT_TRUE(is_defined("allowedTwo")); | 420 EXPECT_TRUE(is_defined("allowedTwo")); |
| 383 EXPECT_FALSE(is_defined("restrictedOne")); | 421 EXPECT_FALSE(is_defined("restrictedOne")); |
| 384 EXPECT_FALSE(is_defined("restrictedTwo")); | 422 EXPECT_FALSE(is_defined("restrictedTwo")); |
| 385 } | 423 } |
| 386 | 424 |
| 425 // Tests that events specified in the API are created as properties of the API |
| 426 // object. |
| 427 TEST_F(APIBindingTest, TestEventCreation) { |
| 428 const char kEvents[] = "[{'name': 'onFoo'}, {'name': 'onBar'}]"; |
| 429 std::unique_ptr<base::ListValue> events = ListValueFromString(kEvents); |
| 430 ASSERT_TRUE(events); |
| 431 std::unique_ptr<base::ListValue> functions = ListValueFromString(kFunctions); |
| 432 ASSERT_TRUE(functions); |
| 433 ArgumentSpec::RefMap refs; |
| 434 APIBinding binding( |
| 435 "test", *functions, nullptr, events.get(), |
| 436 base::Bind(&APIBindingTest::OnFunctionCall, base::Unretained(this)), |
| 437 &refs); |
| 438 |
| 439 v8::Isolate* isolate = instance_->isolate(); |
| 440 v8::HandleScope handle_scope(isolate); |
| 441 v8::Local<v8::Context> context = |
| 442 v8::Local<v8::Context>::New(isolate, context_); |
| 443 |
| 444 APIEventHandler event_handler( |
| 445 base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); |
| 446 v8::Local<v8::Object> binding_object = |
| 447 binding.CreateInstance(context, isolate, &event_handler, |
| 448 base::Bind(&AllowAllAPIs)); |
| 449 |
| 450 // Event behavior is tested in the APIEventHandler unittests as well as the |
| 451 // APIBindingsSystem tests, so we really only need to check that the events |
| 452 // are being initialized on the object. |
| 453 v8::Maybe<bool> has_on_foo = |
| 454 binding_object->Has(context, gin::StringToV8(isolate, "onFoo")); |
| 455 EXPECT_TRUE(has_on_foo.IsJust()); |
| 456 EXPECT_TRUE(has_on_foo.FromJust()); |
| 457 |
| 458 v8::Maybe<bool> has_on_bar = |
| 459 binding_object->Has(context, gin::StringToV8(isolate, "onBar")); |
| 460 EXPECT_TRUE(has_on_bar.IsJust()); |
| 461 EXPECT_TRUE(has_on_bar.FromJust()); |
| 462 |
| 463 v8::Maybe<bool> has_on_baz = |
| 464 binding_object->Has(context, gin::StringToV8(isolate, "onBaz")); |
| 465 EXPECT_TRUE(has_on_baz.IsJust()); |
| 466 EXPECT_FALSE(has_on_baz.FromJust()); |
| 467 } |
| 468 |
| 387 } // namespace extensions | 469 } // namespace extensions |
| OLD | NEW |