1 // Copyright (c) 2011 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 <vector> 6 7 #include "base/compiler_specific.h" 8 #include "base/string_util.h" 9 #include "testing/gtest/include/gtest/gtest.h" 10 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" 11 #include "webkit/glue/cpp_variant.h" 12 13 using WebKit::WebBindings; 14 15 // Creates a std::string from an NPVariant of string type. If the NPVariant 16 // is not a string, empties the std::string. 17 void MakeStdString(const NPVariant& np, std::string* std_string) { 18 if (np.type == NPVariantType_String) { 19 const char* chars = 20 reinterpret_cast<const char*>(np.value.stringValue.UTF8Characters); 21 (*std_string).assign(chars, np.value.stringValue.UTF8Length); 22 } else { 23 (*std_string).clear(); 24 } 25 } 26 27 // Verifies that the actual NPVariant is a string and that its value matches 28 // the expected_str. 29 void CheckString(const std::string& expected_str, const NPVariant& actual) { 30 EXPECT_EQ(NPVariantType_String, actual.type); 31 std::string actual_str; 32 MakeStdString(actual, &actual_str); 33 EXPECT_EQ(expected_str, actual_str); 34 } 35 36 // Verifies that both the actual and the expected NPVariants are strings and 37 // that their values match. 38 void CheckString(const NPVariant& expected, const NPVariant& actual) { 39 EXPECT_EQ(NPVariantType_String, expected.type); 40 std::string expected_str; 41 MakeStdString(expected, &expected_str); 42 CheckString(expected_str, actual); 43 } 44 45 int g_allocate_call_count = 0; 46 int g_deallocate_call_count = 0; 47 48 void CheckObject(const NPVariant& actual) { 49 EXPECT_EQ(NPVariantType_Object, actual.type); 50 EXPECT_TRUE(actual.value.objectValue); 51 EXPECT_EQ(1U, actual.value.objectValue->referenceCount); 52 EXPECT_EQ(1, g_allocate_call_count); 53 EXPECT_EQ(0, g_deallocate_call_count); 54 } 55 56 NPObject* MockNPAllocate(NPP npp, NPClass* aClass) { 57 // This is a mock allocate method that mimics the behavior 58 // of WebBindings::createObject when allocate() is NULL 59 60 ++g_allocate_call_count; 61 // Ignore npp and NPClass 62 return reinterpret_cast<NPObject*>(malloc(sizeof(NPObject))); 63 } 64 65 void MockNPDeallocate(NPObject* npobj) { 66 // This is a mock deallocate method that mimics the behavior 67 // of NPN_DeallocateObject when deallocate() is NULL 68 69 ++g_deallocate_call_count; 70 free(npobj); 71 } 72 73 static NPClass void_class = { NP_CLASS_STRUCT_VERSION, 74 MockNPAllocate, 75 MockNPDeallocate, 76 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 77 78 NPObject* MakeVoidObject() { 79 g_allocate_call_count = 0; 80 g_deallocate_call_count = 0; 81 return WebBindings::createObject(NULL, &void_class); 82 } 83 84 TEST(CppVariantTest, NewVariantHasNullType) { 85 CppVariant value; 86 EXPECT_EQ(NPVariantType_Null, value.type); 87 } 88 89 TEST(CppVariantTest, SetNullSetsType) { 90 CppVariant value; 91 value.Set(17); 92 value.SetNull(); 93 EXPECT_EQ(NPVariantType_Null, value.type); 94 } 95 96 TEST(CppVariantTest, CopyConstructorDoesDeepCopy) { 97 CppVariant source; 98 source.Set("test string"); 99 CppVariant dest = source; 100 EXPECT_EQ(NPVariantType_String, dest.type); 101 EXPECT_EQ(NPVariantType_String, source.type); 102 103 // Ensure that the string was copied, not just the pointer. 104 EXPECT_NE(source.value.stringValue.UTF8Characters, 105 dest.value.stringValue.UTF8Characters); 106 107 CheckString(source, dest); 108 } 109 110 TEST(CppVariantTest, CopyConstructorIncrementsRefCount) { 111 CppVariant source; 112 NPObject *object = MakeVoidObject(); 113 source.Set(object); 114 // 2 references so far. 115 EXPECT_EQ(2U, source.value.objectValue->referenceCount); 116 117 CppVariant dest = source; 118 EXPECT_EQ(3U, dest.value.objectValue->referenceCount); 119 EXPECT_EQ(1, g_allocate_call_count); 120 WebBindings::releaseObject(object); 121 source.SetNull(); 122 CheckObject(dest); 123 } 124 125 TEST(CppVariantTest, AssignmentDoesDeepCopy) { 126 CppVariant source; 127 source.Set("test string"); 128 CppVariant dest; 129 dest = source; 130 EXPECT_EQ(NPVariantType_String, dest.type); 131 EXPECT_EQ(NPVariantType_String, source.type); 132 133 // Ensure that the string was copied, not just the pointer. 134 EXPECT_NE(source.value.stringValue.UTF8Characters, 135 dest.value.stringValue.UTF8Characters); 136 137 CheckString(source, dest); 138 } 139 140 TEST(CppVariantTest, AssignmentIncrementsRefCount) { 141 CppVariant source; 142 NPObject *object = MakeVoidObject(); 143 source.Set(object); 144 // 2 references so far. 145 EXPECT_EQ(2U, source.value.objectValue->referenceCount); 146 147 CppVariant dest; 148 dest = source; 149 EXPECT_EQ(3U, dest.value.objectValue->referenceCount); 150 EXPECT_EQ(1, g_allocate_call_count); 151 152 WebBindings::releaseObject(object); 153 source.SetNull(); 154 CheckObject(dest); 155 } 156 157 TEST(CppVariantTest, DestroyingCopyDoesNotCorruptSource) { 158 CppVariant source; 159 source.Set("test string"); 160 std::string before; 161 MakeStdString(source, &before); 162 { 163 CppVariant dest = source; 164 } 165 CheckString(before, source); 166 167 NPObject *object = MakeVoidObject(); 168 source.Set(object); 169 { 170 CppVariant dest2 = source; 171 } 172 WebBindings::releaseObject(object); 173 CheckObject(source); 174 } 175 176 TEST(CppVariantTest, CopiesTypeAndValueToNPVariant) { 177 NPVariant np; 178 CppVariant cpp; 179 180 cpp.Set(true); 181 cpp.CopyToNPVariant(&np); 182 EXPECT_EQ(cpp.type, np.type); 183 EXPECT_EQ(cpp.value.boolValue, np.value.boolValue); 184 WebBindings::releaseVariantValue(&np); 185 186 cpp.Set(17); 187 cpp.CopyToNPVariant(&np); 188 EXPECT_EQ(cpp.type, np.type); 189 EXPECT_EQ(cpp.value.intValue, np.value.intValue); 190 WebBindings::releaseVariantValue(&np); 191 192 cpp.Set(3.1415); 193 cpp.CopyToNPVariant(&np); 194 EXPECT_EQ(cpp.type, np.type); 195 EXPECT_EQ(cpp.value.doubleValue, np.value.doubleValue); 196 WebBindings::releaseVariantValue(&np); 197 198 cpp.Set("test value"); 199 cpp.CopyToNPVariant(&np); 200 CheckString("test value", np); 201 WebBindings::releaseVariantValue(&np); 202 203 cpp.SetNull(); 204 cpp.CopyToNPVariant(&np); 205 EXPECT_EQ(cpp.type, np.type); 206 WebBindings::releaseVariantValue(&np); 207 208 NPObject *object = MakeVoidObject(); 209 cpp.Set(object); 210 cpp.CopyToNPVariant(&np); 211 WebBindings::releaseObject(object); 212 cpp.SetNull(); 213 CheckObject(np); 214 WebBindings::releaseVariantValue(&np); 215 } 216 217 TEST(CppVariantTest, SetsTypeAndValueFromNPVariant) { 218 NPVariant np; 219 CppVariant cpp; 220 221 VOID_TO_NPVARIANT(np); 222 cpp.Set(np); 223 EXPECT_EQ(np.type, cpp.type); 224 WebBindings::releaseVariantValue(&np); 225 226 NULL_TO_NPVARIANT(np); 227 cpp.Set(np); 228 EXPECT_EQ(np.type, cpp.type); 229 WebBindings::releaseVariantValue(&np); 230 231 BOOLEAN_TO_NPVARIANT(true, np); 232 cpp.Set(np); 233 EXPECT_EQ(np.type, cpp.type); 234 EXPECT_EQ(np.value.boolValue, cpp.value.boolValue); 235 WebBindings::releaseVariantValue(&np); 236 237 INT32_TO_NPVARIANT(15, np); 238 cpp.Set(np); 239 EXPECT_EQ(np.type, cpp.type); 240 EXPECT_EQ(np.value.intValue, cpp.value.intValue); 241 WebBindings::releaseVariantValue(&np); 242 243 DOUBLE_TO_NPVARIANT(2.71828, np); 244 cpp.Set(np); 245 EXPECT_EQ(np.type, cpp.type); 246 EXPECT_EQ(np.value.doubleValue, cpp.value.doubleValue); 247 WebBindings::releaseVariantValue(&np); 248 249 NPString np_ascii_str = { "1st test value", 250 static_cast<uint32_t>(strlen("1st test value")) }; 251 WebBindings::initializeVariantWithStringCopy(&np, &np_ascii_str); 252 cpp.Set(np); 253 CheckString("1st test value", cpp); 254 WebBindings::releaseVariantValue(&np); 255 256 // Test characters represented in 2/3/4 bytes in UTF-8 257 // Greek alpha, Chinese number 1 (horizontal bar), 258 // Deseret letter (similar to 'O') 259 NPString np_intl_str = { "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84", 260 static_cast<uint32_t>(strlen( 261 "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84")) }; 262 WebBindings::initializeVariantWithStringCopy(&np, &np_intl_str); 263 cpp.Set(np); 264 CheckString("\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84", cpp); 265 WebBindings::releaseVariantValue(&np); 266 267 NPObject *obj = MakeVoidObject(); 268 OBJECT_TO_NPVARIANT(obj, np); // Doesn't make a copy. 269 cpp.Set(np); 270 // Use this or WebBindings::releaseObject but NOT both. 271 WebBindings::releaseVariantValue(&np); 272 CheckObject(cpp); 273 } 274 275 TEST(CppVariantTest, SetsSimpleTypesAndValues) { 276 CppVariant cpp; 277 cpp.Set(true); 278 EXPECT_EQ(NPVariantType_Bool, cpp.type); 279 EXPECT_TRUE(cpp.value.boolValue); 280 281 cpp.Set(5); 282 EXPECT_EQ(NPVariantType_Int32, cpp.type); 283 EXPECT_EQ(5, cpp.value.intValue); 284 285 cpp.Set(1.234); 286 EXPECT_EQ(NPVariantType_Double, cpp.type); 287 EXPECT_EQ(1.234, cpp.value.doubleValue); 288 289 // C string 290 cpp.Set("1st test string"); 291 CheckString("1st test string", cpp); 292 293 // std::string 294 std::string source("std test string"); 295 cpp.Set(source); 296 CheckString("std test string", cpp); 297 298 // NPString 299 NPString np_ascii_str = { "test NPString", 300 static_cast<uint32_t>(strlen("test NPString")) }; 301 cpp.Set(np_ascii_str); 302 std::string expected("test NPString"); 303 CheckString(expected, cpp); 304 305 // Test characters represented in 2/3/4 bytes in UTF-8 306 // Greek alpha, Chinese number 1 (horizontal bar), 307 // Deseret letter (similar to 'O') 308 NPString np_intl_str = { "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84", 309 static_cast<uint32_t>(strlen( 310 "\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84")) }; 311 cpp.Set(np_intl_str); 312 expected = std::string("\xce\xb1\xe4\xb8\x80\xf0\x90\x90\x84"); 313 CheckString(expected, cpp); 314 315 NPObject* obj = MakeVoidObject(); 316 cpp.Set(obj); 317 WebBindings::releaseObject(obj); 318 CheckObject(cpp); 319 } 320 321 TEST(CppVariantTest, FreeDataSetsToVoid) { 322 CppVariant cpp; 323 EXPECT_EQ(NPVariantType_Null, cpp.type); 324 cpp.Set(12); 325 EXPECT_EQ(NPVariantType_Int32, cpp.type); 326 cpp.FreeData(); 327 EXPECT_EQ(NPVariantType_Void, cpp.type); 328 } 329 330 TEST(CppVariantTest, FreeDataReleasesObject) { 331 CppVariant cpp; 332 NPObject* object = MakeVoidObject(); 333 cpp.Set(object); 334 EXPECT_EQ(2U, object->referenceCount); 335 cpp.FreeData(); 336 EXPECT_EQ(1U, object->referenceCount); 337 EXPECT_EQ(0, g_deallocate_call_count); 338 339 cpp.Set(object); 340 WebBindings::releaseObject(object); 341 EXPECT_EQ(0, g_deallocate_call_count); 342 cpp.FreeData(); 343 EXPECT_EQ(1, g_deallocate_call_count); 344 } 345 346 TEST(CppVariantTest, IsTypeFunctionsWork) { 347 CppVariant cpp; 348 // These should not happen in practice, since voids are not supported 349 // This test must be first since it just clobbers internal data without 350 // releasing. 351 VOID_TO_NPVARIANT(cpp); 352 EXPECT_FALSE(cpp.isBool()); 353 EXPECT_FALSE(cpp.isInt32()); 354 EXPECT_FALSE(cpp.isDouble()); 355 EXPECT_FALSE(cpp.isNumber()); 356 EXPECT_FALSE(cpp.isString()); 357 EXPECT_TRUE(cpp.isVoid()); 358 EXPECT_FALSE(cpp.isNull()); 359 EXPECT_TRUE(cpp.isEmpty()); 360 361 cpp.Set(true); 362 EXPECT_TRUE(cpp.isBool()); 363 EXPECT_FALSE(cpp.isInt32()); 364 EXPECT_FALSE(cpp.isDouble()); 365 EXPECT_FALSE(cpp.isNumber()); 366 EXPECT_FALSE(cpp.isString()); 367 EXPECT_FALSE(cpp.isVoid()); 368 EXPECT_FALSE(cpp.isNull()); 369 EXPECT_FALSE(cpp.isEmpty()); 370 EXPECT_FALSE(cpp.isObject()); 371 372 cpp.Set(12); 373 EXPECT_FALSE(cpp.isBool()); 374 EXPECT_TRUE(cpp.isInt32()); 375 EXPECT_FALSE(cpp.isDouble()); 376 EXPECT_TRUE(cpp.isNumber()); 377 EXPECT_FALSE(cpp.isString()); 378 EXPECT_FALSE(cpp.isVoid()); 379 EXPECT_FALSE(cpp.isNull()); 380 EXPECT_FALSE(cpp.isEmpty()); 381 EXPECT_FALSE(cpp.isObject()); 382 383 cpp.Set(3.1415); 384 EXPECT_FALSE(cpp.isBool()); 385 EXPECT_FALSE(cpp.isInt32()); 386 EXPECT_TRUE(cpp.isDouble()); 387 EXPECT_TRUE(cpp.isNumber()); 388 EXPECT_FALSE(cpp.isString()); 389 EXPECT_FALSE(cpp.isVoid()); 390 EXPECT_FALSE(cpp.isNull()); 391 EXPECT_FALSE(cpp.isEmpty()); 392 EXPECT_FALSE(cpp.isObject()); 393 394 cpp.Set("a string"); 395 EXPECT_FALSE(cpp.isBool()); 396 EXPECT_FALSE(cpp.isInt32()); 397 EXPECT_FALSE(cpp.isDouble()); 398 EXPECT_FALSE(cpp.isNumber()); 399 EXPECT_TRUE(cpp.isString()); 400 EXPECT_FALSE(cpp.isVoid()); 401 EXPECT_FALSE(cpp.isNull()); 402 EXPECT_FALSE(cpp.isEmpty()); 403 EXPECT_FALSE(cpp.isObject()); 404 405 cpp.SetNull(); 406 EXPECT_FALSE(cpp.isBool()); 407 EXPECT_FALSE(cpp.isInt32()); 408 EXPECT_FALSE(cpp.isDouble()); 409 EXPECT_FALSE(cpp.isNumber()); 410 EXPECT_FALSE(cpp.isString()); 411 EXPECT_FALSE(cpp.isVoid()); 412 EXPECT_TRUE(cpp.isNull()); 413 EXPECT_TRUE(cpp.isEmpty()); 414 EXPECT_FALSE(cpp.isObject()); 415 416 NPObject *obj = MakeVoidObject(); 417 cpp.Set(obj); 418 EXPECT_FALSE(cpp.isBool()); 419 EXPECT_FALSE(cpp.isInt32()); 420 EXPECT_FALSE(cpp.isDouble()); 421 EXPECT_FALSE(cpp.isNumber()); 422 EXPECT_FALSE(cpp.isString()); 423 EXPECT_FALSE(cpp.isVoid()); 424 EXPECT_FALSE(cpp.isNull()); 425 EXPECT_FALSE(cpp.isEmpty()); 426 EXPECT_TRUE(cpp.isObject()); 427 WebBindings::releaseObject(obj); 428 CheckObject(cpp); 429 } 430 431 bool MockNPHasPropertyFunction(NPObject *npobj, NPIdentifier name) { 432 return true; 433 } 434 435 bool MockNPGetPropertyFunction(NPObject *npobj, NPIdentifier name, 436 NPVariant *result) { 437 if (WebBindings::getStringIdentifier("length") == name) { 438 DOUBLE_TO_NPVARIANT(4, *result); 439 } else if (WebBindings::getIntIdentifier(0) == name) { 440 DOUBLE_TO_NPVARIANT(0, *result); 441 } else if (WebBindings::getIntIdentifier(1) == name) { 442 BOOLEAN_TO_NPVARIANT(true, *result); 443 } else if (WebBindings::getIntIdentifier(2) == name) { 444 NULL_TO_NPVARIANT(*result); 445 } else if (WebBindings::getIntIdentifier(3) == name) { 446 const char* s = "string"; 447 size_t length = strlen(s); 448 char* mem = static_cast<char*>(malloc(length + 1)); 449 base::strlcpy(mem, s, length + 1); 450 STRINGZ_TO_NPVARIANT(mem, *result); 451 } 452 453 return true; 454 } 455 456 TEST(CppVariantTest, ToVector) { 457 NPClass array_like_class = { 458 NP_CLASS_STRUCT_VERSION, 459 0, // NPAllocateFunctionPtr allocate; 460 0, // NPDeallocateFunctionPtr deallocate; 461 0, // NPInvalidateFunctionPtr invalidate; 462 0, // NPHasMethodFunctionPtr hasMethod; 463 0, // NPInvokeFunctionPtr invoke; 464 0, // NPInvokeDefaultFunctionPtr invokeDefault; 465 MockNPHasPropertyFunction, // NPHasPropertyFunctionPtr hasProperty; 466 MockNPGetPropertyFunction, // NPGetPropertyFunctionPtr getProperty; 467 0, // NPSetPropertyFunctionPtr setProperty; 468 0, // NPRemovePropertyFunctionPtr removeProperty; 469 0, // NPEnumerationFunctionPtr enumerate; 470 0 // NPConstructFunctionPtr construct; 471 }; 472 473 NPObject* obj = WebBindings::createObject(NULL, &array_like_class); 474 475 CppVariant cpp; 476 cpp.Set(obj); 477 478 std::vector<CppVariant> cpp_vector = cpp.ToVector(); 479 EXPECT_EQ(4u, cpp_vector.size()); 480 481 EXPECT_TRUE(cpp_vector[0].isDouble()); 482 EXPECT_EQ(0, cpp_vector[0].ToDouble()); 483 484 EXPECT_TRUE(cpp_vector[1].isBool()); 485 EXPECT_EQ(true, cpp_vector[1].ToBoolean()); 486 487 EXPECT_TRUE(cpp_vector[2].isNull()); 488 489 EXPECT_TRUE(cpp_vector[3].isString()); 490 CheckString("string", cpp_vector[3]); 491 492 WebBindings::releaseObject(obj); 493 } 494