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
&& value
.GetAsBoolean(&result
) &&
37 result
== PP_ToBool(var
.value
.as_bool
);
39 case base::Value::TYPE_INTEGER
: {
41 return var
.type
== PP_VARTYPE_INT32
&& value
.GetAsInteger(&result
) &&
42 result
== var
.value
.as_int
;
44 case base::Value::TYPE_DOUBLE
: {
46 return var
.type
== PP_VARTYPE_DOUBLE
&& value
.GetAsDouble(&result
) &&
47 fabs(result
- var
.value
.as_double
) < 1.0e-4;
49 case base::Value::TYPE_STRING
: {
51 StringVar
* string_var
= StringVar::FromPPVar(var
);
52 return string_var
&& value
.GetAsString(&result
) &&
53 result
== string_var
->value();
55 case base::Value::TYPE_BINARY
: {
56 const base::BinaryValue
& binary_value
=
57 static_cast<const base::BinaryValue
&>(value
);
58 ArrayBufferVar
* array_buffer_var
= ArrayBufferVar::FromPPVar(var
);
59 if (!array_buffer_var
||
60 binary_value
.GetSize() != array_buffer_var
->ByteLength()) {
64 bool result
= !memcmp(binary_value
.GetBuffer(),
65 array_buffer_var
->Map(),
66 binary_value
.GetSize());
67 array_buffer_var
->Unmap();
70 case base::Value::TYPE_DICTIONARY
: {
71 const base::DictionaryValue
& dict_value
=
72 static_cast<const base::DictionaryValue
&>(value
);
73 DictionaryVar
* dict_var
= DictionaryVar::FromPPVar(var
);
78 for (DictionaryVar::KeyValueMap::const_iterator iter
=
79 dict_var
->key_value_map().begin();
80 iter
!= dict_var
->key_value_map().end();
82 if (iter
->second
.get().type
== PP_VARTYPE_UNDEFINED
||
83 iter
->second
.get().type
== PP_VARTYPE_NULL
) {
88 const base::Value
* sub_value
= NULL
;
89 if (!dict_value
.GetWithoutPathExpansion(iter
->first
, &sub_value
) ||
90 !Equals(*sub_value
, iter
->second
.get())) {
94 return count
== dict_value
.size();
96 case base::Value::TYPE_LIST
: {
97 const base::ListValue
& list_value
=
98 static_cast<const base::ListValue
&>(value
);
99 ArrayVar
* array_var
= ArrayVar::FromPPVar(var
);
100 if (!array_var
|| list_value
.GetSize() != array_var
->elements().size())
103 base::ListValue::const_iterator value_iter
= list_value
.begin();
104 ArrayVar::ElementVector::const_iterator var_iter
=
105 array_var
->elements().begin();
106 for (; value_iter
!= list_value
.end() &&
107 var_iter
!= array_var
->elements().end();
108 ++value_iter
, ++var_iter
) {
109 if (!Equals(**value_iter
, var_iter
->get()))
119 bool ConvertVarAndVerify(const PP_Var
& var
) {
120 scoped_ptr
<base::Value
> value(CreateValueFromVar(var
));
122 return Equals(*value
, var
);
126 bool ConvertValueAndVerify(const base::Value
& value
) {
127 ScopedPPVar
var(ScopedPPVar::PassRef(), CreateVarFromValue(value
));
128 if (var
.get().type
!= PP_VARTYPE_UNDEFINED
)
129 return Equals(value
, var
.get());
133 class VarValueConversionsTest
: public testing::Test
{
135 VarValueConversionsTest() {}
136 virtual ~VarValueConversionsTest() {}
138 // testing::Test implementation.
139 virtual void SetUp() {
140 ProxyLock::EnableLockingOnThreadForTest();
141 ProxyLock::Acquire();
143 virtual void TearDown() {
144 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty());
145 ProxyLock::Release();
149 TestGlobals globals_
;
154 TEST_F(VarValueConversionsTest
, CreateValueFromVar
) {
156 // Var holding a ref to itself is not a valid input.
157 scoped_refptr
<DictionaryVar
> dict_var(new DictionaryVar());
158 ScopedPPVar
var_1(ScopedPPVar::PassRef(), dict_var
->GetPPVar());
159 scoped_refptr
<ArrayVar
> array_var(new ArrayVar());
160 ScopedPPVar
var_2(ScopedPPVar::PassRef(), array_var
->GetPPVar());
162 ASSERT_TRUE(dict_var
->SetWithStringKey("key_1", var_2
.get()));
163 ASSERT_TRUE(ConvertVarAndVerify(var_1
.get()));
165 ASSERT_TRUE(array_var
->Set(0, var_1
.get()));
166 scoped_ptr
<base::Value
> value(CreateValueFromVar(var_1
.get()));
167 ASSERT_EQ(NULL
, value
.get());
169 // Make sure |var_1| doesn't indirectly hold a ref to itself, otherwise it
171 dict_var
->DeleteWithStringKey("key_1");
174 // Vars of null or undefined type are converted to null values.
176 ASSERT_TRUE(ConvertVarAndVerify(PP_MakeNull()));
177 ASSERT_TRUE(ConvertVarAndVerify(PP_MakeUndefined()));
181 // Test empty dictionary.
182 scoped_refptr
<DictionaryVar
> dict_var(new DictionaryVar());
183 ScopedPPVar
var(ScopedPPVar::PassRef(), dict_var
->GetPPVar());
185 ASSERT_TRUE(ConvertVarAndVerify(var
.get()));
189 // Key-value pairs whose value is undefined or null are ignored.
190 scoped_refptr
<DictionaryVar
> dict_var(new DictionaryVar());
191 ASSERT_TRUE(dict_var
->SetWithStringKey("key_1", PP_MakeUndefined()));
192 ASSERT_TRUE(dict_var
->SetWithStringKey("key_2", PP_MakeInt32(1)));
193 ASSERT_TRUE(dict_var
->SetWithStringKey("key_3", PP_MakeNull()));
194 ScopedPPVar
var(ScopedPPVar::PassRef(), dict_var
->GetPPVar());
196 ASSERT_TRUE(ConvertVarAndVerify(var
.get()));
200 // The same PP_Var is allowed to appear multiple times.
201 scoped_refptr
<DictionaryVar
> dict_var_1(new DictionaryVar());
202 ScopedPPVar
dict_pp_var_1(ScopedPPVar::PassRef(), dict_var_1
->GetPPVar());
203 scoped_refptr
<DictionaryVar
> dict_var_2(new DictionaryVar());
204 ScopedPPVar
dict_pp_var_2(ScopedPPVar::PassRef(), dict_var_2
->GetPPVar());
205 scoped_refptr
<StringVar
> string_var(new StringVar("string_value"));
206 ScopedPPVar
string_pp_var(ScopedPPVar::PassRef(), string_var
->GetPPVar());
208 ASSERT_TRUE(dict_var_1
->SetWithStringKey("key_1", dict_pp_var_2
.get()));
209 ASSERT_TRUE(dict_var_1
->SetWithStringKey("key_2", dict_pp_var_2
.get()));
210 ASSERT_TRUE(dict_var_1
->SetWithStringKey("key_3", string_pp_var
.get()));
211 ASSERT_TRUE(dict_var_2
->SetWithStringKey("key_4", string_pp_var
.get()));
213 ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var_1
.get()));
217 // Test basic cases for array.
218 scoped_refptr
<ArrayVar
> array_var(new ArrayVar());
219 ScopedPPVar
var(ScopedPPVar::PassRef(), array_var
->GetPPVar());
221 ASSERT_TRUE(ConvertVarAndVerify(var
.get()));
223 ASSERT_TRUE(array_var
->Set(0, PP_MakeDouble(1)));
225 ASSERT_TRUE(ConvertVarAndVerify(var
.get()));
229 // Test more complex inputs.
230 scoped_refptr
<DictionaryVar
> dict_var_1(new DictionaryVar());
231 ScopedPPVar
dict_pp_var_1(ScopedPPVar::PassRef(), dict_var_1
->GetPPVar());
232 scoped_refptr
<DictionaryVar
> dict_var_2(new DictionaryVar());
233 ScopedPPVar
dict_pp_var_2(ScopedPPVar::PassRef(), dict_var_2
->GetPPVar());
234 scoped_refptr
<ArrayVar
> array_var(new ArrayVar());
235 ScopedPPVar
array_pp_var(ScopedPPVar::PassRef(), array_var
->GetPPVar());
236 scoped_refptr
<StringVar
> string_var(new StringVar("string_value"));
237 ScopedPPVar
string_pp_var(ScopedPPVar::PassRef(), string_var
->GetPPVar());
239 ASSERT_TRUE(dict_var_1
->SetWithStringKey("null_key", PP_MakeNull()));
241 dict_var_1
->SetWithStringKey("string_key", string_pp_var
.get()));
242 ASSERT_TRUE(dict_var_1
->SetWithStringKey("dict_key", dict_pp_var_2
.get()));
245 dict_var_2
->SetWithStringKey("undefined_key", PP_MakeUndefined()));
246 ASSERT_TRUE(dict_var_2
->SetWithStringKey("double_key", PP_MakeDouble(1)));
247 ASSERT_TRUE(dict_var_2
->SetWithStringKey("array_key", array_pp_var
.get()));
249 ASSERT_TRUE(array_var
->Set(0, PP_MakeInt32(2)));
250 ASSERT_TRUE(array_var
->Set(1, PP_MakeBool(PP_TRUE
)));
251 ASSERT_TRUE(array_var
->SetLength(4));
253 ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var_1
.get()));
257 // Test that dictionary keys containing '.' are handled correctly.
258 scoped_refptr
<DictionaryVar
> dict_var(new DictionaryVar());
259 ScopedPPVar
dict_pp_var(ScopedPPVar::PassRef(), dict_var
->GetPPVar());
261 ASSERT_TRUE(dict_var
->SetWithStringKey("double.key", PP_MakeDouble(1)));
262 ASSERT_TRUE(dict_var
->SetWithStringKey("int.key..name", PP_MakeInt32(2)));
264 ASSERT_TRUE(ConvertVarAndVerify(dict_pp_var
.get()));
268 TEST_F(VarValueConversionsTest
, CreateVarFromValue
) {
270 // Test basic cases for dictionary.
271 base::DictionaryValue dict_value
;
272 ASSERT_TRUE(ConvertValueAndVerify(dict_value
));
274 dict_value
.SetInteger("int_key", 1);
275 ASSERT_TRUE(ConvertValueAndVerify(dict_value
));
279 // Test basic cases for array.
280 base::ListValue list_value
;
281 ASSERT_TRUE(ConvertValueAndVerify(list_value
));
283 list_value
.AppendInteger(1);
284 ASSERT_TRUE(ConvertValueAndVerify(list_value
));
288 // Test more complex inputs.
289 base::DictionaryValue dict_value
;
290 dict_value
.SetString("string_key", "string_value");
291 dict_value
.SetDouble("dict_key.double_key", 1);
293 scoped_ptr
<base::ListValue
> list_value(new base::ListValue());
294 list_value
->AppendInteger(2);
295 list_value
->AppendBoolean(true);
296 list_value
->Append(base::Value::CreateNullValue());
298 dict_value
.Set("dict_key.array_key", list_value
.release());
300 ASSERT_TRUE(ConvertValueAndVerify(dict_value
));
304 TEST_F(VarValueConversionsTest
, CreateListValueFromVarVector
) {
306 // Test empty var vector.
307 scoped_ptr
<base::ListValue
> list_value(
308 CreateListValueFromVarVector(std::vector
<PP_Var
>()));
309 ASSERT_TRUE(list_value
.get());
310 ASSERT_EQ(0u, list_value
->GetSize());
314 // Test more complex inputs.
315 scoped_refptr
<StringVar
> string_var(new StringVar("string_value"));
316 ScopedPPVar
string_pp_var(ScopedPPVar::PassRef(), string_var
->GetPPVar());
318 scoped_refptr
<DictionaryVar
> dict_var(new DictionaryVar());
319 ScopedPPVar
dict_pp_var(ScopedPPVar::PassRef(), dict_var
->GetPPVar());
320 ASSERT_TRUE(dict_var
->SetWithStringKey("null_key", PP_MakeNull()));
321 ASSERT_TRUE(dict_var
->SetWithStringKey("string_key", string_pp_var
.get()));
323 scoped_refptr
<ArrayVar
> array_var(new ArrayVar());
324 ScopedPPVar
array_pp_var(ScopedPPVar::PassRef(), array_var
->GetPPVar());
325 ASSERT_TRUE(array_var
->Set(0, PP_MakeInt32(2)));
326 ASSERT_TRUE(array_var
->Set(1, PP_MakeBool(PP_TRUE
)));
327 ASSERT_TRUE(array_var
->SetLength(4));
329 std::vector
<PP_Var
> vars
;
330 vars
.push_back(dict_pp_var
.get());
331 vars
.push_back(string_pp_var
.get());
332 vars
.push_back(array_pp_var
.get());
333 vars
.push_back(PP_MakeDouble(1));
334 vars
.push_back(PP_MakeUndefined());
335 vars
.push_back(PP_MakeNull());
337 scoped_ptr
<base::ListValue
> list_value(CreateListValueFromVarVector(vars
));
339 ASSERT_TRUE(list_value
.get());
340 ASSERT_EQ(vars
.size(), list_value
->GetSize());
342 for (size_t i
= 0; i
< list_value
->GetSize(); ++i
) {
343 const base::Value
* value
= NULL
;
344 ASSERT_TRUE(list_value
->Get(i
, &value
));
345 ASSERT_TRUE(Equals(*value
, vars
[i
]));
350 TEST_F(VarValueConversionsTest
, CreateVarVectorFromListValue
) {
353 base::ListValue list_value
;
354 std::vector
<PP_Var
> vars
;
355 ASSERT_TRUE(CreateVarVectorFromListValue(list_value
, &vars
));
356 ASSERT_EQ(0u, vars
.size());
360 // Test more complex inputs.
361 base::ListValue list_value
;
363 scoped_ptr
<base::DictionaryValue
> dict_value(new base::DictionaryValue());
364 dict_value
->SetString("string_key", "string_value");
366 scoped_ptr
<base::ListValue
> sub_list_value(new base::ListValue());
367 sub_list_value
->AppendInteger(2);
368 sub_list_value
->AppendBoolean(true);
370 list_value
.Append(dict_value
.release());
371 list_value
.AppendString("string_value");
372 list_value
.Append(sub_list_value
.release());
373 list_value
.AppendDouble(1);
374 list_value
.Append(base::Value::CreateNullValue());
376 std::vector
<PP_Var
> vars
;
377 ASSERT_TRUE(CreateVarVectorFromListValue(list_value
, &vars
));
379 ASSERT_EQ(list_value
.GetSize(), vars
.size());
381 for (size_t i
= 0; i
< list_value
.GetSize(); ++i
) {
382 const base::Value
* value
= NULL
;
383 ASSERT_TRUE(list_value
.Get(i
, &value
));
384 ASSERT_TRUE(Equals(*value
, vars
[i
]));
386 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(vars
[i
]);