mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-04 21:10:32 +00:00
separate testing environment
-Separate main for running unit tests -Move unit tests into testing folder
This commit is contained in:
parent
2e8f5795fa
commit
c09f79d199
265 changed files with 84537 additions and 334 deletions
|
|
@ -1,178 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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"
|
||||
|
||||
struct TcpHandle
|
||||
{
|
||||
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 = NetSocket::INVALID;
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Net, TCPRequest)
|
||||
{
|
||||
TcpHandle handler;
|
||||
|
||||
handler.mSocket = NetSocket::INVALID;
|
||||
handler.mDataReceived = 0;
|
||||
|
||||
// Hook into the signals.
|
||||
Net::smConnectionNotify ->notify(&handler, &TcpHandle::notify);
|
||||
Net::smConnectionReceive->notify(&handler, &TcpHandle::receive);
|
||||
|
||||
// Open a TCP connection to torque3d.org
|
||||
handler.mSocket = Net::openConnectTo("108.61.193.195:80");
|
||||
const U32 limit = Platform::getRealMilliseconds() + (5*1000);
|
||||
while(Process::processEvents() && (Platform::getRealMilliseconds() < limit) ) {}
|
||||
|
||||
// Unhook from the signals.
|
||||
Net::smConnectionNotify ->remove(&handler, &TcpHandle::notify);
|
||||
Net::smConnectionReceive->remove(&handler, &TcpHandle::receive);
|
||||
|
||||
EXPECT_GT(handler.mDataReceived, 0)
|
||||
<< "Didn't get any data back!";
|
||||
}
|
||||
|
||||
struct JournalHandle
|
||||
{
|
||||
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 = NetSocket::INVALID;
|
||||
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 = NetSocket::INVALID;
|
||||
mDataReceived = 0;
|
||||
|
||||
// Hook into the signals.
|
||||
Net::smConnectionNotify ->notify(this, &JournalHandle::notify);
|
||||
Net::smConnectionReceive->notify(this, &JournalHandle::receive);
|
||||
|
||||
// Open a TCP connection to torque3d.org
|
||||
mSocket = Net::openConnectTo("108.61.193.195:80");
|
||||
|
||||
// Let the callbacks enable things to process.
|
||||
while(Process::processEvents()) {}
|
||||
|
||||
// Unhook from the signals.
|
||||
Net::smConnectionNotify ->remove(this, &JournalHandle::notify);
|
||||
Net::smConnectionReceive->remove(this, &JournalHandle::receive);
|
||||
|
||||
EXPECT_GT(mDataReceived, 0)
|
||||
<< "Didn't get any data back!";
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Net, JournalTCPRequest)
|
||||
{
|
||||
JournalHandle 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
|
||||
|
|
@ -1,122 +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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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");
|
||||
|
||||
// Sleep for a tick
|
||||
Platform::sleep(32);
|
||||
|
||||
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(32);
|
||||
|
||||
// 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/Linux have no implementations for these functions, so we 'def it out for now.
|
||||
#ifdef WIN32
|
||||
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
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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!";
|
||||
};
|
||||
|
||||
struct handle
|
||||
{
|
||||
S32 mElapsedTime;
|
||||
S32 mNumberCalls;
|
||||
|
||||
handle() : mElapsedTime(0), mNumberCalls(0) {}
|
||||
|
||||
void timeEvent(S32 timeDelta)
|
||||
{
|
||||
mElapsedTime += timeDelta;
|
||||
mNumberCalls++;
|
||||
|
||||
if(mElapsedTime >= 1000)
|
||||
Process::requestShutdown();
|
||||
}
|
||||
};
|
||||
|
||||
TEST(TimeManager, BasicAPI)
|
||||
{
|
||||
handle handler;
|
||||
|
||||
// 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
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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,49 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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" // Allows us to see TORQUE_ENABLE_PROFILER
|
||||
|
||||
#ifdef TORQUE_ENABLE_PROFILER
|
||||
#include "testing/unitTesting.h"
|
||||
#include "platform/profiler.h"
|
||||
|
||||
TEST(Profiler, ProfileStartEnd)
|
||||
{
|
||||
PROFILE_START(ProfileStartEndTest);
|
||||
// Do work.
|
||||
if(true)
|
||||
{
|
||||
PROFILE_END();
|
||||
return;
|
||||
}
|
||||
PROFILE_END();
|
||||
}
|
||||
|
||||
TEST(Profiler, ProfileScope)
|
||||
{
|
||||
PROFILE_SCOPE(ScopedProfilerTest);
|
||||
// Do work and return whenever you want.
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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,121 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/threadPool.h"
|
||||
#include "console/console.h"
|
||||
#include "core/util/tVector.h"
|
||||
|
||||
FIXTURE(ThreadPool)
|
||||
{
|
||||
public:
|
||||
// Represents a single unit of work. In this test we just set an element in
|
||||
// a result vector.
|
||||
struct TestItem : public ThreadPool::WorkItem
|
||||
{
|
||||
U32 mIndex;
|
||||
Vector<U32>& mResults;
|
||||
TestItem(U32 index, Vector<U32>& results)
|
||||
: mIndex(index), mResults(results) {}
|
||||
|
||||
protected:
|
||||
virtual void execute()
|
||||
{
|
||||
mResults[mIndex] = mIndex;
|
||||
}
|
||||
};
|
||||
|
||||
// A worker that delays for some time. We'll use this to test the ThreadPool's
|
||||
// synchronous and asynchronous operations.
|
||||
struct DelayItem : public ThreadPool::WorkItem
|
||||
{
|
||||
U32 ms;
|
||||
DelayItem(U32 _ms) : ms(_ms) {}
|
||||
|
||||
protected:
|
||||
virtual void execute()
|
||||
{
|
||||
Platform::sleep(ms);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
pool->waitForAllItems();
|
||||
|
||||
// Verify.
|
||||
for (U32 i = 0; i < numItems; i++)
|
||||
EXPECT_EQ(results[i], i) << "result mismatch";
|
||||
results.clear();
|
||||
}
|
||||
|
||||
TEST_FIX(ThreadPool, Asynchronous)
|
||||
{
|
||||
const U32 delay = 500; //ms
|
||||
|
||||
// Launch a single delaying work item.
|
||||
ThreadPool* pool = &ThreadPool::GLOBAL();
|
||||
ThreadSafeRef<DelayItem> item(new DelayItem(delay));
|
||||
pool->queueWorkItem(item);
|
||||
|
||||
// The thread should not yet be finished.
|
||||
EXPECT_EQ(false, item->hasExecuted());
|
||||
|
||||
// Wait til the item should have completed.
|
||||
Platform::sleep(delay * 2);
|
||||
|
||||
EXPECT_EQ(true, item->hasExecuted());
|
||||
}
|
||||
|
||||
TEST_FIX(ThreadPool, Synchronous)
|
||||
{
|
||||
const U32 delay = 500; //ms
|
||||
|
||||
// Launch a single delaying work item.
|
||||
ThreadPool* pool = &ThreadPool::GLOBAL();
|
||||
ThreadSafeRef<DelayItem> item(new DelayItem(delay));
|
||||
pool->queueWorkItem(item);
|
||||
|
||||
// Wait for the item to complete.
|
||||
pool->waitForAllItems();
|
||||
|
||||
EXPECT_EQ(true, item->hasExecuted());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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*)
|
||||
{
|
||||
S32 timeOut = mValues.size() * 32;
|
||||
U32 endTime = Platform::getRealMilliseconds() + timeOut;
|
||||
|
||||
for (U32 i = 0; i < mValues.size(); i++)
|
||||
{
|
||||
ValueRef value;
|
||||
bool timedOut = false;
|
||||
while (!mDeque.tryPopFront(value))
|
||||
{
|
||||
if (timeOut && Platform::getRealMilliseconds() >= endTime)
|
||||
{
|
||||
timedOut = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
ASSERT_FALSE(timedOut)
|
||||
<< "consumer thread timed out!";
|
||||
|
||||
if (timedOut) return;
|
||||
|
||||
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 many items in a row
|
||||
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();
|
||||
};
|
||||
/*
|
||||
// Test a few items many times to catch any race-condition in start-up
|
||||
TEST_FIX(ThreadSafeDeque, Concurrent2)
|
||||
{
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
Deque mDeque;
|
||||
Vector<U32> mValues;
|
||||
|
||||
mValues.setSize(5);
|
||||
|
||||
ProducerThread pThread(mValues, mDeque);
|
||||
ConsumerThread cThread(mValues, mDeque);
|
||||
|
||||
cThread.start();
|
||||
pThread.start();
|
||||
|
||||
pThread.join();
|
||||
cThread.join();
|
||||
|
||||
mValues.clear();
|
||||
if (::testing::Test::HasFailure()) break;
|
||||
}
|
||||
};
|
||||
*/
|
||||
#endif
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.2f, 0.7f, 0.4f, 0.6f, 0.1f, 0.5f, 0.3f, 0.8f, 0.6f, 0.9f, 0.0f};
|
||||
|
||||
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.2f, 0.7f, 0.4f, 0.6f, 0.1f, 0.5f, 0.3f, 0.8f, 0.6f, 0.9f, 0.0f};
|
||||
|
||||
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
|
||||
|
|
@ -1,205 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue