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