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