OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can be | |
4 * found in the LICENSE file. | |
5 */ | |
6 | |
7 #include "native_client/tests/fake_browser_ppapi/test_scriptable.h" | |
8 | |
9 #include <stdio.h> | |
10 #include <string.h> | |
11 | |
12 #include "native_client/src/include/nacl_macros.h" | |
13 #include "native_client/src/include/portability.h" | |
14 #include "native_client/src/shared/platform/nacl_check.h" | |
15 #include "native_client/tests/fake_browser_ppapi/fake_core.h" | |
16 #include "native_client/tests/fake_browser_ppapi/fake_host.h" | |
17 #include "native_client/tests/fake_browser_ppapi/fake_instance.h" | |
18 #include "native_client/tests/fake_browser_ppapi/fake_window.h" | |
19 #include "native_client/tests/fake_browser_ppapi/utility.h" | |
20 #include "ppapi/c/dev/ppb_var_deprecated.h" | |
21 #include "ppapi/c/ppb_core.h" | |
22 #include "ppapi/c/ppb_instance.h" | |
23 #include "ppapi/c/ppp_instance.h" | |
24 #include "ppapi/c/pp_errors.h" | |
25 | |
26 | |
27 namespace { | |
28 | |
29 // Some canonical constants used to initialize properties of various types. | |
30 const PP_Bool kBoolValue = PP_TRUE; | |
31 const int32_t kInt32Value = 144000; | |
32 const double kDoubleValue = 3.1415; | |
33 const char* const kStringValue = "hello, world"; | |
34 | |
35 // Some global state. | |
36 const PPB_Var_Deprecated* g_var_interface; | |
37 const PPB_Instance* g_instance_interface; | |
38 PP_Instance g_instance_id; | |
39 PP_Instance g_browser_module_id; | |
40 int64_t g_object_as_id; | |
41 | |
42 // TODO(sehr,polina): add this to the ppapi/c/dev/ppb_var_deprecated.h? | |
43 PP_Var MakeString(const char* str) { | |
44 return g_var_interface->VarFromUtf8(g_browser_module_id, | |
45 str, | |
46 static_cast<uint32_t>(strlen(str))); | |
47 } | |
48 | |
49 // PP_Var of string type that names the property that corresponds to the | |
50 // specified type. | |
51 PP_Var PropertyName(PP_VarType type) { | |
52 switch (type) { | |
53 case PP_VARTYPE_UNDEFINED: | |
54 return MakeString("propUndefined"); | |
55 case PP_VARTYPE_NULL: | |
56 return MakeString("propNull"); | |
57 case PP_VARTYPE_BOOL: | |
58 return MakeString("propBool"); | |
59 case PP_VARTYPE_INT32: | |
60 return MakeString("propInt32"); | |
61 case PP_VARTYPE_DOUBLE: | |
62 return MakeString("propDouble"); | |
63 case PP_VARTYPE_STRING: | |
64 return MakeString("propString"); | |
65 case PP_VARTYPE_OBJECT: | |
66 return MakeString("propObject"); | |
67 case PP_VARTYPE_ARRAY: | |
68 case PP_VARTYPE_DICTIONARY: | |
69 break; | |
70 } | |
71 NACL_NOTREACHED(); | |
72 return PP_MakeUndefined(); | |
73 } | |
74 | |
75 // PP_Var of string type that names a method that corresponds to the | |
76 // specified type. These methods all expect two args of |type|. | |
77 PP_Var MethodNameWith2Args(PP_VarType type) { | |
78 switch (type) { | |
79 case PP_VARTYPE_UNDEFINED: | |
80 return MakeString("methodUndefinedWith2Args"); | |
81 case PP_VARTYPE_NULL: | |
82 return MakeString("methodNullWith2Args"); | |
83 case PP_VARTYPE_BOOL: | |
84 return MakeString("methodBoolWith2Args"); | |
85 case PP_VARTYPE_INT32: | |
86 return MakeString("methodInt32With2Args"); | |
87 case PP_VARTYPE_DOUBLE: | |
88 return MakeString("methodDoubleWith2Args"); | |
89 case PP_VARTYPE_STRING: | |
90 return MakeString("methodStringWith2Args"); | |
91 case PP_VARTYPE_OBJECT: | |
92 return MakeString("methodObjectWith2Args"); | |
93 case PP_VARTYPE_ARRAY: | |
94 case PP_VARTYPE_DICTIONARY: | |
95 break; | |
96 } | |
97 NACL_NOTREACHED(); | |
98 return PP_MakeUndefined(); | |
99 } | |
100 | |
101 // Returns a canonical PP_Var of type. | |
102 PP_Var PropertyValue(PP_VarType type) { | |
103 switch (type) { | |
104 case PP_VARTYPE_UNDEFINED: | |
105 return PP_MakeUndefined(); | |
106 case PP_VARTYPE_NULL: | |
107 return PP_MakeNull(); | |
108 case PP_VARTYPE_BOOL: | |
109 return PP_MakeBool(kBoolValue); | |
110 case PP_VARTYPE_INT32: | |
111 return PP_MakeInt32(kInt32Value); | |
112 case PP_VARTYPE_DOUBLE: | |
113 return PP_MakeDouble(kDoubleValue); | |
114 case PP_VARTYPE_STRING: | |
115 return MakeString(kStringValue); | |
116 case PP_VARTYPE_OBJECT: | |
117 #ifndef PPAPI_INSTANCE_REMOVE_SCRIPTING | |
118 return g_instance_interface->GetWindowObject(g_instance_id); | |
119 #endif | |
120 case PP_VARTYPE_ARRAY: | |
121 case PP_VARTYPE_DICTIONARY: | |
122 break; | |
123 } | |
124 NACL_NOTREACHED(); | |
125 return PP_MakeUndefined(); | |
126 } | |
127 | |
128 // Checks that the var matches the canonical var for the specified type. | |
129 PP_Bool PropertyIsValidValue(PP_VarType type, PP_Var value) { | |
130 switch (type) { | |
131 case PP_VARTYPE_UNDEFINED: | |
132 return static_cast<PP_Bool>(value.type == PP_VARTYPE_UNDEFINED); | |
133 case PP_VARTYPE_NULL: | |
134 return static_cast<PP_Bool>(value.type == PP_VARTYPE_NULL); | |
135 case PP_VARTYPE_BOOL: | |
136 return static_cast<PP_Bool>((value.type == PP_VARTYPE_BOOL) && | |
137 (value.value.as_bool == kBoolValue)); | |
138 case PP_VARTYPE_INT32: | |
139 return static_cast<PP_Bool>((value.type == PP_VARTYPE_INT32) && | |
140 (value.value.as_int == kInt32Value)); | |
141 case PP_VARTYPE_DOUBLE: | |
142 return static_cast<PP_Bool>((value.type == PP_VARTYPE_DOUBLE) && | |
143 (value.value.as_double == kDoubleValue)); | |
144 case PP_VARTYPE_STRING: { | |
145 if (value.type != PP_VARTYPE_STRING) { | |
146 return PP_FALSE; | |
147 } | |
148 uint32_t ret_length; | |
149 const char* ret_str = g_var_interface->VarToUtf8(value, &ret_length); | |
150 if (ret_length == 0 || ret_str == NULL) { | |
151 return PP_FALSE; | |
152 } | |
153 return static_cast<PP_Bool>(strcmp(ret_str, kStringValue) == 0); | |
154 } | |
155 case PP_VARTYPE_OBJECT: { | |
156 // TODO(sehr,polina): check that the value is correct also. This is | |
157 // quite complicated with proxies-to-proxies at the moment. | |
158 return static_cast<PP_Bool>(value.type == PP_VARTYPE_OBJECT); | |
159 } | |
160 case PP_VARTYPE_ARRAY: | |
161 case PP_VARTYPE_DICTIONARY: | |
162 break; | |
163 } | |
164 return PP_FALSE; | |
165 } | |
166 | |
167 // Test that the "prop<Type>" property is present on object. | |
168 void CheckPresentProperty(PP_VarType type, PP_Var object) { | |
169 PP_Var exception = PP_MakeUndefined(); | |
170 // PropertyName always returns a string PP_Var that names a valid property. | |
171 CHECK(g_var_interface->HasProperty(object, PropertyName(type), &exception)); | |
172 CHECK(exception.type == PP_VARTYPE_UNDEFINED); | |
173 } | |
174 | |
175 void CheckAbsentProperty(PP_VarType type, PP_Var object) { | |
176 // PropertyValue returns a PP_Var of the requested type. Only when type | |
177 // == PP_VARTYPE_STRING can HasProperty succeed, and then only for valid | |
178 // property names. PropertyValue(PP_VARTYPE_STRING) returns a string | |
179 // that is not a valid property name. | |
180 PP_Var exception = PP_MakeUndefined(); | |
181 CHECK(!g_var_interface->HasProperty(object, | |
182 PropertyValue(type), | |
183 &exception)); | |
184 // TODO(sehr): Exception should be raised if type is not int or string. | |
185 CHECK(exception.type == PP_VARTYPE_UNDEFINED); | |
186 } | |
187 | |
188 void TestHasProperty(PP_Var object) { | |
189 CheckAbsentProperty(PP_VARTYPE_UNDEFINED, object); | |
190 CheckAbsentProperty(PP_VARTYPE_NULL, object); | |
191 CheckAbsentProperty(PP_VARTYPE_BOOL, object); | |
192 CheckAbsentProperty(PP_VARTYPE_INT32, object); | |
193 CheckAbsentProperty(PP_VARTYPE_DOUBLE, object); | |
194 CheckAbsentProperty(PP_VARTYPE_STRING, object); | |
195 CheckAbsentProperty(PP_VARTYPE_OBJECT, object); | |
196 CheckPresentProperty(PP_VARTYPE_UNDEFINED, object); | |
197 CheckPresentProperty(PP_VARTYPE_NULL, object); | |
198 CheckPresentProperty(PP_VARTYPE_BOOL, object); | |
199 CheckPresentProperty(PP_VARTYPE_INT32, object); | |
200 CheckPresentProperty(PP_VARTYPE_DOUBLE, object); | |
201 CheckPresentProperty(PP_VARTYPE_STRING, object); | |
202 CheckPresentProperty(PP_VARTYPE_OBJECT, object); | |
203 } | |
204 | |
205 // Test setting the "prop<Property_type>" method on object, passing a value of | |
206 // "value_type". | |
207 void CheckSetProperty(PP_VarType property_type, | |
208 PP_VarType value_type, | |
209 PP_Var object) { | |
210 PP_Var exception = PP_MakeUndefined(); | |
211 g_var_interface->SetProperty(object, | |
212 PropertyName(property_type), | |
213 PropertyValue(value_type), | |
214 &exception); | |
215 // Only setting an property to a value of it's intrinsic type should succeed. | |
216 // Success is indicated by the SetProperty returning a void exception. | |
217 if (property_type == value_type) { | |
218 CHECK(exception.type == PP_VARTYPE_UNDEFINED); | |
219 } else { | |
220 CHECK(exception.type != PP_VARTYPE_UNDEFINED); | |
221 } | |
222 } | |
223 | |
224 // Test setting one the "prop<Property_type>" property of object with all | |
225 // argument types. | |
226 void TestSetPropertyForType(PP_VarType property_type, PP_Var object) { | |
227 CheckSetProperty(property_type, PP_VARTYPE_UNDEFINED, object); | |
228 CheckSetProperty(property_type, PP_VARTYPE_NULL, object); | |
229 CheckSetProperty(property_type, PP_VARTYPE_BOOL, object); | |
230 CheckSetProperty(property_type, PP_VARTYPE_INT32, object); | |
231 CheckSetProperty(property_type, PP_VARTYPE_DOUBLE, object); | |
232 CheckSetProperty(property_type, PP_VARTYPE_STRING, object); | |
233 CheckSetProperty(property_type, PP_VARTYPE_OBJECT, object); | |
234 } | |
235 | |
236 // Test setting each type of property of object in succession. | |
237 // The values set in this function are used in TestGetProperty. | |
238 void TestSetProperty(PP_Var object) { | |
239 TestSetPropertyForType(PP_VARTYPE_UNDEFINED, object); | |
240 TestSetPropertyForType(PP_VARTYPE_NULL, object); | |
241 TestSetPropertyForType(PP_VARTYPE_BOOL, object); | |
242 TestSetPropertyForType(PP_VARTYPE_INT32, object); | |
243 TestSetPropertyForType(PP_VARTYPE_DOUBLE, object); | |
244 TestSetPropertyForType(PP_VARTYPE_STRING, object); | |
245 TestSetPropertyForType(PP_VARTYPE_OBJECT, object); | |
246 } | |
247 | |
248 // Invoke the GetProperty method on "object", passing the identifier | |
249 // for "property_type" and checking that the return value agrees in type | |
250 // and value. | |
251 void TestGetPropertyForType(PP_VarType property_type, PP_Var object) { | |
252 PP_Var exception = PP_MakeUndefined(); | |
253 PP_Var result = g_var_interface->GetProperty(object, | |
254 PropertyName(property_type), | |
255 &exception); | |
256 CHECK(PropertyIsValidValue(property_type, result)); | |
257 CHECK(exception.type == PP_VARTYPE_UNDEFINED); | |
258 } | |
259 | |
260 // Test getting each type of property of object in succession. | |
261 void TestGetProperty(PP_Var object) { | |
262 TestGetPropertyForType(PP_VARTYPE_UNDEFINED, object); | |
263 TestGetPropertyForType(PP_VARTYPE_NULL, object); | |
264 TestGetPropertyForType(PP_VARTYPE_BOOL, object); | |
265 TestGetPropertyForType(PP_VARTYPE_INT32, object); | |
266 TestGetPropertyForType(PP_VARTYPE_DOUBLE, object); | |
267 TestGetPropertyForType(PP_VARTYPE_STRING, object); | |
268 TestGetPropertyForType(PP_VARTYPE_OBJECT, object); | |
269 } | |
270 | |
271 // Invoke the "method2<Type>" method of object with values of types arg1_type | |
272 // and arg2_type as parameters. | |
273 void CheckCallWithArgPair(PP_VarType type, | |
274 PP_VarType arg1_type, | |
275 PP_VarType arg2_type, | |
276 PP_Var object) { | |
277 PP_Var argv[] = { PropertyValue(arg1_type), PropertyValue(arg2_type) }; | |
278 uint32_t argc = static_cast<uint32_t>(sizeof argv / sizeof argv[0]); | |
279 PP_Var exception = PP_MakeUndefined(); | |
280 PP_Var retval = g_var_interface->Call(object, | |
281 MethodNameWith2Args(type), | |
282 argc, | |
283 argv, | |
284 &exception); | |
285 // A successful call should return a var of "type" and exception should be | |
286 // void. A failing call's exception should be non-void. | |
287 if (type == arg1_type && type == arg2_type) { | |
288 CHECK(PropertyIsValidValue(type, retval)); | |
289 CHECK(exception.type == PP_VARTYPE_UNDEFINED); | |
290 } else { | |
291 CHECK(exception.type != PP_VARTYPE_UNDEFINED); | |
292 } | |
293 } | |
294 | |
295 // Invoke the "method<Type>" method of object with first argument type arg1_type | |
296 // and all possibilities of second argument type. | |
297 void TestCallForTypeWithArg1Type(PP_VarType type, | |
298 PP_VarType arg1_type, | |
299 PP_Var object) { | |
300 CheckCallWithArgPair(type, arg1_type, PP_VARTYPE_UNDEFINED, object); | |
301 CheckCallWithArgPair(type, arg1_type, PP_VARTYPE_NULL, object); | |
302 CheckCallWithArgPair(type, arg1_type, PP_VARTYPE_BOOL, object); | |
303 CheckCallWithArgPair(type, arg1_type, PP_VARTYPE_INT32, object); | |
304 CheckCallWithArgPair(type, arg1_type, PP_VARTYPE_DOUBLE, object); | |
305 CheckCallWithArgPair(type, arg1_type, PP_VARTYPE_STRING, object); | |
306 CheckCallWithArgPair(type, arg1_type, PP_VARTYPE_OBJECT, object); | |
307 } | |
308 | |
309 // Invoke the "method<Type>" method of object with one parameter of type "type". | |
310 void CallWithTooFewParameters(PP_VarType type, PP_Var object) { | |
311 PP_Var argv[] = { PropertyValue(type) }; | |
312 uint32_t argc = static_cast<uint32_t>(sizeof argv / sizeof argv[0]); | |
313 PP_Var exception = PP_MakeUndefined(); | |
314 (void) g_var_interface->Call(object, | |
315 MethodNameWith2Args(type), | |
316 argc, | |
317 argv, | |
318 &exception); | |
319 CHECK(exception.type != PP_VARTYPE_UNDEFINED); | |
320 } | |
321 | |
322 // Invoke the "method<Type>" method of object with three parameters of type | |
323 // "type". | |
324 void CallWithTooManyParameters(PP_VarType type, PP_Var object) { | |
325 PP_Var argv[] = { | |
326 PropertyValue(type), | |
327 PropertyValue(type), | |
328 PropertyValue(type) | |
329 }; | |
330 uint32_t argc = static_cast<uint32_t>(sizeof argv / sizeof argv[0]); | |
331 PP_Var exception = PP_MakeUndefined(); | |
332 (void) g_var_interface->Call(object, | |
333 MethodNameWith2Args(type), | |
334 argc, | |
335 argv, | |
336 &exception); | |
337 CHECK(exception.type != PP_VARTYPE_UNDEFINED); | |
338 } | |
339 | |
340 // Invoke the "method<Type>" method of object with all combinations of types for | |
341 // the first and second arguments. | |
342 void TestCallForType(PP_VarType method_type, PP_Var object) { | |
343 CallWithTooFewParameters(method_type, object); | |
344 CallWithTooManyParameters(method_type, object); | |
345 // Try with various parameter type combinations. | |
346 TestCallForTypeWithArg1Type(method_type, PP_VARTYPE_UNDEFINED, object); | |
347 TestCallForTypeWithArg1Type(method_type, PP_VARTYPE_NULL, object); | |
348 TestCallForTypeWithArg1Type(method_type, PP_VARTYPE_BOOL, object); | |
349 TestCallForTypeWithArg1Type(method_type, PP_VARTYPE_INT32, object); | |
350 TestCallForTypeWithArg1Type(method_type, PP_VARTYPE_DOUBLE, object); | |
351 TestCallForTypeWithArg1Type(method_type, PP_VARTYPE_STRING, object); | |
352 TestCallForTypeWithArg1Type(method_type, PP_VARTYPE_OBJECT, object); | |
353 } | |
354 | |
355 // Test invoking each method of object in succession. | |
356 void TestCall(PP_Var object) { | |
357 TestCallForType(PP_VARTYPE_UNDEFINED, object); | |
358 TestCallForType(PP_VARTYPE_NULL, object); | |
359 TestCallForType(PP_VARTYPE_BOOL, object); | |
360 TestCallForType(PP_VARTYPE_INT32, object); | |
361 TestCallForType(PP_VARTYPE_DOUBLE, object); | |
362 TestCallForType(PP_VARTYPE_STRING, object); | |
363 TestCallForType(PP_VARTYPE_OBJECT, object); | |
364 } | |
365 | |
366 // Test calling a that scripts the object passed into it. This is the | |
367 // beginning of a test of NaCl to browser scripting. | |
368 void TestWindowScripting(PP_Var object) { | |
369 PP_Var argv = PropertyValue(PP_VARTYPE_OBJECT); | |
370 PP_Var exception = PP_MakeUndefined(); | |
371 PP_Var retval = g_var_interface->Call(object, | |
372 MakeString("windowLocation"), | |
373 1, | |
374 &argv, | |
375 &exception); | |
376 CHECK(PropertyIsValidValue(PP_VARTYPE_BOOL, retval)); | |
377 CHECK(exception.type == PP_VARTYPE_UNDEFINED); | |
378 } | |
379 | |
380 } // namespace | |
381 | |
382 // Called from the fake browser. The object needs to have certain | |
383 // attributes. For each PP_VARTYPE variant, | |
384 // 1) There is a property, of PP_VARTYPE_<TYPE>, named "prop<Type>". | |
385 // 2) SetProperty("prop<Type>", value) only succeeds when value.type == type. | |
386 // 3) GetProperty("prop<Type>") only succeeds when value.type == type, | |
387 // and returns the value set by the corresponding call to SetProperty. | |
388 // 4) Call("prop<Type>", { arg1, arg2 }) only succeeds when arg1.type == type, | |
389 // arg2.type == type. It returns arg1.type. | |
390 void TestScriptableObject(PP_Var object, | |
391 const PPB_Instance* browser_instance_interface, | |
392 const PPB_Var_Deprecated* var_interface, | |
393 PP_Instance instance_id, | |
394 PP_Module browser_module_id) { | |
395 // Receiver needs to be a valid scriptable object. We cannot use | |
396 // is_valid_value here because we haven't set g_object_as_id yet. | |
397 CHECK(object.type == PP_VARTYPE_OBJECT); | |
398 // Save g_object_as_id for future object value validity checks. | |
399 g_object_as_id = object.value.as_id; | |
400 // Initialize the global state. | |
401 g_var_interface = var_interface; | |
402 g_instance_interface = browser_instance_interface; | |
403 g_instance_id = instance_id; | |
404 g_browser_module_id = browser_module_id; | |
405 // And test the scriptable object interfaces one-by-one. | |
406 TestHasProperty(object); | |
407 TestSetProperty(object); | |
408 TestGetProperty(object); | |
409 TestCall(object); | |
410 TestWindowScripting(object); | |
411 // TODO(sehr,polina): add other methods such as RemoveProperty. | |
412 } | |
OLD | NEW |