registar.h 59 KB

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