Home | History | Annotate | Download | only in shared_impl
      1 // Copyright (c) 2013 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/shared_impl/var_value_conversions.h"
      6 
      7 #include <cmath>
      8 #include <cstring>
      9 
     10 #include "base/logging.h"
     11 #include "base/memory/ref_counted.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/values.h"
     14 #include "ppapi/c/pp_bool.h"
     15 #include "ppapi/c/pp_var.h"
     16 #include "ppapi/shared_impl/array_var.h"
     17 #include "ppapi/shared_impl/dictionary_var.h"
     18 #include "ppapi/shared_impl/ppapi_globals.h"
     19 #include "ppapi/shared_impl/proxy_lock.h"
     20 #include "ppapi/shared_impl/scoped_pp_var.h"
     21 #include "ppapi/shared_impl/test_globals.h"
     22 #include "ppapi/shared_impl/var.h"
     23 #include "ppapi/shared_impl/var_tracker.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 
     26 namespace ppapi {
     27 namespace {
     28 
     29 bool Equals(const base::Value& value, const PP_Var& var) {
     30   switch (value.GetType()) {
     31     case base::Value::TYPE_NULL: {
     32       return var.type == PP_VARTYPE_NULL || var.type == PP_VARTYPE_UNDEFINED;
     33     }
     34     case base::Value::TYPE_BOOLEAN: {
     35       bool result = false;
     36       return var.type == PP_VARTYPE_BOOL &&
     37              value.GetAsBoolean(&result) &&
     38              result == PP_ToBool(var.value.as_bool);
     39     }
     40     case base::Value::TYPE_INTEGER: {
     41       int result = 0;
     42       return var.type == PP_VARTYPE_INT32 &&
     43              value.GetAsInteger(&result) &&
     44              result == var.value.as_int;
     45     }
     46     case base::Value::TYPE_DOUBLE: {
     47       double result = 0;
     48       return var.type == PP_VARTYPE_DOUBLE &&
     49              value.GetAsDouble(&result) &&
     50              fabs(result - var.value.as_double) < 1.0e-4;
     51     }
     52     case base::Value::TYPE_STRING: {
     53       std::string result;
     54       StringVar* string_var = StringVar::FromPPVar(var);
     55       return string_var &&
     56              value.GetAsString(&result) &&
     57              result == string_var->value();
     58     }
     59     case base::Value::TYPE_BINARY: {
     60       const base::BinaryValue& binary_value =
     61           static_cast<const base::BinaryValue&>(value);
     62       ArrayBufferVar* array_buffer_var = ArrayBufferVar::FromPPVar(var);
     63       if (!array_buffer_var ||
     64           binary_value.GetSize() != array_buffer_var->ByteLength()) {
     65         return false;
     66       }
     67 
     68       bool result = !memcmp(binary_value.GetBuffer(), array_buffer_var->Map(),
     69                             binary_value.GetSize());
     70       array_buffer_var->Unmap();
     71       return result;
     72     }
     73     case base::Value::TYPE_DICTIONARY: {
     74       const base::DictionaryValue& dict_value =
     75           static_cast<const base::DictionaryValue&>(value);
     76       DictionaryVar* dict_var = DictionaryVar::FromPPVar(var);
     77       if (!dict_var)
     78         return false;
     79 
     80       size_t count = 0;
     81       for (DictionaryVar::KeyValueMap::const_iterator iter =
     82                dict_var->key_value_map().begin();
     83            iter != dict_var->key_value_map().end();
     84            ++iter) {
     85         if (iter->second.get().type == PP_VARTYPE_UNDEFINED ||
     86             iter->second.get().type == PP_VARTYPE_NULL) {
     87           continue;
     88         }
     89 
     90         ++count;
     91         const base::Value* sub_value = NULL;
     92         if (!dict_value.GetWithoutPathExpansion(iter->first, &sub_value) ||
     93             !Equals(*sub_value, iter->second.get())) {
     94           return false;
     95         }
     96       }
     97       return count == dict_value.size();
     98     }
     99     case base::Value::TYPE_LIST: {
    100       const base::ListValue& list_value =
    101           static_cast<const base::ListValue&>(value);
    102       ArrayVar* array_var = ArrayVar::FromPPVar(var);
    103       if (!array_var || list_value.GetSize() != array_var->elements().size())
    104         return false;
    105 
    106       base::ListValue::const_iterator value_iter = list_value.begin();
    107       ArrayVar::ElementVector::const_iterator var_iter =
    108           array_var->elements().begin();
    109       for (; value_iter != list_value.end() &&
    110                  var_iter != array_var->elements().end();
    111            ++value_iter, ++var_iter) {
    112         if (!Equals(**value_iter, var_iter->get()))
    113           return false;
    114       }
    115       return true;
    116     }
    117   }
    118   NOTREACHED();
    119   return false;
    120 }
    121 
    122 bool ConvertVarAndVerify(const PP_Var& var) {
    123   scoped_ptr<base::Value> value(CreateValueFromVar(var));
    124   if (value.get())
    125     return Equals(*value, var);
    126   return false;
    127 }
    128 
    129 bool ConvertValueAndVerify(const base::Value& value) {
    130   ScopedPPVar var(ScopedPPVar::PassRef(), CreateVarFromValue(value));
    131   if (var.get().type != PP_VARTYPE_UNDEFINED)
    132     return Equals(value, var.get());
    133   return false;
    134 }
    135 
    136 class VarValueConversionsTest : public testing::Test {
    137  public:
    138   VarValueConversionsTest() {
    139   }
    140   virtual ~VarValueConversionsTest() {
    141   }
    142 
    143   // testing::Test implementation.
    144   virtual void SetUp() {
    145     ProxyLock::EnableLockingOnThreadForTest();
    146     ProxyLock::Acquire();
    147   }
    148   virtual void TearDown() {
    149     ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty());
    150     ProxyLock::Release();
    151   }
    152 
    153  private:
    154   TestGlobals globals_;
    155 };
    156 
    157 }  // namespace
    158 
    159 TEST_F(VarValueConversionsTest, CreateValueFromVar) {
    160   {
    161     // Var holding a ref to itself is not a valid input.
    162     scoped_refptr<DictionaryVar> dict_var(new DictionaryVar());
    163     ScopedPPVar var_1(ScopedPPVar::PassRef(), dict_var->GetPPVar());
    164     scoped_refptr<ArrayVar> array_var(new ArrayVar());
    165     ScopedPPVar var_2(ScopedPPVar::PassRef(), array_var->GetPPVar());
    166 
    167     ASSERT_TRUE(dict_var->SetWithStringKey("key_1", var_2.get()));
    168     ASSERT_TRUE(ConvertVarAndVerify(var_1.get()));
    169 
    170     ASSERT_TRUE(array_var->Set(0, var_1.get()));
    171     scoped_ptr<base::Value> value(CreateValueFromVar(var_1.get()));
    172     ASSERT_EQ(NULL, value.get());
    173 
    174     // Make sure |var_1| doesn't indirectly hold a ref to itself, otherwise it
    175     // is leaked.
    176     dict_var->DeleteWithStringKey("key_1");
    177   }
    178 
    179   // Vars of null or undefined type are converted to null values.
    180   {
    181     ASSERT_TRUE(ConvertVarAndVerify(PP_MakeNull()));
    182     ASSERT_TRUE(ConvertVarAndVerify(PP_MakeUndefined()));
    183   }
    184 
    185   {
    186     // Test empty dictionary.
    187     scoped_refptr<DictionaryVar> dict_var(new DictionaryVar());
    188     ScopedPPVar var(ScopedPPVar::PassRef(), dict_var->GetPPVar());
    189 
    190     ASSERT_TRUE(ConvertVarAndVerify(var.get()));
    191   }
    192 
    193   {
    194     // Key-value pairs whose value is undefined or null are ignored.
    195     scoped_refptr<DictionaryVar> dict_var(new DictionaryVar());
    196     ASSERT_TRUE(dict_var->SetWithStringKey("key_1", PP_MakeUndefined()));
    197     ASSERT_TRUE(dict_var->SetWithStringKey("key_2", PP_MakeInt32(1)));
    198     ASSERT_TRUE(dict_var->SetWithStringKey("key_3", PP_MakeNull()));
    199     ScopedPPVar var(ScopedPPVar::PassRef(), dict_var->GetPPVar());
    200 
    201     ASSERT_TRUE(ConvertVarAndVerify(var.get()));
    202   }
    203 
    204   {
    205     // The same PP_Var is allowed to appear multiple times.
    206     scoped_refptr<DictionaryVar> dict_var_1(new DictionaryVar());
    207     ScopedPPVar dict_pp_var_1(ScopedPPVar::PassRef(), dict_var_1->GetPPVar());
    208     scoped_refptr<DictionaryVar> dict_var_2(new DictionaryVar());
    209     ScopedPPVar dict_pp_var_2(ScopedPPVar::PassRef(), dict_var_2->GetPPVar());
    210     scoped_refptr<StringVar> string_var(new StringVar("string_value"));
    211     ScopedPPVar string_pp_var(ScopedPPVar::PassRef(), string_var->GetPPVar());
    212 
    213     ASSERT_TRUE(dict_var_1->SetWithStringKey("key_1", dict_pp_var_2.get()));
    214     ASSERT_TRUE(dict_var_1->SetWithStringKey("key_2", dict_pp_var_2.get()));
    215     ASSERT_TRUE(dict_var_1->SetWithStringKey("key_3", string_pp_var.get()));
    216     ASSERT_TRUE(dict_var_2->SetWithStringKey("key_4", string_pp_var.get()));
    217 
    218     ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var_1.get()));
    219   }
    220 
    221   {
    222     // Test basic cases for array.
    223     scoped_refptr<ArrayVar> array_var(new ArrayVar());
    224     ScopedPPVar var(ScopedPPVar::PassRef(), array_var->GetPPVar());
    225 
    226     ASSERT_TRUE(ConvertVarAndVerify(var.get()));
    227 
    228     ASSERT_TRUE(array_var->Set(0, PP_MakeDouble(1)));
    229 
    230     ASSERT_TRUE(ConvertVarAndVerify(var.get()));
    231   }
    232 
    233   {
    234     // Test more complex inputs.
    235     scoped_refptr<DictionaryVar> dict_var_1(new DictionaryVar());
    236     ScopedPPVar dict_pp_var_1(ScopedPPVar::PassRef(), dict_var_1->GetPPVar());
    237     scoped_refptr<DictionaryVar> dict_var_2(new DictionaryVar());
    238     ScopedPPVar dict_pp_var_2(ScopedPPVar::PassRef(), dict_var_2->GetPPVar());
    239     scoped_refptr<ArrayVar> array_var(new ArrayVar());
    240     ScopedPPVar array_pp_var(ScopedPPVar::PassRef(), array_var->GetPPVar());
    241     scoped_refptr<StringVar> string_var(new StringVar("string_value"));
    242     ScopedPPVar string_pp_var(ScopedPPVar::PassRef(), string_var->GetPPVar());
    243 
    244     ASSERT_TRUE(dict_var_1->SetWithStringKey("null_key", PP_MakeNull()));
    245     ASSERT_TRUE(dict_var_1->SetWithStringKey("string_key",
    246                                              string_pp_var.get()));
    247     ASSERT_TRUE(dict_var_1->SetWithStringKey("dict_key", dict_pp_var_2.get()));
    248 
    249     ASSERT_TRUE(dict_var_2->SetWithStringKey("undefined_key",
    250                                              PP_MakeUndefined()));
    251     ASSERT_TRUE(dict_var_2->SetWithStringKey("double_key", PP_MakeDouble(1)));
    252     ASSERT_TRUE(dict_var_2->SetWithStringKey("array_key", array_pp_var.get()));
    253 
    254     ASSERT_TRUE(array_var->Set(0, PP_MakeInt32(2)));
    255     ASSERT_TRUE(array_var->Set(1, PP_MakeBool(PP_TRUE)));
    256     ASSERT_TRUE(array_var->SetLength(4));
    257 
    258     ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var_1.get()));
    259   }
    260 
    261   {
    262     // Test that dictionary keys containing '.' are handled correctly.
    263     scoped_refptr<DictionaryVar> dict_var(new DictionaryVar());
    264     ScopedPPVar dict_pp_var(ScopedPPVar::PassRef(), dict_var->GetPPVar());
    265 
    266     ASSERT_TRUE(dict_var->SetWithStringKey("double.key", PP_MakeDouble(1)));
    267     ASSERT_TRUE(dict_var->SetWithStringKey("int.key..name", PP_MakeInt32(2)));
    268 
    269     ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var.get()));
    270   }
    271 }
    272 
    273 TEST_F(VarValueConversionsTest, CreateVarFromValue) {
    274   {
    275     // Test basic cases for dictionary.
    276     base::DictionaryValue dict_value;
    277     ASSERT_TRUE(ConvertValueAndVerify(dict_value));
    278 
    279     dict_value.SetInteger("int_key", 1);
    280     ASSERT_TRUE(ConvertValueAndVerify(dict_value));
    281   }
    282 
    283   {
    284     // Test basic cases for array.
    285     base::ListValue list_value;
    286     ASSERT_TRUE(ConvertValueAndVerify(list_value));
    287 
    288     list_value.AppendInteger(1);
    289     ASSERT_TRUE(ConvertValueAndVerify(list_value));
    290   }
    291 
    292   {
    293     // Test more complex inputs.
    294     base::DictionaryValue dict_value;
    295     dict_value.SetString("string_key", "string_value");
    296     dict_value.SetDouble("dict_key.double_key", 1);
    297 
    298     scoped_ptr<base::ListValue> list_value(new base::ListValue());
    299     list_value->AppendInteger(2);
    300     list_value->AppendBoolean(true);
    301     list_value->Append(base::Value::CreateNullValue());
    302 
    303     dict_value.Set("dict_key.array_key", list_value.release());
    304 
    305     ASSERT_TRUE(ConvertValueAndVerify(dict_value));
    306   }
    307 }
    308 
    309 TEST_F(VarValueConversionsTest, CreateListValueFromVarVector) {
    310   {
    311     // Test empty var vector.
    312     scoped_ptr<base::ListValue> list_value(
    313         CreateListValueFromVarVector(std::vector<PP_Var>()));
    314     ASSERT_TRUE(list_value.get());
    315     ASSERT_EQ(0u, list_value->GetSize());
    316   }
    317 
    318   {
    319     // Test more complex inputs.
    320     scoped_refptr<StringVar> string_var(new StringVar("string_value"));
    321     ScopedPPVar string_pp_var(ScopedPPVar::PassRef(), string_var->GetPPVar());
    322 
    323     scoped_refptr<DictionaryVar> dict_var(new DictionaryVar());
    324     ScopedPPVar dict_pp_var(ScopedPPVar::PassRef(), dict_var->GetPPVar());
    325     ASSERT_TRUE(dict_var->SetWithStringKey("null_key", PP_MakeNull()));
    326     ASSERT_TRUE(dict_var->SetWithStringKey("string_key", string_pp_var.get()));
    327 
    328     scoped_refptr<ArrayVar> array_var(new ArrayVar());
    329     ScopedPPVar array_pp_var(ScopedPPVar::PassRef(), array_var->GetPPVar());
    330     ASSERT_TRUE(array_var->Set(0, PP_MakeInt32(2)));
    331     ASSERT_TRUE(array_var->Set(1, PP_MakeBool(PP_TRUE)));
    332     ASSERT_TRUE(array_var->SetLength(4));
    333 
    334     std::vector<PP_Var> vars;
    335     vars.push_back(dict_pp_var.get());
    336     vars.push_back(string_pp_var.get());
    337     vars.push_back(array_pp_var.get());
    338     vars.push_back(PP_MakeDouble(1));
    339     vars.push_back(PP_MakeUndefined());
    340     vars.push_back(PP_MakeNull());
    341 
    342     scoped_ptr<base::ListValue> list_value(CreateListValueFromVarVector(vars));
    343 
    344     ASSERT_TRUE(list_value.get());
    345     ASSERT_EQ(vars.size(), list_value->GetSize());
    346 
    347     for (size_t i = 0; i < list_value->GetSize(); ++i) {
    348       const base::Value* value = NULL;
    349       ASSERT_TRUE(list_value->Get(i, &value));
    350       ASSERT_TRUE(Equals(*value, vars[i]));
    351     }
    352   }
    353 }
    354 
    355 TEST_F(VarValueConversionsTest, CreateVarVectorFromListValue) {
    356   {
    357     // Test empty list.
    358     base::ListValue list_value;
    359     std::vector<PP_Var> vars;
    360     ASSERT_TRUE(CreateVarVectorFromListValue(list_value, &vars));
    361     ASSERT_EQ(0u, vars.size());
    362   }
    363 
    364   {
    365     // Test more complex inputs.
    366     base::ListValue list_value;
    367 
    368     scoped_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue());
    369     dict_value->SetString("string_key", "string_value");
    370 
    371     scoped_ptr<base::ListValue> sub_list_value(new base::ListValue());
    372     sub_list_value->AppendInteger(2);
    373     sub_list_value->AppendBoolean(true);
    374 
    375     list_value.Append(dict_value.release());
    376     list_value.AppendString("string_value");
    377     list_value.Append(sub_list_value.release());
    378     list_value.AppendDouble(1);
    379     list_value.Append(base::Value::CreateNullValue());
    380 
    381     std::vector<PP_Var> vars;
    382     ASSERT_TRUE(CreateVarVectorFromListValue(list_value, &vars));
    383 
    384     ASSERT_EQ(list_value.GetSize(), vars.size());
    385 
    386     for (size_t i = 0; i < list_value.GetSize(); ++i) {
    387       const base::Value* value = NULL;
    388       ASSERT_TRUE(list_value.Get(i, &value));
    389       ASSERT_TRUE(Equals(*value, vars[i]));
    390 
    391       PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(vars[i]);
    392     }
    393   }
    394 }
    395 
    396 }  // namespace ppapi
    397