|
@@ -485,6 +485,7 @@ struct ITestRegistryHub {
|
|
|
|
|
|
SPBASE_API ITestRegistryHub& GetRegistryHub();
|
|
|
|
|
|
+/** TODO: hide*/
|
|
|
SPBASE_API TestCase MakeTestCase(IMethodTestCase* testCase,
|
|
|
std::string const& className,
|
|
|
std::string const& name,
|
|
@@ -521,9 +522,7 @@ public:
|
|
|
return m_func();
|
|
|
}
|
|
|
private:
|
|
|
-
|
|
|
virtual ~DefaultFuncTestCase() {};
|
|
|
-
|
|
|
TestFunction m_func;
|
|
|
};
|
|
|
|
|
@@ -534,42 +533,93 @@ struct TwoWayContextTestCase : public SpReqAnsContext<TReq, TAns>, public IMetho
|
|
|
using TestTwoWayFunc = ErrorCodeEnum(TClass::*)(Pointer ctx);
|
|
|
using TestTwoWayFuncVoid = void(TClass::*)(Pointer ctx);
|
|
|
|
|
|
- TwoWayContextTestCase(TClass* testee, TestTwoWayFunc func) :m_obj(testee), m_func(func), m_voidFunc(nullptr), m_ctx(nullptr){}
|
|
|
- TwoWayContextTestCase(TClass* testee, TestTwoWayFuncVoid func) :m_obj(testee), m_func(nullptr), m_voidFunc(func), m_ctx(nullptr) {}
|
|
|
- TwoWayContextTestCase(TestTwoWayFunc func) :TwoWayContextTestCase(nullptr, func){}
|
|
|
- TwoWayContextTestCase(TestTwoWayFuncVoid func) : TwoWayContextTestCase(nullptr, func) {}
|
|
|
+ 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_NotConfig;
|
|
|
+ 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)(m_ctx);
|
|
|
+ result = (m_obj->*m_func)(GetCtx());
|
|
|
}
|
|
|
else if (m_voidFunc != nullptr)
|
|
|
{
|
|
|
- (m_obj->*m_voidFunc)(m_ctx);
|
|
|
+ (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;
|
|
|
+ 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;
|
|
|
- Pointer m_ctx;
|
|
|
TClass* m_obj;
|
|
|
-};
|
|
|
|
|
|
+ ErrorCodeEnum m_errorCode;
|
|
|
+ DWORD m_dwUserCode;
|
|
|
+};
|
|
|
|
|
|
struct TestAutoReg {
|
|
|
|
|
@@ -596,6 +646,15 @@ struct TestAutoReg {
|
|
|
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(
|
|
@@ -701,15 +760,12 @@ public:
|
|
|
|
|
|
|
|
|
#define RVC_TWO_WAY_SECTION(ServiceName, ContextName) \
|
|
|
- void Test_##ContextName_##ServiceName() { \
|
|
|
+ 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_VOID_INVOKE(TestFuncName) \
|
|
|
- testFuncVoid = TestFuncName
|
|
|
-
|
|
|
#define RVC_TWO_WAY_INVOKE(TestFuncName) \
|
|
|
testFunc = TestFuncName; \
|
|
|
}\
|
|
@@ -717,7 +773,6 @@ public:
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
-
|
|
|
#define SECTION_INNER(StructName, ...) \
|
|
|
struct StructName : public TwoWayContextReqAnsImpl { \
|
|
|
void Test(); \
|
|
@@ -727,18 +782,16 @@ public:
|
|
|
#define SECTION(...) \
|
|
|
SECTION_INNER(RVC_INTERVAL_UNIQUE_NAME(CVRnoitceStseTduS), __VA_ARGS__)
|
|
|
|
|
|
-#define CHECK_ANSWER_BEGIN(ansName) \
|
|
|
+#define TWO_WAY_CHECK_ANSWER_BEGIN(ansName) \
|
|
|
checkAnsFunc = [](TwoWayResultType const& ansName) -> ErrorCodeEnum {
|
|
|
|
|
|
-#define CHECK_ANSWER_END() };
|
|
|
+#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;\
|
|
|
- ServiceName##_##ContextName##_Req& Req; \
|
|
|
- ServiceName##_##ContextName##_Ans& Ans; \
|
|
|
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);\
|
|
@@ -746,16 +799,15 @@ public:
|
|
|
std::function<ErrorCodeEnum(ServiceName##_##ContextName##_Ans const&)> checkAnsFunc; \
|
|
|
TestName():mMockTrans(CreateMockTransactionContext(this->GetFunction())), \
|
|
|
mCtx(new SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>(mMockTrans)) \
|
|
|
- , Req(mCtx->Req), Ans(mCtx->Ans) \
|
|
|
, testFuncVoid(nullptr),testFunc(nullptr), testRes(Error_Succeed), checkAnsFunc(nullptr) { \
|
|
|
testFunc = &ClassName::TestFuncName; \
|
|
|
}\
|
|
|
- void PreTest_##ContextName(); \
|
|
|
+ void PreTest_##ContextName(ServiceName##_##ContextName##_Req& Req); \
|
|
|
ErrorCodeEnum PostTest_##ContextName() { \
|
|
|
return checkAnsFunc == nullptr ? Error_Succeed : checkAnsFunc(mCtx->Ans); \
|
|
|
} \
|
|
|
ErrorCodeEnum Test_##ContextName() { \
|
|
|
- PreTest_##ContextName(); \
|
|
|
+ PreTest_##ContextName(mCtx->Req); \
|
|
|
if(testFuncVoid != nullptr) { \
|
|
|
(this->*testFuncVoid)(mCtx); \
|
|
|
} \
|
|
@@ -768,7 +820,8 @@ public:
|
|
|
} \
|
|
|
if(testRes == Error_Succeed) { \
|
|
|
testRes = PostTest_##ContextName(); \
|
|
|
- } \
|
|
|
+ } else if(testRes == Error_IgnoreAll) \
|
|
|
+ testRes = Error_Succeed; \
|
|
|
return testRes; \
|
|
|
} \
|
|
|
struct TwoWayContextReqAnsImpl : \
|
|
@@ -778,13 +831,12 @@ public:
|
|
|
}; \
|
|
|
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()
|
|
|
+ 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 { \
|
|
@@ -806,12 +858,73 @@ public:
|
|
|
#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_CONTEXT(entityClassName, ...) INTERNAL_RVC_TEST_CASE_CONTEXT( entityClassName, __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__
|