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