Home | History | Annotate | Download | only in glue
      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