| 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 "extensions/renderer/api_binding.h" | 10 #include "extensions/renderer/api_binding.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 "}, {" | 39 "}, {" |
| 40 " 'name': 'stringAndInt'," | 40 " 'name': 'stringAndInt'," |
| 41 " 'parameters': [{" | 41 " 'parameters': [{" |
| 42 " 'type': 'string'," | 42 " 'type': 'string'," |
| 43 " 'name': 'str'" | 43 " 'name': 'str'" |
| 44 " }, {" | 44 " }, {" |
| 45 " 'type': 'integer'," | 45 " 'type': 'integer'," |
| 46 " 'name': 'int'" | 46 " 'name': 'int'" |
| 47 " }]" | 47 " }]" |
| 48 "}, {" | 48 "}, {" |
| 49 " 'name': 'stringOptionalIntAndBool'," | |
| 50 " 'parameters': [{" | |
| 51 " 'type': 'string'," | |
| 52 " 'name': 'str'" | |
| 53 " }, {" | |
| 54 " 'type': 'integer'," | |
| 55 " 'name': 'optionalint'," | |
| 56 " 'optional': true" | |
| 57 " }, {" | |
| 58 " 'type': 'boolean'," | |
| 59 " 'name': 'bool'" | |
| 60 " }]" | |
| 61 "}, {" | |
| 62 " 'name': 'oneObject'," | 49 " 'name': 'oneObject'," |
| 63 " 'parameters': [{" | 50 " 'parameters': [{" |
| 64 " 'type': 'object'," | 51 " 'type': 'object'," |
| 65 " 'name': 'foo'," | 52 " 'name': 'foo'," |
| 66 " 'properties': {" | 53 " 'properties': {" |
| 67 " 'prop1': {'type': 'string'}," | 54 " 'prop1': {'type': 'string'}," |
| 68 " 'prop2': {'type': 'string', 'optional': true}" | 55 " 'prop2': {'type': 'string', 'optional': true}" |
| 69 " }" | 56 " }" |
| 70 " }]" | 57 " }]" |
| 71 "}, {" | 58 "}, {" |
| 72 " 'name': 'noArgs'," | |
| 73 " 'parameters': []" | |
| 74 "}, {" | |
| 75 " 'name': 'intAndCallback'," | 59 " 'name': 'intAndCallback'," |
| 76 " 'parameters': [{" | 60 " 'parameters': [{" |
| 77 " 'name': 'int'," | 61 " 'name': 'int'," |
| 78 " 'type': 'integer'" | 62 " 'type': 'integer'" |
| 79 " }, {" | 63 " }, {" |
| 80 " 'name': 'callback'," | 64 " 'name': 'callback'," |
| 81 " 'type': 'function'" | 65 " 'type': 'function'" |
| 82 " }]" | 66 " }]" |
| 83 "}, {" | |
| 84 " 'name': 'optionalIntAndCallback'," | |
| 85 " 'parameters': [{" | |
| 86 " 'name': 'int'," | |
| 87 " 'type': 'integer'," | |
| 88 " 'optional': true" | |
| 89 " }, {" | |
| 90 " 'name': 'callback'," | |
| 91 " 'type': 'function'" | |
| 92 " }]" | |
| 93 "}, {" | |
| 94 " 'name': 'optionalCallback'," | |
| 95 " 'parameters': [{" | |
| 96 " 'name': 'callback'," | |
| 97 " 'type': 'function'," | |
| 98 " 'optional': true" | |
| 99 " }]" | |
| 100 "}, {" | |
| 101 " 'name': 'intAnyOptionalObjectOptionalCallback'," | |
| 102 " 'parameters': [{" | |
| 103 " 'type': 'integer', 'name': 'tabId', 'minimum': 0" | |
| 104 " }, {" | |
| 105 " 'type': 'any', 'name': 'message'" | |
| 106 " }, {" | |
| 107 " 'type': 'object'," | |
| 108 " 'name': 'options'," | |
| 109 " 'properties': {" | |
| 110 " 'frameId': {'type': 'integer', 'optional': true, 'minimum': 0}" | |
| 111 " }," | |
| 112 " 'optional': true" | |
| 113 " }, {" | |
| 114 " 'type': 'function', 'name': 'responseCallback', 'optional': true" | |
| 115 " }]" | |
| 116 "}]"; | 67 "}]"; |
| 117 | 68 |
| 118 const char kError[] = "Uncaught TypeError: Invalid invocation"; | 69 const char kError[] = "Uncaught TypeError: Invalid invocation"; |
| 119 | 70 |
| 120 bool AllowAllAPIs(const std::string& name) { | 71 bool AllowAllAPIs(const std::string& name) { |
| 121 return true; | 72 return true; |
| 122 } | 73 } |
| 123 | 74 |
| 124 void OnEventListenersChanged(const std::string& event_name, | 75 void OnEventListenersChanged(const std::string& event_name, |
| 125 binding::EventListenersChanged change, | 76 binding::EventListenersChanged change, |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 v8::HandleScope handle_scope(isolate()); | 263 v8::HandleScope handle_scope(isolate()); |
| 313 v8::Local<v8::Context> context = MainContext(); | 264 v8::Local<v8::Context> context = MainContext(); |
| 314 | 265 |
| 315 v8::Local<v8::Object> binding_object = | 266 v8::Local<v8::Object> binding_object = |
| 316 binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); | 267 binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); |
| 317 EXPECT_EQ( | 268 EXPECT_EQ( |
| 318 0u, | 269 0u, |
| 319 binding_object->GetOwnPropertyNames(context).ToLocalChecked()->Length()); | 270 binding_object->GetOwnPropertyNames(context).ToLocalChecked()->Length()); |
| 320 } | 271 } |
| 321 | 272 |
| 322 TEST_F(APIBindingUnittest, Test) { | 273 // Tests the basic call -> request flow of the API binding (ensuring that |
| 323 // TODO(devlin): Move this test to an api_signature_unittest file? It really | 274 // functions are set up correctly and correctly enforced). |
| 324 // only tests parsing. | 275 TEST_F(APIBindingUnittest, TestBasicAPICalls) { |
| 325 SetFunctions(kFunctions); | 276 SetFunctions(kFunctions); |
| 326 InitializeBinding(); | 277 InitializeBinding(); |
| 327 | 278 |
| 328 v8::HandleScope handle_scope(isolate()); | 279 v8::HandleScope handle_scope(isolate()); |
| 329 v8::Local<v8::Context> context = MainContext(); | 280 v8::Local<v8::Context> context = MainContext(); |
| 330 | 281 |
| 331 v8::Local<v8::Object> binding_object = | 282 v8::Local<v8::Object> binding_object = |
| 332 binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); | 283 binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); |
| 333 | 284 |
| 285 // Argument parsing is tested primarily in APISignature and ArgumentSpec |
| 286 // tests, so do a few quick sanity checks... |
| 334 ExpectPass(binding_object, "obj.oneString('foo');", "['foo']", false); | 287 ExpectPass(binding_object, "obj.oneString('foo');", "['foo']", false); |
| 335 ExpectPass(binding_object, "obj.oneString('');", "['']", false); | |
| 336 ExpectFailure(binding_object, "obj.oneString(1);", kError); | 288 ExpectFailure(binding_object, "obj.oneString(1);", kError); |
| 337 ExpectFailure(binding_object, "obj.oneString();", kError); | 289 ExpectPass(binding_object, "obj.stringAndInt('foo', 1)", "['foo',1]", false); |
| 338 ExpectFailure(binding_object, "obj.oneString({});", kError); | 290 ExpectFailure(binding_object, "obj.stringAndInt(1)", kError); |
| 339 ExpectFailure(binding_object, "obj.oneString('foo', 'bar');", kError); | 291 ExpectPass(binding_object, "obj.intAndCallback(1, function() {})", "[1]", |
| 292 true); |
| 293 ExpectFailure(binding_object, "obj.intAndCallback(function() {})", kError); |
| 340 | 294 |
| 341 ExpectPass(binding_object, "obj.stringAndInt('foo', 42);", "['foo',42]", | 295 // ...And an interesting case (throwing an error during parsing). |
| 342 false); | |
| 343 ExpectPass(binding_object, "obj.stringAndInt('foo', -1);", "['foo',-1]", | |
| 344 false); | |
| 345 ExpectFailure(binding_object, "obj.stringAndInt(1);", kError); | |
| 346 ExpectFailure(binding_object, "obj.stringAndInt('foo');", kError); | |
| 347 ExpectFailure(binding_object, "obj.stringAndInt(1, 'foo');", kError); | |
| 348 ExpectFailure(binding_object, "obj.stringAndInt('foo', 'foo');", kError); | |
| 349 ExpectFailure(binding_object, "obj.stringAndInt('foo', '1');", kError); | |
| 350 ExpectFailure(binding_object, "obj.stringAndInt('foo', 2.3);", kError); | |
| 351 | |
| 352 ExpectPass(binding_object, "obj.stringOptionalIntAndBool('foo', 42, true);", | |
| 353 "['foo',42,true]", false); | |
| 354 ExpectPass(binding_object, "obj.stringOptionalIntAndBool('foo', true);", | |
| 355 "['foo',null,true]", false); | |
| 356 ExpectFailure(binding_object, | |
| 357 "obj.stringOptionalIntAndBool('foo', 'bar', true);", kError); | |
| 358 | |
| 359 ExpectPass(binding_object, "obj.oneObject({prop1: 'foo'});", | |
| 360 "[{'prop1':'foo'}]", false); | |
| 361 ExpectFailure( | 296 ExpectFailure( |
| 362 binding_object, | 297 binding_object, |
| 363 "obj.oneObject({ get prop1() { throw new Error('Badness'); } });", | 298 "obj.oneObject({ get prop1() { throw new Error('Badness'); } });", |
| 364 "Uncaught Error: Badness"); | 299 "Uncaught Error: Badness"); |
| 365 | |
| 366 ExpectPass(binding_object, "obj.noArgs()", "[]", false); | |
| 367 ExpectFailure(binding_object, "obj.noArgs(0)", kError); | |
| 368 ExpectFailure(binding_object, "obj.noArgs('')", kError); | |
| 369 ExpectFailure(binding_object, "obj.noArgs(null)", kError); | |
| 370 ExpectFailure(binding_object, "obj.noArgs(undefined)", kError); | |
| 371 | |
| 372 ExpectPass(binding_object, "obj.intAndCallback(1, function() {})", "[1]", | |
| 373 true); | |
| 374 ExpectFailure(binding_object, "obj.intAndCallback(function() {})", kError); | |
| 375 ExpectFailure(binding_object, "obj.intAndCallback(1)", kError); | |
| 376 | |
| 377 ExpectPass(binding_object, "obj.optionalIntAndCallback(1, function() {})", | |
| 378 "[1]", true); | |
| 379 ExpectPass(binding_object, "obj.optionalIntAndCallback(function() {})", | |
| 380 "[null]", true); | |
| 381 ExpectFailure(binding_object, "obj.optionalIntAndCallback(1)", kError); | |
| 382 | |
| 383 ExpectPass(binding_object, "obj.optionalCallback(function() {})", "[]", true); | |
| 384 ExpectPass(binding_object, "obj.optionalCallback()", "[]", false); | |
| 385 ExpectPass(binding_object, "obj.optionalCallback(undefined)", "[]", false); | |
| 386 ExpectFailure(binding_object, "obj.optionalCallback(0)", kError); | |
| 387 | |
| 388 ExpectPass(binding_object, | |
| 389 "obj.intAnyOptionalObjectOptionalCallback(4, {foo: 'bar'}, " | |
| 390 "function() {})", | |
| 391 "[4,{'foo':'bar'},null]", true); | |
| 392 ExpectPass(binding_object, | |
| 393 "obj.intAnyOptionalObjectOptionalCallback(4, {foo: 'bar'})", | |
| 394 "[4,{'foo':'bar'},null]", false); | |
| 395 ExpectPass(binding_object, | |
| 396 "obj.intAnyOptionalObjectOptionalCallback(4, {foo: 'bar'}, {})", | |
| 397 "[4,{'foo':'bar'},{}]", false); | |
| 398 ExpectFailure(binding_object, | |
| 399 "obj.intAnyOptionalObjectOptionalCallback(4, function() {})", | |
| 400 kError); | |
| 401 ExpectFailure(binding_object, "obj.intAnyOptionalObjectOptionalCallback(4)", | |
| 402 kError); | |
| 403 } | 300 } |
| 404 | 301 |
| 405 // Test that enum values are properly exposed on the binding object. | 302 // Test that enum values are properly exposed on the binding object. |
| 406 TEST_F(APIBindingUnittest, EnumValues) { | 303 TEST_F(APIBindingUnittest, EnumValues) { |
| 407 const char kTypes[] = | 304 const char kTypes[] = |
| 408 "[{" | 305 "[{" |
| 409 " 'id': 'first'," | 306 " 'id': 'first'," |
| 410 " 'type': 'string'," | 307 " 'type': 'string'," |
| 411 " 'enum': ['alpha', 'camelCase', 'Hyphen-ated'," | 308 " 'enum': ['alpha', 'camelCase', 'Hyphen-ated'," |
| 412 " 'SCREAMING', 'nums123', '42nums']" | 309 " 'SCREAMING', 'nums123', '42nums']" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 450 v8::Local<v8::Context> context = MainContext(); | 347 v8::Local<v8::Context> context = MainContext(); |
| 451 | 348 |
| 452 v8::Local<v8::Object> binding_object = | 349 v8::Local<v8::Object> binding_object = |
| 453 binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); | 350 binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); |
| 454 | 351 |
| 455 EXPECT_EQ( | 352 EXPECT_EQ( |
| 456 "{\"\":\"\",\"OTHER\":\"other\"}", | 353 "{\"\":\"\",\"OTHER\":\"other\"}", |
| 457 GetStringPropertyFromObject(binding_object, context, "enumWithEmpty")); | 354 GetStringPropertyFromObject(binding_object, context, "enumWithEmpty")); |
| 458 } | 355 } |
| 459 | 356 |
| 357 // Test that type references are correctly set up in the API. |
| 460 TEST_F(APIBindingUnittest, TypeRefsTest) { | 358 TEST_F(APIBindingUnittest, TypeRefsTest) { |
| 461 const char kTypes[] = | 359 const char kTypes[] = |
| 462 "[{" | 360 "[{" |
| 463 " 'id': 'refObj'," | 361 " 'id': 'refObj'," |
| 464 " 'type': 'object'," | 362 " 'type': 'object'," |
| 465 " 'properties': {" | 363 " 'properties': {" |
| 466 " 'prop1': {'type': 'string'}," | 364 " 'prop1': {'type': 'string'}," |
| 467 " 'prop2': {'type': 'integer', 'optional': true}" | 365 " 'prop2': {'type': 'integer', 'optional': true}" |
| 468 " }" | 366 " }" |
| 469 "}, {" | 367 "}, {" |
| (...skipping 22 matching lines...) Expand all Loading... |
| 492 EXPECT_EQ(2u, type_refs().size()); | 390 EXPECT_EQ(2u, type_refs().size()); |
| 493 EXPECT_TRUE(type_refs().GetSpec("refObj")); | 391 EXPECT_TRUE(type_refs().GetSpec("refObj")); |
| 494 EXPECT_TRUE(type_refs().GetSpec("refEnum")); | 392 EXPECT_TRUE(type_refs().GetSpec("refEnum")); |
| 495 | 393 |
| 496 v8::HandleScope handle_scope(isolate()); | 394 v8::HandleScope handle_scope(isolate()); |
| 497 v8::Local<v8::Context> context = MainContext(); | 395 v8::Local<v8::Context> context = MainContext(); |
| 498 | 396 |
| 499 v8::Local<v8::Object> binding_object = | 397 v8::Local<v8::Object> binding_object = |
| 500 binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); | 398 binding()->CreateInstance(context, base::Bind(&AllowAllAPIs)); |
| 501 | 399 |
| 400 // Parsing in general is tested in APISignature and ArgumentSpec tests, but |
| 401 // we test that the binding a) correctly finds the definitions, and b) accepts |
| 402 // properties from the API object. |
| 502 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo'})", | 403 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo'})", |
| 503 "[{'prop1':'foo'}]", false); | 404 "[{'prop1':'foo'}]", false); |
| 504 ExpectPass(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 2})", | |
| 505 "[{'prop1':'foo','prop2':2}]", false); | |
| 506 ExpectFailure(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 'a'})", | 405 ExpectFailure(binding_object, "obj.takesRefObj({prop1: 'foo', prop2: 'a'})", |
| 507 kError); | 406 kError); |
| 508 ExpectPass(binding_object, "obj.takesRefEnum('alpha')", "['alpha']", false); | 407 ExpectPass(binding_object, "obj.takesRefEnum('alpha')", "['alpha']", false); |
| 509 ExpectPass(binding_object, "obj.takesRefEnum('beta')", "['beta']", false); | |
| 510 ExpectPass(binding_object, "obj.takesRefEnum(obj.refEnum.BETA)", "['beta']", | 408 ExpectPass(binding_object, "obj.takesRefEnum(obj.refEnum.BETA)", "['beta']", |
| 511 false); | 409 false); |
| 512 ExpectFailure(binding_object, "obj.takesRefEnum('gamma')", kError); | 410 ExpectFailure(binding_object, "obj.takesRefEnum('gamma')", kError); |
| 513 } | 411 } |
| 514 | 412 |
| 515 TEST_F(APIBindingUnittest, RestrictedAPIs) { | 413 TEST_F(APIBindingUnittest, RestrictedAPIs) { |
| 516 const char kFunctions[] = | 414 const char kFunctions[] = |
| 517 "[{" | 415 "[{" |
| 518 " 'name': 'allowedOne'," | 416 " 'name': 'allowedOne'," |
| 519 " 'parameters': []" | 417 " 'parameters': []" |
| (...skipping 727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1247 }; | 1145 }; |
| 1248 | 1146 |
| 1249 check_supports_filters("unfilteredOne", false); | 1147 check_supports_filters("unfilteredOne", false); |
| 1250 check_supports_filters("unfilteredTwo", false); | 1148 check_supports_filters("unfilteredTwo", false); |
| 1251 check_supports_filters("unfilteredThree", false); | 1149 check_supports_filters("unfilteredThree", false); |
| 1252 check_supports_filters("filteredOne", true); | 1150 check_supports_filters("filteredOne", true); |
| 1253 check_supports_filters("filteredTwo", true); | 1151 check_supports_filters("filteredTwo", true); |
| 1254 } | 1152 } |
| 1255 | 1153 |
| 1256 } // namespace extensions | 1154 } // namespace extensions |
| OLD | NEW |