/* Test-ZReferenceCounter.cpp Author: James Russell Purpose: Unit Test the ZReferenceCounter class. */ #include "ZUnitTest.hpp" #include #include #include // 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(_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; }