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::Acquire(); 146 } 147 virtual void TearDown() { 148 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); 149 ProxyLock::Release(); 150 } 151 152 private: 153 TestGlobals globals_; 154 }; 155 156 } // namespace 157 158 TEST_F(VarValueConversionsTest, CreateValueFromVar) { 159 { 160 // Var holding a ref to itself is not a valid input. 161 scoped_refptr<DictionaryVar> dict_var(new DictionaryVar()); 162 ScopedPPVar var_1(ScopedPPVar::PassRef(), dict_var->GetPPVar()); 163 scoped_refptr<ArrayVar> array_var(new ArrayVar()); 164 ScopedPPVar var_2(ScopedPPVar::PassRef(), array_var->GetPPVar()); 165 166 ASSERT_TRUE(dict_var->SetWithStringKey("key_1", var_2.get())); 167 ASSERT_TRUE(ConvertVarAndVerify(var_1.get())); 168 169 ASSERT_TRUE(array_var->Set(0, var_1.get())); 170 scoped_ptr<base::Value> value(CreateValueFromVar(var_1.get())); 171 ASSERT_EQ(NULL, value.get()); 172 173 // Make sure |var_1| doesn't indirectly hold a ref to itself, otherwise it 174 // is leaked. 175 dict_var->DeleteWithStringKey("key_1"); 176 } 177 178 // Vars of null or undefined type are converted to null values. 179 { 180 ASSERT_TRUE(ConvertVarAndVerify(PP_MakeNull())); 181 ASSERT_TRUE(ConvertVarAndVerify(PP_MakeUndefined())); 182 } 183 184 { 185 // Test empty dictionary. 186 scoped_refptr<DictionaryVar> dict_var(new DictionaryVar()); 187 ScopedPPVar var(ScopedPPVar::PassRef(), dict_var->GetPPVar()); 188 189 ASSERT_TRUE(ConvertVarAndVerify(var.get())); 190 } 191 192 { 193 // Key-value pairs whose value is undefined or null are ignored. 194 scoped_refptr<DictionaryVar> dict_var(new DictionaryVar()); 195 ASSERT_TRUE(dict_var->SetWithStringKey("key_1", PP_MakeUndefined())); 196 ASSERT_TRUE(dict_var->SetWithStringKey("key_2", PP_MakeInt32(1))); 197 ASSERT_TRUE(dict_var->SetWithStringKey("key_3", PP_MakeNull())); 198 ScopedPPVar var(ScopedPPVar::PassRef(), dict_var->GetPPVar()); 199 200 ASSERT_TRUE(ConvertVarAndVerify(var.get())); 201 } 202 203 { 204 // The same PP_Var is allowed to appear multiple times. 205 scoped_refptr<DictionaryVar> dict_var_1(new DictionaryVar()); 206 ScopedPPVar dict_pp_var_1(ScopedPPVar::PassRef(), dict_var_1->GetPPVar()); 207 scoped_refptr<DictionaryVar> dict_var_2(new DictionaryVar()); 208 ScopedPPVar dict_pp_var_2(ScopedPPVar::PassRef(), dict_var_2->GetPPVar()); 209 scoped_refptr<StringVar> string_var(new StringVar("string_value")); 210 ScopedPPVar string_pp_var(ScopedPPVar::PassRef(), string_var->GetPPVar()); 211 212 ASSERT_TRUE(dict_var_1->SetWithStringKey("key_1", dict_pp_var_2.get())); 213 ASSERT_TRUE(dict_var_1->SetWithStringKey("key_2", dict_pp_var_2.get())); 214 ASSERT_TRUE(dict_var_1->SetWithStringKey("key_3", string_pp_var.get())); 215 ASSERT_TRUE(dict_var_2->SetWithStringKey("key_4", string_pp_var.get())); 216 217 ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var_1.get())); 218 } 219 220 { 221 // Test basic cases for array. 222 scoped_refptr<ArrayVar> array_var(new ArrayVar()); 223 ScopedPPVar var(ScopedPPVar::PassRef(), array_var->GetPPVar()); 224 225 ASSERT_TRUE(ConvertVarAndVerify(var.get())); 226 227 ASSERT_TRUE(array_var->Set(0, PP_MakeDouble(1))); 228 229 ASSERT_TRUE(ConvertVarAndVerify(var.get())); 230 } 231 232 { 233 // Test more complex inputs. 234 scoped_refptr<DictionaryVar> dict_var_1(new DictionaryVar()); 235 ScopedPPVar dict_pp_var_1(ScopedPPVar::PassRef(), dict_var_1->GetPPVar()); 236 scoped_refptr<DictionaryVar> dict_var_2(new DictionaryVar()); 237 ScopedPPVar dict_pp_var_2(ScopedPPVar::PassRef(), dict_var_2->GetPPVar()); 238 scoped_refptr<ArrayVar> array_var(new ArrayVar()); 239 ScopedPPVar array_pp_var(ScopedPPVar::PassRef(), array_var->GetPPVar()); 240 scoped_refptr<StringVar> string_var(new StringVar("string_value")); 241 ScopedPPVar string_pp_var(ScopedPPVar::PassRef(), string_var->GetPPVar()); 242 243 ASSERT_TRUE(dict_var_1->SetWithStringKey("null_key", PP_MakeNull())); 244 ASSERT_TRUE(dict_var_1->SetWithStringKey("string_key", 245 string_pp_var.get())); 246 ASSERT_TRUE(dict_var_1->SetWithStringKey("dict_key", dict_pp_var_2.get())); 247 248 ASSERT_TRUE(dict_var_2->SetWithStringKey("undefined_key", 249 PP_MakeUndefined())); 250 ASSERT_TRUE(dict_var_2->SetWithStringKey("double_key", PP_MakeDouble(1))); 251 ASSERT_TRUE(dict_var_2->SetWithStringKey("array_key", array_pp_var.get())); 252 253 ASSERT_TRUE(array_var->Set(0, PP_MakeInt32(2))); 254 ASSERT_TRUE(array_var->Set(1, PP_MakeBool(PP_TRUE))); 255 ASSERT_TRUE(array_var->SetLength(4)); 256 257 ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var_1.get())); 258 } 259 260 { 261 // Test that dictionary keys containing '.' are handled correctly. 262 scoped_refptr<DictionaryVar> dict_var(new DictionaryVar()); 263 ScopedPPVar dict_pp_var(ScopedPPVar::PassRef(), dict_var->GetPPVar()); 264 265 ASSERT_TRUE(dict_var->SetWithStringKey("double.key", PP_MakeDouble(1))); 266 ASSERT_TRUE(dict_var->SetWithStringKey("int.key..name", PP_MakeInt32(2))); 267 268 ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var.get())); 269 } 270 } 271 272 TEST_F(VarValueConversionsTest, CreateVarFromValue) { 273 { 274 // Test basic cases for dictionary. 275 base::DictionaryValue dict_value; 276 ASSERT_TRUE(ConvertValueAndVerify(dict_value)); 277 278 dict_value.SetInteger("int_key", 1); 279 ASSERT_TRUE(ConvertValueAndVerify(dict_value)); 280 } 281 282 { 283 // Test basic cases for array. 284 base::ListValue list_value; 285 ASSERT_TRUE(ConvertValueAndVerify(list_value)); 286 287 list_value.AppendInteger(1); 288 ASSERT_TRUE(ConvertValueAndVerify(list_value)); 289 } 290 291 { 292 // Test more complex inputs. 293 base::DictionaryValue dict_value; 294 dict_value.SetString("string_key", "string_value"); 295 dict_value.SetDouble("dict_key.double_key", 1); 296 297 scoped_ptr<base::ListValue> list_value(new base::ListValue()); 298 list_value->AppendInteger(2); 299 list_value->AppendBoolean(true); 300 list_value->Append(base::Value::CreateNullValue()); 301 302 dict_value.Set("dict_key.array_key", list_value.release()); 303 304 ASSERT_TRUE(ConvertValueAndVerify(dict_value)); 305 } 306 } 307 308 TEST_F(VarValueConversionsTest, CreateListValueFromVarVector) { 309 { 310 // Test empty var vector. 311 scoped_ptr<base::ListValue> list_value( 312 CreateListValueFromVarVector(std::vector<PP_Var>())); 313 ASSERT_TRUE(list_value.get()); 314 ASSERT_EQ(0u, list_value->GetSize()); 315 } 316 317 { 318 // Test more complex inputs. 319 scoped_refptr<StringVar> string_var(new StringVar("string_value")); 320 ScopedPPVar string_pp_var(ScopedPPVar::PassRef(), string_var->GetPPVar()); 321 322 scoped_refptr<DictionaryVar> dict_var(new DictionaryVar()); 323 ScopedPPVar dict_pp_var(ScopedPPVar::PassRef(), dict_var->GetPPVar()); 324 ASSERT_TRUE(dict_var->SetWithStringKey("null_key", PP_MakeNull())); 325 ASSERT_TRUE(dict_var->SetWithStringKey("string_key", string_pp_var.get())); 326 327 scoped_refptr<ArrayVar> array_var(new ArrayVar()); 328 ScopedPPVar array_pp_var(ScopedPPVar::PassRef(), array_var->GetPPVar()); 329 ASSERT_TRUE(array_var->Set(0, PP_MakeInt32(2))); 330 ASSERT_TRUE(array_var->Set(1, PP_MakeBool(PP_TRUE))); 331 ASSERT_TRUE(array_var->SetLength(4)); 332 333 std::vector<PP_Var> vars; 334 vars.push_back(dict_pp_var.get()); 335 vars.push_back(string_pp_var.get()); 336 vars.push_back(array_pp_var.get()); 337 vars.push_back(PP_MakeDouble(1)); 338 vars.push_back(PP_MakeUndefined()); 339 vars.push_back(PP_MakeNull()); 340 341 scoped_ptr<base::ListValue> list_value(CreateListValueFromVarVector(vars)); 342 343 ASSERT_TRUE(list_value.get()); 344 ASSERT_EQ(vars.size(), list_value->GetSize()); 345 346 for (size_t i = 0; i < list_value->GetSize(); ++i) { 347 const base::Value* value = NULL; 348 ASSERT_TRUE(list_value->Get(i, &value)); 349 ASSERT_TRUE(Equals(*value, vars[i])); 350 } 351 } 352 } 353 354 TEST_F(VarValueConversionsTest, CreateVarVectorFromListValue) { 355 { 356 // Test empty list. 357 base::ListValue list_value; 358 std::vector<PP_Var> vars; 359 ASSERT_TRUE(CreateVarVectorFromListValue(list_value, &vars)); 360 ASSERT_EQ(0u, vars.size()); 361 } 362 363 { 364 // Test more complex inputs. 365 base::ListValue list_value; 366 367 scoped_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue()); 368 dict_value->SetString("string_key", "string_value"); 369 370 scoped_ptr<base::ListValue> sub_list_value(new base::ListValue()); 371 sub_list_value->AppendInteger(2); 372 sub_list_value->AppendBoolean(true); 373 374 list_value.Append(dict_value.release()); 375 list_value.AppendString("string_value"); 376 list_value.Append(sub_list_value.release()); 377 list_value.AppendDouble(1); 378 list_value.Append(base::Value::CreateNullValue()); 379 380 std::vector<PP_Var> vars; 381 ASSERT_TRUE(CreateVarVectorFromListValue(list_value, &vars)); 382 383 ASSERT_EQ(list_value.GetSize(), vars.size()); 384 385 for (size_t i = 0; i < list_value.GetSize(); ++i) { 386 const base::Value* value = NULL; 387 ASSERT_TRUE(list_value.Get(i, &value)); 388 ASSERT_TRUE(Equals(*value, vars[i])); 389 390 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(vars[i]); 391 } 392 } 393 } 394 395 } // namespace ppapi 396