SpTest.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. #ifndef _RVC_SPTEST_H__
  2. #define _RVC_SPTEST_H__
  3. #pragma once
  4. #include "SpBase.h"
  5. #include "SpHelper.h"
  6. #include "SpComm.hpp"
  7. #include "SpUtility.hpp"
  8. #include <vector>
  9. //helper macro for test temporary.
  10. #define TEST_MODE_SWITCH_ON 1
  11. #if (defined(TEST_MODE_SWITCH_ON) && TEST_MODE_SWITCH_ON == 1)
  12. #define IFFAILRET(func) \
  13. do { \
  14. ErrorCodeEnum errorCode = func; \
  15. if (errorCode != Error_Succeed) { \
  16. LogError(Severity_High, Error_Failed, 0,\
  17. CSimpleStringA::Format("Invoke \"" #func "\" failed ec=%s! at file: <%s>, line: %d",\
  18. SpStrError(errorCode), _GetFileName(__FILE__), __LINE__));\
  19. return Error_Failed; \
  20. } \
  21. } while (false)
  22. #define IFFAILBREAK(func) \
  23. do { \
  24. ErrorCodeEnum errorCode = func; \
  25. if (errorCode != Error_Succeed) { \
  26. LogError(Severity_High, Error_Failed, 0,\
  27. CSimpleStringA::Format("Invoke \"" #func "\" failed ec=%s! at file: <%s>, line: %d",\
  28. SpStrError(errorCode), _GetFileName(__FILE__), __LINE__));\
  29. return; \
  30. } \
  31. } while (false)
  32. #define REQUIRE(expr) \
  33. do { \
  34. if (!(expr)) { \
  35. LogError(Severity_High, Error_Failed, 0,\
  36. CSimpleStringA::Format("Expr (\"" #expr "\") requires failed! at file: <%s>, line: %d", \
  37. _GetFileName(__FILE__), __LINE__));\
  38. return Error_Failed; \
  39. } \
  40. } while (false)
  41. #define CHECK(expr) \
  42. do { \
  43. if (!(expr)) { \
  44. LogError(Severity_High, Error_Failed, 0,\
  45. CSimpleStringA::Format("Expr (\"" #expr "\") requires failed! at file: <%s>, line: %d", \
  46. _GetFileName(__FILE__), __LINE__));\
  47. return; \
  48. } \
  49. } while (false)
  50. #define THROW_FATAL(fmt, ...) \
  51. LogError(Severity_High, Error_Failed, 0, \
  52. CSimpleStringA::Format("%s at file: <%s>, line: %d", \
  53. (LPCTSTR)CSimpleStringA::Format(fmt, ##__VA_ARGS__), _GetFileName(__FILE__), __LINE__))
  54. #define THROW_ERROR(fmt, ...) \
  55. LogError(Severity_Middle, Error_Failed, 0, \
  56. CSimpleStringA::Format("%s at file: <%s>, line: %d", \
  57. (LPCTSTR)CSimpleStringA::Format(fmt, ##__VA_ARGS__), _GetFileName(__FILE__), __LINE__))
  58. #define THROW_FAIL(fmt, ...) \
  59. LogError(Severity_Low, Error_Failed, 0, \
  60. CSimpleStringA::Format("%s at file: <%s>, line: %d", \
  61. (LPCTSTR)CSimpleStringA::Format(fmt, ##__VA_ARGS__), _GetFileName(__FILE__), __LINE__))
  62. #define FALTAL(fmt, ...) LogError(Severity_High, Error_Failed, 0, CSimpleStringA::Format(fmt, ##__VA_ARGS__))
  63. #define ERR(fmt, ...) LogError(Severity_Middle, Error_Failed, 0, CSimpleStringA::Format(fmt, ##__VA_ARGS__))
  64. #define FAIL(fmt, ...) LogError(Severity_Low, Error_Failed, 0, CSimpleStringA::Format(fmt, ##__VA_ARGS__))
  65. #else
  66. #define IFFAILRET(func) ((void)0)
  67. #define IFFAILBREAK(func) ((void)0)
  68. #define REQUIRE(expr) ((void)0)
  69. #define CHECK(expr) ((void)0)
  70. #define THROW_FATAL(fmt, ...) ((void)0)
  71. #define THROW_ERROR(fmt, ...) ((void)0)
  72. #define THROW_FAIL(fmt, ...) ((void)0)
  73. #define FALTAL(fmt, ...) ((void)0)
  74. #define ERR(fmt, ...) ((void)0)
  75. #define FAIL(fmt, ...) ((void)0)
  76. #endif /*defined(TEST_MODE_SWITCH_ON) && TEST_MODE_SWITCH_ON == 1*/
  77. #define REQUIRE_FALSE(expr) \
  78. REQUIRE(!(expr))
  79. #define CHECK_FALSE(expr) \
  80. CHECK(!(expr))
  81. /** Entity's MOCK Context*/
  82. SPBASE_API CSmartPointer<ITransactionContext>
  83. CreateMockTransactionContext(CSmartPointer<IEntityFunction> entityFunction);
  84. /** Test Case */
  85. //struct TestCaseService_RunTest_Req
  86. //{
  87. // CSimpleStringA strParam;
  88. //
  89. // void Serialize(SpBuffer& Buf)
  90. // {
  91. // auto& buf = Buf & strParam;
  92. // }
  93. //
  94. //};
  95. //
  96. //struct TestCaseService_RunTest_Ans
  97. //{
  98. // DWORD dwUserCode;
  99. //
  100. // void Serialize(SpBuffer& Buf)
  101. // {
  102. // auto& buf = Buf & dwUserCode;
  103. // }
  104. //};
  105. //
  106. //void SimulateTestCastEndPoint(SpReqAnsContext< TestCaseService_RunTest_Req, TestCaseService_RunTest_Ans>::Pointer ctx)
  107. //{
  108. // ctx->Answer(Error_Failed);
  109. //}
  110. struct IMethodTestCase
  111. {
  112. virtual ErrorCodeEnum RunTest() = 0;
  113. virtual ~IMethodTestCase() {};
  114. //void BindEntity(CEntityBase* const pEntity) { pEntityBase = pEntity; }
  115. //CEntityBase* pEntityBase = nullptr;
  116. };
  117. template<typename TClass>
  118. class MethodTestCase : public IMethodTestCase
  119. {
  120. public:
  121. MethodTestCase(ErrorCodeEnum(TClass::* method)()) : m_method(method) {}
  122. virtual ErrorCodeEnum RunTest() {
  123. TClass obj;
  124. return (obj.*m_method)();
  125. //return Error_Succeed;
  126. }
  127. private:
  128. virtual ~MethodTestCase() {}
  129. ErrorCodeEnum(TClass::* m_method)();
  130. };
  131. using TestFunction = ErrorCodeEnum(*)();
  132. class DefaultFuncTestCase : public IMethodTestCase
  133. {
  134. public:
  135. DefaultFuncTestCase(TestFunction func) :m_func(func) {}
  136. virtual ErrorCodeEnum RunTest() {
  137. return m_func();
  138. }
  139. private:
  140. virtual ~DefaultFuncTestCase() {};
  141. TestFunction m_func;
  142. };
  143. template<typename TClass, class TReq, class TAns>
  144. struct TwoWayContextTestCaseT : public SpReqAnsContext<TReq, TAns>, public IMethodTestCase
  145. {
  146. using Pointer = CSmartPointer<SpReqAnsContext<TReq, TAns> >;
  147. using TestTwoWayFunc = ErrorCodeEnum(TClass::*)(Pointer ctx);
  148. using TestTwoWayFuncVoid = void(TClass::*)(Pointer ctx);
  149. TwoWayContextTestCaseT(TClass* testee, TestTwoWayFunc func, TestTwoWayFuncVoid funVoid)
  150. :SpReqAnsContext<TReq, TAns>(CreateMockTransactionContext(nullptr))
  151. , m_obj(testee), m_func(func), m_voidFunc(funVoid), m_errorCode(Error_IgnoreAll), m_dwUserCode(0) {
  152. }
  153. TwoWayContextTestCaseT(TClass* testee, TestTwoWayFunc func)
  154. :TwoWayContextTestCaseT(nullptr, func, nullptr) {}
  155. TwoWayContextTestCaseT(TClass* testee, TestTwoWayFuncVoid func)
  156. :TwoWayContextTestCaseT(nullptr, nullptr, func) {}
  157. TwoWayContextTestCaseT(TestTwoWayFunc func) :TwoWayContextTestCaseT(nullptr, func) { }
  158. TwoWayContextTestCaseT(TestTwoWayFuncVoid func) : TwoWayContextTestCaseT(nullptr, func) { }
  159. virtual void PreTest() {/* user should set context request content at Req structure.*/ }
  160. virtual ErrorCodeEnum PostTest()
  161. {
  162. LOG_FUNCTION();
  163. /*User should check response content Ans's validity
  164. *if detect the value conveied by 'Ans' is not the dream one, return ErrorCode except Error_Succeed
  165. *Or*/return Error_Succeed;
  166. /*Tips: Only if the 'RunTest()' returned Error_Succeed, then this function would be invoked.*/
  167. }
  168. virtual ErrorCodeEnum RunTest()
  169. {
  170. ErrorCodeEnum result = Error_IgnoreAll;
  171. TClass obj;
  172. bool flag = false;
  173. if (m_obj == nullptr)
  174. flag = !!(m_obj = &obj);
  175. PreTest();
  176. if (m_func != nullptr) {
  177. result = (m_obj->*m_func)(GetCtx());
  178. }
  179. else if (m_voidFunc != nullptr) {
  180. (m_obj->*m_voidFunc)(GetCtx());
  181. result = Error_Succeed;
  182. }
  183. result = (result == Error_Succeed) ? m_errorCode : result;
  184. Dbg("TwoWayContextTestCaseT->errorCode: %s", SpStrError(result));
  185. if (flag) m_obj = nullptr;
  186. return (((result == Error_Succeed) ? PostTest() : result));
  187. }
  188. ErrorCodeEnum Answer(ErrorCodeEnum Error = Error_Succeed) override
  189. {
  190. LOG_FUNCTION();
  191. m_errorCode = Error;
  192. return Error_Succeed;
  193. }
  194. ErrorCodeEnum Answer(ErrorCodeEnum eSysError, DWORD dwUserError) override
  195. {
  196. LOG_FUNCTION();
  197. m_errorCode = eSysError;
  198. m_dwUserCode = dwUserError;
  199. return Error_Succeed;
  200. }
  201. private:
  202. Pointer GetCtx()
  203. {
  204. Pointer pt = this;
  205. pt.AddRef();
  206. return pt;
  207. }
  208. TestTwoWayFunc m_func;
  209. TestTwoWayFuncVoid m_voidFunc;
  210. TClass* m_obj;
  211. ErrorCodeEnum m_errorCode;
  212. DWORD m_dwUserCode;
  213. };
  214. struct TestCaseStatistics
  215. {
  216. std::size_t totalTestCaseNum;
  217. std::size_t passedTestCaseNum;
  218. std::size_t failureTestCaseNum;
  219. std::size_t ignoreTestCaseNum;
  220. TestCaseStatistics() { Reset(); }
  221. void Reset()
  222. {
  223. totalTestCaseNum = 0;
  224. passedTestCaseNum = 0;
  225. failureTestCaseNum = 0;
  226. ignoreTestCaseNum = 0;
  227. }
  228. void Clear()
  229. {
  230. const std::size_t oldCaseNum = totalTestCaseNum;
  231. Reset();
  232. totalTestCaseNum = oldCaseNum;
  233. }
  234. std::size_t Total() const { return (totalTestCaseNum); }
  235. bool AllPassed() const { return (failureTestCaseNum == 0); }
  236. };
  237. template<typename T>
  238. class ITestCaseSuite
  239. {
  240. public:
  241. ITestCaseSuite() = default;
  242. virtual ~ITestCaseSuite();
  243. typedef T* TestObjectPointer;
  244. template<class TReq, class TAns>
  245. struct TwoWayMethodTestCaseT : public TwoWayContextTestCaseT<T, TReq, TAns> {
  246. TwoWayMethodTestCaseT(T* pEntity, TestTwoWayFunc testFunc)
  247. :TwoWayContextTestCaseT(pEntity, testFunc) {}
  248. };
  249. typedef void(T::* TransMethodProto)(CSmartPointer<ITransactionContext> pTransactionContext);
  250. typedef std::vector<TransMethodProto> TestCaseSet;
  251. void AddTransMethod(TransMethodProto entry);
  252. typedef std::vector<IMethodTestCase*> MethodTestCaseSet;
  253. void AddMethodTestCase(IMethodTestCase* methodCastPtr);
  254. protected:
  255. virtual ErrorCodeEnum RunTestCase();
  256. /** user can override this function to add any other test, but do not
  257. invoke 'AddTransMethod' and 'AddMethodTestCase' method at this scope!!!!*/
  258. virtual ErrorCodeEnum AdditionalTest() { return Error_Succeed; }
  259. private:
  260. TestCaseSet m_testCases;
  261. MethodTestCaseSet m_testMethods;
  262. TestCaseStatistics m_testStatistcs;
  263. static CSmartPointer<ITransactionContext> m_spMockTransactionContext;
  264. };
  265. /*!
  266. * [Gifur@2020519]
  267. * declare Transaction context as static type for some reason:
  268. * 1. when creating SpReqAnsContext class object, we must convey a CSmartPointer<ITransactionContext> type param to initialize,
  269. * 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
  270. * hook it to mock real test result without changing any functional code which I really unwill to see it!
  271. * 2. subclass TwoWayMethodTestCaseT inherited from SpReqAnsContext cannot initialize earlier than SpReqAnsContext as children class, so we
  272. * cannot declare a 'CSmartPointer<ITransactionContext>' type member and initialze it first then convey it to SpReqAnsContext.
  273. * 3. multi-thead unsafe !!!
  274. */
  275. template<typename TClass>
  276. CSmartPointer<ITransactionContext> ITestCaseSuite<TClass>::m_spMockTransactionContext \
  277. = CreateMockTransactionContext(nullptr);
  278. template<typename T>
  279. ITestCaseSuite<T>::~ITestCaseSuite()
  280. {
  281. for (auto& r : m_testMethods) {
  282. if (r) {
  283. delete r;
  284. r = NULL;
  285. }
  286. }
  287. }
  288. /* 'TransMethodProto' Prototype: void Entity::Function(CSmartPointer<ITransactionContext> pTransactionContext)
  289. * User should declare and implement it.
  290. */
  291. template<typename TClass>
  292. void ITestCaseSuite<TClass>::AddTransMethod(TransMethodProto entry)
  293. {
  294. m_testCases.push_back(entry);
  295. m_testStatistcs.totalTestCaseNum++;
  296. }
  297. template<typename TClass>
  298. void ITestCaseSuite<TClass>::AddMethodTestCase(IMethodTestCase* methodCastPtr)
  299. {
  300. m_testMethods.push_back(methodCastPtr);
  301. m_testStatistcs.totalTestCaseNum++;
  302. }
  303. template<typename TClass>
  304. ErrorCodeEnum ITestCaseSuite<TClass>::RunTestCase()
  305. {
  306. LOG_FUNCTION();
  307. m_testStatistcs.Clear();
  308. std::size_t testCaseNum = 0;
  309. TestObjectPointer that = static_cast<TestObjectPointer>(this);
  310. if (!m_testCases.empty())
  311. {
  312. auto it = m_testCases.begin();
  313. while (it != m_testCases.end())
  314. {
  315. ++testCaseNum;
  316. Dbg("Run TestCase#%d...", testCaseNum);
  317. CSmartPointer<ITransactionContext> mock = CreateMockTransactionContext(that->GetFunction());
  318. (that->*(*it))(mock);
  319. DWORD dwUserCode = 0, dwNoUsed = 0;
  320. ErrorCodeEnum result = mock->GetExpireTime(dwUserCode, dwNoUsed);
  321. if (IS_FAILURED(result) && result != Error_IgnoreAll)
  322. {
  323. THROW_ERROR("TestCase#%d test failed return %s(userCode: 0x%X)", testCaseNum, SpStrError(result), dwUserCode);
  324. m_testStatistcs.failureTestCaseNum++;
  325. }
  326. else if (result == Error_IgnoreAll)
  327. {
  328. m_testStatistcs.ignoreTestCaseNum++;
  329. }
  330. else
  331. {
  332. m_testStatistcs.passedTestCaseNum++;
  333. }
  334. it++;
  335. }
  336. }
  337. std::size_t testMethodNum = 0;
  338. if (!m_testMethods.empty())
  339. {
  340. auto it = m_testMethods.begin();
  341. while (it != m_testMethods.end())
  342. {
  343. ++testMethodNum;
  344. Dbg("Run TestMethod#%d...", testMethodNum);
  345. ErrorCodeEnum result = (*it)->RunTest();
  346. if (IS_FAILURED(result) && result != Error_IgnoreAll)
  347. {
  348. THROW_ERROR("TestMethod#%d test failed return %s", testMethodNum, SpStrError(result));
  349. m_testStatistcs.failureTestCaseNum++;
  350. }
  351. else if (result == Error_IgnoreAll)
  352. {
  353. m_testStatistcs.ignoreTestCaseNum++;
  354. }
  355. else
  356. {
  357. m_testStatistcs.passedTestCaseNum++;
  358. }
  359. it++;
  360. }
  361. }
  362. return m_testStatistcs.AllPassed() ? Error_Failed : Error_Succeed;
  363. }
  364. #define TESTCASE_OVERRIDE_ON_EXAM_AND_IMPLEMENT() \
  365. void OnExam(CSmartPointer<ITransactionContext> pTransactionContext) override \
  366. { \
  367. LOG_FUNCTION(); \
  368. ErrorCodeEnum testResult = RunTestCase(); \
  369. if (testResult == Error_Succeed || testResult == Error_IgnoreAll) { \
  370. testResult = AdditionalTest(); \
  371. pTransactionContext->SendAnswer(testResult); \
  372. } else { \
  373. pTransactionContext->SendAnswer(testResult); \
  374. } \
  375. }
  376. ///////////////////////////////experiment below///////////////////////////////////////////
  377. #define TESTCASE_DECLARE_BEGIN(serviceName, testFuncName) \
  378. void Test_##testFuncName(CSmartPointer<ITransactionContext> pTransactionContext) {\
  379. SpReqAnsContext< serviceName##_##testFuncName##_Req, serviceName##_##testFuncName##_Ans>::Pointer ctx = \
  380. new SpReqAnsContext< serviceName##_##testFuncName##_Req, serviceName##_##testFuncName##_Ans>(pTransactionContext)
  381. /*user et the member value */
  382. #define TESTCASE_DECLARE_INVOKE(testFuncName) \
  383. do {\
  384. DWORD dwUserCode = 0, dwNoUsed = 0;\
  385. Test_##testFuncName(ctx);\
  386. ErrorCodeEnum result = mock->GetExpireTime(dwUserCode, dwNoUsed);\
  387. if (IS_FAILURED(result)) { return; }\
  388. } while (false)
  389. #define TESTCASE_DECLARE_END(testFuncName) \
  390. }
  391. ///////////////////////////////experiment end///////////////////////////////////////////
  392. //////////////////////////////////////////////////////////////////////////
  393. using namespace SP::Detail;
  394. struct NameAndDesc
  395. {
  396. NameAndDesc(const char* _name = "", const char* _description = "")
  397. : name(_name), description(_description)
  398. {/*empty*/
  399. }
  400. const char* name;
  401. const char* description;
  402. };
  403. class TestCase;
  404. struct TestConfig
  405. {
  406. std::string filterTag;
  407. };
  408. struct ITestCaseRegistry
  409. {
  410. virtual ~ITestCaseRegistry() {}
  411. /** TODO: relate with Entity Name*/
  412. virtual std::vector<TestCase> const& getAllTests(TestConfig const& config) const = 0;
  413. };
  414. struct ITestRegistryHub
  415. {
  416. virtual ~ITestRegistryHub() {}
  417. virtual void RegisterTest(TestCase const& testInfo) = 0;
  418. virtual ITestCaseRegistry const& GetTestCaseRegistry() const = 0;
  419. };
  420. SPBASE_API ITestRegistryHub& GetRegistryHub();
  421. /** TODO: hide*/
  422. SPBASE_API TestCase MakeTestCase(IMethodTestCase* testCase,
  423. std::string const& className,
  424. std::string const& name,
  425. std::string const& desc,
  426. SourceLineInfo const& lineInfo);
  427. SPBASE_API void RegisterTestCase(IMethodTestCase* testCase, char const* className,
  428. NameAndDesc const& nameAndDesc,
  429. SourceLineInfo const& lineInfo);
  430. SPBASE_API void RegisterTestCaseFunction(TestFunction function,
  431. NameAndDesc const& nameAndDesc,
  432. SourceLineInfo const& lineInfo
  433. );
  434. struct TestAutoReg
  435. {
  436. TestAutoReg() {}
  437. ~TestAutoReg() {}
  438. /** for test simple func*/
  439. TestAutoReg(TestFunction function,
  440. SourceLineInfo const& lineInfo,
  441. NameAndDesc const& nameAndDesc
  442. )
  443. {
  444. RegisterTestCaseFunction(function, nameAndDesc, lineInfo);
  445. }
  446. /** for test Class*/
  447. template<typename TClass>
  448. TestAutoReg(
  449. ErrorCodeEnum(TClass::* method)(),
  450. char const* lpcszClassName,
  451. NameAndDesc const& nameAndDesc,
  452. SourceLineInfo const& lineInfo)
  453. {
  454. RegisterTestCase(new MethodTestCase<TClass>(method), lpcszClassName, nameAndDesc, lineInfo);
  455. }
  456. TestAutoReg(
  457. IMethodTestCase* testCaseImpl,
  458. char const* lpcszClassName,
  459. NameAndDesc const& nameAndDesc,
  460. SourceLineInfo const& lineInfo)
  461. {
  462. RegisterTestCase(testCaseImpl, lpcszClassName, nameAndDesc, lineInfo);
  463. }
  464. };
  465. struct TestCaseInfo {
  466. TestCaseInfo(std::string const& name, std::string const& className, std::string const& desc, SourceLineInfo const& info)
  467. :strName(name.c_str()), strClassName(className.c_str()),strDescription(desc.c_str()), lineInfo(info) {}
  468. TestCaseInfo(TestCaseInfo const& other)
  469. :TestCaseInfo(other.strName, other.strClassName, other.strDescription, other.lineInfo)
  470. {/*delegrate directory*/}
  471. std::string strName;
  472. std::string strClassName;
  473. std::string strDescription;
  474. SourceLineInfo lineInfo;
  475. };
  476. class TestCase : public TestCaseInfo
  477. {
  478. public:
  479. TestCase(IMethodTestCase* testCase, TestCaseInfo const& info): TestCaseInfo(info), m_testCase(testCase) {}
  480. TestCase(TestCase const& other)
  481. :TestCaseInfo(other), m_testCase(other.m_testCase) {}
  482. TestCaseInfo const& GetTestInfo() const { return *this; }
  483. /** for anonymous case regist*/
  484. TestCase CloneExceptName(std::string const& newName) const {
  485. TestCase newCase(*this);
  486. newCase.strName = newName;
  487. return newCase;
  488. }
  489. ErrorCodeEnum RunTest() const
  490. {
  491. return m_testCase->RunTest();
  492. }
  493. private:
  494. CSmartPointer<IMethodTestCase> m_testCase;
  495. };
  496. #define RVC_INTERVAL_UNIQUE_NAME_LINE2( name, line ) name##line
  497. #define RVC_INTERVAL_UNIQUE_NAME_LINE( name, line ) RVC_INTERVAL_UNIQUE_NAME_LINE2( name, line )
  498. #define RVC_INTERVAL_UNIQUE_NAME(name) RVC_INTERVAL_UNIQUE_NAME_LINE(name, __COUNTER__)
  499. #define RVC_INTERVAL_STRINGFY(name) #name
  500. #define INTERNAL_RVC_TEST_CASE_METHOD2(TestName, ClassName, ...) \
  501. namespace { \
  502. struct TestName : ClassName { \
  503. ErrorCodeEnum Test(); \
  504. }; \
  505. TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName::Test, RVC_INTERVAL_STRINGFY(ClassName), NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
  506. } \
  507. ErrorCodeEnum TestName::Test()
  508. #define INTERNAL_RVC_TEST_CASE_METHOD(ClassName, ...) \
  509. INTERNAL_RVC_TEST_CASE_METHOD2(RVC_INTERVAL_UNIQUE_NAME(CVRssalCtseTduS), ClassName, __VA_ARGS__)
  510. //////////////////////////////////////////////////////////////////////////
  511. #define INTERNAL_RVC_TESTCASE2(TestName, ...) \
  512. static ErrorCodeEnum TestName(); \
  513. namespace { \
  514. TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName, SP_INTERNAL_LINEINFO, NameAndDesc(__VA_ARGS__)); \
  515. } \
  516. static ErrorCodeEnum TestName()
  517. #define INTERNAL_RVC_TESTCASE(...) INTERNAL_RVC_TESTCASE2(RVC_INTERVAL_UNIQUE_NAME(CVRcnuFtseTduS), __VA_ARGS__)
  518. #include <functional>
  519. //////////////////////////////////////////////////////////////////////////
  520. #define TWO_WAY_CHECK_ANSWER_BEGIN(ansName) \
  521. checkAnsFunc = [](TwoWayResultType const& ansName) -> ErrorCodeEnum {
  522. #define TWO_WAY_CHECK_ANSWER_END() };
  523. #define INTERNAL_RVC_TEST_CASE_CONTEXT_TWO_WAY2(TestName, ClassName, ServiceName, ContextName, TestFuncName, ...) \
  524. namespace { \
  525. struct TestName : ClassName { \
  526. CSmartPointer<ITransactionContext> mMockTrans; \
  527. SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>::Pointer mCtx;\
  528. using TwoWayResultType = ServiceName##_##ContextName##_Ans; \
  529. void (ClassName::*testFuncVoid)(SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>::Pointer);\
  530. ErrorCodeEnum (ClassName::*testFunc)(SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>::Pointer);\
  531. ErrorCodeEnum testRes; \
  532. std::function<ErrorCodeEnum(ServiceName##_##ContextName##_Ans const&)> checkAnsFunc; \
  533. TestName():mMockTrans(CreateMockTransactionContext(this->GetFunction())), \
  534. mCtx(new SpReqAnsContext< ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans>(mMockTrans)) \
  535. , testFuncVoid(nullptr),testFunc(nullptr), testRes(Error_Succeed), checkAnsFunc(nullptr) { \
  536. testFunc = &ClassName::TestFuncName; \
  537. }\
  538. void PreTest_##ContextName(ServiceName##_##ContextName##_Req& Req); \
  539. ErrorCodeEnum PostTest_##ContextName() { \
  540. return checkAnsFunc == nullptr ? Error_Succeed : checkAnsFunc(mCtx->Ans); \
  541. } \
  542. ErrorCodeEnum Test_##ContextName() { \
  543. PreTest_##ContextName(mCtx->Req); \
  544. if(testFuncVoid != nullptr) { \
  545. (this->*testFuncVoid)(mCtx); \
  546. } \
  547. else if(testFunc != nullptr) { \
  548. testRes =(this->*testFunc)(mCtx); \
  549. } \
  550. if(testRes == Error_Succeed) { \
  551. DWORD dwUserCode = 0, dwNoUsed = 0; \
  552. testRes = mMockTrans->GetExpireTime(dwUserCode, dwNoUsed); \
  553. } \
  554. if(testRes == Error_Succeed) { \
  555. testRes = PostTest_##ContextName(); \
  556. } else if(testRes == Error_IgnoreAll) \
  557. testRes = Error_Succeed; \
  558. return testRes; \
  559. } \
  560. struct TwoWayContextReqAnsImpl : \
  561. public TwoWayContextTestCaseT<ClassName, ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans> \
  562. { \
  563. }; \
  564. }; \
  565. TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName::Test_##ContextName, RVC_INTERVAL_STRINGFY(ClassName), NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
  566. } \
  567. void TestName::PreTest_##ContextName(ServiceName##_##ContextName##_Req& Req)
  568. #define INTERNAL_RVC_TEST_CASE_CONTEXT_TWO_WAY(EntityClassName, ServiceName, TestFuncName, ContextName, ...) \
  569. INTERNAL_RVC_TEST_CASE_CONTEXT_TWO_WAY2(RVC_INTERVAL_UNIQUE_NAME(CVRytitnEtseTduS), EntityClassName, ServiceName, ContextName, TestFuncName, __VA_ARGS__)
  570. //////////////////////////////////////////////////////////////////////////
  571. #define INTERNAL_RVC_TEST_CASE_CONTEXT2(TestName, ClassName, ...) \
  572. namespace { \
  573. struct TestName : ClassName { \
  574. CSmartPointer<ITransactionContext> mMockTrans; \
  575. TestName():mMockTrans(CreateMockTransactionContext(this->GetFunction())){}; \
  576. ErrorCodeEnum Test() { \
  577. TestContext(mMockTrans); \
  578. DWORD dwUserCode = 0, dwNoUsed = 0; \
  579. ErrorCodeEnum testRes = mMockTrans->GetExpireTime(dwUserCode, dwNoUsed); \
  580. return (testRes == Error_IgnoreAll) ? Error_Succeed : testRes; \
  581. } \
  582. void TestContext(CSmartPointer<ITransactionContext> pTransactionContext); \
  583. }; \
  584. TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)(&TestName::Test, RVC_INTERVAL_STRINGFY(ClassName), NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
  585. } \
  586. void TestName::TestContext(CSmartPointer<ITransactionContext> pTransactionContext)
  587. #define INTERNAL_RVC_TEST_CASE_CONTEXT(EntityClassName, ...) \
  588. INTERNAL_RVC_TEST_CASE_CONTEXT2(RVC_INTERVAL_UNIQUE_NAME(CVRytitnEtseTduS), EntityClassName, __VA_ARGS__)
  589. ///////////////////////////////////////////////////////////////////////////////
  590. enum class Tolerate { Strict, Ignore };
  591. template<typename T>
  592. struct Matcher {
  593. Tolerate level = Tolerate::Ignore;
  594. std::string strExpr;
  595. std::function<bool(T const&)> exprFunc;
  596. SourceLineInfo lineInfo;
  597. Matcher(Tolerate const& choice, std::string const& desc, std::function<bool(T const&)>&& expr, SourceLineInfo const& info)
  598. :level(choice), strExpr(desc), exprFunc(expr),lineInfo(info) {}
  599. };
  600. # define RVC_INTERNAL_STRINGIFY(expr) #expr
  601. #define INTERNAL_RVC_REGISTER_TEST_CASE_CONTEXT2(TestName, EntityClassName, ServiceName, ContextName, ...) \
  602. namespace { \
  603. struct TestName : TwoWayContextTestCaseT<EntityClassName, ServiceName##_##ContextName##_Req, ServiceName##_##ContextName##_Ans> { \
  604. TestName(TestTwoWayFunc func):TwoWayContextTestCaseT(func){ Initial(); }\
  605. void Initial(); \
  606. using TwoWayResultType = ServiceName##_##ContextName##_Ans; \
  607. using AnsMatcher = Matcher<TwoWayResultType>; \
  608. using AnsMachers = std::vector< AnsMatcher >; \
  609. AnsMachers matchers; \
  610. ErrorCodeEnum PostTest() { \
  611. ErrorCodeEnum result = Error_Succeed; \
  612. for( AnsMachers::const_iterator it = matchers.begin(), itEnd = matchers.end(); it != itEnd;++it) { \
  613. if (!((it->exprFunc)(Ans))) { \
  614. if(it->level == Tolerate::Strict) { \
  615. ERR("Expr (\" %s \") tests failed !! %s", it->strExpr.c_str(), it->lineInfo.ToString().c_str()); \
  616. result = Error_MisMatched; \
  617. break; \
  618. } else { \
  619. FAIL("Expr (\" %s \") expects failed ! %s", it->strExpr.c_str(), it->lineInfo.ToString().c_str()); \
  620. } \
  621. } \
  622. } \
  623. return result; \
  624. } \
  625. }; \
  626. TestAutoReg RVC_INTERVAL_UNIQUE_NAME(testAutoReg)( new TestName(&EntityClassName::ContextName) , RVC_INTERVAL_STRINGFY(EntityClassName), NameAndDesc(__VA_ARGS__), SP_INTERNAL_LINEINFO); \
  627. } \
  628. void TestName::Initial()
  629. #define INTERNAL_RVC_REGISTER_TEST_CASE_CONTEXT(EntityClassName, ServiceName, ContextName, ... ) \
  630. INTERNAL_RVC_REGISTER_TEST_CASE_CONTEXT2(RVC_INTERVAL_UNIQUE_NAME(CVRtxetnoCtseTduS), EntityClassName, ServiceName, ContextName, __VA_ARGS__)
  631. #define INNER_ANSWER_CHECK(Expression, Description, TolerateLevel) \
  632. do { \
  633. auto f = [](TwoWayResultType const& Ans)->bool { return ( Expression ); }; \
  634. AnsMatcher matchInst(TolerateLevel, std::string(Description), f, SP_INTERNAL_LINEINFO); \
  635. matchers.push_back(matchInst); \
  636. } while (false)
  637. ////////////////////////////Export for user//////////////////////////////////////////////
  638. #define RVC_TEST_CASE( ... ) INTERNAL_RVC_TESTCASE( __VA_ARGS__ )
  639. #define RVC_TEST_CASE_METHOD(className, ...) INTERNAL_RVC_TEST_CASE_METHOD( className, __VA_ARGS__ )
  640. #define RVC_TEST_CASE_VOID_CONTEXT(entityClassName, ...) INTERNAL_RVC_TEST_CASE_CONTEXT( entityClassName, __VA_ARGS__ )
  641. #define RVC_TEST_CASE_CONTEXT_TWO_WAY(entityClassName, serviceName, contextName, ...) INTERNAL_RVC_TEST_CASE_CONTEXT_TWO_WAY(entityClassName, serviceName, contextName, contextName, __VA_ARGS__)
  642. #define ANSWER_CHECK(expr) INNER_ANSWER_CHECK(expr, RVC_INTERNAL_STRINGIFY(expr), Tolerate::Ignore)
  643. #define ANSWER_REQUIRE(expr) INNER_ANSWER_CHECK(expr, RVC_INTERNAL_STRINGIFY(expr), Tolerate::Strict)
  644. #define RVC_TEST_CASE_VOID_CONTEXT_TWO_WAY(entityClassName, serviceName, contextName, ... ) INTERNAL_RVC_REGISTER_TEST_CASE_CONTEXT(entityClassName, serviceName, contextName, __VA_ARGS__ )
  645. #endif //_RVC_SPTEST_H__