#include #include "rbx/test/Base.UnitTest.Lib.h" #include "rbx/test/ScopedFastFlagSetting.h" #include "script/script.h" #include "v8tree/instance.h" #include "v8dataModel/BasicPartInstance.h" #include "v8datamodel/PartInstance.h" #include "v8dataModel/Tool.h" #include "rbx/test/DataModelFixture.h" extern const char* const sInstanceTest; class InstanceTest : public RBX::DescribedCreatable { }; const char* const sInstanceTest = "InstanceTest"; RBX_REGISTER_CLASS(InstanceTest); extern const char* const sStealDescendants; class StealDescendants : public RBX::DescribedCreatable { private: typedef RBX::DescribedCreatable Super; /*override*/ void onDescendantAdded(Instance* instance) { if(instance->getParent() != this) { instance->setAndLockParent(this); } Super::onDescendantAdded(instance); } }; const char* const sStealDescendants = "StealDescendants"; RBX_REGISTER_CLASS(StealDescendants); extern const char* const sThrowOnDescendants; class ThrowOnDescendants : public RBX::DescribedCreatable { private: typedef RBX::DescribedCreatable Super; /*override*/ void onDescendantAdded(Instance* instance) { if(instance->getParent() != this) { throw std::runtime_error(""); } Super::onDescendantAdded(instance); } }; const char* const sThrowOnDescendants = "ThrowOnDescendants"; RBX_REGISTER_CLASS(ThrowOnDescendants); extern const char* const sCheckAncestor; const char* const sCheckAncestor = "CheckAncestor"; class CheckAncestor : public RBX::DescribedCreatable { private: typedef RBX::DescribedCreatable Super; public: CheckAncestor() : RBX::DescribedCreatable() { setName(sCheckAncestor); } protected: void verifySetAncestor(const RBX::Instance* const newParent, const RBX::Instance* const instanceGettingNewParent) const { if (RBX::ServiceProvider::findServiceProvider(newParent)) throw RBX::runtime_error("CheckAncestor can't have a service provider for an ancestor"); Super::verifySetAncestor(newParent, instanceGettingNewParent); } }; RBX_REGISTER_CLASS(CheckAncestor); BOOST_AUTO_TEST_SUITE(Instance) BOOST_AUTO_TEST_CASE(Clone) { int count = RBX::Diagnostics::Countable::getCount(); { boost::shared_ptr i = RBX::Creatable::create(); i->clone(RBX::ScriptingCreator); } BOOST_CHECK_EQUAL(count, RBX::Diagnostics::Countable::getCount()); } BOOST_FIXTURE_TEST_CASE(PerfDynamicCast, RBX::Test::PerformanceTestFixture) { shared_ptr part = RBX::Creatable::create(); RBX::Instance* inst = part.get(); for (int i=0; i<1000000; ++i) { RBX::Tool* testTool = dynamic_cast(inst); testTool = 0; } } BOOST_FIXTURE_TEST_CASE(PerfIsA, RBX::Test::PerformanceTestFixture) { shared_ptr part = RBX::Creatable::create(); RBX::Instance* inst = part.get(); for (int i=0; i<1000000; ++i) { inst->getDescriptor().isA(RBX::PartInstance::classDescriptor()); } } BOOST_FIXTURE_TEST_CASE(PerfIsAFalse, RBX::Test::PerformanceTestFixture) { boost::shared_ptr part = RBX::Creatable::create(); RBX::Instance* inst = part.get(); for (int i=0; i<1000000; ++i) { inst->isA(); } } BOOST_FIXTURE_TEST_CASE(PerfIsATool, RBX::Test::PerformanceTestFixture) { shared_ptr part = RBX::Creatable::create(); RBX::Instance* inst = part.get(); for (int i=0; i<1000000; ++i) { inst->isA(); } } BOOST_AUTO_TEST_CASE(CastTo) { shared_ptr part = RBX::Creatable::create(); shared_ptr instance = RBX::Creatable::create(); BOOST_CHECK(RBX::Instance::fastDynamicCast(part.get())); BOOST_CHECK(!RBX::Instance::fastDynamicCast(instance.get())); RBX::Instance* nullInstance = NULL; BOOST_CHECK(!RBX::Instance::fastDynamicCast(nullInstance)); RBX::Instance* inst = part.get(); BOOST_CHECK(inst->fastDynamicCast()); BOOST_CHECK(!instance->fastDynamicCast()); } BOOST_AUTO_TEST_CASE(CastToConst) { shared_ptr part = RBX::Creatable::create(); shared_ptr instance = RBX::Creatable::create(); BOOST_CHECK(RBX::Instance::fastDynamicCast(part.get())); BOOST_CHECK(!RBX::Instance::fastDynamicCast(instance.get())); const RBX::Instance* nullInstance = NULL; BOOST_CHECK(!RBX::Instance::fastDynamicCast(nullInstance)); const RBX::Instance* inst = part.get(); BOOST_CHECK(inst->fastDynamicCast()); BOOST_CHECK(!instance->fastDynamicCast()); } BOOST_AUTO_TEST_CASE(SharedCastTo) { shared_ptr part = RBX::Creatable::create(); shared_ptr instance = RBX::Creatable::create(); BOOST_CHECK(RBX::Instance::fastSharedDynamicCast(part)); BOOST_CHECK(!RBX::Instance::fastSharedDynamicCast(instance)); shared_ptr nullInstance; BOOST_CHECK(!RBX::Instance::fastSharedDynamicCast(nullInstance)); } BOOST_FIXTURE_TEST_CASE(LockUnlockDeprecated, DataModelFixture) { std::auto_ptr result = execute("Instance.Unlock() return Instance.Lock(nil)"); BOOST_REQUIRE_EQUAL(result->values.size(), 1); BOOST_CHECK(result->values.at(0).get()); } BOOST_AUTO_TEST_CASE(Parenting) { shared_ptr instance = RBX::Creatable::create(); shared_ptr checkAncestor = RBX::Creatable::create(); DataModelFixture dm; RBX::DataModel::LegacyLock lock(&dm, RBX::DataModelJob::Write); checkAncestor->setParent2(instance); BOOST_CHECK(checkAncestor->getParent() != NULL); BOOST_CHECK_THROW(instance->setParent2(dm.dataModel), std::exception); instance->setParent(NULL); BOOST_CHECK_THROW(checkAncestor->setParent2(dm.dataModel), std::exception); checkAncestor->setParent(NULL); instance->setParent2(dm.dataModel); BOOST_CHECK_THROW(checkAncestor->setParent2(instance), std::exception); instance->setParent(NULL); checkAncestor->setParent(NULL); } BOOST_AUTO_TEST_CASE(ReparentingLock) { shared_ptr thievingGrandparent = RBX::Creatable::create(); shared_ptr throwingGrandparent = RBX::Creatable::create(); shared_ptr parent = RBX::Creatable::create(); shared_ptr child = RBX::Creatable::create(); BOOST_CHECK(!parent->getIsParentLocked()); parent->setAndLockParent(thievingGrandparent.get()); BOOST_CHECK(parent->getIsParentLocked()); // grandparent will attempt to steal child from parent, child's parent lock should still have its parent locked child->setAndLockParent(parent.get()); BOOST_CHECK(child->getIsParentLocked()); BOOST_CHECK(child->getParent() == parent.get()); child->unlockParent(); child->setParent(NULL); // grandparent will attempt to steal child from parent, child should not have it's parent locked child->setParent(parent.get()); BOOST_CHECK(!child->getIsParentLocked()); BOOST_CHECK(child->getParent() == parent.get()); child->setParent(NULL); parent->unlockParent(); parent->setParent(throwingGrandparent.get()); BOOST_CHECK_THROW(child->setAndLockParent(parent.get()), std::exception); BOOST_CHECK(!child->getIsParentLocked()); child->setParent(NULL); child->lockParent(); BOOST_CHECK_THROW(child->setAndLockParent(parent.get()), std::exception); BOOST_CHECK(child->getIsParentLocked()); } BOOST_AUTO_TEST_CASE(SetParentNull) { shared_ptr parent = RBX::Creatable::create(); { shared_ptr child = RBX::Creatable::create(); child->setParent(parent.get()); } // child goes out of scope, but the object is still alive since it's a child of parent now RBX::Instance* child = parent->getChild(0); child->setParent(NULL); } BOOST_AUTO_TEST_CASE(WaitForChildReturnsImmediatelyIfChildPresent) { using namespace RBX; shared_ptr