Home | History | Annotate | Download | only in tests
      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 "ppapi/tests/test_var_deprecated.h"
      6 
      7 #include <string.h>
      8 
      9 #include <limits>
     10 
     11 #include "ppapi/c/pp_var.h"
     12 #include "ppapi/c/dev/ppb_testing_dev.h"
     13 #include "ppapi/c/dev/ppb_var_deprecated.h"
     14 #include "ppapi/cpp/dev/scriptable_object_deprecated.h"
     15 #include "ppapi/cpp/instance.h"
     16 #include "ppapi/cpp/module.h"
     17 #include "ppapi/cpp/private/var_private.h"
     18 #include "ppapi/cpp/var.h"
     19 #include "ppapi/tests/testing_instance.h"
     20 
     21 namespace {
     22 
     23 uint32_t kInvalidLength = static_cast<uint32_t>(-1);
     24 
     25 static const char kSetValueFunction[] = "SetValue";
     26 
     27 // ScriptableObject used by the var tests.
     28 class VarScriptableObject : public pp::deprecated::ScriptableObject {
     29  public:
     30   VarScriptableObject(TestVarDeprecated* v) : test_var_deprecated_(v) {}
     31 
     32   // pp::deprecated::ScriptableObject overrides.
     33   bool HasMethod(const pp::Var& name, pp::Var* exception);
     34   pp::Var Call(const pp::Var& name,
     35                const std::vector<pp::Var>& args,
     36                pp::Var* exception);
     37 
     38  private:
     39   TestVarDeprecated* test_var_deprecated_;
     40 };
     41 
     42 bool VarScriptableObject::HasMethod(const pp::Var& name, pp::Var* exception) {
     43   if (!name.is_string())
     44     return false;
     45   return name.AsString() == kSetValueFunction;
     46 }
     47 
     48 pp::Var VarScriptableObject::Call(const pp::Var& method_name,
     49                                   const std::vector<pp::Var>& args,
     50                                   pp::Var* exception) {
     51   if (!method_name.is_string())
     52     return false;
     53   std::string name = method_name.AsString();
     54 
     55   if (name == kSetValueFunction) {
     56     if (args.size() != 1)
     57       *exception = pp::Var("Bad argument to SetValue(<value>)");
     58     else
     59       test_var_deprecated_->set_var_from_page(pp::VarPrivate(args[0]));
     60   }
     61 
     62   return pp::Var();
     63 }
     64 
     65 }  // namespace
     66 
     67 REGISTER_TEST_CASE(VarDeprecated);
     68 
     69 bool TestVarDeprecated::Init() {
     70   var_interface_ = static_cast<const PPB_Var_Deprecated*>(
     71       pp::Module::Get()->GetBrowserInterface(PPB_VAR_DEPRECATED_INTERFACE));
     72   return var_interface_ && CheckTestingInterface();
     73 }
     74 
     75 void TestVarDeprecated::RunTests(const std::string& filter) {
     76   RUN_TEST(BasicString, filter);
     77   RUN_TEST(InvalidAndEmpty, filter);
     78   RUN_TEST(InvalidUtf8, filter);
     79   RUN_TEST(NullInputInUtf8Conversion, filter);
     80   RUN_TEST(ValidUtf8, filter);
     81   RUN_TEST(Utf8WithEmbeddedNulls, filter);
     82   RUN_TEST(VarToUtf8ForWrongType, filter);
     83   RUN_TEST(HasPropertyAndMethod, filter);
     84   RUN_TEST(PassReference, filter);
     85 }
     86 
     87 pp::deprecated::ScriptableObject* TestVarDeprecated::CreateTestObject() {
     88   return new VarScriptableObject(this);
     89 }
     90 
     91 std::string TestVarDeprecated::TestBasicString() {
     92   uint32_t before_object = testing_interface_->GetLiveObjectsForInstance(
     93       instance_->pp_instance());
     94   {
     95     const char kStr[] = "Hello";
     96     const uint32_t kStrLen(sizeof(kStr) - 1);
     97     PP_Var str = var_interface_->VarFromUtf8(pp::Module::Get()->pp_module(),
     98                                              kStr, kStrLen);
     99     ASSERT_EQ(PP_VARTYPE_STRING, str.type);
    100 
    101     // Reading back the string should work.
    102     uint32_t len = 0;
    103     const char* result = var_interface_->VarToUtf8(str, &len);
    104     ASSERT_EQ(kStrLen, len);
    105     ASSERT_EQ(0, strncmp(kStr, result, kStrLen));
    106 
    107     // Destroy the string, readback should now fail.
    108     var_interface_->Release(str);
    109     result = var_interface_->VarToUtf8(str, &len);
    110     ASSERT_EQ(0, len);
    111     ASSERT_EQ(NULL, result);
    112   }
    113 
    114   // Make sure nothing leaked.
    115   ASSERT_TRUE(testing_interface_->GetLiveObjectsForInstance(
    116       instance_->pp_instance()) == before_object);
    117 
    118   PASS();
    119 }
    120 
    121 std::string TestVarDeprecated::TestInvalidAndEmpty() {
    122   PP_Var invalid_string;
    123   invalid_string.type = PP_VARTYPE_STRING;
    124   invalid_string.value.as_id = 31415926;
    125 
    126   // Invalid strings should give NULL as the return value.
    127   uint32_t len = std::numeric_limits<uint32_t>::max();
    128   const char* result = var_interface_->VarToUtf8(invalid_string, &len);
    129   ASSERT_EQ(0, len);
    130   ASSERT_EQ(NULL, result);
    131 
    132   // Same with vars that are not strings.
    133   len = std::numeric_limits<uint32_t>::max();
    134   pp::Var int_var(42);
    135   result = var_interface_->VarToUtf8(int_var.pp_var(), &len);
    136   ASSERT_EQ(0, len);
    137   ASSERT_EQ(NULL, result);
    138 
    139   // Empty strings should return non-NULL.
    140   pp::Var empty_string("");
    141   len = std::numeric_limits<uint32_t>::max();
    142   result = var_interface_->VarToUtf8(empty_string.pp_var(), &len);
    143   ASSERT_EQ(0, len);
    144   ASSERT_NE(NULL, result);
    145 
    146   PASS();
    147 }
    148 
    149 std::string TestVarDeprecated::TestInvalidUtf8() {
    150   // utf8 (japanese for "is not utf8") in shift-jis encoding.
    151   static const char kSjisString[] = "utf8\x82\xb6\x82\xe1\x82\xc8\x82\xa2";
    152   pp::Var sjis(kSjisString);
    153   if (!sjis.is_null())
    154     return "Non-UTF8 string was permitted erroneously.";
    155 
    156   PASS();
    157 }
    158 
    159 std::string TestVarDeprecated::TestNullInputInUtf8Conversion() {
    160   // This test talks directly to the C interface to access edge cases that
    161   // cannot be exercised via the C++ interface.
    162   PP_Var converted_string;
    163 
    164   // 0-length string should not dereference input string, and should produce
    165   // an empty string.
    166   converted_string = var_interface_->VarFromUtf8(
    167       pp::Module::Get()->pp_module(), NULL, 0);
    168   if (converted_string.type != PP_VARTYPE_STRING) {
    169     return "Expected 0 length to return empty string.";
    170   }
    171 
    172   // Now convert it back.
    173   uint32_t length = kInvalidLength;
    174   const char* result = NULL;
    175   result = var_interface_->VarToUtf8(converted_string, &length);
    176   if (length != 0) {
    177     return "Expected 0 length string on conversion.";
    178   }
    179   if (result == NULL) {
    180     return "Expected a non-null result for 0-lengthed string from VarToUtf8.";
    181   }
    182   var_interface_->Release(converted_string);
    183 
    184   // Should not crash, and make an empty string.
    185   const char* null_string = NULL;
    186   pp::Var null_var(null_string);
    187   if (!null_var.is_string() || null_var.AsString() != "") {
    188     return "Expected NULL input to make an empty string Var.";
    189   }
    190 
    191   PASS();
    192 }
    193 
    194 std::string TestVarDeprecated::TestValidUtf8() {
    195   // From UTF8 string -> PP_Var.
    196   // Chinese for "I am utf8."
    197   static const char kValidUtf8[] = "\xe6\x88\x91\xe6\x98\xafutf8.";
    198   pp::Var converted_string(kValidUtf8);
    199 
    200   if (converted_string.is_null())
    201     return "Unable to convert valid utf8 to var.";
    202 
    203   // Since we're already here, test PP_Var back to UTF8 string.
    204   std::string returned_string = converted_string.AsString();
    205 
    206   // We need to check against 1 less than sizeof because the resulting string
    207   // is technically not NULL terminated by API design.
    208   if (returned_string.size() != sizeof(kValidUtf8) - 1) {
    209     return "Unable to convert utf8 string back from var.";
    210   }
    211   if (returned_string != kValidUtf8) {
    212     return "String mismatches on conversion back from PP_Var.";
    213   }
    214 
    215   PASS();
    216 }
    217 
    218 std::string TestVarDeprecated::TestUtf8WithEmbeddedNulls() {
    219   // From UTF8 string with embedded nulls -> PP_Var.
    220   // Chinese for "also utf8."
    221   static const char kUtf8WithEmbededNull[] = "\xe6\xb9\x9f\xe6\x98\xaf\0utf8.";
    222   std::string orig_string(kUtf8WithEmbededNull,
    223                           sizeof(kUtf8WithEmbededNull) -1);
    224   pp::Var converted_string(orig_string);
    225 
    226   if (converted_string.is_null())
    227     return "Unable to convert utf8 with embedded nulls to var.";
    228 
    229   // Since we're already here, test PP_Var back to UTF8 string.
    230   std::string returned_string = converted_string.AsString();
    231 
    232   if (returned_string.size() != orig_string.size()) {
    233     return "Unable to convert utf8 with embedded nulls back from var.";
    234   }
    235   if (returned_string != orig_string) {
    236     return "String mismatches on conversion back from PP_Var.";
    237   }
    238 
    239   PASS();
    240 }
    241 
    242 std::string TestVarDeprecated::TestVarToUtf8ForWrongType() {
    243   uint32_t length = kInvalidLength;
    244   const char* result = NULL;
    245   result = var_interface_->VarToUtf8(PP_MakeUndefined(), &length);
    246   if (length != 0) {
    247     return "Expected 0 on string conversion from Void var.";
    248   }
    249   if (result != NULL) {
    250     return "Expected NULL on string conversion from Void var.";
    251   }
    252 
    253   length = kInvalidLength;
    254   result = NULL;
    255   result = var_interface_->VarToUtf8(PP_MakeNull(), &length);
    256   if (length != 0) {
    257     return "Expected 0 on string conversion from Null var.";
    258   }
    259   if (result != NULL) {
    260     return "Expected NULL on string conversion from Null var.";
    261   }
    262 
    263   length = kInvalidLength;
    264   result = NULL;
    265   result = var_interface_->VarToUtf8(PP_MakeBool(PP_TRUE), &length);
    266   if (length != 0) {
    267     return "Expected 0 on string conversion from Bool var.";
    268   }
    269   if (result != NULL) {
    270     return "Expected NULL on string conversion from Bool var.";
    271   }
    272 
    273   length = kInvalidLength;
    274   result = NULL;
    275   result = var_interface_->VarToUtf8(PP_MakeInt32(1), &length);
    276   if (length != 0) {
    277     return "Expected 0 on string conversion from Int32 var.";
    278   }
    279   if (result != NULL) {
    280     return "Expected NULL on string conversion from Int32 var.";
    281   }
    282 
    283   length = kInvalidLength;
    284   result = NULL;
    285   result = var_interface_->VarToUtf8(PP_MakeDouble(1.0), &length);
    286   if (length != 0) {
    287     return "Expected 0 on string conversion from Double var.";
    288   }
    289   if (result != NULL) {
    290     return "Expected NULL on string conversion from Double var.";
    291   }
    292 
    293   PASS();
    294 }
    295 
    296 std::string TestVarDeprecated::TestHasPropertyAndMethod() {
    297   pp::VarPrivate window = instance_->GetWindowObject();
    298   ASSERT_TRUE(window.is_object());
    299 
    300   // Regular property.
    301   pp::Var exception;
    302   ASSERT_TRUE(window.HasProperty("scrollX", &exception));
    303   ASSERT_TRUE(exception.is_undefined());
    304   ASSERT_FALSE(window.HasMethod("scrollX", &exception));
    305   ASSERT_TRUE(exception.is_undefined());
    306 
    307   // Regular method (also counts as HasProperty).
    308   ASSERT_TRUE(window.HasProperty("find", &exception));
    309   ASSERT_TRUE(exception.is_undefined());
    310   ASSERT_TRUE(window.HasMethod("find", &exception));
    311   ASSERT_TRUE(exception.is_undefined());
    312 
    313   // Nonexistant ones should return false and not set the exception.
    314   ASSERT_FALSE(window.HasProperty("superEvilBit", &exception));
    315   ASSERT_TRUE(exception.is_undefined());
    316   ASSERT_FALSE(window.HasMethod("superEvilBit", &exception));
    317   ASSERT_TRUE(exception.is_undefined());
    318 
    319   // Check exception and return false on invalid property name.
    320   ASSERT_FALSE(window.HasProperty(3.14159, &exception));
    321   ASSERT_FALSE(exception.is_undefined());
    322   exception = pp::Var();
    323 
    324   exception = pp::Var();
    325   ASSERT_FALSE(window.HasMethod(3.14159, &exception));
    326   ASSERT_FALSE(exception.is_undefined());
    327 
    328   // Try to use something not an object.
    329   exception = pp::Var();
    330   pp::VarPrivate string_object("asdf");
    331   ASSERT_FALSE(string_object.HasProperty("find", &exception));
    332   ASSERT_FALSE(exception.is_undefined());
    333   exception = pp::Var();
    334   ASSERT_FALSE(string_object.HasMethod("find", &exception));
    335   ASSERT_FALSE(exception.is_undefined());
    336 
    337   // Try to use an invalid object (need to use the C API).
    338   PP_Var invalid_object;
    339   invalid_object.type = PP_VARTYPE_OBJECT;
    340   invalid_object.value.as_id = static_cast<int64_t>(-1234567);
    341   PP_Var exception2 = PP_MakeUndefined();
    342   ASSERT_FALSE(var_interface_->HasProperty(invalid_object,
    343                                            pp::Var("find").pp_var(),
    344                                            &exception2));
    345   ASSERT_NE(PP_VARTYPE_UNDEFINED, exception2.type);
    346   var_interface_->Release(exception2);
    347 
    348   exception2 = PP_MakeUndefined();
    349   ASSERT_FALSE(var_interface_->HasMethod(invalid_object,
    350                                          pp::Var("find").pp_var(),
    351                                          &exception2));
    352   ASSERT_NE(PP_VARTYPE_UNDEFINED, exception2.type);
    353   var_interface_->Release(exception2);
    354 
    355   // Getting a valid property/method when the exception is set returns false.
    356   exception = pp::Var("Bad something-or-other exception");
    357   ASSERT_FALSE(window.HasProperty("find", &exception));
    358   ASSERT_FALSE(exception.is_undefined());
    359   ASSERT_FALSE(window.HasMethod("find", &exception));
    360   ASSERT_FALSE(exception.is_undefined());
    361 
    362   PASS();
    363 }
    364 
    365 // Tests that when the page sends an object to the plugin via a function call,
    366 // that the refcounting works properly (bug 79813).
    367 std::string TestVarDeprecated::TestPassReference() {
    368   var_from_page_ = pp::Var();
    369 
    370   // Send a JS object from the page to the plugin.
    371   pp::Var exception;
    372   pp::Var ret = instance_->ExecuteScript(
    373       "document.getElementById('plugin').SetValue(function(arg) {"
    374           "return 'works' + arg;"
    375       "})",
    376       &exception);
    377   ASSERT_TRUE(exception.is_undefined());
    378 
    379   // We should have gotten an object set for our var_from_page.
    380   ASSERT_TRUE(var_from_page_.is_object());
    381 
    382   // If the reference counting works, the object should be valid. We can test
    383   // this by executing it (it was a function we defined above) and it should
    384   // return "works" concatenated with the argument.
    385   pp::VarPrivate function(var_from_page_);
    386   pp::Var result = var_from_page_.Call(pp::Var(), "nice");
    387   ASSERT_TRUE(result.is_string());
    388   ASSERT_TRUE(result.AsString() == "worksnice");
    389 
    390   // Reset var_from_page_ so it doesn't seem like a leak to the var leak
    391   // checking code.
    392   var_from_page_ = pp::Var();
    393 
    394   PASS();
    395 }
    396 
    397