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