Home | History | Annotate | Download | only in shared_impl
      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.
      4 
      5 #include "ppapi/shared_impl/unittest_utils.h"
      6 
      7 #include <cmath>
      8 
      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"
     17 
     18 namespace ppapi {
     19 
     20 namespace {
     21 
     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,
     27             const PP_Var& actual,
     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;
     33     return false;
     34   }
     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;
     42         return false;
     43       } else {
     44         return true;
     45       }
     46     } else {
     47       if (expected.type != PP_VARTYPE_STRING || test_string_references)
     48         (*visited_map)[expected.value.as_id] = actual.value.as_id;
     49     }
     50   }
     51   switch (expected.type) {
     52     case PP_VARTYPE_UNDEFINED:
     53       return true;
     54     case PP_VARTYPE_NULL:
     55       return true;
     56     case PP_VARTYPE_BOOL:
     57       if (expected.value.as_bool != actual.value.as_bool) {
     58         LOG(ERROR) << "expected: " << expected.value.as_bool
     59                    << " actual: " << actual.value.as_bool;
     60         return false;
     61       }
     62       return true;
     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;
     67         return false;
     68       }
     69       return true;
     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;
     74         return false;
     75       }
     76       return true;
     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;
     81         return false;
     82       }
     83       return true;
     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();
     91         return false;
     92       }
     93       return true;
     94     }
     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();
    102         return false;
    103       }
    104       if (memcmp(expected_var->Map(),
    105                  actual_var->Map(),
    106                  expected_var->ByteLength()) != 0) {
    107         LOG(ERROR) << "expected array buffer does not match actual.";
    108         return false;
    109       }
    110       return true;
    111     }
    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();
    119         return false;
    120       }
    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,
    125                     visited_map)) {
    126           return false;
    127         }
    128       }
    129       return true;
    130     }
    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();
    139         return false;
    140       }
    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;
    150           return false;
    151         }
    152         if (!Equals(expected_iter->second.get(),
    153                     actual_iter->second.get(),
    154                     test_string_references,
    155                     visited_map)) {
    156           return false;
    157         }
    158       }
    159       return true;
    160     }
    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();
    168         return false;
    169       }
    170 
    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();
    177         return false;
    178       }
    179 
    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.";
    194         return false;
    195       }
    196       return true;
    197     }
    198   }
    199   NOTREACHED();
    200   return false;
    201 }
    202 
    203 }  // namespace
    204 
    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);
    210 }
    211 
    212 }  // namespace ppapi
    213