|
|
@@ -145,151 +145,191 @@ struct IMethodTestCase
|
|
|
{
|
|
|
virtual ErrorCodeEnum RunTest() = 0;
|
|
|
virtual ~IMethodTestCase() {};
|
|
|
+ //void BindEntity(CEntityBase* const pEntity) { pEntityBase = pEntity; }
|
|
|
+ //CEntityBase* pEntityBase = nullptr;
|
|
|
};
|
|
|
|
|
|
-struct TestCaseStatistics
|
|
|
+template<typename TClass>
|
|
|
+class MethodTestCase : public IMethodTestCase
|
|
|
{
|
|
|
- DWORD dwTotalTestCaseNum;
|
|
|
- DWORD dwAcceptTestCaseNum;
|
|
|
- DWORD dwFailureTestCaseNum;
|
|
|
- DWORD dwIgnoreTestCaseNum;
|
|
|
-
|
|
|
- TestCaseStatistics() { Reset(); }
|
|
|
-
|
|
|
- void Reset()
|
|
|
- {
|
|
|
- dwTotalTestCaseNum = 0;
|
|
|
- dwAcceptTestCaseNum = 0;
|
|
|
- dwFailureTestCaseNum = 0;
|
|
|
- dwIgnoreTestCaseNum = 0;
|
|
|
+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)();
|
|
|
+};
|
|
|
|
|
|
- void Clear()
|
|
|
- {
|
|
|
- const DWORD dwCaseNum = dwTotalTestCaseNum;
|
|
|
- Reset();
|
|
|
- dwTotalTestCaseNum = dwCaseNum;
|
|
|
+using TestFunction = ErrorCodeEnum(*)();
|
|
|
+
|
|
|
+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 T>
|
|
|
-class ITestCaseSuite
|
|
|
+template<typename TClass, class TReq, class TAns>
|
|
|
+struct TwoWayContextTestCaseT : public SpReqAnsContext<TReq, TAns>, public IMethodTestCase
|
|
|
{
|
|
|
-public:
|
|
|
+ using Pointer = CSmartPointer<SpReqAnsContext<TReq, TAns> >;
|
|
|
+ using TestTwoWayFunc = ErrorCodeEnum(TClass::*)(Pointer ctx);
|
|
|
+ using TestTwoWayFuncVoid = void(TClass::*)(Pointer ctx);
|
|
|
|
|
|
- ITestCaseSuite() = default;
|
|
|
- virtual ~ITestCaseSuite();
|
|
|
+ TwoWayContextTestCaseT(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) {
|
|
|
+ }
|
|
|
|
|
|
- typedef T* TestObjectPointer;
|
|
|
+ TwoWayContextTestCaseT(TClass* testee, TestTwoWayFunc func)
|
|
|
+ :TwoWayContextTestCaseT(nullptr, func, nullptr) {}
|
|
|
|
|
|
- typedef void(T::* TestCaseEntry)(CSmartPointer<ITransactionContext> pTransactionContext);
|
|
|
+ TwoWayContextTestCaseT(TClass* testee, TestTwoWayFuncVoid func)
|
|
|
+ :TwoWayContextTestCaseT(nullptr, nullptr, func) {}
|
|
|
|
|
|
- template<class TReq, class TAns>
|
|
|
- struct MethodTestCaseT : public SpReqAnsContext<TReq, TAns>, public IMethodTestCase
|
|
|
+ TwoWayContextTestCaseT(TestTwoWayFunc func) :TwoWayContextTestCaseT(nullptr, func) { }
|
|
|
+ TwoWayContextTestCaseT(TestTwoWayFuncVoid func) : TwoWayContextTestCaseT(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.*/
|
|
|
+ }
|
|
|
|
|
|
- using Pointer = CSmartPointer<SpReqAnsContext<TReq, TAns> >;
|
|
|
+ virtual ErrorCodeEnum RunTest()
|
|
|
+ {
|
|
|
+ ErrorCodeEnum result = Error_IgnoreAll;
|
|
|
+ TClass obj;
|
|
|
+ bool flag = false;
|
|
|
|
|
|
- /*Prototype of Test Case Function*/
|
|
|
- typedef ErrorCodeEnum(T::* ToTestFuncProto)(Pointer ctx);
|
|
|
+ if (m_obj == nullptr)
|
|
|
+ flag = !!(m_obj = &obj);
|
|
|
|
|
|
- MethodTestCaseT(CEntityBase* ent, ToTestFuncProto testFunc)
|
|
|
- :SpReqAnsContext<TReq, TAns>(m_spMockTransactionContext),m_pEntity(ent), m_testFunc(testFunc)
|
|
|
- ,m_errorCode(Error_IgnoreAll),m_dwUserCode(0)
|
|
|
- {
|
|
|
- /** empty. */
|
|
|
- }
|
|
|
+ PreTest();
|
|
|
|
|
|
- virtual void PreTest() {/* user should set context request content at Req structure.*/}
|
|
|
+ if (m_func != nullptr) {
|
|
|
+ result = (m_obj->*m_func)(GetCtx());
|
|
|
+ }
|
|
|
+ else if (m_voidFunc != nullptr) {
|
|
|
+ (m_obj->*m_voidFunc)(GetCtx());
|
|
|
+ result = Error_Succeed;
|
|
|
+ }
|
|
|
|
|
|
- virtual ErrorCodeEnum PostTest()
|
|
|
- {
|
|
|
- LOG_FUNCTION();
|
|
|
+ result = (result == Error_Succeed) ? m_errorCode : result;
|
|
|
|
|
|
- /*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;
|
|
|
+ Dbg("TwoWayContextTestCaseT->errorCode: %s", SpStrError(result));
|
|
|
|
|
|
- /*Tips: Only if the 'RunTest()' returned Error_Succeed, then this function would be invoked.*/
|
|
|
- }
|
|
|
+ if (flag) m_obj = nullptr;
|
|
|
|
|
|
- ErrorCodeEnum RunTest()
|
|
|
- {
|
|
|
- LOG_FUNCTION();
|
|
|
+ return (((result == Error_Succeed) ? PostTest() : result));
|
|
|
+ }
|
|
|
|
|
|
- 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));
|
|
|
- }
|
|
|
+ ErrorCodeEnum Answer(ErrorCodeEnum Error = Error_Succeed) override
|
|
|
+ {
|
|
|
+ LOG_FUNCTION();
|
|
|
+ m_errorCode = Error;
|
|
|
+ return Error_Succeed;
|
|
|
+ }
|
|
|
|
|
|
- return Error_IgnoreAll;
|
|
|
- }
|
|
|
+ ErrorCodeEnum Answer(ErrorCodeEnum eSysError, DWORD dwUserError) override
|
|
|
+ {
|
|
|
+ LOG_FUNCTION();
|
|
|
+ m_errorCode = eSysError;
|
|
|
+ m_dwUserCode = dwUserError;
|
|
|
+ return Error_Succeed;
|
|
|
+ }
|
|
|
|
|
|
- ErrorCodeEnum Answer(ErrorCodeEnum Error = Error_Succeed)
|
|
|
- {
|
|
|
- LOG_FUNCTION();
|
|
|
+private:
|
|
|
|
|
|
- m_errorCode = Error;
|
|
|
+ Pointer GetCtx()
|
|
|
+ {
|
|
|
+ Pointer pt = this;
|
|
|
+ pt.AddRef();
|
|
|
+ return pt;
|
|
|
+ }
|
|
|
|
|
|
- return Error_Succeed;
|
|
|
- }
|
|
|
+ TestTwoWayFunc m_func;
|
|
|
+ TestTwoWayFuncVoid m_voidFunc;
|
|
|
+ TClass* m_obj;
|
|
|
|
|
|
- ErrorCodeEnum Answer(ErrorCodeEnum eSysError, DWORD dwUserError)
|
|
|
- {
|
|
|
- LOG_FUNCTION();
|
|
|
+ ErrorCodeEnum m_errorCode;
|
|
|
+ DWORD m_dwUserCode;
|
|
|
+};
|
|
|
|
|
|
- m_errorCode = eSysError;
|
|
|
- m_dwUserCode = dwUserError;
|
|
|
+struct TestCaseStatistics
|
|
|
+{
|
|
|
+ std::size_t totalTestCaseNum;
|
|
|
+ std::size_t passedTestCaseNum;
|
|
|
+ std::size_t failureTestCaseNum;
|
|
|
+ std::size_t ignoreTestCaseNum;
|
|
|
|
|
|
- return Error_Succeed;
|
|
|
- }
|
|
|
+ TestCaseStatistics() { Reset(); }
|
|
|
|
|
|
- private:
|
|
|
+ void Reset()
|
|
|
+ {
|
|
|
+ totalTestCaseNum = 0;
|
|
|
+ passedTestCaseNum = 0;
|
|
|
+ failureTestCaseNum = 0;
|
|
|
+ ignoreTestCaseNum = 0;
|
|
|
+ }
|
|
|
|
|
|
- Pointer GetCtx()
|
|
|
- {
|
|
|
- Pointer pt = this;
|
|
|
- pt.AddRef();
|
|
|
- return pt;
|
|
|
- }
|
|
|
+ void Clear()
|
|
|
+ {
|
|
|
+ const std::size_t oldCaseNum = totalTestCaseNum;
|
|
|
+ Reset();
|
|
|
+ totalTestCaseNum = oldCaseNum;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::size_t Total() const { return (totalTestCaseNum); }
|
|
|
|
|
|
- private:
|
|
|
+ bool AllPassed() const { return (failureTestCaseNum == 0); }
|
|
|
+};
|
|
|
|
|
|
- CEntityBase* m_pEntity;
|
|
|
- ToTestFuncProto m_testFunc;
|
|
|
+template<typename T>
|
|
|
+class ITestCaseSuite
|
|
|
+{
|
|
|
+public:
|
|
|
|
|
|
- ErrorCodeEnum m_errorCode;
|
|
|
- DWORD m_dwUserCode;
|
|
|
+ ITestCaseSuite() = default;
|
|
|
+ virtual ~ITestCaseSuite();
|
|
|
+
|
|
|
+ typedef T* TestObjectPointer;
|
|
|
|
|
|
+ template<class TReq, class TAns>
|
|
|
+ struct TwoWayMethodTestCaseT : public TwoWayContextTestCaseT<T, TReq, TAns> {
|
|
|
+ TwoWayMethodTestCaseT(T* pEntity, TestTwoWayFunc testFunc)
|
|
|
+ :TwoWayContextTestCaseT(pEntity, testFunc) {}
|
|
|
};
|
|
|
|
|
|
- typedef std::vector<TestCaseEntry> TestCaseSet;
|
|
|
+ typedef void(T::* TransMethodProto)(CSmartPointer<ITransactionContext> pTransactionContext);
|
|
|
+
|
|
|
+ typedef std::vector<TransMethodProto> TestCaseSet;
|
|
|
|
|
|
- void AddTestCaseEntry(TestCaseEntry entry);
|
|
|
+ void AddTransMethod(TransMethodProto entry);
|
|
|
|
|
|
typedef std::vector<IMethodTestCase*> MethodTestCaseSet;
|
|
|
|
|
|
- void AddTestMethodEntry(IMethodTestCase* testMethod);
|
|
|
+ void AddMethodTestCase(IMethodTestCase* methodCastPtr);
|
|
|
|
|
|
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!!!!*/
|
|
|
+ invoke 'AddTransMethod' and 'AddMethodTestCase' method at this scope!!!!*/
|
|
|
virtual ErrorCodeEnum AdditionalTest() { return Error_Succeed; }
|
|
|
|
|
|
private:
|
|
|
@@ -309,7 +349,7 @@ private:
|
|
|
* 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
|
|
|
+ * 2. subclass TwoWayMethodTestCaseT 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 !!!
|
|
|
*/
|
|
|
@@ -328,21 +368,21 @@ ITestCaseSuite<T>::~ITestCaseSuite()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /* 'TestCaseEntry' Prototype: void Entity::Function(CSmartPointer<ITransactionContext> pTransactionContext)
|
|
|
+ /* 'TransMethodProto' Prototype: void Entity::Function(CSmartPointer<ITransactionContext> pTransactionContext)
|
|
|
* User should declare and implement it.
|
|
|
*/
|
|
|
template<typename TClass>
|
|
|
-void ITestCaseSuite<TClass>::AddTestCaseEntry(TestCaseEntry entry)
|
|
|
+void ITestCaseSuite<TClass>::AddTransMethod(TransMethodProto entry)
|
|
|
{
|
|
|
m_testCases.push_back(entry);
|
|
|
- m_testStatistcs.dwTotalTestCaseNum++;
|
|
|
+ m_testStatistcs.totalTestCaseNum++;
|
|
|
}
|
|
|
|
|
|
template<typename TClass>
|
|
|
-void ITestCaseSuite<TClass>::AddTestMethodEntry(IMethodTestCase* testMethod)
|
|
|
+void ITestCaseSuite<TClass>::AddMethodTestCase(IMethodTestCase* methodCastPtr)
|
|
|
{
|
|
|
- m_testMethods.push_back(testMethod);
|
|
|
- m_testStatistcs.dwTotalTestCaseNum++;
|
|
|
+ m_testMethods.push_back(methodCastPtr);
|
|
|
+ m_testStatistcs.totalTestCaseNum++;
|
|
|
}
|
|
|
|
|
|
template<typename TClass>
|
|
|
@@ -352,7 +392,7 @@ ErrorCodeEnum ITestCaseSuite<TClass>::RunTestCase()
|
|
|
|
|
|
m_testStatistcs.Clear();
|
|
|
|
|
|
- UINT testCaseNum = 0;
|
|
|
+ std::size_t testCaseNum = 0;
|
|
|
TestObjectPointer that = static_cast<TestObjectPointer>(this);
|
|
|
if (!m_testCases.empty())
|
|
|
{
|
|
|
@@ -368,22 +408,22 @@ ErrorCodeEnum ITestCaseSuite<TClass>::RunTestCase()
|
|
|
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++;
|
|
|
+ m_testStatistcs.failureTestCaseNum++;
|
|
|
}
|
|
|
else if (result == Error_IgnoreAll)
|
|
|
{
|
|
|
- m_testStatistcs.dwIgnoreTestCaseNum++;
|
|
|
+ m_testStatistcs.ignoreTestCaseNum++;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- m_testStatistcs.dwAcceptTestCaseNum++;
|
|
|
+ m_testStatistcs.passedTestCaseNum++;
|
|
|
}
|
|
|
|
|
|
it++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- UINT testMethodNum = 0;
|
|
|
+ std::size_t testMethodNum = 0;
|
|
|
if (!m_testMethods.empty())
|
|
|
{
|
|
|
auto it = m_testMethods.begin();
|
|
|
@@ -395,22 +435,22 @@ ErrorCodeEnum ITestCaseSuite<TClass>::RunTestCase()
|
|
|
if (IS_FAILURED(result) && result != Error_IgnoreAll)
|
|
|
{
|
|
|
THROW_ERROR("TestMethod#%d test failed return %s", testMethodNum, SpStrError(result));
|
|
|
- m_testStatistcs.dwFailureTestCaseNum++;
|
|
|
+ m_testStatistcs.failureTestCaseNum++;
|
|
|
}
|
|
|
else if (result == Error_IgnoreAll)
|
|
|
{
|
|
|
- m_testStatistcs.dwIgnoreTestCaseNum++;
|
|
|
+ m_testStatistcs.ignoreTestCaseNum++;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- m_testStatistcs.dwAcceptTestCaseNum++;
|
|
|
+ m_testStatistcs.passedTestCaseNum++;
|
|
|
}
|
|
|
|
|
|
it++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return (m_testStatistcs.dwFailureTestCaseNum > 0) ? Error_Failed : Error_Succeed;
|
|
|
+ return m_testStatistcs.AllPassed() ? Error_Failed : Error_Succeed;
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -428,7 +468,7 @@ void OnExam(CSmartPointer<ITransactionContext> pTransactionContext) override \
|
|
|
}
|
|
|
|
|
|
|
|
|
-/** experiment below */
|
|
|
+///////////////////////////////experiment below///////////////////////////////////////////
|
|
|
|
|
|
#define TESTCASE_DECLARE_BEGIN(serviceName, testFuncName) \
|
|
|
void Test_##testFuncName(CSmartPointer<ITransactionContext> pTransactionContext) {\
|
|
|
@@ -450,40 +490,26 @@ new SpReqAnsContext< serviceName##_##testFuncName##_Req, serviceName##_##testFun
|
|
|
}
|
|
|
|
|
|
|
|
|
+///////////////////////////////experiment end///////////////////////////////////////////
|
|
|
+
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
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 NameAndDesc
|
|
|
+{
|
|
|
+ NameAndDesc(const char* _name = "", const char* _description = "")
|
|
|
+ : name(_name), description(_description)
|
|
|
+ {/*empty*/
|
|
|
+ }
|
|
|
+ const char* name;
|
|
|
+ const char* description;
|
|
|
};
|
|
|
|
|
|
+class TestCase;
|
|
|
|
|
|
-struct ITestRunner {
|
|
|
-
|
|
|
- virtual ~ITestRunner() {};
|
|
|
- virtual TestStatistics RunTest(TestCase const& testCase) = 0;
|
|
|
-
|
|
|
-};
|
|
|
|
|
|
-struct TestConfig
|
|
|
+struct TestConfig
|
|
|
{
|
|
|
std::string filterTag;
|
|
|
};
|
|
|
@@ -495,8 +521,8 @@ struct ITestCaseRegistry
|
|
|
virtual std::vector<TestCase> const& getAllTests(TestConfig const& config) const = 0;
|
|
|
};
|
|
|
|
|
|
-struct ITestRegistryHub {
|
|
|
-
|
|
|
+struct ITestRegistryHub
|
|
|
+{
|
|
|
virtual ~ITestRegistryHub() {}
|
|
|
virtual void RegisterTest(TestCase const& testInfo) = 0;
|
|
|
virtual ITestCaseRegistry const& GetTestCaseRegistry() const = 0;
|
|
|
@@ -520,127 +546,9 @@ SPBASE_API void RegisterTestCaseFunction(TestFunction function,
|
|
|
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 {
|
|
|
+struct TestAutoReg
|
|
|
+{
|
|
|
|
|
|
TestAutoReg() {}
|
|
|
~TestAutoReg() {}
|
|
|
@@ -674,16 +582,6 @@ struct TestAutoReg {
|
|
|
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 {
|
|
|
@@ -730,25 +628,6 @@ private:
|
|
|
|
|
|
};
|
|
|
|
|
|
-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 )
|
|
|
|
|
|
@@ -760,46 +639,27 @@ public:
|
|
|
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); \
|
|
|
+ TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName::Test, RVC_INTERVAL_STRINGFY(ClassName), 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__)); \
|
|
|
+ TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName, SP_INTERNAL_LINEINFO, NameAndDesc(__VA_ARGS__)); \
|
|
|
} \
|
|
|
static ErrorCodeEnum TestName()
|
|
|
|
|
|
-#define INTERNAL_RVC_TESTCASE(...) \
|
|
|
- INTERNAL_RVC_TESTCASE2(RVC_INTERVAL_UNIQUE_NAME(CVRcnuFtseTduS), __VA_ARGS__)
|
|
|
+#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 {
|
|
|
@@ -844,11 +704,11 @@ public:
|
|
|
return testRes; \
|
|
|
} \
|
|
|
struct TwoWayContextReqAnsImpl : \
|
|
|
- public TwoWayContextTestCase<ClassName, ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans> \
|
|
|
+ public TwoWayContextTestCaseT<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); \
|
|
|
+ TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName::Test_##ContextName, RVC_INTERVAL_STRINGFY(ClassName), NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
|
|
|
} \
|
|
|
void TestName::PreTest_##ContextName(ServiceName##_##ContextName##_Req& Req)
|
|
|
|
|
|
@@ -856,6 +716,8 @@ public:
|
|
|
#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 { \
|
|
|
@@ -869,7 +731,7 @@ public:
|
|
|
} \
|
|
|
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); \
|
|
|
+ TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName::Test, RVC_INTERVAL_STRINGFY(ClassName), NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
|
|
|
} \
|
|
|
void TestName::TestContext(CSmartPointer<ITransactionContext> pTransactionContext)
|
|
|
|
|
|
@@ -895,8 +757,8 @@ struct Matcher {
|
|
|
|
|
|
#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(); }\
|
|
|
+ struct TestName : TwoWayContextTestCaseT<EntityClassName, ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans> { \
|
|
|
+ TestName(TestTwoWayFunc func):TwoWayContextTestCaseT(func){ Initial(); }\
|
|
|
void Initial(); \
|
|
|
using TwoWayResultType = ServiceName##_##ContextName##_Ans; \
|
|
|
using AnsMatcher = Matcher<TwoWayResultType>; \
|
|
|
@@ -907,18 +769,18 @@ struct Matcher {
|
|
|
for( AnsMachers::const_iterator it = matchers.begin(), itEnd = matchers.end(); it != itEnd;++it) { \
|
|
|
if (!((it->exprFunc)(Ans))) { \
|
|
|
if(it->level == Tolerate::Strict) { \
|
|
|
- ERR("Expr (\" %s \") failed, %s", it->strExpr.c_str(), it->lineInfo.ToString().c_str()); \
|
|
|
+ ERR("Expr (\" %s \") tests failed !! %s", it->strExpr.c_str(), it->lineInfo.ToString().c_str()); \
|
|
|
result = Error_MisMatched; \
|
|
|
break; \
|
|
|
} else { \
|
|
|
- FAIL("Expr (\" %s \") failed, %s", it->strExpr.c_str(), it->lineInfo.ToString().c_str()); \
|
|
|
+ FAIL("Expr (\" %s \") expects failed ! %s", it->strExpr.c_str(), it->lineInfo.ToString().c_str()); \
|
|
|
} \
|
|
|
} \
|
|
|
} \
|
|
|
return result; \
|
|
|
} \
|
|
|
}; \
|
|
|
- TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)( new TestName(&EntityClassName::ContextName) , RVC_INTERVAL_STRINGFY(EntityClassName), SP::Detail::NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
|
|
|
+ TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)( new TestName(&EntityClassName::ContextName) , RVC_INTERVAL_STRINGFY(EntityClassName), NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
|
|
|
} \
|
|
|
void TestName::Initial()
|
|
|
|
|
|
@@ -932,15 +794,21 @@ struct Matcher {
|
|
|
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*/
|
|
|
+////////////////////////////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__ )
|
|
|
+
|
|
|
+#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)
|
|
|
+#define RVC_TEST_CASE_VOID_CONTEXT_TWO_WAY(entityClassName, serviceName, contextName, ... ) INTERNAL_RVC_REGISTER_TEST_CASE_CONTEXT(entityClassName, serviceName, contextName, __VA_ARGS__ )
|
|
|
|
|
|
#endif //_RVC_SPTEST_H__
|