registar.h 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. #pragma once
  2. #include <library/cpp/dbg_output/dump.h>
  3. #include <util/generic/bt_exception.h>
  4. #include <util/generic/hash.h>
  5. #include <util/generic/intrlist.h>
  6. #include <util/generic/map.h>
  7. #include <util/generic/ptr.h>
  8. #include <util/generic/set.h>
  9. #include <util/generic/typetraits.h>
  10. #include <util/generic/vector.h>
  11. #include <util/generic/yexception.h>
  12. #include <util/string/builder.h>
  13. #include <util/string/cast.h>
  14. #include <util/string/printf.h>
  15. #include <util/system/defaults.h>
  16. #include <util/system/type_name.h>
  17. #include <util/system/spinlock.h>
  18. #include <util/system/src_location.h>
  19. #include <util/system/rusage.h>
  20. #include <cmath>
  21. #include <cstdio>
  22. #include <functional>
  23. extern bool CheckExceptionMessage(const char*, TString&);
  24. namespace NUnitTest {
  25. class TTestBase;
  26. namespace NPrivate {
  27. void RaiseError(const char* what, const TString& msg, bool fatalFailure);
  28. void SetUnittestThread(bool);
  29. void SetCurrentTest(TTestBase*);
  30. TTestBase* GetCurrentTest();
  31. }
  32. extern bool ShouldColorizeDiff;
  33. extern bool ContinueOnFail;
  34. TString ColoredDiff(TStringBuf s1, TStringBuf s2, const TString& delims = TString(), bool reverse = false);
  35. TString GetFormatTag(const char* name);
  36. TString GetResetTag();
  37. // Raise error handler
  38. // Used for testing library/cpp/testing/unittest macroses
  39. // and unittest helpers.
  40. // For all other unittests standard handler is used
  41. using TRaiseErrorHandler = std::function<void(const char*, const TString&, bool)>;
  42. void SetRaiseErrorHandler(TRaiseErrorHandler handler);
  43. inline void ClearRaiseErrorHandler() {
  44. SetRaiseErrorHandler(TRaiseErrorHandler());
  45. }
  46. class TAssertException: public yexception {
  47. };
  48. class ITestSuiteProcessor;
  49. struct TTestContext {
  50. TTestContext()
  51. : Processor(nullptr)
  52. {
  53. }
  54. explicit TTestContext(ITestSuiteProcessor* processor)
  55. : Processor(processor)
  56. {
  57. }
  58. using TMetrics = THashMap<TString, double>;
  59. TMetrics Metrics;
  60. ITestSuiteProcessor* Processor;
  61. };
  62. class ITestSuiteProcessor {
  63. public:
  64. struct TUnit {
  65. const TString name;
  66. };
  67. struct TTest {
  68. const TUnit* unit;
  69. const char* name;
  70. };
  71. struct TError {
  72. const TTest* test;
  73. const char* msg;
  74. TString BackTrace;
  75. TTestContext* Context;
  76. };
  77. struct TFinish {
  78. const TTest* test;
  79. TTestContext* Context;
  80. bool Success;
  81. };
  82. ITestSuiteProcessor();
  83. virtual ~ITestSuiteProcessor();
  84. void Start();
  85. void End();
  86. void UnitStart(const TUnit& unit);
  87. void UnitStop(const TUnit& unit);
  88. void Error(const TError& descr);
  89. void BeforeTest(const TTest& test);
  90. void Finish(const TFinish& descr);
  91. unsigned GoodTests() const noexcept;
  92. unsigned FailTests() const noexcept;
  93. unsigned GoodTestsInCurrentUnit() const noexcept;
  94. unsigned FailTestsInCurrentUnit() const noexcept;
  95. // Should execute test suite?
  96. virtual bool CheckAccess(TString /*name*/, size_t /*num*/);
  97. // Should execute a test whitin suite?
  98. virtual bool CheckAccessTest(TString /*suite*/, const char* /*name*/);
  99. virtual void Run(std::function<void()> f, const TString& /*suite*/, const char* /*name*/, bool /*forceFork*/);
  100. // This process is forked for current test
  101. virtual bool GetIsForked() const;
  102. // --fork-tests is set (warning: this may be false, but never the less test will be forked if called inside UNIT_FORKED_TEST)
  103. virtual bool GetForkTests() const;
  104. private:
  105. virtual void OnStart();
  106. virtual void OnEnd();
  107. virtual void OnUnitStart(const TUnit* /*unit*/);
  108. virtual void OnUnitStop(const TUnit* /*unit*/);
  109. virtual void OnError(const TError* /*error*/);
  110. virtual void OnFinish(const TFinish* /*finish*/);
  111. virtual void OnBeforeTest(const TTest* /*test*/);
  112. void AddTestError(const TTest& test);
  113. void AddTestFinish(const TTest& test);
  114. private:
  115. TMap<TString, size_t> TestErrors_;
  116. TMap<TString, size_t> CurTestErrors_;
  117. };
  118. class TTestBase;
  119. class TTestFactory;
  120. class ITestBaseFactory: public TIntrusiveListItem<ITestBaseFactory> {
  121. public:
  122. ITestBaseFactory();
  123. virtual ~ITestBaseFactory();
  124. // name of test suite
  125. virtual TString Name() const noexcept = 0;
  126. virtual TTestBase* ConstructTest() = 0;
  127. private:
  128. void Register() noexcept;
  129. };
  130. class TTestBase {
  131. friend class TTestFactory;
  132. TRusage rusage;
  133. public:
  134. TTestBase() noexcept;
  135. virtual ~TTestBase();
  136. virtual TString TypeId() const;
  137. virtual TString Name() const noexcept = 0;
  138. virtual void Execute() = 0;
  139. virtual void SetUp();
  140. virtual void TearDown();
  141. void AddError(const char* msg, const TString& backtrace = TString(), TTestContext* context = nullptr);
  142. void AddError(const char* msg, TTestContext* context);
  143. void RunAfterTest(std::function<void()> f); // function like atexit to run after current unit test
  144. protected:
  145. bool CheckAccessTest(const char* test);
  146. void BeforeTest(const char* func);
  147. void Finish(const char* func, TTestContext* context);
  148. void AtStart();
  149. void AtEnd();
  150. void Run(std::function<void()> f, const TString& suite, const char* name, bool forceFork);
  151. class TCleanUp {
  152. public:
  153. explicit TCleanUp(TTestBase* base);
  154. ~TCleanUp();
  155. private:
  156. TTestBase* Base_;
  157. };
  158. void BeforeTest();
  159. void AfterTest();
  160. bool GetIsForked() const;
  161. bool GetForkTests() const;
  162. ITestSuiteProcessor* Processor() const noexcept;
  163. private:
  164. TTestFactory* Parent_;
  165. size_t TestErrors_;
  166. const char* CurrentSubtest_;
  167. TAdaptiveLock AfterTestFunctionsLock_;
  168. TVector<std::function<void()>> AfterTestFunctions_;
  169. };
  170. #define UNIT_TEST_SUITE(N) \
  171. typedef N TThisUnitTestSuite; \
  172. \
  173. public: \
  174. static TString StaticName() noexcept { \
  175. return TString(#N); \
  176. } \
  177. \
  178. private: \
  179. virtual TString Name() const noexcept override { \
  180. return this->StaticName(); \
  181. } \
  182. \
  183. virtual void Execute() override { \
  184. this->AtStart();
  185. #define UNIT_TEST_SUITE_DEMANGLE(N) \
  186. typedef N TThisUnitTestSuite; \
  187. \
  188. public: \
  189. static TString StaticName() noexcept { \
  190. return TypeName<N>(); \
  191. } \
  192. \
  193. private: \
  194. virtual TString Name() const noexcept override { \
  195. return this->StaticName(); \
  196. } \
  197. \
  198. virtual void Execute() override { \
  199. this->AtStart();
  200. #ifndef UT_SKIP_EXCEPTIONS
  201. #define CATCH_REACTION(FN, e, context) this->AddError(("(" + TypeName(e) + ") " + e.what()).data(), context)
  202. #define CATCH_REACTION_BT(FN, e, context) this->AddError(("(" + TypeName(e) + ") " + e.what()).data(), (e.BackTrace() ? e.BackTrace()->PrintToString() : TString()), context)
  203. #else
  204. #define CATCH_REACTION(FN, e, context) throw
  205. #define CATCH_REACTION_BT(FN, e, context) throw
  206. #endif
  207. #define UNIT_TEST_CHECK_TEST_IS_DECLARED_ONLY_ONCE(F) \
  208. /* If you see this message - delete multiple UNIT_TEST(TestName) with same TestName. */ \
  209. /* It's forbidden to declare same test twice because it breaks --fork-tests logic. */ \
  210. int You_have_declared_test_##F##_multiple_times_This_is_forbidden; \
  211. Y_UNUSED(You_have_declared_test_##F##_multiple_times_This_is_forbidden);
  212. #define UNIT_TEST_RUN(F, FF, context) \
  213. this->BeforeTest((#F)); \
  214. { \
  215. struct T##F##Caller { \
  216. static void X(TThisUnitTestSuite* thiz, NUnitTest::TTestContext&) { \
  217. TCleanUp cleaner(thiz); \
  218. thiz->F(); \
  219. } \
  220. }; \
  221. this->TTestBase::Run(std::bind(&T##F##Caller::X, this, context), StaticName(), (#F), FF); \
  222. }
  223. #define UNIT_TEST_IMPL(F, FF) \
  224. UNIT_TEST_CHECK_TEST_IS_DECLARED_ONLY_ONCE(F) { \
  225. NUnitTest::TTestContext context(this->TTestBase::Processor()); \
  226. if (this->CheckAccessTest((#F))) { \
  227. try { \
  228. UNIT_TEST_RUN(F, FF, context) \
  229. } catch (const ::NUnitTest::TAssertException&) { \
  230. } catch (const yexception& e) { \
  231. CATCH_REACTION_BT((#F), e, &context); \
  232. } catch (const std::exception& e) { \
  233. CATCH_REACTION((#F), e, &context); \
  234. } catch (...) { \
  235. this->AddError("non-std exception!", &context); \
  236. } \
  237. this->Finish((#F), &context); \
  238. } \
  239. }
  240. #define UNIT_TEST(F) UNIT_TEST_IMPL(F, false)
  241. #define UNIT_FORKED_TEST(F) UNIT_TEST_IMPL(F, true)
  242. #define UNIT_TEST_EXCEPTION(F, E) \
  243. /* main process with "--fork-tests" flag treats exceptions as errors - it's result of forked test run */ \
  244. if (this->GetForkTests() && !this->GetIsForked()) { \
  245. UNIT_TEST_IMPL(F, false); \
  246. /* forked process (or main without "--fork-tests") treats some exceptions as success - it's exception test! */ \
  247. } else { \
  248. NUnitTest::TTestContext context(this->TTestBase::Processor()); \
  249. if (this->CheckAccessTest((#F))) { \
  250. try { \
  251. UNIT_TEST_RUN(F, false, context) \
  252. this->AddError("exception expected", &context); \
  253. } catch (const ::NUnitTest::TAssertException&) { \
  254. } catch (const E& e) { \
  255. TString err; \
  256. if (!CheckExceptionMessage(e.what(), err)) \
  257. this->AddError(err.c_str(), &context); \
  258. } catch (const std::exception& e) { \
  259. this->AddError(e.what(), &context); \
  260. } catch (...) { \
  261. this->AddError("non-std exception!", &context); \
  262. } \
  263. this->Finish((#F), &context); \
  264. } \
  265. }
  266. #define UNIT_TEST_SUITE_END() \
  267. this->AtEnd(); \
  268. } \
  269. \
  270. public: \
  271. /*for ; after macros*/ void sub##F()
  272. #define UNIT_FAIL_IMPL(R, M) \
  273. do { \
  274. ::NUnitTest::NPrivate::RaiseError(R, ::TStringBuilder() << R << " at " << __LOCATION__ << ", " << __PRETTY_FUNCTION__ << ": " << M, true); \
  275. } while (false)
  276. #define UNIT_FAIL_NONFATAL_IMPL(R, M) \
  277. do { \
  278. ::NUnitTest::NPrivate::RaiseError(R, ::TStringBuilder() << R << " at " << __LOCATION__ << ", " << __PRETTY_FUNCTION__ << ": " << M, false); \
  279. } while (false)
  280. #define UNIT_FAIL(M) UNIT_FAIL_IMPL("forced failure", M)
  281. #define UNIT_FAIL_NONFATAL(M) UNIT_FAIL_NONFATAL_IMPL("forced failure", M)
  282. //types
  283. #define UNIT_ASSERT_TYPES_EQUAL(A, B) \
  284. do { \
  285. if (!std::is_same<A, B>::value) { \
  286. UNIT_FAIL_IMPL("types equal assertion failed", (::TStringBuilder() << #A << " (" << TypeName<A>() << ") != " << #B << " (" << TypeName<B>() << ")").data()); \
  287. } \
  288. } while (false)
  289. //doubles
  290. // UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED* macros do not handle NaNs correctly (see IGNIETFERRO-1419) and are for backward compatibility
  291. // only. Consider switching to regular UNIT_ASSERT_DOUBLES_EQUAL* macros if you're still using the deprecated version.
  292. #define UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED_C(E, A, D, C) \
  293. do { \
  294. if (std::abs((E) - (A)) > (D)) { \
  295. const auto _es = ToString((long double)(E)); \
  296. const auto _as = ToString((long double)(A)); \
  297. const auto _ds = ToString((long double)(D)); \
  298. auto&& failMsg = Sprintf("std::abs(%s - %s) > %s %s", _es.data(), _as.data(), _ds.data(), (::TStringBuilder() << C).data()); \
  299. UNIT_FAIL_IMPL("assertion failure", failMsg); \
  300. } \
  301. } while (false)
  302. #define UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED(E, A, D) UNIT_ASSERT_DOUBLES_EQUAL_DEPRECATED_C(E, A, D, "")
  303. #define UNIT_ASSERT_DOUBLES_EQUAL_C(E, A, D, C) \
  304. do { \
  305. const auto _ed = (E); \
  306. const auto _ad = (A); \
  307. const auto _dd = (D); \
  308. if (std::isnan((long double)_ed) && !std::isnan((long double)_ad)) { \
  309. const auto _as = ToString((long double)_ad); \
  310. auto&& failMsg = Sprintf("expected NaN, got %s %s", _as.data(), (::TStringBuilder() << C).data()); \
  311. UNIT_FAIL_IMPL("assertion failure", failMsg); \
  312. } \
  313. if (!std::isnan((long double)_ed) && std::isnan((long double)_ad)) { \
  314. const auto _es = ToString((long double)_ed); \
  315. auto&& failMsg = Sprintf("expected %s, got NaN %s", _es.data(), (::TStringBuilder() << C).data()); \
  316. UNIT_FAIL_IMPL("assertion failure", failMsg); \
  317. } \
  318. if (std::abs((_ed) - (_ad)) > (_dd)) { \
  319. const auto _es = ToString((long double)_ed); \
  320. const auto _as = ToString((long double)_ad); \
  321. const auto _ds = ToString((long double)_dd); \
  322. auto&& failMsg = Sprintf("std::abs(%s - %s) > %s %s", _es.data(), _as.data(), _ds.data(), (::TStringBuilder() << C).data()); \
  323. UNIT_FAIL_IMPL("assertion failure", failMsg); \
  324. } \
  325. } while (false)
  326. #define UNIT_ASSERT_DOUBLES_EQUAL(E, A, D) UNIT_ASSERT_DOUBLES_EQUAL_C(E, A, D, "")
  327. //strings
  328. #define UNIT_ASSERT_STRINGS_EQUAL_C(A, B, C) \
  329. do { \
  330. const TString _a(A); \
  331. const TString _b(B); \
  332. if (_a != _b) { \
  333. auto&& failMsg = Sprintf("%s != %s %s", ToString(_a).data(), ToString(_b).data(), (::TStringBuilder() << C).data()); \
  334. UNIT_FAIL_IMPL("strings equal assertion failed", failMsg); \
  335. } \
  336. } while (false)
  337. #define UNIT_ASSERT_STRINGS_EQUAL(A, B) UNIT_ASSERT_STRINGS_EQUAL_C(A, B, "")
  338. #define UNIT_ASSERT_STRING_CONTAINS_C(A, B, C) \
  339. do { \
  340. const TString _a(A); \
  341. const TString _b(B); \
  342. if (!_a.Contains(_b)) { \
  343. auto&& msg = Sprintf("\"%s\" does not contain \"%s\", %s", ToString(_a).data(), ToString(_b).data(), (::TStringBuilder() << C).data()); \
  344. UNIT_FAIL_IMPL("strings contains assertion failed", msg); \
  345. } \
  346. } while (false)
  347. #define UNIT_ASSERT_STRING_CONTAINS(A, B) UNIT_ASSERT_STRING_CONTAINS_C(A, B, "")
  348. #define UNIT_ASSERT_NO_DIFF(A, B) \
  349. do { \
  350. const TString _a(A); \
  351. const TString _b(B); \
  352. if (_a != _b) { \
  353. UNIT_FAIL_IMPL("strings (" #A ") and (" #B ") are different", Sprintf("\n%s", ::NUnitTest::ColoredDiff(_a, _b, " \t\n.,:;'\"").data())); \
  354. } \
  355. } while (false)
  356. //strings
  357. #define UNIT_ASSERT_STRINGS_UNEQUAL_C(A, B, C) \
  358. do { \
  359. const TString _a(A); \
  360. const TString _b(B); \
  361. if (_a == _b) { \
  362. auto&& msg = Sprintf("%s == %s %s", ToString(_a).data(), ToString(_b).data(), (::TStringBuilder() << C).data()); \
  363. UNIT_FAIL_IMPL("strings unequal assertion failed", msg); \
  364. } \
  365. } while (false)
  366. #define UNIT_ASSERT_STRINGS_UNEQUAL(A, B) UNIT_ASSERT_STRINGS_UNEQUAL_C(A, B, "")
  367. //bool
  368. #define UNIT_ASSERT_C(A, C) \
  369. do { \
  370. if (!(A)) { \
  371. UNIT_FAIL_IMPL("assertion failed", Sprintf("(%s) %s", #A, (::TStringBuilder() << C).data())); \
  372. } \
  373. } while (false)
  374. #define UNIT_ASSERT(A) UNIT_ASSERT_C(A, "")
  375. //general
  376. #define UNIT_ASSERT_EQUAL_C(A, B, C) \
  377. do { \
  378. if (!((A) == (B))) { \
  379. UNIT_FAIL_IMPL("equal assertion failed", Sprintf("%s == %s %s", #A, #B, (::TStringBuilder() << C).data())); \
  380. } \
  381. } while (false)
  382. #define UNIT_ASSERT_EQUAL(A, B) UNIT_ASSERT_EQUAL_C(A, B, "")
  383. #define UNIT_ASSERT_UNEQUAL_C(A, B, C) \
  384. do { \
  385. if ((A) == (B)) { \
  386. UNIT_FAIL_IMPL("unequal assertion failed", Sprintf("%s != %s %s", #A, #B, (::TStringBuilder() << C).data()));\
  387. } \
  388. } while (false)
  389. #define UNIT_ASSERT_UNEQUAL(A, B) UNIT_ASSERT_UNEQUAL_C(A, B, "")
  390. #define UNIT_ASSERT_LT_C(A, B, C) \
  391. do { \
  392. if (!((A) < (B))) { \
  393. UNIT_FAIL_IMPL("less-than assertion failed", Sprintf("%s < %s %s", #A, #B, (::TStringBuilder() << C).data())); \
  394. } \
  395. } while (false)
  396. #define UNIT_ASSERT_LT(A, B) UNIT_ASSERT_LT_C(A, B, "")
  397. #define UNIT_ASSERT_LE_C(A, B, C) \
  398. do { \
  399. if (!((A) <= (B))) { \
  400. UNIT_FAIL_IMPL("less-or-equal assertion failed", Sprintf("%s <= %s %s", #A, #B, (::TStringBuilder() << C).data())); \
  401. } \
  402. } while (false)
  403. #define UNIT_ASSERT_LE(A, B) UNIT_ASSERT_LE_C(A, B, "")
  404. #define UNIT_ASSERT_GT_C(A, B, C) \
  405. do { \
  406. if (!((A) > (B))) { \
  407. UNIT_FAIL_IMPL("greater-than assertion failed", Sprintf("%s > %s %s", #A, #B, (::TStringBuilder() << C).data())); \
  408. } \
  409. } while (false)
  410. #define UNIT_ASSERT_GT(A, B) UNIT_ASSERT_GT_C(A, B, "")
  411. #define UNIT_ASSERT_GE_C(A, B, C) \
  412. do { \
  413. if (!((A) >= (B))) { \
  414. UNIT_FAIL_IMPL("greater-or-equal assertion failed", Sprintf("%s >= %s %s", #A, #B, (::TStringBuilder() << C).data())); \
  415. } \
  416. } while (false)
  417. #define UNIT_ASSERT_GE(A, B) UNIT_ASSERT_GE_C(A, B, "")
  418. #define UNIT_CHECK_GENERATED_EXCEPTION_C(A, E, C) \
  419. do { \
  420. try { \
  421. (void)(A); \
  422. } catch (const ::NUnitTest::TAssertException&) { \
  423. throw; \
  424. } catch (const E&) { \
  425. break; \
  426. } \
  427. UNIT_ASSERT_C(0, "Exception hasn't been thrown, but it should have happened " << C); \
  428. } while (false)
  429. #define UNIT_CHECK_GENERATED_EXCEPTION(A, E) UNIT_CHECK_GENERATED_EXCEPTION_C(A, E, "")
  430. #define UNIT_CHECK_GENERATED_NO_EXCEPTION_C(A, E, C) \
  431. do { \
  432. try { \
  433. (void)(A); \
  434. } catch (const ::NUnitTest::TAssertException&) { \
  435. throw; \
  436. } catch (const E&) { \
  437. UNIT_ASSERT_C(0, "Exception has been thrown, but it shouldn't have happened " << C); \
  438. } \
  439. } while (false)
  440. #define UNIT_CHECK_GENERATED_NO_EXCEPTION(A, E) UNIT_CHECK_GENERATED_NO_EXCEPTION_C(A, E, "and exception message is:\n" << CurrentExceptionMessage())
  441. // Same as UNIT_ASSERT_EXCEPTION_SATISFIES but prints additional string C when nothing was thrown
  442. #define UNIT_ASSERT_EXCEPTION_SATISFIES_C(A, E, pred, C) \
  443. do { \
  444. bool _thrown = false; \
  445. try { \
  446. (void)(A); \
  447. } catch (const ::NUnitTest::TAssertException&) { \
  448. throw; \
  449. } catch (const E& e) { \
  450. _thrown = true; \
  451. UNIT_ASSERT_C(pred(e), "Exception does not satisfy predicate '" \
  452. << #pred << "'"); \
  453. } catch (...) { \
  454. _thrown = true; \
  455. UNIT_FAIL_IMPL("exception assertion failed", \
  456. #A << " did not throw " << #E \
  457. << ", but threw other exception " \
  458. << "with message:\n" \
  459. << CurrentExceptionMessage()); \
  460. } \
  461. if (!_thrown) { \
  462. UNIT_FAIL_IMPL("exception assertion failed", \
  463. #A << " did not throw any exception" \
  464. << " (expected " << #E << ") " << C); \
  465. } \
  466. } while (false)
  467. // Assert that a specific exception is thrown and satisfies predicate pred(e), where e is the exception instance.
  468. // Example:
  469. // UNIT_ASSERT_EXCEPTION_SATISFIES(MakeRequest(invalidData), TError,
  470. // [](const TError& e){ return e.Status == HTTP_BAD_REQUEST; })
  471. // This code validates that MakeRequest with invalidData throws TError with code 400.
  472. #define UNIT_ASSERT_EXCEPTION_SATISFIES(A, E, pred) \
  473. UNIT_ASSERT_EXCEPTION_SATISFIES_C(A, E, pred, "")
  474. // Same as UNIT_ASSERT_EXCEPTION_CONTAINS but prints additional string C when nothing was thrown
  475. #define UNIT_ASSERT_EXCEPTION_CONTAINS_C(A, E, substr, C) \
  476. do { \
  477. const TString _substr{substr}; \
  478. UNIT_ASSERT_EXCEPTION_SATISFIES_C(A, E, \
  479. [&_substr](const E&){ \
  480. if (!_substr.empty()) { \
  481. UNIT_ASSERT_C(CurrentExceptionMessage() \
  482. .Contains(_substr), \
  483. "Exception message does not contain \"" \
  484. << _substr << "\".\n" \
  485. << "Exception message: " \
  486. << CurrentExceptionMessage()); \
  487. } \
  488. return true; \
  489. }, \
  490. C); \
  491. } while (false)
  492. // Assert that a specific exception is thrown and CurrentExceptionMessage() contains substr
  493. #define UNIT_ASSERT_EXCEPTION_CONTAINS(A, E, substr) \
  494. UNIT_ASSERT_EXCEPTION_CONTAINS_C(A, E, substr, "")
  495. // Same as UNIT_ASSERT_EXCEPTION but prints additional string C when nothing was thrown
  496. #define UNIT_ASSERT_EXCEPTION_C(A, E, C) UNIT_ASSERT_EXCEPTION_SATISFIES_C(A, E, [](const E&){ return true; }, C)
  497. // Assert that a specific exception is thrown
  498. #define UNIT_ASSERT_EXCEPTION(A, E) UNIT_ASSERT_EXCEPTION_C(A, E, "")
  499. #define UNIT_ASSERT_NO_EXCEPTION_RESULT_C(A, C) \
  500. [&] () mutable -> decltype(A) { \
  501. static_assert(!std::is_void_v<decltype(A)>); \
  502. try { return (A); } \
  503. catch (const ::NUnitTest::TAssertException&) { throw; } \
  504. catch (...) { \
  505. UNIT_FAIL_IMPL( \
  506. "exception-free assertion failed", \
  507. Sprintf("%s throws %s\nException message: %s", \
  508. #A, (::TStringBuilder() << C).data(), \
  509. CurrentExceptionMessage().data())); \
  510. return decltype(A){}; \
  511. } \
  512. }()
  513. #define UNIT_ASSERT_NO_EXCEPTION_RESULT(A) UNIT_ASSERT_NO_EXCEPTION_RESULT_C(A, "")
  514. #define UNIT_ASSERT_NO_EXCEPTION_C(A, C) \
  515. do { \
  516. try { \
  517. (void)(A); \
  518. } catch (const ::NUnitTest::TAssertException&) { \
  519. throw; \
  520. } catch (...) { \
  521. UNIT_FAIL_IMPL("exception-free assertion failed", Sprintf("%s throws %s\nException message: %s", #A, (::TStringBuilder() << C).data(), CurrentExceptionMessage().data())); \
  522. } \
  523. } while (false)
  524. #define UNIT_ASSERT_NO_EXCEPTION(A) UNIT_ASSERT_NO_EXCEPTION_C(A, "")
  525. namespace NPrivate {
  526. template <class T, class U, bool Integers>
  527. struct TCompareValuesImpl {
  528. static inline bool Compare(const T& a, const U& b) {
  529. return a == b;
  530. }
  531. };
  532. template <class T, class U>
  533. struct TCompareValuesImpl<T, U, true> {
  534. static inline bool Compare(const T& a, const U& b) {
  535. return ::ToString(a) == ::ToString(b);
  536. }
  537. };
  538. template <class T, class U>
  539. using TCompareValues = TCompareValuesImpl<T, U, std::is_integral<T>::value && std::is_integral<U>::value>;
  540. template <typename T, typename U>
  541. static inline bool CompareEqual(const T& a, const U& b) {
  542. return TCompareValues<T, U>::Compare(a, b);
  543. }
  544. static inline bool CompareEqual(const char* a, const char* b) {
  545. return 0 == strcmp(a, b);
  546. }
  547. // helper method to avoid double evaluation of A and B expressions in UNIT_ASSERT_VALUES_EQUAL_C
  548. template <typename T, typename U>
  549. static inline bool CompareAndMakeStrings(const T& a, const U& b, TString& as, TString& asInd, TString& bs, TString& bsInd, bool& usePlainDiff, bool want) {
  550. const bool have = CompareEqual(a, b);
  551. usePlainDiff = std::is_integral<T>::value && std::is_integral<U>::value;
  552. if (want == have) {
  553. return true;
  554. }
  555. as = ::TStringBuilder() << ::DbgDump(a);
  556. bs = ::TStringBuilder() << ::DbgDump(b);
  557. asInd = ::TStringBuilder() << ::DbgDump(a).SetIndent(true);
  558. bsInd = ::TStringBuilder() << ::DbgDump(b).SetIndent(true);
  559. return false;
  560. }
  561. }
  562. //values
  563. #define UNIT_ASSERT_VALUES_EQUAL_IMPL(A, B, C, EQflag, EQstr, NEQstr) \
  564. do { \
  565. TString _as; \
  566. TString _bs; \
  567. TString _asInd; \
  568. TString _bsInd; \
  569. bool _usePlainDiff; \
  570. if (!::NUnitTest::NPrivate::CompareAndMakeStrings(A, B, _as, _asInd, _bs, _bsInd, _usePlainDiff, EQflag)) { \
  571. auto&& failMsg = Sprintf("(%s %s %s) failed: (%s %s %s) %s", #A, EQstr, #B, _as.data(), NEQstr, _bs.data(), (::TStringBuilder() << C).data()); \
  572. if (EQflag && !_usePlainDiff) { \
  573. failMsg += ", with diff:\n"; \
  574. failMsg += ::NUnitTest::ColoredDiff(_asInd, _bsInd); \
  575. } \
  576. UNIT_FAIL_IMPL("assertion failed", failMsg); \
  577. } \
  578. } while (false)
  579. #define UNIT_ASSERT_VALUES_EQUAL_C(A, B, C) \
  580. UNIT_ASSERT_VALUES_EQUAL_IMPL(A, B, C, true, "==", "!=")
  581. #define UNIT_ASSERT_VALUES_UNEQUAL_C(A, B, C) \
  582. UNIT_ASSERT_VALUES_EQUAL_IMPL(A, B, C, false, "!=", "==")
  583. #define UNIT_ASSERT_VALUES_EQUAL(A, B) UNIT_ASSERT_VALUES_EQUAL_C(A, B, "")
  584. #define UNIT_ASSERT_VALUES_UNEQUAL(A, B) UNIT_ASSERT_VALUES_UNEQUAL_C(A, B, "")
  585. // Checks that test will fail while executing given expression
  586. // Macro for using in unitests for ut helpers
  587. #define UNIT_ASSERT_TEST_FAILS_C(A, C) \
  588. do { \
  589. ::NUnitTest::TUnitTestFailChecker checker; \
  590. try { \
  591. auto guard = checker.InvokeGuard(); \
  592. (void)(A); \
  593. } catch (...) { \
  594. UNIT_FAIL_IMPL("fail test assertion failure", \
  595. "code is expected to generate test failure, " \
  596. "but it throws exception with message: " \
  597. << CurrentExceptionMessage()); \
  598. } \
  599. if (!checker.Failed()) { \
  600. UNIT_FAIL_IMPL("fail test assertion failure", \
  601. "code is expected to generate test failure"); \
  602. } \
  603. } while (false)
  604. #define UNIT_ASSERT_TEST_FAILS(A) UNIT_ASSERT_TEST_FAILS_C(A, "")
  605. #define UNIT_ADD_METRIC(name, value) ut_context.Metrics[name] = value
  606. class TTestFactory {
  607. friend class TTestBase;
  608. friend class ITestBaseFactory;
  609. public:
  610. static TTestFactory& Instance();
  611. unsigned Execute();
  612. void SetProcessor(ITestSuiteProcessor* processor);
  613. private:
  614. void Register(ITestBaseFactory* b) noexcept;
  615. ITestSuiteProcessor* Processor() const noexcept;
  616. private:
  617. explicit TTestFactory(ITestSuiteProcessor* processor);
  618. ~TTestFactory();
  619. private:
  620. TIntrusiveList<ITestBaseFactory> Items_;
  621. ITestSuiteProcessor* Processor_;
  622. };
  623. template <class T>
  624. class TTestBaseFactory: public ITestBaseFactory {
  625. public:
  626. ~TTestBaseFactory() override = default;
  627. inline TTestBase* ConstructTest() override {
  628. return new T;
  629. }
  630. inline TString Name() const noexcept override {
  631. return T::StaticName();
  632. }
  633. };
  634. struct TBaseTestCase {
  635. // NOTE: since EACH test case is instantiated for listing tests, its
  636. // ctor/dtor are not the best place to do heavy preparations in test fixtures.
  637. //
  638. // Consider using SetUp()/TearDown() methods instead
  639. inline TBaseTestCase()
  640. : TBaseTestCase(nullptr, nullptr, false)
  641. {
  642. }
  643. inline TBaseTestCase(const char* name, std::function<void(TTestContext&)> body, bool forceFork)
  644. : Name_(name)
  645. , Body_(std::move(body))
  646. , ForceFork_(forceFork)
  647. {
  648. }
  649. virtual ~TBaseTestCase() = default;
  650. // Each test case is executed in 3 steps:
  651. //
  652. // 1. SetUp() (from fixture)
  653. // 2. Execute_() (test body from Y_UNIT_TEST macro)
  654. // 3. TearDown() (from fixture)
  655. //
  656. // Both SetUp() and TearDown() may use UNIT_* check macros and are only
  657. // called when the test is executed.
  658. virtual void SetUp(TTestContext& /* context */) {
  659. }
  660. virtual void TearDown(TTestContext& /* context */) {
  661. }
  662. virtual void Execute_(TTestContext& context) {
  663. Body_(context);
  664. }
  665. const char* Name_;
  666. std::function<void(TTestContext&)> Body_;
  667. bool ForceFork_;
  668. };
  669. using TBaseFixture = TBaseTestCase;
  670. // Class for checking that code raises unittest failure
  671. class TUnitTestFailChecker {
  672. public:
  673. struct TInvokeGuard {
  674. explicit TInvokeGuard(TUnitTestFailChecker& parent)
  675. : Parent(&parent)
  676. {
  677. Parent->SetHandler();
  678. }
  679. TInvokeGuard(TInvokeGuard&& guard) noexcept
  680. : Parent(guard.Parent)
  681. {
  682. guard.Parent = nullptr;
  683. }
  684. ~TInvokeGuard() {
  685. if (Parent) {
  686. ClearRaiseErrorHandler();
  687. }
  688. }
  689. TUnitTestFailChecker* Parent;
  690. };
  691. TUnitTestFailChecker() = default;
  692. TUnitTestFailChecker(const TUnitTestFailChecker&) = delete;
  693. TUnitTestFailChecker(TUnitTestFailChecker&&) = delete;
  694. TInvokeGuard InvokeGuard() {
  695. return TInvokeGuard(*this);
  696. }
  697. const TString& What() const {
  698. return What_;
  699. }
  700. const TString& Msg() const {
  701. return Msg_;
  702. }
  703. bool FatalFailure() const {
  704. return FatalFailure_;
  705. }
  706. bool Failed() const {
  707. return Failed_;
  708. }
  709. private:
  710. void Handler(const char* what, const TString& msg, bool fatalFailure) {
  711. What_ = what;
  712. Msg_ = msg;
  713. FatalFailure_ = fatalFailure;
  714. Failed_ = true;
  715. }
  716. void SetHandler() {
  717. TRaiseErrorHandler handler = [this](const char* what, const TString& msg, bool fatalFailure) {
  718. Handler(what, msg, fatalFailure);
  719. };
  720. SetRaiseErrorHandler(std::move(handler));
  721. }
  722. private:
  723. TString What_;
  724. TString Msg_;
  725. bool FatalFailure_ = false;
  726. bool Failed_ = false;
  727. };
  728. #define UNIT_TEST_SUITE_REGISTRATION(T) \
  729. static const ::NUnitTest::TTestBaseFactory<T> Y_GENERATE_UNIQUE_ID(UTREG_);
  730. #define Y_UNIT_TEST_SUITE_IMPL_F(N, T, F) \
  731. namespace NTestSuite##N { \
  732. class TCurrentTestCase: public F { \
  733. }; \
  734. class TCurrentTest: public T { \
  735. private: \
  736. typedef std::function<THolder<NUnitTest::TBaseTestCase>()> TTestCaseFactory; \
  737. typedef TVector<TTestCaseFactory> TTests; \
  738. \
  739. static TTests& Tests() { \
  740. static TTests tests; \
  741. return tests; \
  742. } \
  743. \
  744. public: \
  745. static TString StaticName() { \
  746. return #N; \
  747. } \
  748. virtual TString Name() const noexcept { \
  749. return StaticName(); \
  750. } \
  751. \
  752. static void AddTest(const char* name, \
  753. const std::function<void(NUnitTest::TTestContext&)>& body, bool forceFork) \
  754. { \
  755. Tests().push_back([=]{ return MakeHolder<NUnitTest::TBaseTestCase>(name, body, forceFork); }); \
  756. } \
  757. \
  758. static void AddTest(TTestCaseFactory testCaseFactory) { \
  759. Tests().push_back(std::move(testCaseFactory)); \
  760. } \
  761. \
  762. virtual void Execute() { \
  763. this->AtStart(); \
  764. for (TTests::iterator it = Tests().begin(), ie = Tests().end(); it != ie; ++it) { \
  765. const auto i = (*it)(); \
  766. if (!this->CheckAccessTest(i->Name_)) { \
  767. continue; \
  768. } \
  769. NUnitTest::TTestContext context(this->TTestBase::Processor()); \
  770. try { \
  771. this->BeforeTest(i->Name_); \
  772. { \
  773. TCleanUp cleaner(this); \
  774. auto testCase = [&i, &context] { \
  775. i->SetUp(context); \
  776. i->Execute_(context); \
  777. i->TearDown(context); \
  778. }; \
  779. this->T::Run(testCase, StaticName(), i->Name_, i->ForceFork_); \
  780. } \
  781. } catch (const ::NUnitTest::TAssertException&) { \
  782. } catch (const yexception& e) { \
  783. CATCH_REACTION_BT(i->Name_, e, &context); \
  784. } catch (const std::exception& e) { \
  785. CATCH_REACTION(i->Name_, e, &context); \
  786. } catch (...) { \
  787. this->AddError("non-std exception!", &context); \
  788. } \
  789. this->Finish(i->Name_, &context); \
  790. } \
  791. this->AtEnd(); \
  792. } \
  793. }; \
  794. UNIT_TEST_SUITE_REGISTRATION(TCurrentTest) \
  795. } \
  796. namespace NTestSuite##N
  797. #define Y_UNIT_TEST_SUITE_IMPL(N, T) Y_UNIT_TEST_SUITE_IMPL_F(N, T, ::NUnitTest::TBaseTestCase)
  798. #define Y_UNIT_TEST_SUITE(N) Y_UNIT_TEST_SUITE_IMPL(N, TTestBase)
  799. #define Y_UNIT_TEST_SUITE_F(N, F) Y_UNIT_TEST_SUITE_IMPL_F(N, TTestBase, F)
  800. #define RUSAGE_UNIT_TEST_SUITE(N) Y_UNIT_TEST_SUITE_IMPL(N, NUnitTest::TRusageTest, ::NUnitTest::TBaseTestCase)
  801. #define Y_UNIT_TEST_IMPL_REGISTER(N, FF, F) \
  802. struct TTestCase##N : public F { \
  803. TTestCase##N() \
  804. : F() \
  805. { \
  806. Name_ = #N; \
  807. ForceFork_ = FF; \
  808. } \
  809. static THolder<NUnitTest::TBaseTestCase> Create() { \
  810. return ::MakeHolder<TTestCase##N>(); \
  811. } \
  812. void Execute_(NUnitTest::TTestContext&) override; \
  813. }; \
  814. struct TTestRegistration##N { \
  815. TTestRegistration##N() { \
  816. TCurrentTest::AddTest(TTestCase##N::Create); \
  817. } \
  818. }; \
  819. static const TTestRegistration##N testRegistration##N;
  820. #define Y_UNIT_TEST_IMPL(N, FF, F) \
  821. Y_UNIT_TEST_IMPL_REGISTER(N, FF, F) \
  822. void TTestCase##N::Execute_(NUnitTest::TTestContext& ut_context Y_DECLARE_UNUSED)
  823. #define Y_UNIT_TEST(N) Y_UNIT_TEST_IMPL(N, false, TCurrentTestCase)
  824. #define Y_UNIT_TEST_F(N, F) Y_UNIT_TEST_IMPL(N, false, F)
  825. #define SIMPLE_UNIT_FORKED_TEST(N) Y_UNIT_TEST_IMPL(N, true, TCurrentTestCase)
  826. #define Y_UNIT_TEST_SUITE_IMPLEMENTATION(N) \
  827. namespace NTestSuite##N
  828. #define Y_UNIT_TEST_DECLARE(N) \
  829. struct TTestCase##N
  830. #define Y_UNIT_TEST_FRIEND(N, T) \
  831. friend NTestSuite##N::TTestCase##T \
  832. TString RandomString(size_t len, ui32 seed = 0);
  833. }
  834. using ::NUnitTest::TTestBase;