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 |