Files
libsst/ZTestSuite/Test-ZReferenceCounter.cpp
2026-04-03 00:22:39 -05:00

107 lines
3.8 KiB
C++

/*
Test-ZReferenceCounter.cpp
Author: James Russell <jcrussell@762studios.com>
Purpose: Unit Test the ZReferenceCounter class.
*/
#include "ZUnitTest.hpp"
#include <ZUtil/ZConcurrency.hpp>
#include <ZUtil/ZReferenceCounter.hpp>
#include <SST/SST_Thread.h> // SST_Concurrency_YieldThread()
static const char* test_GainLoseReferences();
static const char* test_Signal();
//List of unit tests
ZUnitTest ZReferenceCounterUnitTests[] =
{
{ "ZReferenceCounter: Gain / Lose References", test_GainLoseReferences },
{ "ZReferenceCounter: Signal", test_Signal }
};
//Now declare the ZUnitTestBlock associated with this.
DECLARE_ZTESTBLOCK(ZReferenceCounter);
/*************************************************************************/
static const char* test_GainLoseReferences()
{
ZReferenceCounter counter;
//Ensure both start at zero
TASSERT(counter.GetStrongRefCount() == 0, "Strong count set to non-zero value on default construct!");
TASSERT(counter.GetWeakRefCount() == 0, "Weak count set to non-zero value on default construct!");
//Test GainStrongRef()
counter.GainStrongRef();
TASSERT(counter.GetStrongRefCount() == 1, "Strong count not equal to 1 after strong reference gained!");
//Test GainWeakRef()
counter.GainWeakRef();
counter.GainWeakRef();
TASSERT(counter.GetWeakRefCount() == 2, "Weak count not equal to 2 after double increment!");
//Test validity of both counters after weak ref decrement
uint32_t combinedCount = counter.LoseWeakRef();
TASSERT(ZREFCOUNTER_EXTRACT_STRONG_REF(combinedCount) == 1, "After losing weak reference, strong count does not equal one!");
TASSERT(ZREFCOUNTER_EXTRACT_WEAK_REF(combinedCount) == 1, "After losing weak reference, weak count does not equal one!");
//Test validity of both counters after strong ref decrement
combinedCount = counter.LoseStrongRef();
TASSERT(ZREFCOUNTER_EXTRACT_STRONG_REF(combinedCount) == 0, "After losing strong reference, strong count does not equal zero!");
TASSERT(ZREFCOUNTER_EXTRACT_WEAK_REF(combinedCount) == 1, "After losing strong reference, weak count does not equal one!");
//Test validity of both counters when all references are lost
combinedCount = counter.LoseWeakRef();
TASSERT(ZREFCOUNTER_EXTRACT_STRONG_REF(combinedCount) == 0, "After losing second weak reference, strong count does not equal zero!");
TASSERT(ZREFCOUNTER_EXTRACT_WEAK_REF(combinedCount) == 0, "After losing second weak reference, weak count does not equal one!");
return ZTEST_SUCCESS;
}
/*************************************************************************/
static int signalDeallocate(void* _refCounter)
{
//This should block
reinterpret_cast<ZReferenceCounter*>(_refCounter)->SignalDeallocateObject();
return 0;
}
static const char* test_Signal()
{
ZReferenceCounter counter;
counter.GainStrongRef();
counter.GainWeakRef();
TASSERT(counter.GetStrongRefCount() == 1, "Strong count incorrect after GainStrongRef!");
TASSERT(counter.GetWeakRefCount() == 1, "Weak count incorrect after GainWeakRef!");
TASSERT(counter.SignalInUse(), "SignalInUse returned false when it should be valid to use!");
TASSERT(counter.State > 0, "State not increased after SignalInUse!");
ZThreadContext ctxt = ZConcurrency::CreateThread(signalDeallocate, &counter);
//At this point, the other thread should be waiting on this one, but
//should signal us by setting state to NULL with an atomic XOR
while (counter.State > 0)
SST_Concurrency_YieldThread();
TASSERT(counter.SignalInUse() == false, "SignalInUse returned true when it should be invalid to use!");
counter.SignalUnused(); //This should allow the thread to return from the SignalDeallocate method
ZConcurrency::WaitThread(ctxt);
ZConcurrency::DestroyThread(ctxt);
TASSERT(counter.State == (-1 & ZREFCOUNTER_DEALLOC_BIT), "State variable invalid after SignalDeallocate and SignalUnused!");
return ZTEST_SUCCESS;
}