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/resource_var.h" 18#include "ppapi/shared_impl/scoped_pp_var.h" 19#include "ppapi/shared_impl/test_globals.h" 20#include "ppapi/shared_impl/unittest_utils.h" 21#include "ppapi/shared_impl/var.h" 22#include "ppapi/shared_impl/var_tracker.h" 23#include "testing/gtest/include/gtest/gtest.h" 24 25namespace ppapi { 26namespace proxy { 27 28namespace { 29 30void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) { 31 IPC::ParamTraits<SerializedHandle>::Write(m, handle); 32} 33 34class RawVarDataTest : public testing::Test { 35 public: 36 RawVarDataTest() {} 37 ~RawVarDataTest() {} 38 39 // testing::Test implementation. 40 virtual void SetUp() { 41 ProxyLock::EnableLockingOnThreadForTest(); 42 ProxyLock::Acquire(); 43 } 44 virtual void TearDown() { 45 ASSERT_TRUE(PpapiGlobals::Get()->GetVarTracker()->GetLiveVars().empty()); 46 ProxyLock::Release(); 47 } 48 49 private: 50 TestGlobals globals_; 51}; 52 53bool WriteAndRead(const PP_Var& var, PP_Var* result) { 54 PP_Instance dummy_instance = 1234; 55 scoped_ptr<RawVarDataGraph> expected_data(RawVarDataGraph::Create( 56 var, dummy_instance)); 57 if (!expected_data) 58 return false; 59 IPC::Message m; 60 expected_data->Write(&m, base::Bind(&DefaultHandleWriter)); 61 PickleIterator iter(m); 62 scoped_ptr<RawVarDataGraph> actual_data(RawVarDataGraph::Read(&m, &iter)); 63 *result = actual_data->CreatePPVar(dummy_instance); 64 return true; 65} 66 67// Assumes a ref for var. 68bool WriteReadAndCompare(const PP_Var& var) { 69 ScopedPPVar expected(ScopedPPVar::PassRef(), var); 70 PP_Var result; 71 bool success = WriteAndRead(expected.get(), &result); 72 if (!success) 73 return false; 74 ScopedPPVar actual(ScopedPPVar::PassRef(), result); 75 return TestEqual(expected.get(), actual.get(), true); 76} 77 78} // namespace 79 80TEST_F(RawVarDataTest, SimpleTest) { 81 EXPECT_TRUE(WriteReadAndCompare(PP_MakeUndefined())); 82 EXPECT_TRUE(WriteReadAndCompare(PP_MakeNull())); 83 EXPECT_TRUE(WriteReadAndCompare(PP_MakeInt32(100))); 84 EXPECT_TRUE(WriteReadAndCompare(PP_MakeBool(PP_TRUE))); 85 EXPECT_TRUE(WriteReadAndCompare(PP_MakeDouble(53.75))); 86 PP_Var object; 87 object.type = PP_VARTYPE_OBJECT; 88 object.value.as_id = 10; 89 EXPECT_TRUE(WriteReadAndCompare(object)); 90} 91 92TEST_F(RawVarDataTest, StringTest) { 93 EXPECT_TRUE(WriteReadAndCompare(StringVar::StringToPPVar(""))); 94 EXPECT_TRUE(WriteReadAndCompare(StringVar::StringToPPVar("hello world!"))); 95} 96 97TEST_F(RawVarDataTest, ArrayBufferTest) { 98 std::string data = "hello world!"; 99 PP_Var var = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( 100 data.size(), data.data()); 101 EXPECT_TRUE(WriteReadAndCompare(var)); 102 var = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( 103 0, static_cast<void*>(NULL)); 104 EXPECT_TRUE(WriteReadAndCompare(var)); 105 // TODO(raymes): add tests for shmem type array buffers. 106} 107 108TEST_F(RawVarDataTest, DictionaryArrayTest) { 109 // Empty array. 110 scoped_refptr<ArrayVar> array(new ArrayVar); 111 ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); 112 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); 113 114 size_t index = 0; 115 116 // Array with primitives. 117 array->Set(index++, PP_MakeUndefined()); 118 array->Set(index++, PP_MakeNull()); 119 array->Set(index++, PP_MakeInt32(100)); 120 array->Set(index++, PP_MakeBool(PP_FALSE)); 121 array->Set(index++, PP_MakeDouble(0.123)); 122 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); 123 124 // Array with 2 references to the same string. 125 ScopedPPVar release_string( 126 ScopedPPVar::PassRef(), StringVar::StringToPPVar("abc")); 127 array->Set(index++, release_string.get()); 128 array->Set(index++, release_string.get()); 129 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); 130 131 // Array with nested array that references the same string. 132 scoped_refptr<ArrayVar> array2(new ArrayVar); 133 ScopedPPVar release_array2(ScopedPPVar::PassRef(), array2->GetPPVar()); 134 array2->Set(0, release_string.get()); 135 array->Set(index++, release_array2.get()); 136 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); 137 138 // Empty dictionary. 139 scoped_refptr<DictionaryVar> dictionary(new DictionaryVar); 140 ScopedPPVar release_dictionary(ScopedPPVar::PassRef(), 141 dictionary->GetPPVar()); 142 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar())); 143 144 // Dictionary with primitives. 145 dictionary->SetWithStringKey("1", PP_MakeUndefined()); 146 dictionary->SetWithStringKey("2", PP_MakeNull()); 147 dictionary->SetWithStringKey("3", PP_MakeInt32(-100)); 148 dictionary->SetWithStringKey("4", PP_MakeBool(PP_TRUE)); 149 dictionary->SetWithStringKey("5", PP_MakeDouble(-103.52)); 150 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar())); 151 152 // Dictionary with 2 references to the same string. 153 dictionary->SetWithStringKey("6", release_string.get()); 154 dictionary->SetWithStringKey("7", release_string.get()); 155 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar())); 156 157 // Dictionary with nested dictionary that references the same string. 158 scoped_refptr<DictionaryVar> dictionary2(new DictionaryVar); 159 ScopedPPVar release_dictionary2(ScopedPPVar::PassRef(), 160 dictionary2->GetPPVar()); 161 dictionary2->SetWithStringKey("abc", release_string.get()); 162 dictionary->SetWithStringKey("8", release_dictionary2.get()); 163 EXPECT_TRUE(WriteReadAndCompare(dictionary->GetPPVar())); 164 165 // Array with dictionary. 166 array->Set(index++, release_dictionary.get()); 167 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); 168 169 // Array with dictionary with array. 170 array2->Set(0, PP_MakeInt32(100)); 171 dictionary->SetWithStringKey("9", release_array2.get()); 172 EXPECT_TRUE(WriteReadAndCompare(array->GetPPVar())); 173 174 // Array <-> dictionary cycle. 175 dictionary->SetWithStringKey("10", release_array.get()); 176 PP_Var result; 177 ASSERT_FALSE(WriteAndRead(release_dictionary.get(), &result)); 178 // Break the cycle. 179 // TODO(raymes): We need some better machinery for releasing vars with 180 // cycles. Remove the code below once we have that. 181 dictionary->DeleteWithStringKey("10"); 182 183 // Array with self references. 184 array->Set(index, release_array.get()); 185 ASSERT_FALSE(WriteAndRead(release_array.get(), &result)); 186 // Break the self reference. 187 array->Set(index, PP_MakeUndefined()); 188} 189 190TEST_F(RawVarDataTest, ResourceTest) { 191 // TODO(mgiuca): This test passes trivially, since GetVarTracker() returns a 192 // TestVarTracker which returns a null PP_Var. 193 ScopedPPVar resource( 194 ScopedPPVar::PassRef(), 195 PpapiGlobals::Get()->GetVarTracker()->MakeResourcePPVar(34)); 196 EXPECT_TRUE(WriteReadAndCompare(resource.get())); 197 198 // TODO(mgiuca): Test a host resource with an IPC::Message. It is currently a 199 // checkfail to deserialize such a resource. 200} 201 202} // namespace proxy 203} // namespace ppapi 204