Home | History | Annotate | Download | only in renderer
      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 
     14 using WebKit::WebBindings;
     15 using 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.
     19 void 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.
     31 void 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.
     40 void 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 
     47 int g_allocate_call_count = 0;
     48 int g_deallocate_call_count = 0;
     49 
     50 void 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 
     58 NPObject* 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 
     67 void 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 
     75 static NPClass void_class = { NP_CLASS_STRUCT_VERSION,
     76                               MockNPAllocate,
     77                               MockNPDeallocate,
     78                               0, 0, 0, 0, 0, 0, 0, 0, 0 };
     79 
     80 class CppVariantTest : public testing::Test {
     81 public:
     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 
    101 private:
    102   scoped_ptr<struct _NPP> npp_;
    103 };
    104 
    105 TEST_F(CppVariantTest, NewVariantHasNullType) {
    106   CppVariant value;
    107   EXPECT_EQ(NPVariantType_Null, value.type);
    108 }
    109 
    110 TEST_F(CppVariantTest, SetNullSetsType) {
    111   CppVariant value;
    112   value.Set(17);
    113   value.SetNull();
    114   EXPECT_EQ(NPVariantType_Null, value.type);
    115 }
    116 
    117 TEST_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 
    131 TEST_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 
    146 TEST_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 
    161 TEST_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 
    178 TEST_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 
    197 TEST_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 
    238 TEST_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 
    296 TEST_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 
    342 TEST_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 
    351 TEST_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 
    367 TEST_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 
    452 bool MockNPHasPropertyFunction(NPObject *npobj, NPIdentifier name) {
    453   return true;
    454 }
    455 
    456 bool 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 
    477 TEST_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