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 |