Chromium Code Reviews| 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 "extensions/renderer/api_bindings_system.h" | 5 #include "extensions/renderer/api_bindings_system.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/macros.h" | 8 #include "base/macros.h" |
| 9 #include "base/memory/ptr_util.h" | 9 #include "base/memory/ptr_util.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 const char kAlphaAPIName[] = "alpha"; | 28 const char kAlphaAPIName[] = "alpha"; |
| 29 const char kAlphaAPISpec[] = | 29 const char kAlphaAPISpec[] = |
| 30 "{" | 30 "{" |
| 31 " 'types': [{" | 31 " 'types': [{" |
| 32 " 'id': 'alpha.objRef'," | 32 " 'id': 'alpha.objRef'," |
| 33 " 'type': 'object'," | 33 " 'type': 'object'," |
| 34 " 'properties': {" | 34 " 'properties': {" |
| 35 " 'prop1': {'type': 'string'}," | 35 " 'prop1': {'type': 'string'}," |
| 36 " 'prop2': {'type': 'integer', 'optional': true}" | 36 " 'prop2': {'type': 'integer', 'optional': true}" |
| 37 " }" | 37 " }" |
| 38 " }, {" | |
| 39 " 'id': 'alpha.enumRef'," | |
| 40 " 'type': 'string'," | |
| 41 " 'enum': ['cat', 'dog']" | |
| 38 " }]," | 42 " }]," |
| 39 " 'functions': [{" | 43 " 'functions': [{" |
| 40 " 'name': 'functionWithCallback'," | 44 " 'name': 'functionWithCallback'," |
| 41 " 'parameters': [{" | 45 " 'parameters': [{" |
| 42 " 'name': 'str'," | 46 " 'name': 'str'," |
| 43 " 'type': 'string'" | 47 " 'type': 'string'" |
| 44 " }, {" | 48 " }, {" |
| 45 " 'name': 'callback'," | 49 " 'name': 'callback'," |
| 46 " 'type': 'function'" | 50 " 'type': 'function'" |
| 47 " }]" | 51 " }]" |
| 48 " }, {" | 52 " }, {" |
| 49 " 'name': 'functionWithRefAndCallback'," | 53 " 'name': 'functionWithRefAndCallback'," |
| 50 " 'parameters': [{" | 54 " 'parameters': [{" |
| 51 " 'name': 'ref'," | 55 " 'name': 'ref'," |
| 52 " '$ref': 'alpha.objRef'" | 56 " '$ref': 'alpha.objRef'" |
| 53 " }, {" | 57 " }, {" |
| 54 " 'name': 'callback'," | 58 " 'name': 'callback'," |
| 55 " 'type': 'function'" | 59 " 'type': 'function'" |
| 56 " }]" | 60 " }]" |
| 61 " }, {" | |
| 62 " 'name': 'functionWithEnum'," | |
| 63 " 'parameters': [{ 'name': 'e', '$ref': 'alpha.enumRef'}]" | |
|
lazyboy
2017/03/20 19:24:19
nit: rm space after {
Devlin
2017/03/20 22:00:34
Done.
| |
| 57 " }]," | 64 " }]," |
| 58 " 'events': [{" | 65 " 'events': [{" |
| 59 " 'name': 'alphaEvent'" | 66 " 'name': 'alphaEvent'" |
| 60 " }]" | 67 " }]" |
| 61 "}"; | 68 "}"; |
| 62 | 69 |
| 63 // Another fake API for testing. | 70 // Another fake API for testing. |
| 64 const char kBetaAPIName[] = "beta"; | 71 const char kBetaAPIName[] = "beta"; |
| 65 const char kBetaAPISpec[] = | 72 const char kBetaAPISpec[] = |
| 66 "{" | 73 "{" |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 80 "}"; | 87 "}"; |
| 81 | 88 |
| 82 bool AllowAllAPIs(const std::string& name) { | 89 bool AllowAllAPIs(const std::string& name) { |
| 83 return true; | 90 return true; |
| 84 } | 91 } |
| 85 | 92 |
| 86 } // namespace | 93 } // namespace |
| 87 | 94 |
| 88 // The base class to test the APIBindingsSystem. This allows subclasses to | 95 // The base class to test the APIBindingsSystem. This allows subclasses to |
| 89 // retrieve API schemas differently. | 96 // retrieve API schemas differently. |
| 90 class APIBindingsSystemTestBase : public APIBindingTest { | 97 class APIBindingsSystemTest : public APIBindingTest { |
| 91 public: | 98 public: |
| 92 // Returns the DictionaryValue representing the schema with the given API | 99 // Returns the DictionaryValue representing the schema with the given API |
| 93 // name. | 100 // name. |
| 94 virtual const base::DictionaryValue& GetAPISchema( | 101 const base::DictionaryValue& GetAPISchema(const std::string& api_name) { |
| 95 const std::string& api_name) = 0; | 102 EXPECT_TRUE(base::ContainsKey(api_schemas_, api_name)); |
| 103 return *api_schemas_[api_name]; | |
| 104 } | |
| 96 | 105 |
| 97 // Stores the request in |last_request_|. | 106 // Stores the request in |last_request_|. |
| 98 void OnAPIRequest(std::unique_ptr<APIRequestHandler::Request> request, | 107 void OnAPIRequest(std::unique_ptr<APIRequestHandler::Request> request, |
| 99 v8::Local<v8::Context> context) { | 108 v8::Local<v8::Context> context) { |
| 100 ASSERT_FALSE(last_request_); | 109 ASSERT_FALSE(last_request_); |
| 101 last_request_ = std::move(request); | 110 last_request_ = std::move(request); |
| 102 } | 111 } |
| 103 | 112 |
| 104 void OnEventListenersChanged(const std::string& event_name, | 113 void OnEventListenersChanged(const std::string& event_name, |
| 105 binding::EventListenersChanged changed, | 114 binding::EventListenersChanged changed, |
| 106 v8::Local<v8::Context> context) {} | 115 v8::Local<v8::Context> context) {} |
| 107 | 116 |
| 108 protected: | 117 protected: |
| 109 APIBindingsSystemTestBase() {} | 118 APIBindingsSystemTest() {} |
| 110 void SetUp() override { | 119 void SetUp() override { |
| 111 APIBindingTest::SetUp(); | 120 APIBindingTest::SetUp(); |
| 121 | |
| 122 // Create the fake API schemas. | |
| 123 { | |
| 124 struct APIData { | |
| 125 const char* name; | |
| 126 const char* spec; | |
| 127 } api_data[] = { | |
| 128 {kAlphaAPIName, kAlphaAPISpec}, | |
| 129 {kBetaAPIName, kBetaAPISpec}, | |
| 130 {kGammaAPIName, kGammaAPISpec}, | |
| 131 }; | |
| 132 for (const auto& api : api_data) { | |
| 133 std::unique_ptr<base::DictionaryValue> api_schema = | |
| 134 DictionaryValueFromString(api.spec); | |
| 135 ASSERT_TRUE(api_schema); | |
| 136 api_schemas_[api.name] = std::move(api_schema); | |
| 137 } | |
| 138 } | |
| 139 | |
| 112 bindings_system_ = base::MakeUnique<APIBindingsSystem>( | 140 bindings_system_ = base::MakeUnique<APIBindingsSystem>( |
| 113 base::Bind(&RunFunctionOnGlobalAndIgnoreResult), | 141 base::Bind(&RunFunctionOnGlobalAndIgnoreResult), |
| 114 base::Bind(&RunFunctionOnGlobalAndReturnHandle), | 142 base::Bind(&RunFunctionOnGlobalAndReturnHandle), |
| 115 base::Bind(&APIBindingsSystemTestBase::GetAPISchema, | 143 base::Bind(&APIBindingsSystemTest::GetAPISchema, |
| 116 base::Unretained(this)), | 144 base::Unretained(this)), |
| 117 base::Bind(&APIBindingsSystemTestBase::OnAPIRequest, | 145 base::Bind(&APIBindingsSystemTest::OnAPIRequest, |
| 118 base::Unretained(this)), | 146 base::Unretained(this)), |
| 119 base::Bind(&APIBindingsSystemTestBase::OnEventListenersChanged, | 147 base::Bind(&APIBindingsSystemTest::OnEventListenersChanged, |
| 120 base::Unretained(this)), | 148 base::Unretained(this)), |
| 121 APILastError(APILastError::GetParent())); | 149 APILastError(APILastError::GetParent())); |
| 122 } | 150 } |
| 123 | 151 |
| 124 void TearDown() override { | 152 void TearDown() override { |
| 125 // Dispose all contexts now so that we call WillReleaseContext(). | 153 // Dispose all contexts now so that we call WillReleaseContext(). |
| 126 DisposeAllContexts(); | 154 DisposeAllContexts(); |
| 127 bindings_system_.reset(); | 155 bindings_system_.reset(); |
| 128 APIBindingTest::TearDown(); | 156 APIBindingTest::TearDown(); |
| 129 } | 157 } |
| 130 | 158 |
| 131 void OnWillDisposeContext(v8::Local<v8::Context> context) override { | 159 void OnWillDisposeContext(v8::Local<v8::Context> context) override { |
| 132 bindings_system_->WillReleaseContext(context); | 160 bindings_system_->WillReleaseContext(context); |
| 133 } | 161 } |
| 134 | 162 |
| 135 // Checks that |last_request_| exists and was provided with the | 163 // Checks that |last_request_| exists and was provided with the |
| 136 // |expected_name| and |expected_arguments|. | 164 // |expected_name| and |expected_arguments|. |
| 137 void ValidateLastRequest(const std::string& expected_name, | 165 void ValidateLastRequest(const std::string& expected_name, |
| 138 const std::string& expected_arguments); | 166 const std::string& expected_arguments) { |
| 167 ASSERT_TRUE(last_request()); | |
| 168 // Note that even if no arguments are provided by the API call, we should | |
| 169 // have an empty list. | |
| 170 ASSERT_TRUE(last_request()->arguments); | |
| 171 EXPECT_EQ(expected_name, last_request()->method_name); | |
| 172 EXPECT_EQ(ReplaceSingleQuotes(expected_arguments), | |
| 173 ValueToString(*last_request()->arguments)); | |
| 174 } | |
| 175 | |
| 176 void CallFunctionOnObject(v8::Local<v8::Context> context, | |
| 177 v8::Local<v8::Object> object, | |
| 178 const std::string& script_source) { | |
| 179 std::string wrapped_script_source = | |
| 180 base::StringPrintf("(function(obj) { %s })", script_source.c_str()); | |
| 181 | |
| 182 v8::Local<v8::Function> func = | |
| 183 FunctionFromString(context, wrapped_script_source); | |
| 184 ASSERT_FALSE(func.IsEmpty()); | |
| 185 | |
| 186 v8::Local<v8::Value> argv[] = {object}; | |
| 187 RunFunction(func, context, 1, argv); | |
| 188 } | |
| 139 | 189 |
| 140 const APIRequestHandler::Request* last_request() const { | 190 const APIRequestHandler::Request* last_request() const { |
| 141 return last_request_.get(); | 191 return last_request_.get(); |
| 142 } | 192 } |
| 143 void reset_last_request() { last_request_.reset(); } | 193 void reset_last_request() { last_request_.reset(); } |
| 144 APIBindingsSystem* bindings_system() { return bindings_system_.get(); } | 194 APIBindingsSystem* bindings_system() { return bindings_system_.get(); } |
| 145 | 195 |
| 146 private: | 196 private: |
| 197 // The API schemas for the fake APIs. | |
| 198 std::map<std::string, std::unique_ptr<base::DictionaryValue>> api_schemas_; | |
| 199 | |
| 147 // The APIBindingsSystem associated with the test. Safe to use across multiple | 200 // The APIBindingsSystem associated with the test. Safe to use across multiple |
| 148 // contexts. | 201 // contexts. |
| 149 std::unique_ptr<APIBindingsSystem> bindings_system_; | 202 std::unique_ptr<APIBindingsSystem> bindings_system_; |
| 150 | 203 |
| 151 // The last request to be received from the APIBindingsSystem, or null if | 204 // The last request to be received from the APIBindingsSystem, or null if |
| 152 // there is none. | 205 // there is none. |
| 153 std::unique_ptr<APIRequestHandler::Request> last_request_; | 206 std::unique_ptr<APIRequestHandler::Request> last_request_; |
| 154 | 207 |
| 155 DISALLOW_COPY_AND_ASSIGN(APIBindingsSystemTestBase); | |
| 156 }; | |
| 157 | |
| 158 void APIBindingsSystemTestBase::ValidateLastRequest( | |
| 159 const std::string& expected_name, | |
| 160 const std::string& expected_arguments) { | |
| 161 ASSERT_TRUE(last_request()); | |
| 162 // Note that even if no arguments are provided by the API call, we should have | |
| 163 // an empty list. | |
| 164 ASSERT_TRUE(last_request()->arguments); | |
| 165 EXPECT_EQ(expected_name, last_request()->method_name); | |
| 166 EXPECT_EQ(ReplaceSingleQuotes(expected_arguments), | |
| 167 ValueToString(*last_request()->arguments)); | |
| 168 } | |
| 169 | |
| 170 // An implementation that works with fake/supplied APIs, for easy testability. | |
| 171 class APIBindingsSystemTest : public APIBindingsSystemTestBase { | |
| 172 protected: | |
| 173 APIBindingsSystemTest() {} | |
| 174 | |
| 175 // Calls a function constructed from |script_source| on the given |object|. | |
| 176 void CallFunctionOnObject(v8::Local<v8::Context> context, | |
| 177 v8::Local<v8::Object> object, | |
| 178 const std::string& script_source); | |
| 179 | |
| 180 private: | |
| 181 const base::DictionaryValue& GetAPISchema( | |
| 182 const std::string& api_name) override { | |
| 183 EXPECT_TRUE(base::ContainsKey(api_schemas_, api_name)); | |
| 184 return *api_schemas_[api_name]; | |
| 185 } | |
| 186 void SetUp() override; | |
| 187 | |
| 188 // The API schemas for the fake APIs. | |
| 189 std::map<std::string, std::unique_ptr<base::DictionaryValue>> api_schemas_; | |
| 190 | |
| 191 DISALLOW_COPY_AND_ASSIGN(APIBindingsSystemTest); | 208 DISALLOW_COPY_AND_ASSIGN(APIBindingsSystemTest); |
| 192 }; | 209 }; |
| 193 | 210 |
| 194 void APIBindingsSystemTest::CallFunctionOnObject( | |
| 195 v8::Local<v8::Context> context, | |
| 196 v8::Local<v8::Object> object, | |
| 197 const std::string& script_source) { | |
| 198 std::string wrapped_script_source = | |
| 199 base::StringPrintf("(function(obj) { %s })", script_source.c_str()); | |
| 200 | |
| 201 v8::Local<v8::Function> func = | |
| 202 FunctionFromString(context, wrapped_script_source); | |
| 203 ASSERT_FALSE(func.IsEmpty()); | |
| 204 | |
| 205 v8::Local<v8::Value> argv[] = {object}; | |
| 206 RunFunction(func, context, 1, argv); | |
| 207 } | |
| 208 | |
| 209 void APIBindingsSystemTest::SetUp() { | |
| 210 // Create the fake API schemas. | |
| 211 { | |
| 212 struct APIData { | |
| 213 const char* name; | |
| 214 const char* spec; | |
| 215 } api_data[] = { | |
| 216 {kAlphaAPIName, kAlphaAPISpec}, | |
| 217 {kBetaAPIName, kBetaAPISpec}, | |
| 218 {kGammaAPIName, kGammaAPISpec}, | |
| 219 }; | |
| 220 for (const auto& api : api_data) { | |
| 221 std::unique_ptr<base::DictionaryValue> api_schema = | |
| 222 DictionaryValueFromString(api.spec); | |
| 223 ASSERT_TRUE(api_schema); | |
| 224 api_schemas_[api.name] = std::move(api_schema); | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 APIBindingsSystemTestBase::SetUp(); | |
| 229 } | |
| 230 | |
| 231 // Tests API object initialization, calling a method on the supplied APIs, and | 211 // Tests API object initialization, calling a method on the supplied APIs, and |
| 232 // triggering the callback for the request. | 212 // triggering the callback for the request. |
| 233 TEST_F(APIBindingsSystemTest, TestInitializationAndCallbacks) { | 213 TEST_F(APIBindingsSystemTest, TestInitializationAndCallbacks) { |
| 234 v8::HandleScope handle_scope(isolate()); | 214 v8::HandleScope handle_scope(isolate()); |
| 235 v8::Local<v8::Context> context = MainContext(); | 215 v8::Local<v8::Context> context = MainContext(); |
| 236 | 216 |
| 237 v8::Local<v8::Object> alpha_api = bindings_system()->CreateAPIInstance( | 217 v8::Local<v8::Object> alpha_api = bindings_system()->CreateAPIInstance( |
| 238 kAlphaAPIName, context, isolate(), base::Bind(&AllowAllAPIs), nullptr); | 218 kAlphaAPIName, context, isolate(), base::Bind(&AllowAllAPIs), nullptr); |
| 239 ASSERT_FALSE(alpha_api.IsEmpty()); | 219 ASSERT_FALSE(alpha_api.IsEmpty()); |
| 240 v8::Local<v8::Object> beta_api = bindings_system()->CreateAPIInstance( | 220 v8::Local<v8::Object> beta_api = bindings_system()->CreateAPIInstance( |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 | 258 |
| 279 bindings_system()->CompleteRequest(last_request()->request_id, | 259 bindings_system()->CompleteRequest(last_request()->request_id, |
| 280 base::ListValue(), std::string()); | 260 base::ListValue(), std::string()); |
| 281 | 261 |
| 282 EXPECT_EQ("[]", GetStringPropertyFromObject(context->Global(), context, | 262 EXPECT_EQ("[]", GetStringPropertyFromObject(context->Global(), context, |
| 283 "callbackArguments")); | 263 "callbackArguments")); |
| 284 reset_last_request(); | 264 reset_last_request(); |
| 285 } | 265 } |
| 286 | 266 |
| 287 { | 267 { |
| 268 // Test an invalid invocation -> throwing error. | |
| 269 const char kTestCall[] = | |
| 270 "(function(obj) { obj.functionWithEnum('mouse') })"; | |
| 271 v8::Local<v8::Function> function = FunctionFromString(context, kTestCall); | |
| 272 v8::Local<v8::Value> args[] = {alpha_api}; | |
| 273 RunFunctionAndExpectError(function, context, arraysize(args), args, | |
| 274 "Uncaught TypeError: Invalid invocation"); | |
| 275 EXPECT_FALSE(last_request()); | |
| 276 reset_last_request(); // Just to not pollute future results. | |
| 277 } | |
| 278 | |
| 279 { | |
| 288 // Test an event registration -> event occurrence. | 280 // Test an event registration -> event occurrence. |
| 289 const char kTestCall[] = | 281 const char kTestCall[] = |
| 290 "obj.alphaEvent.addListener(function() {\n" | 282 "obj.alphaEvent.addListener(function() {\n" |
| 291 " this.eventArguments = Array.from(arguments);\n" | 283 " this.eventArguments = Array.from(arguments);\n" |
| 292 "});\n"; | 284 "});\n"; |
| 293 CallFunctionOnObject(context, alpha_api, kTestCall); | 285 CallFunctionOnObject(context, alpha_api, kTestCall); |
| 294 | 286 |
| 295 const char kResponseArgsJson[] = "['response',1,{'key':42}]"; | 287 const char kResponseArgsJson[] = "['response',1,{'key':42}]"; |
| 296 std::unique_ptr<base::ListValue> expected_args = | 288 std::unique_ptr<base::ListValue> expected_args = |
| 297 ListValueFromString(kResponseArgsJson); | 289 ListValueFromString(kResponseArgsJson); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 438 | 430 |
| 439 { | 431 { |
| 440 // Test a simple call -> response. | 432 // Test a simple call -> response. |
| 441 const char kTestCall[] = "obj.functionWithExternalRef({prop1: 'foo'});"; | 433 const char kTestCall[] = "obj.functionWithExternalRef({prop1: 'foo'});"; |
| 442 CallFunctionOnObject(context, gamma_api, kTestCall); | 434 CallFunctionOnObject(context, gamma_api, kTestCall); |
| 443 ValidateLastRequest("gamma.functionWithExternalRef", "[{'prop1':'foo'}]"); | 435 ValidateLastRequest("gamma.functionWithExternalRef", "[{'prop1':'foo'}]"); |
| 444 reset_last_request(); | 436 reset_last_request(); |
| 445 } | 437 } |
| 446 } | 438 } |
| 447 | 439 |
| 448 // An implementation using real API schemas. | |
| 449 class APIBindingsSystemTestWithRealAPI : public APIBindingsSystemTestBase { | |
| 450 protected: | |
| 451 APIBindingsSystemTestWithRealAPI() {} | |
| 452 | |
| 453 // Executes the given |script_source| in |context|, expecting no exceptions. | |
| 454 void ExecuteScript(v8::Local<v8::Context> context, | |
| 455 const std::string& script_source); | |
| 456 | |
| 457 // Executes the given |script_source| in |context| and compares a caught | |
| 458 // error to |expected_error|. | |
| 459 void ExecuteScriptAndExpectError(v8::Local<v8::Context> context, | |
| 460 const std::string& script_source, | |
| 461 const std::string& expected_error); | |
| 462 | |
| 463 private: | |
| 464 const base::DictionaryValue& GetAPISchema( | |
| 465 const std::string& api_name) override { | |
| 466 const base::DictionaryValue* schema = | |
| 467 ExtensionAPI::GetSharedInstance()->GetSchema(api_name); | |
| 468 EXPECT_TRUE(schema); | |
| 469 return *schema; | |
| 470 } | |
| 471 | |
| 472 DISALLOW_COPY_AND_ASSIGN(APIBindingsSystemTestWithRealAPI); | |
| 473 }; | |
| 474 | |
| 475 void APIBindingsSystemTestWithRealAPI::ExecuteScript( | |
| 476 v8::Local<v8::Context> context, | |
| 477 const std::string& script_source) { | |
| 478 v8::TryCatch try_catch(isolate()); | |
| 479 // V8ValueFromScriptSource runs the source and returns the result; here, we | |
| 480 // only care about running the source. | |
| 481 V8ValueFromScriptSource(context, script_source); | |
| 482 EXPECT_FALSE(try_catch.HasCaught()) | |
| 483 << gin::V8ToString(try_catch.Message()->Get()); | |
| 484 } | |
| 485 | |
| 486 void APIBindingsSystemTestWithRealAPI::ExecuteScriptAndExpectError( | |
| 487 v8::Local<v8::Context> context, | |
| 488 const std::string& script_source, | |
| 489 const std::string& expected_error) { | |
| 490 v8::TryCatch try_catch(isolate()); | |
| 491 V8ValueFromScriptSource(context, script_source); | |
| 492 ASSERT_TRUE(try_catch.HasCaught()) << script_source; | |
| 493 EXPECT_EQ(expected_error, gin::V8ToString(try_catch.Message()->Get())); | |
| 494 } | |
| 495 | |
| 496 // The following test demonstrates how APIBindingsSystem can be used with "real" | |
| 497 // Extension APIs; that is, using the raw Extension API schemas, rather than a | |
| 498 // substituted test schema. This is useful to both show how the system is | |
| 499 // intended to be used in the future as well as to make sure that it works with | |
| 500 // actual APIs. | |
| 501 TEST_F(APIBindingsSystemTestWithRealAPI, RealAPIs) { | |
| 502 v8::HandleScope handle_scope(isolate()); | |
| 503 v8::Local<v8::Context> context = MainContext(); | |
| 504 | |
| 505 v8::Local<v8::Object> chrome = v8::Object::New(isolate()); | |
| 506 { | |
| 507 v8::Maybe<bool> res = context->Global()->Set( | |
| 508 context, gin::StringToV8(isolate(), "chrome"), chrome); | |
| 509 ASSERT_TRUE(res.IsJust()); | |
| 510 ASSERT_TRUE(res.FromJust()); | |
| 511 } | |
| 512 | |
| 513 auto add_api_to_chrome = [this, &chrome, | |
| 514 &context](const std::string& api_name) { | |
| 515 v8::Local<v8::Object> api = bindings_system()->CreateAPIInstance( | |
| 516 api_name, context, context->GetIsolate(), base::Bind(&AllowAllAPIs), | |
| 517 nullptr); | |
| 518 ASSERT_FALSE(api.IsEmpty()) << api_name; | |
| 519 v8::Maybe<bool> res = chrome->Set( | |
| 520 context, gin::StringToV8(context->GetIsolate(), api_name), api); | |
| 521 ASSERT_TRUE(res.IsJust()); | |
| 522 ASSERT_TRUE(res.FromJust()); | |
| 523 }; | |
| 524 | |
| 525 // Pick two relatively small APIs that don't have any custom bindings (which | |
| 526 // aren't supported yet). | |
| 527 add_api_to_chrome("idle"); | |
| 528 add_api_to_chrome("power"); | |
| 529 | |
| 530 // Test passing methods. | |
| 531 { | |
| 532 const char kTestCall[] = "chrome.power.requestKeepAwake('display');"; | |
| 533 ExecuteScript(context, kTestCall); | |
| 534 ValidateLastRequest("power.requestKeepAwake", "['display']"); | |
| 535 EXPECT_EQ(-1, last_request()->request_id); | |
| 536 reset_last_request(); | |
| 537 } | |
| 538 | |
| 539 { | |
| 540 const char kTestCall[] = "chrome.power.releaseKeepAwake()"; | |
| 541 ExecuteScript(context, kTestCall); | |
| 542 ValidateLastRequest("power.releaseKeepAwake", "[]"); | |
| 543 EXPECT_EQ(-1, last_request()->request_id); | |
| 544 reset_last_request(); | |
| 545 } | |
| 546 | |
| 547 { | |
| 548 const char kTestCall[] = "chrome.idle.queryState(30, function() {})"; | |
| 549 ExecuteScript(context, kTestCall); | |
| 550 ValidateLastRequest("idle.queryState", "[30]"); | |
| 551 EXPECT_NE(-1, last_request()->request_id); | |
| 552 reset_last_request(); | |
| 553 } | |
| 554 | |
| 555 { | |
| 556 const char kTestCall[] = "chrome.idle.setDetectionInterval(30);"; | |
| 557 ExecuteScript(context, kTestCall); | |
| 558 ValidateLastRequest("idle.setDetectionInterval", "[30]"); | |
| 559 EXPECT_EQ(-1, last_request()->request_id); | |
| 560 reset_last_request(); | |
| 561 } | |
| 562 | |
| 563 // Check catching errors. | |
| 564 const char kError[] = "Uncaught TypeError: Invalid invocation"; | |
| 565 { | |
| 566 // "disp" is not an allowed enum value. | |
| 567 const char kTestCall[] = "chrome.power.requestKeepAwake('disp');"; | |
| 568 ExecuteScriptAndExpectError(context, kTestCall, kError); | |
| 569 EXPECT_FALSE(last_request()); | |
| 570 reset_last_request(); // Just to not pollute future results. | |
| 571 } | |
| 572 | |
| 573 { | |
| 574 // The queryState() param has a minimum of 15. | |
| 575 const char kTestCall[] = "chrome.idle.queryState(10, function() {});"; | |
| 576 ExecuteScriptAndExpectError(context, kTestCall, kError); | |
| 577 EXPECT_FALSE(last_request()); | |
| 578 reset_last_request(); // Just to not pollute future results. | |
| 579 } | |
| 580 | |
| 581 { | |
| 582 const char kTestCall[] = | |
| 583 "chrome.idle.onStateChanged.addListener(state => {\n" | |
| 584 " this.idleState = state;\n" | |
| 585 "});\n"; | |
| 586 ExecuteScript(context, kTestCall); | |
| 587 EXPECT_EQ("undefined", GetStringPropertyFromObject(context->Global(), | |
| 588 context, "idleState")); | |
| 589 bindings_system()->FireEventInContext("idle.onStateChanged", context, | |
| 590 *ListValueFromString("['active']")); | |
| 591 | |
| 592 EXPECT_EQ("\"active\"", GetStringPropertyFromObject(context->Global(), | |
| 593 context, "idleState")); | |
| 594 } | |
| 595 } | |
| 596 | |
| 597 } // namespace extensions | 440 } // namespace extensions |
| OLD | NEW |