diff --git a/Engine/source/component/moreAdvancedComponent.cpp b/Engine/source/component/moreAdvancedComponent.cpp index 02f8f4fe8..7ddfac688 100644 --- a/Engine/source/component/moreAdvancedComponent.cpp +++ b/Engine/source/component/moreAdvancedComponent.cpp @@ -21,7 +21,6 @@ //----------------------------------------------------------------------------- #include "component/moreAdvancedComponent.h" -#include "unit/test.h" // unitTest_runTests("Component/MoreAdvancedComponent"); @@ -58,50 +57,4 @@ bool MoreAdvancedComponent::testDependentInterface() return false; return mSCInterface->isFortyTwo( 42 ); -} - -////////////////////////////////////////////////////////////////////////// - -using namespace UnitTesting; - -CreateUnitTest(MoreAdvancedComponentTest, "Component/MoreAdvancedComponent") -{ - void run() - { - // Create component instances and compose them. - SimComponent *parentComponent = new SimComponent(); - SimpleComponent *simpleComponent = new SimpleComponent(); - MoreAdvancedComponent *moreAdvComponent = new MoreAdvancedComponent(); - // CodeReview note that the interface pointer isn't initialized in a ctor - // on the components, so it's bad memory against which you might - // be checking in testDependentInterface [3/3/2007 justind] - parentComponent->addComponent( simpleComponent ); - parentComponent->addComponent( moreAdvComponent ); - - simpleComponent->registerObject(); - moreAdvComponent->registerObject(); - - // Put a break-point here, follow the onAdd call, and observe the order in - // which the SimComponent::onAdd function executes. You will see the interfaces - // get cached, and the dependent interface query being made. - parentComponent->registerObject(); - - // If the MoreAdvancedComponent found an interface, than the parentComponent - // should have returned true, from onAdd, and should therefore be registered - // properly with the Sim - test( parentComponent->isProperlyAdded(), "Parent component not properly added!" ); - - // Now lets test the interface. You can step through this, as well. - test( moreAdvComponent->testDependentInterface(), "Dependent interface test failed." ); - - // CodeReview is there a reason we can't just delete the parentComponent here? [3/3/2007 justind] - // - // Clean up - parentComponent->removeComponent( simpleComponent ); - parentComponent->removeComponent( moreAdvComponent ); - - parentComponent->deleteObject(); - moreAdvComponent->deleteObject(); - simpleComponent->deleteObject(); - } -}; \ No newline at end of file +} \ No newline at end of file diff --git a/Engine/source/component/simpleComponent.cpp b/Engine/source/component/simpleComponent.cpp index aa1147c63..246672c28 100644 --- a/Engine/source/component/simpleComponent.cpp +++ b/Engine/source/component/simpleComponent.cpp @@ -28,124 +28,4 @@ ConsoleDocClass( SimpleComponent, "@brief The purpose of this component is to provide a minimalistic component that " "exposes a simple, cached interface\n\n" "Soon to be deprecated, internal only.\n\n " - "@internal"); - -////////////////////////////////////////////////////////////////////////// -// It may seem like some weak sauce to use a unit test for this, however -// it is very, very easy to set breakpoints in a unit test, and trace -// execution in the debugger, so I will use a unit test. -// -// Note I am not using much actual 'test' functionality, just providing -// an easy place to examine the functionality that was described and implemented -// in the header file. -// -// If you want to run this code, simply run Torque, pull down the console, and -// type: -// unitTest_runTests("Components/SimpleComponent"); - -#include "unit/test.h" -using namespace UnitTesting; - -CreateUnitTest(TestSimpleComponent, "Components/SimpleComponent") -{ - void run() - { - // When instantiating, and working with a SimObject in C++ code, such as - // a unit test, you *may not* allocate a SimObject off of the stack. - // - // For example: - // SimpleComponent sc; - // is a stack allocation. This memory is allocated off of the program stack - // when the function is called. SimObject deletion is done via SimObject::deleteObject() - // and the last command of this method is 'delete this;' That command will - // cause an assert if it is called on stack-allocated memory. Therefor, when - // instantiating SimObjects in C++ code, it is imperitive that you keep in - // mind that if any script calls 'delete()' on that SimObject, or any other - // C++ code calls 'deleteObject()' on that SimObject, it will crash. - SimpleComponent *sc = new SimpleComponent(); - - // SimObject::registerObject must be called on a SimObject before it is - // fully 'hooked in' to the engine. - // - // Tracing execution of this function will let you see onAdd get called on - // the component, and you will see it cache the interface we exposed. - sc->registerObject(); - - // It is *not* required that a component always be owned by a component (obviously) - // however I am using an owner so that you can trace execution of recursive - // calls to cache interfaces and such. - SimComponent *testOwner = new SimComponent(); - - // Add the test component to it's owner. This will set the 'mOwner' field - // of 'sc' to the address of 'testOwner' - testOwner->addComponent( sc ); - - // If you step-into this registerObject the same way as the previous one, - // you will be able to see the recursive caching of the exposed interface. - testOwner->registerObject(); - - // Now to prove that object composition is working properly, lets ask - // both of these components for their interface lists... - - // The ComponentInterfaceList is a typedef for type 'VectorPtr' - // and it will be used by getInterfaces() to store the results of the interface - // query. This is the "complete" way to obtain an interface, and it is too - // heavy-weight for most cases. A simplified query will be performed next, - // to demonstrate the usage of both. - ComponentInterfaceList iLst; - - // This query requests all interfaces, on all components, regardless of name - // or owner. - sc->getInterfaces( &iLst, - // This is the type field. I am passing NULL here to signify that the query - // should match all values of 'type' in the list. - NULL, - - // The name field, let's pass NULL again just so when you trace execution - // you can see how queries work in the simple case, first. - NULL ); - - // Lets process the list that we've gotten back, and find the interface that - // we want. - SimpleComponentInterface *scQueriedInterface = NULL; - - for( ComponentInterfaceListIterator i = iLst.begin(); i != iLst.end(); i++ ) - { - scQueriedInterface = dynamic_cast( *i ); - - if( scQueriedInterface != NULL ) - break; - } - - AssertFatal( scQueriedInterface != NULL, "No valid SimpleComponentInterface was found in query" ); - - // Lets do it again, only we will execute the query on the parent instead, - // in a simplified way. Remember the parent component doesn't expose any - // interfaces at all, so the success of this behavior is entirely dependent - // on the recursive registration that occurs in registerInterfaces() - SimpleComponentInterface *ownerQueriedInterface = testOwner->getInterface(); - - AssertFatal( ownerQueriedInterface != NULL, "No valid SimpleComponentInterface was found in query" ); - - // We should now have two pointers to the same interface obtained by querying - // different components. - test( ownerQueriedInterface == scQueriedInterface, "This really shouldn't be possible to fail given the setup of the test" ); - - // Lets call the method that was exposed on the component via the interface. - // Trace the execution of this function, if you wish. - test( ownerQueriedInterface->isFortyTwo( 42 ), "Don't panic, but it's a bad day in the component system." ); - test( scQueriedInterface->isFortyTwo( 42 ), "Don't panic, but it's a bad day in the component system." ); - - // So there you have it. Writing a simple component that exposes a cached - // interface, and testing it. It's time to clean up. - testOwner->removeComponent( sc ); - - sc->deleteObject(); - testOwner->deleteObject(); - - // Interfaces do not need to be freed. In Juggernaught, these will be ref-counted - // for more robust behavior. Right now, however, the values of our two interface - // pointers, scQueriedInterface and ownerQueriedInterface, reference invalid - // memory. - } -}; \ No newline at end of file + "@internal"); \ No newline at end of file diff --git a/Engine/source/component/test/moreAdvancedComponentTest.cpp b/Engine/source/component/test/moreAdvancedComponentTest.cpp new file mode 100644 index 000000000..a6a7335f4 --- /dev/null +++ b/Engine/source/component/test/moreAdvancedComponentTest.cpp @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifdef TORQUE_TESTS_ENABLED +#include "testing/unitTesting.h" +#include "component/moreAdvancedComponent.h" + +TEST(MoreAdvancedComponent, MoreAdvancedComponent) +{ + // Create component instances and compose them. + SimComponent *parentComponent = new SimComponent(); + SimpleComponent *simpleComponent = new SimpleComponent(); + MoreAdvancedComponent *moreAdvComponent = new MoreAdvancedComponent(); + // CodeReview note that the interface pointer isn't initialized in a ctor + // on the components, so it's bad memory against which you might + // be checking in testDependentInterface [3/3/2007 justind] + parentComponent->addComponent( simpleComponent ); + parentComponent->addComponent( moreAdvComponent ); + + simpleComponent->registerObject(); + moreAdvComponent->registerObject(); + + // Put a break-point here, follow the onAdd call, and observe the order in + // which the SimComponent::onAdd function executes. You will see the interfaces + // get cached, and the dependent interface query being made. + parentComponent->registerObject(); + + // If the MoreAdvancedComponent found an interface, than the parentComponent + // should have returned true, from onAdd, and should therefore be registered + // properly with the Sim + EXPECT_TRUE( parentComponent->isProperlyAdded() ) + << "Parent component not properly added!"; + + // Now lets test the interface. You can step through this, as well. + EXPECT_TRUE( moreAdvComponent->testDependentInterface() ) + << "Dependent interface test failed."; + + // CodeReview is there a reason we can't just delete the parentComponent here? [3/3/2007 justind] + // + // Clean up + parentComponent->removeComponent( simpleComponent ); + parentComponent->removeComponent( moreAdvComponent ); + + parentComponent->deleteObject(); + moreAdvComponent->deleteObject(); + simpleComponent->deleteObject(); +}; + +#endif \ No newline at end of file diff --git a/Engine/source/unit/tests/testComponents.cpp b/Engine/source/component/test/simComponentTest.cpp similarity index 62% rename from Engine/source/unit/tests/testComponents.cpp rename to Engine/source/component/test/simComponentTest.cpp index b4a78ca39..d7d135a08 100644 --- a/Engine/source/unit/tests/testComponents.cpp +++ b/Engine/source/component/test/simComponentTest.cpp @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC +// Copyright (c) 2014 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to @@ -20,14 +20,10 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "unit/test.h" -#include "unit/memoryTester.h" +#ifdef TORQUE_TESTS_ENABLED +#include "testing/unitTesting.h" #include "component/simComponent.h" -using namespace UnitTesting; - -////////////////////////////////////////////////////////////////////////// - class CachedInterfaceExampleComponent : public SimComponent { typedef SimComponent Parent; @@ -89,18 +85,16 @@ public: // CodeReview [patw, 2, 17, 2007] I'm going to make another lightweight interface // for this functionality later - void unit_test( UnitTest *test ) + void unit_test() { - AssertFatal(test, "CachedInterfaceExampleComponent::unit_test - NULL UnitTest"); - - if( !test ) - return; - - test->test( mpU32 != NULL, "Pointer to dependent interface is NULL" ); + EXPECT_TRUE( mpU32 != NULL ) + << "Pointer to dependent interface is NULL"; if( mpU32 ) { - test->test( *(*mpU32) & ( 1 << 24 ), "Pointer to interface data is bogus." ); - test->test( *(*mpU32) != *mMyId, "Two of me have the same ID, bad!" ); + EXPECT_TRUE( *(*mpU32) & ( 1 << 24 )) + << "Pointer to interface data is bogus."; + EXPECT_TRUE( *(*mpU32) != *mMyId) + << "Two of me have the same ID, bad!"; } } }; @@ -113,42 +107,47 @@ ConsoleDocClass( CachedInterfaceExampleComponent, "Not intended for game development, for editors or internal use only.\n\n " "@internal"); -////////////////////////////////////////////////////////////////////////// - -CreateUnitTest(TestComponentInterfacing, "Components/Composition") +TEST(SimComponent, Composition) { - void run() + SimComponent *testComponent = new SimComponent(); + CachedInterfaceExampleComponent *componentA = new CachedInterfaceExampleComponent(); + CachedInterfaceExampleComponent *componentB = new CachedInterfaceExampleComponent(); + + // Register sub-components + EXPECT_TRUE( componentA->registerObject()) + << "Failed to register componentA"; + EXPECT_TRUE( componentB->registerObject()) + << "Failed to register componentB"; + + // Add the components + EXPECT_TRUE( testComponent->addComponent( componentA )) + << "Failed to add component a to testComponent"; + EXPECT_TRUE( testComponent->addComponent( componentB )) + << "Failed to add component b to testComponent"; + + EXPECT_EQ( componentA->getOwner(), testComponent) + << "testComponent did not properly set the mOwner field of componentA to NULL."; + EXPECT_EQ( componentB->getOwner(), testComponent) + << "testComponent did not properly set the mOwner field of componentB to NULL."; + + // Register the object with the simulation, kicking off the interface registration + const bool registered = testComponent->registerObject(); + EXPECT_TRUE( registered ) + << "Failed to register testComponent"; + + // Interface tests + if( registered ) { - MemoryTester m; - m.mark(); - - SimComponent *testComponent = new SimComponent(); - CachedInterfaceExampleComponent *componentA = new CachedInterfaceExampleComponent(); - CachedInterfaceExampleComponent *componentB = new CachedInterfaceExampleComponent(); - - // Register sub-components - test( componentA->registerObject(), "Failed to register componentA" ); - test( componentB->registerObject(), "Failed to register componentB" ); - - // Add the components - test( testComponent->addComponent( componentA ), "Failed to add component a to testComponent" ); - test( testComponent->addComponent( componentB ), "Failed to add component b to testComponent" ); - - test( componentA->getOwner() == testComponent, "testComponent did not properly set the mOwner field of componentA to NULL." ); - test( componentB->getOwner() == testComponent, "testComponent did not properly set the mOwner field of componentB to NULL." ); - - // Register the object with the simulation, kicking off the interface registration - const bool registered = testComponent->registerObject(); - test( registered, "Failed to register testComponent" ); - - // Interface tests - if( registered ) { - componentA->unit_test( this ); - componentB->unit_test( this ); - testComponent->deleteObject(); - } - - test( m.check(), "Component composition test leaked memory." ); + SCOPED_TRACE("componentA"); + componentA->unit_test(); + } + { + SCOPED_TRACE("componentB"); + componentB->unit_test(); + } + testComponent->deleteObject(); } -}; \ No newline at end of file +}; + +#endif \ No newline at end of file diff --git a/Engine/source/component/test/simpleComponentTest.cpp b/Engine/source/component/test/simpleComponentTest.cpp new file mode 100644 index 000000000..a528e918f --- /dev/null +++ b/Engine/source/component/test/simpleComponentTest.cpp @@ -0,0 +1,131 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2014 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifdef TORQUE_TESTS_ENABLED +#include "testing/unitTesting.h" +#include "component/simpleComponent.h" + +TEST(SimpleComponent, SimpleComponent) +{ + // When instantiating, and working with a SimObject in C++ code, such as + // a unit test, you *may not* allocate a SimObject off of the stack. + // + // For example: + // SimpleComponent sc; + // is a stack allocation. This memory is allocated off of the program stack + // when the function is called. SimObject deletion is done via SimObject::deleteObject() + // and the last command of this method is 'delete this;' That command will + // cause an assert if it is called on stack-allocated memory. Therefor, when + // instantiating SimObjects in C++ code, it is imperitive that you keep in + // mind that if any script calls 'delete()' on that SimObject, or any other + // C++ code calls 'deleteObject()' on that SimObject, it will crash. + SimpleComponent *sc = new SimpleComponent(); + + // SimObject::registerObject must be called on a SimObject before it is + // fully 'hooked in' to the engine. + // + // Tracing execution of this function will let you see onAdd get called on + // the component, and you will see it cache the interface we exposed. + sc->registerObject(); + + // It is *not* required that a component always be owned by a component (obviously) + // however I am using an owner so that you can trace execution of recursive + // calls to cache interfaces and such. + SimComponent *testOwner = new SimComponent(); + + // Add the test component to it's owner. This will set the 'mOwner' field + // of 'sc' to the address of 'testOwner' + testOwner->addComponent( sc ); + + // If you step-into this registerObject the same way as the previous one, + // you will be able to see the recursive caching of the exposed interface. + testOwner->registerObject(); + + // Now to prove that object composition is working properly, lets ask + // both of these components for their interface lists... + + // The ComponentInterfaceList is a typedef for type 'VectorPtr' + // and it will be used by getInterfaces() to store the results of the interface + // query. This is the "complete" way to obtain an interface, and it is too + // heavy-weight for most cases. A simplified query will be performed next, + // to demonstrate the usage of both. + ComponentInterfaceList iLst; + + // This query requests all interfaces, on all components, regardless of name + // or owner. + sc->getInterfaces( &iLst, + // This is the type field. I am passing NULL here to signify that the query + // should match all values of 'type' in the list. + NULL, + + // The name field, let's pass NULL again just so when you trace execution + // you can see how queries work in the simple case, first. + NULL ); + + // Lets process the list that we've gotten back, and find the interface that + // we want. + SimpleComponentInterface *scQueriedInterface = NULL; + + for( ComponentInterfaceListIterator i = iLst.begin(); i != iLst.end(); i++ ) + { + scQueriedInterface = dynamic_cast( *i ); + + if( scQueriedInterface != NULL ) + break; + } + + AssertFatal( scQueriedInterface != NULL, "No valid SimpleComponentInterface was found in query" ); + + // Lets do it again, only we will execute the query on the parent instead, + // in a simplified way. Remember the parent component doesn't expose any + // interfaces at all, so the success of this behavior is entirely dependent + // on the recursive registration that occurs in registerInterfaces() + SimpleComponentInterface *ownerQueriedInterface = testOwner->getInterface(); + + AssertFatal( ownerQueriedInterface != NULL, "No valid SimpleComponentInterface was found in query" ); + + // We should now have two pointers to the same interface obtained by querying + // different components. + EXPECT_EQ( ownerQueriedInterface, scQueriedInterface ) + << "This really shouldn't be possible to fail given the setup of the test"; + + // Lets call the method that was exposed on the component via the interface. + // Trace the execution of this function, if you wish. + EXPECT_TRUE( ownerQueriedInterface->isFortyTwo( 42 ) ) + << "Don't panic, but it's a bad day in the component system."; + EXPECT_TRUE( scQueriedInterface->isFortyTwo( 42 ) ) + << "Don't panic, but it's a bad day in the component system."; + + // So there you have it. Writing a simple component that exposes a cached + // interface, and testing it. It's time to clean up. + testOwner->removeComponent( sc ); + + sc->deleteObject(); + testOwner->deleteObject(); + + // Interfaces do not need to be freed. In Juggernaught, these will be ref-counted + // for more robust behavior. Right now, however, the values of our two interface + // pointers, scQueriedInterface and ownerQueriedInterface, reference invalid + // memory. +}; + +#endif \ No newline at end of file