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'}]" |
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 |