OLD | NEW |
(Empty) | |
| 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/api_signature.h" |
| 6 |
| 7 #include "base/memory/ptr_util.h" |
| 8 #include "base/values.h" |
| 9 #include "extensions/renderer/api_binding_test.h" |
| 10 #include "extensions/renderer/api_binding_test_util.h" |
| 11 #include "extensions/renderer/api_type_reference_map.h" |
| 12 #include "extensions/renderer/argument_spec.h" |
| 13 #include "extensions/renderer/argument_spec_builder.h" |
| 14 #include "gin/converter.h" |
| 15 |
| 16 namespace extensions { |
| 17 namespace { |
| 18 |
| 19 using SpecVector = std::vector<std::unique_ptr<ArgumentSpec>>; |
| 20 |
| 21 std::unique_ptr<APISignature> OneString() { |
| 22 SpecVector specs; |
| 23 specs.push_back(ArgumentSpecBuilder(ArgumentType::STRING, "string").Build()); |
| 24 return base::MakeUnique<APISignature>(std::move(specs)); |
| 25 } |
| 26 |
| 27 std::unique_ptr<APISignature> StringAndInt() { |
| 28 SpecVector specs; |
| 29 specs.push_back(ArgumentSpecBuilder(ArgumentType::STRING, "string").Build()); |
| 30 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int").Build()); |
| 31 return base::MakeUnique<APISignature>(std::move(specs)); |
| 32 } |
| 33 |
| 34 std::unique_ptr<APISignature> StringOptionalIntAndBool() { |
| 35 SpecVector specs; |
| 36 specs.push_back(ArgumentSpecBuilder(ArgumentType::STRING, "string").Build()); |
| 37 specs.push_back( |
| 38 ArgumentSpecBuilder(ArgumentType::INTEGER, "int").MakeOptional().Build()); |
| 39 specs.push_back(ArgumentSpecBuilder(ArgumentType::BOOLEAN, "bool").Build()); |
| 40 return base::MakeUnique<APISignature>(std::move(specs)); |
| 41 } |
| 42 |
| 43 std::unique_ptr<APISignature> OneObject() { |
| 44 SpecVector specs; |
| 45 specs.push_back( |
| 46 ArgumentSpecBuilder(ArgumentType::OBJECT, "obj") |
| 47 .AddProperty("prop1", |
| 48 ArgumentSpecBuilder(ArgumentType::STRING).Build()) |
| 49 .AddProperty( |
| 50 "prop2", |
| 51 ArgumentSpecBuilder(ArgumentType::STRING).MakeOptional().Build()) |
| 52 .Build()); |
| 53 return base::MakeUnique<APISignature>(std::move(specs)); |
| 54 } |
| 55 |
| 56 std::unique_ptr<APISignature> NoArgs() { |
| 57 return base::MakeUnique<APISignature>(SpecVector()); |
| 58 } |
| 59 |
| 60 std::unique_ptr<APISignature> IntAndCallback() { |
| 61 SpecVector specs; |
| 62 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int").Build()); |
| 63 specs.push_back( |
| 64 ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback").Build()); |
| 65 return base::MakeUnique<APISignature>(std::move(specs)); |
| 66 } |
| 67 |
| 68 std::unique_ptr<APISignature> OptionalIntAndCallback() { |
| 69 SpecVector specs; |
| 70 specs.push_back( |
| 71 ArgumentSpecBuilder(ArgumentType::INTEGER, "int").MakeOptional().Build()); |
| 72 specs.push_back( |
| 73 ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback").Build()); |
| 74 return base::MakeUnique<APISignature>(std::move(specs)); |
| 75 } |
| 76 |
| 77 std::unique_ptr<APISignature> OptionalCallback() { |
| 78 SpecVector specs; |
| 79 specs.push_back(ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback") |
| 80 .MakeOptional() |
| 81 .Build()); |
| 82 return base::MakeUnique<APISignature>(std::move(specs)); |
| 83 } |
| 84 |
| 85 std::unique_ptr<APISignature> IntAnyOptionalObjectOptionalCallback() { |
| 86 SpecVector specs; |
| 87 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int").Build()); |
| 88 specs.push_back(ArgumentSpecBuilder(ArgumentType::ANY, "any").Build()); |
| 89 specs.push_back( |
| 90 ArgumentSpecBuilder(ArgumentType::OBJECT, "obj") |
| 91 .AddProperty( |
| 92 "prop", |
| 93 ArgumentSpecBuilder(ArgumentType::INTEGER).MakeOptional().Build()) |
| 94 .MakeOptional() |
| 95 .Build()); |
| 96 specs.push_back(ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback") |
| 97 .MakeOptional() |
| 98 .Build()); |
| 99 return base::MakeUnique<APISignature>(std::move(specs)); |
| 100 } |
| 101 |
| 102 std::unique_ptr<APISignature> RefObj() { |
| 103 SpecVector specs; |
| 104 specs.push_back( |
| 105 ArgumentSpecBuilder(ArgumentType::REF, "obj").SetRef("refObj").Build()); |
| 106 return base::MakeUnique<APISignature>(std::move(specs)); |
| 107 } |
| 108 |
| 109 std::unique_ptr<APISignature> RefEnum() { |
| 110 SpecVector specs; |
| 111 specs.push_back( |
| 112 ArgumentSpecBuilder(ArgumentType::REF, "enum").SetRef("refEnum").Build()); |
| 113 return base::MakeUnique<APISignature>(std::move(specs)); |
| 114 } |
| 115 |
| 116 } // namespace |
| 117 |
| 118 class APISignatureTest : public APIBindingTest { |
| 119 public: |
| 120 APISignatureTest() |
| 121 : type_refs_(APITypeReferenceMap::InitializeTypeCallback()) {} |
| 122 ~APISignatureTest() override = default; |
| 123 |
| 124 void SetUp() override { |
| 125 APIBindingTest::SetUp(); |
| 126 |
| 127 std::unique_ptr<ArgumentSpec> ref_obj_spec = |
| 128 ArgumentSpecBuilder(ArgumentType::OBJECT) |
| 129 .AddProperty("prop1", |
| 130 ArgumentSpecBuilder(ArgumentType::STRING).Build()) |
| 131 .AddProperty("prop2", ArgumentSpecBuilder(ArgumentType::INTEGER) |
| 132 .MakeOptional() |
| 133 .Build()) |
| 134 .Build(); |
| 135 type_refs_.AddSpec("refObj", std::move(ref_obj_spec)); |
| 136 |
| 137 type_refs_.AddSpec("refEnum", ArgumentSpecBuilder(ArgumentType::STRING) |
| 138 .SetEnums({"alpha", "beta"}) |
| 139 .Build()); |
| 140 } |
| 141 |
| 142 void ExpectPass(const APISignature& signature, |
| 143 base::StringPiece arg_values, |
| 144 base::StringPiece expected_parsed_args, |
| 145 bool expect_callback) { |
| 146 RunTest(signature, arg_values, expected_parsed_args, expect_callback, true); |
| 147 } |
| 148 |
| 149 void ExpectFailure(const APISignature& signature, |
| 150 base::StringPiece arg_values) { |
| 151 RunTest(signature, arg_values, base::StringPiece(), false, false); |
| 152 } |
| 153 |
| 154 private: |
| 155 void RunTest(const APISignature& signature, |
| 156 base::StringPiece arg_values, |
| 157 base::StringPiece expected_parsed_args, |
| 158 bool expect_callback, |
| 159 bool should_succeed) { |
| 160 SCOPED_TRACE(arg_values); |
| 161 v8::Local<v8::Context> context = MainContext(); |
| 162 v8::Local<v8::Value> v8_args = V8ValueFromScriptSource(context, arg_values); |
| 163 ASSERT_FALSE(v8_args.IsEmpty()); |
| 164 ASSERT_TRUE(v8_args->IsArray()); |
| 165 std::vector<v8::Local<v8::Value>> vector_args; |
| 166 ASSERT_TRUE(gin::ConvertFromV8(isolate(), v8_args, &vector_args)); |
| 167 |
| 168 std::unique_ptr<base::ListValue> result; |
| 169 v8::Local<v8::Function> callback; |
| 170 std::string error; |
| 171 bool success = signature.ParseArgumentsToJSON( |
| 172 context, vector_args, type_refs_, &result, &callback, &error); |
| 173 EXPECT_EQ(should_succeed, success); |
| 174 ASSERT_EQ(should_succeed, !!result); |
| 175 EXPECT_EQ(expect_callback, !callback.IsEmpty()); |
| 176 if (should_succeed) { |
| 177 EXPECT_EQ(ReplaceSingleQuotes(expected_parsed_args), |
| 178 ValueToString(*result)); |
| 179 } |
| 180 } |
| 181 |
| 182 APITypeReferenceMap type_refs_; |
| 183 |
| 184 DISALLOW_COPY_AND_ASSIGN(APISignatureTest); |
| 185 }; |
| 186 |
| 187 TEST_F(APISignatureTest, BasicSignatureParsing) { |
| 188 v8::HandleScope handle_scope(isolate()); |
| 189 |
| 190 { |
| 191 auto signature = OneString(); |
| 192 ExpectPass(*signature, "['foo']", "['foo']", false); |
| 193 ExpectPass(*signature, "['']", "['']", false); |
| 194 ExpectFailure(*signature, "[1]"); |
| 195 ExpectFailure(*signature, "[]"); |
| 196 ExpectFailure(*signature, "[{}]"); |
| 197 ExpectFailure(*signature, "['foo', 'bar']"); |
| 198 } |
| 199 |
| 200 { |
| 201 auto signature = StringAndInt(); |
| 202 ExpectPass(*signature, "['foo', 42]", "['foo',42]", false); |
| 203 ExpectPass(*signature, "['foo', -1]", "['foo',-1]", false); |
| 204 ExpectFailure(*signature, "[1]"); |
| 205 ExpectFailure(*signature, "['foo'];"); |
| 206 ExpectFailure(*signature, "[1, 'foo']"); |
| 207 ExpectFailure(*signature, "['foo', 'foo']"); |
| 208 ExpectFailure(*signature, "['foo', '1']"); |
| 209 ExpectFailure(*signature, "['foo', 2.3]"); |
| 210 } |
| 211 |
| 212 { |
| 213 auto signature = StringOptionalIntAndBool(); |
| 214 ExpectPass(*signature, "['foo', 42, true]", "['foo',42,true]", false); |
| 215 ExpectPass(*signature, "['foo', true]", "['foo',null,true]", false); |
| 216 ExpectFailure(*signature, "['foo', 'bar', true]"); |
| 217 } |
| 218 |
| 219 { |
| 220 auto signature = OneObject(); |
| 221 ExpectPass(*signature, "[{prop1: 'foo'}]", "[{'prop1':'foo'}]", false); |
| 222 ExpectFailure(*signature, |
| 223 "[{ get prop1() { throw new Error('Badness'); } }]"); |
| 224 } |
| 225 |
| 226 { |
| 227 auto signature = NoArgs(); |
| 228 ExpectPass(*signature, "[]", "[]", false); |
| 229 ExpectFailure(*signature, "[0]"); |
| 230 ExpectFailure(*signature, "['']"); |
| 231 ExpectFailure(*signature, "[null]"); |
| 232 ExpectFailure(*signature, "[undefined]"); |
| 233 } |
| 234 |
| 235 { |
| 236 auto signature = IntAndCallback(); |
| 237 ExpectPass(*signature, "[1, function() {}]", "[1]", true); |
| 238 ExpectFailure(*signature, "[function() {}]"); |
| 239 ExpectFailure(*signature, "[1]"); |
| 240 } |
| 241 |
| 242 { |
| 243 auto signature = OptionalIntAndCallback(); |
| 244 ExpectPass(*signature, "[1, function() {}]", "[1]", true); |
| 245 ExpectPass(*signature, "[function() {}]", "[null]", true); |
| 246 ExpectFailure(*signature, "[1]"); |
| 247 } |
| 248 |
| 249 { |
| 250 auto signature = OptionalCallback(); |
| 251 ExpectPass(*signature, "[function() {}]", "[]", true); |
| 252 ExpectPass(*signature, "[]", "[]", false); |
| 253 ExpectPass(*signature, "[undefined]", "[]", false); |
| 254 ExpectFailure(*signature, "[0]"); |
| 255 } |
| 256 |
| 257 { |
| 258 auto signature = IntAnyOptionalObjectOptionalCallback(); |
| 259 ExpectPass(*signature, "[4, {foo: 'bar'}, function() {}]", |
| 260 "[4,{'foo':'bar'},null]", true); |
| 261 ExpectPass(*signature, "[4, {foo: 'bar'}]", "[4,{'foo':'bar'},null]", |
| 262 false); |
| 263 ExpectPass(*signature, "[4, {foo: 'bar'}, {}]", "[4,{'foo':'bar'},{}]", |
| 264 false); |
| 265 ExpectFailure(*signature, "[4, function() {}]"); |
| 266 ExpectFailure(*signature, "[4]"); |
| 267 } |
| 268 } |
| 269 |
| 270 TEST_F(APISignatureTest, TypeRefsTest) { |
| 271 v8::HandleScope handle_scope(isolate()); |
| 272 |
| 273 { |
| 274 auto signature = RefObj(); |
| 275 ExpectPass(*signature, "[{prop1: 'foo'}]", "[{'prop1':'foo'}]", false); |
| 276 ExpectPass(*signature, "[{prop1: 'foo', prop2: 2}]", |
| 277 "[{'prop1':'foo','prop2':2}]", false); |
| 278 ExpectFailure(*signature, "[{prop1: 'foo', prop2: 'a'}]"); |
| 279 } |
| 280 |
| 281 { |
| 282 auto signature = RefEnum(); |
| 283 ExpectPass(*signature, "['alpha']", "['alpha']", false); |
| 284 ExpectPass(*signature, "['beta']", "['beta']", false); |
| 285 ExpectFailure(*signature, "['gamma']"); |
| 286 } |
| 287 } |
| 288 |
| 289 } // namespace extensions |
OLD | NEW |