Chromium Code Reviews| 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 "gin/converter.h" | |
| 14 | |
| 15 namespace extensions { | |
| 16 namespace { | |
| 17 | |
| 18 using SpecVector = std::vector<std::unique_ptr<ArgumentSpec>>; | |
| 19 | |
| 20 std::unique_ptr<APISignature> OneString() { | |
| 21 auto string_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::STRING); | |
| 22 string_spec->set_name("string"); | |
| 23 SpecVector specs; | |
| 24 specs.push_back(std::move(string_spec)); | |
| 25 return base::MakeUnique<APISignature>(std::move(specs)); | |
| 26 } | |
| 27 | |
| 28 std::unique_ptr<APISignature> StringAndInt() { | |
| 29 auto string_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::STRING); | |
| 30 string_spec->set_name("string"); | |
| 31 auto int_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::INTEGER); | |
| 32 int_spec->set_name("int"); | |
| 33 SpecVector specs; | |
| 34 specs.push_back(std::move(string_spec)); | |
| 35 specs.push_back(std::move(int_spec)); | |
| 36 return base::MakeUnique<APISignature>(std::move(specs)); | |
| 37 } | |
| 38 | |
| 39 std::unique_ptr<APISignature> StringOptionalIntAndBool() { | |
| 40 auto string_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::STRING); | |
| 41 string_spec->set_name("string"); | |
| 42 auto opt_int_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::INTEGER); | |
| 43 opt_int_spec->set_name("int"); | |
| 44 opt_int_spec->set_optional(true); | |
| 45 auto bool_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::BOOLEAN); | |
| 46 bool_spec->set_name("bool"); | |
| 47 SpecVector specs; | |
| 48 specs.push_back(std::move(string_spec)); | |
| 49 specs.push_back(std::move(opt_int_spec)); | |
| 50 specs.push_back(std::move(bool_spec)); | |
| 51 return base::MakeUnique<APISignature>(std::move(specs)); | |
| 52 } | |
| 53 | |
| 54 std::unique_ptr<APISignature> OneObject() { | |
| 55 auto object_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::OBJECT); | |
| 56 object_spec->set_name("obj"); | |
| 57 auto prop1_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::STRING); | |
| 58 auto prop2_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::STRING); | |
| 59 prop2_spec->set_optional(true); | |
| 60 ArgumentSpec::PropertiesMap properties; | |
| 61 properties["prop1"] = std::move(prop1_spec); | |
| 62 properties["prop2"] = std::move(prop2_spec); | |
| 63 object_spec->set_properties(std::move(properties)); | |
| 64 SpecVector specs; | |
| 65 specs.push_back(std::move(object_spec)); | |
| 66 return base::MakeUnique<APISignature>(std::move(specs)); | |
|
jbroman
2017/04/27 19:18:17
super-nit: Or this could just be, if you'd want to
jbroman
2017/04/27 19:59:05
Update: urgh, nope, I'm wrong about this point.
Devlin
2017/04/27 20:55:46
Yep, originally tried to do that (and failed).
| |
| 67 } | |
| 68 | |
| 69 std::unique_ptr<APISignature> NoArgs() { | |
| 70 return base::MakeUnique<APISignature>(SpecVector()); | |
| 71 } | |
| 72 | |
| 73 std::unique_ptr<APISignature> IntAndCallback() { | |
| 74 auto int_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::INTEGER); | |
| 75 int_spec->set_name("int"); | |
| 76 auto callback_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::FUNCTION); | |
| 77 callback_spec->set_name("callback"); | |
| 78 SpecVector specs; | |
| 79 specs.push_back(std::move(int_spec)); | |
| 80 specs.push_back(std::move(callback_spec)); | |
| 81 return base::MakeUnique<APISignature>(std::move(specs)); | |
| 82 } | |
| 83 | |
| 84 std::unique_ptr<APISignature> OptionalIntAndCallback() { | |
| 85 auto int_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::INTEGER); | |
| 86 int_spec->set_name("int"); | |
| 87 int_spec->set_optional(true); | |
| 88 auto callback_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::FUNCTION); | |
| 89 callback_spec->set_name("callback"); | |
| 90 SpecVector specs; | |
| 91 specs.push_back(std::move(int_spec)); | |
| 92 specs.push_back(std::move(callback_spec)); | |
| 93 return base::MakeUnique<APISignature>(std::move(specs)); | |
| 94 } | |
| 95 | |
| 96 std::unique_ptr<APISignature> OptionalCallback() { | |
| 97 auto callback_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::FUNCTION); | |
| 98 callback_spec->set_name("callback"); | |
| 99 callback_spec->set_optional(true); | |
| 100 SpecVector specs; | |
| 101 specs.push_back(std::move(callback_spec)); | |
| 102 return base::MakeUnique<APISignature>(std::move(specs)); | |
| 103 } | |
| 104 | |
| 105 std::unique_ptr<APISignature> IntAnyOptionalObjectOptionalCallback() { | |
| 106 auto int_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::INTEGER); | |
| 107 int_spec->set_name("int"); | |
| 108 auto any_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::ANY); | |
| 109 any_spec->set_name("any"); | |
| 110 auto object_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::OBJECT); | |
| 111 object_spec->set_name("obj"); | |
| 112 object_spec->set_optional(true); | |
| 113 auto prop_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::INTEGER); | |
| 114 prop_spec->set_optional(true); | |
| 115 ArgumentSpec::PropertiesMap properties; | |
| 116 properties["prop"] = std::move(prop_spec); | |
| 117 object_spec->set_properties(std::move(properties)); | |
| 118 auto callback_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::FUNCTION); | |
| 119 callback_spec->set_name("callback"); | |
| 120 callback_spec->set_optional(true); | |
| 121 SpecVector specs; | |
| 122 specs.push_back(std::move(int_spec)); | |
| 123 specs.push_back(std::move(any_spec)); | |
| 124 specs.push_back(std::move(object_spec)); | |
| 125 specs.push_back(std::move(callback_spec)); | |
| 126 return base::MakeUnique<APISignature>(std::move(specs)); | |
| 127 } | |
|
jbroman
2017/04/27 19:18:17
nit: Hmm. This is only unit tests, so maybe it's n
jbroman
2017/04/27 19:59:05
To correct myself slightly here, for some frustrat
Devlin
2017/04/27 20:55:45
Interesting thought. Short answer: why not! Long
| |
| 128 | |
| 129 std::unique_ptr<APISignature> RefObj() { | |
| 130 auto ref_obj_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::REF); | |
| 131 ref_obj_spec->set_name("obj"); | |
| 132 ref_obj_spec->set_ref("refObj"); | |
| 133 SpecVector specs; | |
| 134 specs.push_back(std::move(ref_obj_spec)); | |
| 135 return base::MakeUnique<APISignature>(std::move(specs)); | |
| 136 } | |
| 137 | |
| 138 std::unique_ptr<APISignature> RefEnum() { | |
| 139 auto ref_enum_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::REF); | |
| 140 ref_enum_spec->set_name("enum"); | |
| 141 ref_enum_spec->set_ref("refEnum"); | |
| 142 SpecVector specs; | |
| 143 specs.push_back(std::move(ref_enum_spec)); | |
| 144 return base::MakeUnique<APISignature>(std::move(specs)); | |
| 145 } | |
| 146 | |
| 147 } // namespace | |
| 148 | |
| 149 class APISignatureTest : public APIBindingTest { | |
| 150 public: | |
| 151 APISignatureTest() | |
| 152 : type_refs_(APITypeReferenceMap::InitializeTypeCallback()) {} | |
| 153 ~APISignatureTest() override = default; | |
| 154 | |
| 155 void SetUp() override { | |
| 156 APIBindingTest::SetUp(); | |
| 157 | |
| 158 auto ref_obj_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::OBJECT); | |
| 159 auto prop1_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::STRING); | |
| 160 auto prop2_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::INTEGER); | |
| 161 prop2_spec->set_optional(true); | |
| 162 ArgumentSpec::PropertiesMap properties; | |
| 163 properties["prop1"] = std::move(prop1_spec); | |
| 164 properties["prop2"] = std::move(prop2_spec); | |
| 165 ref_obj_spec->set_properties(std::move(properties)); | |
| 166 type_refs_.AddSpec("refObj", std::move(ref_obj_spec)); | |
| 167 | |
| 168 auto ref_enum_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::STRING); | |
| 169 ref_enum_spec->set_enum_values({"alpha", "beta"}); | |
| 170 type_refs_.AddSpec("refEnum", std::move(ref_enum_spec)); | |
| 171 } | |
| 172 | |
| 173 void ExpectPass(const APISignature& signature, | |
| 174 base::StringPiece arg_values, | |
| 175 base::StringPiece expected_parsed_args, | |
| 176 bool expect_callback) { | |
| 177 RunTest(signature, arg_values, expected_parsed_args, expect_callback, true); | |
| 178 } | |
| 179 | |
| 180 void ExpectFailure(const APISignature& signature, | |
| 181 base::StringPiece arg_values) { | |
| 182 RunTest(signature, arg_values, base::StringPiece(), false, false); | |
| 183 } | |
| 184 | |
| 185 private: | |
| 186 void RunTest(const APISignature& signature, | |
| 187 base::StringPiece arg_values, | |
| 188 base::StringPiece expected_parsed_args, | |
| 189 bool expect_callback, | |
| 190 bool should_succeed) { | |
| 191 SCOPED_TRACE(arg_values); | |
| 192 v8::Local<v8::Context> context = MainContext(); | |
| 193 v8::Local<v8::Value> v8_args = V8ValueFromScriptSource(context, arg_values); | |
| 194 ASSERT_FALSE(v8_args.IsEmpty()); | |
| 195 ASSERT_TRUE(v8_args->IsArray()); | |
| 196 std::vector<v8::Local<v8::Value>> vector_args; | |
| 197 ASSERT_TRUE(gin::ConvertFromV8(isolate(), v8_args, &vector_args)); | |
| 198 | |
| 199 std::unique_ptr<base::ListValue> result; | |
| 200 v8::Local<v8::Function> callback; | |
| 201 std::string error; | |
| 202 bool success = signature.ParseArgumentsToJSON( | |
| 203 context, vector_args, type_refs_, &result, &callback, &error); | |
| 204 EXPECT_EQ(should_succeed, success); | |
| 205 ASSERT_EQ(should_succeed, !!result); | |
| 206 EXPECT_EQ(expect_callback, !callback.IsEmpty()); | |
| 207 if (should_succeed) { | |
| 208 EXPECT_EQ(ReplaceSingleQuotes(expected_parsed_args), | |
| 209 ValueToString(*result)); | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 APITypeReferenceMap type_refs_; | |
| 214 | |
| 215 DISALLOW_COPY_AND_ASSIGN(APISignatureTest); | |
| 216 }; | |
| 217 | |
| 218 TEST_F(APISignatureTest, Foo) { | |
| 219 v8::HandleScope handle_scope(isolate()); | |
| 220 | |
| 221 { | |
| 222 auto signature = OneString(); | |
| 223 ExpectPass(*signature, "['foo']", "['foo']", false); | |
| 224 ExpectPass(*signature, "['']", "['']", false); | |
| 225 ExpectFailure(*signature, "[1]"); | |
| 226 ExpectFailure(*signature, "[]"); | |
| 227 ExpectFailure(*signature, "[{}]"); | |
| 228 ExpectFailure(*signature, "['foo', 'bar']"); | |
| 229 } | |
| 230 | |
| 231 { | |
| 232 auto signature = StringAndInt(); | |
| 233 ExpectPass(*signature, "['foo', 42]", "['foo',42]", false); | |
| 234 ExpectPass(*signature, "['foo', -1]", "['foo',-1]", false); | |
| 235 ExpectFailure(*signature, "[1]"); | |
| 236 ExpectFailure(*signature, "['foo'];"); | |
| 237 ExpectFailure(*signature, "[1, 'foo']"); | |
| 238 ExpectFailure(*signature, "['foo', 'foo']"); | |
| 239 ExpectFailure(*signature, "['foo', '1']"); | |
| 240 ExpectFailure(*signature, "['foo', 2.3]"); | |
| 241 } | |
| 242 | |
| 243 { | |
| 244 auto signature = StringOptionalIntAndBool(); | |
| 245 ExpectPass(*signature, "['foo', 42, true]", "['foo',42,true]", false); | |
| 246 ExpectPass(*signature, "['foo', true]", "['foo',null,true]", false); | |
| 247 ExpectFailure(*signature, "['foo', 'bar', true]"); | |
| 248 } | |
| 249 | |
| 250 { | |
| 251 auto signature = OneObject(); | |
| 252 ExpectPass(*signature, "[{prop1: 'foo'}]", "[{'prop1':'foo'}]", false); | |
| 253 ExpectFailure(*signature, | |
| 254 "[{ get prop1() { throw new Error('Badness'); } }]"); | |
| 255 } | |
| 256 | |
| 257 { | |
| 258 auto signature = NoArgs(); | |
| 259 ExpectPass(*signature, "[]", "[]", false); | |
| 260 ExpectFailure(*signature, "[0]"); | |
| 261 ExpectFailure(*signature, "['']"); | |
| 262 ExpectFailure(*signature, "[null]"); | |
| 263 ExpectFailure(*signature, "[undefined]"); | |
| 264 } | |
| 265 | |
| 266 { | |
| 267 auto signature = IntAndCallback(); | |
| 268 ExpectPass(*signature, "[1, function() {}]", "[1]", true); | |
| 269 ExpectFailure(*signature, "[function() {}]"); | |
| 270 ExpectFailure(*signature, "[1]"); | |
| 271 } | |
| 272 | |
| 273 { | |
| 274 auto signature = OptionalIntAndCallback(); | |
| 275 ExpectPass(*signature, "[1, function() {}]", "[1]", true); | |
| 276 ExpectPass(*signature, "[function() {}]", "[null]", true); | |
| 277 ExpectFailure(*signature, "[1]"); | |
| 278 } | |
| 279 | |
| 280 { | |
| 281 auto signature = OptionalCallback(); | |
| 282 ExpectPass(*signature, "[function() {}]", "[]", true); | |
| 283 ExpectPass(*signature, "[]", "[]", false); | |
| 284 ExpectPass(*signature, "[undefined]", "[]", false); | |
| 285 ExpectFailure(*signature, "[0]"); | |
| 286 } | |
| 287 | |
| 288 { | |
| 289 auto signature = IntAnyOptionalObjectOptionalCallback(); | |
| 290 ExpectPass(*signature, "[4, {foo: 'bar'}, function() {}]", | |
| 291 "[4,{'foo':'bar'},null]", true); | |
| 292 ExpectPass(*signature, "[4, {foo: 'bar'}]", "[4,{'foo':'bar'},null]", | |
| 293 false); | |
| 294 ExpectPass(*signature, "[4, {foo: 'bar'}, {}]", "[4,{'foo':'bar'},{}]", | |
| 295 false); | |
| 296 ExpectFailure(*signature, "[4, function() {}]"); | |
| 297 ExpectFailure(*signature, "[4]"); | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 TEST_F(APISignatureTest, TypeRefsTest) { | |
| 302 v8::HandleScope handle_scope(isolate()); | |
| 303 | |
| 304 { | |
| 305 auto signature = RefObj(); | |
| 306 ExpectPass(*signature, "[{prop1: 'foo'}]", "[{'prop1':'foo'}]", false); | |
| 307 ExpectPass(*signature, "[{prop1: 'foo', prop2: 2}]", | |
| 308 "[{'prop1':'foo','prop2':2}]", false); | |
| 309 ExpectFailure(*signature, "[{prop1: 'foo', prop2: 'a'}]"); | |
| 310 } | |
| 311 | |
| 312 { | |
| 313 auto signature = RefEnum(); | |
| 314 ExpectPass(*signature, "['alpha']", "['alpha']", false); | |
| 315 ExpectPass(*signature, "['beta']", "['beta']", false); | |
| 316 ExpectFailure(*signature, "['gamma']"); | |
| 317 } | |
| 318 } | |
| 319 | |
| 320 } // namespace extensions | |
| OLD | NEW |