diff options
author | raymes@chromium.org <raymes@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-15 16:09:32 +0000 |
---|---|---|
committer | raymes@chromium.org <raymes@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-15 16:09:32 +0000 |
commit | f55538030498151e8031e4593d900fe9a0f46417 (patch) | |
tree | fb5b06c820b7dfd0fff393b26b06c20320d562a4 /ppapi | |
parent | c061a3b6200597a2d852a84ebb6623573f8c8b48 (diff) | |
download | chromium_src-f55538030498151e8031e4593d900fe9a0f46417.zip chromium_src-f55538030498151e8031e4593d900fe9a0f46417.tar.gz chromium_src-f55538030498151e8031e4593d900fe9a0f46417.tar.bz2 |
Implement a V8 value<->PP_Var converter
NOTE: This patch is being relanded after it was reverted in 199944 due to a unittest breakage, fixed by 200279.
This implements a converter for transforming between V8 values and PP_Vars. This is needed to support transferring arrays/dictionaries (or arrays/objects in javascript) to and from the plugin using the pepper Post/HandleMessage APIs. The entire object graph is converted in the process.
TBR=darin@chromium.org
BUG=236958
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=199938
Review URL: https://chromiumcodereview.appspot.com/14424006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@200283 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
-rw-r--r-- | ppapi/ppapi_tests.gypi | 2 | ||||
-rw-r--r-- | ppapi/proxy/raw_var_data_unittest.cc | 156 | ||||
-rw-r--r-- | ppapi/shared_impl/unittest_utils.cc | 166 | ||||
-rw-r--r-- | ppapi/shared_impl/unittest_utils.h | 19 |
4 files changed, 191 insertions, 152 deletions
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi index ffd577f..3e5dbf1 100644 --- a/ppapi/ppapi_tests.gypi +++ b/ppapi/ppapi_tests.gypi @@ -101,6 +101,8 @@ 'proxy/resource_message_test_sink.h', 'shared_impl/test_globals.cc', 'shared_impl/test_globals.h', + 'shared_impl/unittest_utils.cc', + 'shared_impl/unittest_utils.h', ], }, diff --git a/ppapi/proxy/raw_var_data_unittest.cc b/ppapi/proxy/raw_var_data_unittest.cc index 8a00d21..2b134af 100644 --- a/ppapi/proxy/raw_var_data_unittest.cc +++ b/ppapi/proxy/raw_var_data_unittest.cc @@ -4,8 +4,6 @@ #include "ppapi/proxy/raw_var_data.h" -#include <cmath> - #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" @@ -18,6 +16,7 @@ #include "ppapi/shared_impl/proxy_lock.h" #include "ppapi/shared_impl/scoped_pp_var.h" #include "ppapi/shared_impl/test_globals.h" +#include "ppapi/shared_impl/unittest_utils.h" #include "ppapi/shared_impl/var.h" #include "ppapi/shared_impl/var_tracker.h" #include "testing/gtest/include/gtest/gtest.h" @@ -45,153 +44,6 @@ class RawVarDataTest : public testing::Test { TestGlobals globals_; }; -// Compares two vars for equality. When two vars are found to be equal, an entry -// is inserted into |visited_map| with (expected id, actual id). When comparing -// two PP_Vars that have a graph of references, this avoids following reference -// cycles. It also ensures that a var with ID x in the graph is always equal -// to a var with ID y. This guarantees that the topology of the two graphs -// being compared is identical. -bool Equals(const PP_Var& expected, - const PP_Var& actual, - base::hash_map<int64_t, int64_t>* visited_map) { - if (expected.type != actual.type) { - LOG(ERROR) << "expected type: " << expected.type << - " actual type: " << actual.type; - return false; - } - if (VarTracker::IsVarTypeRefcounted(expected.type)) { - base::hash_map<int64_t, int64_t>::iterator it = - visited_map->find(expected.value.as_id); - if (it != visited_map->end()) { - if (it->second != actual.value.as_id) { - LOG(ERROR) << "expected id: " << it->second << " actual id: " << - actual.value.as_id; - return false; - } else { - return true; - } - } else { - (*visited_map)[expected.value.as_id] = actual.value.as_id; - } - } - switch (expected.type) { - case PP_VARTYPE_UNDEFINED: - return true; - case PP_VARTYPE_NULL: - return true; - case PP_VARTYPE_BOOL: - if (expected.value.as_bool != actual.value.as_bool) { - LOG(ERROR) << "expected: " << expected.value.as_bool << " actual: " << - actual.value.as_bool; - return false; - } - return true; - case PP_VARTYPE_INT32: - if (expected.value.as_int != actual.value.as_int) { - LOG(ERROR) << "expected: " << expected.value.as_int << " actual: " << - actual.value.as_int; - return false; - } - return true; - case PP_VARTYPE_DOUBLE: - if (fabs(expected.value.as_double - actual.value.as_double) > 1.0e-4) { - LOG(ERROR) << "expected: " << expected.value.as_double << - " actual: " << actual.value.as_double; - return false; - } - return true; - case PP_VARTYPE_OBJECT: - if (expected.value.as_id != actual.value.as_id) { - LOG(ERROR) << "expected: " << expected.value.as_id << " actual: " << - actual.value.as_id; - return false; - } - return true; - case PP_VARTYPE_STRING: { - StringVar* expected_var = StringVar::FromPPVar(expected); - StringVar* actual_var = StringVar::FromPPVar(actual); - DCHECK(expected_var && actual_var); - if (expected_var->value() != actual_var->value()) { - LOG(ERROR) << "expected: " << expected_var->value() << " actual: " << - actual_var->value(); - return false; - } - return true; - } - case PP_VARTYPE_ARRAY_BUFFER: { - ArrayBufferVar* expected_var = ArrayBufferVar::FromPPVar(expected); - ArrayBufferVar* actual_var = ArrayBufferVar::FromPPVar(actual); - DCHECK(expected_var && actual_var); - if (expected_var->ByteLength() != actual_var->ByteLength()) { - LOG(ERROR) << "expected: " << expected_var->ByteLength() << - " actual: " << actual_var->ByteLength(); - return false; - } - if (memcmp(expected_var->Map(), actual_var->Map(), - expected_var->ByteLength()) != 0) { - LOG(ERROR) << "expected array buffer does not match actual."; - return false; - } - return true; - } - case PP_VARTYPE_ARRAY: { - ArrayVar* expected_var = ArrayVar::FromPPVar(expected); - ArrayVar* actual_var = ArrayVar::FromPPVar(actual); - DCHECK(expected_var && actual_var); - if (expected_var->elements().size() != actual_var->elements().size()) { - LOG(ERROR) << "expected: " << expected_var->elements().size() << - " actual: " << actual_var->elements().size(); - return false; - } - for (size_t i = 0; i < expected_var->elements().size(); ++i) { - if (!Equals(expected_var->elements()[i].get(), - actual_var->elements()[i].get(), - visited_map)) { - return false; - } - } - return true; - } - case PP_VARTYPE_DICTIONARY: { - DictionaryVar* expected_var = DictionaryVar::FromPPVar(expected); - DictionaryVar* actual_var = DictionaryVar::FromPPVar(actual); - DCHECK(expected_var && actual_var); - if (expected_var->key_value_map().size() != - actual_var->key_value_map().size()) { - LOG(ERROR) << "expected: " << expected_var->key_value_map().size() << - " actual: " << actual_var->key_value_map().size(); - return false; - } - DictionaryVar::KeyValueMap::const_iterator expected_iter = - expected_var->key_value_map().begin(); - DictionaryVar::KeyValueMap::const_iterator actual_iter = - actual_var->key_value_map().begin(); - for ( ; expected_iter != expected_var->key_value_map().end(); - ++expected_iter, ++actual_iter) { - if (expected_iter->first != actual_iter->first) { - LOG(ERROR) << "expected: " << expected_iter->first << - " actual: " << actual_iter->first; - return false; - } - if (!Equals(expected_iter->second.get(), - actual_iter->second.get(), - visited_map)) { - return false; - } - } - return true; - } - } - NOTREACHED(); - return false; -} - -bool Equals(const PP_Var& expected, - const PP_Var& actual) { - base::hash_map<int64_t, int64_t> visited_map; - return Equals(expected, actual, &visited_map); -} - PP_Var WriteAndRead(const PP_Var& var) { PP_Instance dummy_instance = 1234; scoped_ptr<RawVarDataGraph> expected_data(RawVarDataGraph::Create( @@ -207,7 +59,7 @@ PP_Var WriteAndRead(const PP_Var& var) { bool WriteReadAndCompare(const PP_Var& var) { ScopedPPVar expected(ScopedPPVar::PassRef(), var); ScopedPPVar actual(ScopedPPVar::PassRef(), WriteAndRead(expected.get())); - return Equals(expected.get(), actual.get()); + return TestEqual(expected.get(), actual.get()); } } // namespace @@ -310,7 +162,7 @@ TEST_F(RawVarDataTest, DictionaryArrayTest) { dictionary->SetWithStringKey("10", release_array.get()); ScopedPPVar result = ScopedPPVar(ScopedPPVar::PassRef(), WriteAndRead(release_dictionary.get())); - EXPECT_TRUE(Equals(release_dictionary.get(), result.get())); + EXPECT_TRUE(TestEqual(release_dictionary.get(), result.get())); // Break the cycle. // TODO(raymes): We need some better machinery for releasing vars with // cycles. Remove the code below once we have that. @@ -322,7 +174,7 @@ TEST_F(RawVarDataTest, DictionaryArrayTest) { array->Set(index, release_array.get()); result = ScopedPPVar(ScopedPPVar::PassRef(), WriteAndRead(release_array.get())); - EXPECT_TRUE(Equals(release_array.get(), result.get())); + EXPECT_TRUE(TestEqual(release_array.get(), result.get())); // Break the self reference. array->Set(index, PP_MakeUndefined()); ArrayVar* result_array = ArrayVar::FromPPVar(result.get()); diff --git a/ppapi/shared_impl/unittest_utils.cc b/ppapi/shared_impl/unittest_utils.cc new file mode 100644 index 0000000..2c32b30 --- /dev/null +++ b/ppapi/shared_impl/unittest_utils.cc @@ -0,0 +1,166 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/shared_impl/unittest_utils.h" + +#include <cmath> + +#include "base/hash_tables.h" +#include "base/logging.h" +#include "ppapi/shared_impl/array_var.h" +#include "ppapi/shared_impl/dictionary_var.h" +#include "ppapi/shared_impl/var.h" +#include "ppapi/shared_impl/var_tracker.h" + +namespace ppapi { + +namespace { + +// When two vars x and y are found to be equal, an entry is inserted into +// |visited_map| with (x.value.as_id, y.value.as_id). This allows reference +// cycles to be avoided. It also allows us to associate nodes in |expected| with +// nodes in |actual| and check whether the graphs have equivalent topology. +bool Equals(const PP_Var& expected, + const PP_Var& actual, + base::hash_map<int64_t, int64_t>* visited_map) { + if (expected.type != actual.type) { + LOG(ERROR) << "expected type: " << expected.type << + " actual type: " << actual.type; + return false; + } + if (VarTracker::IsVarTypeRefcounted(expected.type)) { + base::hash_map<int64_t, int64_t>::iterator it = + visited_map->find(expected.value.as_id); + if (it != visited_map->end()) { + if (it->second != actual.value.as_id) { + LOG(ERROR) << "expected id: " << it->second << " actual id: " << + actual.value.as_id; + return false; + } else { + return true; + } + } else { + (*visited_map)[expected.value.as_id] = actual.value.as_id; + } + } + switch (expected.type) { + case PP_VARTYPE_UNDEFINED: + return true; + case PP_VARTYPE_NULL: + return true; + case PP_VARTYPE_BOOL: + if (expected.value.as_bool != actual.value.as_bool) { + LOG(ERROR) << "expected: " << expected.value.as_bool << " actual: " << + actual.value.as_bool; + return false; + } + return true; + case PP_VARTYPE_INT32: + if (expected.value.as_int != actual.value.as_int) { + LOG(ERROR) << "expected: " << expected.value.as_int << " actual: " << + actual.value.as_int; + return false; + } + return true; + case PP_VARTYPE_DOUBLE: + if (fabs(expected.value.as_double - actual.value.as_double) > 1.0e-4) { + LOG(ERROR) << "expected: " << expected.value.as_double << + " actual: " << actual.value.as_double; + return false; + } + return true; + case PP_VARTYPE_OBJECT: + if (expected.value.as_id != actual.value.as_id) { + LOG(ERROR) << "expected: " << expected.value.as_id << " actual: " << + actual.value.as_id; + return false; + } + return true; + case PP_VARTYPE_STRING: { + StringVar* expected_var = StringVar::FromPPVar(expected); + StringVar* actual_var = StringVar::FromPPVar(actual); + DCHECK(expected_var && actual_var); + if (expected_var->value() != actual_var->value()) { + LOG(ERROR) << "expected: " << expected_var->value() << " actual: " << + actual_var->value(); + return false; + } + return true; + } + case PP_VARTYPE_ARRAY_BUFFER: { + ArrayBufferVar* expected_var = ArrayBufferVar::FromPPVar(expected); + ArrayBufferVar* actual_var = ArrayBufferVar::FromPPVar(actual); + DCHECK(expected_var && actual_var); + if (expected_var->ByteLength() != actual_var->ByteLength()) { + LOG(ERROR) << "expected: " << expected_var->ByteLength() << + " actual: " << actual_var->ByteLength(); + return false; + } + if (memcmp(expected_var->Map(), actual_var->Map(), + expected_var->ByteLength()) != 0) { + LOG(ERROR) << "expected array buffer does not match actual."; + return false; + } + return true; + } + case PP_VARTYPE_ARRAY: { + ArrayVar* expected_var = ArrayVar::FromPPVar(expected); + ArrayVar* actual_var = ArrayVar::FromPPVar(actual); + DCHECK(expected_var && actual_var); + if (expected_var->elements().size() != actual_var->elements().size()) { + LOG(ERROR) << "expected: " << expected_var->elements().size() << + " actual: " << actual_var->elements().size(); + return false; + } + for (size_t i = 0; i < expected_var->elements().size(); ++i) { + if (!Equals(expected_var->elements()[i].get(), + actual_var->elements()[i].get(), + visited_map)) { + return false; + } + } + return true; + } + case PP_VARTYPE_DICTIONARY: { + DictionaryVar* expected_var = DictionaryVar::FromPPVar(expected); + DictionaryVar* actual_var = DictionaryVar::FromPPVar(actual); + DCHECK(expected_var && actual_var); + if (expected_var->key_value_map().size() != + actual_var->key_value_map().size()) { + LOG(ERROR) << "expected: " << expected_var->key_value_map().size() << + " actual: " << actual_var->key_value_map().size(); + return false; + } + DictionaryVar::KeyValueMap::const_iterator expected_iter = + expected_var->key_value_map().begin(); + DictionaryVar::KeyValueMap::const_iterator actual_iter = + actual_var->key_value_map().begin(); + for ( ; expected_iter != expected_var->key_value_map().end(); + ++expected_iter, ++actual_iter) { + if (expected_iter->first != actual_iter->first) { + LOG(ERROR) << "expected: " << expected_iter->first << + " actual: " << actual_iter->first; + return false; + } + if (!Equals(expected_iter->second.get(), + actual_iter->second.get(), + visited_map)) { + return false; + } + } + return true; + } + } + NOTREACHED(); + return false; +} + +} // namespace + +bool TestEqual(const PP_Var& expected, const PP_Var& actual) { + base::hash_map<int64_t, int64_t> visited_map; + return Equals(expected, actual, &visited_map); +} + +} // namespace ppapi diff --git a/ppapi/shared_impl/unittest_utils.h b/ppapi/shared_impl/unittest_utils.h new file mode 100644 index 0000000..e07d8a8 --- /dev/null +++ b/ppapi/shared_impl/unittest_utils.h @@ -0,0 +1,19 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_SHARED_IMPL_UNITTEST_UTILS_H_ +#define PPAPI_SHARED_IMPL_UNITTEST_UTILS_H_ + +#include "ppapi/c/pp_var.h" + +namespace ppapi { + +// Compares two vars for equality. This is a deep comparison (the entire graph +// is traversed recursively). The function guarantees that the topology of the +// two PP_Var graphs being compared is identical, including graphs with cycles. +bool TestEqual(const PP_Var& expected, const PP_Var& actual); + +} // namespace ppapi + +#endif // PPAPI_SHARED_IMPL_UNITTEST_UTILS_H_ |