| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- #ifndef _RVC_SPTEST_H__
- #define _RVC_SPTEST_H__
- #pragma once
- #include "SpBase.h"
- #include "SpHelper.h"
- #include <vector>
- //helper macro for test temporary.
- #define TEST_MODE_SWITCH_ON 1
- #if (defined(TEST_MODE_SWITCH_ON) && TEST_MODE_SWITCH_ON == 1)
- #define IFFAILRET(func) \
- do { \
- ErrorCodeEnum errorCode = func; \
- if (errorCode != Error_Succeed) { \
- LogError(Severity_High, Error_Failed, 0,\
- CSimpleStringA::Format("Invoke \"" #func "\" failed ec=%s! at file: <%s>, line: %d",\
- SpStrError(errorCode), _GetFileName(__FILE__), __LINE__));\
- return Error_Failed; \
- } \
- } while (false)
- #define IFFAILBREAK(func) \
- do { \
- ErrorCodeEnum errorCode = func; \
- if (errorCode != Error_Succeed) { \
- LogError(Severity_High, Error_Failed, 0,\
- CSimpleStringA::Format("Invoke \"" #func "\" failed ec=%s! at file: <%s>, line: %d",\
- SpStrError(errorCode), _GetFileName(__FILE__), __LINE__));\
- return; \
- } \
- } while (false)
- #define REQUIRE(expr) \
- do { \
- if (!(expr)) { \
- LogError(Severity_High, Error_Failed, 0,\
- CSimpleStringA::Format("expression (\"" #expr "\") requires failed! at file: <%s>, line: %d", _GetFileName(__FILE__), __LINE__));\
- return Error_Failed; \
- } \
- } while (false)
- #define CHECK(expr) \
- do { \
- if (!(expr)) { \
- LogError(Severity_High, Error_Failed, 0,\
- CSimpleStringA::Format("expression (\"" #expr "\") requires failed! at file: <%s>, line: %d", _GetFileName(__FILE__), __LINE__));\
- return; \
- } \
- } while (false)
- #define THROW_FATAL(fmt, ...) \
- LogError(Severity_High, Error_Failed, 0, \
- CSimpleStringA::Format("%s at file: <%s>, line: %d", \
- (LPCTSTR)CSimpleStringA::Format(fmt, ##__VA_ARGS__), _GetFileName(__FILE__), __LINE__))
- #define THROW_ERROR(fmt, ...) \
- LogError(Severity_Middle, Error_Failed, 0, \
- CSimpleStringA::Format("%s at file: <%s>, line: %d", \
- (LPCTSTR)CSimpleStringA::Format(fmt, ##__VA_ARGS__), _GetFileName(__FILE__), __LINE__))
- #else
- #define IFFAILRET(func) ((void)0)
- #define IFFAILBREAK(func) ((void)0)
- #define REQUIRE(expr) ((void)0)
- #define CHECK(expr) ((void)0)
- #define THROW_FATAL(fmt, ...) ((void)0)
- #define THROW_ERROR(fmt, ...) ((void)0)
- #endif
- #define REQUIRE_FALSE(expr) \
- REQUIRE(!(expr))
- #define CHECK_FALSE(expr) \
- CHECK(!(expr))
- /** Entity's MOCK Context*/
- SPBASE_API CSmartPointer<ITransactionContext>
- CreateMockTransactionContext(CSmartPointer<IEntityFunction> entityFunction);
- /** Test Case */
- struct TestCaseService_RunTest_Req
- {
- CSimpleStringA strParam;
- void Serialize(SpBuffer& Buf)
- {
- auto& buf = Buf & strParam;
- }
- };
- struct TestCaseService_RunTest_Ans
- {
- DWORD dwUserCode;
- void Serialize(SpBuffer& Buf)
- {
- auto& buf = Buf & dwUserCode;
- }
- };
- void SimulateTestCastEndPoint(SpReqAnsContext< TestCaseService_RunTest_Req, TestCaseService_RunTest_Ans>::Pointer ctx)
- {
- ctx->Answer(Error_Failed);
- }
- struct IMethodTestCase
- {
- virtual ErrorCodeEnum RunTest() = 0;
- virtual ~IMethodTestCase() {};
- };
- struct TestCaseStatistics
- {
- DWORD dwTotalTestCaseNum;
- DWORD dwAcceptTestCaseNum;
- DWORD dwFailureTestCaseNum;
- DWORD dwIgnoreTestCaseNum;
- TestCaseStatistics() = default;
- void Reset()
- {
- dwTotalTestCaseNum = 0;
- dwAcceptTestCaseNum = 0;
- dwFailureTestCaseNum = 0;
- dwIgnoreTestCaseNum = 0;
- }
- void Clear()
- {
- const DWORD dwCaseNum = dwTotalTestCaseNum;
- Reset();
- dwTotalTestCaseNum = dwCaseNum;
- }
- };
- template<typename T>
- class ITestCaseSuite
- {
- public:
- ITestCaseSuite() = default;
- virtual ~ITestCaseSuite();
- typedef T* TestObjectPointer;
- typedef void(T::* TestCaseEntry)(CSmartPointer<ITransactionContext> pTransactionContext);
- template<class TReq, class TAns>
- struct MethodTestCaseT : public SpReqAnsContext<TReq, TAns>, public IMethodTestCase
- {
- using Pointer = CSmartPointer<SpReqAnsContext<TReq, TAns> >;
- /*Prototype of Test Case Function*/
- typedef ErrorCodeEnum(T::* ToTestFuncProto)(Pointer ctx);
- MethodTestCaseT(CEntityBase* ent, ToTestFuncProto testFunc)
- :SpReqAnsContext<TReq, TAns>(m_spMockTransactionContext),m_enti(ent), m_testFunc(testFunc)
- ,m_errorCode(Error_IgnoreAll),m_dwUserCode(0)
- { }
- virtual void PreTest() {/*To Set member Req value*/}
- virtual ErrorCodeEnum PostTest()
- {
- LOG_FUNCTION();
- /*To Check result member Ans's validity, only if the 'RunTest' returned Error_Succeed, then this function would be invoked.
- *if detect the value contained by 'Ans' not the dream one, return ErrorCode except Error_Succeed
- *Or*/return Error_Succeed;
- }
- ErrorCodeEnum RunTest()
- {
- LOG_FUNCTION();
- if (m_testFunc && m_enti)
- {
- PreTest();
- TestObjectPointer that = static_cast<TestObjectPointer>(m_enti);
-
- (that->*m_testFunc)(GetCtx());
- #if 0
- DWORD dwUserCode = 0, dwNoUsed = 0;
- ErrorCodeEnum result = m_spMockTransactionContext->GetExpireTime(dwUserCode, dwNoUsed);
- #else
- ErrorCodeEnum result = m_errorCode;
- #endif
- Dbg("errorCode: %s", SpStrError(result));
-
- return (((result == Error_Succeed) ? PostTest() : result));
- }
- return Error_IgnoreAll;
- }
- ErrorCodeEnum Answer(ErrorCodeEnum Error = Error_Succeed)
- {
- LOG_FUNCTION();
- m_errorCode = Error;
- return Error_Succeed;
- }
- ErrorCodeEnum Answer(ErrorCodeEnum eSysError, DWORD dwUserError)
- {
- LOG_FUNCTION();
- m_errorCode = eSysError;
- m_dwUserCode = dwUserError;
- return Error_Succeed;
- }
- private:
- Pointer GetCtx()
- {
- Pointer pt = this;
- pt.AddRef();
- return pt;
- }
- private:
- CEntityBase* m_enti;
- ToTestFuncProto m_testFunc;
- ErrorCodeEnum m_errorCode;
- DWORD m_dwUserCode;
- };
- typedef std::vector<TestCaseEntry> TestCaseSet;
- void AddTestCaseEntry(TestCaseEntry entry);
- typedef std::vector<IMethodTestCase*> MethodTestCaseSet;
- void AddTestMethodEntry(IMethodTestCase* testMethod);
- protected:
- virtual ErrorCodeEnum RunTestCase();
- /** user can override this function to add any other test, but do not
- invoke 'AddTestCaseEntry' and 'AddTestMethodEntry' method at this scope!!!!*/
- virtual ErrorCodeEnum CustomTestCase() { return Error_Succeed; }
- private:
- TestCaseSet m_testCases;
- MethodTestCaseSet m_testMethods;
- TestCaseStatistics m_testStatistcs;
- static CSmartPointer<ITransactionContext> m_spMockTransactionContext;
- };
- /*!
- * [Gifur@2020519]
- * declare Transaction context as static type for some reason:
- * 1. when creating SpReqAnsContext class object, we must convey a CSmartPointer<ITransactionContext> type param to initialize,
- * if we create it at the same time, we cannot get it anymore because it has been declared as private at SpReqAnsContext, but we must
- * hook it to mock real test result without changing any functional code which I really unwill to see it!
- * 2. subclass MethodTestCaseT inherited from SpReqAnsContext cannot initialize earlier than SpReqAnsContext as children class, so we
- * cannot declare a 'CSmartPointer<ITransactionContext>' type member and initialze it first then convey it to SpReqAnsContext.
- * 3. multi-thead unsafe !!!
- */
- template<typename TClass>
- CSmartPointer<ITransactionContext> ITestCaseSuite<TClass>::m_spMockTransactionContext = CreateMockTransactionContext(nullptr);
- template<typename T>
- ITestCaseSuite<T>::~ITestCaseSuite()
- {
- for (auto& r : m_testMethods) {
- if (r) {
- delete r;
- r = NULL;
- }
- }
- }
- /** 'TestCaseEntry' Prototype: void Entity::Function(CSmartPointer<ITransactionContext> pTransactionContext)
- * User should declare and implement it.
- */
- template<typename TClass>
- void ITestCaseSuite<TClass>::AddTestCaseEntry(TestCaseEntry entry)
- {
- m_testCases.push_back(entry);
- m_testStatistcs.dwTotalTestCaseNum++;
- }
- template<typename TClass>
- void ITestCaseSuite<TClass>::AddTestMethodEntry(IMethodTestCase* testMethod)
- {
- m_testMethods.push_back(testMethod);
- m_testStatistcs.dwTotalTestCaseNum++;
- }
- template<typename TClass>
- ErrorCodeEnum ITestCaseSuite<TClass>::RunTestCase()
- {
- LOG_FUNCTION();
- m_testStatistcs.Clear();
- UINT testCaseNum = 0;
- TestObjectPointer that = static_cast<TestObjectPointer>(this);
- if (!m_testCases.empty()) {
- auto it = m_testCases.begin();
- while (it != m_testCases.end()) {
- ++testCaseNum;
- Dbg("Run TestCase#%d...", testCaseNum);
- CSmartPointer<ITransactionContext> mock = CreateMockTransactionContext(that->GetFunction());
- (that->*(*it))(mock);
- DWORD dwUserCode = 0, dwNoUsed = 0;
- ErrorCodeEnum result = mock->GetExpireTime(dwUserCode, dwNoUsed);
- if (IS_FAILURED(result) && result != Error_IgnoreAll) {
- THROW_ERROR("TestCase#%d test failed return %s(userCode: 0x%X)", testCaseNum, SpStrError(result), dwUserCode);
- m_testStatistcs.dwFailureTestCaseNum++;
- }
- else if (result == Error_IgnoreAll) {
- m_testStatistcs.dwIgnoreTestCaseNum++;
- }
- else {
- m_testStatistcs.dwAcceptTestCaseNum++;
- }
- it++;
- }
- }
- UINT testMethodNum = 0;
- if (!m_testMethods.empty())
- {
- auto it = m_testMethods.begin();
- while (it != m_testMethods.end()) {
- ++testMethodNum;
- Dbg("Run TestMethod#%d...", testMethodNum);
- ErrorCodeEnum result = (*it)->RunTest();
- if (IS_FAILURED(result) && result != Error_IgnoreAll) {
- THROW_FATAL("TestMethod#%d test failed return %s", testMethodNum, SpStrError(result));
- m_testStatistcs.dwFailureTestCaseNum++;
- }
- else if (result == Error_IgnoreAll) {
- m_testStatistcs.dwIgnoreTestCaseNum++;
- }
- else {
- m_testStatistcs.dwAcceptTestCaseNum++;
- }
- it++;
- }
- }
- return (m_testStatistcs.dwFailureTestCaseNum > 0) ? Error_Failed : Error_Succeed;
- }
- #define TESTCASE_OVERRIDE_ON_EXAM_AND_IMPLEMENT() \
- void OnExam(CSmartPointer<ITransactionContext> pTransactionContext) override \
- { \
- LOG_FUNCTION(); \
- ErrorCodeEnum testResult = RunTestCase(); \
- if (testResult == Error_Succeed || testResult == Error_IgnoreAll) { \
- testResult = CustomTestCase(); \
- pTransactionContext->SendAnswer(testResult); \
- } else { \
- pTransactionContext->SendAnswer(testResult); \
- } \
- }
- #define TESTCASE_DECLARE_BEGIN(serviceName, testFuncName) \
- void Test_##testFuncName(CSmartPointer<ITransactionContext> pTransactionContext) {\
- SpReqAnsContext< serviceName##_##testFuncName##_Req, serviceName##_##testFuncName##_Ans>::Pointer ctx = \
- new SpReqAnsContext< serviceName##_##testFuncName##_Req, serviceName##_##testFuncName##_Ans>(pTransactionContext)
- /*User to Set the member value */
- #define TESTCASE_DECLARE_INVOKE(testFuncName) \
- do {\
- DWORD dwUserCode = 0, dwNoUsed = 0;\
- testFuncName(ctx);\
- ErrorCodeEnum result = mock->GetExpireTime(dwUserCode, dwNoUsed);\
- if (IS_FAILURED(result)) { return; }\
- } while (false)
- #define TESTCASE_DECLARE_END(testFuncName) \
- }
- #endif //_RVC_SPTEST_H__
|