SpTest.h 29 KB

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