123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930 |
- #ifndef _RVC_SPTEST_H__
- #define _RVC_SPTEST_H__
- #pragma once
- #include "SpBase.h"
- #include "SpHelper.h"
- #include "SpComm.hpp"
- #include "SpUtility.hpp"
- #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 /*defined(TEST_MODE_SWITCH_ON) && TEST_MODE_SWITCH_ON == 1*/
- #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() { Reset(); }
- 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_pEntity(ent), m_testFunc(testFunc)
- ,m_errorCode(Error_IgnoreAll),m_dwUserCode(0)
- {
- /** empty. */
- }
- virtual void PreTest() {/* user should set context request content at Req structure.*/}
- virtual ErrorCodeEnum PostTest()
- {
- LOG_FUNCTION();
- /*User should check response content Ans's validity
- *if detect the value conveied by 'Ans' is not the dream one, return ErrorCode except Error_Succeed
- *Or*/return Error_Succeed;
- /*Tips: Only if the 'RunTest()' returned Error_Succeed, then this function would be invoked.*/
- }
- ErrorCodeEnum RunTest()
- {
- LOG_FUNCTION();
- if (m_testFunc && m_pEntity)
- {
- PreTest();
- TestObjectPointer that = static_cast<TestObjectPointer>(m_pEntity);
-
- (that->*m_testFunc)(GetCtx());
- #if 0
- DWORD dwUserCode = 0, dwNoUsed = 0;
- const ErrorCodeEnum result = m_spMockTransactionContext->GetExpireTime(dwUserCode, dwNoUsed);
- #else
- const 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_pEntity;
- 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 AdditionalTest() { 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_ERROR("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 = AdditionalTest(); \
- pTransactionContext->SendAnswer(testResult); \
- } else { \
- pTransactionContext->SendAnswer(testResult); \
- } \
- }
- /** experiment below */
- #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 et the member value */
- #define TESTCASE_DECLARE_INVOKE(testFuncName) \
- do {\
- DWORD dwUserCode = 0, dwNoUsed = 0;\
- Test_##testFuncName(ctx);\
- ErrorCodeEnum result = mock->GetExpireTime(dwUserCode, dwNoUsed);\
- if (IS_FAILURED(result)) { return; }\
- } while (false)
- #define TESTCASE_DECLARE_END(testFuncName) \
- }
- //////////////////////////////////////////////////////////////////////////
- using namespace SP::Detail;
- class TestCase;
- using TestFunction = ErrorCodeEnum(*)();
- struct Counters {
- Counters() :passed(0), failed(0) {}
- std::size_t Total() const { return (passed + failed); }
- bool AllPassed() const { return (failed == 0); }
- std::size_t passed;
- std::size_t failed;
- };
- struct TestStatistics {
- Counters testCases;
- };
- struct ITestRunner {
- virtual ~ITestRunner() {};
- virtual TestStatistics RunTest(TestCase const& testCase) = 0;
- };
- struct TestConfig
- {
- std::string filterTag;
- };
- struct ITestCaseRegistry
- {
- virtual ~ITestCaseRegistry() {}
- /** TODO: relate with Entity Name*/
- virtual std::vector<TestCase> const& getAllTests(TestConfig const& config) const = 0;
- };
- struct ITestRegistryHub {
- virtual ~ITestRegistryHub() {}
- virtual void RegisterTest(TestCase const& testInfo) = 0;
- virtual ITestCaseRegistry const& GetTestCaseRegistry() const = 0;
- };
- SPBASE_API ITestRegistryHub& GetRegistryHub();
- /** TODO: hide*/
- SPBASE_API TestCase MakeTestCase(IMethodTestCase* testCase,
- std::string const& className,
- std::string const& name,
- std::string const& desc,
- SourceLineInfo const& lineInfo);
- SPBASE_API void RegisterTestCase(IMethodTestCase* testCase, char const* className,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo);
- SPBASE_API void RegisterTestCaseFunction(TestFunction function,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo
- );
- template<typename TClass>
- class MethodTestCase : public IMethodTestCase {
- public :
- MethodTestCase(ErrorCodeEnum(TClass::* method)()) : m_method(method) {}
- virtual ErrorCodeEnum RunTest() {
- TClass obj;
- return (obj.*m_method)();
- //return Error_Succeed;
- }
- private:
- virtual ~MethodTestCase() {}
- ErrorCodeEnum(TClass::* m_method)();
- };
- class DefaultFuncTestCase : public IMethodTestCase {
- public:
- DefaultFuncTestCase(TestFunction func) :m_func(func) {}
- virtual ErrorCodeEnum RunTest() {
- return m_func();
- }
- private:
- virtual ~DefaultFuncTestCase() {};
- TestFunction m_func;
- };
- template<typename TClass, class TReq, class TAns>
- struct TwoWayContextTestCase : public SpReqAnsContext<TReq, TAns>, public IMethodTestCase {
- using Pointer = CSmartPointer<SpReqAnsContext<TReq, TAns> >;
- using TestTwoWayFunc = ErrorCodeEnum(TClass::*)(Pointer ctx);
- using TestTwoWayFuncVoid = void(TClass::*)(Pointer ctx);
- TwoWayContextTestCase(TClass* testee, TestTwoWayFunc func, TestTwoWayFuncVoid funVoid)
- :SpReqAnsContext<TReq, TAns>(CreateMockTransactionContext(nullptr))
- ,m_obj(testee), m_func(func), m_voidFunc(funVoid), m_errorCode(Error_IgnoreAll), m_dwUserCode(0) {
- }
- TwoWayContextTestCase(TClass* testee, TestTwoWayFunc func)
- :TwoWayContextTestCase(nullptr, func, nullptr){}
- TwoWayContextTestCase(TClass* testee, TestTwoWayFuncVoid func)
- :TwoWayContextTestCase(nullptr, nullptr, func) {}
- TwoWayContextTestCase(TestTwoWayFunc func) :TwoWayContextTestCase(nullptr, func){ }
- TwoWayContextTestCase(TestTwoWayFuncVoid func) : TwoWayContextTestCase(nullptr, func) { }
- virtual void PreTest() {/* user should set context request content at Req structure.*/ }
- virtual ErrorCodeEnum PostTest()
- {
- LOG_FUNCTION();
- /*User should check response content Ans's validity
- *if detect the value conveied by 'Ans' is not the dream one, return ErrorCode except Error_Succeed
- *Or*/return Error_Succeed;
- /*Tips: Only if the 'RunTest()' returned Error_Succeed, then this function would be invoked.*/
- }
- virtual ErrorCodeEnum RunTest()
- {
- ErrorCodeEnum result = Error_IgnoreAll;
- TClass obj;
- bool flag = false;
- if (m_obj == nullptr)
- flag = !!(m_obj = &obj);
- PreTest();
- if (m_func != nullptr)
- {
- result = (m_obj->*m_func)(GetCtx());
- }
- else if (m_voidFunc != nullptr)
- {
- (m_obj->*m_voidFunc)(GetCtx());
- result = Error_Succeed;
- }
- result = (result == Error_Succeed) ? m_errorCode : result;
-
- Dbg("TwoWayContextTestCase->errorCode: %s", SpStrError(result));
- if (flag) m_obj = nullptr;
- return (((result == Error_Succeed) ? PostTest() : result));
- }
- ErrorCodeEnum Answer(ErrorCodeEnum Error = Error_Succeed) override
- {
- LOG_FUNCTION();
- m_errorCode = Error;
- return Error_Succeed;
- }
- ErrorCodeEnum Answer(ErrorCodeEnum eSysError, DWORD dwUserError) override
- {
- LOG_FUNCTION();
- m_errorCode = eSysError;
- m_dwUserCode = dwUserError;
- return Error_Succeed;
- }
- private:
- CSmartPointer<ITransactionContext> m_mockCtx = CreateMockTransactionContext(nullptr);
- Pointer GetCtx()
- {
- Pointer pt = this;
- pt.AddRef();
- return pt;
- }
- TestTwoWayFunc m_func;
- TestTwoWayFuncVoid m_voidFunc;
- TClass* m_obj;
- ErrorCodeEnum m_errorCode;
- DWORD m_dwUserCode;
- };
- struct TestAutoReg {
- TestAutoReg() {}
- ~TestAutoReg() {}
- /** for test simple func*/
- TestAutoReg(TestFunction function,
- SourceLineInfo const& lineInfo,
- NameAndDesc const& nameAndDesc
- )
- {
- RegisterTestCaseFunction(function, nameAndDesc, lineInfo);
- }
- /** for test Class*/
- template<typename TClass>
- TestAutoReg(
- ErrorCodeEnum(TClass::* method)(),
- char const* lpcszClassName,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo)
- {
- RegisterTestCase(new MethodTestCase<TClass>(method), lpcszClassName, nameAndDesc, lineInfo);
- }
- TestAutoReg(
- IMethodTestCase* testCaseImpl,
- char const* lpcszClassName,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo)
- {
- RegisterTestCase(testCaseImpl, lpcszClassName, nameAndDesc, lineInfo);
- }
- /** for test Class's context*/
- template<typename TClass>
- TestAutoReg(
- void(TClass::* method)(),
- char const* lpcszClassName,
- NameAndDesc const& nameAndDesc,
- SourceLineInfo const& lineInfo)
- {
- //RegisterTestCase(new MethodTestCase<TClass>(method), lpcszClassName, nameAndDesc, lineInfo);
- }
- };
- struct TestCaseInfo {
- TestCaseInfo(std::string const& name, std::string const& className, std::string const& desc, SourceLineInfo const& info)
- :strName(name.c_str()), strClassName(className.c_str()),strDescription(desc.c_str()), lineInfo(info) {}
- TestCaseInfo(TestCaseInfo const& other)
- :TestCaseInfo(other.strName, other.strClassName, other.strDescription, other.lineInfo)
- {/*delegrate directory*/}
- std::string strName;
- std::string strClassName;
- std::string strDescription;
- SourceLineInfo lineInfo;
- };
- class TestCase : public TestCaseInfo
- {
- public:
- TestCase(IMethodTestCase* testCase, TestCaseInfo const& info): TestCaseInfo(info), m_testCase(testCase) {}
- TestCase(TestCase const& other)
- :TestCaseInfo(other), m_testCase(other.m_testCase) {}
- TestCaseInfo const& GetTestInfo() const { return *this; }
- /** for anonymous case regist*/
- TestCase CloneExceptName(std::string const& newName) const {
- TestCase newCase(*this);
- newCase.strName = newName;
- return newCase;
- }
- ErrorCodeEnum RunTest() const
- {
- return m_testCase->RunTest();
- }
- private:
- CSmartPointer<IMethodTestCase> m_testCase;
- };
- class TestRunner : public ITestRunner
- {
- public:
- TestStatistics RunTest(TestCase const& testCase)
- {
- try {
- testCase.RunTest();
- }
- catch (std::exception& ex) {
- }
- return TestStatistics();
- }
- };
- #define RVC_INTERVAL_UNIQUE_NAME_LINE2( name, line ) name##line
- #define RVC_INTERVAL_UNIQUE_NAME_LINE( name, line ) RVC_INTERVAL_UNIQUE_NAME_LINE2( name, line )
- #define RVC_INTERVAL_UNIQUE_NAME(name) RVC_INTERVAL_UNIQUE_NAME_LINE(name, __COUNTER__)
- #define RVC_INTERVAL_STRINGFY(name) #name
- #define INTERNAL_RVC_TEST_CASE_METHOD2(TestName, ClassName, ...) \
- namespace { \
- struct TestName : ClassName { \
- ErrorCodeEnum Test(); \
- }; \
- TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName::Test, RVC_INTERVAL_STRINGFY(ClassName), SP::Detail::NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
- } \
- ErrorCodeEnum TestName::Test()
- #define INTERNAL_RVC_TEST_CASE_METHOD(ClassName, ...) \
- INTERNAL_RVC_TEST_CASE_METHOD2(RVC_INTERVAL_UNIQUE_NAME(CVRssalCtseTduS), ClassName, __VA_ARGS__)
- #define INTERNAL_RVC_TESTCASE2(TestName, ...) \
- static ErrorCodeEnum TestName(); \
- namespace { \
- TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName, SP_INTERNAL_LINEINFO, SP::Detail::NameAndDesc(__VA_ARGS__)); \
- } \
- static ErrorCodeEnum TestName()
- #define INTERNAL_RVC_TESTCASE(...) \
- INTERNAL_RVC_TESTCASE2(RVC_INTERVAL_UNIQUE_NAME(CVRcnuFtseTduS), __VA_ARGS__)
- #define RVC_TWO_WAY_SECTION(ServiceName, ContextName) \
- void Test_##ServiceName_##ContextName() { \
- CSmartPointer<ITransactionContext> mock = CreateMockTransactionContext(this->GetFunction()); \
- SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>::Pointer ctx = \
- new SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>(mock); \
- }
- #define RVC_TWO_WAY_INVOKE(TestFuncName) \
- testFunc = TestFuncName; \
- }\
- ErrorCodeEnum TestName::PostTest_##ContextName(ServiceName##_##ContextName##_Ans const& Ans) \
-
- #include <functional>
- #define SECTION_INNER(StructName, ...) \
- struct StructName : public TwoWayContextReqAnsImpl { \
- void Test(); \
- }; \
- void StructName::Test()
- #define SECTION(...) \
- SECTION_INNER(RVC_INTERVAL_UNIQUE_NAME(CVRnoitceStseTduS), __VA_ARGS__)
- #define TWO_WAY_CHECK_ANSWER_BEGIN(ansName) \
- checkAnsFunc = [](TwoWayResultType const& ansName) -> ErrorCodeEnum {
- #define TWO_WAY_CHECK_ANSWER_END() };
- #define INTERNAL_RVC_TEST_CASE_CONTEXT_TWO_WAY2(TestName, ClassName, ServiceName, ContextName, TestFuncName, ...) \
- namespace { \
- struct TestName : ClassName { \
- CSmartPointer<ITransactionContext> mMockTrans; \
- SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>::Pointer mCtx;\
- using TwoWayResultType = ServiceName##_##ContextName##_Ans; \
- void (ClassName::*testFuncVoid)(SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>::Pointer);\
- ErrorCodeEnum (ClassName::*testFunc)(SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>::Pointer);\
- ErrorCodeEnum testRes; \
- std::function<ErrorCodeEnum(ServiceName##_##ContextName##_Ans const&)> checkAnsFunc; \
- TestName():mMockTrans(CreateMockTransactionContext(this->GetFunction())), \
- mCtx(new SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>(mMockTrans)) \
- , testFuncVoid(nullptr),testFunc(nullptr), testRes(Error_Succeed), checkAnsFunc(nullptr) { \
- testFunc = &ClassName::TestFuncName; \
- }\
- void PreTest_##ContextName(ServiceName##_##ContextName##_Req& Req); \
- ErrorCodeEnum PostTest_##ContextName() { \
- return checkAnsFunc == nullptr ? Error_Succeed : checkAnsFunc(mCtx->Ans); \
- } \
- ErrorCodeEnum Test_##ContextName() { \
- PreTest_##ContextName(mCtx->Req); \
- if(testFuncVoid != nullptr) { \
- (this->*testFuncVoid)(mCtx); \
- } \
- else if(testFunc != nullptr) { \
- testRes =(this->*testFunc)(mCtx); \
- } \
- if(testRes == Error_Succeed) { \
- DWORD dwUserCode = 0, dwNoUsed = 0; \
- testRes = mMockTrans->GetExpireTime(dwUserCode, dwNoUsed); \
- } \
- if(testRes == Error_Succeed) { \
- testRes = PostTest_##ContextName(); \
- } else if(testRes == Error_IgnoreAll) \
- testRes = Error_Succeed; \
- return testRes; \
- } \
- struct TwoWayContextReqAnsImpl : \
- public TwoWayContextTestCase<ClassName, ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans> \
- { \
- }; \
- }; \
- TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName::Test_##ContextName, RVC_INTERVAL_STRINGFY(ClassName), SP::Detail::NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
- } \
- void TestName::PreTest_##ContextName(ServiceName##_##ContextName##_Req& Req)
-
- #define INTERNAL_RVC_TEST_CASE_CONTEXT_TWO_WAY(EntityClassName, ServiceName, TestFuncName, ContextName, ...) \
- INTERNAL_RVC_TEST_CASE_CONTEXT_TWO_WAY2(RVC_INTERVAL_UNIQUE_NAME(CVRytitnEtseTduS), EntityClassName, ServiceName, ContextName, TestFuncName, __VA_ARGS__)
- #define INTERNAL_RVC_TEST_CASE_CONTEXT2(TestName, ClassName, ...) \
- namespace { \
- struct TestName : ClassName { \
- CSmartPointer<ITransactionContext> mMockTrans; \
- TestName():mMockTrans(CreateMockTransactionContext(this->GetFunction())){}; \
- ErrorCodeEnum Test() { \
- TestContext(mMockTrans); \
- DWORD dwUserCode = 0, dwNoUsed = 0; \
- ErrorCodeEnum testRes = mMockTrans->GetExpireTime(dwUserCode, dwNoUsed); \
- return (testRes == Error_IgnoreAll) ? Error_Succeed : testRes; \
- } \
- void TestContext(CSmartPointer<ITransactionContext> pTransactionContext); \
- }; \
- TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName::Test, RVC_INTERVAL_STRINGFY(ClassName), SP::Detail::NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
- } \
- void TestName::TestContext(CSmartPointer<ITransactionContext> pTransactionContext)
-
- #define INTERNAL_RVC_TEST_CASE_CONTEXT(EntityClassName, ...) \
- INTERNAL_RVC_TEST_CASE_CONTEXT2(RVC_INTERVAL_UNIQUE_NAME(CVRytitnEtseTduS), EntityClassName, __VA_ARGS__)
- ///////////////////////////////////////////////////////////////////////////////
- struct Tolerate {
- enum Choice
- {
- Strict,
- Ignore
- };
- };
- template<typename T>
- struct Matcher {
- Tolerate::Choice level = Tolerate::Ignore;
- std::string strExpr;
- std::function<bool(T const&)> exprFunc;
- SourceLineInfo lineInfo;
- Matcher(Tolerate::Choice const& choice, std::string const& desc, std::function<bool(T const&)>&& expr, SourceLineInfo const& info)
- :level(choice), strExpr(desc), exprFunc(expr),lineInfo(info) {}
- };
- # define RVC_INTERNAL_STRINGIFY(expr) #expr
- #define INTERNAL_RVC_REGISTER_TEST_CASE_CONTEXT2(TestName, EntityClassName, ServiceName, ContextName, ...) \
- namespace { \
- struct TestName : TwoWayContextTestCase<EntityClassName, ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans> { \
- TestName(TestTwoWayFunc func):TwoWayContextTestCase(func){ Initial(); }\
- void Initial(); \
- using TwoWayResultType = ServiceName##_##ContextName##_Ans; \
- using AnsMatcher = Matcher<TwoWayResultType>; \
- using AnsMachers = std::vector< AnsMatcher >; \
- AnsMachers matchers; \
- ErrorCodeEnum PostTest() { \
- ErrorCodeEnum result = Error_Succeed; \
- for( AnsMachers::const_iterator it = matchers.begin(), itEnd = matchers.end(); it != itEnd;++it) { \
- if (((it->exprFunc)(Ans))) { \
- } else { \
- Dbg("Test \" %s \" failed %s", it->strExpr.c_str(), it->lineInfo.ToString().c_str()); \
- if(it->level == Tolerate::Strict) { result = Error_MisMatched; break; } \
- } \
- } \
- return result; \
- } \
- }; \
- TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)( new TestName(&EntityClassName::ContextName) , RVC_INTERVAL_STRINGFY(EntityClassName), SP::Detail::NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
- } \
- void TestName::Initial()
-
- #define INTERNAL_RVC_REGISTER_TEST_CASE_CONTEXT(EntityClassName, ServiceName, ContextName, ... ) \
- INTERNAL_RVC_REGISTER_TEST_CASE_CONTEXT2(RVC_INTERVAL_UNIQUE_NAME(CVRtxetnoCtseTduS), EntityClassName, ServiceName, ContextName, __VA_ARGS__)
- #define INNER_ANSWER_CHECK(Expression, Description, TolerateLevel) \
- do { \
- auto f = [](TwoWayResultType const& Ans)->bool { return ( Expression ); }; \
- AnsMatcher matchInst(TolerateLevel, std::string(Description), f, SP_INTERNAL_LINEINFO); \
- matchers.push_back(matchInst); \
- } while (false)
- #define ANSWER_CHECK(expr) INNER_ANSWER_CHECK(expr, RVC_INTERNAL_STRINGIFY(expr), Tolerate::Ignore)
- #define ANSWER_REQUIRE(expr) INNER_ANSWER_CHECK(expr, RVC_INTERNAL_STRINGIFY(expr), Tolerate::Strict)
- /** Export for user*/
- #define RVC_TEST_CASE( ... ) INTERNAL_RVC_TESTCASE( __VA_ARGS__ )
- #define RVC_TEST_CASE_METHOD(className, ...) INTERNAL_RVC_TEST_CASE_METHOD( className, __VA_ARGS__ )
- #define RVC_TEST_CASE_VOID_CONTEXT(entityClassName, ...) INTERNAL_RVC_TEST_CASE_CONTEXT( entityClassName, __VA_ARGS__ )
- #define RVC_TEST_CASE_CONTEXT_TWO_WAY(entityClassName, serviceName, contextName, ...) INTERNAL_RVC_TEST_CASE_CONTEXT_TWO_WAY(entityClassName, serviceName, contextName, contextName, __VA_ARGS__)
- #define RVC_REGISTER_TEST_CASE_CONTEXT(entityClassName, serviceName, contextName, ... ) INTERNAL_RVC_REGISTER_TEST_CASE_CONTEXT(entityClassName, serviceName, contextName, __VA_ARGS__ )
- #endif //_RVC_SPTEST_H__
|