| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ppapi/tests/test_instance_deprecated.h" | 5 #include "ppapi/tests/test_instance_deprecated.h" |
| 6 | 6 |
| 7 #include <assert.h> |
| 8 |
| 9 #include "ppapi/c/ppb_var.h" |
| 7 #include "ppapi/cpp/module.h" | 10 #include "ppapi/cpp/module.h" |
| 8 #include "ppapi/cpp/dev/scriptable_object_deprecated.h" | 11 #include "ppapi/cpp/dev/scriptable_object_deprecated.h" |
| 9 #include "ppapi/tests/testing_instance.h" | 12 #include "ppapi/tests/testing_instance.h" |
| 10 | 13 |
| 11 namespace { | 14 namespace { |
| 12 | 15 |
| 13 static const char kSetValueFunction[] = "SetValue"; | 16 static const char kSetValueFunction[] = "SetValue"; |
| 14 static const char kSetExceptionFunction[] = "SetException"; | 17 static const char kSetExceptionFunction[] = "SetException"; |
| 15 static const char kReturnValueFunction[] = "ReturnValue"; | 18 static const char kReturnValueFunction[] = "ReturnValue"; |
| 16 | 19 |
| 17 // ScriptableObject used by instance. | 20 // ScriptableObject used by instance. |
| 18 class InstanceSO : public pp::deprecated::ScriptableObject { | 21 class InstanceSO : public pp::deprecated::ScriptableObject { |
| 19 public: | 22 public: |
| 20 InstanceSO(TestInstance* i) : test_instance_(i) {} | 23 InstanceSO(TestInstance* i); |
| 24 virtual ~InstanceSO(); |
| 21 | 25 |
| 22 // pp::deprecated::ScriptableObject overrides. | 26 // pp::deprecated::ScriptableObject overrides. |
| 23 bool HasMethod(const pp::Var& name, pp::Var* exception); | 27 bool HasMethod(const pp::Var& name, pp::Var* exception); |
| 24 pp::Var Call(const pp::Var& name, | 28 pp::Var Call(const pp::Var& name, |
| 25 const std::vector<pp::Var>& args, | 29 const std::vector<pp::Var>& args, |
| 26 pp::Var* exception); | 30 pp::Var* exception); |
| 27 | 31 |
| 28 private: | 32 private: |
| 29 TestInstance* test_instance_; | 33 TestInstance* test_instance_; |
| 30 }; | 34 }; |
| 31 | 35 |
| 36 InstanceSO::InstanceSO(TestInstance* i) : test_instance_(i) { |
| 37 // Set up a post-condition for the test so that we can ensure our destructor |
| 38 // is called. This only works in-process right now. Rather than disable the |
| 39 // whole test, we only do this check when running in-process. |
| 40 // TODO(dmichael): Figure out if we want this to work out-of-process, and if |
| 41 // so, fix it. Note that it might just be failing because the |
| 42 // ReleaseObject and Deallocate messages are asynchronous. |
| 43 if (i->testing_interface() && |
| 44 i->testing_interface()->IsOutOfProcess() == PP_FALSE) { |
| 45 i->instance()->AddPostCondition( |
| 46 "window.document.getElementById('container').instance_object_destroyed" |
| 47 ); |
| 48 } |
| 49 } |
| 50 |
| 51 InstanceSO::~InstanceSO() { |
| 52 pp::Var exception; |
| 53 pp::Var ret = test_instance_->instance()->ExecuteScript( |
| 54 "document.getElementById('container').instance_object_destroyed=true;"); |
| 55 } |
| 56 |
| 32 bool InstanceSO::HasMethod(const pp::Var& name, pp::Var* exception) { | 57 bool InstanceSO::HasMethod(const pp::Var& name, pp::Var* exception) { |
| 33 if (!name.is_string()) | 58 if (!name.is_string()) |
| 34 return false; | 59 return false; |
| 35 return name.AsString() == kSetValueFunction || | 60 return name.AsString() == kSetValueFunction || |
| 36 name.AsString() == kSetExceptionFunction || | 61 name.AsString() == kSetExceptionFunction || |
| 37 name.AsString() == kReturnValueFunction; | 62 name.AsString() == kReturnValueFunction; |
| 38 } | 63 } |
| 39 | 64 |
| 40 pp::Var InstanceSO::Call(const pp::Var& method_name, | 65 pp::Var InstanceSO::Call(const pp::Var& method_name, |
| 41 const std::vector<pp::Var>& args, | 66 const std::vector<pp::Var>& args, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 72 | 97 |
| 73 TestInstance::TestInstance(TestingInstance* instance) : TestCase(instance) { | 98 TestInstance::TestInstance(TestingInstance* instance) : TestCase(instance) { |
| 74 } | 99 } |
| 75 | 100 |
| 76 bool TestInstance::Init() { | 101 bool TestInstance::Init() { |
| 77 return true; | 102 return true; |
| 78 } | 103 } |
| 79 | 104 |
| 80 void TestInstance::RunTests(const std::string& filter) { | 105 void TestInstance::RunTests(const std::string& filter) { |
| 81 RUN_TEST(ExecuteScript, filter); | 106 RUN_TEST(ExecuteScript, filter); |
| 107 RUN_TEST(RecursiveObjects, filter); |
| 108 RUN_TEST(LeakedObjectDestructors, filter); |
| 109 } |
| 110 |
| 111 void TestInstance::LeakReferenceAndIgnore(const pp::Var& leaked) { |
| 112 static const PPB_Var* var_interface = static_cast<const PPB_Var*>( |
| 113 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE)); |
| 114 var_interface->AddRef(leaked.pp_var()); |
| 115 IgnoreLeakedVar(leaked.pp_var().value.as_id); |
| 82 } | 116 } |
| 83 | 117 |
| 84 pp::deprecated::ScriptableObject* TestInstance::CreateTestObject() { | 118 pp::deprecated::ScriptableObject* TestInstance::CreateTestObject() { |
| 85 return new InstanceSO(this); | 119 return new InstanceSO(this); |
| 86 } | 120 } |
| 87 | 121 |
| 88 std::string TestInstance::TestExecuteScript() { | 122 std::string TestInstance::TestExecuteScript() { |
| 89 // Simple call back into the plugin. | 123 // Simple call back into the plugin. |
| 90 pp::Var exception; | 124 pp::Var exception; |
| 91 pp::Var ret = instance_->ExecuteScript( | 125 pp::Var ret = instance_->ExecuteScript( |
| (...skipping 21 matching lines...) Expand all Loading... |
| 113 // not to bother fixing this for now. | 147 // not to bother fixing this for now. |
| 114 | 148 |
| 115 // Exception caused by string evaluation should be caught. | 149 // Exception caused by string evaluation should be caught. |
| 116 exception = pp::Var(); | 150 exception = pp::Var(); |
| 117 ret = instance_->ExecuteScript("document.doesntExist()", &exception); | 151 ret = instance_->ExecuteScript("document.doesntExist()", &exception); |
| 118 ASSERT_TRUE(ret.is_undefined()); | 152 ASSERT_TRUE(ret.is_undefined()); |
| 119 ASSERT_TRUE(exception.is_string()); // Don't know exactly what it will say. | 153 ASSERT_TRUE(exception.is_string()); // Don't know exactly what it will say. |
| 120 | 154 |
| 121 PASS(); | 155 PASS(); |
| 122 } | 156 } |
| 157 |
| 158 // A scriptable object that contains other scriptable objects recursively. This |
| 159 // is used to help verify that our scriptable object clean-up code works |
| 160 // properly. |
| 161 class ObjectWithChildren : public pp::deprecated::ScriptableObject { |
| 162 public: |
| 163 ObjectWithChildren(TestInstance* i, int num_descendents) { |
| 164 if (num_descendents > 0) { |
| 165 child_ = pp::VarPrivate(i->instance(), |
| 166 new ObjectWithChildren(i, num_descendents - 1)); |
| 167 } |
| 168 } |
| 169 struct IgnoreLeaks {}; |
| 170 ObjectWithChildren(TestInstance* i, int num_descendents, IgnoreLeaks) { |
| 171 if (num_descendents > 0) { |
| 172 child_ = pp::VarPrivate(i->instance(), |
| 173 new ObjectWithChildren(i, num_descendents - 1, |
| 174 IgnoreLeaks())); |
| 175 i->IgnoreLeakedVar(child_.pp_var().value.as_id); |
| 176 } |
| 177 } |
| 178 private: |
| 179 pp::VarPrivate child_; |
| 180 }; |
| 181 |
| 182 std::string TestInstance::TestRecursiveObjects() { |
| 183 // These should be deleted when we exit scope, so should not leak. |
| 184 pp::VarPrivate not_leaked(instance(), new ObjectWithChildren(this, 50)); |
| 185 |
| 186 // Leak some, but tell TestCase to ignore the leaks. This test is run and then |
| 187 // reloaded (see ppapi_uitest.cc). If these aren't cleaned up when the first |
| 188 // run is torn down, they will show up as leaks in the second run. |
| 189 // NOTE: The ScriptableObjects are actually leaked, but they should be removed |
| 190 // from the tracker. See below for a test that verifies that the |
| 191 // destructor is not run. |
| 192 pp::VarPrivate leaked( |
| 193 instance(), |
| 194 new ObjectWithChildren(this, 50, ObjectWithChildren::IgnoreLeaks())); |
| 195 // Now leak a reference to the root object. This should force the root and |
| 196 // all its descendents to stay in the tracker. |
| 197 LeakReferenceAndIgnore(leaked); |
| 198 |
| 199 PASS(); |
| 200 } |
| 201 |
| 202 // A scriptable object that should cause a crash if its destructor is run. We |
| 203 // don't run the destructor for objects which the plugin leaks. This is to |
| 204 // prevent them doing dangerous things at cleanup time, such as executing script |
| 205 // or creating new objects. |
| 206 class BadDestructorObject : public pp::deprecated::ScriptableObject { |
| 207 public: |
| 208 BadDestructorObject() {} |
| 209 ~BadDestructorObject() { |
| 210 assert(false); |
| 211 } |
| 212 }; |
| 213 |
| 214 std::string TestInstance::TestLeakedObjectDestructors() { |
| 215 pp::VarPrivate leaked(instance(), new BadDestructorObject()); |
| 216 // Leak a reference so it gets deleted on instance shutdown. |
| 217 LeakReferenceAndIgnore(leaked); |
| 218 PASS(); |
| 219 } |
| 220 |
| OLD | NEW |