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 "ppapi/shared_impl/array_var.h"
12 #include "ppapi/shared_impl/dictionary_var.h"
13 #include "ppapi/shared_impl/resource_var.h"
14 #include "ppapi/shared_impl/var.h"
15 #include "ppapi/shared_impl/var_tracker.h"
21 // When two vars x and y are found to be equal, an entry is inserted into
22 // |visited_map| with (x.value.as_id, y.value.as_id). This allows reference
23 // cycles to be avoided. It also allows us to associate nodes in |expected| with
24 // nodes in |actual| and check whether the graphs have equivalent topology.
25 bool Equals(const PP_Var
& expected
,
27 base::hash_map
<int64_t, int64_t>* visited_map
) {
28 if (expected
.type
!= actual
.type
) {
29 LOG(ERROR
) << "expected type: " << expected
.type
<<
30 " actual type: " << actual
.type
;
33 if (VarTracker::IsVarTypeRefcounted(expected
.type
)) {
34 base::hash_map
<int64_t, int64_t>::iterator it
=
35 visited_map
->find(expected
.value
.as_id
);
36 if (it
!= visited_map
->end()) {
37 if (it
->second
!= actual
.value
.as_id
) {
38 LOG(ERROR
) << "expected id: " << it
->second
<< " actual id: " <<
45 (*visited_map
)[expected
.value
.as_id
] = actual
.value
.as_id
;
48 switch (expected
.type
) {
49 case PP_VARTYPE_UNDEFINED
:
54 if (expected
.value
.as_bool
!= actual
.value
.as_bool
) {
55 LOG(ERROR
) << "expected: " << expected
.value
.as_bool
<< " actual: " <<
60 case PP_VARTYPE_INT32
:
61 if (expected
.value
.as_int
!= actual
.value
.as_int
) {
62 LOG(ERROR
) << "expected: " << expected
.value
.as_int
<< " actual: " <<
67 case PP_VARTYPE_DOUBLE
:
68 if (fabs(expected
.value
.as_double
- actual
.value
.as_double
) > 1.0e-4) {
69 LOG(ERROR
) << "expected: " << expected
.value
.as_double
<<
70 " actual: " << actual
.value
.as_double
;
74 case PP_VARTYPE_OBJECT
:
75 if (expected
.value
.as_id
!= actual
.value
.as_id
) {
76 LOG(ERROR
) << "expected: " << expected
.value
.as_id
<< " actual: " <<
81 case PP_VARTYPE_STRING
: {
82 StringVar
* expected_var
= StringVar::FromPPVar(expected
);
83 StringVar
* actual_var
= StringVar::FromPPVar(actual
);
84 DCHECK(expected_var
&& actual_var
);
85 if (expected_var
->value() != actual_var
->value()) {
86 LOG(ERROR
) << "expected: " << expected_var
->value() << " actual: " <<
92 case PP_VARTYPE_ARRAY_BUFFER
: {
93 ArrayBufferVar
* expected_var
= ArrayBufferVar::FromPPVar(expected
);
94 ArrayBufferVar
* actual_var
= ArrayBufferVar::FromPPVar(actual
);
95 DCHECK(expected_var
&& actual_var
);
96 if (expected_var
->ByteLength() != actual_var
->ByteLength()) {
97 LOG(ERROR
) << "expected: " << expected_var
->ByteLength() <<
98 " actual: " << actual_var
->ByteLength();
101 if (memcmp(expected_var
->Map(), actual_var
->Map(),
102 expected_var
->ByteLength()) != 0) {
103 LOG(ERROR
) << "expected array buffer does not match actual.";
108 case PP_VARTYPE_ARRAY
: {
109 ArrayVar
* expected_var
= ArrayVar::FromPPVar(expected
);
110 ArrayVar
* actual_var
= ArrayVar::FromPPVar(actual
);
111 DCHECK(expected_var
&& actual_var
);
112 if (expected_var
->elements().size() != actual_var
->elements().size()) {
113 LOG(ERROR
) << "expected: " << expected_var
->elements().size() <<
114 " actual: " << actual_var
->elements().size();
117 for (size_t i
= 0; i
< expected_var
->elements().size(); ++i
) {
118 if (!Equals(expected_var
->elements()[i
].get(),
119 actual_var
->elements()[i
].get(),
126 case PP_VARTYPE_DICTIONARY
: {
127 DictionaryVar
* expected_var
= DictionaryVar::FromPPVar(expected
);
128 DictionaryVar
* actual_var
= DictionaryVar::FromPPVar(actual
);
129 DCHECK(expected_var
&& actual_var
);
130 if (expected_var
->key_value_map().size() !=
131 actual_var
->key_value_map().size()) {
132 LOG(ERROR
) << "expected: " << expected_var
->key_value_map().size() <<
133 " actual: " << actual_var
->key_value_map().size();
136 DictionaryVar::KeyValueMap::const_iterator expected_iter
=
137 expected_var
->key_value_map().begin();
138 DictionaryVar::KeyValueMap::const_iterator actual_iter
=
139 actual_var
->key_value_map().begin();
140 for ( ; expected_iter
!= expected_var
->key_value_map().end();
141 ++expected_iter
, ++actual_iter
) {
142 if (expected_iter
->first
!= actual_iter
->first
) {
143 LOG(ERROR
) << "expected: " << expected_iter
->first
<<
144 " actual: " << actual_iter
->first
;
147 if (!Equals(expected_iter
->second
.get(),
148 actual_iter
->second
.get(),
155 case PP_VARTYPE_RESOURCE
: {
156 ResourceVar
* expected_var
= ResourceVar::FromPPVar(expected
);
157 ResourceVar
* actual_var
= ResourceVar::FromPPVar(actual
);
158 DCHECK(expected_var
&& actual_var
);
159 if (expected_var
->pp_resource() != actual_var
->pp_resource()) {
160 LOG(ERROR
) << "expected: " << expected_var
->pp_resource() << " actual: "
161 << actual_var
->pp_resource();
164 IPC::Message
actual_message(actual_var
->creation_message());
165 const IPC::Message
& expected_message
= expected_var
->creation_message();
166 if (expected_message
.size() != actual_message
.size()) {
167 LOG(ERROR
) << "expected creation message size: "
168 << expected_message
.size() << " actual: "
169 << actual_message
.size();
173 // Set the upper 24 bits of actual creation_message flags to the same as
174 // expected. This is an unpredictable reference number that changes
175 // between serialization/deserialization, and we do not want it to cause
176 // the comparison to fail.
177 actual_message
.SetHeaderValues(actual_message
.routing_id(),
178 actual_message
.type(),
179 (expected_message
.flags() & 0xffffff00) |
180 (actual_message
.flags() & 0xff));
181 if (memcmp(expected_message
.data(), actual_message
.data(),
182 expected_message
.size()) != 0) {
183 LOG(ERROR
) << "expected creation message does not match actual.";
195 bool TestEqual(const PP_Var
& expected
, const PP_Var
& actual
) {
196 base::hash_map
<int64_t, int64_t> visited_map
;
197 return Equals(expected
, actual
, &visited_map
);