1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "extensions/renderer/bindings/api_signature.h"
6
7 #include "base/values.h"
8 #include "extensions/renderer/bindings/api_binding_test.h"
9 #include "extensions/renderer/bindings/api_binding_test_util.h"
10 #include "extensions/renderer/bindings/api_invocation_errors.h"
11 #include "extensions/renderer/bindings/api_type_reference_map.h"
12 #include "extensions/renderer/bindings/argument_spec.h"
13 #include "extensions/renderer/bindings/argument_spec_builder.h"
14 #include "extensions/renderer/bindings/binding_access_checker.h"
15 #include "gin/converter.h"
16 #include "gin/dictionary.h"
17
18 namespace extensions {
19
20 using api_errors::ArgumentError;
21 using api_errors::InvalidType;
22 using api_errors::kTypeBoolean;
23 using api_errors::kTypeInteger;
24 using api_errors::kTypeString;
25 using api_errors::NoMatchingSignature;
26
27 namespace {
28
29 using SpecVector = std::vector<std::unique_ptr<ArgumentSpec>>;
30
OneString()31 std::unique_ptr<APISignature> OneString() {
32 SpecVector specs;
33 specs.push_back(ArgumentSpecBuilder(ArgumentType::STRING, "string").Build());
34 return std::make_unique<APISignature>(std::move(specs));
35 }
36
StringAndInt()37 std::unique_ptr<APISignature> StringAndInt() {
38 SpecVector specs;
39 specs.push_back(ArgumentSpecBuilder(ArgumentType::STRING, "string").Build());
40 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int").Build());
41 return std::make_unique<APISignature>(std::move(specs));
42 }
43
StringOptionalIntAndBool()44 std::unique_ptr<APISignature> StringOptionalIntAndBool() {
45 SpecVector specs;
46 specs.push_back(ArgumentSpecBuilder(ArgumentType::STRING, "string").Build());
47 specs.push_back(
48 ArgumentSpecBuilder(ArgumentType::INTEGER, "int").MakeOptional().Build());
49 specs.push_back(ArgumentSpecBuilder(ArgumentType::BOOLEAN, "bool").Build());
50 return std::make_unique<APISignature>(std::move(specs));
51 }
52
OneObject()53 std::unique_ptr<APISignature> OneObject() {
54 SpecVector specs;
55 specs.push_back(
56 ArgumentSpecBuilder(ArgumentType::OBJECT, "obj")
57 .AddProperty("prop1",
58 ArgumentSpecBuilder(ArgumentType::STRING).Build())
59 .AddProperty(
60 "prop2",
61 ArgumentSpecBuilder(ArgumentType::STRING).MakeOptional().Build())
62 .Build());
63 return std::make_unique<APISignature>(std::move(specs));
64 }
65
NoArgs()66 std::unique_ptr<APISignature> NoArgs() {
67 return std::make_unique<APISignature>(SpecVector());
68 }
69
IntAndCallback()70 std::unique_ptr<APISignature> IntAndCallback() {
71 SpecVector specs;
72 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int").Build());
73 specs.push_back(
74 ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback").Build());
75 return std::make_unique<APISignature>(std::move(specs));
76 }
77
IntAndOptionalCallback()78 std::unique_ptr<APISignature> IntAndOptionalCallback() {
79 SpecVector specs;
80 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int").Build());
81 specs.push_back(ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback")
82 .MakeOptional()
83 .Build());
84 return std::make_unique<APISignature>(std::move(specs));
85 }
86
OptionalIntAndCallback()87 std::unique_ptr<APISignature> OptionalIntAndCallback() {
88 SpecVector specs;
89 specs.push_back(
90 ArgumentSpecBuilder(ArgumentType::INTEGER, "int").MakeOptional().Build());
91 specs.push_back(
92 ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback").Build());
93 return std::make_unique<APISignature>(std::move(specs));
94 }
95
OptionalCallback()96 std::unique_ptr<APISignature> OptionalCallback() {
97 SpecVector specs;
98 specs.push_back(ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback")
99 .MakeOptional()
100 .Build());
101 return std::make_unique<APISignature>(std::move(specs));
102 }
103
IntAnyOptionalObjectOptionalCallback()104 std::unique_ptr<APISignature> IntAnyOptionalObjectOptionalCallback() {
105 SpecVector specs;
106 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int").Build());
107 specs.push_back(ArgumentSpecBuilder(ArgumentType::ANY, "any").Build());
108 specs.push_back(
109 ArgumentSpecBuilder(ArgumentType::OBJECT, "obj")
110 .AddProperty(
111 "prop",
112 ArgumentSpecBuilder(ArgumentType::INTEGER).MakeOptional().Build())
113 .MakeOptional()
114 .Build());
115 specs.push_back(ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback")
116 .MakeOptional()
117 .Build());
118 return std::make_unique<APISignature>(std::move(specs));
119 }
120
RefObj()121 std::unique_ptr<APISignature> RefObj() {
122 SpecVector specs;
123 specs.push_back(
124 ArgumentSpecBuilder(ArgumentType::REF, "obj").SetRef("refObj").Build());
125 return std::make_unique<APISignature>(std::move(specs));
126 }
127
RefEnum()128 std::unique_ptr<APISignature> RefEnum() {
129 SpecVector specs;
130 specs.push_back(
131 ArgumentSpecBuilder(ArgumentType::REF, "enum").SetRef("refEnum").Build());
132 return std::make_unique<APISignature>(std::move(specs));
133 }
134
OptionalObjectAndCallback()135 std::unique_ptr<APISignature> OptionalObjectAndCallback() {
136 SpecVector specs;
137 specs.push_back(
138 ArgumentSpecBuilder(ArgumentType::OBJECT, "obj")
139 .AddProperty(
140 "prop1",
141 ArgumentSpecBuilder(ArgumentType::INTEGER).MakeOptional().Build())
142 .MakeOptional()
143 .Build());
144 specs.push_back(ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback")
145 .MakeOptional()
146 .Build());
147 return std::make_unique<APISignature>(std::move(specs));
148 }
149
OptionalIntAndNumber()150 std::unique_ptr<APISignature> OptionalIntAndNumber() {
151 SpecVector specs;
152 specs.push_back(
153 ArgumentSpecBuilder(ArgumentType::INTEGER, "int").MakeOptional().Build());
154 specs.push_back(ArgumentSpecBuilder(ArgumentType::DOUBLE, "num").Build());
155 return std::make_unique<APISignature>(std::move(specs));
156 }
157
OptionalIntAndInt()158 std::unique_ptr<APISignature> OptionalIntAndInt() {
159 SpecVector specs;
160 specs.push_back(
161 ArgumentSpecBuilder(ArgumentType::INTEGER, "int").MakeOptional().Build());
162 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int2").Build());
163 return std::make_unique<APISignature>(std::move(specs));
164 }
165
StringToV8Vector(v8::Local<v8::Context> context,const char * args)166 std::vector<v8::Local<v8::Value>> StringToV8Vector(
167 v8::Local<v8::Context> context,
168 const char* args) {
169 v8::Local<v8::Value> v8_args = V8ValueFromScriptSource(context, args);
170 EXPECT_FALSE(v8_args.IsEmpty());
171 EXPECT_TRUE(v8_args->IsArray());
172 std::vector<v8::Local<v8::Value>> vector_args;
173 EXPECT_TRUE(gin::ConvertFromV8(context->GetIsolate(), v8_args, &vector_args));
174 return vector_args;
175 }
176
177 } // namespace
178
179 class APISignatureTest : public APIBindingTest {
180 public:
APISignatureTest()181 APISignatureTest()
182 : type_refs_(APITypeReferenceMap::InitializeTypeCallback()) {}
183 ~APISignatureTest() override = default;
184
SetUp()185 void SetUp() override {
186 APIBindingTest::SetUp();
187
188 std::unique_ptr<ArgumentSpec> ref_obj_spec =
189 ArgumentSpecBuilder(ArgumentType::OBJECT)
190 .AddProperty("prop1",
191 ArgumentSpecBuilder(ArgumentType::STRING).Build())
192 .AddProperty("prop2", ArgumentSpecBuilder(ArgumentType::INTEGER)
193 .MakeOptional()
194 .Build())
195 .Build();
196 type_refs_.AddSpec("refObj", std::move(ref_obj_spec));
197
198 type_refs_.AddSpec("refEnum", ArgumentSpecBuilder(ArgumentType::STRING)
199 .SetEnums({"alpha", "beta"})
200 .Build());
201 }
202
ExpectPass(const APISignature & signature,base::StringPiece arg_values,base::StringPiece expected_parsed_args,binding::AsyncResponseType expected_response_type)203 void ExpectPass(const APISignature& signature,
204 base::StringPiece arg_values,
205 base::StringPiece expected_parsed_args,
206 binding::AsyncResponseType expected_response_type) {
207 RunTest(signature, arg_values, expected_parsed_args, expected_response_type,
208 true, std::string());
209 }
210
ExpectFailure(const APISignature & signature,base::StringPiece arg_values,const std::string & expected_error)211 void ExpectFailure(const APISignature& signature,
212 base::StringPiece arg_values,
213 const std::string& expected_error) {
214 RunTest(signature, arg_values, base::StringPiece(),
215 binding::AsyncResponseType::kNone, false, expected_error);
216 }
217
ExpectResponsePass(const APISignature & signature,base::StringPiece arg_values)218 void ExpectResponsePass(const APISignature& signature,
219 base::StringPiece arg_values) {
220 RunResponseTest(signature, arg_values, base::nullopt);
221 }
222
ExpectResponseFailure(const APISignature & signature,base::StringPiece arg_values,const std::string & expected_error)223 void ExpectResponseFailure(const APISignature& signature,
224 base::StringPiece arg_values,
225 const std::string& expected_error) {
226 RunResponseTest(signature, arg_values, expected_error);
227 }
228
type_refs() const229 const APITypeReferenceMap& type_refs() const { return type_refs_; }
230
231 private:
RunTest(const APISignature & signature,base::StringPiece arg_values,base::StringPiece expected_parsed_args,binding::AsyncResponseType expected_response_type,bool should_succeed,const std::string & expected_error)232 void RunTest(const APISignature& signature,
233 base::StringPiece arg_values,
234 base::StringPiece expected_parsed_args,
235 binding::AsyncResponseType expected_response_type,
236 bool should_succeed,
237 const std::string& expected_error) {
238 SCOPED_TRACE(arg_values);
239 v8::Local<v8::Context> context = MainContext();
240 v8::Local<v8::Value> v8_args = V8ValueFromScriptSource(context, arg_values);
241 ASSERT_FALSE(v8_args.IsEmpty());
242 ASSERT_TRUE(v8_args->IsArray());
243 std::vector<v8::Local<v8::Value>> vector_args;
244 ASSERT_TRUE(gin::ConvertFromV8(isolate(), v8_args, &vector_args));
245
246 APISignature::JSONParseResult parse_result =
247 signature.ParseArgumentsToJSON(context, vector_args, type_refs_);
248 ASSERT_EQ(should_succeed, !!parse_result.arguments);
249 ASSERT_NE(should_succeed, parse_result.error.has_value());
250 EXPECT_EQ(expected_response_type, parse_result.async_type);
251 EXPECT_EQ(expected_response_type == binding::AsyncResponseType::kCallback,
252 !parse_result.callback.IsEmpty());
253 if (should_succeed) {
254 EXPECT_EQ(ReplaceSingleQuotes(expected_parsed_args),
255 ValueToString(*parse_result.arguments));
256 } else {
257 EXPECT_EQ(expected_error, *parse_result.error);
258 }
259 }
260
RunResponseTest(const APISignature & signature,base::StringPiece arg_values,base::Optional<std::string> expected_error)261 void RunResponseTest(const APISignature& signature,
262 base::StringPiece arg_values,
263 base::Optional<std::string> expected_error) {
264 SCOPED_TRACE(arg_values);
265 v8::Local<v8::Context> context = MainContext();
266 v8::Local<v8::Value> v8_args = V8ValueFromScriptSource(context, arg_values);
267 ASSERT_FALSE(v8_args.IsEmpty());
268 ASSERT_TRUE(v8_args->IsArray());
269 std::vector<v8::Local<v8::Value>> vector_args;
270 ASSERT_TRUE(gin::ConvertFromV8(isolate(), v8_args, &vector_args));
271
272 std::string error;
273 bool should_succeed = !expected_error;
274 bool success =
275 signature.ValidateResponse(context, vector_args, type_refs_, &error);
276 EXPECT_EQ(should_succeed, success) << error;
277 ASSERT_EQ(should_succeed, error.empty());
278 if (!should_succeed)
279 EXPECT_EQ(*expected_error, error);
280 }
281
282 APITypeReferenceMap type_refs_;
283
284 DISALLOW_COPY_AND_ASSIGN(APISignatureTest);
285 };
286
TEST_F(APISignatureTest,BasicSignatureParsing)287 TEST_F(APISignatureTest, BasicSignatureParsing) {
288 v8::HandleScope handle_scope(isolate());
289
290 {
291 SCOPED_TRACE("OneString");
292 auto signature = OneString();
293 ExpectPass(*signature, "['foo']", "['foo']",
294 binding::AsyncResponseType::kNone);
295 ExpectPass(*signature, "['']", "['']", binding::AsyncResponseType::kNone);
296 ExpectFailure(*signature, "[1]", NoMatchingSignature());
297 ExpectFailure(*signature, "[]", NoMatchingSignature());
298 ExpectFailure(*signature, "[{}]", NoMatchingSignature());
299 ExpectFailure(*signature, "['foo', 'bar']", NoMatchingSignature());
300 }
301
302 {
303 SCOPED_TRACE("StringAndInt");
304 auto signature = StringAndInt();
305 ExpectPass(*signature, "['foo', 42]", "['foo',42]",
306 binding::AsyncResponseType::kNone);
307 ExpectPass(*signature, "['foo', -1]", "['foo',-1]",
308 binding::AsyncResponseType::kNone);
309 ExpectFailure(*signature, "[1]", NoMatchingSignature());
310 ExpectFailure(*signature, "['foo'];", NoMatchingSignature());
311 ExpectFailure(*signature, "[1, 'foo']", NoMatchingSignature());
312 ExpectFailure(*signature, "['foo', 'foo']", NoMatchingSignature());
313 ExpectFailure(*signature, "['foo', '1']", NoMatchingSignature());
314 ExpectFailure(*signature, "['foo', 2.3]", NoMatchingSignature());
315 }
316
317 {
318 SCOPED_TRACE("StringOptionalIntAndBool");
319 auto signature = StringOptionalIntAndBool();
320 ExpectPass(*signature, "['foo', 42, true]", "['foo',42,true]",
321 binding::AsyncResponseType::kNone);
322 ExpectPass(*signature, "['foo', true]", "['foo',null,true]",
323 binding::AsyncResponseType::kNone);
324 ExpectFailure(*signature, "['foo', 'bar', true]", NoMatchingSignature());
325 }
326
327 {
328 SCOPED_TRACE("OneObject");
329 auto signature = OneObject();
330 ExpectPass(*signature, "[{prop1: 'foo'}]", "[{'prop1':'foo'}]",
331 binding::AsyncResponseType::kNone);
332 ExpectFailure(*signature,
333 "[{ get prop1() { throw new Error('Badness'); } }]",
334 ArgumentError("obj", api_errors::ScriptThrewError()));
335 }
336
337 {
338 SCOPED_TRACE("NoArgs");
339 auto signature = NoArgs();
340 ExpectPass(*signature, "[]", "[]", binding::AsyncResponseType::kNone);
341 ExpectFailure(*signature, "[0]", NoMatchingSignature());
342 ExpectFailure(*signature, "['']", NoMatchingSignature());
343 ExpectFailure(*signature, "[null]", NoMatchingSignature());
344 ExpectFailure(*signature, "[undefined]", NoMatchingSignature());
345 }
346
347 {
348 SCOPED_TRACE("IntAndCallback");
349 auto signature = IntAndCallback();
350 ExpectPass(*signature, "[1, function() {}]", "[1]",
351 binding::AsyncResponseType::kCallback);
352 ExpectFailure(*signature, "[function() {}]", NoMatchingSignature());
353 ExpectFailure(*signature, "[1]", NoMatchingSignature());
354 }
355
356 {
357 SCOPED_TRACE("OptionalIntAndCallback");
358 auto signature = OptionalIntAndCallback();
359 ExpectPass(*signature, "[1, function() {}]", "[1]",
360 binding::AsyncResponseType::kCallback);
361 ExpectPass(*signature, "[function() {}]", "[null]",
362 binding::AsyncResponseType::kCallback);
363 ExpectFailure(*signature, "[1]", NoMatchingSignature());
364 }
365
366 {
367 SCOPED_TRACE("OptionalCallback");
368 auto signature = OptionalCallback();
369 ExpectPass(*signature, "[function() {}]", "[]",
370 binding::AsyncResponseType::kCallback);
371 ExpectPass(*signature, "[]", "[]", binding::AsyncResponseType::kNone);
372 ExpectPass(*signature, "[undefined]", "[]",
373 binding::AsyncResponseType::kNone);
374 ExpectFailure(*signature, "[0]", NoMatchingSignature());
375 }
376
377 {
378 SCOPED_TRACE("IntAnyOptionalObjectOptionalCallback");
379 auto signature = IntAnyOptionalObjectOptionalCallback();
380 ExpectPass(*signature, "[4, {foo: 'bar'}, function() {}]",
381 "[4,{'foo':'bar'},null]", binding::AsyncResponseType::kCallback);
382 ExpectPass(*signature, "[4, {foo: 'bar'}]", "[4,{'foo':'bar'},null]",
383 binding::AsyncResponseType::kNone);
384 ExpectPass(*signature, "[4, {foo: 'bar'}, {}]", "[4,{'foo':'bar'},{}]",
385 binding::AsyncResponseType::kNone);
386 ExpectFailure(*signature, "[4, function() {}]",
387 ArgumentError("any", api_errors::UnserializableValue()));
388 ExpectFailure(*signature, "[4]", NoMatchingSignature());
389 }
390
391 {
392 SCOPED_TRACE("OptionalObjectAndCallback");
393 auto signature = OptionalObjectAndCallback();
394 ExpectPass(*signature, "[{prop1: 1}]", "[{'prop1':1}]",
395 binding::AsyncResponseType::kNone);
396 ExpectPass(*signature, "[]", "[null]", binding::AsyncResponseType::kNone);
397 ExpectPass(*signature, "[null]", "[null]",
398 binding::AsyncResponseType::kNone);
399 ExpectFailure(*signature, "[{prop1: 'str'}]",
400 ArgumentError("obj", api_errors::PropertyError(
401 "prop1", InvalidType(kTypeInteger,
402 kTypeString))));
403 ExpectFailure(*signature, "[{prop1: 'str'}, function() {}]",
404 ArgumentError("obj", api_errors::PropertyError(
405 "prop1", InvalidType(kTypeInteger,
406 kTypeString))));
407 }
408
409 {
410 SCOPED_TRACE("OptionalIntAndNumber");
411 auto signature = OptionalIntAndNumber();
412 ExpectPass(*signature, "[1.0, 1.0]", "[1,1.0]",
413 binding::AsyncResponseType::kNone);
414 ExpectPass(*signature, "[1, 1]", "[1,1.0]",
415 binding::AsyncResponseType::kNone);
416 ExpectPass(*signature, "[1.0]", "[null,1.0]",
417 binding::AsyncResponseType::kNone);
418 ExpectPass(*signature, "[1]", "[null,1.0]",
419 binding::AsyncResponseType::kNone);
420 ExpectFailure(*signature, "[1.0, null]", NoMatchingSignature());
421 ExpectFailure(*signature, "[1, null]", NoMatchingSignature());
422 }
423
424 {
425 SCOPED_TRACE("OptionalIntAndInt");
426 auto signature = OptionalIntAndInt();
427 ExpectPass(*signature, "[1.0, 1.0]", "[1,1]",
428 binding::AsyncResponseType::kNone);
429 ExpectPass(*signature, "[1, 1]", "[1,1]",
430 binding::AsyncResponseType::kNone);
431 ExpectPass(*signature, "[1.0]", "[null,1]",
432 binding::AsyncResponseType::kNone);
433 ExpectPass(*signature, "[1]", "[null,1]",
434 binding::AsyncResponseType::kNone);
435 ExpectFailure(*signature, "[1.0, null]", NoMatchingSignature());
436 ExpectFailure(*signature, "[1, null]", NoMatchingSignature());
437 }
438 }
439
TEST_F(APISignatureTest,TypeRefsTest)440 TEST_F(APISignatureTest, TypeRefsTest) {
441 v8::HandleScope handle_scope(isolate());
442
443 {
444 auto signature = RefObj();
445 ExpectPass(*signature, "[{prop1: 'foo'}]", "[{'prop1':'foo'}]",
446 binding::AsyncResponseType::kNone);
447 ExpectPass(*signature, "[{prop1: 'foo', prop2: 2}]",
448 "[{'prop1':'foo','prop2':2}]",
449 binding::AsyncResponseType::kNone);
450 ExpectFailure(*signature, "[{prop1: 'foo', prop2: 'a'}]",
451 ArgumentError("obj", api_errors::PropertyError(
452 "prop2", InvalidType(kTypeInteger,
453 kTypeString))));
454 }
455
456 {
457 auto signature = RefEnum();
458 ExpectPass(*signature, "['alpha']", "['alpha']",
459 binding::AsyncResponseType::kNone);
460 ExpectPass(*signature, "['beta']", "['beta']",
461 binding::AsyncResponseType::kNone);
462 ExpectFailure(
463 *signature, "['gamma']",
464 ArgumentError("enum", api_errors::InvalidEnumValue({"alpha", "beta"})));
465 }
466 }
467
TEST_F(APISignatureTest,ExpectedSignature)468 TEST_F(APISignatureTest, ExpectedSignature) {
469 EXPECT_EQ("string string", OneString()->GetExpectedSignature());
470 EXPECT_EQ("string string, integer int",
471 StringAndInt()->GetExpectedSignature());
472 EXPECT_EQ("string string, optional integer int, boolean bool",
473 StringOptionalIntAndBool()->GetExpectedSignature());
474 EXPECT_EQ("object obj", OneObject()->GetExpectedSignature());
475 EXPECT_EQ("", NoArgs()->GetExpectedSignature());
476 EXPECT_EQ("integer int, function callback",
477 IntAndCallback()->GetExpectedSignature());
478 EXPECT_EQ("optional integer int, function callback",
479 OptionalIntAndCallback()->GetExpectedSignature());
480 EXPECT_EQ("optional function callback",
481 OptionalCallback()->GetExpectedSignature());
482 EXPECT_EQ(
483 "integer int, any any, optional object obj, optional function callback",
484 IntAnyOptionalObjectOptionalCallback()->GetExpectedSignature());
485 EXPECT_EQ("refObj obj", RefObj()->GetExpectedSignature());
486 EXPECT_EQ("refEnum enum", RefEnum()->GetExpectedSignature());
487 }
488
TEST_F(APISignatureTest,ParseIgnoringSchema)489 TEST_F(APISignatureTest, ParseIgnoringSchema) {
490 v8::HandleScope handle_scope(isolate());
491 v8::Local<v8::Context> context = MainContext();
492
493 {
494 // Test with providing an optional callback.
495 auto signature = IntAndOptionalCallback();
496 std::vector<v8::Local<v8::Value>> v8_args =
497 StringToV8Vector(context, "[1, function() {}]");
498 APISignature::JSONParseResult parse_result =
499 signature->ConvertArgumentsIgnoringSchema(context, v8_args);
500 EXPECT_FALSE(parse_result.error);
501 ASSERT_TRUE(parse_result.arguments);
502 EXPECT_EQ("[1]", ValueToString(*parse_result.arguments));
503 EXPECT_FALSE(parse_result.callback.IsEmpty());
504 }
505
506 {
507 // Test with omitting the optional callback.
508 auto signature = IntAndOptionalCallback();
509 std::vector<v8::Local<v8::Value>> v8_args =
510 StringToV8Vector(context, "[1, null]");
511 v8::Local<v8::Function> callback;
512 std::unique_ptr<base::ListValue> parsed;
513 APISignature::JSONParseResult parse_result =
514 signature->ConvertArgumentsIgnoringSchema(context, v8_args);
515 EXPECT_FALSE(parse_result.error);
516 ASSERT_TRUE(parse_result.arguments);
517 EXPECT_EQ("[1]", ValueToString(*parse_result.arguments));
518 EXPECT_TRUE(parse_result.callback.IsEmpty());
519 }
520
521 {
522 // Test with providing something completely different than the spec, which
523 // is (unfortunately) allowed and used.
524 auto signature = OneString();
525 std::vector<v8::Local<v8::Value>> v8_args =
526 StringToV8Vector(context, "[{not: 'a string'}]");
527 APISignature::JSONParseResult parse_result =
528 signature->ConvertArgumentsIgnoringSchema(context, v8_args);
529 EXPECT_FALSE(parse_result.error);
530 ASSERT_TRUE(parse_result.arguments);
531 EXPECT_EQ(R"([{"not":"a string"}])",
532 ValueToString(*parse_result.arguments));
533 EXPECT_TRUE(parse_result.callback.IsEmpty());
534 }
535
536 {
537 auto signature = OneObject();
538 std::vector<v8::Local<v8::Value>> v8_args = StringToV8Vector(
539 context, "[{prop1: 'foo', other: 'bar', nullProp: null}]");
540 APISignature::JSONParseResult parse_result =
541 signature->ConvertArgumentsIgnoringSchema(context, v8_args);
542 EXPECT_FALSE(parse_result.error);
543 ASSERT_TRUE(parse_result.arguments);
544 EXPECT_EQ(R"([{"other":"bar","prop1":"foo"}])",
545 ValueToString(*parse_result.arguments));
546 EXPECT_TRUE(parse_result.callback.IsEmpty());
547 }
548
549 {
550 // Unserializable arguments are inserted as "null" in the argument list in
551 // order to match existing JS bindings behavior.
552 // See https://crbug.com/924045.
553 auto signature = OneString();
554 std::vector<v8::Local<v8::Value>> v8_args =
555 StringToV8Vector(context, "[1, undefined, 1/0]");
556 APISignature::JSONParseResult parse_result =
557 signature->ConvertArgumentsIgnoringSchema(context, v8_args);
558 EXPECT_FALSE(parse_result.error);
559 ASSERT_TRUE(parse_result.arguments);
560 EXPECT_EQ("[1,null,null]", ValueToString(*parse_result.arguments));
561 EXPECT_TRUE(parse_result.callback.IsEmpty());
562 }
563 }
564
TEST_F(APISignatureTest,ParseArgumentsToV8)565 TEST_F(APISignatureTest, ParseArgumentsToV8) {
566 v8::HandleScope handle_scope(isolate());
567 v8::Local<v8::Context> context = MainContext();
568
569 // Test that parsing a signature returns values that are free of tricky
570 // getters. This is more thoroughly tested in the ArgumentSpec conversion
571 // unittests, but verify that it applies to signature parsing.
572 auto signature = OneObject();
573 constexpr char kTrickyArgs[] = R"(
574 [{
575 get prop1() {
576 if (this.got)
577 return 'bar';
578 this.got = true;
579 return 'foo';
580 },
581 prop2: 'baz'
582 }])";
583 std::vector<v8::Local<v8::Value>> args =
584 StringToV8Vector(context, kTrickyArgs);
585
586 APISignature::V8ParseResult parse_result =
587 signature->ParseArgumentsToV8(context, args, type_refs());
588 ASSERT_TRUE(parse_result.arguments);
589
590 ASSERT_EQ(1u, parse_result.arguments->size());
591 ASSERT_TRUE((*parse_result.arguments)[0]->IsObject());
592 gin::Dictionary dict(isolate(),
593 (*parse_result.arguments)[0].As<v8::Object>());
594
595 std::string prop1;
596 ASSERT_TRUE(dict.Get("prop1", &prop1));
597 EXPECT_EQ("foo", prop1);
598
599 std::string prop2;
600 ASSERT_TRUE(dict.Get("prop2", &prop2));
601 EXPECT_EQ("baz", prop2);
602 }
603
604 // Tests response validation, which is stricter than typical validation.
TEST_F(APISignatureTest,ValidateResponse)605 TEST_F(APISignatureTest, ValidateResponse) {
606 v8::HandleScope handle_scope(isolate());
607
608 {
609 auto signature = StringAndInt();
610 ExpectResponsePass(*signature, "['hello', 42]");
611 ExpectResponseFailure(
612 *signature, "['hello', 'goodbye']",
613 ArgumentError("int", InvalidType(kTypeInteger, kTypeString)));
614 }
615
616 {
617 auto signature = StringOptionalIntAndBool();
618 ExpectResponsePass(*signature, "['hello', 42, true]");
619 ExpectResponsePass(*signature, "['hello', null, true]");
620 // Responses are not allowed to omit optional inner parameters.
621 ExpectResponseFailure(
622 *signature, "['hello', true]",
623 ArgumentError("int", InvalidType(kTypeInteger, kTypeBoolean)));
624 }
625
626 {
627 SpecVector specs;
628 specs.push_back(
629 ArgumentSpecBuilder(ArgumentType::STRING, "string").Build());
630 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int")
631 .MakeOptional()
632 .Build());
633 auto signature = std::make_unique<APISignature>(std::move(specs));
634 // Responses *are* allowed to omit optional trailing parameters (which will
635 // then be `undefined` to the caller).
636 ExpectResponsePass(*signature, "['hello']");
637
638 ExpectResponseFailure(
639 *signature, "['hello', true]",
640 ArgumentError("int", InvalidType(kTypeInteger, kTypeBoolean)));
641 }
642 }
643
644 // Tests signature parsing when promise-based responses are supported.
TEST_F(APISignatureTest,PromisesSupport)645 TEST_F(APISignatureTest, PromisesSupport) {
646 v8::HandleScope handle_scope(isolate());
647 auto api_available =
648 base::BindRepeating([](v8::Local<v8::Context> context,
649 const std::string& name) { return true; });
650 // Set up a boolean we can flip to simulate if a context supports promises.
651 // For clarity, this should be explicitly set before each testcase below.
652 bool context_allows_promises = true;
653 auto promises_available = base::BindRepeating(
654 [](bool* flag, v8::Local<v8::Context> context) { return *flag; },
655 &context_allows_promises);
656 BindingAccessChecker access_checker(api_available, promises_available);
657
658 {
659 // Test a signature with a required callback.
660 context_allows_promises = true;
661 SpecVector required_callback_specs;
662 required_callback_specs.push_back(
663 ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback").Build());
664 auto required_callback_signature =
665 std::make_unique<APISignature>(std::move(required_callback_specs));
666 // By default, APIs don't support promises, and passing in no arguments
667 // should fail.
668 ExpectFailure(*required_callback_signature, "[]", NoMatchingSignature());
669 }
670
671 {
672 // If we allow promises on the API, parsing the arguments should succeed
673 // (with a promise-based response type) if the context supports promises.
674 context_allows_promises = true;
675 SpecVector required_callback_specs;
676 required_callback_specs.push_back(
677 ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback").Build());
678 auto required_callback_signature = std::make_unique<APISignature>(
679 std::move(required_callback_specs), true /*api_supports_promises*/,
680 &access_checker);
681 ExpectPass(*required_callback_signature, "[]", "[]",
682 binding::AsyncResponseType::kPromise);
683 // If the context doesn't support promises, parsing should fail.
684 context_allows_promises = false;
685 ExpectFailure(*required_callback_signature, "[]", NoMatchingSignature());
686 }
687
688 {
689 // Next, try an optional callback.
690 context_allows_promises = true;
691 SpecVector optional_callback_specs;
692 optional_callback_specs.push_back(
693 ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback")
694 .MakeOptional()
695 .Build());
696 auto optional_callback_signature =
697 std::make_unique<APISignature>(std::move(optional_callback_specs));
698 // Even if promises aren't supported, parsing should succeed, because the
699 // callback is optional.
700 ExpectPass(*optional_callback_signature, "[]", "[]",
701 binding::AsyncResponseType::kNone);
702 }
703
704 {
705 // If we allow promises on the API, parsing the arguments should succeed,
706 // with a promise-based response type.
707 context_allows_promises = true;
708 SpecVector optional_callback_specs;
709 optional_callback_specs.push_back(
710 ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback")
711 .MakeOptional()
712 .Build());
713 auto optional_callback_signature = std::make_unique<APISignature>(
714 std::move(optional_callback_specs), true /*api_supports_promises*/,
715 &access_checker);
716 ExpectPass(*optional_callback_signature, "[]", "[]",
717 binding::AsyncResponseType::kPromise);
718 // If the context doesn't support promises, the call should still pass, but
719 // there shouldn't be a promise response type.
720 context_allows_promises = false;
721 ExpectPass(*optional_callback_signature, "[]", "[]",
722 binding::AsyncResponseType::kNone);
723 }
724 }
725
726 } // namespace extensions
727