| 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 |