Skip to content

Commit

Permalink
Add more unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
endurodave committed Dec 16, 2024
1 parent 13a90de commit 785ddbb
Show file tree
Hide file tree
Showing 7 changed files with 316 additions and 13 deletions.
9 changes: 9 additions & 0 deletions src/Port/WorkerThreadStd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ std::thread::id WorkerThread::GetCurrentThreadId()
return this_thread::get_id();
}

//----------------------------------------------------------------------------
// GetQueueSize
//----------------------------------------------------------------------------
size_t WorkerThread::GetQueueSize()
{
lock_guard<mutex> lock(m_mutex);
return m_queue.size();
}

//----------------------------------------------------------------------------
// ExitThread
//----------------------------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions src/Port/WorkerThreadStd.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class WorkerThread : public DelegateLib::DelegateThread
/// Get the ID of the currently executing thread
static std::thread::id GetCurrentThreadId();

/// Get size of thread message queue.
size_t GetQueueSize();

virtual void DispatchDelegate(std::shared_ptr<DelegateLib::DelegateMsg> msg);

private:
Expand Down
3 changes: 0 additions & 3 deletions tests/UnitTests/DelegateAsyncWait_UT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
#include "UnitTestCommon.h"
#include <iostream>
#include "WorkerThreadStd.h"
#ifdef WIN32
#include <Windows.h>
#endif

using namespace DelegateLib;
using namespace std;
Expand Down
3 changes: 0 additions & 3 deletions tests/UnitTests/DelegateAsync_UT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
#include "UnitTestCommon.h"
#include <iostream>
#include "WorkerThreadStd.h"
#ifdef WIN32
#include <Windows.h>
#endif

using namespace DelegateLib;
using namespace std;
Expand Down
292 changes: 292 additions & 0 deletions tests/UnitTests/DelegateThreads_UT.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
#include "DelegateLib.h"
#include "UnitTestCommon.h"
#include <iostream>
#include "WorkerThreadStd.h"
#include <random>
#include <chrono>

using namespace DelegateLib;
using namespace std;
using namespace UnitTestData;

static WorkerThread workerThread1("DelegateThreads1_UT");
static WorkerThread workerThread2("DelegateThreads2_UT");

static std::mutex m_lock;
static const int LOOPS = 10;
static const int CNT_MAX = 7;
static int callerCnt[CNT_MAX] = { 0 };

static void Wait()
{
// Wait for tests to complete. Test complete when thread queues empty.
while (workerThread1.GetQueueSize() != 0 &&
workerThread2.GetQueueSize() != 0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

static std::chrono::milliseconds getRandomTime()
{
// Create a random number generator and a uniform distribution
std::random_device rd; // Non-deterministic random number generator
std::mt19937 gen(rd()); // Mersenne Twister engine initialized with rd
std::uniform_int_distribution<> dis(0, 10); // Uniform distribution between 0 and 10

// Generate a random number (between 0 and 10 milliseconds)
int random_ms = dis(gen);

// Return the random number as a chrono::milliseconds object
return std::chrono::milliseconds(random_ms);
}

static void FreeThreadSafe(std::chrono::milliseconds delay, int idx)
{
const std::lock_guard<std::mutex> lock(m_lock);
callerCnt[idx]++;
std::this_thread::sleep_for(delay);
}

static std::function<void(std::chrono::milliseconds, int)> LambdaThreadSafe = [](std::chrono::milliseconds delay, int idx)
{
const std::lock_guard<std::mutex> lock(m_lock);
callerCnt[idx]++;
std::this_thread::sleep_for(delay);
};

class TestClass
{
public:
void MemberThreadSafe(std::chrono::milliseconds delay, int idx)
{
const std::lock_guard<std::mutex> lock(m_lock);
callerCnt[idx]++;
std::this_thread::sleep_for(delay);
}
};

static void FreeTests()
{
std::memset(callerCnt, 0, sizeof(callerCnt));

auto delegateSync1 = MakeDelegate(&FreeThreadSafe);
auto delegateSync2 = MakeDelegate(&FreeThreadSafe);
auto delegateAsync1 = MakeDelegate(&FreeThreadSafe, workerThread1);
auto delegateAsync2 = MakeDelegate(&FreeThreadSafe, workerThread2);
auto delegateAsyncWait1 = MakeDelegate(&FreeThreadSafe, workerThread1, std::chrono::milliseconds(500));
auto delegateAsyncWait2 = MakeDelegate(&FreeThreadSafe, workerThread1, std::chrono::milliseconds(500));

MulticastDelegateSafe<void(std::chrono::milliseconds, int)> container;
container += delegateSync1;
container += delegateSync2;
container += delegateAsync1;
container += delegateAsync2;
container += delegateAsyncWait1;
container += delegateAsyncWait2;

int cnt = 0;
int cnt2 = 0;
while (cnt++ < LOOPS)
{
delegateSync1(getRandomTime(), 0);
delegateSync2(getRandomTime(), 1);

auto retVal1 = delegateAsyncWait1.AsyncInvoke(getRandomTime(), 4);
ASSERT_TRUE(retVal1.has_value());
auto retVal2 = delegateAsyncWait2.AsyncInvoke(getRandomTime(), 5);
ASSERT_TRUE(retVal2.has_value());

while (cnt2++ < 5)
{
delegateAsync1(getRandomTime(), 2);
delegateAsync2(getRandomTime(), 3);
}
cnt2 = 0;
container(getRandomTime(), 6);
}

Wait();

ASSERT_TRUE(callerCnt[0] == LOOPS);
ASSERT_TRUE(callerCnt[1] == LOOPS);
ASSERT_TRUE(callerCnt[2] == LOOPS * 5);
ASSERT_TRUE(callerCnt[3] == LOOPS * 5);
ASSERT_TRUE(callerCnt[4] == LOOPS);
ASSERT_TRUE(callerCnt[5] == LOOPS);
ASSERT_TRUE(callerCnt[6] == LOOPS * 6);
std::cout << "FreeTests() complete!" << std::endl;
}

static void MemberTests()
{
std::memset(callerCnt, 0, sizeof(callerCnt));
TestClass testClass;

auto delegateSync1 = MakeDelegate(&testClass, &TestClass::MemberThreadSafe);
auto delegateSync2 = MakeDelegate(&testClass, &TestClass::MemberThreadSafe);
auto delegateAsync1 = MakeDelegate(&testClass, &TestClass::MemberThreadSafe, workerThread1);
auto delegateAsync2 = MakeDelegate(&testClass, &TestClass::MemberThreadSafe, workerThread2);
auto delegateAsyncWait1 = MakeDelegate(&testClass, &TestClass::MemberThreadSafe, workerThread1, std::chrono::milliseconds(500));
auto delegateAsyncWait2 = MakeDelegate(&testClass, &TestClass::MemberThreadSafe, workerThread1, std::chrono::milliseconds(500));

MulticastDelegateSafe<void(std::chrono::milliseconds, int)> container;
container += delegateSync1;
container += delegateSync2;
container += delegateAsync1;
container += delegateAsync2;
container += delegateAsyncWait1;
container += delegateAsyncWait2;

int cnt = 0;
int cnt2 = 0;
while (cnt++ < LOOPS)
{
delegateSync1(getRandomTime(), 0);
delegateSync2(getRandomTime(), 1);

auto retVal1 = delegateAsyncWait1.AsyncInvoke(getRandomTime(), 4);
ASSERT_TRUE(retVal1.has_value());
auto retVal2 = delegateAsyncWait2.AsyncInvoke(getRandomTime(), 5);
ASSERT_TRUE(retVal2.has_value());

while (cnt2++ < 5)
{
delegateAsync1(getRandomTime(), 2);
delegateAsync2(getRandomTime(), 3);
}
cnt2 = 0;
container(getRandomTime(), 6);
}

Wait();

ASSERT_TRUE(callerCnt[0] == LOOPS);
ASSERT_TRUE(callerCnt[1] == LOOPS);
ASSERT_TRUE(callerCnt[2] == LOOPS * 5);
ASSERT_TRUE(callerCnt[3] == LOOPS * 5);
ASSERT_TRUE(callerCnt[4] == LOOPS);
ASSERT_TRUE(callerCnt[5] == LOOPS);
ASSERT_TRUE(callerCnt[6] == LOOPS * 6);
std::cout << "MemberTests() complete!" << std::endl;
}

static void MemberSpTests()
{
std::memset(callerCnt, 0, sizeof(callerCnt));
auto testClass = std::make_shared<TestClass>();

auto delegateSync1 = MakeDelegate(testClass, &TestClass::MemberThreadSafe);
auto delegateSync2 = MakeDelegate(testClass, &TestClass::MemberThreadSafe);
auto delegateAsync1 = MakeDelegate(testClass, &TestClass::MemberThreadSafe, workerThread1);
auto delegateAsync2 = MakeDelegate(testClass, &TestClass::MemberThreadSafe, workerThread2);
auto delegateAsyncWait1 = MakeDelegate(testClass, &TestClass::MemberThreadSafe, workerThread1, std::chrono::milliseconds(500));
auto delegateAsyncWait2 = MakeDelegate(testClass, &TestClass::MemberThreadSafe, workerThread1, std::chrono::milliseconds(500));

MulticastDelegateSafe<void(std::chrono::milliseconds, int)> container;
container += delegateSync1;
container += delegateSync2;
container += delegateAsync1;
container += delegateAsync2;
container += delegateAsyncWait1;
container += delegateAsyncWait2;

int cnt = 0;
int cnt2 = 0;
while (cnt++ < LOOPS)
{
delegateSync1(getRandomTime(), 0);
delegateSync2(getRandomTime(), 1);

auto retVal1 = delegateAsyncWait1.AsyncInvoke(getRandomTime(), 4);
ASSERT_TRUE(retVal1.has_value());
auto retVal2 = delegateAsyncWait2.AsyncInvoke(getRandomTime(), 5);
ASSERT_TRUE(retVal2.has_value());

while (cnt2++ < 5)
{
delegateAsync1(getRandomTime(), 2);
delegateAsync2(getRandomTime(), 3);
}
cnt2 = 0;
container(getRandomTime(), 6);
}

Wait();

ASSERT_TRUE(callerCnt[0] == LOOPS);
ASSERT_TRUE(callerCnt[1] == LOOPS);
ASSERT_TRUE(callerCnt[2] == LOOPS * 5);
ASSERT_TRUE(callerCnt[3] == LOOPS * 5);
ASSERT_TRUE(callerCnt[4] == LOOPS);
ASSERT_TRUE(callerCnt[5] == LOOPS);
ASSERT_TRUE(callerCnt[6] == LOOPS * 6);
std::cout << "MemberSpTests() complete!" << std::endl;
}

static void FunctionTests()
{
std::memset(callerCnt, 0, sizeof(callerCnt));

auto delegateSync1 = MakeDelegate(LambdaThreadSafe);
auto delegateSync2 = MakeDelegate(LambdaThreadSafe);
auto delegateAsync1 = MakeDelegate(LambdaThreadSafe, workerThread1);
auto delegateAsync2 = MakeDelegate(LambdaThreadSafe, workerThread2);
auto delegateAsyncWait1 = MakeDelegate(LambdaThreadSafe, workerThread1, std::chrono::milliseconds(500));
auto delegateAsyncWait2 = MakeDelegate(LambdaThreadSafe, workerThread1, std::chrono::milliseconds(500));

MulticastDelegateSafe<void(std::chrono::milliseconds, int)> container;
container += delegateSync1;
container += delegateSync2;
container += delegateAsync1;
container += delegateAsync2;
container += delegateAsyncWait1;
container += delegateAsyncWait2;

int cnt = 0;
int cnt2 = 0;
while (cnt++ < LOOPS)
{
delegateSync1(getRandomTime(), 0);
delegateSync2(getRandomTime(), 1);

auto retVal1 = delegateAsyncWait1.AsyncInvoke(getRandomTime(), 4);
ASSERT_TRUE(retVal1.has_value());
auto retVal2 = delegateAsyncWait2.AsyncInvoke(getRandomTime(), 5);
ASSERT_TRUE(retVal2.has_value());

while (cnt2++ < 5)
{
delegateAsync1(getRandomTime(), 2);
delegateAsync2(getRandomTime(), 3);
}
cnt2 = 0;
container(getRandomTime(), 6);
}

Wait();

ASSERT_TRUE(callerCnt[0] == LOOPS);
ASSERT_TRUE(callerCnt[1] == LOOPS);
ASSERT_TRUE(callerCnt[2] == LOOPS * 5);
ASSERT_TRUE(callerCnt[3] == LOOPS * 5);
ASSERT_TRUE(callerCnt[4] == LOOPS);
ASSERT_TRUE(callerCnt[5] == LOOPS);
ASSERT_TRUE(callerCnt[6] == LOOPS * 6);
std::cout << "FunctionTests() complete!" << std::endl;
}

void DelegateThreads_UT()
{
workerThread1.CreateThread();
workerThread2.CreateThread();

FreeTests();
MemberTests();
MemberSpTests();
FunctionTests();

workerThread1.ExitThread();
workerThread2.ExitThread();
}
16 changes: 12 additions & 4 deletions tests/UnitTests/DelegateUnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2575,12 +2575,21 @@ void DelegateMemberAsyncWaitTests()
extern void Delegate_UT();
extern void DelegateAsync_UT();
extern void DelegateAsyncWait_UT();
extern void DelegateThreads_UT();

void DelegateUnitTests()
{
Delegate_UT();
DelegateAsync_UT();
DelegateAsyncWait_UT();
try
{
Delegate_UT();
DelegateAsync_UT();
DelegateAsyncWait_UT();
DelegateThreads_UT();
}
catch (const std::exception& e)
{
std::cout << "Unit Tests Failed: " << e.what() << std::endl;
}

testThread.CreateThread();

Expand Down Expand Up @@ -2613,7 +2622,6 @@ void DelegateUnitTests()
std::cout << "Unit Tests Failed: " << e.what() << std::endl;
}


#ifdef WIN32
QueryPerformanceCounter(&EndingTime);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
Expand Down
3 changes: 0 additions & 3 deletions tests/UnitTests/Delegate_UT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
#include "UnitTestCommon.h"
#include <iostream>
#include "WorkerThreadStd.h"
#ifdef WIN32
#include <Windows.h>
#endif

using namespace DelegateLib;
using namespace std;
Expand Down

0 comments on commit 785ddbb

Please sign in to comment.