• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Equals(const base::Value & value,const PP_Var & var)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 
ConvertVarAndVerify(const PP_Var & var)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 
ConvertValueAndVerify(const base::Value & value)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:
VarValueConversionsTest()138   VarValueConversionsTest() {
139   }
~VarValueConversionsTest()140   virtual ~VarValueConversionsTest() {
141   }
142 
143   // testing::Test implementation.
SetUp()144   virtual void SetUp() {
145     ProxyLock::EnableLockingOnThreadForTest();
146     ProxyLock::Acquire();
147   }
TearDown()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 
TEST_F(VarValueConversionsTest,CreateValueFromVar)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 
TEST_F(VarValueConversionsTest,CreateVarFromValue)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 
TEST_F(VarValueConversionsTest,CreateListValueFromVarVector)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 
TEST_F(VarValueConversionsTest,CreateVarVectorFromListValue)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