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.
5 #include "ppapi/shared_impl/var_value_conversions.h"
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"
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
;
34 case base::Value::TYPE_BOOLEAN
: {
36 return var
.type
== PP_VARTYPE_BOOL
&&
37 value
.GetAsBoolean(&result
) &&
38 result
== PP_ToBool(var
.value
.as_bool
);
40 case base::Value::TYPE_INTEGER
: {
42 return var
.type
== PP_VARTYPE_INT32
&&
43 value
.GetAsInteger(&result
) &&
44 result
== var
.value
.as_int
;
46 case base::Value::TYPE_DOUBLE
: {
48 return var
.type
== PP_VARTYPE_DOUBLE
&&
49 value
.GetAsDouble(&result
) &&
50 fabs(result
- var
.value
.as_double
) < 1.0e-4;
52 case base::Value::TYPE_STRING
: {
54 StringVar
* string_var
= StringVar::FromPPVar(var
);
56 value
.GetAsString(&result
) &&
57 result
== string_var
->value();
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()) {
68 bool result
= !memcmp(binary_value
.GetBuffer(), array_buffer_var
->Map(),
69 binary_value
.GetSize());
70 array_buffer_var
->Unmap();
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
);
81 for (DictionaryVar::KeyValueMap::const_iterator iter
=
82 dict_var
->key_value_map().begin();
83 iter
!= dict_var
->key_value_map().end();
85 if (iter
->second
.get().type
== PP_VARTYPE_UNDEFINED
||
86 iter
->second
.get().type
== PP_VARTYPE_NULL
) {
91 const base::Value
* sub_value
= NULL
;
92 if (!dict_value
.GetWithoutPathExpansion(iter
->first
, &sub_value
) ||
93 !Equals(*sub_value
, iter
->second
.get())) {
97 return count
== dict_value
.size();
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())
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()))
122 bool ConvertVarAndVerify(const PP_Var
& var
) {
123 scoped_ptr
<base::Value
> value(CreateValueFromVar(var
));
125 return Equals(*value
, var
);
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());
136 class VarValueConversionsTest
: public testing::Test
{
138 VarValueConversionsTest() {
140 virtual ~VarValueConversionsTest() {
143 // testing::Test implementation.
144 virtual void SetUp() {
145 ProxyLock::EnableLockingOnThreadForTest();
146 ProxyLock::Acquire();
148 virtual void TearDown() {
149 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty());
150 ProxyLock::Release();
154 TestGlobals globals_
;
159 TEST_F(VarValueConversionsTest
, CreateValueFromVar
) {
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());
167 ASSERT_TRUE(dict_var
->SetWithStringKey("key_1", var_2
.get()));
168 ASSERT_TRUE(ConvertVarAndVerify(var_1
.get()));
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());
174 // Make sure |var_1| doesn't indirectly hold a ref to itself, otherwise it
176 dict_var
->DeleteWithStringKey("key_1");
179 // Vars of null or undefined type are converted to null values.
181 ASSERT_TRUE(ConvertVarAndVerify(PP_MakeNull()));
182 ASSERT_TRUE(ConvertVarAndVerify(PP_MakeUndefined()));
186 // Test empty dictionary.
187 scoped_refptr
<DictionaryVar
> dict_var(new DictionaryVar());
188 ScopedPPVar
var(ScopedPPVar::PassRef(), dict_var
->GetPPVar());
190 ASSERT_TRUE(ConvertVarAndVerify(var
.get()));
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());
201 ASSERT_TRUE(ConvertVarAndVerify(var
.get()));
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());
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()));
218 ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var_1
.get()));
222 // Test basic cases for array.
223 scoped_refptr
<ArrayVar
> array_var(new ArrayVar());
224 ScopedPPVar
var(ScopedPPVar::PassRef(), array_var
->GetPPVar());
226 ASSERT_TRUE(ConvertVarAndVerify(var
.get()));
228 ASSERT_TRUE(array_var
->Set(0, PP_MakeDouble(1)));
230 ASSERT_TRUE(ConvertVarAndVerify(var
.get()));
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());
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()));
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()));
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));
258 ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var_1
.get()));
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());
266 ASSERT_TRUE(dict_var
->SetWithStringKey("double.key", PP_MakeDouble(1)));
267 ASSERT_TRUE(dict_var
->SetWithStringKey("int.key..name", PP_MakeInt32(2)));
269 ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var
.get()));
273 TEST_F(VarValueConversionsTest
, CreateVarFromValue
) {
275 // Test basic cases for dictionary.
276 base::DictionaryValue dict_value
;
277 ASSERT_TRUE(ConvertValueAndVerify(dict_value
));
279 dict_value
.SetInteger("int_key", 1);
280 ASSERT_TRUE(ConvertValueAndVerify(dict_value
));
284 // Test basic cases for array.
285 base::ListValue list_value
;
286 ASSERT_TRUE(ConvertValueAndVerify(list_value
));
288 list_value
.AppendInteger(1);
289 ASSERT_TRUE(ConvertValueAndVerify(list_value
));
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);
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());
303 dict_value
.Set("dict_key.array_key", list_value
.release());
305 ASSERT_TRUE(ConvertValueAndVerify(dict_value
));
309 TEST_F(VarValueConversionsTest
, CreateListValueFromVarVector
) {
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());
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());
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()));
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));
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());
342 scoped_ptr
<base::ListValue
> list_value(CreateListValueFromVarVector(vars
));
344 ASSERT_TRUE(list_value
.get());
345 ASSERT_EQ(vars
.size(), list_value
->GetSize());
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
]));
355 TEST_F(VarValueConversionsTest
, CreateVarVectorFromListValue
) {
358 base::ListValue list_value
;
359 std::vector
<PP_Var
> vars
;
360 ASSERT_TRUE(CreateVarVectorFromListValue(list_value
, &vars
));
361 ASSERT_EQ(0u, vars
.size());
365 // Test more complex inputs.
366 base::ListValue list_value
;
368 scoped_ptr
<base::DictionaryValue
> dict_value(new base::DictionaryValue());
369 dict_value
->SetString("string_key", "string_value");
371 scoped_ptr
<base::ListValue
> sub_list_value(new base::ListValue());
372 sub_list_value
->AppendInteger(2);
373 sub_list_value
->AppendBoolean(true);
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());
381 std::vector
<PP_Var
> vars
;
382 ASSERT_TRUE(CreateVarVectorFromListValue(list_value
, &vars
));
384 ASSERT_EQ(list_value
.GetSize(), vars
.size());
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
]));
391 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(vars
[i
]);