Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012 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/proxy/raw_var_data.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/memory/ref_counted.h" | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/values.h" | |
| 11 #include "ppapi/c/pp_bool.h" | |
| 12 #include "ppapi/c/pp_var.h" | |
| 13 #include "ppapi/shared_impl/array_var.h" | |
| 14 #include "ppapi/shared_impl/dictionary_var.h" | |
| 15 #include "ppapi/shared_impl/ppapi_globals.h" | |
| 16 #include "ppapi/shared_impl/proxy_lock.h" | |
| 17 #include "ppapi/shared_impl/scoped_pp_var.h" | |
| 18 #include "ppapi/shared_impl/test_globals.h" | |
| 19 #include "ppapi/shared_impl/var.h" | |
| 20 #include "ppapi/shared_impl/var_tracker.h" | |
| 21 #include "testing/gtest/include/gtest/gtest.h" | |
| 22 | |
| 23 namespace ppapi { | |
| 24 namespace proxy { | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 class RawVarDataTest : public testing::Test { | |
| 29 public: | |
| 30 RawVarDataTest() {} | |
| 31 ~RawVarDataTest() {} | |
| 32 | |
| 33 // testing::Test implementation. | |
| 34 virtual void SetUp() { | |
| 35 ProxyLock::Acquire(); | |
| 36 } | |
| 37 virtual void TearDown() { | |
| 38 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); | |
| 39 ProxyLock::Release(); | |
| 40 } | |
| 41 | |
| 42 private: | |
| 43 TestGlobals globals_; | |
| 44 }; | |
| 45 | |
| 46 bool Equals(const PP_Var& expected, | |
| 47 const PP_Var& actual, | |
| 48 base::hash_map<int64_t, int64_t>* visited_map) { | |
|
dmichael (off chromium)
2013/04/16 16:36:53
May be worth a comment... it seems visited_map is
raymes1
2013/04/16 18:27:19
Done.
| |
| 49 if (expected.type != actual.type) | |
| 50 return false; | |
| 51 if (VarTracker::IsVarTypeRefcounted(expected.type)) { | |
| 52 base::hash_map<int64_t, int64_t>::iterator it = | |
| 53 visited_map->find(expected.value.as_id); | |
| 54 if (it != visited_map->end()) | |
| 55 return it->second == actual.value.as_id; | |
| 56 else | |
| 57 (*visited_map)[expected.value.as_id] = actual.value.as_id; | |
| 58 } | |
| 59 switch (expected.type) { | |
| 60 case PP_VARTYPE_UNDEFINED: | |
| 61 return true; | |
| 62 case PP_VARTYPE_NULL: | |
| 63 return true; | |
| 64 case PP_VARTYPE_BOOL: | |
| 65 return expected.value.as_bool == actual.value.as_bool; | |
| 66 case PP_VARTYPE_INT32: | |
| 67 return expected.value.as_int == actual.value.as_int; | |
| 68 case PP_VARTYPE_DOUBLE: | |
| 69 return expected.value.as_double == actual.value.as_double; | |
| 70 case PP_VARTYPE_OBJECT: | |
| 71 return expected.value.as_id == actual.value.as_id; | |
|
dmichael (off chromium)
2013/04/16 16:36:53
This could be a DCHECK instead, right?
raymes1
2013/04/16 18:27:19
Not sure exactly what you mean? In the old code, t
dmichael (off chromium)
2013/04/16 18:41:20
You're right, nevermind. Was confused because we d
| |
| 72 case PP_VARTYPE_STRING: { | |
| 73 StringVar* expected_var = StringVar::FromPPVar(expected); | |
| 74 StringVar* actual_var = StringVar::FromPPVar(actual); | |
| 75 if (!expected_var || !actual_var) | |
| 76 return expected_var == actual_var; | |
|
dmichael (off chromium)
2013/04/16 16:36:53
Since we want to bail for invalid Vars, should thi
raymes1
2013/04/16 18:27:19
Good idea this was a remnant from when I handled t
| |
| 77 return expected_var->value() == expected_var->value(); | |
| 78 } | |
| 79 case PP_VARTYPE_ARRAY_BUFFER: { | |
| 80 ArrayBufferVar* expected_var = ArrayBufferVar::FromPPVar(expected); | |
| 81 ArrayBufferVar* actual_var = ArrayBufferVar::FromPPVar(actual); | |
| 82 if (!expected_var || !actual_var) | |
| 83 return expected_var == actual_var; | |
| 84 std::string expected_data(static_cast<const char*>(expected_var->Map()), | |
| 85 expected_var->ByteLength()); | |
| 86 std::string actual_data(static_cast<const char*>(actual_var->Map()), | |
| 87 actual_var->ByteLength()); | |
| 88 return expected_data == actual_data; | |
|
dmichael (off chromium)
2013/04/16 16:36:53
Optional: It feels a little odd to copy them just
raymes1
2013/04/16 18:27:19
haha I avoid C memory functions like the plague an
dmichael (off chromium)
2013/04/16 18:41:20
I almost suggested std::equal, but you would have
| |
| 89 } | |
| 90 case PP_VARTYPE_ARRAY: { | |
| 91 ArrayVar* expected_var = ArrayVar::FromPPVar(expected); | |
| 92 ArrayVar* actual_var = ArrayVar::FromPPVar(actual); | |
| 93 if (!expected_var || !actual_var) | |
| 94 return expected_var == actual_var; | |
| 95 if (expected_var->elements().size() != actual_var->elements().size()) | |
| 96 return false; | |
| 97 for (size_t i = 0; i < expected_var->elements().size(); ++i) { | |
| 98 if (!Equals(expected_var->elements()[i].get(), | |
| 99 actual_var->elements()[i].get(), | |
| 100 visited_map)) { | |
| 101 return false; | |
| 102 } | |
| 103 } | |
| 104 return true; | |
| 105 } | |
| 106 case PP_VARTYPE_DICTIONARY: { | |
| 107 DictionaryVar* expected_var = DictionaryVar::FromPPVar(expected); | |
| 108 DictionaryVar* actual_var = DictionaryVar::FromPPVar(actual); | |
| 109 if (!expected_var || !actual_var) | |
| 110 return expected_var == actual_var; | |
| 111 if (expected_var->key_value_map().size() != | |
| 112 actual_var->key_value_map().size()) | |
| 113 return false; | |
| 114 DictionaryVar::KeyValueMap::const_iterator expected_iter = | |
| 115 expected_var->key_value_map().begin(); | |
| 116 DictionaryVar::KeyValueMap::const_iterator actual_iter = | |
| 117 actual_var->key_value_map().begin(); | |
| 118 for ( ; expected_iter != expected_var->key_value_map().end() && | |
| 119 actual_iter != actual_var->key_value_map().end(); | |
|
dmichael (off chromium)
2013/04/16 16:36:53
nit/suggestion: you don't really need to bounds ch
raymes1
2013/04/16 18:27:19
Done.
| |
| 120 ++expected_iter, ++actual_iter) { | |
| 121 if (expected_iter->first != actual_iter->first) | |
| 122 return false; | |
| 123 if (!Equals(expected_iter->second.get(), | |
| 124 actual_iter->second.get(), | |
| 125 visited_map)) { | |
| 126 return false; | |
| 127 } | |
| 128 } | |
| 129 return true; | |
| 130 } | |
| 131 } | |
| 132 NOTREACHED(); | |
| 133 return false; | |
| 134 } | |
|
dmichael (off chromium)
2013/04/16 16:36:53
Optional suggestion: You might want to have loggin
raymes1
2013/04/16 18:27:19
Ok - it's a good suggestion but I just added a TOD
| |
| 135 | |
| 136 bool Equals(const PP_Var& expected, | |
| 137 const PP_Var& actual) { | |
| 138 base::hash_map<int64_t, int64_t> visited_map; | |
| 139 return Equals(expected, actual, &visited_map); | |
| 140 } | |
| 141 | |
| 142 PP_Var WriteAndRead(const PP_Var& var) { | |
| 143 PP_Instance dummy_instance = 1234; | |
| 144 scoped_ptr<RawVarDataGraph> expected_data(RawVarDataGraph::Create( | |
| 145 var, dummy_instance)); | |
| 146 IPC::Message m; | |
| 147 expected_data->Write(&m); | |
| 148 PickleIterator iter(m); | |
| 149 scoped_ptr<RawVarDataGraph> actual_data(RawVarDataGraph::Read(&m, &iter)); | |
| 150 return actual_data->CreatePPVar(dummy_instance); | |
| 151 } | |
| 152 | |
| 153 // Assumes a ref for var. | |
| 154 bool WriteReadAndCompare(const PP_Var& var) { | |
| 155 ScopedPPVar expected(ScopedPPVar::PassRef(), var); | |
| 156 ScopedPPVar actual(ScopedPPVar::PassRef(), WriteAndRead(expected.get())); | |
| 157 return Equals(expected.get(), actual.get()); | |
| 158 } | |
| 159 | |
| 160 } // namespace | |
| 161 | |
| 162 TEST_F(RawVarDataTest, SimpleTest) { | |
| 163 EXPECT_TRUE(WriteReadAndCompare(PP_MakeUndefined())); | |
| 164 EXPECT_TRUE(WriteReadAndCompare(PP_MakeNull())); | |
| 165 EXPECT_TRUE(WriteReadAndCompare(PP_MakeInt32(100))); | |
| 166 EXPECT_TRUE(WriteReadAndCompare(PP_MakeBool(PP_TRUE))); | |
| 167 EXPECT_TRUE(WriteReadAndCompare(PP_MakeDouble(53.75))); | |
| 168 PP_Var object; | |
| 169 object.type = PP_VARTYPE_OBJECT; | |
| 170 object.value.as_id = 10; | |
| 171 EXPECT_TRUE(WriteReadAndCompare(object)); | |
| 172 } | |
| 173 | |
| 174 TEST_F(RawVarDataTest, StringTest) { | |
| 175 EXPECT_TRUE(WriteReadAndCompare(StringVar::StringToPPVar(""))); | |
| 176 EXPECT_TRUE(WriteReadAndCompare(StringVar::StringToPPVar("hello world!"))); | |
| 177 } | |
| 178 | |
| 179 TEST_F(RawVarDataTest, ArrayBufferTest) { | |
| 180 std::string data = "hello world!"; | |
| 181 PP_Var var = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( | |
| 182 data.size(), data.data()); | |
| 183 EXPECT_TRUE(WriteReadAndCompare(var)); | |
| 184 var = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( | |
| 185 0, static_cast<void*>(NULL)); | |
| 186 EXPECT_TRUE(WriteReadAndCompare(var)); | |
| 187 // TODO(raymes): add tests for shmem type array buffers. | |
| 188 } | |
| 189 | |
| 190 TEST_F(RawVarDataTest, DictionaryArrayTest) { | |
| 191 // Empty array. | |
| 192 scoped_refptr<ArrayVar> array(new ArrayVar); | |
| 193 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); | |
| 194 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); | |
| 195 | |
| 196 size_t index = 0; | |
| 197 | |
| 198 // Array with primitives. | |
| 199 array->Set(index++, PP_MakeUndefined()); | |
| 200 array->Set(index++, PP_MakeNull()); | |
| 201 array->Set(index++, PP_MakeInt32(100)); | |
| 202 array->Set(index++, PP_MakeBool(PP_FALSE)); | |
| 203 array->Set(index++, PP_MakeDouble(0.123)); | |
| 204 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); | |
| 205 | |
| 206 // Empty dictionary. | |
| 207 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar); | |
| 208 ScopedPPVar release_dictionary(ScopedPPVar::PassRef(), | |
| 209 dictionary->GetPPVar()); | |
| 210 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar())); | |
| 211 | |
| 212 // Dictionary with primitives. | |
| 213 ScopedPPVar key1(ScopedPPVar::PassRef(), StringVar::StringToPPVar("1")); | |
| 214 dictionary->Set(key1.get(), PP_MakeUndefined()); | |
| 215 ScopedPPVar key2(ScopedPPVar::PassRef(), StringVar::StringToPPVar("2")); | |
| 216 dictionary->Set(key2.get(), PP_MakeNull()); | |
| 217 ScopedPPVar key3(ScopedPPVar::PassRef(), StringVar::StringToPPVar("3")); | |
| 218 dictionary->Set(key3.get(), PP_MakeInt32(-100)); | |
| 219 ScopedPPVar key4(ScopedPPVar::PassRef(), StringVar::StringToPPVar("4")); | |
| 220 dictionary->Set(key4.get(), PP_MakeBool(PP_TRUE)); | |
| 221 ScopedPPVar key5(ScopedPPVar::PassRef(), StringVar::StringToPPVar("5")); | |
| 222 dictionary->Set(key5.get(), PP_MakeDouble(-103.52)); | |
| 223 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar())); | |
| 224 | |
| 225 // Array with dictionary. | |
| 226 array->Set(index++, release_dictionary.get()); | |
| 227 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); | |
| 228 | |
| 229 // Array with dictionary with array. | |
| 230 scoped_refptr<ArrayVar> array2(new ArrayVar); | |
| 231 ScopedPPVar release_array2(ScopedPPVar::PassRef(), array2->GetPPVar()); | |
| 232 array2->Set(0, PP_MakeInt32(100)); | |
| 233 ScopedPPVar key6(ScopedPPVar::PassRef(), StringVar::StringToPPVar("6")); | |
| 234 dictionary->Set(key6.get(), release_array2.get()); | |
| 235 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); | |
| 236 | |
| 237 // Array <-> dictionary cycle. | |
| 238 ScopedPPVar key7(ScopedPPVar::PassRef(), StringVar::StringToPPVar("7")); | |
| 239 dictionary->Set(key7.get(), release_array.get()); | |
| 240 ScopedPPVar result = ScopedPPVar(ScopedPPVar::PassRef(), | |
| 241 WriteAndRead(release_dictionary.get())); | |
| 242 EXPECT_TRUE(Equals(release_dictionary.get(), result.get())); | |
| 243 // Break the cycle. | |
|
dmichael (off chromium)
2013/04/16 16:36:53
This is because we'll leak it otherwise?
I feel l
raymes1
2013/04/16 18:27:19
Yes we leak otherwise. I agree. We need to provide
| |
| 244 dictionary->Delete(key7.get()); | |
| 245 DictionaryVar* result_dictionary = DictionaryVar::FromPPVar(result.get()); | |
| 246 result_dictionary->Delete(key7.get()); | |
| 247 | |
| 248 // Array with self references. | |
| 249 array->Set(index, release_array.get()); | |
| 250 result = ScopedPPVar(ScopedPPVar::PassRef(), | |
| 251 WriteAndRead(release_array.get())); | |
| 252 EXPECT_TRUE(Equals(release_array.get(), result.get())); | |
| 253 // Break the self reference. | |
| 254 array->Set(index, PP_MakeUndefined()); | |
| 255 ArrayVar* result_array = ArrayVar::FromPPVar(result.get()); | |
| 256 result_array->Set(index, PP_MakeUndefined()); | |
| 257 } | |
|
dmichael (off chromium)
2013/04/16 16:36:53
How about a test where one direct child references
raymes1
2013/04/16 18:27:19
Good idea. I also forgot to add a test for the sim
| |
| 258 | |
| 259 } // namespace proxy | |
| 260 } // namespace ppapi | |
| OLD | NEW |