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 bool test_string_references
,
29 base::hash_map
<int64_t, int64_t>* visited_map
) {
30 if (expected
.type
!= actual
.type
) {
31 LOG(ERROR
) << "expected type: " << expected
.type
32 << " actual type: " << actual
.type
;
35 if (VarTracker::IsVarTypeRefcounted(expected
.type
)) {
36 base::hash_map
<int64_t, int64_t>::iterator it
=
37 visited_map
->find(expected
.value
.as_id
);
38 if (it
!= visited_map
->end()) {
39 if (it
->second
!= actual
.value
.as_id
) {
40 LOG(ERROR
) << "expected id: " << it
->second
41 << " actual id: " << actual
.value
.as_id
;
47 if (expected
.type
!= PP_VARTYPE_STRING
|| test_string_references
)
48 (*visited_map
)[expected
.value
.as_id
] = actual
.value
.as_id
;
51 switch (expected
.type
) {
52 case PP_VARTYPE_UNDEFINED
:
57 if (expected
.value
.as_bool
!= actual
.value
.as_bool
) {
58 LOG(ERROR
) << "expected: " << expected
.value
.as_bool
59 << " actual: " << actual
.value
.as_bool
;
63 case PP_VARTYPE_INT32
:
64 if (expected
.value
.as_int
!= actual
.value
.as_int
) {
65 LOG(ERROR
) << "expected: " << expected
.value
.as_int
66 << " actual: " << actual
.value
.as_int
;
70 case PP_VARTYPE_DOUBLE
:
71 if (fabs(expected
.value
.as_double
- actual
.value
.as_double
) > 1.0e-4) {
72 LOG(ERROR
) << "expected: " << expected
.value
.as_double
73 << " actual: " << actual
.value
.as_double
;
77 case PP_VARTYPE_OBJECT
:
78 if (expected
.value
.as_id
!= actual
.value
.as_id
) {
79 LOG(ERROR
) << "expected: " << expected
.value
.as_id
80 << " actual: " << actual
.value
.as_id
;
84 case PP_VARTYPE_STRING
: {
85 StringVar
* expected_var
= StringVar::FromPPVar(expected
);
86 StringVar
* actual_var
= StringVar::FromPPVar(actual
);
87 DCHECK(expected_var
&& actual_var
);
88 if (expected_var
->value() != actual_var
->value()) {
89 LOG(ERROR
) << "expected: " << expected_var
->value()
90 << " actual: " << actual_var
->value();
95 case PP_VARTYPE_ARRAY_BUFFER
: {
96 ArrayBufferVar
* expected_var
= ArrayBufferVar::FromPPVar(expected
);
97 ArrayBufferVar
* actual_var
= ArrayBufferVar::FromPPVar(actual
);
98 DCHECK(expected_var
&& actual_var
);
99 if (expected_var
->ByteLength() != actual_var
->ByteLength()) {
100 LOG(ERROR
) << "expected: " << expected_var
->ByteLength()
101 << " actual: " << actual_var
->ByteLength();
104 if (memcmp(expected_var
->Map(),
106 expected_var
->ByteLength()) != 0) {
107 LOG(ERROR
) << "expected array buffer does not match actual.";
112 case PP_VARTYPE_ARRAY
: {
113 ArrayVar
* expected_var
= ArrayVar::FromPPVar(expected
);
114 ArrayVar
* actual_var
= ArrayVar::FromPPVar(actual
);
115 DCHECK(expected_var
&& actual_var
);
116 if (expected_var
->elements().size() != actual_var
->elements().size()) {
117 LOG(ERROR
) << "expected: " << expected_var
->elements().size()
118 << " actual: " << actual_var
->elements().size();
121 for (size_t i
= 0; i
< expected_var
->elements().size(); ++i
) {
122 if (!Equals(expected_var
->elements()[i
].get(),
123 actual_var
->elements()[i
].get(),
124 test_string_references
,
131 case PP_VARTYPE_DICTIONARY
: {
132 DictionaryVar
* expected_var
= DictionaryVar::FromPPVar(expected
);
133 DictionaryVar
* actual_var
= DictionaryVar::FromPPVar(actual
);
134 DCHECK(expected_var
&& actual_var
);
135 if (expected_var
->key_value_map().size() !=
136 actual_var
->key_value_map().size()) {
137 LOG(ERROR
) << "expected: " << expected_var
->key_value_map().size()
138 << " actual: " << actual_var
->key_value_map().size();
141 DictionaryVar::KeyValueMap::const_iterator expected_iter
=
142 expected_var
->key_value_map().begin();
143 DictionaryVar::KeyValueMap::const_iterator actual_iter
=
144 actual_var
->key_value_map().begin();
145 for (; expected_iter
!= expected_var
->key_value_map().end();
146 ++expected_iter
, ++actual_iter
) {
147 if (expected_iter
->first
!= actual_iter
->first
) {
148 LOG(ERROR
) << "expected: " << expected_iter
->first
149 << " actual: " << actual_iter
->first
;
152 if (!Equals(expected_iter
->second
.get(),
153 actual_iter
->second
.get(),
154 test_string_references
,
161 case PP_VARTYPE_RESOURCE
: {
162 ResourceVar
* expected_var
= ResourceVar::FromPPVar(expected
);
163 ResourceVar
* actual_var
= ResourceVar::FromPPVar(actual
);
164 DCHECK(expected_var
&& actual_var
);
165 if (expected_var
->GetPPResource() != actual_var
->GetPPResource()) {
166 LOG(ERROR
) << "expected: " << expected_var
->GetPPResource()
167 << " actual: " << actual_var
->GetPPResource();
171 const IPC::Message
* actual_message
= actual_var
->GetCreationMessage();
172 const IPC::Message
* expected_message
= expected_var
->GetCreationMessage();
173 if (expected_message
->size() != actual_message
->size()) {
174 LOG(ERROR
) << "expected creation message size: "
175 << expected_message
->size()
176 << " actual: " << actual_message
->size();
180 // Set the upper 24 bits of actual creation_message flags to the same as
181 // expected. This is an unpredictable reference number that changes
182 // between serialization/deserialization, and we do not want it to cause
183 // the comparison to fail.
184 IPC::Message
local_actual_message(*actual_message
);
185 local_actual_message
.SetHeaderValues(
186 actual_message
->routing_id(),
187 actual_message
->type(),
188 (expected_message
->flags() & 0xffffff00) |
189 (actual_message
->flags() & 0xff));
190 if (memcmp(expected_message
->data(),
191 local_actual_message
.data(),
192 expected_message
->size()) != 0) {
193 LOG(ERROR
) << "expected creation message does not match actual.";
205 bool TestEqual(const PP_Var
& expected
,
206 const PP_Var
& actual
,
207 bool test_string_references
) {
208 base::hash_map
<int64_t, int64_t> visited_map
;
209 return Equals(expected
, actual
, test_string_references
, &visited_map
);