mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
commit
535f56af6e
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -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<ComponentInterface *>'
|
||||
// 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<SimpleComponentInterface *>( *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<SimpleComponentInterface>();
|
||||
|
||||
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.
|
||||
}
|
||||
};
|
||||
"@internal");
|
||||
68
Engine/source/component/test/moreAdvancedComponentTest.cpp
Normal file
68
Engine/source/component/test/moreAdvancedComponentTest.cpp
Normal file
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -51,10 +47,10 @@ public:
|
|||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void registerInterfaces( const SimComponent *owner )
|
||||
virtual void registerInterfaces( SimComponent *owner )
|
||||
{
|
||||
// Register a cached interface for this
|
||||
registerCachedInterface( NULL, "aU32", this, &mMyId );
|
||||
owner->registerCachedInterface( NULL, "aU32", this, &mMyId );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -70,7 +66,7 @@ public:
|
|||
ComponentInterfaceList list;
|
||||
|
||||
// Enumerate the interfaces on the owner, only ignore interfaces that this object owns
|
||||
if( !_getOwner()->getInterfaces( &list, NULL, "aU32", this, true ) )
|
||||
if( !owner->getInterfaces( &list, NULL, "aU32", this, true ) )
|
||||
return false;
|
||||
|
||||
// Sanity check before just assigning all willy-nilly
|
||||
|
|
@ -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,43 @@ 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
|
||||
ASSERT_TRUE( testComponent->registerObject() )
|
||||
<< "Failed to register testComponent";
|
||||
|
||||
{
|
||||
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();
|
||||
};
|
||||
|
||||
#endif
|
||||
131
Engine/source/component/test/simpleComponentTest.cpp
Normal file
131
Engine/source/component/test/simpleComponentTest.cpp
Normal file
|
|
@ -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<ComponentInterface *>'
|
||||
// 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<SimpleComponentInterface *>( *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<SimpleComponentInterface>();
|
||||
|
||||
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
|
||||
108
Engine/source/console/test/runtimeClassRepTest.cpp
Normal file
108
Engine/source/console/test/runtimeClassRepTest.cpp
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/platform.h"
|
||||
#include "console/simBase.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/runtimeClassRep.h"
|
||||
|
||||
class RuntimeRegisteredSimObject : public SimObject
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
|
||||
protected:
|
||||
bool mFoo;
|
||||
|
||||
public:
|
||||
RuntimeRegisteredSimObject() : mFoo(false) {};
|
||||
|
||||
DECLARE_RUNTIME_CONOBJECT(RuntimeRegisteredSimObject);
|
||||
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
IMPLEMENT_RUNTIME_CONOBJECT(RuntimeRegisteredSimObject);
|
||||
|
||||
void RuntimeRegisteredSimObject::initPersistFields()
|
||||
{
|
||||
addField("fooField", TypeBool, Offset(mFoo, RuntimeRegisteredSimObject));
|
||||
}
|
||||
|
||||
TEST(Console, RuntimeClassRep)
|
||||
{
|
||||
// First test to make sure that the test class is not registered (don't
|
||||
// know how it could be, but that's programming for you). Stop the test if
|
||||
// it is.
|
||||
ASSERT_TRUE(!RuntimeRegisteredSimObject::dynRTClassRep.isRegistered())
|
||||
<< "RuntimeRegisteredSimObject class was already registered with the console";
|
||||
|
||||
// This should not be able to find the class, and return null (this may
|
||||
// AssertWarn as well).
|
||||
ConsoleObject *conobj = ConsoleObject::create("RuntimeRegisteredSimObject");
|
||||
EXPECT_TRUE(conobj == NULL)
|
||||
<< "Unregistered AbstractClassRep returned non-NULL value! That is really bad!";
|
||||
|
||||
// Register with console system.
|
||||
RuntimeRegisteredSimObject::dynRTClassRep.consoleRegister();
|
||||
|
||||
// Make sure that the object knows it's registered.
|
||||
EXPECT_TRUE(RuntimeRegisteredSimObject::dynRTClassRep.isRegistered())
|
||||
<< "RuntimeRegisteredSimObject class failed console registration";
|
||||
|
||||
// Now try again to create the instance.
|
||||
conobj = ConsoleObject::create("RuntimeRegisteredSimObject");
|
||||
EXPECT_TRUE(conobj != NULL)
|
||||
<< "AbstractClassRep::create method failed!";
|
||||
|
||||
// Cast the instance, and test it.
|
||||
RuntimeRegisteredSimObject *rtinst =
|
||||
dynamic_cast<RuntimeRegisteredSimObject *>(conobj);
|
||||
EXPECT_TRUE(rtinst != NULL)
|
||||
<< "Casting failed for some reason";
|
||||
|
||||
// Register it with a name.
|
||||
rtinst->registerObject("_utRRTestObject");
|
||||
EXPECT_TRUE(rtinst->isProperlyAdded())
|
||||
<< "registerObject failed on test object";
|
||||
|
||||
// Now execute some script on it.
|
||||
Con::evaluate("_utRRTestObject.fooField = true;");
|
||||
|
||||
// Test to make sure field worked.
|
||||
EXPECT_TRUE(dAtob(rtinst->getDataField(StringTable->insert("fooField"), NULL)))
|
||||
<< "Set property failed on instance.";
|
||||
|
||||
// BALETED
|
||||
rtinst->deleteObject();
|
||||
|
||||
// Unregister the type.
|
||||
RuntimeRegisteredSimObject::dynRTClassRep.consoleUnRegister();
|
||||
|
||||
// And make sure we can't create another one.
|
||||
conobj = ConsoleObject::create("RuntimeRegisteredSimObject");
|
||||
EXPECT_TRUE(conobj == NULL)
|
||||
<< "Unregistration of type failed";
|
||||
}
|
||||
|
||||
#endif
|
||||
189
Engine/source/core/util/journal/test/journalTest.cpp
Normal file
189
Engine/source/core/util/journal/test/journalTest.cpp
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "core/util/journal/journaledSignal.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
|
||||
FIXTURE(Journal)
|
||||
{
|
||||
public:
|
||||
// Used for basic API test.
|
||||
struct receiver
|
||||
{
|
||||
U16 lastTriggerValue;
|
||||
void trigger(U16 msg)
|
||||
{
|
||||
lastTriggerValue = msg;
|
||||
}
|
||||
};
|
||||
|
||||
// Used for non-basic test.
|
||||
typedef JournaledSignal<void(U32, U16)> EventA;
|
||||
typedef JournaledSignal<void(U8, S8)> EventB;
|
||||
typedef JournaledSignal<void(U32, S32)> EventC;
|
||||
|
||||
// Root, non-dynamic signal receiver.
|
||||
struct multiReceiver {
|
||||
U32 recvA, recvB, recvC;
|
||||
|
||||
EventA *dynamicA;
|
||||
EventB *dynamicB;
|
||||
EventC *dynamicC;
|
||||
|
||||
void receiverRoot(U8 msg)
|
||||
{
|
||||
if(msg==1)
|
||||
{
|
||||
dynamicA = new EventA();
|
||||
dynamicA->notify(this, &multiReceiver::receiverA);
|
||||
}
|
||||
|
||||
if(msg==2)
|
||||
{
|
||||
dynamicB = new EventB();
|
||||
dynamicB->notify(this, &multiReceiver::receiverB);
|
||||
}
|
||||
|
||||
if(msg==3)
|
||||
{
|
||||
dynamicC = new EventC();
|
||||
dynamicC->notify(this, &multiReceiver::receiverC);
|
||||
}
|
||||
}
|
||||
|
||||
void receiverA(U32, U16 d)
|
||||
{
|
||||
recvA += d;
|
||||
}
|
||||
|
||||
void receiverB(U8, S8 d)
|
||||
{
|
||||
recvB += d;
|
||||
}
|
||||
|
||||
void receiverC(U32, S32 d)
|
||||
{
|
||||
recvC += d;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
TEST_FIX(Journal, BasicAPI)
|
||||
{
|
||||
receiver rec;
|
||||
rec.lastTriggerValue = 0;
|
||||
|
||||
// Set up a journaled signal to test with.
|
||||
JournaledSignal<void(U16)> testEvent;
|
||||
testEvent.notify(&rec, &receiver::trigger);
|
||||
|
||||
// Initialize journal recording and fire off some events...
|
||||
Journal::Record("test.jrn");
|
||||
ASSERT_TRUE(Journal::IsRecording());
|
||||
|
||||
testEvent.trigger(16);
|
||||
testEvent.trigger(17);
|
||||
testEvent.trigger(18);
|
||||
|
||||
EXPECT_EQ(rec.lastTriggerValue, 18)
|
||||
<< "Should encounter last triggered value (18).";
|
||||
|
||||
Journal::Stop();
|
||||
ASSERT_FALSE(Journal::IsRecording());
|
||||
|
||||
// Clear it...
|
||||
rec.lastTriggerValue = 0;
|
||||
|
||||
// and play back - should get same thing.
|
||||
Journal::Play("test.jrn");
|
||||
|
||||
// Since we fired 3 events, it should take three loops.
|
||||
EXPECT_TRUE(Journal::PlayNext()) << "Should be two more events.";
|
||||
EXPECT_TRUE(Journal::PlayNext()) << "Should be one more event.";
|
||||
EXPECT_FALSE(Journal::PlayNext()) << "Should be no more events.";
|
||||
|
||||
EXPECT_EQ(rec.lastTriggerValue, 18)
|
||||
<< "Should encounter last journaled value (18).";
|
||||
}
|
||||
|
||||
TEST_FIX(Journal, DynamicSignals)
|
||||
{
|
||||
multiReceiver rec;
|
||||
|
||||
// Reset our state values.
|
||||
rec.recvA = rec.recvB = rec.recvC = 0;
|
||||
|
||||
// Set up a signal to start with.
|
||||
JournaledSignal<void(U8)> testEvent;
|
||||
testEvent.notify(&rec, &multiReceiver::receiverRoot);
|
||||
|
||||
// Initialize journal recording and fire off some events...
|
||||
Journal::Record("test.jrn");
|
||||
ASSERT_TRUE(Journal::IsRecording());
|
||||
|
||||
testEvent.trigger(1);
|
||||
rec.dynamicA->trigger(8, 100);
|
||||
testEvent.trigger(2);
|
||||
rec.dynamicA->trigger(8, 8);
|
||||
rec.dynamicB->trigger(9, 'a');
|
||||
testEvent.trigger(3);
|
||||
SAFE_DELETE(rec.dynamicB); // Test a deletion.
|
||||
rec.dynamicC->trigger(8, 1);
|
||||
rec.dynamicC->trigger(8, 1);
|
||||
|
||||
// Did we end up with expected values? Check before clearing.
|
||||
EXPECT_EQ(rec.recvA, 108) << "recvA wasn't 108 - something broken in signals?";
|
||||
EXPECT_EQ(rec.recvB, 'a') << "recvB wasn't 'a' - something broken in signals?";
|
||||
EXPECT_EQ(rec.recvC, 2) << "recvC wasn't 2 - something broken in signals?";
|
||||
|
||||
// Reset our state values.
|
||||
rec.recvA = rec.recvB = rec.recvC = 0;
|
||||
|
||||
// And kill the journal...
|
||||
Journal::Stop();
|
||||
|
||||
// Also kill our remaining dynamic signals.
|
||||
SAFE_DELETE(rec.dynamicA);
|
||||
SAFE_DELETE(rec.dynamicB);
|
||||
SAFE_DELETE(rec.dynamicC);
|
||||
|
||||
// Play back - should get same thing.
|
||||
Journal::Play("test.jrn");
|
||||
|
||||
// Since we fired 8 events, it should take 7+1=8 loops.
|
||||
for(S32 i = 0; i < 7; i++)
|
||||
{
|
||||
EXPECT_TRUE(Journal::PlayNext())
|
||||
<< "Should be more events.";
|
||||
}
|
||||
|
||||
EXPECT_FALSE(Journal::PlayNext())
|
||||
<< "Should be no more events.";
|
||||
|
||||
EXPECT_EQ(rec.recvA, 108) << "recvA wasn't 108 - something broken in journal?";
|
||||
EXPECT_EQ(rec.recvB, 'a') << "recvB wasn't 'a' - something broken in journal?";
|
||||
EXPECT_EQ(rec.recvC, 2) << "recvC wasn't 2 - something broken in journal?";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -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,39 +20,41 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#ifdef TORQUE_TESTS_ENABLED
|
||||
#include "testing/unitTesting.h"
|
||||
#include "core/util/journal/process.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateUnitTest(TestingProcess, "Journal/Process")
|
||||
FIXTURE(Process)
|
||||
{
|
||||
// How many ticks remaining?
|
||||
U32 _remainingTicks;
|
||||
|
||||
// Callback for process list.
|
||||
void process()
|
||||
public:
|
||||
U32 remainingTicks;
|
||||
void notification()
|
||||
{
|
||||
if(_remainingTicks==0)
|
||||
if(remainingTicks == 0)
|
||||
Process::requestShutdown();
|
||||
|
||||
_remainingTicks--;
|
||||
remainingTicks--;
|
||||
}
|
||||
};
|
||||
|
||||
void run()
|
||||
TEST_FIX(Process, BasicAPI)
|
||||
{
|
||||
// We'll run 30 ticks, then quit.
|
||||
remainingTicks = 30;
|
||||
|
||||
// Register with the process list.
|
||||
Process::notify(this, &ProcessFixture::notification);
|
||||
|
||||
// And do 30 notifies, making sure we end on the 30th.
|
||||
for(S32 i = 0; i < 30; i++)
|
||||
{
|
||||
// We'll run 30 ticks, then quit.
|
||||
_remainingTicks = 30;
|
||||
|
||||
// Register with the process list.
|
||||
Process::notify(this, &TestingProcess::process);
|
||||
|
||||
// And do 30 notifies, making sure we end on the 30th.
|
||||
for(S32 i=0; i<30; i++)
|
||||
test(Process::processEvents(), "Should quit after 30 ProcessEvents() calls - not before!");
|
||||
test(!Process::processEvents(), "Should quit after the 30th ProcessEvent() call!");
|
||||
|
||||
Process::remove(this, &TestingProcess::process);
|
||||
EXPECT_TRUE(Process::processEvents())
|
||||
<< "Should quit after 30 ProcessEvents() calls - not before!";
|
||||
}
|
||||
};
|
||||
|
||||
EXPECT_FALSE(Process::processEvents())
|
||||
<< "Should quit after the 30th ProcessEvent() call!";
|
||||
|
||||
Process::remove(this, &ProcessFixture::notification);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "core/util/journal/journaledSignal.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateUnitTest(TestsJournalRecordAndPlayback, "Journal/Basic")
|
||||
{
|
||||
U32 _lastTriggerValue;
|
||||
|
||||
void triggerReceiver(U16 msg)
|
||||
{
|
||||
_lastTriggerValue = msg;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
// Reset the last trigger value just in case...
|
||||
_lastTriggerValue = 0;
|
||||
|
||||
// Set up a journaled signal to test with.
|
||||
JournaledSignal<void(U16)> testEvent;
|
||||
|
||||
testEvent.notify(this, &TestsJournalRecordAndPlayback::triggerReceiver);
|
||||
|
||||
// Initialize journal recording and fire off some events...
|
||||
Journal::Record("test.jrn");
|
||||
|
||||
if( !Journal::IsRecording() )
|
||||
{
|
||||
test(false, "Fail");
|
||||
return;
|
||||
}
|
||||
|
||||
testEvent.trigger(16);
|
||||
testEvent.trigger(17);
|
||||
testEvent.trigger(18);
|
||||
|
||||
test(_lastTriggerValue == 18, "Should encounter last triggered value (18).");
|
||||
|
||||
Journal::Stop();
|
||||
|
||||
// Clear it...
|
||||
_lastTriggerValue = 0;
|
||||
|
||||
// and play back - should get same thing.
|
||||
Journal::Play("test.jrn");
|
||||
|
||||
// Since we fired 3 events, it should take three loops.
|
||||
test(Journal::PlayNext(), "Should be two more events.");
|
||||
test(Journal::PlayNext(), "Should be one more event.");
|
||||
test(!Journal::PlayNext(), "Should be no more events.");
|
||||
|
||||
test(_lastTriggerValue == 18, "Should encounter last journaled value (18).");
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest(TestsJournalDynamicSignals, "Journal/DynamicSignals")
|
||||
{
|
||||
typedef JournaledSignal<void(U32, U16)> EventA;
|
||||
typedef JournaledSignal<void(U8, S8)> EventB;
|
||||
typedef JournaledSignal<void(U32, S32)> EventC;
|
||||
|
||||
EventA *dynamicA;
|
||||
EventB *dynamicB;
|
||||
EventC *dynamicC;
|
||||
|
||||
// Root, non-dynamic signal receiver.
|
||||
void receiverRoot(U8 msg)
|
||||
{
|
||||
if(msg==1)
|
||||
{
|
||||
dynamicA = new EventA();
|
||||
dynamicA->notify(this, &TestsJournalDynamicSignals::receiverA);
|
||||
}
|
||||
|
||||
if(msg==2)
|
||||
{
|
||||
dynamicB = new EventB();
|
||||
dynamicB->notify(this, &TestsJournalDynamicSignals::receiverB);
|
||||
}
|
||||
|
||||
if(msg==3)
|
||||
{
|
||||
dynamicC = new EventC();
|
||||
dynamicC->notify(this, &TestsJournalDynamicSignals::receiverC);
|
||||
}
|
||||
}
|
||||
|
||||
U32 recvA, recvB, recvC;
|
||||
|
||||
void receiverA(U32, U16 d)
|
||||
{
|
||||
recvA += d;
|
||||
}
|
||||
|
||||
void receiverB(U8, S8 d)
|
||||
{
|
||||
recvB += d;
|
||||
}
|
||||
|
||||
void receiverC(U32, S32 d)
|
||||
{
|
||||
recvC += d;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
// Reset our state values.
|
||||
recvA = recvB = recvC = 0;
|
||||
|
||||
// Set up a signal to start with.
|
||||
JournaledSignal<void(U8)> testEvent;
|
||||
testEvent.notify(this, &TestsJournalDynamicSignals::receiverRoot);
|
||||
|
||||
// Initialize journal recording and fire off some events...
|
||||
Journal::Record("test.jrn");
|
||||
|
||||
if( !Journal::IsRecording() )
|
||||
{
|
||||
test(false, "Fail");
|
||||
return;
|
||||
}
|
||||
|
||||
testEvent.trigger(1);
|
||||
dynamicA->trigger(8, 100);
|
||||
testEvent.trigger(2);
|
||||
dynamicA->trigger(8, 8);
|
||||
dynamicB->trigger(9, 'a');
|
||||
testEvent.trigger(3);
|
||||
SAFE_DELETE(dynamicB); // Test a deletion.
|
||||
dynamicC->trigger(8, 1);
|
||||
dynamicC->trigger(8, 1);
|
||||
|
||||
// Did we end up with expected values? Check before clearing.
|
||||
test(recvA == 108, "recvA wasn't 108 - something broken in signals?");
|
||||
test(recvB == 'a', "recvB wasn't 'a' - something broken in signals?");
|
||||
test(recvC == 2, "recvC wasn't 2 - something broken in signals?");
|
||||
|
||||
// Reset our state values.
|
||||
recvA = recvB = recvC = 0;
|
||||
|
||||
// And kill the journal...
|
||||
Journal::Stop();
|
||||
|
||||
// Also kill our remaining dynamic signals.
|
||||
SAFE_DELETE(dynamicA);
|
||||
SAFE_DELETE(dynamicB);
|
||||
SAFE_DELETE(dynamicC);
|
||||
|
||||
// Play back - should get same thing.
|
||||
Journal::Play("test.jrn");
|
||||
|
||||
// Since we fired 8 events, it should take 7+1=8 loops.
|
||||
for(S32 i=0; i<7; i++)
|
||||
test(Journal::PlayNext(), "Should be more events.");
|
||||
test(!Journal::PlayNext(), "Should be no more events.");
|
||||
|
||||
test(recvA == 108, "recvA wasn't 108 - something broken in journal?");
|
||||
test(recvB == 'a', "recvB wasn't 'a' - something broken in journal?");
|
||||
test(recvC == 2, "recvC wasn't 2 - something broken in journal?");
|
||||
}
|
||||
};
|
||||
|
|
@ -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,20 +20,21 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "core/strings/stringFunctions.h"
|
||||
#ifdef TORQUE_TESTS_ENABLED
|
||||
#include "testing/unitTesting.h"
|
||||
#include "core/util/path.h"
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "console/console.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
ConsoleFunction(unitTest_runTests, void, 1, 3, "([searchString[, bool skipInteractive]])"
|
||||
"@brief Run unit tests, or just the tests that prefix match against the searchString.\n\n"
|
||||
"@ingroup Console")
|
||||
TEST(MakeRelativePath, MakeRelativePath)
|
||||
{
|
||||
const char *searchString = (argc > 1 ? argv[1] : "");
|
||||
bool skip = (argc > 2 ? dAtob(argv[2]) : false);
|
||||
EXPECT_EQ(Torque::Path::MakeRelativePath("art/interiors/burg/file.png", "art/interiors/"), "burg/file.png");
|
||||
EXPECT_EQ(Torque::Path::MakeRelativePath("art/interiors/file.png", "art/interiors/burg/"), "../file.png");
|
||||
EXPECT_EQ(Torque::Path::MakeRelativePath("art/file.png", "art/interiors/burg/"), "../../file.png");
|
||||
EXPECT_EQ(Torque::Path::MakeRelativePath("file.png", "art/interiors/burg/"), "../../../file.png");
|
||||
EXPECT_EQ(Torque::Path::MakeRelativePath("art/interiors/burg/file.png", "art/interiors/burg/"), "file.png");
|
||||
EXPECT_EQ(Torque::Path::MakeRelativePath("art/interiors/camp/file.png", "art/interiors/burg/"), "../camp/file.png");
|
||||
EXPECT_EQ(Torque::Path::MakeRelativePath("art/interiors/burg/file.png", "art/shapes/"), "../interiors/burg/file.png");
|
||||
EXPECT_EQ(Torque::Path::MakeRelativePath("levels/den/file.png", "art/interiors/burg/"), "../../../levels/den/file.png");
|
||||
EXPECT_EQ(Torque::Path::MakeRelativePath("art/interiors/burg/file.png", "art/dts/burg/"), "../../interiors/burg/file.png");
|
||||
};
|
||||
|
||||
TestRun tr;
|
||||
tr.test(searchString, skip);
|
||||
}
|
||||
#endif
|
||||
332
Engine/source/core/util/test/strTest.cpp
Normal file
332
Engine/source/core/util/test/strTest.cpp
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "core/util/str.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
#include "core/strings/unicode.h"
|
||||
|
||||
/// This is called Str, not String, because googletest doesn't let you use both
|
||||
/// TEST(x) and TEST_FIX(x). So this fixture is called Str, to match the StrTest
|
||||
/// struct, and the remaining fixture-les tests are named String.
|
||||
FIXTURE(Str)
|
||||
{
|
||||
protected:
|
||||
struct StrTest
|
||||
{
|
||||
const UTF8* mData;
|
||||
const UTF16* mUTF16;
|
||||
U32 mLength;
|
||||
|
||||
StrTest() : mData( 0 ), mUTF16( 0 ) {}
|
||||
StrTest( const char* str )
|
||||
: mData( str ), mLength( str ? dStrlen( str ) : 0 ), mUTF16( NULL )
|
||||
{
|
||||
if( str )
|
||||
mUTF16 = convertUTF8toUTF16( mData );
|
||||
}
|
||||
~StrTest()
|
||||
{
|
||||
if( mUTF16 )
|
||||
delete [] mUTF16;
|
||||
}
|
||||
};
|
||||
|
||||
Vector< StrTest* > mStrings;
|
||||
|
||||
virtual void SetUp()
|
||||
{
|
||||
mStrings.push_back( new StrTest( NULL ) );
|
||||
mStrings.push_back( new StrTest( "" ) );
|
||||
mStrings.push_back( new StrTest( "Torque" ) );
|
||||
mStrings.push_back( new StrTest( "TGEA" ) );
|
||||
mStrings.push_back( new StrTest( "GarageGames" ) );
|
||||
mStrings.push_back( new StrTest( "TGB" ) );
|
||||
mStrings.push_back( new StrTest( "games" ) );
|
||||
mStrings.push_back( new StrTest( "engine" ) );
|
||||
mStrings.push_back( new StrTest( "rocks" ) );
|
||||
mStrings.push_back( new StrTest( "technology" ) );
|
||||
mStrings.push_back( new StrTest( "Torque 3D" ) );
|
||||
mStrings.push_back( new StrTest( "Torque 2D" ) );
|
||||
}
|
||||
|
||||
virtual void TearDown()
|
||||
{
|
||||
for( U32 i = 0; i < mStrings.size(); ++ i )
|
||||
delete mStrings[ i ];
|
||||
mStrings.clear();
|
||||
}
|
||||
};
|
||||
|
||||
#define EACH_STRING(i) \
|
||||
for( U32 i = 0; i < mStrings.size(); ++ i )
|
||||
#define EACH_PAIR(i, j) \
|
||||
for( U32 i = 0; i < mStrings.size(); ++ i ) \
|
||||
for( U32 j = 0; j < mStrings.size(); ++ j )
|
||||
|
||||
TEST_FIX(Str, Test1)
|
||||
{
|
||||
EACH_STRING(i)
|
||||
{
|
||||
StrTest& data = *mStrings[i];
|
||||
String str( data.mData );
|
||||
String str16( data.mUTF16 );
|
||||
|
||||
EXPECT_TRUE( str.length() == data.mLength );
|
||||
EXPECT_TRUE( str.size() == data.mLength + 1 );
|
||||
EXPECT_TRUE( str.isEmpty() || str.length() > 0 );
|
||||
EXPECT_TRUE( str.length() == str16.length() );
|
||||
EXPECT_TRUE( str.size() == str16.size() );
|
||||
|
||||
EXPECT_TRUE( dMemcmp( str.utf16(), str16.utf16(), str.length() * sizeof( UTF16 ) ) == 0 );
|
||||
EXPECT_TRUE( !data.mData || dMemcmp( str.utf16(), data.mUTF16, str.length() * sizeof( UTF16 ) ) == 0 );
|
||||
EXPECT_TRUE( !data.mData || dMemcmp( str16.utf8(), data.mData, str.length() ) == 0 );
|
||||
|
||||
EXPECT_TRUE( !data.mData || dStrcmp( str.utf8(), data.mData ) == 0 );
|
||||
EXPECT_TRUE( !data.mData || dStrcmp( str.utf16(), data.mUTF16 ) == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_FIX(Str, Test2)
|
||||
{
|
||||
EACH_STRING(i)
|
||||
{
|
||||
StrTest& data = *mStrings[i];
|
||||
String str( data.mData );
|
||||
|
||||
EXPECT_TRUE( str == str );
|
||||
EXPECT_FALSE( str != str );
|
||||
EXPECT_FALSE( str < str );
|
||||
EXPECT_FALSE( str > str );
|
||||
EXPECT_TRUE( str.equal( str ) );
|
||||
EXPECT_TRUE( str.equal( str, String::NoCase ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_FIX(Str, Test3)
|
||||
{
|
||||
EACH_PAIR(i, j)
|
||||
{
|
||||
StrTest& d1 = *mStrings[i];
|
||||
StrTest& d2 = *mStrings[j];
|
||||
|
||||
if( &d1 != &d2 )
|
||||
EXPECT_TRUE( String( d1.mData ) != String( d2.mData )
|
||||
|| ( String( d1.mData ).isEmpty() && String( d2.mData ).isEmpty() ) );
|
||||
else
|
||||
EXPECT_TRUE( String( d1.mData ) == String( d2.mData ) );
|
||||
}
|
||||
}
|
||||
|
||||
TEST(String, Empty)
|
||||
{
|
||||
EXPECT_TRUE( String().length() == 0 );
|
||||
EXPECT_TRUE( String( "" ).length() == 0 );
|
||||
EXPECT_TRUE( String().size() == 1 );
|
||||
EXPECT_TRUE( String( "" ).size() == 1 );
|
||||
EXPECT_TRUE( String().isEmpty() );
|
||||
EXPECT_TRUE( String( "" ).isEmpty() );
|
||||
}
|
||||
|
||||
TEST(String, Trim)
|
||||
{
|
||||
EXPECT_TRUE( String( " Foobar Barfoo \n\t " ).trim() == String( "Foobar Barfoo" ) );
|
||||
EXPECT_TRUE( String( "Foobar" ).trim() == String( "Foobar" ) );
|
||||
EXPECT_TRUE( String( " " ).trim().isEmpty() );
|
||||
}
|
||||
|
||||
TEST(String, Compare)
|
||||
{
|
||||
String str( "Foobar" );
|
||||
|
||||
EXPECT_TRUE( str.compare( "Foo", 3 ) == 0 );
|
||||
EXPECT_TRUE( str.compare( "bar", 3, String::NoCase | String::Right ) == 0 );
|
||||
EXPECT_TRUE( str.compare( "foo", 3, String::NoCase ) == 0 );
|
||||
EXPECT_TRUE( str.compare( "BAR", 3, String::NoCase | String::Right ) == 0 );
|
||||
EXPECT_TRUE( str.compare( "Foobar" ) == 0 );
|
||||
EXPECT_TRUE( str.compare( "Foo" ) != 0 );
|
||||
EXPECT_TRUE( str.compare( "foobar", 0, String::NoCase ) == 0 );
|
||||
EXPECT_TRUE( str.compare( "FOOBAR", 0, String::NoCase ) == 0 );
|
||||
EXPECT_TRUE( str.compare( "Foobar", 0, String::Right ) == 0 );
|
||||
EXPECT_TRUE( str.compare( "foobar", 0, String::NoCase | String::Right ) == 0 );
|
||||
}
|
||||
|
||||
TEST(String, Order)
|
||||
{
|
||||
Vector< String > strs;
|
||||
|
||||
strs.push_back( "a" );
|
||||
strs.push_back( "a0" );
|
||||
strs.push_back( "a1" );
|
||||
strs.push_back( "a1a" );
|
||||
strs.push_back( "a1b" );
|
||||
strs.push_back( "a2" );
|
||||
strs.push_back( "a10" );
|
||||
strs.push_back( "a20" );
|
||||
|
||||
for( U32 i = 0; i < strs.size(); ++ i )
|
||||
{
|
||||
for( U32 j = 0; j < i; ++ j )
|
||||
{
|
||||
EXPECT_TRUE( strs[ j ] < strs[ i ] );
|
||||
EXPECT_TRUE( strs[ i ] > strs[ j ] );
|
||||
|
||||
EXPECT_TRUE( !( strs[ j ] > strs[ i ] ) );
|
||||
EXPECT_TRUE( !( strs[ i ] < strs[ i ] ) );
|
||||
|
||||
EXPECT_TRUE( strs[ j ] <= strs[ i ] );
|
||||
EXPECT_TRUE( strs[ i ] >= strs[ j ] );
|
||||
}
|
||||
|
||||
EXPECT_TRUE( !( strs[ i ] < strs[ i ] ) );
|
||||
EXPECT_TRUE( !( strs[ i ] > strs[ i ] ) );
|
||||
EXPECT_TRUE( strs[ i ] <= strs[ i ] );
|
||||
EXPECT_TRUE( strs[ i ] >= strs[ i ] );
|
||||
|
||||
for( U32 j = i + 1; j < strs.size(); ++ j )
|
||||
{
|
||||
EXPECT_TRUE( strs[ j ] > strs[ i ] );
|
||||
EXPECT_TRUE( strs[ i ] < strs[ j ] );
|
||||
|
||||
EXPECT_TRUE( !( strs[ j ] < strs[ i ] ) );
|
||||
EXPECT_TRUE( !( strs[ i ] > strs[ j ] ) );
|
||||
|
||||
EXPECT_TRUE( strs[ j ] >= strs[ i ] );
|
||||
EXPECT_TRUE( strs[ i ] <= strs[ j ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO
|
||||
TEST(String, Find)
|
||||
{
|
||||
}
|
||||
|
||||
TEST(String, Insert)
|
||||
{
|
||||
// String.insert( Pos, Char )
|
||||
EXPECT_TRUE( String( "aa" ).insert( 1, 'c' ) == String( "aca" ) );
|
||||
|
||||
// String.insert( Pos, String )
|
||||
EXPECT_TRUE( String( "aa" ).insert( 1, "cc" ) == String( "acca" ) );
|
||||
EXPECT_TRUE( String( "aa" ).insert( 1, String( "cc" ) ) == String( "acca" ) );
|
||||
|
||||
// String.insert( Pos, String, Len )
|
||||
EXPECT_TRUE( String( "aa" ).insert( 1, "ccdddd", 2 ) == String( "acca" ) );
|
||||
}
|
||||
|
||||
TEST(String, Erase)
|
||||
{
|
||||
EXPECT_TRUE( String( "abba" ).erase( 1, 2 ) == String( "aa" ) );
|
||||
EXPECT_TRUE( String( "abba" ).erase( 0, 4 ).isEmpty() );
|
||||
}
|
||||
|
||||
TEST(String, Replace)
|
||||
{
|
||||
// String.replace( Pos, Len, String )
|
||||
EXPECT_TRUE( String( "abba" ).replace( 1, 2, "ccc" ) == String( "accca" ) );
|
||||
EXPECT_TRUE( String( "abba" ).replace( 1, 2, String( "ccc" ) ) == String( "accca" ) );
|
||||
EXPECT_TRUE( String( "abba" ).replace( 0, 4, "" ).isEmpty() );
|
||||
EXPECT_TRUE( String( "abba" ).replace( 2, 2, "c" ) == String( "abc" ) );
|
||||
|
||||
// String.replace( Char, Char )
|
||||
EXPECT_TRUE( String().replace( 'a', 'b' ).isEmpty() );
|
||||
EXPECT_TRUE( String( "ababc" ).replace( 'a', 'b' ) == String( "bbbbc" ) );
|
||||
EXPECT_TRUE( String( "ababc" ).replace( 'd', 'e' ) == String( "ababc" ) );
|
||||
|
||||
// String.replace( String, String )
|
||||
EXPECT_TRUE( String().replace( "foo", "bar" ).isEmpty() );
|
||||
EXPECT_TRUE( String( "foobarfoo" ).replace( "foo", "bar" ) == String( "barbarbar" ) );
|
||||
EXPECT_TRUE( String( "foobar" ).replace( "xx", "yy" ) == String( "foobar" ) );
|
||||
EXPECT_TRUE( String( "foofoofoo" ).replace( "foo", "" ).isEmpty() );
|
||||
}
|
||||
|
||||
TEST(String, SubStr)
|
||||
{
|
||||
EXPECT_TRUE( String( "foobar" ).substr( 0, 3 ) == String( "foo" ) );
|
||||
EXPECT_TRUE( String( "foobar" ).substr( 3 ) == String( "bar" ) );
|
||||
EXPECT_TRUE( String( "foobar" ).substr( 2, 2 ) == String( "ob" ) );
|
||||
EXPECT_TRUE( String( "foobar" ).substr( 2, 0 ).isEmpty() );
|
||||
EXPECT_TRUE( String( "foobar" ).substr( 0, 6 ) == String( "foobar" ) );
|
||||
}
|
||||
|
||||
TEST(String, ToString)
|
||||
{
|
||||
EXPECT_TRUE( String::ToString( U32( 1 ) ) == String( "1" ) );
|
||||
EXPECT_TRUE( String::ToString( S32( -1 ) ) == String( "-1" ) );
|
||||
EXPECT_TRUE( String::ToString( F32( 1.01 ) ) == String( "1.01" ) );
|
||||
EXPECT_TRUE( String::ToString( "%s%i", "foo", 1 ) == String( "foo1" ) );
|
||||
}
|
||||
|
||||
TEST(String, CaseConversion)
|
||||
{
|
||||
EXPECT_TRUE( String::ToLower( "foobar123." ) == String( "foobar123." ) );
|
||||
EXPECT_TRUE( String::ToLower( "FOOBAR123." ) == String( "foobar123." ) );
|
||||
EXPECT_TRUE( String::ToUpper( "barfoo123." ) == String( "BARFOO123." ) );
|
||||
EXPECT_TRUE( String::ToUpper( "BARFOO123." ) == String( "BARFOO123." ) );
|
||||
}
|
||||
|
||||
TEST(String, Concat)
|
||||
{
|
||||
EXPECT_TRUE( String( "foo" ) + String( "bar" ) == String( "foobar" ) );
|
||||
EXPECT_TRUE( String() + String( "bar" ) == String( "bar" ) );
|
||||
EXPECT_TRUE( String( "foo" ) + String() == String( "foo" ) );
|
||||
EXPECT_TRUE( String() + String() == String() );
|
||||
EXPECT_TRUE( String( "fo" ) + 'o' == String( "foo" ) );
|
||||
EXPECT_TRUE( 'f' + String( "oo" ) == String( "foo" ) );
|
||||
EXPECT_TRUE( String( "foo" ) + "bar" == String( "foobar" ) );
|
||||
EXPECT_TRUE( "foo" + String( "bar" ) == String( "foobar" ) );
|
||||
}
|
||||
|
||||
TEST(String, Hash)
|
||||
{
|
||||
EXPECT_TRUE( String( "foo" ).getHashCaseSensitive() == String( "foo" ).getHashCaseSensitive() );
|
||||
EXPECT_TRUE( String( "foo" ).getHashCaseSensitive() != String( "bar" ).getHashCaseSensitive() );
|
||||
EXPECT_TRUE( String( "foo" ).getHashCaseInsensitive() == String( "FOO" ).getHashCaseInsensitive() );
|
||||
}
|
||||
|
||||
TEST(String, Intern)
|
||||
{
|
||||
EXPECT_TRUE( String( "foo" ).intern().isSame( String( "foo" ).intern() ) );
|
||||
EXPECT_TRUE( !String( "foo" ).intern().isSame( String( "bar" ).intern() ) );
|
||||
EXPECT_TRUE( !String( "foo" ).intern().isSame( String( "Foo" ).intern() ) );
|
||||
EXPECT_TRUE( String( "foo" ).intern() == String( "foo" ).intern() );
|
||||
EXPECT_TRUE( String( "foo" ).intern() != String( "bar" ).intern() );
|
||||
EXPECT_TRUE( String( "foo" ).intern().isInterned() );
|
||||
}
|
||||
|
||||
TEST(StringBuilder, StringBuilder)
|
||||
{
|
||||
StringBuilder str;
|
||||
|
||||
str.append( 'f' );
|
||||
str.append( "oo" );
|
||||
str.append( String( "ba" ) );
|
||||
str.append( "rfajskfdj", 1 );
|
||||
str.format( "%s", "barfoo" );
|
||||
|
||||
EXPECT_TRUE( str.end() == String( "foobarbarfoo" ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
129
Engine/source/core/util/test/swizzleTest.cpp
Normal file
129
Engine/source/core/util/test/swizzleTest.cpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/platform.h"
|
||||
#include "testing/unitTesting.h"
|
||||
#include "core/util/swizzle.h"
|
||||
#include "math/mRandom.h"
|
||||
|
||||
class TestStruct
|
||||
{
|
||||
private:
|
||||
static U32 smIdx;
|
||||
U32 mIdx;
|
||||
U32 mData;
|
||||
|
||||
public:
|
||||
TestStruct( const S32 data = -1 ) : mData( data ), mIdx( smIdx++ ) {};
|
||||
|
||||
dsize_t Idx() const { return mIdx; }
|
||||
|
||||
U32 Data() const { return mData; }
|
||||
void Data(U32 val) { mData = val; }
|
||||
};
|
||||
|
||||
U32 TestStruct::smIdx = 0;
|
||||
|
||||
TEST(Swizzle, Swizzle)
|
||||
{
|
||||
//------------------------------------------------------------------------
|
||||
// Debugger-Observable Functionality Tests
|
||||
//------------------------------------------------------------------------
|
||||
U8 simpleBuffer[] = { 0, 1, 2, 3 };
|
||||
U8 simpleTest[] = { 0, 1, 2, 3 };
|
||||
|
||||
#define RESET_SIMPLE() dMemcpy( simpleTest, simpleBuffer, sizeof( simpleBuffer ) )
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// No-switch test
|
||||
dsize_t noSwzl4[] = { 0, 1, 2, 3 };
|
||||
Swizzle<U8,4> noSwizzle4( noSwzl4 );
|
||||
|
||||
noSwizzle4.InPlace( simpleTest, sizeof( simpleTest ) );
|
||||
EXPECT_EQ( dMemcmp( simpleTest, simpleBuffer, sizeof( simpleBuffer ) ), 0 )
|
||||
<< "No-switch test failed!";
|
||||
RESET_SIMPLE();
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// No-brainer RGBA->BGRA test
|
||||
dsize_t bgraSwzl[] = { 2, 1, 0, 3 };
|
||||
Swizzle<U8,4> bgraSwizzle( bgraSwzl );
|
||||
|
||||
U8 bgraTest[] = { 2, 1, 0, 3 };
|
||||
bgraSwizzle.InPlace( simpleTest, sizeof( simpleTest ) );
|
||||
EXPECT_EQ( dMemcmp( simpleTest, bgraTest, sizeof( bgraTest ) ), 0 )
|
||||
<< "U8 RGBA->BGRA test failed";
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Reverse test
|
||||
bgraSwizzle.InPlace( simpleTest, sizeof( simpleTest ) );
|
||||
EXPECT_EQ( dMemcmp( simpleTest, simpleBuffer, sizeof( simpleBuffer ) ), 0 )
|
||||
<< "U8 RGBA->BGRA reverse test failed";
|
||||
|
||||
RESET_SIMPLE();
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Object support test
|
||||
Swizzle<TestStruct,4> bgraObjSwizzle( bgraSwzl );
|
||||
{
|
||||
U32 objIdx[] = { 0, 1, 2, 3 };
|
||||
|
||||
FrameTemp<TestStruct> objTest( sizeof( objIdx ) / sizeof( U32 ) );
|
||||
FrameTemp<U32> randData( sizeof( objIdx ) / sizeof( U32 ) );
|
||||
|
||||
bool same = true;
|
||||
|
||||
for( U32 i = 0; i < sizeof( objIdx ) / sizeof( U32 ); i++ )
|
||||
{
|
||||
// Make random data and assign it
|
||||
randData[i] = gRandGen.randI();
|
||||
objTest[i].Data( randData[i] );
|
||||
|
||||
// Continue object sanity check
|
||||
same &= ( objTest[i].Idx() == objIdx[i] );
|
||||
}
|
||||
|
||||
EXPECT_TRUE( same )
|
||||
<< "Test object failed to be competent";
|
||||
|
||||
bgraObjSwizzle.InPlace( ~objTest, sizeof( TestStruct ) * ( sizeof( objIdx ) / sizeof( U32 ) ) );
|
||||
same = true;
|
||||
|
||||
for( U32 i = 0; i < sizeof( objIdx ) / sizeof( U32 ); i++ )
|
||||
same &= ( objTest[i].Idx() == bgraTest[i] ) && ( objTest[i].Data() == randData[ (U32)bgraTest[ i ] ] );
|
||||
|
||||
EXPECT_TRUE( same )
|
||||
<< "Object RGBA->BGRA test failed.";
|
||||
|
||||
bgraObjSwizzle.InPlace( ~objTest, sizeof( TestStruct ) * ( sizeof( objIdx ) / sizeof( U32 ) ) );
|
||||
same = true;
|
||||
|
||||
for( U32 i = 0; i < sizeof( objIdx ) / sizeof( U32 ); i++ )
|
||||
same &= ( objTest[i].Idx() == objIdx[i] ) && ( objTest[i].Data() == randData[i] );
|
||||
|
||||
EXPECT_TRUE( same )
|
||||
<< "Object RGBA->BGRA reverse test failed.";
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -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,34 +20,30 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "unit/test.h"
|
||||
#include "unit/memoryTester.h"
|
||||
#include "core/util/tVector.h"
|
||||
#ifdef TORQUE_TESTS_ENABLED
|
||||
#include "testing/unitTesting.h"
|
||||
#include "core/util/tFixedSizeDeque.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateUnitTest(TestVectorAllocate, "Types/Vector")
|
||||
TEST(FixedSizeDeque, FixedSizeDeque)
|
||||
{
|
||||
void run()
|
||||
{
|
||||
MemoryTester m;
|
||||
m.mark();
|
||||
enum { DEQUE_SIZE = 3 };
|
||||
FixedSizeDeque< U32 > deque( DEQUE_SIZE );
|
||||
|
||||
Vector<S32> *vector = new Vector<S32>;
|
||||
for(S32 i=0; i<1000; i++)
|
||||
vector->push_back(10000 + i);
|
||||
EXPECT_EQ( deque.capacity(), DEQUE_SIZE );
|
||||
EXPECT_EQ( deque.size(), 0 );
|
||||
|
||||
// Erase the first element, 500 times.
|
||||
for(S32 i=0; i<500; i++)
|
||||
vector->erase(U32(0));
|
||||
deque.pushFront( 1 );
|
||||
EXPECT_EQ( deque.capacity(), ( DEQUE_SIZE - 1 ) );
|
||||
EXPECT_EQ( deque.size(), 1 );
|
||||
EXPECT_FALSE( deque.isEmpty() );
|
||||
|
||||
vector->compact();
|
||||
deque.pushBack( 2 );
|
||||
EXPECT_EQ( deque.capacity(), ( DEQUE_SIZE - 2 ) );
|
||||
EXPECT_EQ( deque.size(), 2 );
|
||||
|
||||
test(vector->size() == 500, "Vector was unexpectedly short!");
|
||||
EXPECT_EQ( deque.popFront(), 1 );
|
||||
EXPECT_EQ( deque.popFront(), 2 );
|
||||
EXPECT_TRUE( deque.isEmpty() );
|
||||
};
|
||||
|
||||
delete vector;
|
||||
|
||||
test(m.check(), "Vector allocation test leaked memory!");
|
||||
}
|
||||
};
|
||||
#endif
|
||||
125
Engine/source/core/util/test/tVectorTest.cpp
Normal file
125
Engine/source/core/util/test/tVectorTest.cpp
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "core/util/tVector.h"
|
||||
|
||||
// Define some test data used below.
|
||||
FIXTURE(Vector)
|
||||
{
|
||||
public:
|
||||
struct Dtor
|
||||
{
|
||||
bool* ptr;
|
||||
Dtor() {} // Needed for vector increment.
|
||||
Dtor(bool* ptr): ptr(ptr) {}
|
||||
~Dtor()
|
||||
{
|
||||
*ptr = true;
|
||||
}
|
||||
};
|
||||
|
||||
static const S32 ints[];
|
||||
static const U32 length;
|
||||
static S32 QSORT_CALLBACK sortInts(const S32* a, const S32* b)
|
||||
{
|
||||
S32 av = *a;
|
||||
S32 bv = *b;
|
||||
|
||||
if (av < bv)
|
||||
return -1;
|
||||
else if (av > bv)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
const S32 VectorFixture::ints[] = {0, 10, 2, 3, 14, 4, 12, 6, 16, 7, 8, 1, 11, 5, 13, 9, 15};
|
||||
const U32 VectorFixture::length = sizeof(VectorFixture::ints) / sizeof(S32);
|
||||
|
||||
TEST_FIX(Vector, Allocation)
|
||||
{
|
||||
Vector<S32> *vector = new Vector<S32>;
|
||||
for (S32 i = 0; i < 1000; i++)
|
||||
vector->push_back(10000 + i);
|
||||
|
||||
// Erase the first element, 500 times.
|
||||
for (S32 i = 0; i < 500; i++)
|
||||
vector->erase(U32(0));
|
||||
|
||||
vector->compact();
|
||||
|
||||
EXPECT_EQ(vector->size(), 500) << "Vector was unexpectedly short!";
|
||||
|
||||
delete vector;
|
||||
}
|
||||
|
||||
TEST_FIX(Vector, Deallocation)
|
||||
{
|
||||
bool dtorVals[10];
|
||||
Vector<Dtor> v;
|
||||
|
||||
// Only add the first 9 entries; the last is populated below.
|
||||
for (U32 i = 0; i < 9; i++)
|
||||
v.push_back(Dtor(&dtorVals[i]));
|
||||
|
||||
// Fill the values array with false so we can test for destruction.
|
||||
for (U32 i = 0; i < 10; i++)
|
||||
dtorVals[i] = false;
|
||||
|
||||
v.decrement();
|
||||
EXPECT_TRUE(dtorVals[8]) << "Vector::decrement failed to call destructor";
|
||||
|
||||
v.decrement(2);
|
||||
EXPECT_TRUE(dtorVals[7]) << "Vector::decrement failed to call destructor";
|
||||
EXPECT_TRUE(dtorVals[6]) << "Vector::decrement failed to call destructor";
|
||||
|
||||
v.pop_back();
|
||||
EXPECT_TRUE(dtorVals[5]) << "Vector::pop_back failed to call destructor";
|
||||
|
||||
v.increment();
|
||||
v.last() = Dtor(&dtorVals[9]);
|
||||
v.clear();
|
||||
|
||||
// All elements should have been destructed.
|
||||
for (U32 i = 0; i < 10; i++)
|
||||
EXPECT_TRUE(dtorVals[i])
|
||||
<< "Element " << i << "'s destructor was not called";
|
||||
}
|
||||
|
||||
TEST_FIX(Vector, Sorting)
|
||||
{
|
||||
Vector<S32> v;
|
||||
|
||||
for(U32 i = 0; i < length; i++)
|
||||
v.push_back(ints[i]);
|
||||
|
||||
v.sort(sortInts);
|
||||
|
||||
for(U32 i = 0; i < length - 1; i++)
|
||||
EXPECT_TRUE(v[i] <= v[i + 1])
|
||||
<< "Element " << i << " was not in sorted order";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "core/util/path.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
#define TEST( x ) test( ( x ), "FAIL: " #x )
|
||||
|
||||
CreateUnitTest(TestPathMakeRelativePath, "Core/Util/Path/MakeRelativePath")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
TEST(Torque::Path::MakeRelativePath("art/interiors/burg/file.png", "art/interiors/") == "burg/file.png");
|
||||
TEST(Torque::Path::MakeRelativePath("art/interiors/file.png", "art/interiors/burg/") == "../file.png");
|
||||
TEST(Torque::Path::MakeRelativePath("art/file.png", "art/interiors/burg/") == "../../file.png");
|
||||
TEST(Torque::Path::MakeRelativePath("file.png", "art/interiors/burg/") == "../../../file.png");
|
||||
TEST(Torque::Path::MakeRelativePath("art/interiors/burg/file.png", "art/interiors/burg/") == "file.png");
|
||||
TEST(Torque::Path::MakeRelativePath("art/interiors/camp/file.png", "art/interiors/burg/") == "../camp/file.png");
|
||||
TEST(Torque::Path::MakeRelativePath("art/interiors/burg/file.png", "art/shapes/") == "../interiors/burg/file.png");
|
||||
TEST(Torque::Path::MakeRelativePath("levels/den/file.png", "art/interiors/burg/") == "../../../levels/den/file.png");
|
||||
TEST(Torque::Path::MakeRelativePath("art/interiors/burg/file.png", "art/dts/burg/") == "../../interiors/burg/file.png");
|
||||
}
|
||||
};
|
||||
|
|
@ -1,358 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "core/util/str.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
#include "core/strings/unicode.h"
|
||||
|
||||
|
||||
#ifndef TORQUE_SHIPPING
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
#define TEST( x ) test( ( x ), "FAIL: " #x )
|
||||
#define XTEST( t, x ) t->test( ( x ), "FAIL: " #x )
|
||||
|
||||
CreateUnitTest( TestString, "Util/String" )
|
||||
{
|
||||
struct StrTest
|
||||
{
|
||||
const UTF8* mData;
|
||||
const UTF16* mUTF16;
|
||||
U32 mLength;
|
||||
|
||||
StrTest() : mData( 0 ), mUTF16( 0 ) {}
|
||||
StrTest( const char* str )
|
||||
: mData( str ), mLength( str ? dStrlen( str ) : 0 ), mUTF16( NULL )
|
||||
{
|
||||
if( str )
|
||||
mUTF16 = convertUTF8toUTF16( mData );
|
||||
}
|
||||
~StrTest()
|
||||
{
|
||||
if( mUTF16 )
|
||||
delete [] mUTF16;
|
||||
}
|
||||
};
|
||||
|
||||
Vector< StrTest* > mStrings;
|
||||
|
||||
template< class T >
|
||||
void runTestOnStrings()
|
||||
{
|
||||
for( U32 i = 0; i < mStrings.size(); ++ i )
|
||||
T::run( this, *mStrings[ i ] );
|
||||
}
|
||||
template< class T >
|
||||
void runPairwiseTestOnStrings()
|
||||
{
|
||||
for( U32 i = 0; i < mStrings.size(); ++ i )
|
||||
for( U32 j = 0; j < mStrings.size(); ++ j )
|
||||
T::run( this, *mStrings[ i ], *mStrings[ j ] );
|
||||
}
|
||||
|
||||
struct Test1
|
||||
{
|
||||
static void run( TestString* test, StrTest& data )
|
||||
{
|
||||
String str( data.mData );
|
||||
String str16( data.mUTF16 );
|
||||
|
||||
XTEST( test, str.length() == data.mLength );
|
||||
XTEST( test, str.size() == data.mLength + 1 );
|
||||
XTEST( test, str.isEmpty() || str.length() > 0 );
|
||||
XTEST( test, str.length() == str16.length() );
|
||||
XTEST( test, str.size() == str16.size() );
|
||||
|
||||
XTEST( test, dMemcmp( str.utf16(), str16.utf16(), str.length() * sizeof( UTF16 ) ) == 0 );
|
||||
XTEST( test, !data.mData || dMemcmp( str.utf16(), data.mUTF16, str.length() * sizeof( UTF16 ) ) == 0 );
|
||||
XTEST( test, !data.mData || dMemcmp( str16.utf8(), data.mData, str.length() ) == 0 );
|
||||
|
||||
XTEST( test, !data.mData || dStrcmp( str.utf8(), data.mData ) == 0 );
|
||||
XTEST( test, !data.mData || dStrcmp( str.utf16(), data.mUTF16 ) == 0 );
|
||||
}
|
||||
};
|
||||
|
||||
struct Test2
|
||||
{
|
||||
static void run( TestString* test, StrTest& data )
|
||||
{
|
||||
String str( data.mData );
|
||||
|
||||
XTEST( test, str == str );
|
||||
XTEST( test, !( str != str ) );
|
||||
XTEST( test, !( str < str ) );
|
||||
XTEST( test, !( str > str ) );
|
||||
XTEST( test, str.equal( str ) );
|
||||
XTEST( test, str.equal( str, String::NoCase ) );
|
||||
}
|
||||
};
|
||||
|
||||
struct Test3
|
||||
{
|
||||
static void run( TestString* test, StrTest& d1, StrTest& d2 )
|
||||
{
|
||||
if( &d1 != &d2 )
|
||||
XTEST( test, String( d1.mData ) != String( d2.mData )
|
||||
|| ( String( d1.mData ).isEmpty() && String( d2.mData ).isEmpty() ) );
|
||||
else
|
||||
XTEST( test, String( d1.mData ) == String( d2.mData ) );
|
||||
}
|
||||
};
|
||||
|
||||
void testEmpty()
|
||||
{
|
||||
TEST( String().length() == 0 );
|
||||
TEST( String( "" ).length() == 0 );
|
||||
TEST( String().size() == 1 );
|
||||
TEST( String( "" ).size() == 1 );
|
||||
TEST( String().isEmpty() );
|
||||
TEST( String( "" ).isEmpty() );
|
||||
}
|
||||
|
||||
void testTrim()
|
||||
{
|
||||
TEST( String( " Foobar Barfoo \n\t " ).trim() == String( "Foobar Barfoo" ) );
|
||||
TEST( String( "Foobar" ).trim() == String( "Foobar" ) );
|
||||
TEST( String( " " ).trim().isEmpty() );
|
||||
}
|
||||
|
||||
void testCompare()
|
||||
{
|
||||
String str( "Foobar" );
|
||||
|
||||
TEST( str.compare( "Foo", 3 ) == 0 );
|
||||
TEST( str.compare( "bar", 3, String::NoCase | String::Right ) == 0 );
|
||||
TEST( str.compare( "foo", 3, String::NoCase ) == 0 );
|
||||
TEST( str.compare( "BAR", 3, String::NoCase | String::Right ) == 0 );
|
||||
TEST( str.compare( "Foobar" ) == 0 );
|
||||
TEST( str.compare( "Foo" ) != 0 );
|
||||
TEST( str.compare( "foobar", 0, String::NoCase ) == 0 );
|
||||
TEST( str.compare( "FOOBAR", 0, String::NoCase ) == 0 );
|
||||
TEST( str.compare( "Foobar", 0, String::Right ) == 0 );
|
||||
TEST( str.compare( "foobar", 0, String::NoCase | String::Right ) == 0 );
|
||||
}
|
||||
|
||||
void testOrder()
|
||||
{
|
||||
Vector< String > strs;
|
||||
|
||||
strs.push_back( "a" );
|
||||
strs.push_back( "a0" );
|
||||
strs.push_back( "a1" );
|
||||
strs.push_back( "a1a" );
|
||||
strs.push_back( "a1b" );
|
||||
strs.push_back( "a2" );
|
||||
strs.push_back( "a10" );
|
||||
strs.push_back( "a20" );
|
||||
|
||||
for( U32 i = 0; i < strs.size(); ++ i )
|
||||
{
|
||||
for( U32 j = 0; j < i; ++ j )
|
||||
{
|
||||
TEST( strs[ j ] < strs[ i ] );
|
||||
TEST( strs[ i ] > strs[ j ] );
|
||||
|
||||
TEST( !( strs[ j ] > strs[ i ] ) );
|
||||
TEST( !( strs[ i ] < strs[ i ] ) );
|
||||
|
||||
TEST( strs[ j ] <= strs[ i ] );
|
||||
TEST( strs[ i ] >= strs[ j ] );
|
||||
}
|
||||
|
||||
TEST( !( strs[ i ] < strs[ i ] ) );
|
||||
TEST( !( strs[ i ] > strs[ i ] ) );
|
||||
TEST( strs[ i ] <= strs[ i ] );
|
||||
TEST( strs[ i ] >= strs[ i ] );
|
||||
|
||||
for( U32 j = i + 1; j < strs.size(); ++ j )
|
||||
{
|
||||
TEST( strs[ j ] > strs[ i ] );
|
||||
TEST( strs[ i ] < strs[ j ] );
|
||||
|
||||
TEST( !( strs[ j ] < strs[ i ] ) );
|
||||
TEST( !( strs[ i ] > strs[ j ] ) );
|
||||
|
||||
TEST( strs[ j ] >= strs[ i ] );
|
||||
TEST( strs[ i ] <= strs[ j ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testFind()
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
void testInsert()
|
||||
{
|
||||
// String.insert( Pos, Char )
|
||||
TEST( String( "aa" ).insert( 1, 'c' ) == String( "aca" ) );
|
||||
|
||||
// String.insert( Pos, String )
|
||||
TEST( String( "aa" ).insert( 1, "cc" ) == String( "acca" ) );
|
||||
TEST( String( "aa" ).insert( 1, String( "cc" ) ) == String( "acca" ) );
|
||||
|
||||
// String.insert( Pos, String, Len )
|
||||
TEST( String( "aa" ).insert( 1, "ccdddd", 2 ) == String( "acca" ) );
|
||||
}
|
||||
|
||||
void testErase()
|
||||
{
|
||||
TEST( String( "abba" ).erase( 1, 2 ) == String( "aa" ) );
|
||||
TEST( String( "abba" ).erase( 0, 4 ).isEmpty() );
|
||||
}
|
||||
|
||||
void testReplace()
|
||||
{
|
||||
// String.replace( Pos, Len, String )
|
||||
TEST( String( "abba" ).replace( 1, 2, "ccc" ) == String( "accca" ) );
|
||||
TEST( String( "abba" ).replace( 1, 2, String( "ccc" ) ) == String( "accca" ) );
|
||||
TEST( String( "abba" ).replace( 0, 4, "" ).isEmpty() );
|
||||
TEST( String( "abba" ).replace( 2, 2, "c" ) == String( "abc" ) );
|
||||
|
||||
// String.replace( Char, Char )
|
||||
TEST( String().replace( 'a', 'b' ).isEmpty() );
|
||||
TEST( String( "ababc" ).replace( 'a', 'b' ) == String( "bbbbc" ) );
|
||||
TEST( String( "ababc" ).replace( 'd', 'e' ) == String( "ababc" ) );
|
||||
|
||||
// String.replace( String, String )
|
||||
TEST( String().replace( "foo", "bar" ).isEmpty() );
|
||||
TEST( String( "foobarfoo" ).replace( "foo", "bar" ) == String( "barbarbar" ) );
|
||||
TEST( String( "foobar" ).replace( "xx", "yy" ) == String( "foobar" ) );
|
||||
TEST( String( "foofoofoo" ).replace( "foo", "" ).isEmpty() );
|
||||
}
|
||||
|
||||
void testSubstr()
|
||||
{
|
||||
TEST( String( "foobar" ).substr( 0, 3 ) == String( "foo" ) );
|
||||
TEST( String( "foobar" ).substr( 3 ) == String( "bar" ) );
|
||||
TEST( String( "foobar" ).substr( 2, 2 ) == String( "ob" ) );
|
||||
TEST( String( "foobar" ).substr( 2, 0 ).isEmpty() );
|
||||
TEST( String( "foobar" ).substr( 0, 6 ) == String( "foobar" ) );
|
||||
}
|
||||
|
||||
void testToString()
|
||||
{
|
||||
TEST( String::ToString( U32( 1 ) ) == String( "1" ) );
|
||||
TEST( String::ToString( S32( -1 ) ) == String( "-1" ) );
|
||||
TEST( String::ToString( F32( 1.01 ) ) == String( "1.01" ) );
|
||||
TEST( String::ToString( "%s%i", "foo", 1 ) == String( "foo1" ) );
|
||||
}
|
||||
|
||||
void testCaseConversion()
|
||||
{
|
||||
TEST( String::ToLower( "foobar123." ) == String( "foobar123." ) );
|
||||
TEST( String::ToLower( "FOOBAR123." ) == String( "foobar123." ) );
|
||||
TEST( String::ToUpper( "barfoo123." ) == String( "BARFOO123." ) );
|
||||
TEST( String::ToUpper( "BARFOO123." ) == String( "BARFOO123." ) );
|
||||
}
|
||||
|
||||
void testConcat()
|
||||
{
|
||||
TEST( String( "foo" ) + String( "bar" ) == String( "foobar" ) );
|
||||
TEST( String() + String( "bar" ) == String( "bar" ) );
|
||||
TEST( String( "foo" ) + String() == String( "foo" ) );
|
||||
TEST( String() + String() == String() );
|
||||
TEST( String( "fo" ) + 'o' == String( "foo" ) );
|
||||
TEST( 'f' + String( "oo" ) == String( "foo" ) );
|
||||
TEST( String( "foo" ) + "bar" == String( "foobar" ) );
|
||||
TEST( "foo" + String( "bar" ) == String( "foobar" ) );
|
||||
}
|
||||
|
||||
void testHash()
|
||||
{
|
||||
TEST( String( "foo" ).getHashCaseSensitive() == String( "foo" ).getHashCaseSensitive() );
|
||||
TEST( String( "foo" ).getHashCaseSensitive() != String( "bar" ).getHashCaseSensitive() );
|
||||
TEST( String( "foo" ).getHashCaseInsensitive() == String( "FOO" ).getHashCaseInsensitive() );
|
||||
}
|
||||
|
||||
void testIntern()
|
||||
{
|
||||
TEST( String( "foo" ).intern().isSame( String( "foo" ).intern() ) );
|
||||
TEST( !String( "foo" ).intern().isSame( String( "bar" ).intern() ) );
|
||||
TEST( !String( "foo" ).intern().isSame( String( "Foo" ).intern() ) );
|
||||
TEST( String( "foo" ).intern() == String( "foo" ).intern() );
|
||||
TEST( String( "foo" ).intern() != String( "bar" ).intern() );
|
||||
TEST( String( "foo" ).intern().isInterned() );
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
mStrings.push_back( new StrTest( NULL ) );
|
||||
mStrings.push_back( new StrTest( "" ) );
|
||||
mStrings.push_back( new StrTest( "Torque" ) );
|
||||
mStrings.push_back( new StrTest( "TGEA" ) );
|
||||
mStrings.push_back( new StrTest( "GarageGames" ) );
|
||||
mStrings.push_back( new StrTest( "TGB" ) );
|
||||
mStrings.push_back( new StrTest( "games" ) );
|
||||
mStrings.push_back( new StrTest( "engine" ) );
|
||||
mStrings.push_back( new StrTest( "rocks" ) );
|
||||
mStrings.push_back( new StrTest( "technology" ) );
|
||||
mStrings.push_back( new StrTest( "Torque 3D" ) );
|
||||
mStrings.push_back( new StrTest( "Torque 2D" ) );
|
||||
|
||||
runTestOnStrings< Test1 >();
|
||||
runTestOnStrings< Test2 >();
|
||||
|
||||
runPairwiseTestOnStrings< Test3 >();
|
||||
|
||||
testEmpty();
|
||||
testTrim();
|
||||
testCompare();
|
||||
testOrder();
|
||||
testFind();
|
||||
testInsert();
|
||||
testReplace();
|
||||
testErase();
|
||||
testSubstr();
|
||||
testToString();
|
||||
testCaseConversion();
|
||||
testConcat();
|
||||
testHash();
|
||||
testIntern();
|
||||
|
||||
for( U32 i = 0; i < mStrings.size(); ++ i )
|
||||
delete mStrings[ i ];
|
||||
mStrings.clear();
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest( TestStringBuilder, "Util/StringBuilder" )
|
||||
{
|
||||
void run()
|
||||
{
|
||||
StringBuilder str;
|
||||
|
||||
str.append( 'f' );
|
||||
str.append( "oo" );
|
||||
str.append( String( "ba" ) );
|
||||
str.append( "rfajskfdj", 1 );
|
||||
str.format( "%s", "barfoo" );
|
||||
|
||||
TEST( str.end() == String( "foobarbarfoo" ) );
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !TORQUE_SHIPPING
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "console/console.h"
|
||||
#include "core/util/tVector.h"
|
||||
|
||||
|
||||
#ifndef TORQUE_SHIPPING
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
#define TEST( x ) test( ( x ), "FAIL: " #x )
|
||||
#define XTEST( t, x ) t->test( ( x ), "FAIL: " #x )
|
||||
|
||||
CreateUnitTest( TestVector, "Util/Vector" )
|
||||
{
|
||||
bool dtorVals[ 10 ];
|
||||
struct Dtor
|
||||
{
|
||||
bool* ptr;
|
||||
Dtor() {}
|
||||
Dtor( bool* ptr )
|
||||
: ptr( ptr ) { *ptr = false; }
|
||||
~Dtor()
|
||||
{
|
||||
*ptr = true;
|
||||
}
|
||||
};
|
||||
void testDestruction()
|
||||
{
|
||||
Vector< Dtor > v;
|
||||
|
||||
for( U32 i = 0; i < 9; ++ i )
|
||||
v.push_back( Dtor( &dtorVals[ i ] ) );
|
||||
|
||||
v.decrement();
|
||||
v.decrement( 2 );
|
||||
v.pop_back();
|
||||
v.increment();
|
||||
v.last() = Dtor( &dtorVals[ 9 ] );
|
||||
v.clear();
|
||||
|
||||
TEST( dtorVals[ 0 ] );
|
||||
TEST( dtorVals[ 1 ] );
|
||||
TEST( dtorVals[ 2 ] );
|
||||
TEST( dtorVals[ 3 ] );
|
||||
TEST( dtorVals[ 4 ] );
|
||||
TEST( dtorVals[ 5 ] );
|
||||
TEST( dtorVals[ 6 ] );
|
||||
TEST( dtorVals[ 7 ] );
|
||||
TEST( dtorVals[ 8 ] );
|
||||
TEST( dtorVals[ 9 ] );
|
||||
}
|
||||
|
||||
static S32 QSORT_CALLBACK sortInts( const S32* a, const S32* b )
|
||||
{
|
||||
S32 av = *a;
|
||||
S32 bv = *b;
|
||||
|
||||
if( av < bv )
|
||||
return -1;
|
||||
else if( av > bv )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void testSort()
|
||||
{
|
||||
Vector< S32 > v;
|
||||
|
||||
v.push_back( 0 );
|
||||
v.push_back( 10 );
|
||||
v.push_back( 2 );
|
||||
v.push_back( 3 );
|
||||
v.push_back( 14 );
|
||||
v.push_back( 4 );
|
||||
v.push_back( 12 );
|
||||
v.push_back( 6 );
|
||||
v.push_back( 16 );
|
||||
v.push_back( 7 );
|
||||
v.push_back( 8 );
|
||||
v.push_back( 1 );
|
||||
v.push_back( 11 );
|
||||
v.push_back( 5 );
|
||||
v.push_back( 13 );
|
||||
v.push_back( 9 );
|
||||
v.push_back( 15 );
|
||||
|
||||
v.sort( sortInts );
|
||||
|
||||
TEST( v[ 0 ] == 0 );
|
||||
TEST( v[ 1 ] == 1 );
|
||||
TEST( v[ 2 ] == 2 );
|
||||
TEST( v[ 3 ] == 3 );
|
||||
TEST( v[ 4 ] == 4 );
|
||||
TEST( v[ 5 ] == 5 );
|
||||
TEST( v[ 6 ] == 6 );
|
||||
TEST( v[ 7 ] == 7 );
|
||||
TEST( v[ 8 ] == 8 );
|
||||
TEST( v[ 9 ] == 9 );
|
||||
TEST( v[ 10 ] == 10 );
|
||||
TEST( v[ 11 ] == 11 );
|
||||
TEST( v[ 12 ] == 12 );
|
||||
TEST( v[ 13 ] == 13 );
|
||||
TEST( v[ 14 ] == 14 );
|
||||
TEST( v[ 15 ] == 15 );
|
||||
TEST( v[ 16 ] == 16 );
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
testSort();
|
||||
testDestruction();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
#include "core/crc.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
#include "core/util/zip/zipArchive.h"
|
||||
|
|
@ -194,3 +194,4 @@ private:
|
|||
return ret;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
#include "platform/platform.h"
|
||||
|
||||
#include "unit/test.h"
|
||||
|
|
@ -250,3 +250,4 @@ private:
|
|||
return ret;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
#include "core/strings/stringFunctions.h"
|
||||
#include "core/util/zip/zipArchive.h"
|
||||
#include "core/util/zip/unitTests/zipTest.h"
|
||||
|
|
@ -242,3 +242,4 @@ bail:
|
|||
return ret;
|
||||
}
|
||||
};
|
||||
*/
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -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,18 +20,23 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "unit/memoryTester.h"
|
||||
#ifdef TORQUE_TESTS_ENABLED
|
||||
#include "testing/unitTesting.h"
|
||||
#include "math/mBox.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
void MemoryTester::mark()
|
||||
TEST(Box3F, GetOverlap)
|
||||
{
|
||||
Box3F b1(Point3F(-1, -1, -1), Point3F(1, 1, 1));
|
||||
EXPECT_EQ(b1.getOverlap(b1), b1)
|
||||
<< "A box's overlap with itself should be itself.";
|
||||
|
||||
Box3F b2(Point3F(0, 0, 0), Point3F(1, 1, 1));
|
||||
EXPECT_EQ(b1.getOverlap(b2), b2)
|
||||
<< "Box's overlap should be the intersection of two boxes.";
|
||||
|
||||
Box3F b3(Point3F(10, 10, 10), Point3F(11, 11, 11));
|
||||
EXPECT_TRUE(b1.getOverlap(b3).isEmpty())
|
||||
<< "Overlap of boxes that do not overlap should be empty.";
|
||||
}
|
||||
|
||||
bool MemoryTester::check()
|
||||
{
|
||||
//UnitTesting::UnitPrint("MemoryTester::check - unavailable w/o TORQUE_DEBUG_GUARD defined!");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
106
Engine/source/math/test/mMatrixTest.cpp
Normal file
106
Engine/source/math/test/mMatrixTest.cpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/platform.h"
|
||||
#include "math/mMatrix.h"
|
||||
#include "math/mRandom.h"
|
||||
|
||||
extern void default_matF_x_matF_C(const F32 *a, const F32 *b, F32 *mresult);
|
||||
extern void mInstallLibrary_ASM();
|
||||
|
||||
// If we're x86 and not Mac, then include these. There's probably a better way to do this.
|
||||
#if defined(TORQUE_CPU_X86) && !defined(TORQUE_OS_MAC)
|
||||
extern "C" void Athlon_MatrixF_x_MatrixF(const F32 *matA, const F32 *matB, F32 *result);
|
||||
extern "C" void SSE_MatrixF_x_MatrixF(const F32 *matA, const F32 *matB, F32 *result);
|
||||
#endif
|
||||
|
||||
#if defined( __VEC__ )
|
||||
extern void vec_MatrixF_x_MatrixF(const F32 *matA, const F32 *matB, F32 *result);
|
||||
#endif
|
||||
|
||||
TEST(MatrixF, MultiplyImplmentations)
|
||||
{
|
||||
F32 m1[16], m2[16], mrC[16];
|
||||
|
||||
// I am not positive that the best way to do this is to use random numbers
|
||||
// but I think that using some kind of standard matrix may not always catch
|
||||
// all problems.
|
||||
for (S32 i = 0; i < 16; i++)
|
||||
{
|
||||
m1[i] = gRandGen.randF();
|
||||
m2[i] = gRandGen.randF();
|
||||
}
|
||||
|
||||
// C will be the baseline
|
||||
default_matF_x_matF_C(m1, m2, mrC);
|
||||
|
||||
#if defined(TORQUE_CPU_X86) && !defined(TORQUE_OS_MAC)
|
||||
// Check the CPU info
|
||||
U32 cpuProperties = Platform::SystemInfo.processor.properties;
|
||||
bool same;
|
||||
|
||||
// Test 3D NOW! if it is available
|
||||
F32 mrAMD[16];
|
||||
if (cpuProperties & CPU_PROP_3DNOW)
|
||||
{
|
||||
Athlon_MatrixF_x_MatrixF(m1, m2, mrAMD);
|
||||
|
||||
same = true;
|
||||
for (S32 i = 0; i < 16; i++)
|
||||
same &= mIsEqual(mrC[i], mrAMD[i]);
|
||||
|
||||
EXPECT_TRUE(same) << "Matrix multiplication verification failed. (C vs. 3D NOW!)";
|
||||
}
|
||||
|
||||
// Test SSE if it is available
|
||||
F32 mrSSE[16];
|
||||
if (cpuProperties & CPU_PROP_SSE)
|
||||
{
|
||||
SSE_MatrixF_x_MatrixF(m1, m2, mrSSE);
|
||||
|
||||
same = true;
|
||||
for (S32 i = 0; i < 16; i++)
|
||||
same &= mIsEqual(mrC[i], mrSSE[i]);
|
||||
|
||||
EXPECT_TRUE(same) << "Matrix multiplication verification failed. (C vs. SSE)";
|
||||
}
|
||||
|
||||
same = true;
|
||||
#endif
|
||||
|
||||
// If Altivec exists, test it!
|
||||
#if defined(__VEC__)
|
||||
bool same = false;
|
||||
F32 mrVEC[16];
|
||||
|
||||
vec_MatrixF_x_MatrixF(m1, m2, mrVEC);
|
||||
|
||||
for (S32 i = 0; i < 16; i++)
|
||||
same &= isEqual(mrC[i], mrVEC[i]);
|
||||
|
||||
EXPECT_TRUE(same) << "Matrix multiplication verification failed. (C vs. Altivec)";
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
74
Engine/source/math/test/mPlaneTest.cpp
Normal file
74
Engine/source/math/test/mPlaneTest.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "math/mPlane.h"
|
||||
|
||||
// Static test data. All combinations of position and normal are tested in each
|
||||
// test case. This allows a large number of tests without introducing non-
|
||||
// deterministic test behavior.
|
||||
|
||||
static const Point3F positions[] = {Point3F(0, 0, 0), Point3F(1, -2, 3), Point3F(1e-2, -2e-2, 1)};
|
||||
static const U32 numPositions = sizeof(positions) / sizeof(Point3F);
|
||||
|
||||
static const Point3F normals[] = {Point3F(1, 0, 0), Point3F(-4, -2, 6)};
|
||||
static const U32 numNormals = sizeof(normals) / sizeof(Point3F);
|
||||
|
||||
/// Tests that points in the direction of the normal are in 'Front' of the
|
||||
/// plane, while points in the reverse direction of the normal are in
|
||||
/// 'Back' of the plane.
|
||||
TEST(Plane, WhichSide)
|
||||
{
|
||||
for(U32 i = 0; i < numPositions; i++) {
|
||||
for(U32 j = 0; j < numNormals; j++) {
|
||||
Point3F position = positions[i];
|
||||
Point3F normal = normals[j];
|
||||
|
||||
PlaneF p(position, normal);
|
||||
|
||||
EXPECT_EQ(p.whichSide(position + normal), PlaneF::Front );
|
||||
EXPECT_EQ(p.whichSide(position - normal), PlaneF::Back );
|
||||
EXPECT_EQ(p.whichSide(position), PlaneF::On );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests that the distToPlane method returns the exact length that the test
|
||||
/// point is offset by in the direction of the normal.
|
||||
TEST(Plane, DistToPlane)
|
||||
{
|
||||
for(U32 i = 0; i < numPositions; i++) {
|
||||
for(U32 j = 0; j < numNormals; j++) {
|
||||
Point3F position = positions[i];
|
||||
Point3F normal = normals[j];
|
||||
|
||||
PlaneF p(position, normal);
|
||||
|
||||
EXPECT_FLOAT_EQ(p.distToPlane(position + normal), normal.len());
|
||||
EXPECT_FLOAT_EQ(p.distToPlane(position - normal), -normal.len());
|
||||
EXPECT_FLOAT_EQ(p.distToPlane(position), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
70
Engine/source/math/test/mPolyhedronTest.cpp
Normal file
70
Engine/source/math/test/mPolyhedronTest.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "math/mPolyhedron.h"
|
||||
|
||||
FIXTURE(Polyhedron)
|
||||
{
|
||||
protected:
|
||||
Vector<PlaneF> planes;
|
||||
|
||||
virtual void SetUp()
|
||||
{
|
||||
// Build planes for a unit cube centered at the origin.
|
||||
// Note that the normals must be facing inwards.
|
||||
planes.push_back(PlaneF(Point3F(-0.5f, 0.f, 0.f ), Point3F( 1.f, 0.f, 0.f)));
|
||||
planes.push_back(PlaneF(Point3F( 0.5f, 0.f, 0.f ), Point3F(-1.f, 0.f, 0.f)));
|
||||
planes.push_back(PlaneF(Point3F( 0.f, -0.5f, 0.f ), Point3F( 0.f, 1.f, 0.f)));
|
||||
planes.push_back(PlaneF(Point3F( 0.f, 0.5f, 0.f ), Point3F( 0.f, -1.f, 0.f)));
|
||||
planes.push_back(PlaneF(Point3F( 0.f, 0.f, -0.5f), Point3F( 0.f, 0.f, 1.f)));
|
||||
planes.push_back(PlaneF(Point3F( 0.f, 0.f, 0.5f), Point3F( 0.f, 0.f, -1.f)));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_FIX(Polyhedron, BuildFromPlanes)
|
||||
{
|
||||
// Turn planes into a polyhedron.
|
||||
Polyhedron p1;
|
||||
p1.buildFromPlanes(PlaneSetF(planes.address(), planes.size()));
|
||||
|
||||
// Check if we got a cube back.
|
||||
EXPECT_EQ(p1.getNumPoints(), 8);
|
||||
EXPECT_EQ(p1.getNumPlanes(), 6);
|
||||
EXPECT_EQ(p1.getNumEdges(), 12);
|
||||
|
||||
// Add extra plane that doesn't contribute a new edge.
|
||||
Vector<PlaneF> planes2 = planes;
|
||||
planes2.push_back( PlaneF( Point3F( 0.5f, 0.5f, 0.5f ), Point3F( -1.f, -1.f, -1.f ) ) );
|
||||
|
||||
// Turn them into another polyhedron.
|
||||
Polyhedron p2;
|
||||
p2.buildFromPlanes(PlaneSetF(planes2.address(), planes2.size()));
|
||||
|
||||
// Check if we got a cube back.
|
||||
EXPECT_EQ(p2.getNumPoints(), 8);
|
||||
EXPECT_EQ(p2.getNumPlanes(), 6);
|
||||
EXPECT_EQ(p2.getNumEdges(), 12);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "math/mPlane.h"
|
||||
#include "math/mRandom.h"
|
||||
|
||||
|
||||
#ifndef TORQUE_SHIPPING
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
#define TEST( x ) test( ( x ), "FAIL: " #x )
|
||||
#define XTEST( t, x ) t->test( ( x ), "FAIL: " #x )
|
||||
|
||||
CreateUnitTest( TestMathPlane, "Math/Plane" )
|
||||
{
|
||||
static F32 randF()
|
||||
{
|
||||
return gRandGen.randF( -1.f, 1.f );
|
||||
}
|
||||
|
||||
void test_whichSide()
|
||||
{
|
||||
for( U32 i = 0; i < 100; ++ i )
|
||||
{
|
||||
Point3F position( randF(), randF(), randF() );
|
||||
Point3F normal( randF(), randF(), randF() );
|
||||
|
||||
PlaneF p1( position, normal );
|
||||
|
||||
TEST( p1.whichSide( position + normal ) == PlaneF::Front );
|
||||
TEST( p1.whichSide( position + ( - normal ) ) == PlaneF::Back );
|
||||
TEST( p1.whichSide( position ) == PlaneF::On );
|
||||
}
|
||||
}
|
||||
|
||||
void test_distToPlane()
|
||||
{
|
||||
for( U32 i = 0; i < 100; ++ i )
|
||||
{
|
||||
Point3F position( randF(), randF(), randF() );
|
||||
Point3F normal( randF(), randF(), randF() );
|
||||
|
||||
PlaneF p1( position, normal );
|
||||
|
||||
TEST( mIsEqual( p1.distToPlane( position + normal ), normal.len() ) );
|
||||
TEST( mIsEqual( p1.distToPlane( position + ( - normal ) ), - normal.len() ) );
|
||||
TEST( mIsZero( p1.distToPlane( position ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
test_whichSide();
|
||||
test_distToPlane();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !TORQUE_SHIPPING
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "math/mPolyhedron.h"
|
||||
|
||||
|
||||
#ifndef TORQUE_SHIPPING
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
#define TEST( x ) test( ( x ), "FAIL: " #x )
|
||||
#define XTEST( t, x ) t->test( ( x ), "FAIL: " #x )
|
||||
|
||||
|
||||
CreateUnitTest( TestMathPolyhedronBuildFromPlanes, "Math/Polyhedron/BuildFromPlanes" )
|
||||
{
|
||||
void test_unitCube()
|
||||
{
|
||||
Vector< PlaneF > planes;
|
||||
|
||||
// Build planes for a unit cube centered at the origin.
|
||||
// Note that the normals must be facing inwards.
|
||||
|
||||
planes.push_back( PlaneF( Point3F( -0.5f, 0.f, 0.f ), Point3F( 1.f, 0.f, 0.f ) ) );
|
||||
planes.push_back( PlaneF( Point3F( 0.5f, 0.f, 0.f ), Point3F( -1.f, 0.f, 0.f ) ) );
|
||||
planes.push_back( PlaneF( Point3F( 0.f, -0.5f, 0.f ), Point3F( 0.f, 1.f, 0.f ) ) );
|
||||
planes.push_back( PlaneF( Point3F( 0.f, 0.5f, 0.f ), Point3F( 0.f, -1.f, 0.f ) ) );
|
||||
planes.push_back( PlaneF( Point3F( 0.f, 0.f, -0.5f ), Point3F( 0.f, 0.f, 1.f ) ) );
|
||||
planes.push_back( PlaneF( Point3F( 0.f, 0.f, 0.5f ), Point3F( 0.f, 0.f, -1.f ) ) );
|
||||
|
||||
// Turn it into a polyhedron.
|
||||
|
||||
Polyhedron polyhedron;
|
||||
polyhedron.buildFromPlanes(
|
||||
PlaneSetF( planes.address(), planes.size() )
|
||||
);
|
||||
|
||||
// Check if we got a cube back.
|
||||
|
||||
TEST( polyhedron.getNumPoints() == 8 );
|
||||
TEST( polyhedron.getNumPlanes() == 6 );
|
||||
TEST( polyhedron.getNumEdges() == 12 );
|
||||
}
|
||||
|
||||
void test_extraPlane()
|
||||
{
|
||||
Vector< PlaneF > planes;
|
||||
|
||||
// Build planes for a unit cube centered at the origin.
|
||||
// Note that the normals must be facing inwards.
|
||||
|
||||
planes.push_back( PlaneF( Point3F( -0.5f, 0.f, 0.f ), Point3F( 1.f, 0.f, 0.f ) ) );
|
||||
planes.push_back( PlaneF( Point3F( 0.5f, 0.f, 0.f ), Point3F( -1.f, 0.f, 0.f ) ) );
|
||||
planes.push_back( PlaneF( Point3F( 0.f, -0.5f, 0.f ), Point3F( 0.f, 1.f, 0.f ) ) );
|
||||
planes.push_back( PlaneF( Point3F( 0.f, 0.5f, 0.f ), Point3F( 0.f, -1.f, 0.f ) ) );
|
||||
planes.push_back( PlaneF( Point3F( 0.f, 0.f, -0.5f ), Point3F( 0.f, 0.f, 1.f ) ) );
|
||||
planes.push_back( PlaneF( Point3F( 0.f, 0.f, 0.5f ), Point3F( 0.f, 0.f, -1.f ) ) );
|
||||
|
||||
// Add extra plane that doesn't contribute a new edge.
|
||||
|
||||
planes.push_back( PlaneF( Point3F( 0.5f, 0.5f, 0.5f ), Point3F( -1.f, -1.f, -1.f ) ) );
|
||||
|
||||
// Turn it into a polyhedron.
|
||||
|
||||
Polyhedron polyhedron;
|
||||
polyhedron.buildFromPlanes(
|
||||
PlaneSetF( planes.address(), planes.size() )
|
||||
);
|
||||
|
||||
// Check if we got a cube back.
|
||||
|
||||
TEST( polyhedron.getNumPoints() == 8 );
|
||||
TEST( polyhedron.getNumPlanes() == 6 );
|
||||
TEST( polyhedron.getNumEdges() == 12 );
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
test_unitCube();
|
||||
//test_extraPlane();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !TORQUE_SHIPPING
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
#include "unit/test.h"
|
||||
#include "platform/async/asyncPacketQueue.h"
|
||||
#include "console/console.h"
|
||||
|
|
@ -149,3 +149,4 @@ CreateUnitTest( TestAsyncPacketQueue, "Platform/AsyncPacketQueue" )
|
|||
};
|
||||
|
||||
#endif // !TORQUE_SHIPPING
|
||||
*/
|
||||
174
Engine/source/platform/test/netTest.cpp
Normal file
174
Engine/source/platform/test/netTest.cpp
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/platformNet.h"
|
||||
#include "core/util/journal/process.h"
|
||||
|
||||
TEST(Net, TCPRequest)
|
||||
{
|
||||
struct handle
|
||||
{
|
||||
NetSocket mSocket;
|
||||
S32 mDataReceived;
|
||||
|
||||
void notify(NetSocket sock, U32 state)
|
||||
{
|
||||
// Only consider our own socket.
|
||||
if(mSocket != sock)
|
||||
return;
|
||||
|
||||
// Ok - what's the state? We do some dumb responses to given states
|
||||
// in order to fulfill the request.
|
||||
if(state == Net::Connected)
|
||||
{
|
||||
U8 reqBuffer[] = {
|
||||
"GET / HTTP/1.0\nUser-Agent: Torque/1.0\n\n"
|
||||
};
|
||||
|
||||
Net::Error e = Net::sendtoSocket(mSocket, reqBuffer, sizeof(reqBuffer));
|
||||
|
||||
ASSERT_EQ(Net::NoError, e)
|
||||
<< "Got an error sending our HTTP request!";
|
||||
}
|
||||
else
|
||||
{
|
||||
Process::requestShutdown();
|
||||
mSocket = NULL;
|
||||
ASSERT_EQ(Net::Disconnected, state)
|
||||
<< "Ended with a network error!";
|
||||
}
|
||||
}
|
||||
|
||||
void receive(NetSocket sock, RawData incomingData)
|
||||
{
|
||||
// Only consider our own socket.
|
||||
if(mSocket != sock)
|
||||
return;
|
||||
|
||||
mDataReceived += incomingData.size;
|
||||
}
|
||||
} handler;
|
||||
|
||||
handler.mSocket = InvalidSocket;
|
||||
handler.mDataReceived = 0;
|
||||
|
||||
// Hook into the signals.
|
||||
Net::smConnectionNotify. notify(&handler, &handle::notify);
|
||||
Net::smConnectionReceive.notify(&handler, &handle::receive);
|
||||
|
||||
// Open a TCP connection to garagegames.com
|
||||
handler.mSocket = Net::openConnectTo("72.246.107.193:80");
|
||||
const U32 limit = Platform::getRealMilliseconds() + (5*1000);
|
||||
while(Process::processEvents() && (Platform::getRealMilliseconds() < limit) ) {}
|
||||
|
||||
// Unhook from the signals.
|
||||
Net::smConnectionNotify. remove(&handler, &handle::notify);
|
||||
Net::smConnectionReceive.remove(&handler, &handle::receive);
|
||||
|
||||
EXPECT_GT(handler.mDataReceived, 0)
|
||||
<< "Didn't get any data back!";
|
||||
}
|
||||
|
||||
TEST(Net, JournalTCPRequest)
|
||||
{
|
||||
struct handle
|
||||
{
|
||||
NetSocket mSocket;
|
||||
S32 mDataReceived;
|
||||
|
||||
void notify(NetSocket sock, U32 state)
|
||||
{
|
||||
// Only consider our own socket.
|
||||
if(mSocket != sock)
|
||||
return;
|
||||
|
||||
// Ok - what's the state? We do some dumb responses to given states
|
||||
// in order to fulfill the request.
|
||||
if(state == Net::Connected)
|
||||
{
|
||||
U8 reqBuffer[] = {
|
||||
"GET / HTTP/1.0\nUser-Agent: Torque/1.0\n\n"
|
||||
};
|
||||
|
||||
Net::Error e = Net::sendtoSocket(mSocket, reqBuffer, sizeof(reqBuffer));
|
||||
|
||||
ASSERT_EQ(Net::NoError, e)
|
||||
<< "Got an error sending our HTTP request!";
|
||||
}
|
||||
else
|
||||
{
|
||||
Process::requestShutdown();
|
||||
mSocket = NULL;
|
||||
ASSERT_EQ(Net::Disconnected, state)
|
||||
<< "Ended with a network error!";
|
||||
}
|
||||
}
|
||||
|
||||
void receive(NetSocket sock, RawData incomingData)
|
||||
{
|
||||
// Only consider our own socket.
|
||||
if(mSocket != sock)
|
||||
return;
|
||||
mDataReceived += incomingData.size;
|
||||
}
|
||||
|
||||
void makeRequest()
|
||||
{
|
||||
mSocket = InvalidSocket;
|
||||
mDataReceived = 0;
|
||||
|
||||
// Hook into the signals.
|
||||
Net::smConnectionNotify. notify(this, &handle::notify);
|
||||
Net::smConnectionReceive.notify(this, &handle::receive);
|
||||
|
||||
// Open a TCP connection to garagegames.com
|
||||
mSocket = Net::openConnectTo("72.246.107.193:80");
|
||||
|
||||
// Let the callbacks enable things to process.
|
||||
while(Process::processEvents()) {}
|
||||
|
||||
// Unhook from the signals.
|
||||
Net::smConnectionNotify. remove(this, &handle::notify);
|
||||
Net::smConnectionReceive.remove(this, &handle::receive);
|
||||
|
||||
EXPECT_GT(mDataReceived, 0)
|
||||
<< "Didn't get any data back!";
|
||||
}
|
||||
} handler;
|
||||
|
||||
Journal::Record("journalTCP.jrn");
|
||||
ASSERT_TRUE(Journal::IsRecording());
|
||||
handler.makeRequest();
|
||||
S32 bytesRead = handler.mDataReceived;
|
||||
Journal::Stop();
|
||||
|
||||
Journal::Play("journalTCP.jrn");
|
||||
handler.makeRequest();
|
||||
Journal::Stop();
|
||||
|
||||
EXPECT_EQ(bytesRead, handler.mDataReceived)
|
||||
<< "Didn't get same data back from journal playback.";
|
||||
}
|
||||
|
||||
#endif
|
||||
118
Engine/source/platform/test/platformFileIOTest.cpp
Normal file
118
Engine/source/platform/test/platformFileIOTest.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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 "platform/platform.h"
|
||||
#include "core/fileio.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "console/console.h"
|
||||
|
||||
TEST(Platform, ExcludedDirectories)
|
||||
{
|
||||
// Just dump everything under the current directory. We should
|
||||
// find at least one file.
|
||||
|
||||
// Exclude .svn and CVS
|
||||
Platform::clearExcludedDirectories();
|
||||
Platform::addExcludedDirectory(".svn");
|
||||
Platform::addExcludedDirectory("CVS");
|
||||
|
||||
EXPECT_TRUE(Platform::isExcludedDirectory(".svn"))
|
||||
<< "On list, should be excluded.";
|
||||
EXPECT_TRUE(Platform::isExcludedDirectory("CVS"))
|
||||
<< "On list, should be excluded.";
|
||||
EXPECT_FALSE(Platform::isExcludedDirectory("foo"))
|
||||
<< "Doesn't match list, shouldn't be excluded.";
|
||||
EXPECT_FALSE(Platform::isExcludedDirectory(".svnCVS"))
|
||||
<< "Looks like a duck, but it shouldn't be excluded cuz it's distinct from all entries on the exclusion list.";
|
||||
|
||||
// Ok, now our exclusion list is setup, so let's dump some paths.
|
||||
Vector<Platform::FileInfo> pathInfo;
|
||||
Platform::dumpPath(Platform::getCurrentDirectory(), pathInfo, 2);
|
||||
EXPECT_GT(pathInfo.size(), 0)
|
||||
<< "Should find at least SOMETHING in the current directory!";
|
||||
|
||||
// This'll nuke info if we run it in a live situation... so don't run unit
|
||||
// tests in a live situation. ;)
|
||||
Platform::clearExcludedDirectories();
|
||||
};
|
||||
|
||||
TEST(File, TouchAndTime)
|
||||
{
|
||||
FileTime create[2], modify[2];
|
||||
|
||||
// Create a file and sleep for a second.
|
||||
File f;
|
||||
f.open("testTouch.file", File::WriteAppend);
|
||||
f.close();
|
||||
|
||||
// Touch a file and note its last-modified.
|
||||
dFileTouch("testTouch.file");
|
||||
EXPECT_TRUE(Platform::isFile("testTouch.file"))
|
||||
<< "We just touched this file - it should exist.";
|
||||
EXPECT_TRUE(Platform::getFileTimes("testTouch.file", &create[0], &modify[0]))
|
||||
<< "Failed to get filetimes for a file we just created.";
|
||||
|
||||
// Sleep for a tick
|
||||
Platform::sleep(10);
|
||||
|
||||
// Touch it again, and compare the last-modifieds.
|
||||
EXPECT_TRUE(Platform::isFile("testTouch.file"))
|
||||
<< "We just touched this file - it should exist.";
|
||||
dFileTouch("testTouch.file");
|
||||
EXPECT_TRUE(Platform::isFile("testTouch.file"))
|
||||
<< "We just touched this file - it should exist.";
|
||||
EXPECT_TRUE(Platform::getFileTimes("testTouch.file", &create[1], &modify[1]))
|
||||
<< "Failed to get filetimes for a file we just created.";
|
||||
|
||||
// Now compare the times...
|
||||
EXPECT_LT(Platform::compareFileTimes(modify[0], modify[1]), 0)
|
||||
<< "Timestamps are wrong - modify[0] should be before modify[1]!";
|
||||
EXPECT_EQ(Platform::compareFileTimes(create[0], create[1]), 0)
|
||||
<< "Create timestamps should match - we didn't delete the file during this test.";
|
||||
|
||||
// Clean up..
|
||||
dFileDelete("testTouch.file");
|
||||
EXPECT_FALSE(Platform::isFile("testTouch.file"))
|
||||
<< "Somehow failed to delete our test file.";
|
||||
};
|
||||
|
||||
// Mac has no implementations for these functions, so we 'def it out for now.
|
||||
#ifndef __MACOSX__
|
||||
TEST(Platform, Volumes)
|
||||
{
|
||||
Vector<const char*> names;
|
||||
Platform::getVolumeNamesList(names);
|
||||
|
||||
EXPECT_GT(names.size(), 0)
|
||||
<< "We should have at least one volume...";
|
||||
|
||||
Vector<Platform::VolumeInformation> info;
|
||||
Platform::getVolumeInformationList(info);
|
||||
|
||||
EXPECT_EQ(names.size(), info.size())
|
||||
<< "Got inconsistent number of volumes back from info vs. name list functions!";
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
93
Engine/source/platform/test/platformTimerTest.cpp
Normal file
93
Engine/source/platform/test/platformTimerTest.cpp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/platformTimer.h"
|
||||
#include "core/util/journal/process.h"
|
||||
#include "math/mMath.h"
|
||||
|
||||
TEST(Platform, AdvanceTime)
|
||||
{
|
||||
U32 time = Platform::getVirtualMilliseconds();
|
||||
Platform::advanceTime(10);
|
||||
U32 newTime = Platform::getVirtualMilliseconds();
|
||||
EXPECT_EQ(10, newTime - time)
|
||||
<< "We advanced 10ms but didn't get a 10ms delta!";
|
||||
}
|
||||
|
||||
TEST(Platform, Sleep)
|
||||
{
|
||||
U32 start = Platform::getRealMilliseconds();
|
||||
Platform::sleep(500);
|
||||
U32 end = Platform::getRealMilliseconds();
|
||||
EXPECT_GE(end - start, 500-10) // account for clock resolution
|
||||
<< "We didn't sleep at least as long as we requested!";
|
||||
};
|
||||
|
||||
TEST(TimeManager, BasicAPI)
|
||||
{
|
||||
struct handle
|
||||
{
|
||||
S32 mElapsedTime;
|
||||
S32 mNumberCalls;
|
||||
|
||||
void timeEvent(S32 timeDelta)
|
||||
{
|
||||
mElapsedTime += timeDelta;
|
||||
mNumberCalls++;
|
||||
|
||||
if(mElapsedTime >= 1000)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
} handler;
|
||||
|
||||
handler.mElapsedTime = handler.mNumberCalls = 0;
|
||||
|
||||
// Initialize the time manager...
|
||||
TimeManager time;
|
||||
time.timeEvent.notify(&handler, &handle::timeEvent);
|
||||
|
||||
// Event loop till at least one second has passed.
|
||||
const U32 start = Platform::getRealMilliseconds();
|
||||
|
||||
while(Process::processEvents())
|
||||
{
|
||||
// If we go too long, kill it off...
|
||||
if(Platform::getRealMilliseconds() - start > 30*1000)
|
||||
{
|
||||
EXPECT_TRUE(false)
|
||||
<< "Terminated process loop due to watchdog, not due to time manager event, after 30 seconds.";
|
||||
Process::requestShutdown();
|
||||
}
|
||||
}
|
||||
const U32 end = Platform::getRealMilliseconds();
|
||||
|
||||
// Now, confirm we have approximately similar elapsed times.
|
||||
S32 elapsedRealTime = end - start;
|
||||
EXPECT_LT(mAbs(elapsedRealTime - handler.mElapsedTime), 50)
|
||||
<< "Failed to elapse time to within the desired tolerance.";
|
||||
EXPECT_GT(handler.mNumberCalls, 0)
|
||||
<< "Somehow got no event callbacks from TimeManager?";
|
||||
};
|
||||
|
||||
#endif
|
||||
118
Engine/source/platform/test/platformTypesTest.cpp
Normal file
118
Engine/source/platform/test/platformTypesTest.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/platform.h"
|
||||
#include "core/util/endian.h"
|
||||
|
||||
TEST(PlatformTypes, Sizes)
|
||||
{
|
||||
// Run through all the types and ensure they're the right size.
|
||||
#define CheckType(typeName, expectedSize) \
|
||||
EXPECT_EQ( sizeof(typeName), expectedSize) \
|
||||
<< "Wrong size for a " #typeName ", expected " #expectedSize;
|
||||
|
||||
// One byte types.
|
||||
CheckType(bool, 1);
|
||||
CheckType(U8, 1);
|
||||
CheckType(S8, 1);
|
||||
CheckType(UTF8, 1);
|
||||
|
||||
// Two byte types.
|
||||
CheckType(U16, 2);
|
||||
CheckType(S16, 2);
|
||||
CheckType(UTF16, 2);
|
||||
|
||||
// Four byte types.
|
||||
CheckType(U32, 4);
|
||||
CheckType(S32, 4);
|
||||
CheckType(F32, 4);
|
||||
CheckType(UTF32, 4);
|
||||
|
||||
// Eight byte types.
|
||||
CheckType(U64, 8);
|
||||
CheckType(S64, 8);
|
||||
CheckType(F64, 8);
|
||||
|
||||
// 16 byte (128bit) types will go here, when we get some.
|
||||
#undef CheckType
|
||||
};
|
||||
|
||||
TEST(PlatformTypes, EndianConversion)
|
||||
{
|
||||
// Convenient and non-palindrome byte patterns to test with.
|
||||
const U16 U16Test = 0xA1B2;
|
||||
const S16 S16Test = 0x52A1;
|
||||
|
||||
const U32 U32Test = 0xA1B2C3D4;
|
||||
const S32 S32Test = 0xD4C3B2A1;
|
||||
const F32 F32Test = 1234.5678f;
|
||||
|
||||
//const U64 U64Test = 0xA1B2C3D4E3F2E10A;
|
||||
//const S64 S64Test = 0x1A2B3C4D3E2F1EA0;
|
||||
const F64 F64Test = 12345678.9101112131415;
|
||||
|
||||
// Run through all the conversions - bump stuff from host to little or big
|
||||
// endian and back again.
|
||||
#define CheckEndianRoundTrip(type, b_or_l) \
|
||||
EXPECT_EQ( type##Test, convert##b_or_l##EndianToHost(convertHostTo##b_or_l##Endian(type##Test))) \
|
||||
<< "Failed to convert the " #type " test value to " #b_or_l " endian and back to host endian order.";
|
||||
|
||||
#define CheckTypeBothWays(type) \
|
||||
CheckEndianRoundTrip(type, B); \
|
||||
CheckEndianRoundTrip(type, L);
|
||||
|
||||
#define CheckIntsForBitSize(bits) \
|
||||
CheckTypeBothWays( U##bits ); \
|
||||
CheckTypeBothWays( S##bits );
|
||||
|
||||
// Don't check 8-bit types - they aren't affected by endian issues.
|
||||
|
||||
// Check the >1 byte int types, though.
|
||||
CheckIntsForBitSize(16);
|
||||
CheckIntsForBitSize(32);
|
||||
// CheckIntsForBitSize(64); // don't have convertHostToLEndian(const U64/S64) so this doesn't work
|
||||
|
||||
// And check the float types.
|
||||
CheckTypeBothWays(F32);
|
||||
CheckTypeBothWays(F64);
|
||||
|
||||
// We'd check 128bit types here, if we had any.
|
||||
|
||||
#undef CheckIntsForBitSize
|
||||
#undef CheckTypeBothWays
|
||||
#undef CheckEndianRoundTrip
|
||||
};
|
||||
|
||||
TEST(PlatformTypes, EndianSwap)
|
||||
{
|
||||
U32 swap32 = 0xABCDEF12;
|
||||
U16 swap16 = 0xABCD;
|
||||
|
||||
EXPECT_EQ(endianSwap(swap32), 0x12EFCDAB)
|
||||
<< "32 bit endianSwap should reverse byte order, but didn't.";
|
||||
EXPECT_EQ(endianSwap(swap16), 0xCDAB)
|
||||
<< "16 bit endianSwap should reverse byte order, but didn't.";
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -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,18 +20,30 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _UNIT_MEMORYTESTER_H_
|
||||
#define _UNIT_MEMORYTESTER_H_
|
||||
#ifdef TORQUE_TESTS_ENABLED
|
||||
#include "platform/platform.h" // Allows us to see TORQUE_ENABLE_PROFILER
|
||||
|
||||
namespace UnitTesting
|
||||
#ifdef TORQUE_ENABLE_PROFILER
|
||||
#include "testing/unitTesting.h"
|
||||
#include "platform/profiler.h"
|
||||
|
||||
TEST(Profiler, ProfileStartEnd)
|
||||
{
|
||||
class MemoryTester
|
||||
PROFILE_START(ProfileStartEndTest);
|
||||
// Do work.
|
||||
if(true)
|
||||
{
|
||||
public:
|
||||
void mark();
|
||||
bool check();
|
||||
};
|
||||
PROFILE_END(ProfileStartEndTest);
|
||||
return;
|
||||
}
|
||||
PROFILE_END(ProfileStartEndTest);
|
||||
}
|
||||
|
||||
TEST(Profiler, ProfileScope)
|
||||
{
|
||||
PROFILE_SCOPE(ScopedProfilerTest);
|
||||
// Do work and return whenever you want.
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "unit/test.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateInteractiveTest(CheckPlatformAlerts, "Platform/Alerts")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
// Run through all the alert types.
|
||||
Platform::AlertOK("Test #1 - AlertOK", "This is a test of Platform::AlertOK. I am a blocking dialog with an OK button. Please hit OK to continue.");
|
||||
test(true, "AlertOK should return when the user clicks on it..."); // <-- gratuitous test point.
|
||||
|
||||
bool res;
|
||||
|
||||
res = Platform::AlertOKCancel("Test #2 - AlertOKCancel", "This is a test of Platform::alertOKCancel. I am a blocking dialog with an OK and a Cancel button. Please hit Cancel to continue.");
|
||||
test(res==false,"AlertOKCancel - Didn't get cancel. User error, or just bad code?");
|
||||
|
||||
res = Platform::AlertOKCancel("Test #3 - AlertOKCancel", "This is a test of Platform::alertOKCancel. I am a blocking dialog with an OK and a Cancel button. Please hit OK to continue.");
|
||||
test(res==true,"AlertOKCancel - Didn't get ok. User error, or just bad code?");
|
||||
|
||||
res = Platform::AlertRetry("Test #4 - AlertRetry", "This is a test of Platform::AlertRetry. I am a blocking dialog with an Retry and a Cancel button. Please hit Retry to continue.");
|
||||
test(res==true,"AlertRetry - Didn't get retry. User error, or just bad code?");
|
||||
|
||||
res = Platform::AlertRetry("Test #5 - AlertRetry", "This is a test of Platform::AlertRetry. I am a blocking dialog with an Retry and a Cancel button. Please hit Cancel to continue.");
|
||||
test(res==false,"AlertRetry - Didn't get cancel. User error, or just bad code?");
|
||||
}
|
||||
};
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "core/util/endian.h"
|
||||
#include "unit/test.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateUnitTest(CheckTypeSizes, "Platform/Types/Sizes")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
// Run through all the types and ensure they're the right size.
|
||||
|
||||
#define CheckType(typeName, expectedSize) \
|
||||
test( sizeof(typeName) == expectedSize, "Wrong size for a " #typeName ", expected " #expectedSize);
|
||||
|
||||
// One byte types.
|
||||
CheckType(bool, 1);
|
||||
CheckType(U8, 1);
|
||||
CheckType(S8, 1);
|
||||
CheckType(UTF8, 1);
|
||||
|
||||
// Two byte types.
|
||||
CheckType(U16, 2);
|
||||
CheckType(S16, 2);
|
||||
CheckType(UTF16, 2);
|
||||
|
||||
// Four byte types.
|
||||
CheckType(U32, 4);
|
||||
CheckType(S32, 4);
|
||||
CheckType(F32, 4);
|
||||
CheckType(UTF32, 4);
|
||||
|
||||
// Eight byte types.
|
||||
CheckType(U64, 8);
|
||||
CheckType(S64, 8);
|
||||
CheckType(F64, 8);
|
||||
|
||||
// 16 byte (128bit) types will go here, when we get some.
|
||||
#undef CheckType
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest(CheckEndianConversion, "Platform/Types/EndianRoundTrip")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
// Convenient and non-palindrome byte patterns to test with.
|
||||
const U16 U16Test = 0xA1B2;
|
||||
const S16 S16Test = 0x52A1;
|
||||
|
||||
const U32 U32Test = 0xA1B2C3D4;
|
||||
const S32 S32Test = 0xD4C3B2A1;
|
||||
const F32 F32Test = 1234.5678f;
|
||||
|
||||
//const U64 U64Test = 0xA1B2C3D4E3F2E10A;
|
||||
//const S64 S64Test = 0x1A2B3C4D3E2F1EA0;
|
||||
const F64 F64Test = 12345678.9101112131415;
|
||||
|
||||
// Run through all the conversions - bump stuff from host to little or big
|
||||
// endian and back again.
|
||||
#define CheckEndianRoundTrip(type, b_or_l) \
|
||||
test( type##Test == convert##b_or_l##EndianToHost(convertHostTo##b_or_l##Endian(type##Test)), "Failed to convert the " #type " test value to " #b_or_l " endian and back to host endian order.");
|
||||
|
||||
#define CheckTypeBothWays(type) \
|
||||
CheckEndianRoundTrip(type, B); \
|
||||
CheckEndianRoundTrip(type, L);
|
||||
|
||||
#define CheckIntsForBitSize(bits) \
|
||||
CheckTypeBothWays( U##bits ); \
|
||||
CheckTypeBothWays( S##bits );
|
||||
|
||||
// Don't check 8-bit types - they aren't affected by endian issues.
|
||||
|
||||
// Check the >1 byte int types, though.
|
||||
CheckIntsForBitSize(16);
|
||||
CheckIntsForBitSize(32);
|
||||
// CheckIntsForBitSize(64); // don't have convertHostToLEndian(const U64/S64) so this doesn't work
|
||||
|
||||
// And check the float types.
|
||||
CheckTypeBothWays(F32);
|
||||
CheckTypeBothWays(F64);
|
||||
|
||||
// We'd check 128bit types here, if we had any.
|
||||
|
||||
#undef CheckIntsForBitSize
|
||||
#undef CheckTypeBothWays
|
||||
#undef CheckEndianRoundTrip
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest(CheckEndianSwap, "Platform/Types/EndianSwap")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
U32 swap32 = 0xABCDEF12;
|
||||
U16 swap16 = 0xABCD;
|
||||
|
||||
test(endianSwap(swap32) == 0x12EFCDAB, "32 bit endianSwap should reverse byte order, but didn't.");
|
||||
test(endianSwap(swap16) == 0xCDAB, "16 bit endianSwap should reverse byte order, but didn't.");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "core/fileio.h"
|
||||
#include "unit/test.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "console/console.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateUnitTest(CheckFileListingAndExclusion, "File/ListDirectoryAndExclusions")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
// Just dump everything under the current directory. We should
|
||||
// find at least one file.
|
||||
|
||||
// Exclude .svn and CVS
|
||||
Platform::clearExcludedDirectories();
|
||||
Platform::addExcludedDirectory(".svn");
|
||||
Platform::addExcludedDirectory("CVS");
|
||||
|
||||
test(Platform::isExcludedDirectory("foo") == false, "Doesn't match list, shouldn't be excluded.");
|
||||
test(Platform::isExcludedDirectory(".svn") == true, "On list, should be excluded.");
|
||||
test(Platform::isExcludedDirectory("CVS") == true, "On list, should be excluded.");
|
||||
test(Platform::isExcludedDirectory(".svnCVS") == false, "Looks like a duck, but it shouldn't be excluded cuz it's distinct from all entries on the exclusion list.");
|
||||
|
||||
// Ok, now our exclusion list is setup, so let's dump some paths.
|
||||
Vector < Platform::FileInfo > pathInfo;
|
||||
Platform::dumpPath (Platform::getCurrentDirectory(), pathInfo, 2);
|
||||
|
||||
Con::printf("Dump of files in '%s', up to 2 levels deep...", Platform::getCurrentDirectory());
|
||||
for(S32 i=0; i<pathInfo.size(); i++)
|
||||
{
|
||||
Platform::FileInfo &file = pathInfo[i];
|
||||
|
||||
Con::printf(" %s (%s) %d bytes", file.pFullPath, file.pFileName, file.fileSize);
|
||||
}
|
||||
|
||||
test(pathInfo.size() > 0, "Should find at least SOMETHING in the current directory!");
|
||||
|
||||
// This'll nuke info if we run it in a live situation... so don't run unit
|
||||
// tests in a live situation. ;)
|
||||
Platform::clearExcludedDirectories();
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest(CheckFileTouchAndTime, "File/TouchAndTime")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
FileTime create[2], modify[2];
|
||||
|
||||
// Create a file and sleep for a second.
|
||||
File f;
|
||||
f.open("testTouch.file", File::WriteAppend);
|
||||
f.close();
|
||||
|
||||
Platform::sleep(2000);
|
||||
|
||||
// Touch a file and note its last-modified.
|
||||
dFileTouch("testTouch.file");
|
||||
test(Platform::isFile("testTouch.file"), "We just touched this file - it should exist.");
|
||||
test(Platform::getFileTimes("testTouch.file", &create[0], &modify[0]), "Failed to get filetimes for a file we just created.");
|
||||
|
||||
// Sleep for a few seconds...
|
||||
Platform::sleep(5000);
|
||||
|
||||
// Touch it again, and compare the last-modifieds.
|
||||
test(Platform::isFile("testTouch.file"), "We just touched this file - it should exist.");
|
||||
dFileTouch("testTouch.file");
|
||||
test(Platform::isFile("testTouch.file"), "We just touched this file - it should exist.");
|
||||
test(Platform::getFileTimes("testTouch.file", &create[1], &modify[1]), "Failed to get filetimes for a file we just created.");
|
||||
|
||||
// Now compare the times...
|
||||
test(Platform::compareFileTimes(modify[0], modify[1]) < 0, "Timestamps are wrong - modify[0] should be before modify[1]!");
|
||||
|
||||
// This seems to fail even on a valid case...
|
||||
// test(Platform::compareFileTimes(create[0], create[1]) == 0, "Create timestamps should match - we didn't delete the file during this test.");
|
||||
|
||||
// Clean up..
|
||||
dFileDelete("testTouch.file");
|
||||
test(!Platform::isFile("testTouch.file"), "Somehow failed to delete our test file.");
|
||||
}
|
||||
};
|
||||
|
||||
// Mac has no implementations for these functions, so we 'def it out for now.
|
||||
#if 0
|
||||
CreateUnitTest(CheckVolumes, "File/Volumes")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
Con::printf("Dumping volumes by name:");
|
||||
|
||||
Vector<const char*> names;
|
||||
Platform::getVolumeNamesList(names);
|
||||
|
||||
test(names.size() > 0, "We should have at least one volume...");
|
||||
|
||||
for(S32 i=0; i<names.size(); i++)
|
||||
Con::printf(" %s", names[i]);
|
||||
|
||||
Con::printf("Dumping volume info:");
|
||||
|
||||
Vector<Platform::VolumeInformation> info;
|
||||
Platform::getVolumeInformationList(info);
|
||||
|
||||
test(names.size() == info.size(), "Got inconsistent number of volumes back from info vs. name list functions!");
|
||||
|
||||
for(S32 i=0; i<info.size(); i++)
|
||||
Con::printf(" %s rootPath = %s filesystem = %s ser. num. = %d type = %d readonly = %s",
|
||||
info[i].Name,
|
||||
info[i].RootPath,
|
||||
info[i].FileSystem,
|
||||
info[i].SerialNumber,
|
||||
info[i].Type,
|
||||
info[i].ReadOnly ? "true" : "false");
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
CreateUnitTest(CheckFileWriteAndRead, "File/ReadAndWrite")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
// Open a file, write some junk to it, close it,
|
||||
// check size is correct, and open it again.
|
||||
|
||||
}
|
||||
};
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platformNet.h"
|
||||
#include "unit/test.h"
|
||||
#include "core/util/journal/process.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateUnitTest( TestTCPRequest, "Platform/Net/TCPRequest")
|
||||
{
|
||||
NetSocket mSocket;
|
||||
S32 mDataRecved;
|
||||
|
||||
void handleNotify(NetSocket sock, U32 state)
|
||||
{
|
||||
// Only consider our own socket.
|
||||
if(mSocket != sock)
|
||||
return;
|
||||
|
||||
// Ok - what's the state? We do some dumb responses to given states
|
||||
// in order to fulfill the request.
|
||||
if(state == Net::Connected)
|
||||
{
|
||||
U8 reqBuffer[] = {
|
||||
"GET / HTTP/1.0\nUser-Agent: Torque/1.0\n\n"
|
||||
};
|
||||
|
||||
Net::Error e = Net::sendtoSocket(mSocket, reqBuffer, sizeof(reqBuffer));
|
||||
|
||||
test(e == Net::NoError, "Got an error sending our HTTP request!");
|
||||
}
|
||||
else if(state == Net::Disconnected)
|
||||
{
|
||||
Process::requestShutdown();
|
||||
mSocket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void handleReceive(NetSocket sock, RawData incomingData)
|
||||
{
|
||||
// Only consider our own socket.
|
||||
if(mSocket != sock)
|
||||
return;
|
||||
|
||||
char buff[4096];
|
||||
dMemcpy(buff, incomingData.data, incomingData.size);
|
||||
buff[incomingData.size] = 0;
|
||||
|
||||
UnitPrint("Got a message...\n");
|
||||
UnitPrint(buff);
|
||||
UnitPrint("------\n");
|
||||
|
||||
mDataRecved += incomingData.size;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
mSocket = InvalidSocket;
|
||||
mDataRecved = 0;
|
||||
|
||||
// Initialize networking - done by initLibraries currently
|
||||
//test(Net::init(), "Failed to initialize networking!");
|
||||
|
||||
// Hook into the signals.
|
||||
Net::smConnectionNotify. notify(this, &TestTCPRequest::handleNotify);
|
||||
Net::smConnectionReceive.notify(this, &TestTCPRequest::handleReceive);
|
||||
|
||||
// Open a TCP connection to garagegames.com
|
||||
mSocket = Net::openConnectTo("ip:72.246.107.193:80");
|
||||
U32 limit = Platform::getRealMilliseconds() + (5*1000);
|
||||
while(Process::processEvents() && (Platform::getRealMilliseconds() < limit) )
|
||||
;
|
||||
|
||||
// Unhook from the signals.
|
||||
Net::smConnectionNotify. remove(this, &TestTCPRequest::handleNotify);
|
||||
Net::smConnectionReceive.remove(this, &TestTCPRequest::handleReceive);
|
||||
|
||||
test(mDataRecved > 0, "Didn't get any data back!");
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest( TestTCPRequestJournal, "Platform/Net/JournalTCPRequest")
|
||||
{
|
||||
NetSocket mSocket;
|
||||
S32 mDataRecved;
|
||||
|
||||
void handleNotify(NetSocket sock, U32 state)
|
||||
{
|
||||
// Only consider our own socket.
|
||||
if(mSocket != sock)
|
||||
return;
|
||||
|
||||
// Ok - what's the state? We do some dumb responses to given states
|
||||
// in order to fulfill the request.
|
||||
if(state == Net::Connected)
|
||||
{
|
||||
U8 reqBuffer[] = {
|
||||
"GET / HTTP/1.0\nUser-Agent: Torque/1.0\n\n"
|
||||
};
|
||||
|
||||
Net::Error e = Net::sendtoSocket(mSocket, reqBuffer, sizeof(reqBuffer));
|
||||
|
||||
test(e == Net::NoError, "Got an error sending our HTTP request!");
|
||||
}
|
||||
else if(state == Net::Disconnected)
|
||||
{
|
||||
Process::requestShutdown();
|
||||
mSocket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void handleReceive(NetSocket sock, RawData incomingData)
|
||||
{
|
||||
// Only consider our own socket.
|
||||
if(mSocket != sock)
|
||||
return;
|
||||
|
||||
char buff[4096];
|
||||
dMemcpy(buff, incomingData.data, incomingData.size);
|
||||
buff[incomingData.size] = 0;
|
||||
|
||||
UnitPrint("Got a message...\n");
|
||||
UnitPrint(buff);
|
||||
UnitPrint("------\n");
|
||||
|
||||
mDataRecved += incomingData.size;
|
||||
}
|
||||
|
||||
void makeRequest()
|
||||
{
|
||||
mSocket = InvalidSocket;
|
||||
mDataRecved = 0;
|
||||
|
||||
// Initialize networking - done by initLibraries currently
|
||||
//test(Net::init(), "Failed to initialize networking!");
|
||||
|
||||
// Hook into the signals.
|
||||
Net::smConnectionNotify. notify(this, &TestTCPRequestJournal::handleNotify);
|
||||
Net::smConnectionReceive.notify(this, &TestTCPRequestJournal::handleReceive);
|
||||
|
||||
// Open a TCP connection to garagegames.com
|
||||
mSocket = Net::openConnectTo("ip:72.246.107.193:80");
|
||||
|
||||
// Let the callbacks enable things to process.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
// Unhook from the signals.
|
||||
Net::smConnectionNotify. remove(this, &TestTCPRequestJournal::handleNotify);
|
||||
Net::smConnectionReceive.remove(this, &TestTCPRequestJournal::handleReceive);
|
||||
|
||||
test(mDataRecved > 0, "Didn't get any data back!");
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
Journal::Record("journalTCP.jrn");
|
||||
|
||||
if( !Journal::IsRecording() )
|
||||
{
|
||||
test(0, "Failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
makeRequest();
|
||||
|
||||
S32 bytesRead = mDataRecved;
|
||||
|
||||
Journal::Stop();
|
||||
|
||||
Journal::Play("journalTCP.jrn");
|
||||
|
||||
makeRequest();
|
||||
|
||||
Journal::Stop();
|
||||
|
||||
test(bytesRead == mDataRecved, "Didn't get same data back from journal playback.");
|
||||
|
||||
}
|
||||
};
|
||||
|
|
@ -1,403 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "platform/threads/threadSafeDeque.h"
|
||||
#include "platform/threads/thread.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "console/console.h"
|
||||
|
||||
|
||||
#ifndef TORQUE_SHIPPING
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
#define TEST( x ) test( ( x ), "FAIL: " #x )
|
||||
#define XTEST( t, x ) t->test( ( x ), "FAIL: " #x )
|
||||
|
||||
|
||||
// Test deque without concurrency.
|
||||
|
||||
CreateUnitTest( TestThreadSafeDequeSerial, "Platform/ThreadSafeDeque/Serial" )
|
||||
{
|
||||
void test1()
|
||||
{
|
||||
ThreadSafeDeque< char > deque;
|
||||
String str = "teststring";
|
||||
|
||||
for( U32 i = 0; i < str.length(); ++ i )
|
||||
deque.pushBack( str[ i ] );
|
||||
|
||||
TEST( !deque.isEmpty() );
|
||||
|
||||
for( U32 i = 0; i < str.length(); ++ i )
|
||||
{
|
||||
char ch;
|
||||
TEST( deque.tryPopFront( ch ) && ch == str[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
ThreadSafeDeque< char > deque;
|
||||
String str = "teststring";
|
||||
|
||||
const char* p1 = str.c_str() + 4;
|
||||
const char* p2 = p1 + 1;
|
||||
while( *p2 )
|
||||
{
|
||||
deque.pushFront( *p1 );
|
||||
deque.pushBack( *p2 );
|
||||
|
||||
-- p1;
|
||||
++ p2;
|
||||
}
|
||||
|
||||
#ifdef TORQUE_DEBUG
|
||||
deque.dumpDebug();
|
||||
#endif
|
||||
|
||||
for( U32 i = 0; i < str.length(); ++ i )
|
||||
{
|
||||
char ch;
|
||||
TEST( deque.tryPopFront( ch ) && ch == str[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
void test3()
|
||||
{
|
||||
ThreadSafeDeque< char > deque;
|
||||
String str = "teststring";
|
||||
|
||||
const char* p1 = str.c_str() + 4;
|
||||
const char* p2 = p1 + 1;
|
||||
while( *p2 )
|
||||
{
|
||||
deque.pushFront( *p1 );
|
||||
deque.pushBack( *p2 );
|
||||
|
||||
-- p1;
|
||||
++ p2;
|
||||
}
|
||||
|
||||
#ifdef TORQUE_DEBUG
|
||||
deque.dumpDebug();
|
||||
#endif
|
||||
|
||||
for( S32 i = ( str.length() - 1 ); i >= 0; -- i )
|
||||
{
|
||||
char ch;
|
||||
TEST( deque.tryPopBack( ch ) && ch == str[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
void test4()
|
||||
{
|
||||
ThreadSafeDeque< char > deque;
|
||||
char ch;
|
||||
|
||||
TEST( deque.isEmpty() );
|
||||
|
||||
deque.pushFront( 'a' );
|
||||
TEST( !deque.isEmpty() );
|
||||
TEST( deque.tryPopFront( ch ) );
|
||||
TEST( ch == 'a' );
|
||||
|
||||
deque.pushBack( 'a' );
|
||||
TEST( !deque.isEmpty() );
|
||||
TEST( deque.tryPopFront( ch ) );
|
||||
TEST( ch == 'a' );
|
||||
|
||||
deque.pushBack( 'a' );
|
||||
TEST( !deque.isEmpty() );
|
||||
TEST( deque.tryPopBack( ch ) );
|
||||
TEST( ch == 'a' );
|
||||
|
||||
deque.pushFront( 'a' );
|
||||
TEST( !deque.isEmpty() );
|
||||
TEST( deque.tryPopBack( ch ) );
|
||||
TEST( ch == 'a' );
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
}
|
||||
};
|
||||
|
||||
// Test deque in a concurrent setting.
|
||||
|
||||
CreateUnitTest( TestThreadSafeDequeConcurrentSimple, "Platform/ThreadSafeDeque/ConcurrentSimple" )
|
||||
{
|
||||
public:
|
||||
typedef TestThreadSafeDequeConcurrentSimple TestType;
|
||||
|
||||
enum
|
||||
{
|
||||
DEFAULT_NUM_VALUES = 100000,
|
||||
};
|
||||
|
||||
struct Value : public ThreadSafeRefCount< Value >
|
||||
{
|
||||
U32 mIndex;
|
||||
U32 mTick;
|
||||
|
||||
Value() {}
|
||||
Value( U32 index, U32 tick )
|
||||
: mIndex( index ), mTick( tick ) {}
|
||||
};
|
||||
|
||||
typedef ThreadSafeRef< Value > ValueRef;
|
||||
|
||||
struct Deque : public ThreadSafeDeque< ValueRef >
|
||||
{
|
||||
typedef ThreadSafeDeque<ValueRef> Parent;
|
||||
|
||||
U32 mPushIndex;
|
||||
U32 mPopIndex;
|
||||
|
||||
Deque()
|
||||
: mPushIndex( 0 ), mPopIndex( 0 ) {}
|
||||
|
||||
void pushBack( const ValueRef& value )
|
||||
{
|
||||
AssertFatal( value->mIndex == mPushIndex, "index out of line" );
|
||||
mPushIndex ++;
|
||||
Parent::pushBack( value );
|
||||
}
|
||||
bool tryPopFront( ValueRef& outValue )
|
||||
{
|
||||
if( Parent::tryPopFront( outValue ) )
|
||||
{
|
||||
AssertFatal( outValue->mIndex == mPopIndex, "index out of line" );
|
||||
mPopIndex ++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Deque mDeque;
|
||||
Vector< U32 > mValues;
|
||||
|
||||
struct ProducerThread : public Thread
|
||||
{
|
||||
ProducerThread( TestType* test )
|
||||
: Thread( 0, test ) {}
|
||||
|
||||
virtual void run( void* arg )
|
||||
{
|
||||
_setName( "ProducerThread" );
|
||||
Platform::outputDebugString( "Starting ProducerThread" );
|
||||
|
||||
TestType* test = ( TestType* ) arg;
|
||||
|
||||
for( U32 i = 0; i < test->mValues.size(); ++ i )
|
||||
{
|
||||
U32 tick = Platform::getRealMilliseconds();
|
||||
test->mValues[ i ] = tick;
|
||||
|
||||
ValueRef val = new Value( i, tick );
|
||||
test->mDeque.pushBack( val );
|
||||
}
|
||||
Platform::outputDebugString( "Stopping ProducerThread" );
|
||||
}
|
||||
};
|
||||
struct ConsumerThread : public Thread
|
||||
{
|
||||
ConsumerThread( TestType* test )
|
||||
: Thread( 0, test ) {}
|
||||
|
||||
virtual void run( void* arg )
|
||||
{
|
||||
_setName( "ConsumerThread" );
|
||||
Platform::outputDebugString( "Starting CosumerThread" );
|
||||
TestType* t = ( TestType* ) arg;
|
||||
|
||||
for( U32 i = 0; i < t->mValues.size(); ++ i )
|
||||
{
|
||||
ValueRef value;
|
||||
while( !t->mDeque.tryPopFront( value ) );
|
||||
|
||||
XTEST( t, value->mIndex == i );
|
||||
XTEST( t, t->mValues[ i ] == value->mTick );
|
||||
}
|
||||
Platform::outputDebugString( "Stopping ConsumerThread" );
|
||||
}
|
||||
};
|
||||
|
||||
void run()
|
||||
{
|
||||
U32 numValues = Con::getIntVariable( "$testThreadSafeDeque::numValues", DEFAULT_NUM_VALUES );
|
||||
mValues.setSize( numValues );
|
||||
|
||||
ProducerThread pThread( this );
|
||||
ConsumerThread cThread( this );
|
||||
|
||||
pThread.start();
|
||||
cThread.start();
|
||||
|
||||
pThread.join();
|
||||
cThread.join();
|
||||
|
||||
mValues.clear();
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest( TestThreadSafeDequeConcurrent, "Platform/ThreadSafeDeque/Concurrent" )
|
||||
{
|
||||
public:
|
||||
typedef TestThreadSafeDequeConcurrent TestType;
|
||||
|
||||
enum
|
||||
{
|
||||
DEFAULT_NUM_VALUES = 100000,
|
||||
DEFAULT_NUM_CONSUMERS = 10,
|
||||
DEFAULT_NUM_PRODUCERS = 10
|
||||
};
|
||||
|
||||
struct Value : public ThreadSafeRefCount< Value >
|
||||
{
|
||||
U32 mIndex;
|
||||
U32 mTick;
|
||||
|
||||
Value() {}
|
||||
Value( U32 index, U32 tick )
|
||||
: mIndex( index ), mTick( tick ) {}
|
||||
};
|
||||
|
||||
typedef ThreadSafeRef< Value > ValueRef;
|
||||
|
||||
U32 mProducerIndex;
|
||||
U32 mConsumerIndex;
|
||||
ThreadSafeDeque< ValueRef > mDeque;
|
||||
Vector< U32 > mValues;
|
||||
|
||||
struct ProducerThread : public Thread
|
||||
{
|
||||
ProducerThread( TestType* test )
|
||||
: Thread( 0, test ) {}
|
||||
|
||||
virtual void run( void* arg )
|
||||
{
|
||||
_setName( "ProducerThread" );
|
||||
Platform::outputDebugString( "Starting ProducerThread" );
|
||||
TestType* test = ( TestType* ) arg;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
U32 index = test->mProducerIndex;
|
||||
if( index == test->mValues.size() )
|
||||
break;
|
||||
|
||||
if( dCompareAndSwap( test->mProducerIndex, index, index + 1 ) )
|
||||
{
|
||||
U32 tick = Platform::getRealMilliseconds();
|
||||
test->mValues[ index ] = tick;
|
||||
|
||||
ValueRef val = new Value( index, tick );
|
||||
test->mDeque.pushBack( val );
|
||||
}
|
||||
}
|
||||
Platform::outputDebugString( "Stopping ProducerThread" );
|
||||
}
|
||||
};
|
||||
struct ConsumerThread : public Thread
|
||||
{
|
||||
ConsumerThread( TestType* test )
|
||||
: Thread( 0, test ) {}
|
||||
|
||||
virtual void run( void* arg )
|
||||
{
|
||||
_setName( "ConsumerThread" );
|
||||
Platform::outputDebugString( "Starting ConsumerThread" );
|
||||
TestType* t = ( TestType* ) arg;
|
||||
|
||||
while( t->mConsumerIndex < t->mValues.size() )
|
||||
{
|
||||
ValueRef value;
|
||||
if( t->mDeque.tryPopFront( value ) )
|
||||
{
|
||||
dFetchAndAdd( t->mConsumerIndex, 1 );
|
||||
XTEST( t, t->mValues[ value->mIndex ] == value->mTick );
|
||||
t->mValues[ value->mIndex ] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Platform::outputDebugString( "Stopping ConsumerThread" );
|
||||
}
|
||||
};
|
||||
|
||||
void run()
|
||||
{
|
||||
U32 numValues = Con::getIntVariable( "$testThreadSafeDeque::numValues", DEFAULT_NUM_VALUES );
|
||||
U32 numConsumers = Con::getIntVariable( "$testThreadSafeDeque::numConsumers", DEFAULT_NUM_CONSUMERS );
|
||||
U32 numProducers = Con::getIntVariable( "$testThreadSafeDeque::numProducers", DEFAULT_NUM_PRODUCERS );
|
||||
|
||||
mProducerIndex = 0;
|
||||
mConsumerIndex = 0;
|
||||
mValues.setSize( numValues );
|
||||
|
||||
U32 tick = Platform::getRealMilliseconds();
|
||||
for( U32 i = 0; i < numValues; ++ i )
|
||||
mValues[ i ] = tick;
|
||||
|
||||
Vector< ProducerThread* > producers;
|
||||
Vector< ConsumerThread* > consumers;
|
||||
|
||||
producers.setSize( numProducers );
|
||||
consumers.setSize( numConsumers );
|
||||
|
||||
for( U32 i = 0; i < numProducers; ++ i )
|
||||
{
|
||||
producers[ i ] = new ProducerThread( this );
|
||||
producers[ i ]->start();
|
||||
}
|
||||
for( U32 i = 0; i < numConsumers; ++ i )
|
||||
{
|
||||
consumers[ i ] = new ConsumerThread( this );
|
||||
consumers[ i ]->start();
|
||||
}
|
||||
|
||||
for( U32 i = 0; i < numProducers; ++ i )
|
||||
{
|
||||
producers[ i ]->join();
|
||||
delete producers[ i ];
|
||||
}
|
||||
for( U32 i = 0; i < numConsumers; ++ i )
|
||||
{
|
||||
consumers[ i ]->join();
|
||||
delete consumers[ i ];
|
||||
}
|
||||
|
||||
for( U32 i = 0; i < mValues.size(); ++ i )
|
||||
TEST( mValues[ i ] == 0 );
|
||||
|
||||
mValues.clear();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !TORQUE_SHIPPING
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "platform/threads/threadSafePriorityQueue.h"
|
||||
#include "platform/threads/thread.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "console/console.h"
|
||||
|
||||
|
||||
#ifndef TORQUE_SHIPPING
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
#define TEST( x ) test( ( x ), "FAIL: " #x )
|
||||
#define XTEST( t, x ) t->test( ( x ), "FAIL: " #x )
|
||||
|
||||
|
||||
// Test queue without concurrency.
|
||||
|
||||
CreateUnitTest( TestThreadSafePriorityQueueSerial, "Platform/ThreadSafePriorityQueue/Serial" )
|
||||
{
|
||||
struct Value
|
||||
{
|
||||
F32 mPriority;
|
||||
U32 mIndex;
|
||||
|
||||
Value() {}
|
||||
Value( F32 priority, U32 index )
|
||||
: mPriority( priority ), mIndex( index ) {}
|
||||
};
|
||||
|
||||
template< bool SORT_MIN_TO_MAX >
|
||||
void test1()
|
||||
{
|
||||
Vector< Value > values;
|
||||
|
||||
values.push_back( Value( 0.2f, 2 ) );
|
||||
values.push_back( Value( 0.7f, 7 ) );
|
||||
values.push_back( Value( 0.4f, 4 ) );
|
||||
values.push_back( Value( 0.6f, 6 ) );
|
||||
values.push_back( Value( 0.1f, 1 ) );
|
||||
values.push_back( Value( 0.5f, 5 ) );
|
||||
values.push_back( Value( 0.3f, 3 ) );
|
||||
values.push_back( Value( 0.8f, 8 ) );
|
||||
values.push_back( Value( 0.6f, 6 ) );
|
||||
values.push_back( Value( 0.9f, 9 ) );
|
||||
values.push_back( Value( 0.0f, 0 ) );
|
||||
|
||||
const S32 min = 0;
|
||||
const S32 max = 9;
|
||||
|
||||
ThreadSafePriorityQueue< U32, F32, SORT_MIN_TO_MAX > queue;
|
||||
|
||||
for( U32 i = 0; i < values.size(); ++ i )
|
||||
queue.insert( values[ i ].mPriority, values[ i ].mIndex );
|
||||
|
||||
TEST( !queue.isEmpty() );
|
||||
|
||||
S32 index;
|
||||
if( SORT_MIN_TO_MAX )
|
||||
index = min - 1;
|
||||
else
|
||||
index = max + 1;
|
||||
|
||||
for( U32 i = 0; i < values.size(); ++ i )
|
||||
{
|
||||
U32 value;
|
||||
TEST( queue.takeNext( value ) );
|
||||
|
||||
if( value != index )
|
||||
{
|
||||
if( SORT_MIN_TO_MAX )
|
||||
index ++;
|
||||
else
|
||||
index --;
|
||||
}
|
||||
|
||||
TEST( value == index );
|
||||
}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
test1< true >();
|
||||
test1< false >();
|
||||
}
|
||||
};
|
||||
|
||||
// Test queue with concurrency.
|
||||
|
||||
CreateUnitTest( TestThreadSafePriorityQueueConcurrent, "Platform/ThreadSafePriorityQueue/Concurrent" )
|
||||
{
|
||||
public:
|
||||
typedef TestThreadSafePriorityQueueConcurrent TestType;
|
||||
|
||||
enum
|
||||
{
|
||||
DEFAULT_NUM_VALUES = 100000,
|
||||
DEFAULT_NUM_CONSUMERS = 10,
|
||||
DEFAULT_NUM_PRODUCERS = 10
|
||||
};
|
||||
|
||||
struct Value : public ThreadSafeRefCount< Value >
|
||||
{
|
||||
U32 mIndex;
|
||||
F32 mPriority;
|
||||
bool mCheck;
|
||||
|
||||
Value() : mCheck( false ) {}
|
||||
Value( U32 index, F32 priority )
|
||||
: mIndex( index ), mPriority( priority ), mCheck( false ) {}
|
||||
};
|
||||
|
||||
typedef ThreadSafeRef< Value > ValueRef;
|
||||
|
||||
U32 mProducerIndex;
|
||||
U32 mConsumerIndex;
|
||||
ThreadSafePriorityQueue< ValueRef > mQueue;
|
||||
Vector< ValueRef > mValues;
|
||||
|
||||
struct ProducerThread : public Thread
|
||||
{
|
||||
ProducerThread( TestType* test )
|
||||
: Thread( 0, test ) {}
|
||||
|
||||
virtual void run( void* arg )
|
||||
{
|
||||
_setName( "ProducerThread" );
|
||||
Platform::outputDebugString( "Starting ProducerThread" );
|
||||
TestType* test = ( TestType* ) arg;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
U32 index = test->mProducerIndex;
|
||||
if( index == test->mValues.size() )
|
||||
break;
|
||||
|
||||
if( dCompareAndSwap( test->mProducerIndex, index, index + 1 ) )
|
||||
{
|
||||
F32 priority = Platform::getRandom();
|
||||
ValueRef val = new Value( index, priority );
|
||||
test->mValues[ index ] = val;
|
||||
test->mQueue.insert( priority, val );
|
||||
}
|
||||
}
|
||||
Platform::outputDebugString( "Stopping ProducerThread" );
|
||||
}
|
||||
};
|
||||
struct ConsumerThread : public Thread
|
||||
{
|
||||
ConsumerThread( TestType* test )
|
||||
: Thread( 0, test ) {}
|
||||
|
||||
virtual void run( void* arg )
|
||||
{
|
||||
_setName( "ConsumerThread" );
|
||||
Platform::outputDebugString( "Starting ConsumerThread" );
|
||||
TestType* t = ( TestType* ) arg;
|
||||
|
||||
while( t->mConsumerIndex < t->mValues.size() )
|
||||
{
|
||||
ValueRef value;
|
||||
if( t->mQueue.takeNext( value ) )
|
||||
{
|
||||
dFetchAndAdd( t->mConsumerIndex, 1 );
|
||||
XTEST( t, t->mValues[ value->mIndex ] == value );
|
||||
value->mCheck = true;
|
||||
}
|
||||
else
|
||||
Platform::sleep( 5 );
|
||||
}
|
||||
Platform::outputDebugString( "Stopping ConsumerThread" );
|
||||
}
|
||||
};
|
||||
|
||||
void run()
|
||||
{
|
||||
U32 numValues = Con::getIntVariable( "$testThreadSafePriorityQueue::numValues", DEFAULT_NUM_VALUES );
|
||||
U32 numConsumers = Con::getIntVariable( "$testThreadSafePriorityQueue::numConsumers", DEFAULT_NUM_CONSUMERS );
|
||||
U32 numProducers = Con::getIntVariable( "$testThreadSafePriorityQueue::numProducers", DEFAULT_NUM_PRODUCERS );
|
||||
|
||||
mProducerIndex = 0;
|
||||
mConsumerIndex = 0;
|
||||
mValues.setSize( numValues );
|
||||
|
||||
Vector< ProducerThread* > producers;
|
||||
Vector< ConsumerThread* > consumers;
|
||||
|
||||
producers.setSize( numProducers );
|
||||
consumers.setSize( numConsumers );
|
||||
|
||||
for( U32 i = 0; i < numProducers; ++ i )
|
||||
{
|
||||
producers[ i ] = new ProducerThread( this );
|
||||
producers[ i ]->start();
|
||||
}
|
||||
for( U32 i = 0; i < numConsumers; ++ i )
|
||||
{
|
||||
consumers[ i ] = new ConsumerThread( this );
|
||||
consumers[ i ]->start();
|
||||
}
|
||||
|
||||
for( U32 i = 0; i < numProducers; ++ i )
|
||||
{
|
||||
producers[ i ]->join();
|
||||
delete producers[ i ];
|
||||
}
|
||||
for( U32 i = 0; i < numConsumers; ++ i )
|
||||
{
|
||||
consumers[ i ]->join();
|
||||
delete consumers[ i ];
|
||||
}
|
||||
|
||||
for( U32 i = 0; i < mValues.size(); ++ i )
|
||||
{
|
||||
TEST( mValues[ i ] != NULL );
|
||||
if( mValues[ i ] != NULL )
|
||||
TEST( mValues[ i ]->mCheck );
|
||||
}
|
||||
|
||||
mValues.clear();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !TORQUE_SHIPPING
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "platform/threads/threadSafeRefCount.h"
|
||||
#include "platform/threads/thread.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "console/console.h"
|
||||
|
||||
#ifndef TORQUE_SHIPPING
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
#define TEST( x ) test( ( x ), "FAIL: " #x )
|
||||
|
||||
CreateUnitTest( TestThreadSafeRefCountSerial, "Platform/ThreadSafeRefCount/Serial" )
|
||||
{
|
||||
struct TestObject : public ThreadSafeRefCount< TestObject >
|
||||
{
|
||||
static bool smDeleted;
|
||||
|
||||
TestObject()
|
||||
{
|
||||
smDeleted = false;
|
||||
}
|
||||
~TestObject()
|
||||
{
|
||||
smDeleted = true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef ThreadSafeRef< TestObject > TestObjectRef;
|
||||
|
||||
void run()
|
||||
{
|
||||
TestObjectRef ref1 = new TestObject;
|
||||
TEST( !ref1->isShared() );
|
||||
TEST( ref1 != NULL );
|
||||
|
||||
TestObjectRef ref2 = ref1;
|
||||
TEST( ref1->isShared() );
|
||||
TEST( ref2->isShared() );
|
||||
TEST( ref1 == ref2 );
|
||||
|
||||
ref1 = NULL;
|
||||
TEST( !ref2->isShared() );
|
||||
|
||||
ref2 = NULL;
|
||||
TEST( TestObject::smDeleted );
|
||||
}
|
||||
};
|
||||
|
||||
bool TestThreadSafeRefCountSerial::TestObject::smDeleted;
|
||||
|
||||
CreateUnitTest( TestThreadSafeRefCountConcurrent, "Platform/ThreadSafeRefCount/Concurrent" )
|
||||
{
|
||||
public:
|
||||
typedef TestThreadSafeRefCountConcurrent TestType;
|
||||
enum
|
||||
{
|
||||
NUM_ADD_REFS_PER_THREAD = 1000,
|
||||
NUM_EXTRA_REFS_PER_THREAD = 1000,
|
||||
NUM_THREADS = 10
|
||||
};
|
||||
|
||||
class TestObject : public ThreadSafeRefCount< TestObject >
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
ThreadSafeRef< TestObject > mRef;
|
||||
|
||||
class TestThread : public Thread
|
||||
{
|
||||
public:
|
||||
TestType* mTest;
|
||||
Vector< ThreadSafeRef< TestObject > > mExtraRefs;
|
||||
|
||||
TestThread( TestType* test )
|
||||
: mTest( test ) {}
|
||||
|
||||
void run( void* arg )
|
||||
{
|
||||
if( !arg )
|
||||
{
|
||||
for( U32 i = 0; i < NUM_ADD_REFS_PER_THREAD; ++ i )
|
||||
mTest->mRef->addRef();
|
||||
|
||||
mExtraRefs.setSize( NUM_EXTRA_REFS_PER_THREAD );
|
||||
for( U32 i = 0; i < NUM_EXTRA_REFS_PER_THREAD; ++ i )
|
||||
mExtraRefs[ i ] = mTest->mRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
mExtraRefs.clear();
|
||||
|
||||
for( U32 i = 0; i < NUM_ADD_REFS_PER_THREAD; ++ i )
|
||||
mTest->mRef->release();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void run()
|
||||
{
|
||||
mRef = new TestObject;
|
||||
TEST( mRef->getRefCount() == 2 ); // increments of 2
|
||||
|
||||
Vector< TestThread* > threads;
|
||||
threads.setSize( NUM_THREADS );
|
||||
|
||||
// Create threads.
|
||||
for( U32 i = 0; i < NUM_THREADS; ++ i )
|
||||
threads[ i ] = new TestThread( this );
|
||||
|
||||
// Run phase 1: create references.
|
||||
for( U32 i = 0; i < NUM_THREADS; ++ i )
|
||||
threads[ i ]->start( NULL );
|
||||
|
||||
// Wait for completion.
|
||||
for( U32 i = 0; i < NUM_THREADS; ++ i )
|
||||
threads[ i ]->join();
|
||||
|
||||
Con::printf( "REF: %i", mRef->getRefCount() );
|
||||
TEST( mRef->getRefCount() == 2 + ( ( NUM_ADD_REFS_PER_THREAD + NUM_EXTRA_REFS_PER_THREAD ) * NUM_THREADS * 2 ) );
|
||||
|
||||
// Run phase 2: release references.
|
||||
for( U32 i = 0; i < NUM_THREADS; ++ i )
|
||||
threads[ i ]->start( ( void* ) 1 );
|
||||
|
||||
// Wait for completion.
|
||||
for( U32 i = 0; i < NUM_THREADS; ++ i )
|
||||
{
|
||||
threads[ i ]->join();
|
||||
delete threads[ i ];
|
||||
}
|
||||
|
||||
TEST( mRef->getRefCount() == 2 ); // increments of two
|
||||
|
||||
mRef = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest( TestThreadSafeRefCountTagging, "Platform/ThreadSafeRefCount/Tagging" )
|
||||
{
|
||||
struct TestObject : public ThreadSafeRefCount< TestObject > {};
|
||||
|
||||
typedef ThreadSafeRef< TestObject > TestObjectRef;
|
||||
|
||||
void run()
|
||||
{
|
||||
TestObjectRef ref;
|
||||
|
||||
TEST( !ref.isTagged() );
|
||||
TEST( !ref );
|
||||
TEST( !ref.ptr() );
|
||||
|
||||
TEST( ref.trySetFromTo( ref, NULL ) );
|
||||
TEST( !ref.isTagged() );
|
||||
|
||||
TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_Set ) );
|
||||
TEST( ref.isTagged() );
|
||||
TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_Set ) );
|
||||
TEST( ref.isTagged() );
|
||||
|
||||
TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_Unset ) );
|
||||
TEST( !ref.isTagged() );
|
||||
TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_Unset ) );
|
||||
TEST( !ref.isTagged() );
|
||||
|
||||
TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_SetOrFail ) );
|
||||
TEST( ref.isTagged() );
|
||||
TEST( !ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_SetOrFail ) );
|
||||
TEST( ref.isTagged() );
|
||||
TEST( !ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_FailIfSet ) );
|
||||
|
||||
TEST( ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_UnsetOrFail ) );
|
||||
TEST( !ref.isTagged() );
|
||||
TEST( !ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_UnsetOrFail ) );
|
||||
TEST( !ref.isTagged() );
|
||||
TEST( !ref.trySetFromTo( ref, NULL, TestObjectRef::TAG_FailIfUnset ) );
|
||||
|
||||
TestObjectRef objectA = new TestObject;
|
||||
TestObjectRef objectB = new TestObject;
|
||||
|
||||
TEST( !objectA->isShared() );
|
||||
TEST( !objectB->isShared() );
|
||||
|
||||
ref = objectA;
|
||||
TEST( !ref.isTagged() );
|
||||
TEST( ref == objectA );
|
||||
TEST( ref == objectA.ptr() );
|
||||
TEST( objectA->isShared() );
|
||||
|
||||
TEST( ref.trySetFromTo( objectA, objectB, TestObjectRef::TAG_Set ) );
|
||||
TEST( ref.isTagged() );
|
||||
TEST( ref == objectB );
|
||||
TEST( ref == objectB.ptr() );
|
||||
TEST( objectB->isShared() );
|
||||
TEST( !objectA->isShared() );
|
||||
|
||||
TEST( ref.trySetFromTo( ref, objectA ) );
|
||||
TEST( ref.isTagged() );
|
||||
TEST( ref == objectA );
|
||||
TEST( ref == objectA.ptr() );
|
||||
}
|
||||
};
|
||||
|
||||
#endif // !TORQUE_SHIPPING
|
||||
|
|
@ -1,417 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "platform/threads/thread.h"
|
||||
#include "platform/threads/semaphore.h"
|
||||
#include "platform/threads/mutex.h"
|
||||
#include "unit/test.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "console/console.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
class ThreadTestHarness
|
||||
{
|
||||
U32 mStartTime, mEndTime, mCleanupTime;
|
||||
void (*mThreadBody)(void*);
|
||||
S32 mThreadCount;
|
||||
Thread **mThreads;
|
||||
|
||||
public:
|
||||
ThreadTestHarness()
|
||||
{
|
||||
mStartTime = mEndTime = mCleanupTime = 0;
|
||||
mThreadBody = NULL;
|
||||
mThreadCount = 1;
|
||||
mThreads = NULL;
|
||||
}
|
||||
|
||||
void startThreads(void (*threadBody)(void*), void *arg, U32 threadCount)
|
||||
{
|
||||
mThreadCount = threadCount;
|
||||
mThreadBody = threadBody;
|
||||
|
||||
// Start up threadCount threads...
|
||||
mThreads = new Thread*[threadCount];
|
||||
|
||||
mStartTime = Platform::getRealMilliseconds();
|
||||
|
||||
//Con::printf(" Running with %d threads...", threadCount);
|
||||
for(S32 i=0; i<mThreadCount; i++)
|
||||
{
|
||||
mThreads[i] = new Thread(threadBody, arg);
|
||||
mThreads[i]->start();
|
||||
}
|
||||
}
|
||||
|
||||
void waitForThreadExit(U32 checkFrequencyMs)
|
||||
{
|
||||
// And wait for them to complete.
|
||||
bool someAlive = true;
|
||||
S32 liveCount = mThreadCount;
|
||||
|
||||
while(someAlive)
|
||||
{
|
||||
//Con::printf(" - Sleeping for %dms with %d live threads.", checkFrequencyMs, liveCount);
|
||||
Platform::sleep(checkFrequencyMs);
|
||||
|
||||
someAlive = false;
|
||||
liveCount = 0;
|
||||
|
||||
for(S32 i=0; i<mThreadCount; i++)
|
||||
{
|
||||
if(!mThreads[i]->isAlive())
|
||||
continue;
|
||||
|
||||
someAlive = true;
|
||||
liveCount++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mEndTime = Platform::getRealMilliseconds();
|
||||
|
||||
// Clean up memory at this point.
|
||||
for(S32 i=0; i<mThreadCount; i++)
|
||||
delete mThreads[i];
|
||||
delete[] mThreads;
|
||||
|
||||
// Make sure we didn't take a long time to complete.
|
||||
mCleanupTime = Platform::getRealMilliseconds();
|
||||
|
||||
// And dump some stats.
|
||||
Con::printf(" Took approximately %dms (+/- %dms) to run %d threads, and %dms to cleanup.",
|
||||
(mEndTime - mStartTime),
|
||||
checkFrequencyMs,
|
||||
mThreadCount,
|
||||
mCleanupTime - mEndTime);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CreateUnitTest( ThreadSanityCheck, "Platform/Threads/BasicSanity")
|
||||
{
|
||||
const static S32 amountOfWork = 100;
|
||||
const static S32 numberOfThreads = 8;
|
||||
|
||||
static void threadBody(void *)
|
||||
{
|
||||
S32 work = 0x381f4fd3;
|
||||
// Spin on some work, then exit.
|
||||
for(S32 i=0; i<amountOfWork; i++)
|
||||
{
|
||||
// Do a little computation...
|
||||
work ^= (i + work | amountOfWork);
|
||||
|
||||
// And sleep a slightly variable bit.
|
||||
Platform::sleep(10 + ((work+i) % 10));
|
||||
}
|
||||
}
|
||||
|
||||
void runNThreads(S32 threadCount)
|
||||
{
|
||||
ThreadTestHarness tth;
|
||||
|
||||
tth.startThreads(&threadBody, NULL, threadCount);
|
||||
tth.waitForThreadExit(32);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
for(S32 i=0; i<numberOfThreads; i++)
|
||||
runNThreads(i);
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest( MutexStressTest, "Platform/Threads/MutexStress")
|
||||
{
|
||||
const static S32 numberOfLocks = 100;
|
||||
const static S32 numberOfThreads = 4;
|
||||
|
||||
void *mMutex;
|
||||
|
||||
static void threadBody(void *mutex)
|
||||
{
|
||||
// Acquire the mutex numberOfLocks times. Sleep for 1ms, acquire, sleep, release.
|
||||
S32 lockCount = numberOfLocks;
|
||||
while(lockCount--)
|
||||
{
|
||||
Platform::sleep(1);
|
||||
Mutex::lockMutex(mutex, true);
|
||||
Platform::sleep(1);
|
||||
Mutex::unlockMutex(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void runNThreads(S32 threadCount)
|
||||
{
|
||||
ThreadTestHarness tth;
|
||||
|
||||
mMutex = Mutex::createMutex();
|
||||
|
||||
tth.startThreads(&threadBody, mMutex, threadCount);
|
||||
|
||||
// We fudge the wait period to be about the expected time assuming
|
||||
// perfect execution speed.
|
||||
tth.waitForThreadExit(32); //threadCount * 2 * numberOfLocks + 100);
|
||||
|
||||
Mutex::destroyMutex(mMutex);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
for(S32 i=0; i<numberOfThreads; i++)
|
||||
runNThreads(i);
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest( MemoryStressTest, "Platform/Threads/MemoryStress")
|
||||
{
|
||||
const static S32 numberOfAllocs = 1000;
|
||||
const static S32 minAllocSize = 13;
|
||||
const static S32 maxAllocSize = 1024 * 1024;
|
||||
const static S32 numberOfThreads = 4;
|
||||
|
||||
void *mMutex;
|
||||
|
||||
// Cheap little RNG so we can vary our allocations more uniquely per thread.
|
||||
static U32 threadRandom(U32 &seed, U32 min, U32 max)
|
||||
{
|
||||
seed = (1664525 * seed + 1013904223);
|
||||
U32 res = seed;
|
||||
res %= (max - min);
|
||||
return res + min;
|
||||
}
|
||||
|
||||
static void threadBody(void *mutex)
|
||||
{
|
||||
// Acquire the mutex numberOfLocks times. Sleep for 1ms, acquire, sleep, release.
|
||||
S32 allocCount = numberOfAllocs;
|
||||
U32 seed = (U32)((U32)mutex + (U32)&allocCount);
|
||||
while(allocCount--)
|
||||
{
|
||||
U8 *mem = new U8[threadRandom(seed, minAllocSize, maxAllocSize)];
|
||||
delete[] mem;
|
||||
}
|
||||
}
|
||||
|
||||
void runNThreads(S32 threadCount)
|
||||
{
|
||||
ThreadTestHarness tth;
|
||||
|
||||
mMutex = Mutex::createMutex();
|
||||
|
||||
tth.startThreads(&threadBody, mMutex, threadCount);
|
||||
|
||||
// We fudge the wait period to be about the expected time assuming
|
||||
// perfect execution speed.
|
||||
tth.waitForThreadExit(32);
|
||||
|
||||
Mutex::destroyMutex(mMutex);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
for(S32 i=0; i<numberOfThreads; i++)
|
||||
runNThreads(i);
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest( ThreadGymnastics, "Platform/Threads/BasicSynchronization")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
// We test various scenarios wrt to locking and unlocking, in a single
|
||||
// thread, just to make sure our basic primitives are working in the
|
||||
// most basic case.
|
||||
|
||||
void *mutex1 = Mutex::createMutex();
|
||||
test(mutex1, "First Mutex::createMutex call failed - that's pretty bad!");
|
||||
|
||||
void *mutex2 = Mutex::createMutex();
|
||||
test(mutex2, "Second Mutex::createMutex call failed - that's pretty bad, too!");
|
||||
|
||||
test(Mutex::lockMutex(mutex1, false), "Nonblocking call to brand new mutex failed - should not be.");
|
||||
test(Mutex::lockMutex(mutex1, true), "Failed relocking a mutex from the same thread - should be able to do this.");
|
||||
|
||||
// Unlock & kill mutex 1
|
||||
Mutex::unlockMutex(mutex1);
|
||||
Mutex::unlockMutex(mutex1);
|
||||
Mutex::destroyMutex(mutex1);
|
||||
|
||||
// Kill mutex2, which was never touched.
|
||||
Mutex::destroyMutex(mutex2);
|
||||
|
||||
// Now we can test semaphores.
|
||||
Semaphore *sem1 = new Semaphore(1);
|
||||
Semaphore *sem2 = new Semaphore(1);
|
||||
|
||||
// Test that we can do non-blocking acquires that succeed.
|
||||
test(sem1->acquire(false), "Should succeed at acquiring a new semaphore with count 1.");
|
||||
test(sem2->acquire(false), "This one should succeed too, see previous test.");
|
||||
|
||||
// Test that we can do non-blocking acquires that fail.
|
||||
test(sem1->acquire(false)==false, "Should failed, as we've already got the sem.");
|
||||
sem1->release();
|
||||
test(sem2->acquire(false)==false, "Should also fail.");
|
||||
sem2->release();
|
||||
|
||||
// Test that we can do blocking acquires that succeed.
|
||||
test(sem1->acquire(true)==true, "Should succeed as we just released.");
|
||||
test(sem2->acquire(true)==true, "Should succeed as we just released.");
|
||||
|
||||
// Can't test blocking acquires that never happen... :)
|
||||
|
||||
// Clean up.
|
||||
delete sem1;
|
||||
delete sem2;
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest( SemaphoreWaitTest, "Platform/Threads/SemaphoreWaitTest")
|
||||
{
|
||||
static void threadBody(void *self)
|
||||
{
|
||||
SemaphoreWaitTest *me = (SemaphoreWaitTest*)self;
|
||||
|
||||
// Wait for the semaphore to get released.
|
||||
me->mSemaphore->acquire();
|
||||
|
||||
// Increment the counter.
|
||||
Mutex::lockMutex(me->mMutex);
|
||||
me->mDoneCount++;
|
||||
Mutex::unlockMutex(me->mMutex);
|
||||
|
||||
// Signal back to the main thread we're done.
|
||||
me->mPostbackSemaphore->release();
|
||||
}
|
||||
|
||||
Semaphore *mSemaphore;
|
||||
Semaphore *mPostbackSemaphore;
|
||||
void *mMutex;
|
||||
U32 mDoneCount;
|
||||
|
||||
const static S32 csmThreadCount = 10;
|
||||
|
||||
void run()
|
||||
{
|
||||
ThreadTestHarness tth;
|
||||
|
||||
mDoneCount = 0;
|
||||
mSemaphore = new Semaphore(0);
|
||||
mPostbackSemaphore = new Semaphore(0);
|
||||
mMutex = Mutex::createMutex();
|
||||
|
||||
tth.startThreads(&threadBody, this, csmThreadCount);
|
||||
|
||||
Platform::sleep(500);
|
||||
|
||||
Mutex::lockMutex(mMutex);
|
||||
test(mDoneCount == 0, "no threads should have touched the counter yet.");
|
||||
Mutex::unlockMutex(mMutex);
|
||||
|
||||
// Let 500 come out.
|
||||
for(S32 i=0; i<csmThreadCount/2; i++)
|
||||
mSemaphore->release();
|
||||
|
||||
// And wait for 500 postbacks.
|
||||
for(S32 i=0; i<csmThreadCount/2; i++)
|
||||
mPostbackSemaphore->acquire();
|
||||
|
||||
Mutex::lockMutex(mMutex);
|
||||
test(mDoneCount == csmThreadCount / 2, "Didn't get expected number of done threads! (a)");
|
||||
Mutex::unlockMutex(mMutex);
|
||||
|
||||
// Ok, now do the rest.
|
||||
// Let 500 come out.
|
||||
for(S32 i=0; i<csmThreadCount/2; i++)
|
||||
mSemaphore->release();
|
||||
|
||||
// And wait for 500 postbacks.
|
||||
for(S32 i=0; i<csmThreadCount/2; i++)
|
||||
mPostbackSemaphore->acquire();
|
||||
|
||||
Mutex::lockMutex(mMutex);
|
||||
test(mDoneCount == csmThreadCount, "Didn't get expected number of done threads! (b)");
|
||||
Mutex::unlockMutex(mMutex);
|
||||
|
||||
// Wait for the threads to exit - shouldn't have to wait ever though.
|
||||
tth.waitForThreadExit(10);
|
||||
|
||||
// Make sure no one touched our data after shutdown time.
|
||||
Mutex::lockMutex(mMutex);
|
||||
test(mDoneCount == csmThreadCount, "Didn't get expected number of done threads! (c)");
|
||||
Mutex::unlockMutex(mMutex);
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest( MutexWaitTest, "Platform/Threads/MutexWaitTest")
|
||||
{
|
||||
static void threadBody(void *self)
|
||||
{
|
||||
MutexWaitTest *me = (MutexWaitTest*)self;
|
||||
|
||||
// Increment the counter. We'll block until the mutex
|
||||
// is open.
|
||||
Mutex::lockMutex(me->mMutex);
|
||||
me->mDoneCount++;
|
||||
Mutex::unlockMutex(me->mMutex);
|
||||
}
|
||||
|
||||
void *mMutex;
|
||||
U32 mDoneCount;
|
||||
|
||||
const static S32 csmThreadCount = 10;
|
||||
|
||||
void run()
|
||||
{
|
||||
mMutex = Mutex::createMutex();
|
||||
mDoneCount = 0;
|
||||
|
||||
// We lock the mutex before we create any threads, so that all the threads
|
||||
// block on the mutex. Then we unlock it and let them all work their way
|
||||
// through the increment.
|
||||
Mutex::lockMutex(mMutex);
|
||||
|
||||
ThreadTestHarness tth;
|
||||
tth.startThreads(&threadBody, this, csmThreadCount);
|
||||
|
||||
Platform::sleep(5000);
|
||||
|
||||
// Check count is still zero.
|
||||
test(mDoneCount == 0, "Uh oh - a thread somehow didn't get blocked by the locked mutex!");
|
||||
|
||||
// Open the flood gates...
|
||||
Mutex::unlockMutex(mMutex);
|
||||
|
||||
// Wait for the threads to all finish executing.
|
||||
tth.waitForThreadExit(10);
|
||||
|
||||
Mutex::lockMutex(mMutex);
|
||||
test(mDoneCount == csmThreadCount, "Hmm - all threads reported done, but we didn't get the expected count.");
|
||||
Mutex::unlockMutex(mMutex);
|
||||
|
||||
// Kill the mutex.
|
||||
Mutex::destroyMutex(mMutex);
|
||||
}
|
||||
};
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "platform/platformTimer.h"
|
||||
#include "core/util/journal/journaledSignal.h"
|
||||
#include "core/util/journal/process.h"
|
||||
#include "math/mMath.h"
|
||||
#include "console/console.h"
|
||||
|
||||
#include "unit/test.h"
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateUnitTest(Check_advanceTime, "Platform/Time/advanceTime")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
U32 time = Platform::getVirtualMilliseconds();
|
||||
Platform::advanceTime(10);
|
||||
U32 newTime = Platform::getVirtualMilliseconds();
|
||||
|
||||
test(newTime - time == 10, "Platform::advanceTime is borked, we advanced 10ms but didn't get a 10ms delta!");
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest(Check_platformSleep, "Platform/Time/Sleep")
|
||||
{
|
||||
const static S32 sleepTimeMs = 500;
|
||||
void run()
|
||||
{
|
||||
U32 start = Platform::getRealMilliseconds();
|
||||
Platform::sleep(sleepTimeMs);
|
||||
U32 end = Platform::getRealMilliseconds();
|
||||
|
||||
test(end - start >= sleepTimeMs, "We didn't sleep at least as long as we requested!");
|
||||
}
|
||||
};
|
||||
|
||||
CreateUnitTest(Check_timeManager, "Platform/Time/Manager")
|
||||
{
|
||||
void handleTimeEvent(S32 timeDelta)
|
||||
{
|
||||
mElapsedTime += timeDelta;
|
||||
mNumberCalls++;
|
||||
|
||||
if(mElapsedTime >= 1000)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
S32 mElapsedTime;
|
||||
S32 mNumberCalls;
|
||||
|
||||
void run()
|
||||
{
|
||||
mElapsedTime = mNumberCalls = 0;
|
||||
|
||||
// Initialize the time manager...
|
||||
TimeManager time;
|
||||
time.timeEvent.notify(this, &Check_timeManager::handleTimeEvent);
|
||||
|
||||
// Event loop till at least one second has passed.
|
||||
const U32 start = Platform::getRealMilliseconds();
|
||||
|
||||
while(Process::processEvents())
|
||||
{
|
||||
// If we go too long, kill it off...
|
||||
if(Platform::getRealMilliseconds() - start > 30*1000)
|
||||
{
|
||||
test(false, "Terminated process loop due to watchdog, not due to time manager event, after 30 seconds.");
|
||||
Process::requestShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
const U32 end = Platform::getRealMilliseconds();
|
||||
|
||||
// Now, confirm we have approximately similar elapsed times.
|
||||
S32 elapsedRealTime = end - start;
|
||||
test(mAbs(elapsedRealTime - mElapsedTime) < 50, "Failed to elapse time to within the desired tolerance.");
|
||||
|
||||
test(mNumberCalls > 0, "Somehow got no event callbacks from TimeManager?");
|
||||
|
||||
Con::printf(" Got %d time events, and elapsed %dms from TimeManager, "
|
||||
"%dms according to Platform::getRealMilliseconds()",
|
||||
mNumberCalls, mElapsedTime, elapsedRealTime);
|
||||
}
|
||||
};
|
||||
139
Engine/source/platform/test/threadStaticTest.cpp
Normal file
139
Engine/source/platform/test/threadStaticTest.cpp
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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"
|
||||
|
||||
// This unit test will blow up without thread static support
|
||||
#include "core/threadStatic.h"
|
||||
#ifdef TORQUE_ENABLE_THREAD_STATICS
|
||||
|
||||
// Declare a test thread static
|
||||
DITTS(U32, gUnitTestFoo, 42);
|
||||
DITTS(F32, gUnitTestF32, 1.0);
|
||||
|
||||
TEST(ThreadStatic, BasicAPI)
|
||||
{
|
||||
// ThreadStatic list should be initialized right now, so lets see if it has
|
||||
// any entries.
|
||||
EXPECT_FALSE(_TorqueThreadStaticReg::getStaticList().empty())
|
||||
<< "Self-registration has failed, or no statics declared";
|
||||
|
||||
// Spawn a new copy.
|
||||
TorqueThreadStaticListHandle testInstance = _TorqueThreadStaticReg::spawnThreadStaticsInstance();
|
||||
|
||||
// Test the copy
|
||||
ASSERT_EQ(_TorqueThreadStaticReg::getStaticList(0).size(), testInstance->size())
|
||||
<< "Spawned static list has a different size from master copy.";
|
||||
|
||||
// Traverse the list and compare it to the initial value copy (index 0)
|
||||
for(S32 i = 0; i < _TorqueThreadStaticReg::getStaticList().size(); i++)
|
||||
{
|
||||
_TorqueThreadStatic *master = _TorqueThreadStaticReg::getStaticList()[i];
|
||||
_TorqueThreadStatic *cpy = (*testInstance)[i];
|
||||
|
||||
// Make sure it is not the same memory
|
||||
EXPECT_NE(master, cpy)
|
||||
<< "Copy not spawned properly.";
|
||||
|
||||
// Make sure the sizes are the same
|
||||
ASSERT_EQ(master->getMemInstSize(), cpy->getMemInstSize())
|
||||
<< "Size mismatch between master and copy";
|
||||
|
||||
// Make sure the initialization occurred properly
|
||||
EXPECT_EQ(0, dMemcmp(master->getMemInstPtr(), cpy->getMemInstPtr(), master->getMemInstSize()))
|
||||
<< "Initial value for spawned list is not correct";
|
||||
}
|
||||
|
||||
// Test metrics if enabled
|
||||
#ifdef TORQUE_ENABLE_THREAD_STATIC_METRICS
|
||||
U32 fooHitCount = (*testInstance)[_gUnitTestFooTorqueThreadStatic::getListIndex()]->getHitCount();
|
||||
#endif
|
||||
|
||||
// Set/get some values (If we test static metrics, this is hit 1)
|
||||
ATTS_(gUnitTestFoo, 1) = 55;
|
||||
|
||||
// Test to see that the master copy and the spawned copy differ
|
||||
// (If we test metrics, this is hit 2, for the instance, and hit 1 for the master)
|
||||
EXPECT_NE(ATTS_(gUnitTestFoo, 0), ATTS_(gUnitTestFoo, 1))
|
||||
<< "Assignment for spawned instanced memory failed";
|
||||
|
||||
#ifdef TORQUE_ENABLE_THREAD_STATIC_METRICS
|
||||
U32 fooHitCount2 = (*testInstance)[_gUnitTestFooTorqueThreadStatic::getListIndex()]->getHitCount();
|
||||
EXPECT_EQ(fooHitCount2, (fooHitCount + 2))
|
||||
<< "Thread static metric hit count failed";
|
||||
#endif
|
||||
|
||||
// Destroy instances
|
||||
_TorqueThreadStaticReg::destroyInstance(testInstance);
|
||||
}
|
||||
|
||||
#ifdef TORQUE_ENABLE_PROFILER
|
||||
#include "math/mRandom.h"
|
||||
#include "platform/profiler.h"
|
||||
|
||||
// Declare a test thread static
|
||||
DITTS(U32, gInstancedStaticFoo, 42);
|
||||
static U32 gTrueStaticFoo = 42;
|
||||
|
||||
TEST(ThreadStatic, StressThreadStatic)
|
||||
{
|
||||
ASSERT_FALSE(gProfiler->isEnabled())
|
||||
<< "Profiler is currently enabled, test cannot continue";
|
||||
|
||||
// Spawn an instance
|
||||
TorqueThreadStaticListHandle testInstance = _TorqueThreadStaticReg::spawnThreadStaticsInstance();
|
||||
|
||||
static const dsize_t TEST_SIZE = 100000;
|
||||
|
||||
// What we are going to do in this test is to test some U32 static
|
||||
// performance. The test will be run TEST_SIZE times, and so first create
|
||||
// an array of values to standardize the tests on.
|
||||
U32 testValue[TEST_SIZE];
|
||||
|
||||
for(S32 i = 0; i < TEST_SIZE; i++)
|
||||
testValue[i] = gRandGen.randI();
|
||||
|
||||
// Reset the profiler, tell it to dump to console when done
|
||||
gProfiler->dumpToConsole();
|
||||
gProfiler->enable(true);
|
||||
|
||||
// Value array is initialized, so lets put the foo's through the paces
|
||||
PROFILE_START(ThreadStaticPerf_TrueStaticAssign);
|
||||
for(int i = 0; i < TEST_SIZE; i++)
|
||||
gTrueStaticFoo = testValue[i];
|
||||
PROFILE_END();
|
||||
|
||||
PROFILE_START(ThreadStaticPerf_InstanceStaticAssign);
|
||||
for(S32 i = 0; i < TEST_SIZE; i++)
|
||||
ATTS_(gInstancedStaticFoo, 1) = testValue[i];
|
||||
PROFILE_END();
|
||||
|
||||
gProfiler->enable(false);
|
||||
|
||||
// Clean up instance
|
||||
_TorqueThreadStaticReg::destroyInstance(testInstance);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
70
Engine/source/platform/threads/test/mutexTest.cpp
Normal file
70
Engine/source/platform/threads/test/mutexTest.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/threads/mutex.h"
|
||||
#include "platform/threads/thread.h"
|
||||
|
||||
TEST(Mutex, BasicSynchronization)
|
||||
{
|
||||
// We test various scenarios wrt to locking and unlocking, in a single
|
||||
// thread, just to make sure our basic primitives are working in the
|
||||
// most basic case.
|
||||
void *mutex1 = Mutex::createMutex();
|
||||
EXPECT_TRUE(mutex1 != NULL)
|
||||
<< "First Mutex::createMutex call failed - that's pretty bad!";
|
||||
|
||||
// This mutex is intentionally unused.
|
||||
void *mutex2 = Mutex::createMutex();
|
||||
EXPECT_TRUE(mutex2 != NULL)
|
||||
<< "Second Mutex::createMutex call failed - that's pretty bad, too!";
|
||||
|
||||
EXPECT_TRUE(Mutex::lockMutex(mutex1, false))
|
||||
<< "Nonblocking call to brand new mutex failed - should not be.";
|
||||
EXPECT_TRUE(Mutex::lockMutex(mutex1, true))
|
||||
<< "Failed relocking a mutex from the same thread - should be able to do this.";
|
||||
|
||||
// Try to acquire the mutex from another thread.
|
||||
struct thread
|
||||
{
|
||||
static void body(void* mutex)
|
||||
{
|
||||
// We should not be able to lock the mutex from a separate thread, but
|
||||
// we don't want to block either.
|
||||
EXPECT_FALSE(Mutex::lockMutex(mutex, false));
|
||||
}
|
||||
};
|
||||
Thread thread(&thread::body, mutex1);
|
||||
thread.start();
|
||||
thread.join();
|
||||
|
||||
// Unlock & kill mutex 1
|
||||
Mutex::unlockMutex(mutex1);
|
||||
Mutex::unlockMutex(mutex1);
|
||||
Mutex::destroyMutex(mutex1);
|
||||
|
||||
// Kill mutex2, which was never touched.
|
||||
Mutex::destroyMutex(mutex2);
|
||||
}
|
||||
|
||||
#endif
|
||||
90
Engine/source/platform/threads/test/semaphoreTest.cpp
Normal file
90
Engine/source/platform/threads/test/semaphoreTest.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/threads/semaphore.h"
|
||||
#include "platform/threads/thread.h"
|
||||
|
||||
TEST(Semaphore, BasicSynchronization)
|
||||
{
|
||||
Semaphore *sem1 = new Semaphore(1);
|
||||
Semaphore *sem2 = new Semaphore(1);
|
||||
|
||||
// Test that we can do non-blocking acquires that succeed.
|
||||
EXPECT_TRUE(sem1->acquire(false))
|
||||
<< "Should succeed at acquiring a new semaphore with count 1.";
|
||||
EXPECT_TRUE(sem2->acquire(false))
|
||||
<< "This one should succeed too, see previous test.";
|
||||
|
||||
// Test that we can do non-blocking acquires that fail.
|
||||
EXPECT_FALSE(sem1->acquire(false))
|
||||
<< "Should failed, as we've already got the sem.";
|
||||
sem1->release();
|
||||
EXPECT_FALSE(sem2->acquire(false))
|
||||
<< "Should also fail.";
|
||||
sem2->release();
|
||||
|
||||
// Test that we can do blocking acquires that succeed.
|
||||
EXPECT_TRUE(sem1->acquire(true))
|
||||
<< "Should succeed as we just released.";
|
||||
EXPECT_TRUE(sem2->acquire(true))
|
||||
<< "Should succeed as we just released.";
|
||||
|
||||
// Clean up.
|
||||
delete sem1;
|
||||
delete sem2;
|
||||
}
|
||||
|
||||
TEST(Semaphore, MultiThreadSynchronization)
|
||||
{
|
||||
Semaphore semaphore(1);
|
||||
|
||||
struct thread
|
||||
{
|
||||
// Try to acquire the semaphore from another thread.
|
||||
static void body1(void* sem)
|
||||
{
|
||||
Semaphore *semaphore = reinterpret_cast<Semaphore*>(sem);
|
||||
EXPECT_TRUE(semaphore->acquire(true));
|
||||
// Note that this semaphore is never released. Bad programmer!
|
||||
}
|
||||
// One more acquisition should fail!
|
||||
static void body2(void* sem)
|
||||
{
|
||||
Semaphore *semaphore = reinterpret_cast<Semaphore*>(sem);
|
||||
EXPECT_FALSE(semaphore->acquire(false));
|
||||
}
|
||||
};
|
||||
|
||||
Thread thread1(&thread::body1, &semaphore);
|
||||
EXPECT_TRUE(semaphore.acquire(true));
|
||||
thread1.start();
|
||||
semaphore.release();
|
||||
thread1.join();
|
||||
|
||||
Thread thread2(&thread::body2, &semaphore);
|
||||
thread2.start();
|
||||
thread2.join();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -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,66 +20,56 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#ifdef TORQUE_TESTS_ENABLED
|
||||
#include "testing/unitTesting.h"
|
||||
#include "platform/threads/threadPool.h"
|
||||
#include "console/console.h"
|
||||
#include "core/util/tVector.h"
|
||||
|
||||
#ifndef TORQUE_SHIPPING
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
#define TEST( x ) test( ( x ), "FAIL: " #x )
|
||||
|
||||
// Simple test that creates and verifies an array of numbers using
|
||||
// thread pool work items.
|
||||
|
||||
CreateUnitTest( TestThreadPool, "Platform/ThreadPool/Simple" )
|
||||
FIXTURE(ThreadPool)
|
||||
{
|
||||
enum { DEFAULT_NUM_ITEMS = 4000 };
|
||||
|
||||
static Vector< U32 > results;
|
||||
|
||||
public:
|
||||
// Represents a single unit of work. In this test we just set an element in
|
||||
// a result vector.
|
||||
struct TestItem : public ThreadPool::WorkItem
|
||||
{
|
||||
typedef ThreadPool::WorkItem Parent;
|
||||
|
||||
U32 mIndex;
|
||||
|
||||
TestItem( U32 index )
|
||||
: mIndex( index ) {}
|
||||
|
||||
protected:
|
||||
virtual void execute()
|
||||
{
|
||||
results[ mIndex ] = mIndex;
|
||||
}
|
||||
};
|
||||
|
||||
void run()
|
||||
{
|
||||
U32 numItems = Con::getIntVariable( "$testThreadPool::numValues", DEFAULT_NUM_ITEMS );
|
||||
ThreadPool* pool = &ThreadPool::GLOBAL();
|
||||
results.setSize( numItems );
|
||||
U32 mIndex;
|
||||
Vector<U32>& mResults;
|
||||
TestItem(U32 index, Vector<U32>& results)
|
||||
: mIndex(index), mResults(results) {}
|
||||
|
||||
for( U32 i = 0; i < numItems; ++ i )
|
||||
results[ i ] = U32( -1 );
|
||||
|
||||
for( U32 i = 0; i < numItems; ++ i )
|
||||
protected:
|
||||
virtual void execute()
|
||||
{
|
||||
ThreadSafeRef< TestItem > item( new TestItem( i ) );
|
||||
pool->queueWorkItem( item );
|
||||
mResults[mIndex] = mIndex;
|
||||
}
|
||||
|
||||
pool->flushWorkItems();
|
||||
|
||||
for( U32 i = 0; i < numItems; ++ i )
|
||||
test( results[ i ] == i, "result mismatch" );
|
||||
|
||||
results.clear();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Vector< U32 > TestThreadPool::results( __FILE__, __LINE__ );
|
||||
TEST_FIX(ThreadPool, BasicAPI)
|
||||
{
|
||||
// Construct the vector of results from the work items.
|
||||
const U32 numItems = 100;
|
||||
Vector<U32> results(__FILE__, __LINE__);
|
||||
results.setSize(numItems);
|
||||
for (U32 i = 0; i < numItems; i++)
|
||||
results[i] = U32(-1);
|
||||
|
||||
#endif // !TORQUE_SHIPPING
|
||||
// Launch the work items.
|
||||
ThreadPool* pool = &ThreadPool::GLOBAL();
|
||||
for (U32 i = 0; i < numItems; i++)
|
||||
{
|
||||
ThreadSafeRef<TestItem> item(new TestItem(i, results));
|
||||
pool->queueWorkItem(item);
|
||||
}
|
||||
|
||||
// Wait for all items to complete.
|
||||
pool->flushWorkItems();
|
||||
|
||||
// Verify.
|
||||
for (U32 i = 0; i < numItems; i++)
|
||||
EXPECT_EQ(results[i], i) << "result mismatch";
|
||||
results.clear();
|
||||
}
|
||||
|
||||
#endif
|
||||
186
Engine/source/platform/threads/test/threadSafeDequeTest.cpp
Normal file
186
Engine/source/platform/threads/test/threadSafeDequeTest.cpp
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/threads/threadSafeDeque.h"
|
||||
#include "platform/threads/thread.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "console/console.h"
|
||||
|
||||
FIXTURE(ThreadSafeDeque)
|
||||
{
|
||||
public:
|
||||
// Used by the concurrent test.
|
||||
struct Value : public ThreadSafeRefCount<Value>
|
||||
{
|
||||
U32 mIndex;
|
||||
U32 mTick;
|
||||
|
||||
Value() {}
|
||||
Value(U32 index, U32 tick)
|
||||
: mIndex(index), mTick(tick) {}
|
||||
};
|
||||
|
||||
typedef ThreadSafeRef<Value> ValueRef;
|
||||
|
||||
struct Deque : public ThreadSafeDeque<ValueRef>
|
||||
{
|
||||
typedef ThreadSafeDeque<ValueRef> Parent;
|
||||
|
||||
U32 mPushIndex;
|
||||
U32 mPopIndex;
|
||||
|
||||
Deque()
|
||||
: mPushIndex(0), mPopIndex(0) {}
|
||||
|
||||
void pushBack(const ValueRef& value)
|
||||
{
|
||||
EXPECT_EQ(value->mIndex, mPushIndex) << "index out of line";
|
||||
mPushIndex++;
|
||||
Parent::pushBack(value);
|
||||
}
|
||||
|
||||
bool tryPopFront(ValueRef& outValue)
|
||||
{
|
||||
if(Parent::tryPopFront(outValue))
|
||||
{
|
||||
EXPECT_EQ(outValue->mIndex, mPopIndex) << "index out of line";
|
||||
mPopIndex++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct ProducerThread : public Thread
|
||||
{
|
||||
Vector<U32>& mValues;
|
||||
Deque& mDeque;
|
||||
ProducerThread(Vector<U32>& values, Deque& deque)
|
||||
: mValues(values), mDeque(deque) {}
|
||||
|
||||
virtual void run(void*)
|
||||
{
|
||||
for(U32 i = 0; i < mValues.size(); i++)
|
||||
{
|
||||
U32 tick = Platform::getRealMilliseconds();
|
||||
mValues[i] = tick;
|
||||
|
||||
ValueRef val = new Value(i, tick);
|
||||
mDeque.pushBack(val);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ConsumerThread : public Thread
|
||||
{
|
||||
Vector<U32>& mValues;
|
||||
Deque& mDeque;
|
||||
ConsumerThread(Vector<U32>& values, Deque& deque)
|
||||
: mValues(values), mDeque(deque) {}
|
||||
|
||||
virtual void run(void*)
|
||||
{
|
||||
for(U32 i = 0; i < mValues.size(); i++)
|
||||
{
|
||||
ValueRef value;
|
||||
while(!mDeque.tryPopFront(value));
|
||||
|
||||
EXPECT_EQ(i, value->mIndex);
|
||||
EXPECT_EQ(value->mTick, mValues[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Test deque without concurrency.
|
||||
TEST_FIX(ThreadSafeDeque, PopFront)
|
||||
{
|
||||
ThreadSafeDeque<char> deque;
|
||||
String str = "teststring";
|
||||
|
||||
for(U32 i = 0; i < str.length(); i++)
|
||||
deque.pushBack(str[i]);
|
||||
|
||||
EXPECT_FALSE(deque.isEmpty());
|
||||
|
||||
char ch;
|
||||
for(U32 i = 0; i < str.length(); i++)
|
||||
{
|
||||
EXPECT_TRUE(deque.tryPopFront(ch));
|
||||
EXPECT_EQ(str[i], ch);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(deque.isEmpty());
|
||||
}
|
||||
|
||||
TEST_FIX(ThreadSafeDeque, PopBack)
|
||||
{
|
||||
ThreadSafeDeque<char> deque;
|
||||
String str = "teststring";
|
||||
|
||||
const char* p1 = str.c_str() + 4;
|
||||
const char* p2 = p1 + 1;
|
||||
while(*p2)
|
||||
{
|
||||
deque.pushFront(*p1);
|
||||
deque.pushBack(*p2);
|
||||
--p1;
|
||||
++p2;
|
||||
}
|
||||
|
||||
char ch;
|
||||
for(S32 i = str.length()-1; i >= 0; i--)
|
||||
{
|
||||
EXPECT_TRUE(deque.tryPopBack(ch));
|
||||
EXPECT_EQ(str[i], ch);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(deque.isEmpty());
|
||||
}
|
||||
|
||||
// Test deque in a concurrent setting.
|
||||
TEST_FIX(ThreadSafeDeque, Concurrent1)
|
||||
{
|
||||
const U32 NumValues = 100;
|
||||
|
||||
Deque mDeque;
|
||||
Vector<U32> mValues;
|
||||
|
||||
mValues.setSize(NumValues);
|
||||
|
||||
ProducerThread pThread(mValues, mDeque);
|
||||
ConsumerThread cThread(mValues, mDeque);
|
||||
|
||||
pThread.start();
|
||||
cThread.start();
|
||||
|
||||
pThread.join();
|
||||
cThread.join();
|
||||
|
||||
mValues.clear();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/threads/threadSafePriorityQueue.h"
|
||||
#include "platform/threads/thread.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "console/console.h"
|
||||
|
||||
// Test queue without concurrency.
|
||||
TEST(ThreadSafePriorityQueue, Serial)
|
||||
{
|
||||
const U32 min = 0;
|
||||
const U32 max = 9;
|
||||
const U32 len = 11;
|
||||
|
||||
U32 indices[len] = { 2, 7, 4, 6, 1, 5, 3, 8, 6, 9, 0};
|
||||
F32 priorities[len] = {0.2, 0.7, 0.4, 0.6, 0.1, 0.5, 0.3, 0.8, 0.6, 0.9, 0};
|
||||
|
||||
ThreadSafePriorityQueue<U32, F32, true> minQueue;
|
||||
ThreadSafePriorityQueue<U32, F32, false> maxQueue;
|
||||
|
||||
for(U32 i = 0; i < len; i++)
|
||||
{
|
||||
minQueue.insert(priorities[i], indices[i]);
|
||||
maxQueue.insert(priorities[i], indices[i]);
|
||||
}
|
||||
|
||||
EXPECT_FALSE(minQueue.isEmpty());
|
||||
EXPECT_FALSE(maxQueue.isEmpty());
|
||||
|
||||
U32 index = min;
|
||||
for(U32 i = 0; i < len; i++)
|
||||
{
|
||||
U32 popped;
|
||||
EXPECT_TRUE(minQueue.takeNext(popped))
|
||||
<< "Failed to pop element from minQueue";
|
||||
EXPECT_LE(index, popped)
|
||||
<< "Element from minQueue was not in sort order";
|
||||
index = popped;
|
||||
}
|
||||
|
||||
index = max;
|
||||
for(U32 i = 0; i < len; i++)
|
||||
{
|
||||
U32 popped;
|
||||
EXPECT_TRUE(maxQueue.takeNext(popped))
|
||||
<< "Failed to pop element from maxQueue";
|
||||
EXPECT_GE(index, popped)
|
||||
<< "Element from maxQueue was not in sort order";
|
||||
index = popped;
|
||||
}
|
||||
}
|
||||
|
||||
// Test queue with concurrency.
|
||||
TEST(ThreadSafePriorityQueue, Concurrent)
|
||||
{
|
||||
#define MIN 0
|
||||
#define MAX 9
|
||||
#define LEN 11
|
||||
|
||||
typedef ThreadSafePriorityQueue<U32, F32, true> MinQueue;
|
||||
typedef ThreadSafePriorityQueue<U32, F32, false> MaxQueue;
|
||||
|
||||
struct ProducerThread : public Thread
|
||||
{
|
||||
MinQueue& minQueue;
|
||||
MaxQueue& maxQueue;
|
||||
ProducerThread(MinQueue& min, MaxQueue& max)
|
||||
: minQueue(min), maxQueue(max) {}
|
||||
|
||||
virtual void run(void*)
|
||||
{
|
||||
U32 indices[LEN] = { 2, 7, 4, 6, 1, 5, 3, 8, 6, 9, 0};
|
||||
F32 priorities[LEN] = {0.2, 0.7, 0.4, 0.6, 0.1, 0.5, 0.3, 0.8, 0.6, 0.9, 0};
|
||||
|
||||
for(U32 i = 0; i < LEN; i++)
|
||||
{
|
||||
minQueue.insert(priorities[i], indices[i]);
|
||||
maxQueue.insert(priorities[i], indices[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MinQueue minQueue;
|
||||
MaxQueue maxQueue;
|
||||
ProducerThread producers[] = {
|
||||
ProducerThread(minQueue, maxQueue),
|
||||
ProducerThread(minQueue, maxQueue),
|
||||
ProducerThread(minQueue, maxQueue)
|
||||
};
|
||||
|
||||
const U32 len = sizeof(producers) / sizeof(ProducerThread);
|
||||
for(U32 i = 0; i < len; i++)
|
||||
producers[i].start();
|
||||
for(U32 i = 0; i < len; i++)
|
||||
producers[i].join();
|
||||
|
||||
U32 index = MIN;
|
||||
for(U32 i = 0; i < LEN * len; i++)
|
||||
{
|
||||
U32 popped;
|
||||
EXPECT_TRUE(minQueue.takeNext(popped))
|
||||
<< "Failed to pop element from minQueue";
|
||||
EXPECT_LE(index, popped)
|
||||
<< "Element from minQueue was not in sort order";
|
||||
index = popped;
|
||||
}
|
||||
|
||||
index = MAX;
|
||||
for(U32 i = 0; i < LEN * len; i++)
|
||||
{
|
||||
U32 popped;
|
||||
EXPECT_TRUE(maxQueue.takeNext(popped))
|
||||
<< "Failed to pop element from maxQueue";
|
||||
EXPECT_GE(index, popped)
|
||||
<< "Element from maxQueue was not in sort order";
|
||||
index = popped;
|
||||
}
|
||||
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
#undef LEN
|
||||
}
|
||||
|
||||
#endif
|
||||
205
Engine/source/platform/threads/test/threadSafeRefCountTest.cpp
Normal file
205
Engine/source/platform/threads/test/threadSafeRefCountTest.cpp
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/threads/threadSafeRefCount.h"
|
||||
#include "platform/threads/thread.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "console/console.h"
|
||||
|
||||
FIXTURE(ThreadSafeRefCount)
|
||||
{
|
||||
public:
|
||||
struct TestObjectDtor : public ThreadSafeRefCount<TestObjectDtor>
|
||||
{
|
||||
bool &flag;
|
||||
TestObjectDtor(bool &f) : flag(f)
|
||||
{
|
||||
flag = false;
|
||||
}
|
||||
~TestObjectDtor()
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
};
|
||||
typedef ThreadSafeRef<TestObjectDtor> TestObjectDtorRef;
|
||||
|
||||
enum
|
||||
{
|
||||
NUM_ADD_REFS_PER_THREAD = 10,
|
||||
NUM_EXTRA_REFS_PER_THREAD = 10,
|
||||
NUM_THREADS = 10
|
||||
};
|
||||
|
||||
class TestObject : public ThreadSafeRefCount<TestObject> {};
|
||||
typedef ThreadSafeRef<TestObject> TestObjectRef;
|
||||
|
||||
class TestThread : public Thread
|
||||
{
|
||||
public:
|
||||
TestObjectRef mRef;
|
||||
Vector<TestObjectRef> mExtraRefs;
|
||||
|
||||
TestThread(TestObjectRef ref) : mRef(ref) {}
|
||||
|
||||
void run(void* arg)
|
||||
{
|
||||
if (!arg)
|
||||
{
|
||||
// Create references.
|
||||
for (U32 i = 0; i < NUM_ADD_REFS_PER_THREAD; i++)
|
||||
mRef->addRef();
|
||||
|
||||
mExtraRefs.setSize(NUM_EXTRA_REFS_PER_THREAD);
|
||||
for (U32 i = 0; i < NUM_EXTRA_REFS_PER_THREAD; i++)
|
||||
mExtraRefs[i] = mRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear references.
|
||||
mExtraRefs.clear();
|
||||
for (U32 i = 0; i < NUM_ADD_REFS_PER_THREAD; i++)
|
||||
mRef->release();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
TEST_FIX(ThreadSafeRefCount, Serial)
|
||||
{
|
||||
bool deleted = false;
|
||||
TestObjectDtorRef ref1 = new TestObjectDtor(deleted);
|
||||
ASSERT_FALSE(deleted);
|
||||
EXPECT_FALSE(ref1->isShared());
|
||||
EXPECT_TRUE(ref1 != NULL);
|
||||
|
||||
TestObjectDtorRef ref2 = ref1;
|
||||
EXPECT_TRUE(ref1->isShared());
|
||||
EXPECT_TRUE(ref2->isShared());
|
||||
EXPECT_EQ(ref1, ref2);
|
||||
|
||||
ref1 = NULL;
|
||||
EXPECT_FALSE(ref2->isShared());
|
||||
|
||||
ref2 = NULL;
|
||||
ASSERT_TRUE(deleted);
|
||||
}
|
||||
|
||||
TEST_FIX(ThreadSafeRefCount, Concurrent)
|
||||
{
|
||||
TestObjectRef mRef = new TestObject;
|
||||
EXPECT_EQ(2, mRef->getRefCount()); // increments of 2
|
||||
|
||||
Vector<TestThread*> threads;
|
||||
threads.setSize(NUM_THREADS);
|
||||
|
||||
// Create threads.
|
||||
for (U32 i = 0; i < NUM_THREADS; i++)
|
||||
threads[i] = new TestThread(mRef);
|
||||
|
||||
// Run phase 1: create references.
|
||||
for (U32 i = 0; i < NUM_THREADS; i++)
|
||||
threads[i]->start(NULL);
|
||||
|
||||
// Wait for completion.
|
||||
for (U32 i = 0; i < NUM_THREADS; i++)
|
||||
threads[i]->join();
|
||||
|
||||
EXPECT_EQ(2 + ((1 + NUM_ADD_REFS_PER_THREAD + NUM_EXTRA_REFS_PER_THREAD) * NUM_THREADS * 2),
|
||||
mRef->getRefCount());
|
||||
|
||||
// Run phase 2: release references.
|
||||
for (U32 i = 0; i < NUM_THREADS; i++)
|
||||
threads[i]->start((void*) 1);
|
||||
|
||||
// Wait for completion.
|
||||
for (U32 i = 0; i < NUM_THREADS; i++)
|
||||
{
|
||||
threads[i]->join();
|
||||
delete threads[i];
|
||||
}
|
||||
|
||||
EXPECT_EQ(2, mRef->getRefCount()); // increments of two
|
||||
|
||||
mRef = NULL;
|
||||
}
|
||||
|
||||
TEST_FIX(ThreadSafeRefCount, Tagging)
|
||||
{
|
||||
TestObjectRef ref;
|
||||
EXPECT_FALSE(ref.isTagged());
|
||||
EXPECT_FALSE(bool(ref));
|
||||
EXPECT_FALSE(bool(ref.ptr()));
|
||||
|
||||
EXPECT_TRUE(ref.trySetFromTo(ref, NULL));
|
||||
EXPECT_FALSE(ref.isTagged());
|
||||
|
||||
EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Set));
|
||||
EXPECT_TRUE(ref.isTagged());
|
||||
EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Set));
|
||||
EXPECT_TRUE(ref.isTagged());
|
||||
|
||||
EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Unset));
|
||||
EXPECT_FALSE(ref.isTagged());
|
||||
EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_Unset));
|
||||
EXPECT_FALSE(ref.isTagged());
|
||||
|
||||
EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_SetOrFail));
|
||||
EXPECT_TRUE(ref.isTagged());
|
||||
EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_SetOrFail));
|
||||
EXPECT_TRUE(ref.isTagged());
|
||||
EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_FailIfSet));
|
||||
|
||||
EXPECT_TRUE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_UnsetOrFail));
|
||||
EXPECT_FALSE(ref.isTagged());
|
||||
EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_UnsetOrFail));
|
||||
EXPECT_FALSE(ref.isTagged());
|
||||
EXPECT_FALSE(ref.trySetFromTo(ref, NULL, TestObjectRef::TAG_FailIfUnset));
|
||||
|
||||
TestObjectRef objectA = new TestObject;
|
||||
TestObjectRef objectB = new TestObject;
|
||||
|
||||
EXPECT_FALSE(objectA->isShared());
|
||||
EXPECT_FALSE(objectB->isShared());
|
||||
|
||||
ref = objectA;
|
||||
EXPECT_FALSE(ref.isTagged());
|
||||
EXPECT_TRUE(ref == objectA);
|
||||
EXPECT_TRUE(ref == objectA.ptr());
|
||||
EXPECT_TRUE(objectA->isShared());
|
||||
|
||||
EXPECT_TRUE(ref.trySetFromTo(objectA, objectB, TestObjectRef::TAG_Set));
|
||||
EXPECT_TRUE(ref.isTagged());
|
||||
EXPECT_EQ(ref, objectB);
|
||||
EXPECT_EQ(ref, objectB.ptr());
|
||||
EXPECT_TRUE(objectB->isShared());
|
||||
EXPECT_FALSE(objectA->isShared());
|
||||
|
||||
EXPECT_TRUE(ref.trySetFromTo(ref, objectA));
|
||||
EXPECT_TRUE(ref.isTagged());
|
||||
EXPECT_EQ(ref, objectA);
|
||||
EXPECT_EQ(ref, objectA.ptr());
|
||||
}
|
||||
|
||||
#endif
|
||||
87
Engine/source/platform/threads/test/threadTest.cpp
Normal file
87
Engine/source/platform/threads/test/threadTest.cpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/threads/thread.h"
|
||||
|
||||
TEST(Thread, CallbackAPI)
|
||||
{
|
||||
#define VALUE_TO_SET 10
|
||||
|
||||
// This struct exists just so we can define run as a local function.
|
||||
struct thread
|
||||
{
|
||||
// Do some work we can observe.
|
||||
static void body(void* arg)
|
||||
{
|
||||
U32* value = reinterpret_cast<U32*>(arg);
|
||||
*value = VALUE_TO_SET;
|
||||
}
|
||||
};
|
||||
|
||||
// Test most basic Thread API functions.
|
||||
U32 value = ~VALUE_TO_SET;
|
||||
Thread thread(&thread::body, reinterpret_cast<void*>(&value));
|
||||
thread.start();
|
||||
EXPECT_TRUE(thread.isAlive());
|
||||
thread.join();
|
||||
EXPECT_FALSE(thread.isAlive());
|
||||
|
||||
EXPECT_EQ(value, VALUE_TO_SET)
|
||||
<< "Thread did not set expected value!";
|
||||
|
||||
#undef VALUE_TO_SET
|
||||
}
|
||||
|
||||
TEST(Thread, InheritanceAPI)
|
||||
{
|
||||
#define VALUE_TO_SET 10
|
||||
|
||||
// This struct exists just so we can define run as a local function.
|
||||
struct thread : public Thread
|
||||
{
|
||||
U32* mPtr;
|
||||
thread(U32* ptr): mPtr(ptr) {}
|
||||
|
||||
// Do some work we can observe.
|
||||
virtual void run(void*)
|
||||
{
|
||||
*mPtr = VALUE_TO_SET;
|
||||
}
|
||||
};
|
||||
|
||||
// Test most basic Thread API functions.
|
||||
U32 value = ~VALUE_TO_SET;
|
||||
thread thread(&value);
|
||||
thread.start();
|
||||
EXPECT_TRUE(thread.isAlive());
|
||||
thread.join();
|
||||
EXPECT_FALSE(thread.isAlive());
|
||||
|
||||
EXPECT_EQ(value, VALUE_TO_SET)
|
||||
<< "Thread did not set expected value!";
|
||||
|
||||
#undef VALUE_TO_SET
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -311,18 +311,10 @@ S32 main(S32 argc, const char **argv)
|
|||
|
||||
//--------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "app/mainLoop.h"
|
||||
|
||||
S32 PASCAL WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, S32)
|
||||
{
|
||||
#if 0
|
||||
// Run a unit test.
|
||||
StandardMainLoop::initCore();
|
||||
UnitTesting::TestRun tr;
|
||||
tr.test("Platform", true);
|
||||
#else
|
||||
|
||||
Vector<char *> argv( __FILE__, __LINE__ );
|
||||
|
||||
char moduleName[256];
|
||||
|
|
@ -366,7 +358,6 @@ S32 PASCAL WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR lpszCmdLine, S32)
|
|||
dFree(argv[j]);
|
||||
|
||||
return retVal;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else //TORQUE_SHARED
|
||||
|
|
|
|||
|
|
@ -36,8 +36,9 @@ class TorqueUnitTestListener : public ::testing::EmptyTestEventListener
|
|||
// Called before a test starts.
|
||||
virtual void OnTestStart( const ::testing::TestInfo& testInfo )
|
||||
{
|
||||
Con::printf("> Starting Test '%s.%s'",
|
||||
testInfo.test_case_name(), testInfo.name());
|
||||
if( mVerbose )
|
||||
Con::printf("> Starting Test '%s.%s'",
|
||||
testInfo.test_case_name(), testInfo.name());
|
||||
}
|
||||
|
||||
// Called after a failed assertion or a SUCCEED() invocation.
|
||||
|
|
@ -45,13 +46,13 @@ class TorqueUnitTestListener : public ::testing::EmptyTestEventListener
|
|||
{
|
||||
if ( testPartResult.failed() )
|
||||
{
|
||||
Con::warnf(">> Failed with '%s' in '%s' at (line:%d)",
|
||||
Con::warnf(">> Failed with '%s' in '%s' at (line:%d)\n",
|
||||
testPartResult.summary(),
|
||||
testPartResult.file_name(),
|
||||
testPartResult.line_number()
|
||||
);
|
||||
}
|
||||
else
|
||||
else if( mVerbose )
|
||||
{
|
||||
Con::printf(">> Passed with '%s' in '%s' at (line:%d)",
|
||||
testPartResult.summary(),
|
||||
|
|
@ -64,17 +65,43 @@ class TorqueUnitTestListener : public ::testing::EmptyTestEventListener
|
|||
// Called after a test ends.
|
||||
virtual void OnTestEnd( const ::testing::TestInfo& testInfo )
|
||||
{
|
||||
Con::printf("> Ending Test '%s.%s'\n",
|
||||
testInfo.test_case_name(), testInfo.name());
|
||||
if( mVerbose )
|
||||
Con::printf("> Ending Test '%s.%s'\n",
|
||||
testInfo.test_case_name(), testInfo.name());
|
||||
}
|
||||
|
||||
bool mVerbose;
|
||||
|
||||
public:
|
||||
TorqueUnitTestListener( bool verbose ) : mVerbose( verbose ) {}
|
||||
};
|
||||
|
||||
DefineConsoleFunction( runAllUnitTests, int, (),,
|
||||
"" )
|
||||
DefineConsoleFunction( runAllUnitTests, int, (const char* testSpecs), (""),
|
||||
"Runs engine unit tests. Some tests are marked as 'stress' tests which do not "
|
||||
"necessarily check correctness, just performance or possible nondeterministic "
|
||||
"glitches. There may also be interactive or networking tests which may be "
|
||||
"excluded by using the testSpecs argument.\n"
|
||||
"This function should only be called once per executable run, because of "
|
||||
"googletest's design.\n\n"
|
||||
|
||||
"@param testSpecs A space-sepatated list of filters for test cases. "
|
||||
"See https://code.google.com/p/googletest/wiki/AdvancedGuide#Running_a_Subset_of_the_Tests "
|
||||
"and http://stackoverflow.com/a/14021997/945863 "
|
||||
"for a description of the flag format.")
|
||||
{
|
||||
// Set-up some empty arguments.
|
||||
S32 testArgc = 0;
|
||||
char** testArgv = NULL;
|
||||
if ( dStrlen( testSpecs ) > 0 )
|
||||
{
|
||||
String specs(testSpecs);
|
||||
specs.replace(' ', ':');
|
||||
specs.insert(0, "--gtest_filter=");
|
||||
testArgc = 2;
|
||||
testArgv = new char*[2];
|
||||
testArgv[0] = NULL; // Program name is unused by googletest.
|
||||
testArgv[1] = new char[specs.length()+1];
|
||||
dStrcpy(testArgv[1], specs);
|
||||
}
|
||||
|
||||
// Initialize Google Test.
|
||||
testing::InitGoogleTest( &testArgc, testArgv );
|
||||
|
|
@ -88,19 +115,18 @@ DefineConsoleFunction( runAllUnitTests, int, (),,
|
|||
// Release the default listener.
|
||||
delete listeners.Release( listeners.default_result_printer() );
|
||||
|
||||
if ( Con::getBoolVariable( "$testing::checkMemoryLeaks", false ) ) {
|
||||
if ( Con::getBoolVariable( "$Testing::CheckMemoryLeaks", false ) ) {
|
||||
// Add the memory leak tester.
|
||||
listeners.Append( new testing::MemoryLeakDetector );
|
||||
}
|
||||
|
||||
// Add the Torque unit test listener.
|
||||
listeners.Append( new TorqueUnitTestListener );
|
||||
listeners.Append( new TorqueUnitTestListener(false) );
|
||||
|
||||
// Perform googletest run.
|
||||
Con::printf( "\nUnit Tests Starting...\n" );
|
||||
|
||||
const S32 result = RUN_ALL_TESTS();
|
||||
|
||||
Con::printf( "\n... Unit Tests Ended.\n" );
|
||||
Con::printf( "... Unit Tests Ended.\n" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,17 +27,17 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
/// Convenience to define a test fixture with a Fixture suffix for use with
|
||||
/// TEST_FIX.
|
||||
#define FIXTURE(test_fixture)\
|
||||
class test_fixture##Fixture : public ::testing::Test
|
||||
|
||||
/// Allow test fixtures named with a Fixture suffix, so that we can name tests
|
||||
/// after a class name rather than having to call them XXTest.
|
||||
#define TEST_FIX(test_fixture, test_name)\
|
||||
GTEST_TEST_(test_fixture, test_name, test_fixture##Fixture, \
|
||||
::testing::internal::GetTypeId<test_fixture##Fixture>())
|
||||
|
||||
/// Convenience to define a test fixture with a Fixture suffix for use with
|
||||
/// TEST_FIX.
|
||||
#define FIXTURE(test_fixture)\
|
||||
class test_fixture##Fixture : public ::testing::Test
|
||||
|
||||
#endif // TORQUE_TESTS_ENABLED
|
||||
|
||||
#endif // _UNIT_TESTING_H_
|
||||
|
|
|
|||
|
|
@ -1,288 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "core/strings/stringFunctions.h"
|
||||
|
||||
#include "console/console.h"
|
||||
|
||||
#include "unit/test.h"
|
||||
|
||||
#include "core/util/journal/process.h"
|
||||
|
||||
|
||||
namespace UnitTesting
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
TestRegistry *TestRegistry::_list = 0;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static const S32 MaxMarginCount = 32;
|
||||
static const S32 MaxMarginValue = 128;
|
||||
static S32 _Margin[MaxMarginCount] = { 3 };
|
||||
static S32* _MarginPtr = _Margin;
|
||||
static char _MarginString[MaxMarginValue];
|
||||
|
||||
static void _printMargin()
|
||||
{
|
||||
if (*_MarginPtr)
|
||||
::fwrite(_MarginString,1,*_MarginPtr,stdout);
|
||||
}
|
||||
|
||||
void UnitMargin::Push(S32 margin)
|
||||
{
|
||||
if (_MarginPtr < _Margin + MaxMarginCount) {
|
||||
*++_MarginPtr = (margin < MaxMarginValue)? margin: MaxMarginValue;
|
||||
memset(_MarginString,' ',*_MarginPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void UnitMargin::Pop()
|
||||
{
|
||||
if (_MarginPtr > _Margin) {
|
||||
_MarginPtr--;
|
||||
memset(_MarginString,' ',*_MarginPtr);
|
||||
}
|
||||
}
|
||||
|
||||
S32 UnitMargin::Current()
|
||||
{
|
||||
return *_MarginPtr;
|
||||
}
|
||||
|
||||
void UnitPrint(const char* str)
|
||||
{
|
||||
static bool lineStart = true;
|
||||
Platform::outputDebugString(str);
|
||||
|
||||
// Need to scan for '\n' in order to support margins
|
||||
const char* ptr = str, *itr = ptr;
|
||||
for (; *itr != 0; itr++)
|
||||
if (*itr == '\n')
|
||||
{
|
||||
if (lineStart)
|
||||
_printMargin();
|
||||
::fwrite(ptr,1,itr - ptr + 1,stdout);
|
||||
ptr = itr + 1;
|
||||
lineStart = true;
|
||||
}
|
||||
|
||||
// End the line with a carriage return unless the
|
||||
// line ends with a line continuation char.
|
||||
if (ptr != itr) {
|
||||
if (lineStart)
|
||||
_printMargin();
|
||||
if (itr[-1] == '\\') {
|
||||
::fwrite(ptr,1,itr - ptr - 1,stdout);
|
||||
lineStart = false;
|
||||
}
|
||||
else {
|
||||
::fwrite(ptr,1,itr - ptr,stdout);
|
||||
::fwrite("\n",1,1,stdout);
|
||||
lineStart = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
::fwrite("\n",1,1,stdout);
|
||||
lineStart = true;
|
||||
}
|
||||
::fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
UnitTest::UnitTest() {
|
||||
_testCount = 0;
|
||||
_failureCount = 0;
|
||||
_warningCount = 0;
|
||||
_lastTestResult = true;
|
||||
}
|
||||
|
||||
void UnitTest::fail(const char* msg)
|
||||
{
|
||||
Con::warnf("** Failed: %s",msg);
|
||||
dFetchAndAdd( _failureCount, 1 );
|
||||
}
|
||||
|
||||
void UnitTest::warn(const char* msg)
|
||||
{
|
||||
Con::warnf("** Warning: %s",msg);
|
||||
dFetchAndAdd( _warningCount, 1 );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
TestRegistry::TestRegistry(const char* name, bool interactive, const char *className)
|
||||
{
|
||||
// Check that no existing test uses the same class-name; this is guaranteed
|
||||
// to lead to funkiness.
|
||||
TestRegistry *walk = _list;
|
||||
while(walk)
|
||||
{
|
||||
if(walk->_className)
|
||||
{
|
||||
AssertFatal(dStricmp(className, walk->_className), "TestRegistry::TestRegistry - got two unit tests with identical class names; they must have unique class names!");
|
||||
}
|
||||
|
||||
walk = walk->_next;
|
||||
}
|
||||
|
||||
// Add us to the list.
|
||||
_next = _list;
|
||||
_list = this;
|
||||
|
||||
// And fill in our fields.
|
||||
_name = name;
|
||||
_className = className;
|
||||
_isInteractive = interactive;
|
||||
}
|
||||
|
||||
DynamicTestRegistration::DynamicTestRegistration( const char *name, UnitTest *test ) : TestRegistry( name, false, NULL ), mUnitTest( test )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DynamicTestRegistration::~DynamicTestRegistration()
|
||||
{
|
||||
// Un-link ourselves from the test registry
|
||||
TestRegistry *walk = _list;
|
||||
|
||||
// Easy case!
|
||||
if( walk == this )
|
||||
_list = _next;
|
||||
else
|
||||
{
|
||||
// Search for us and remove
|
||||
while( ( walk != 0 ) && ( walk->_next != 0 ) && ( walk->_next != this ) )
|
||||
walk = walk->_next;
|
||||
|
||||
// When this loop is broken, walk will be the unit test in the list previous to this one
|
||||
if( walk != 0 && walk->_next != 0 )
|
||||
walk->_next = walk->_next->_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
TestRun::TestRun()
|
||||
{
|
||||
_subCount = 0;
|
||||
_testCount = 0;
|
||||
_failureCount = 0;
|
||||
_warningCount = 0;
|
||||
}
|
||||
|
||||
void TestRun::printStats()
|
||||
{
|
||||
Con::printf("-- %d test%s run (with %d sub-test%s)",
|
||||
_testCount,(_testCount != 1)? "s": "",
|
||||
_subCount,(_subCount != 1)? "s": "");
|
||||
|
||||
if (_testCount)
|
||||
{
|
||||
if (_failureCount)
|
||||
Con::printf("** %d reported failure%s",
|
||||
_failureCount,(_failureCount != 1)? "s": "");
|
||||
else if (_warningCount)
|
||||
Con::printf("** %d reported warning%s",
|
||||
_warningCount,(_warningCount != 1)? "s": "");
|
||||
else
|
||||
Con::printf("-- No reported failures");
|
||||
}
|
||||
}
|
||||
|
||||
void TestRun::test(TestRegistry* reg)
|
||||
{
|
||||
Con::printf("-- Testing: %s %s",reg->getName(), reg->isInteractive() ? "(interactive)" : "" );
|
||||
|
||||
UnitMargin::Push(_Margin[0]);
|
||||
|
||||
// Run the test.
|
||||
UnitTest* test = reg->newTest();
|
||||
test->run();
|
||||
|
||||
UnitMargin::Pop();
|
||||
|
||||
// Update stats.
|
||||
_failureCount += test->getFailureCount();
|
||||
_subCount += test->getTestCount();
|
||||
_warningCount += test->getWarningCount();
|
||||
_testCount++;
|
||||
|
||||
// Don't forget to delete the test!
|
||||
delete test;
|
||||
}
|
||||
|
||||
// [tom, 2/5/2007] To provide a predictable environment for the tests, this
|
||||
// now changes the current directory to the executable's directory before
|
||||
// running the tests. The previous current directory is restored on exit.
|
||||
|
||||
bool TestRun::test(const char* module, bool skipInteractive)
|
||||
{
|
||||
StringTableEntry cwdSave = Platform::getCurrentDirectory();
|
||||
|
||||
S32 len = strlen(module);
|
||||
|
||||
const char *skipMsg = skipInteractive ? "(skipping interactive tests)" : "";
|
||||
|
||||
// Indicate to the user what we're up to.
|
||||
if (!len)
|
||||
Con::printf("-- Running all unit tests %s", skipMsg);
|
||||
else
|
||||
Con::printf("-- Running %s tests %s",module, skipMsg);
|
||||
|
||||
for (TestRegistry* itr = TestRegistry::getFirst(); itr; itr = itr->getNext())
|
||||
{
|
||||
if (!len || !dStrnicmp(module,itr->getName(),len))
|
||||
{
|
||||
// Skip the test if it's interactive and we're in skipinteractive mode.
|
||||
if(skipInteractive && itr->isInteractive())
|
||||
continue;
|
||||
|
||||
// Otherwise, run the test!
|
||||
Platform::setCurrentDirectory(Platform::getMainDotCsDir());
|
||||
test(itr);
|
||||
}
|
||||
}
|
||||
// Print out a nice report on how we did.
|
||||
printStats();
|
||||
|
||||
Platform::setCurrentDirectory(cwdSave);
|
||||
|
||||
// sanity check for avoid Process::requestShutdown() called on some tests
|
||||
Process::processEvents();
|
||||
|
||||
// And indicate our failure situation in the return value.
|
||||
return !_failureCount;
|
||||
}
|
||||
|
||||
} // Namespace
|
||||
|
||||
|
|
@ -1,165 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef UNIT_UNITTESTING_H
|
||||
#define UNIT_UNITTESTING_H
|
||||
|
||||
#ifndef _PLATFORMINTRINSICS_H_
|
||||
# include "platform/platformIntrinsics.h"
|
||||
#endif
|
||||
|
||||
|
||||
namespace UnitTesting {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct UnitMargin
|
||||
{
|
||||
static void Push(S32 margin);
|
||||
static void Pop();
|
||||
static S32 Current();
|
||||
};
|
||||
|
||||
void UnitPrint(const char* msg);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class UnitTest {
|
||||
S32 _testCount;
|
||||
S32 _failureCount;
|
||||
S32 _warningCount;
|
||||
|
||||
bool _lastTestResult;
|
||||
|
||||
public:
|
||||
UnitTest();
|
||||
virtual ~UnitTest() {};
|
||||
|
||||
/// Test an assertion and note if it has failed.
|
||||
bool test(bool a,const char* msg) {
|
||||
dFetchAndAdd( _testCount, 1 );
|
||||
if (!a)
|
||||
fail(msg);
|
||||
_lastTestResult = a;
|
||||
return a;
|
||||
}
|
||||
|
||||
/// Report a failture condition.
|
||||
void fail(const char* msg);
|
||||
|
||||
/// Report a warning
|
||||
void warn(const char* msg);
|
||||
|
||||
S32 getTestCount() const { return _testCount; }
|
||||
S32 getFailureCount() const { return _failureCount; }
|
||||
S32 getWarningCount() const { return _warningCount; }
|
||||
bool lastTestPassed() const { return _lastTestResult; }
|
||||
|
||||
/// Implement this with the specific test.
|
||||
virtual void run() = 0;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class TestRegistry
|
||||
{
|
||||
friend class DynamicTestRegistration; // Bless me, Father, for I have sinned, but this is damn cool
|
||||
|
||||
static TestRegistry *_list;
|
||||
TestRegistry *_next;
|
||||
|
||||
const char *_name;
|
||||
const char *_className;
|
||||
bool _isInteractive;
|
||||
|
||||
public:
|
||||
TestRegistry(const char* name, bool interactive, const char *className);
|
||||
virtual ~TestRegistry() {}
|
||||
static TestRegistry* getFirst() { return _list; }
|
||||
TestRegistry* getNext() { return _next; }
|
||||
const char* getName() { return _name; }
|
||||
const bool isInteractive() { return _isInteractive; }
|
||||
virtual UnitTest* newTest() = 0;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class TestRegistration: public TestRegistry
|
||||
{
|
||||
public:
|
||||
virtual ~TestRegistration()
|
||||
{
|
||||
}
|
||||
|
||||
TestRegistration(const char* name, bool interactive, const char *className)
|
||||
: TestRegistry(name, interactive, className)
|
||||
{
|
||||
}
|
||||
|
||||
virtual UnitTest* newTest()
|
||||
{
|
||||
return new T;
|
||||
}
|
||||
};
|
||||
|
||||
class DynamicTestRegistration : public TestRegistry
|
||||
{
|
||||
|
||||
UnitTest *mUnitTest;
|
||||
|
||||
public:
|
||||
DynamicTestRegistration( const char *name, UnitTest *test );
|
||||
|
||||
virtual ~DynamicTestRegistration();
|
||||
|
||||
virtual UnitTest *newTest() { return mUnitTest; }
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class TestRun {
|
||||
S32 _testCount;
|
||||
S32 _subCount;
|
||||
S32 _failureCount;
|
||||
S32 _warningCount;
|
||||
void test(TestRegistry* reg);
|
||||
public:
|
||||
TestRun();
|
||||
void printStats();
|
||||
bool test(const char* module, bool skipInteractive = false);
|
||||
};
|
||||
|
||||
#define CreateUnitTest(Class,Name) \
|
||||
class Class; \
|
||||
static UnitTesting::TestRegistration<Class> _UnitTester##Class (Name, false, #Class); \
|
||||
class Class : public UnitTesting::UnitTest
|
||||
|
||||
#define CreateInteractiveTest(Class,Name) \
|
||||
class Class; \
|
||||
static UnitTesting::TestRegistration<Class> _UnitTester##Class (Name, true, #Class); \
|
||||
class Class : public UnitTesting::UnitTest
|
||||
|
||||
} // Namespace
|
||||
|
||||
#endif
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "console/simObject.h"
|
||||
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
|
||||
// Test to ensure that all console classes in the system are default-constructible.
|
||||
|
||||
CreateUnitTest( TestDefaultConstruction, "Console/DefaultConstruction" )
|
||||
{
|
||||
void run()
|
||||
{
|
||||
for( AbstractClassRep* classRep = AbstractClassRep::getClassList();
|
||||
classRep != NULL;
|
||||
classRep = classRep->getNextClass() )
|
||||
{
|
||||
// Create object.
|
||||
|
||||
ConsoleObject* object = classRep->create();
|
||||
test( object, avar( "AbstractClassRep::create failed for class '%s'", classRep->getClassName() ) );
|
||||
if( !object )
|
||||
continue;
|
||||
|
||||
// Make sure it's a SimObject.
|
||||
|
||||
SimObject* simObject = dynamic_cast< SimObject* >( object );
|
||||
if( !simObject )
|
||||
{
|
||||
SAFE_DELETE( object );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Register the object.
|
||||
|
||||
bool result = simObject->registerObject();
|
||||
test( result, avar( "registerObject failed for object of class '%s'", classRep->getClassName() ) );
|
||||
|
||||
if( result )
|
||||
simObject->deleteObject();
|
||||
else
|
||||
SAFE_DELETE( simObject );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "unit/test.h"
|
||||
#include "math/mMath.h"
|
||||
#include "math/mRandom.h"
|
||||
|
||||
extern void default_matF_x_matF_C(const F32 *a, const F32 *b, F32 *mresult);
|
||||
extern void mInstallLibrary_ASM();
|
||||
|
||||
// If we're x86 and not Mac, then include these. There's probably a better way to do this.
|
||||
#if defined(TORQUE_CPU_X86) && !defined(TORQUE_OS_MAC)
|
||||
extern "C" void Athlon_MatrixF_x_MatrixF(const F32 *matA, const F32 *matB, F32 *result);
|
||||
extern "C" void SSE_MatrixF_x_MatrixF(const F32 *matA, const F32 *matB, F32 *result);
|
||||
#endif
|
||||
|
||||
#if defined( __VEC__ )
|
||||
extern void vec_MatrixF_x_MatrixF(const F32 *matA, const F32 *matB, F32 *result);
|
||||
#endif
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateUnitTest( TestMatrixMul, "Math/Matrix/Multiply" )
|
||||
{
|
||||
// The purpose of this test is to verify that the matrix multiplication operation
|
||||
// always agrees with the different implementations of itself within a reasonable
|
||||
// epsilon.
|
||||
void run()
|
||||
{
|
||||
F32 m1[16], m2[16], mrC[16];
|
||||
|
||||
// I am not positive that the best way to do this is to use random numbers
|
||||
// but I think that using some kind of standard matrix may not always catch
|
||||
// all problems.
|
||||
for( S32 i = 0; i < 16; i++ )
|
||||
{
|
||||
m1[i] = gRandGen.randF();
|
||||
m2[i] = gRandGen.randF();
|
||||
}
|
||||
|
||||
// C will be the baseline
|
||||
default_matF_x_matF_C( m1, m2, mrC );
|
||||
|
||||
#if defined(TORQUE_CPU_X86) && !defined(TORQUE_OS_MAC)
|
||||
// Check the CPU info
|
||||
U32 cpuProperties = Platform::SystemInfo.processor.properties;
|
||||
bool same = true;
|
||||
// Test 3D NOW! if it is available
|
||||
F32 mrAMD[16];
|
||||
if( cpuProperties & CPU_PROP_3DNOW )
|
||||
{
|
||||
Athlon_MatrixF_x_MatrixF( m1, m2, mrAMD );
|
||||
|
||||
for( S32 i = 0; i < 16; i++ )
|
||||
same &= mIsEqual( mrC[i], mrAMD[i] );
|
||||
|
||||
test( same, "Matrix multiplication verification failed. (C vs. 3D NOW!)" );
|
||||
}
|
||||
else
|
||||
warn( "Could not test 3D NOW! matrix multiplication because CPU does not support 3D NOW!." );
|
||||
|
||||
same = true;
|
||||
|
||||
// Test SSE if it is available
|
||||
F32 mrSSE[16];
|
||||
if( cpuProperties & CPU_PROP_SSE )
|
||||
{
|
||||
SSE_MatrixF_x_MatrixF( m1, m2, mrSSE );
|
||||
|
||||
for( S32 i = 0; i < 16; i++ )
|
||||
same &= mIsEqual( mrC[i], mrSSE[i] );
|
||||
|
||||
test( same, "Matrix multiplication verification failed. (C vs. SSE)" );
|
||||
}
|
||||
else
|
||||
warn( "Could not test SSE matrix multiplication because CPU does not support SSE." );
|
||||
|
||||
same = true;
|
||||
#endif
|
||||
|
||||
// If Altivec exists, test it!
|
||||
#if defined( __VEC__ )
|
||||
bool same = false;
|
||||
F32 mrVEC[16];
|
||||
|
||||
vec_MatrixF_x_MatrixF( m1, m2, mrVEC );
|
||||
|
||||
for( S32 i = 0; i < 16; i++ )
|
||||
same &= isEqual( mrC[i], mrVEC[i] );
|
||||
|
||||
test( same, "Matrix multiplication verification failed. (C vs. Altivec)" );
|
||||
#else
|
||||
warn( "Could not test Altivec matrix multiplication because CPU does not support Altivec." );
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "console/simBase.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/runtimeClassRep.h"
|
||||
#include "unit/test.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class RuntimeRegisteredSimObject : public SimObject
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
|
||||
protected:
|
||||
bool mFoo;
|
||||
|
||||
public:
|
||||
RuntimeRegisteredSimObject() : mFoo( false ) {};
|
||||
|
||||
DECLARE_RUNTIME_CONOBJECT(RuntimeRegisteredSimObject);
|
||||
|
||||
static void initPersistFields();
|
||||
};
|
||||
|
||||
IMPLEMENT_RUNTIME_CONOBJECT(RuntimeRegisteredSimObject);
|
||||
|
||||
void RuntimeRegisteredSimObject::initPersistFields()
|
||||
{
|
||||
addField( "fooField", TypeBool, Offset( mFoo, RuntimeRegisteredSimObject ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CreateUnitTest( RuntimeClassRepUnitTest, "Console/RuntimeClassRep" )
|
||||
{
|
||||
void run()
|
||||
{
|
||||
// First test to make sure that the test class is not registered (don't know how it could be, but that's programming for you)
|
||||
test( !RuntimeRegisteredSimObject::dynRTClassRep.isRegistered(), "RuntimeRegisteredSimObject class was already registered with the console" );
|
||||
|
||||
// This should not be able to find the class, and return null (this may AssertWarn as well)
|
||||
ConsoleObject *conobj = ConsoleObject::create( "RuntimeRegisteredSimObject" );
|
||||
test( conobj == NULL, "AbstractClassRep returned non-NULL value! That is really bad!" );
|
||||
|
||||
// Register with console system
|
||||
RuntimeRegisteredSimObject::dynRTClassRep.consoleRegister();
|
||||
|
||||
// Make sure that the object knows it's registered
|
||||
test( RuntimeRegisteredSimObject::dynRTClassRep.isRegistered(), "RuntimeRegisteredSimObject class failed console registration" );
|
||||
|
||||
// Now try again to create the instance
|
||||
conobj = ConsoleObject::create( "RuntimeRegisteredSimObject" );
|
||||
test( conobj != NULL, "AbstractClassRep::create method failed!" );
|
||||
|
||||
// Cast the instance, and test it
|
||||
RuntimeRegisteredSimObject *rtinst = dynamic_cast<RuntimeRegisteredSimObject *>( conobj );
|
||||
test( rtinst != NULL, "Casting failed for some reason" );
|
||||
|
||||
// Register it
|
||||
rtinst->registerObject( "_utRRTestObject" );
|
||||
test( rtinst->isProperlyAdded(), "registerObject failed on test object" );
|
||||
|
||||
// Now execute some script on it
|
||||
Con::evaluate( "_utRRTestObject.fooField = true;" );
|
||||
|
||||
// Test to make sure field worked
|
||||
test( dAtob( rtinst->getDataField( StringTable->insert( "fooField" ), NULL ) ), "Script test failed!" );
|
||||
|
||||
// BALETED
|
||||
rtinst->deleteObject();
|
||||
|
||||
// Unregister the class
|
||||
RuntimeRegisteredSimObject::dynRTClassRep.consoleUnRegister();
|
||||
|
||||
// And make sure we can't create another one
|
||||
conobj = ConsoleObject::create( "RuntimeRegisteredSimObject" );
|
||||
test( conobj == NULL, "Unregistration of type failed" );
|
||||
}
|
||||
};
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "unit/test.h"
|
||||
#include "unit/memoryTester.h"
|
||||
#include "core/util/swizzle.h"
|
||||
#include "math/mRandom.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
class TestStruct
|
||||
{
|
||||
private:
|
||||
static U32 smIdx;
|
||||
U32 mIdx;
|
||||
U32 mData;
|
||||
|
||||
public:
|
||||
TestStruct( const S32 data = -1 ) : mData( data ), mIdx( smIdx++ ) {};
|
||||
|
||||
dsize_t Idx() const { return mIdx; }
|
||||
|
||||
U32 Data() const { return mData; }
|
||||
void Data(U32 val) { mData = val; }
|
||||
};
|
||||
|
||||
U32 TestStruct::smIdx = 0;
|
||||
|
||||
CreateUnitTest(TestSwizzle, "Utils/Swizzle")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
//------------------------------------------------------------------------
|
||||
// Debugger-Observable Functionality Tests
|
||||
//------------------------------------------------------------------------
|
||||
U8 simpleBuffer[] = { 0, 1, 2, 3 };
|
||||
U8 simpleTest[] = { 0, 1, 2, 3 };
|
||||
|
||||
#define RESET_SIMPLE() dMemcpy( simpleTest, simpleBuffer, sizeof( simpleBuffer ) )
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// No-switch test
|
||||
dsize_t noSwzl4[] = { 0, 1, 2, 3 };
|
||||
Swizzle<U8,4> noSwizzle4( noSwzl4 );
|
||||
|
||||
noSwizzle4.InPlace( simpleTest, sizeof( simpleTest ) );
|
||||
test( dMemcmp( simpleTest, simpleBuffer, sizeof( simpleBuffer ) ) == 0, "No-switch test failed!" );
|
||||
RESET_SIMPLE();
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// No-brainer RGBA->BGRA test
|
||||
dsize_t bgraSwzl[] = { 2, 1, 0, 3 };
|
||||
Swizzle<U8,4> bgraSwizzle( bgraSwzl );
|
||||
|
||||
U8 bgraTest[] = { 2, 1, 0, 3 };
|
||||
bgraSwizzle.InPlace( simpleTest, sizeof( simpleTest ) );
|
||||
test( dMemcmp( simpleTest, bgraTest, sizeof( bgraTest ) ) == 0, "U8 RGBA->BGRA test failed" );
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Reverse test
|
||||
bgraSwizzle.InPlace( simpleTest, sizeof( simpleTest ) );
|
||||
test( dMemcmp( simpleTest, simpleBuffer, sizeof( simpleBuffer ) ) == 0, "U8 RGBA->BGRA reverse test failed" );
|
||||
|
||||
RESET_SIMPLE();
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Object support test
|
||||
Swizzle<TestStruct,4> bgraObjSwizzle( bgraSwzl );
|
||||
{
|
||||
U32 objIdx[] = { 0, 1, 2, 3 };
|
||||
|
||||
FrameTemp<TestStruct> objTest( sizeof( objIdx ) / sizeof( U32 ) );
|
||||
FrameTemp<U32> randData( sizeof( objIdx ) / sizeof( U32 ) );
|
||||
|
||||
bool same = true;
|
||||
|
||||
for( U32 i = 0; i < sizeof( objIdx ) / sizeof( U32 ); i++ )
|
||||
{
|
||||
// Make random data and assign it
|
||||
randData[i] = gRandGen.randI();
|
||||
objTest[i].Data( randData[i] );
|
||||
|
||||
// Continue object sanity check
|
||||
same &= ( objTest[i].Idx() == objIdx[i] );
|
||||
}
|
||||
|
||||
test( same, "Test object failed to be competent" );
|
||||
|
||||
bgraObjSwizzle.InPlace( ~objTest, sizeof( TestStruct ) * ( sizeof( objIdx ) / sizeof( U32 ) ) );
|
||||
same = true;
|
||||
|
||||
for( U32 i = 0; i < sizeof( objIdx ) / sizeof( U32 ); i++ )
|
||||
same &= ( objTest[i].Idx() == bgraTest[i] ) && ( objTest[i].Data() == randData[ (U32)bgraTest[ i ] ] );
|
||||
|
||||
test( same, "Object RGBA->BGRA test failed." );
|
||||
|
||||
bgraObjSwizzle.InPlace( ~objTest, sizeof( TestStruct ) * ( sizeof( objIdx ) / sizeof( U32 ) ) );
|
||||
same = true;
|
||||
|
||||
for( U32 i = 0; i < sizeof( objIdx ) / sizeof( U32 ); i++ )
|
||||
same &= ( objTest[i].Idx() == objIdx[i] ) && ( objTest[i].Data() == randData[i] );
|
||||
|
||||
test( same, "Object RGBA->BGRA reverse test failed." );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "unit/test.h"
|
||||
#include "core/threadStatic.h"
|
||||
#include "unit/memoryTester.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This unit test will blow up without thread static support
|
||||
#ifdef TORQUE_ENABLE_THREAD_STATICS
|
||||
|
||||
// Declare a test thread static
|
||||
DITTS( U32, gUnitTestFoo, 42 );
|
||||
DITTS( F32, gUnitTestF32, 1.0 );
|
||||
|
||||
CreateUnitTest( TestThreadStatic, "Core/ThreadStatic" )
|
||||
{
|
||||
void run()
|
||||
{
|
||||
MemoryTester m;
|
||||
m.mark();
|
||||
|
||||
// ThreadStatic list should be initialized right now, so lets see if it has
|
||||
// any entries.
|
||||
test( !_TorqueThreadStaticReg::getStaticList().empty(), "Self-registration has failed, or no statics declared" );
|
||||
|
||||
// Spawn a new copy.
|
||||
TorqueThreadStaticListHandle testInstance = _TorqueThreadStaticReg::spawnThreadStaticsInstance();
|
||||
|
||||
// Test the copy
|
||||
test( _TorqueThreadStaticReg::getStaticList( 0 ).size() == testInstance->size(), "Spawned static list has a different size from master copy." );
|
||||
|
||||
// Make sure the size test passed before this is attempted
|
||||
if( lastTestPassed() )
|
||||
{
|
||||
// Traverse the list and compare it to the initial value copy (index 0)
|
||||
for( S32 i = 0; i < _TorqueThreadStaticReg::getStaticList().size(); i++ )
|
||||
{
|
||||
_TorqueThreadStatic *master = _TorqueThreadStaticReg::getStaticList()[i];
|
||||
_TorqueThreadStatic *cpy = (*testInstance)[i];
|
||||
|
||||
// Make sure it is not the same memory
|
||||
test( master != cpy, "Copy not spawned properly." );
|
||||
|
||||
// Make sure the sizes are the same
|
||||
test( master->getMemInstSize() == cpy->getMemInstSize(), "Size mismatch between master and copy" );
|
||||
|
||||
// Make sure the initialization occurred properly
|
||||
if( lastTestPassed() )
|
||||
test( dMemcmp( master->getMemInstPtr(), cpy->getMemInstPtr(), master->getMemInstSize() ) == 0, "Initial value for spawned list is not correct" );
|
||||
}
|
||||
}
|
||||
|
||||
// Test metrics if enabled
|
||||
#ifdef TORQUE_ENABLE_THREAD_STATIC_METRICS
|
||||
U32 fooHitCount = (*testInstance)[_gUnitTestFooTorqueThreadStatic::getListIndex()]->getHitCount();
|
||||
#endif
|
||||
|
||||
// Set/get some values (If we test static metrics, this is hit 1)
|
||||
ATTS_(gUnitTestFoo, 1) = 55;
|
||||
|
||||
// Test to see that the master copy and the spawned copy differ
|
||||
// (If we test metrics, this is hit 2, for the instance, and hit 1 for the master)
|
||||
test( ATTS_(gUnitTestFoo, 0) != ATTS_(gUnitTestFoo, 1 ) , "Assignment for spawned instanced memory failed" );
|
||||
|
||||
#ifdef TORQUE_ENABLE_THREAD_STATIC_METRICS
|
||||
U32 fooHitCount2 = (*testInstance)[_gUnitTestFooTorqueThreadStatic::getListIndex()]->getHitCount();
|
||||
test( fooHitCount2 == ( fooHitCount + 2 ), "Thread static metric hit count failed" );
|
||||
#endif
|
||||
|
||||
// Destroy instances
|
||||
_TorqueThreadStaticReg::destroyInstance( testInstance );
|
||||
|
||||
// Now test the cleanup
|
||||
test( m.check(), "Memory leak in dynamic static allocation stuff." );
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TORQUE_ENABLE_THREAD_STATICS
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "unit/test.h"
|
||||
#include "core/threadStatic.h"
|
||||
#include "math/mRandom.h"
|
||||
#include "platform/profiler.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This unit test will blow up without thread static support
|
||||
#if defined(TORQUE_ENABLE_THREAD_STATICS) && defined(TORQUE_ENABLE_PROFILER)
|
||||
|
||||
// Declare a test thread static
|
||||
DITTS( U32, gInstancedStaticFoo, 42 );
|
||||
static U32 gTrueStaticFoo = 42;
|
||||
|
||||
CreateUnitTest( TestThreadStaticPerformance, "Core/ThreadStaticPerformance" )
|
||||
{
|
||||
void run()
|
||||
{
|
||||
// Bail if the profiler is turned on right now
|
||||
if( !test( !gProfiler->isEnabled(), "Profiler is currently enabled, test cannot continue" ) )
|
||||
return;
|
||||
|
||||
// Spawn an instance
|
||||
TorqueThreadStaticListHandle testInstance = _TorqueThreadStaticReg::spawnThreadStaticsInstance();
|
||||
|
||||
static const dsize_t TEST_SIZE = 100000;
|
||||
|
||||
// What we are going to do in this test is to test some U32 static
|
||||
// performance. The test will be run TEST_SIZE times, and so first create
|
||||
// an array of values to standardize the tests on.
|
||||
U32 testValue[TEST_SIZE];
|
||||
|
||||
for( S32 i = 0; i < TEST_SIZE; i++ )
|
||||
testValue[i] = gRandGen.randI();
|
||||
|
||||
// Reset the profiler, tell it to dump to console when done
|
||||
gProfiler->dumpToConsole();
|
||||
gProfiler->enable( true );
|
||||
|
||||
// Value array is initialized, so lets put the foo's through the paces
|
||||
PROFILE_START(ThreadStaticPerf_TrueStaticAssign);
|
||||
for( int i = 0; i < TEST_SIZE; i++ )
|
||||
gTrueStaticFoo = testValue[i];
|
||||
PROFILE_END();
|
||||
|
||||
PROFILE_START(ThreadStaticPerf_InstanceStaticAssign);
|
||||
for( S32 i = 0; i < TEST_SIZE; i++ )
|
||||
ATTS_( gInstancedStaticFoo, 1 ) = testValue[i];
|
||||
PROFILE_END();
|
||||
|
||||
gProfiler->enable( false );
|
||||
|
||||
// Clean up instance
|
||||
_TorqueThreadStaticReg::destroyInstance( testInstance );
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TORQUE_ENABLE_THREAD_STATICS
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/unitTestComponentInterface.h"
|
||||
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _UNITTESTCOMPONENTINTERFACE_H_
|
||||
#define _UNITTESTCOMPONENTINTERFACE_H_
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "component/simComponent.h"
|
||||
#include "component/componentInterface.h"
|
||||
|
||||
// This is commented out because I want to keep the explicit namespace referencing
|
||||
// so that the multiple inheritances from UnitTest doesn't screw anyone up. It will
|
||||
// also make for more readable code in the derived test-interfaces. -patw
|
||||
//using namespace UnitTesting;
|
||||
|
||||
/// This is a class that will make it very easy for a component author to provide
|
||||
/// unit testing functionality from within an instantiated component.
|
||||
class UnitTestComponentInterface : public ComponentInterface, UnitTesting::UnitTest
|
||||
{
|
||||
typedef ComponentInterface Parent;
|
||||
|
||||
private:
|
||||
StringTableEntry mName;
|
||||
UnitTesting::DynamicTestRegistration *mTestReg;
|
||||
|
||||
// Constructors/Destructors
|
||||
public:
|
||||
UnitTestComponentInterface( const char *name )
|
||||
{
|
||||
mName = StringTable->insert( name );
|
||||
|
||||
mTestReg = new UnitTesting::DynamicTestRegistration( name, this );
|
||||
}
|
||||
|
||||
virtual ~UnitTestComponentInterface()
|
||||
{
|
||||
delete mTestReg;
|
||||
}
|
||||
|
||||
// ComponentInterface overrides
|
||||
public:
|
||||
virtual bool isValid() const
|
||||
{
|
||||
return Parent::isValid() && ( mTestReg != NULL );
|
||||
}
|
||||
|
||||
// UnitTest overrides
|
||||
public:
|
||||
/// This is the only function you need to overwrite to add a unit test interface
|
||||
/// your component.
|
||||
virtual void run() = 0;
|
||||
};
|
||||
|
||||
// Macros
|
||||
#ifndef TORQUE_DEBUG
|
||||
# define DECLARE_UNITTEST_INTERFACE(x)
|
||||
# define CACHE_UNITTEST_INTERFACE(x)
|
||||
#else
|
||||
//-----------------------------------------------------------------------------
|
||||
# define DECLARE_UNITTEST_INTERFACE(x) \
|
||||
class x##_UnitTestInterface : public UnitTestComponentInterface \
|
||||
{\
|
||||
typedef UnitTestComponentInterface Parent; \
|
||||
public: \
|
||||
x##_UnitTestInterface() : UnitTestComponentInterface( #x ) {}; \
|
||||
virtual void run(); \
|
||||
} _##x##UnitTestInterface
|
||||
//-----------------------------------------------------------------------------
|
||||
# define CACHE_UNITTEST_INTERFACE(x) registerCachedInterface( "unittest", #x, this, &_##x##UnitTestInterface )
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,538 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "console/console.h"
|
||||
#include "windowManager/platformWindowMgr.h"
|
||||
#include "unit/test.h"
|
||||
#include "core/util/tVector.h"
|
||||
#include "gfx/gfxStructs.h"
|
||||
#include "core/util/journal/process.h"
|
||||
#include "gfx/gfxInit.h"
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
CreateUnitTest(TestWinMgrQueries, "WindowManager/BasicQueries")
|
||||
{
|
||||
void run()
|
||||
{
|
||||
PlatformWindowManager *pwm = CreatePlatformWindowManager();
|
||||
|
||||
// Check out the primary desktop area...
|
||||
RectI primary = pwm->getPrimaryDesktopArea();
|
||||
|
||||
Con::printf("Primary desktop area is (%d,%d) (%d,%d)",
|
||||
primary.point.x, primary.point.y, primary.extent.x, primary.extent.y);
|
||||
|
||||
test(primary.isValidRect(), "Got some sort of invalid rect from the window manager!");
|
||||
|
||||
// Now try to get info about all the monitors.
|
||||
Vector<RectI> monitorRects;
|
||||
pwm->getMonitorRegions(monitorRects);
|
||||
|
||||
test(monitorRects.size() > 0, "Should get at least one monitor rect back from getMonitorRegions!");
|
||||
|
||||
// This test is here just to detect overflow/runaway situations. -- BJG
|
||||
test(monitorRects.size() < 64, "Either something's wrong, or you have a lot of monitors...");
|
||||
|
||||
for(S32 i=0; i<monitorRects.size(); i++)
|
||||
{
|
||||
Con::printf(" Monitor #%d region is (%d,%d) (%d,%d)", i,
|
||||
monitorRects[i].point.x, monitorRects[i].point.y, monitorRects[i].extent.x, monitorRects[i].extent.y);
|
||||
|
||||
test(monitorRects[i].isValidRect(), "Got an invalid rect for this monitor - no good.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreateInteractiveTest(TestWinMgrCreate, "WindowManager/CreateAWindow")
|
||||
{
|
||||
void handleMouseEvent(WindowId,U32,S32 x,S32 y, bool isRelative)
|
||||
{
|
||||
Con::printf("Mouse at %d, %d %s", x, y, isRelative ? "(relative)" : "(absolute)");
|
||||
}
|
||||
|
||||
void handleAppEvent(WindowId, S32 event)
|
||||
{
|
||||
if(event == WindowClose)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
PlatformWindowManager *pwm = CreatePlatformWindowManager();
|
||||
|
||||
GFXVideoMode vm;
|
||||
vm.resolution.x = 800;
|
||||
vm.resolution.y = 600;
|
||||
|
||||
PlatformWindow *pw = pwm->createWindow(NULL, vm);
|
||||
|
||||
test(pw, "Didn't get a window back from the window manager, no good.");
|
||||
if(!pw)
|
||||
return;
|
||||
|
||||
// Setup our events.
|
||||
pw->mouseEvent.notify(this, &TestWinMgrCreate::handleMouseEvent);
|
||||
pw->appEvent.notify(this, &TestWinMgrCreate::handleAppEvent);
|
||||
|
||||
// And, go on our way.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
SAFE_DELETE(pw);
|
||||
}
|
||||
};
|
||||
|
||||
CreateInteractiveTest(TestWinMgrGFXInit, "WindowManager/SimpleGFX")
|
||||
{
|
||||
PlatformWindow *mWindow;
|
||||
GFXDevice *mDevice;
|
||||
|
||||
void handleDrawEvent(WindowId id)
|
||||
{
|
||||
mDevice->beginScene();
|
||||
mDevice->setActiveRenderTarget(mWindow->getGFXTarget());
|
||||
mDevice->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget, ColorI( 255, 255, 0 ), 1.0f, 0 );
|
||||
mDevice->endScene();
|
||||
mWindow->getGFXTarget()->present();
|
||||
}
|
||||
|
||||
void forceDraw()
|
||||
{
|
||||
handleDrawEvent(0);
|
||||
}
|
||||
|
||||
void handleAppEvent(WindowId, S32 event)
|
||||
{
|
||||
if(event == WindowClose)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
PlatformWindowManager *pwm = CreatePlatformWindowManager();
|
||||
|
||||
// Create a device.
|
||||
GFXAdapter a;
|
||||
a.mType = Direct3D9;
|
||||
a.mIndex = 0;
|
||||
|
||||
mDevice = GFXInit::createDevice(&a);
|
||||
test(mDevice, "Unable to create d3d9 device #0.");
|
||||
|
||||
// Initialize the window...
|
||||
GFXVideoMode vm;
|
||||
vm.resolution.x = 400;
|
||||
vm.resolution.y = 400;
|
||||
|
||||
mWindow = pwm->createWindow(mDevice, vm);
|
||||
|
||||
test(mWindow, "Didn't get a window back from the window manager, no good.");
|
||||
if(!mWindow)
|
||||
return;
|
||||
|
||||
// Setup our events.
|
||||
mWindow->displayEvent.notify(this, &TestWinMgrGFXInit::handleDrawEvent);
|
||||
mWindow->idleEvent.notify(this, &TestWinMgrGFXInit::forceDraw);
|
||||
mWindow->appEvent.notify(this, &TestWinMgrGFXInit::handleAppEvent);
|
||||
|
||||
// And, go on our way.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
mWindow->displayEvent.remove(this, &TestWinMgrGFXInit::handleDrawEvent);
|
||||
mWindow->idleEvent.remove(this, &TestWinMgrGFXInit::forceDraw);
|
||||
mWindow->appEvent.remove(this, &TestWinMgrGFXInit::handleAppEvent);
|
||||
|
||||
// Clean up!
|
||||
SAFE_DELETE(mDevice);
|
||||
SAFE_DELETE(mWindow);
|
||||
}
|
||||
};
|
||||
|
||||
CreateInteractiveTest(TestWinMgrGFXInitMultiWindow, "WindowManager/GFXMultiWindow")
|
||||
{
|
||||
enum {
|
||||
NumWindows = 4,
|
||||
};
|
||||
|
||||
PlatformWindowManager *mWindowManager;
|
||||
PlatformWindow *mWindows[NumWindows];
|
||||
GFXDevice *mDevice;
|
||||
|
||||
void handleDrawEvent(WindowId id)
|
||||
{
|
||||
// Which window are we getting this event on?
|
||||
PlatformWindow *w = mWindowManager->getWindowById(id);
|
||||
|
||||
mDevice->beginScene();
|
||||
mDevice->setActiveRenderTarget(w->getGFXTarget());
|
||||
|
||||
// Vary clear color by window to discern which window is which.
|
||||
mDevice->clear( GFXClearTarget,
|
||||
ColorI( 255 - (id * 50), 255, id * 100 ), 1.0f, 0 );
|
||||
mDevice->endScene();
|
||||
|
||||
// Call swap on the window's render target.
|
||||
((GFXWindowTarget*)w->getGFXTarget())->present();
|
||||
}
|
||||
|
||||
void handleAppEvent(WindowId, S32 event)
|
||||
{
|
||||
if(event == WindowClose)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
void handleIdleEvent()
|
||||
{
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
handleDrawEvent(mWindows[i]->getWindowId());
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
mWindowManager = CreatePlatformWindowManager();
|
||||
|
||||
// Create a device.
|
||||
GFXAdapter a;
|
||||
a.mType = Direct3D9;
|
||||
a.mIndex = 0;
|
||||
|
||||
mDevice = GFXInit::createDevice(&a);
|
||||
test(mDevice, "Unable to create d3d9 device #0.");
|
||||
|
||||
// Initialize the windows...
|
||||
GFXVideoMode vm;
|
||||
vm.resolution.x = 400;
|
||||
vm.resolution.y = 400;
|
||||
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
{
|
||||
mWindows[i] = mWindowManager->createWindow(mDevice, vm);
|
||||
|
||||
test(mWindows[i], "Didn't get a window back from the window manager, no good.");
|
||||
if(!mWindows[i])
|
||||
continue;
|
||||
|
||||
// Setup our events.
|
||||
mWindows[i]->displayEvent.notify(this, &TestWinMgrGFXInitMultiWindow::handleDrawEvent);
|
||||
mWindows[i]->appEvent.notify(this, &TestWinMgrGFXInitMultiWindow::handleAppEvent);
|
||||
mWindows[i]->idleEvent.notify(this, &TestWinMgrGFXInitMultiWindow::handleIdleEvent);
|
||||
}
|
||||
|
||||
// And, go on our way.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
SAFE_DELETE(mWindowManager);
|
||||
SAFE_DELETE(mDevice);
|
||||
}
|
||||
};
|
||||
|
||||
CreateInteractiveTest(TestJournaledMultiWindowGFX, "WindowManager/GFXJournaledMultiWindow")
|
||||
{
|
||||
enum {
|
||||
NumWindows = 2,
|
||||
};
|
||||
|
||||
PlatformWindowManager *mWindowManager;
|
||||
PlatformWindow *mWindows[NumWindows];
|
||||
GFXDevice *mDevice;
|
||||
|
||||
S32 mNumDraws;
|
||||
S32 mNumResize;
|
||||
|
||||
void drawToWindow(PlatformWindow *win)
|
||||
{
|
||||
// Do some simple checks to make sure we draw the same number of times
|
||||
// on both runs.
|
||||
if(Journal::IsPlaying())
|
||||
mNumDraws--;
|
||||
else
|
||||
mNumDraws++;
|
||||
|
||||
// Render!
|
||||
mDevice->beginScene();
|
||||
mDevice->setActiveRenderTarget(win->getGFXTarget());
|
||||
|
||||
// Vary clear color by window to discern which window is which.
|
||||
static S32 timeVariance = 0;
|
||||
|
||||
mDevice->clear( GFXClearTarget,
|
||||
ColorI( 0xFF - (++timeVariance * 5), 0xFF, win->getWindowId() * 0x0F ), 1.0f, 0 );
|
||||
|
||||
mDevice->endScene();
|
||||
|
||||
// Call swap on the window's render target.
|
||||
win->getGFXTarget()->present();
|
||||
|
||||
}
|
||||
|
||||
void handleDrawEvent(WindowId id)
|
||||
{
|
||||
// Which window are we getting this event on?
|
||||
PlatformWindow *w = mWindowManager->getWindowById(id);
|
||||
|
||||
drawToWindow(w);
|
||||
}
|
||||
|
||||
void handleAppEvent(WindowId, S32 event)
|
||||
{
|
||||
if(event == WindowClose)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
void handleIdleEvent()
|
||||
{
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
drawToWindow(mWindows[i]);
|
||||
}
|
||||
|
||||
void handleResizeEvent(WindowId id, S32 width, S32 height)
|
||||
{
|
||||
// Do some simple checks to make sure we resize the same number of times
|
||||
// on both runs.
|
||||
|
||||
if(Journal::IsPlaying())
|
||||
{
|
||||
// If we're playing back, APPLY the resize event...
|
||||
mWindowManager->getWindowById(id)->setSize(Point2I(width, height));
|
||||
|
||||
mNumResize--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we're not playing back, do nothing except note it.
|
||||
mNumResize++;
|
||||
}
|
||||
|
||||
// Which window are we getting this event on?
|
||||
PlatformWindow *w = mWindowManager->getWindowById(id);
|
||||
|
||||
drawToWindow(w);
|
||||
}
|
||||
|
||||
/// The mainloop of our app - we'll run this twice, once to create
|
||||
/// a journal and again to play it back.
|
||||
void mainLoop()
|
||||
{
|
||||
mWindowManager = CreatePlatformWindowManager();
|
||||
|
||||
// Create a device.
|
||||
GFXAdapter a;
|
||||
a.mType = Direct3D9;
|
||||
a.mIndex = 0;
|
||||
|
||||
mDevice = GFXInit::createDevice(&a);
|
||||
test(mDevice, "Unable to create ogl device #0.");
|
||||
|
||||
// Initialize the windows...
|
||||
GFXVideoMode vm;
|
||||
vm.resolution.x = 400;
|
||||
vm.resolution.y = 400;
|
||||
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
{
|
||||
mWindows[i] = mWindowManager->createWindow(mDevice, vm);
|
||||
|
||||
test(mWindows[i], "Didn't get a window back from the window manager, no good.");
|
||||
if(!mWindows[i])
|
||||
continue;
|
||||
|
||||
// Setup our events.
|
||||
mWindows[i]->displayEvent.notify(this, &TestJournaledMultiWindowGFX::handleDrawEvent);
|
||||
mWindows[i]->appEvent.notify(this, &TestJournaledMultiWindowGFX::handleAppEvent);
|
||||
mWindows[i]->resizeEvent.notify(this, &TestJournaledMultiWindowGFX::handleResizeEvent);
|
||||
|
||||
// Only subscribe to the first idle event.
|
||||
if(i==0)
|
||||
mWindows[i]->idleEvent.notify(this, &TestJournaledMultiWindowGFX::handleIdleEvent);
|
||||
}
|
||||
|
||||
// And, go on our way.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
// Finally, clean up.
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
SAFE_DELETE(mWindows[i]);
|
||||
|
||||
SAFE_DELETE(mDevice);
|
||||
SAFE_DELETE(mWindowManager);
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
return;
|
||||
|
||||
// CodeReview: this should be deleted or enabled.
|
||||
#if 0
|
||||
mNumDraws = 0;
|
||||
mNumResize = 0;
|
||||
|
||||
// Record a run of the main loop.
|
||||
Journal::Record("multiwindow.jrn");
|
||||
mainLoop();
|
||||
Journal::Stop();
|
||||
|
||||
test(mNumDraws > 0, "No draws occurred!");
|
||||
test(mNumResize > 0, "No resizes occurred!");
|
||||
|
||||
// And play it back.
|
||||
Journal::Play("multiwindow.jrn");
|
||||
mainLoop();
|
||||
Journal::Stop();
|
||||
|
||||
test(mNumDraws == 0, "Failed to play journal back with same number of draws.");
|
||||
test(mNumResize == 0, "Failed to play journal back with same number of resizes.");
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
CreateInteractiveTest(GFXTestFullscreenToggle, "GFX/TestFullscreenToggle")
|
||||
{
|
||||
enum Constants
|
||||
{
|
||||
NumWindows = 1,
|
||||
};
|
||||
|
||||
PlatformWindowManager *mWindowManager;
|
||||
PlatformWindow *mWindows[NumWindows];
|
||||
GFXDevice *mDevice;
|
||||
|
||||
void drawToWindow(PlatformWindow *win)
|
||||
{
|
||||
// Render!
|
||||
mDevice->beginScene();
|
||||
mDevice->setActiveRenderTarget(win->getGFXTarget());
|
||||
|
||||
// Vary clear color by window to discern which window is which.
|
||||
static S32 timeVariance = 0;
|
||||
|
||||
mDevice->clear( GFXClearZBuffer | GFXClearStencil | GFXClearTarget,
|
||||
ColorI( 0xFF - (++timeVariance * 5), 0xFF, win->getWindowId() * 0x40 ), 1.0f, 0 );
|
||||
|
||||
mDevice->endScene();
|
||||
|
||||
// Call swap on the window's render target.
|
||||
win->getGFXTarget()->present();
|
||||
}
|
||||
|
||||
void handleDrawEvent(WindowId id)
|
||||
{
|
||||
// Which window are we getting this event on?
|
||||
PlatformWindow *w = mWindowManager->getWindowById(id);
|
||||
|
||||
drawToWindow(w);
|
||||
}
|
||||
|
||||
void handleAppEvent(WindowId, S32 event)
|
||||
{
|
||||
if(event == WindowClose)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
|
||||
void handleIdleEvent()
|
||||
{
|
||||
// Redraw everything.
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
drawToWindow(mWindows[i]);
|
||||
|
||||
// Don't monopolize the CPU.
|
||||
Platform::sleep(10);
|
||||
}
|
||||
|
||||
void handleButtonEvent(WindowId did,U32 modifier,U32 action,U16 button)
|
||||
{
|
||||
// Only respond to button down
|
||||
if(action != IA_MAKE)
|
||||
return;
|
||||
|
||||
// Get the window...
|
||||
PlatformWindow *win = mWindowManager->getWindowById(did);
|
||||
GFXVideoMode winVm = win->getVideoMode();
|
||||
|
||||
// If the window is not full screen, make it full screen 800x600x32
|
||||
if(winVm.fullScreen == false)
|
||||
{
|
||||
winVm.fullScreen = true;
|
||||
winVm.resolution.set(800,600);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the window is full screen, then bump it to 400x400x32
|
||||
winVm.fullScreen = false;
|
||||
winVm.resolution.set(400,400);
|
||||
}
|
||||
|
||||
win->setVideoMode(winVm);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
mWindowManager = CreatePlatformWindowManager();
|
||||
|
||||
// Create a device.
|
||||
GFXAdapter a;
|
||||
a.mType = Direct3D9;
|
||||
a.mIndex = 0;
|
||||
|
||||
mDevice = GFXInit::createDevice(&a);
|
||||
test(mDevice, "Unable to create d3d9 device #0.");
|
||||
|
||||
// Initialize the windows...
|
||||
GFXVideoMode vm;
|
||||
vm.resolution.x = 400;
|
||||
vm.resolution.y = 400;
|
||||
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
{
|
||||
mWindows[i] = mWindowManager->createWindow(mDevice, vm);
|
||||
|
||||
test(mWindows[i], "Didn't get a window back from the window manager, no good.");
|
||||
if(!mWindows[i])
|
||||
continue;
|
||||
|
||||
// Setup our events.
|
||||
mWindows[i]->appEvent.notify(this, &GFXTestFullscreenToggle::handleAppEvent);
|
||||
mWindows[i]->buttonEvent.notify(this, &GFXTestFullscreenToggle::handleButtonEvent);
|
||||
mWindows[i]->displayEvent.notify(this, &GFXTestFullscreenToggle::handleDrawEvent);
|
||||
|
||||
// Only subscribe to the first idle event.
|
||||
if(i==0)
|
||||
mWindows[i]->idleEvent.notify(this, &GFXTestFullscreenToggle::handleIdleEvent);
|
||||
}
|
||||
|
||||
// And, go on our way.
|
||||
while(Process::processEvents())
|
||||
;
|
||||
|
||||
// Finally, clean up.
|
||||
for(S32 i=0; i<NumWindows; i++)
|
||||
SAFE_DELETE(mWindows[i]);
|
||||
|
||||
mDevice->preDestroy();
|
||||
SAFE_DELETE(mDevice);
|
||||
SAFE_DELETE(mWindowManager);
|
||||
}
|
||||
};
|
||||
|
|
@ -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,35 +20,39 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "unit/test.h"
|
||||
#include "core/util/tFixedSizeDeque.h"
|
||||
#ifdef TORQUE_TESTS_ENABLED
|
||||
#include "testing/unitTesting.h"
|
||||
#include "windowManager/platformWindowMgr.h"
|
||||
|
||||
|
||||
using namespace UnitTesting;
|
||||
|
||||
#define TEST( x ) test( ( x ), "FAIL: " #x )
|
||||
|
||||
CreateUnitTest( TestFixedSizeDeque, "Util/FixedSizeDeque" )
|
||||
// Mysteriously, TEST(WindowManager, BasicAPI) gives an error. Huh.
|
||||
TEST(WinMgr, BasicAPI)
|
||||
{
|
||||
void run()
|
||||
PlatformWindowManager *pwm = CreatePlatformWindowManager();
|
||||
|
||||
// Check out the primary desktop area...
|
||||
RectI primary = pwm->getPrimaryDesktopArea();
|
||||
|
||||
EXPECT_TRUE(primary.isValidRect())
|
||||
<< "Got some sort of invalid rect from the window manager!";
|
||||
|
||||
// Now try to get info about all the monitors.
|
||||
Vector<RectI> monitorRects;
|
||||
pwm->getMonitorRegions(monitorRects);
|
||||
|
||||
EXPECT_GT(monitorRects.size(), 0)
|
||||
<< "Should get at least one monitor rect back from getMonitorRegions!";
|
||||
|
||||
// This test is here just to detect overflow/runaway situations. -- BJG
|
||||
EXPECT_LT(monitorRects.size(), 64)
|
||||
<< "Either something's wrong, or you have a lot of monitors...";
|
||||
|
||||
for(S32 i=0; i<monitorRects.size(); i++)
|
||||
{
|
||||
enum { DEQUE_SIZE = 3 };
|
||||
FixedSizeDeque< U32 > deque( DEQUE_SIZE );
|
||||
|
||||
TEST( deque.capacity() == DEQUE_SIZE );
|
||||
TEST( deque.size() == 0 );
|
||||
|
||||
deque.pushFront( 1 );
|
||||
TEST( deque.capacity() == ( DEQUE_SIZE - 1 ) );
|
||||
TEST( deque.size() == 1 );
|
||||
TEST( !deque.isEmpty() );
|
||||
|
||||
deque.pushBack( 2 );
|
||||
TEST( deque.capacity() == ( DEQUE_SIZE - 2 ) );
|
||||
TEST( deque.size() == 2 );
|
||||
|
||||
TEST( deque.popFront() == 1 );
|
||||
TEST( deque.popFront() == 2 );
|
||||
TEST( deque.isEmpty() );
|
||||
EXPECT_TRUE(monitorRects[i].isValidRect())
|
||||
<< "Got an invalid rect for this monitor - no good.";
|
||||
}
|
||||
|
||||
// No way to destroy the window manager.
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,13 +1,5 @@
|
|||
new GuiControlProfile(GuiDefaultProfile);
|
||||
new GuiControlProfile(GuiToolTipProfile);
|
||||
new GuiCanvas(Canvas);
|
||||
function onLightManagerActivate() {}
|
||||
function onLightManagerDeactivate() {}
|
||||
Canvas.setWindowTitle("Torque 3D Unit Tests");
|
||||
new RenderPassManager(DiffuseRenderPassManager);
|
||||
setLightManager("Basic Lighting");
|
||||
setLogMode(2);
|
||||
$Con::LogBufferEnabled = false;
|
||||
$Testing::checkMemoryLeaks = false;
|
||||
runAllUnitTests();
|
||||
$Testing::CheckMemoryLeaks = false;
|
||||
runAllUnitTests("-*.Stress*");
|
||||
quit();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,5 @@
|
|||
new GuiControlProfile(GuiDefaultProfile);
|
||||
new GuiControlProfile(GuiToolTipProfile);
|
||||
new GuiCanvas(Canvas);
|
||||
function onLightManagerActivate() {}
|
||||
function onLightManagerDeactivate() {}
|
||||
Canvas.setWindowTitle("Torque 3D Unit Tests");
|
||||
new RenderPassManager(DiffuseRenderPassManager);
|
||||
setLightManager("Basic Lighting");
|
||||
setLogMode(2);
|
||||
$Con::LogBufferEnabled = false;
|
||||
$Testing::checkMemoryLeaks = false;
|
||||
runAllUnitTests();
|
||||
$Testing::CheckMemoryLeaks = false;
|
||||
runAllUnitTests("-*.Stress*");
|
||||
quit();
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ option(TORQUE_EXTENDED_MOVE "Extended move support" OFF)
|
|||
mark_as_advanced(TORQUE_EXTENDED_MOVE)
|
||||
option(TORQUE_NAVIGATION "Enable Navigation module" OFF)
|
||||
#mark_as_advanced(TORQUE_NAVIGATION)
|
||||
option(TORQUE_TESTING "Enable unit test module" OFF)
|
||||
mark_as_advanced(TORQUE_TESTING)
|
||||
if(WIN32)
|
||||
option(TORQUE_OPENGL "Allow OpenGL render" OFF)
|
||||
#mark_as_advanced(TORQUE_OPENGL)
|
||||
|
|
@ -170,12 +172,10 @@ addPath("${srcDir}/core/util/test")
|
|||
addPath("${srcDir}/core/util/journal")
|
||||
addPath("${srcDir}/core/util/journal/test")
|
||||
addPath("${srcDir}/core/util/zip")
|
||||
addPath("${srcDir}/core/util/zip/unitTests")
|
||||
addPath("${srcDir}/core/util/zip/test")
|
||||
addPath("${srcDir}/core/util/zip/compressors")
|
||||
addPath("${srcDir}/i18n")
|
||||
addPath("${srcDir}/sim")
|
||||
#addPath("${srcDir}/unit/tests")
|
||||
addPath("${srcDir}/unit")
|
||||
addPath("${srcDir}/util")
|
||||
addPath("${srcDir}/windowManager")
|
||||
addPath("${srcDir}/windowManager/torque")
|
||||
|
|
@ -192,6 +192,7 @@ endif()
|
|||
addPath("${srcDir}/platform/test")
|
||||
addPath("${srcDir}/platform/threads")
|
||||
addPath("${srcDir}/platform/async")
|
||||
addPath("${srcDir}/platform/async/test")
|
||||
addPath("${srcDir}/platform/input")
|
||||
addPath("${srcDir}/platform/output")
|
||||
addPath("${srcDir}/app")
|
||||
|
|
@ -331,6 +332,10 @@ else()
|
|||
addPath("${srcDir}/T3D/gameBase/std")
|
||||
endif()
|
||||
|
||||
if(TORQUE_TESTING)
|
||||
include( "modules/module_testing.cmake" )
|
||||
endif()
|
||||
|
||||
if(TORQUE_NAVIGATION)
|
||||
include( "modules/module_navigation.cmake" )
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ addEngineSrcDir('sfx');
|
|||
// Components
|
||||
addEngineSrcDir('component');
|
||||
addEngineSrcDir('component/interfaces');
|
||||
addEngineSrcDir('component/test');
|
||||
|
||||
// Core
|
||||
if (T3D_Generator::isApp())
|
||||
|
|
@ -43,12 +44,10 @@ addEngineSrcDir('core/util/test');
|
|||
addEngineSrcDir('core/util/journal');
|
||||
addEngineSrcDir('core/util/journal/test');
|
||||
addEngineSrcDir('core/util/zip');
|
||||
addEngineSrcDir('core/util/zip/unitTests');
|
||||
addEngineSrcDir('core/util/zip/test');
|
||||
addEngineSrcDir('core/util/zip/compressors');
|
||||
addEngineSrcDir('i18n');
|
||||
addEngineSrcDir('sim');
|
||||
addEngineSrcDir('unit/tests');
|
||||
addEngineSrcDir('unit');
|
||||
addEngineSrcDir('util');
|
||||
addEngineSrcDir('windowManager');
|
||||
addEngineSrcDir('windowManager/torque');
|
||||
|
|
@ -71,7 +70,9 @@ switch( T3D_Generator::$platform )
|
|||
}
|
||||
|
||||
addEngineSrcDir('platform/threads');
|
||||
addEngineSrcDir('platform/threads/test');
|
||||
addEngineSrcDir('platform/async');
|
||||
addEngineSrcDir('platform/async/test');
|
||||
addEngineSrcDir('platform/input');
|
||||
addEngineSrcDir('platform/output');
|
||||
addEngineSrcDir('app');
|
||||
|
|
@ -124,7 +125,6 @@ switch( T3D_Generator::$platform )
|
|||
|
||||
// GFX
|
||||
addEngineSrcDir( 'gfx/Null' );
|
||||
addEngineSrcDir( 'gfx/test' );
|
||||
addEngineSrcDir( 'gfx/bitmap' );
|
||||
addEngineSrcDir( 'gfx/bitmap/loaders' );
|
||||
addEngineSrcDir( 'gfx/util' );
|
||||
|
|
|
|||
Loading…
Reference in a new issue