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