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