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