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/unittest_utils.h"
9 #include "base/containers/hash_tables.h"
10 #include "base/logging.h"
11 #include "ipc/ipc_message.h"
12 #include "ppapi/shared_impl/array_var.h"
13 #include "ppapi/shared_impl/dictionary_var.h"
14 #include "ppapi/shared_impl/resource_var.h"
15 #include "ppapi/shared_impl/var.h"
16 #include "ppapi/shared_impl/var_tracker.h"
22 // When two vars x and y are found to be equal, an entry is inserted into
23 // |visited_map| with (x.value.as_id, y.value.as_id). This allows reference
24 // cycles to be avoided. It also allows us to associate nodes in |expected| with
25 // nodes in |actual| and check whether the graphs have equivalent topology.
26 bool Equals(const PP_Var
& expected
,
28 base::hash_map
<int64_t, int64_t>* visited_map
) {
29 if (expected
.type
!= actual
.type
) {
30 LOG(ERROR
) << "expected type: " << expected
.type
<<
31 " actual type: " << actual
.type
;
34 if (VarTracker::IsVarTypeRefcounted(expected
.type
)) {
35 base::hash_map
<int64_t, int64_t>::iterator it
=
36 visited_map
->find(expected
.value
.as_id
);
37 if (it
!= visited_map
->end()) {
38 if (it
->second
!= actual
.value
.as_id
) {
39 LOG(ERROR
) << "expected id: " << it
->second
<< " actual id: " <<
46 (*visited_map
)[expected
.value
.as_id
] = actual
.value
.as_id
;
49 switch (expected
.type
) {
50 case PP_VARTYPE_UNDEFINED
:
55 if (expected
.value
.as_bool
!= actual
.value
.as_bool
) {
56 LOG(ERROR
) << "expected: " << expected
.value
.as_bool
<< " actual: " <<
61 case PP_VARTYPE_INT32
:
62 if (expected
.value
.as_int
!= actual
.value
.as_int
) {
63 LOG(ERROR
) << "expected: " << expected
.value
.as_int
<< " actual: " <<
68 case PP_VARTYPE_DOUBLE
:
69 if (fabs(expected
.value
.as_double
- actual
.value
.as_double
) > 1.0e-4) {
70 LOG(ERROR
) << "expected: " << expected
.value
.as_double
<<
71 " actual: " << actual
.value
.as_double
;
75 case PP_VARTYPE_OBJECT
:
76 if (expected
.value
.as_id
!= actual
.value
.as_id
) {
77 LOG(ERROR
) << "expected: " << expected
.value
.as_id
<< " actual: " <<
82 case PP_VARTYPE_STRING
: {
83 StringVar
* expected_var
= StringVar::FromPPVar(expected
);
84 StringVar
* actual_var
= StringVar::FromPPVar(actual
);
85 DCHECK(expected_var
&& actual_var
);
86 if (expected_var
->value() != actual_var
->value()) {
87 LOG(ERROR
) << "expected: " << expected_var
->value() << " actual: " <<
93 case PP_VARTYPE_ARRAY_BUFFER
: {
94 ArrayBufferVar
* expected_var
= ArrayBufferVar::FromPPVar(expected
);
95 ArrayBufferVar
* actual_var
= ArrayBufferVar::FromPPVar(actual
);
96 DCHECK(expected_var
&& actual_var
);
97 if (expected_var
->ByteLength() != actual_var
->ByteLength()) {
98 LOG(ERROR
) << "expected: " << expected_var
->ByteLength() <<
99 " actual: " << actual_var
->ByteLength();
102 if (memcmp(expected_var
->Map(), actual_var
->Map(),
103 expected_var
->ByteLength()) != 0) {
104 LOG(ERROR
) << "expected array buffer does not match actual.";
109 case PP_VARTYPE_ARRAY
: {
110 ArrayVar
* expected_var
= ArrayVar::FromPPVar(expected
);
111 ArrayVar
* actual_var
= ArrayVar::FromPPVar(actual
);
112 DCHECK(expected_var
&& actual_var
);
113 if (expected_var
->elements().size() != actual_var
->elements().size()) {
114 LOG(ERROR
) << "expected: " << expected_var
->elements().size() <<
115 " actual: " << actual_var
->elements().size();
118 for (size_t i
= 0; i
< expected_var
->elements().size(); ++i
) {
119 if (!Equals(expected_var
->elements()[i
].get(),
120 actual_var
->elements()[i
].get(),
127 case PP_VARTYPE_DICTIONARY
: {
128 DictionaryVar
* expected_var
= DictionaryVar::FromPPVar(expected
);
129 DictionaryVar
* actual_var
= DictionaryVar::FromPPVar(actual
);
130 DCHECK(expected_var
&& actual_var
);
131 if (expected_var
->key_value_map().size() !=
132 actual_var
->key_value_map().size()) {
133 LOG(ERROR
) << "expected: " << expected_var
->key_value_map().size() <<
134 " actual: " << actual_var
->key_value_map().size();
137 DictionaryVar::KeyValueMap::const_iterator expected_iter
=
138 expected_var
->key_value_map().begin();
139 DictionaryVar::KeyValueMap::const_iterator actual_iter
=
140 actual_var
->key_value_map().begin();
141 for ( ; expected_iter
!= expected_var
->key_value_map().end();
142 ++expected_iter
, ++actual_iter
) {
143 if (expected_iter
->first
!= actual_iter
->first
) {
144 LOG(ERROR
) << "expected: " << expected_iter
->first
<<
145 " actual: " << actual_iter
->first
;
148 if (!Equals(expected_iter
->second
.get(),
149 actual_iter
->second
.get(),
156 case PP_VARTYPE_RESOURCE
: {
157 ResourceVar
* expected_var
= ResourceVar::FromPPVar(expected
);
158 ResourceVar
* actual_var
= ResourceVar::FromPPVar(actual
);
159 DCHECK(expected_var
&& actual_var
);
160 if (expected_var
->GetPPResource() != actual_var
->GetPPResource()) {
161 LOG(ERROR
) << "expected: " << expected_var
->GetPPResource()
162 << " actual: " << actual_var
->GetPPResource();
166 const IPC::Message
* actual_message
= actual_var
->GetCreationMessage();
167 const IPC::Message
* expected_message
=
168 expected_var
->GetCreationMessage();
169 if (expected_message
->size() != actual_message
->size()) {
170 LOG(ERROR
) << "expected creation message size: "
171 << expected_message
->size() << " actual: "
172 << actual_message
->size();
176 // Set the upper 24 bits of actual creation_message flags to the same as
177 // expected. This is an unpredictable reference number that changes
178 // between serialization/deserialization, and we do not want it to cause
179 // the comparison to fail.
180 IPC::Message
local_actual_message(*actual_message
);
181 local_actual_message
.SetHeaderValues(
182 actual_message
->routing_id(), actual_message
->type(),
183 (expected_message
->flags() & 0xffffff00) |
184 (actual_message
->flags() & 0xff));
185 if (memcmp(expected_message
->data(), local_actual_message
.data(),
186 expected_message
->size()) != 0) {
187 LOG(ERROR
) << "expected creation message does not match actual.";
199 bool TestEqual(const PP_Var
& expected
, const PP_Var
& actual
) {
200 base::hash_map
<int64_t, int64_t> visited_map
;
201 return Equals(expected
, actual
, &visited_map
);