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 | |
jbroman
2017/04/27 21:24:32
nit: not a huge win, but you could (here, in Argum
Devlin
2017/04/28 01:16:44
Yep, mentioned this here:
https://codereview.chrom
| |
21 std::unique_ptr<APISignature> OneString() { | |
22 SpecVector specs; | |
23 specs.push_back(ArgumentSpecBuilder(ArgumentType::STRING, "string")); | |
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")); | |
30 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int")); | |
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")); | |
37 specs.push_back( | |
38 ArgumentSpecBuilder(ArgumentType::INTEGER, "int").MakeOptional()); | |
39 specs.push_back(ArgumentSpecBuilder(ArgumentType::BOOLEAN, "bool")); | |
40 return base::MakeUnique<APISignature>(std::move(specs)); | |
Devlin
2017/04/27 21:04:43
As alluded offline, we could get to the world of
r
| |
41 } | |
42 | |
43 std::unique_ptr<APISignature> OneObject() { | |
44 SpecVector specs; | |
45 specs.push_back( | |
46 ArgumentSpecBuilder(ArgumentType::OBJECT, "obj") | |
47 .AddProperty("prop1", ArgumentSpecBuilder(ArgumentType::STRING)) | |
48 .AddProperty( | |
49 "prop2", | |
50 ArgumentSpecBuilder(ArgumentType::STRING).MakeOptional())); | |
51 return base::MakeUnique<APISignature>(std::move(specs)); | |
52 } | |
53 | |
54 std::unique_ptr<APISignature> NoArgs() { | |
55 return base::MakeUnique<APISignature>(SpecVector()); | |
56 } | |
57 | |
58 std::unique_ptr<APISignature> IntAndCallback() { | |
59 SpecVector specs; | |
60 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int")); | |
61 specs.push_back(ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback")); | |
62 return base::MakeUnique<APISignature>(std::move(specs)); | |
63 } | |
64 | |
65 std::unique_ptr<APISignature> OptionalIntAndCallback() { | |
66 SpecVector specs; | |
67 specs.push_back( | |
68 ArgumentSpecBuilder(ArgumentType::INTEGER, "int").MakeOptional()); | |
69 specs.push_back(ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback")); | |
70 return base::MakeUnique<APISignature>(std::move(specs)); | |
71 } | |
72 | |
73 std::unique_ptr<APISignature> OptionalCallback() { | |
74 SpecVector specs; | |
75 specs.push_back( | |
76 ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback").MakeOptional()); | |
77 return base::MakeUnique<APISignature>(std::move(specs)); | |
78 } | |
79 | |
80 std::unique_ptr<APISignature> IntAnyOptionalObjectOptionalCallback() { | |
81 SpecVector specs; | |
82 specs.push_back(ArgumentSpecBuilder(ArgumentType::INTEGER, "int")); | |
83 specs.push_back(ArgumentSpecBuilder(ArgumentType::ANY, "any")); | |
84 specs.push_back( | |
85 ArgumentSpecBuilder(ArgumentType::OBJECT, "obj") | |
86 .AddProperty( | |
87 "prop", ArgumentSpecBuilder(ArgumentType::INTEGER).MakeOptional()) | |
88 .MakeOptional()); | |
89 specs.push_back( | |
90 ArgumentSpecBuilder(ArgumentType::FUNCTION, "callback").MakeOptional()); | |
91 return base::MakeUnique<APISignature>(std::move(specs)); | |
92 } | |
93 | |
94 std::unique_ptr<APISignature> RefObj() { | |
95 SpecVector specs; | |
96 specs.push_back( | |
97 ArgumentSpecBuilder(ArgumentType::REF, "obj").SetRef("refObj")); | |
98 return base::MakeUnique<APISignature>(std::move(specs)); | |
99 } | |
100 | |
101 std::unique_ptr<APISignature> RefEnum() { | |
102 SpecVector specs; | |
103 specs.push_back( | |
104 ArgumentSpecBuilder(ArgumentType::REF, "enum").SetRef("refEnum")); | |
105 return base::MakeUnique<APISignature>(std::move(specs)); | |
106 } | |
107 | |
108 } // namespace | |
109 | |
110 class APISignatureTest : public APIBindingTest { | |
111 public: | |
112 APISignatureTest() | |
113 : type_refs_(APITypeReferenceMap::InitializeTypeCallback()) {} | |
114 ~APISignatureTest() override = default; | |
115 | |
116 void SetUp() override { | |
117 APIBindingTest::SetUp(); | |
118 | |
119 auto ref_obj_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::OBJECT); | |
120 auto prop1_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::STRING); | |
121 auto prop2_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::INTEGER); | |
122 prop2_spec->set_optional(true); | |
123 ArgumentSpec::PropertiesMap properties; | |
124 properties["prop1"] = std::move(prop1_spec); | |
125 properties["prop2"] = std::move(prop2_spec); | |
126 ref_obj_spec->set_properties(std::move(properties)); | |
127 type_refs_.AddSpec("refObj", std::move(ref_obj_spec)); | |
jbroman
2017/04/27 21:24:32
or:
std::unique_ptr<ArgumentSpec> ref_obj_spec =
Devlin
2017/04/28 01:16:44
Whoops! Missed this one. Thanks.
| |
128 | |
129 auto ref_enum_spec = base::MakeUnique<ArgumentSpec>(ArgumentType::STRING); | |
130 ref_enum_spec->set_enum_values({"alpha", "beta"}); | |
131 type_refs_.AddSpec("refEnum", std::move(ref_enum_spec)); | |
jbroman
2017/04/27 21:24:32
or (albeit not much difference):
type_refs_.AddSp
Devlin
2017/04/28 01:16:44
Done.
| |
132 } | |
133 | |
134 void ExpectPass(const APISignature& signature, | |
135 base::StringPiece arg_values, | |
136 base::StringPiece expected_parsed_args, | |
137 bool expect_callback) { | |
138 RunTest(signature, arg_values, expected_parsed_args, expect_callback, true); | |
139 } | |
140 | |
141 void ExpectFailure(const APISignature& signature, | |
142 base::StringPiece arg_values) { | |
143 RunTest(signature, arg_values, base::StringPiece(), false, false); | |
144 } | |
145 | |
146 private: | |
147 void RunTest(const APISignature& signature, | |
148 base::StringPiece arg_values, | |
149 base::StringPiece expected_parsed_args, | |
150 bool expect_callback, | |
151 bool should_succeed) { | |
152 SCOPED_TRACE(arg_values); | |
153 v8::Local<v8::Context> context = MainContext(); | |
154 v8::Local<v8::Value> v8_args = V8ValueFromScriptSource(context, arg_values); | |
155 ASSERT_FALSE(v8_args.IsEmpty()); | |
156 ASSERT_TRUE(v8_args->IsArray()); | |
157 std::vector<v8::Local<v8::Value>> vector_args; | |
158 ASSERT_TRUE(gin::ConvertFromV8(isolate(), v8_args, &vector_args)); | |
159 | |
160 std::unique_ptr<base::ListValue> result; | |
161 v8::Local<v8::Function> callback; | |
162 std::string error; | |
163 bool success = signature.ParseArgumentsToJSON( | |
164 context, vector_args, type_refs_, &result, &callback, &error); | |
165 EXPECT_EQ(should_succeed, success); | |
166 ASSERT_EQ(should_succeed, !!result); | |
167 EXPECT_EQ(expect_callback, !callback.IsEmpty()); | |
168 if (should_succeed) { | |
169 EXPECT_EQ(ReplaceSingleQuotes(expected_parsed_args), | |
170 ValueToString(*result)); | |
171 } | |
172 } | |
173 | |
174 APITypeReferenceMap type_refs_; | |
175 | |
176 DISALLOW_COPY_AND_ASSIGN(APISignatureTest); | |
177 }; | |
178 | |
179 TEST_F(APISignatureTest, Foo) { | |
jbroman
2017/04/27 21:24:32
nit: Foo is not a helpful test name.
Devlin
2017/04/28 01:16:44
D'oh! Thanks for catching this. It's a terrible
| |
180 v8::HandleScope handle_scope(isolate()); | |
181 | |
182 { | |
183 auto signature = OneString(); | |
jbroman
2017/04/27 21:24:32
nit: since these seem to all be from above an only
Devlin
2017/04/28 01:16:44
If it's okay, I'd like to refrain. When we add mo
jbroman
2017/04/28 01:30:54
Sure, sounds good then.
| |
184 ExpectPass(*signature, "['foo']", "['foo']", false); | |
185 ExpectPass(*signature, "['']", "['']", false); | |
186 ExpectFailure(*signature, "[1]"); | |
187 ExpectFailure(*signature, "[]"); | |
188 ExpectFailure(*signature, "[{}]"); | |
189 ExpectFailure(*signature, "['foo', 'bar']"); | |
190 } | |
191 | |
192 { | |
193 auto signature = StringAndInt(); | |
194 ExpectPass(*signature, "['foo', 42]", "['foo',42]", false); | |
195 ExpectPass(*signature, "['foo', -1]", "['foo',-1]", false); | |
196 ExpectFailure(*signature, "[1]"); | |
197 ExpectFailure(*signature, "['foo'];"); | |
198 ExpectFailure(*signature, "[1, 'foo']"); | |
199 ExpectFailure(*signature, "['foo', 'foo']"); | |
200 ExpectFailure(*signature, "['foo', '1']"); | |
201 ExpectFailure(*signature, "['foo', 2.3]"); | |
202 } | |
203 | |
204 { | |
205 auto signature = StringOptionalIntAndBool(); | |
206 ExpectPass(*signature, "['foo', 42, true]", "['foo',42,true]", false); | |
207 ExpectPass(*signature, "['foo', true]", "['foo',null,true]", false); | |
208 ExpectFailure(*signature, "['foo', 'bar', true]"); | |
209 } | |
210 | |
211 { | |
212 auto signature = OneObject(); | |
213 ExpectPass(*signature, "[{prop1: 'foo'}]", "[{'prop1':'foo'}]", false); | |
214 ExpectFailure(*signature, | |
215 "[{ get prop1() { throw new Error('Badness'); } }]"); | |
216 } | |
217 | |
218 { | |
219 auto signature = NoArgs(); | |
220 ExpectPass(*signature, "[]", "[]", false); | |
221 ExpectFailure(*signature, "[0]"); | |
222 ExpectFailure(*signature, "['']"); | |
223 ExpectFailure(*signature, "[null]"); | |
224 ExpectFailure(*signature, "[undefined]"); | |
225 } | |
226 | |
227 { | |
228 auto signature = IntAndCallback(); | |
229 ExpectPass(*signature, "[1, function() {}]", "[1]", true); | |
230 ExpectFailure(*signature, "[function() {}]"); | |
231 ExpectFailure(*signature, "[1]"); | |
232 } | |
233 | |
234 { | |
235 auto signature = OptionalIntAndCallback(); | |
236 ExpectPass(*signature, "[1, function() {}]", "[1]", true); | |
237 ExpectPass(*signature, "[function() {}]", "[null]", true); | |
238 ExpectFailure(*signature, "[1]"); | |
239 } | |
240 | |
241 { | |
242 auto signature = OptionalCallback(); | |
243 ExpectPass(*signature, "[function() {}]", "[]", true); | |
244 ExpectPass(*signature, "[]", "[]", false); | |
245 ExpectPass(*signature, "[undefined]", "[]", false); | |
246 ExpectFailure(*signature, "[0]"); | |
247 } | |
248 | |
249 { | |
250 auto signature = IntAnyOptionalObjectOptionalCallback(); | |
251 ExpectPass(*signature, "[4, {foo: 'bar'}, function() {}]", | |
252 "[4,{'foo':'bar'},null]", true); | |
253 ExpectPass(*signature, "[4, {foo: 'bar'}]", "[4,{'foo':'bar'},null]", | |
254 false); | |
255 ExpectPass(*signature, "[4, {foo: 'bar'}, {}]", "[4,{'foo':'bar'},{}]", | |
256 false); | |
257 ExpectFailure(*signature, "[4, function() {}]"); | |
258 ExpectFailure(*signature, "[4]"); | |
259 } | |
260 } | |
261 | |
262 TEST_F(APISignatureTest, TypeRefsTest) { | |
263 v8::HandleScope handle_scope(isolate()); | |
264 | |
265 { | |
266 auto signature = RefObj(); | |
267 ExpectPass(*signature, "[{prop1: 'foo'}]", "[{'prop1':'foo'}]", false); | |
268 ExpectPass(*signature, "[{prop1: 'foo', prop2: 2}]", | |
269 "[{'prop1':'foo','prop2':2}]", false); | |
270 ExpectFailure(*signature, "[{prop1: 'foo', prop2: 'a'}]"); | |
271 } | |
272 | |
273 { | |
274 auto signature = RefEnum(); | |
275 ExpectPass(*signature, "['alpha']", "['alpha']", false); | |
276 ExpectPass(*signature, "['beta']", "['beta']", false); | |
277 ExpectFailure(*signature, "['gamma']"); | |
278 } | |
279 } | |
280 | |
281 } // namespace extensions | |
OLD | NEW |