registar.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. #include "registar.h"
  2. #include <library/cpp/diff/diff.h>
  3. #include <library/cpp/colorizer/colors.h>
  4. #include <util/generic/bt_exception.h>
  5. #include <util/random/fast.h>
  6. #include <util/string/printf.h>
  7. #include <util/system/backtrace.h>
  8. #include <util/system/guard.h>
  9. #include <util/system/tls.h>
  10. #include <util/system/error.h>
  11. #include <util/string/cast.h>
  12. bool NUnitTest::ShouldColorizeDiff = true;
  13. TString NUnitTest::RandomString(size_t len, ui32 seed) {
  14. TReallyFastRng32 rand(seed);
  15. TString ret;
  16. ret.reserve(len);
  17. for (size_t i = 0; i < len; ++i) {
  18. ret.push_back(char(rand.Uniform(1, 128)));
  19. }
  20. return ret;
  21. }
  22. Y_POD_STATIC_THREAD(bool)
  23. UnittestThread;
  24. Y_POD_STATIC_THREAD(NUnitTest::TTestBase*)
  25. currentTest;
  26. ::NUnitTest::TRaiseErrorHandler RaiseErrorHandler;
  27. void ::NUnitTest::NPrivate::RaiseError(const char* what, const TString& msg, bool fatalFailure) {
  28. Y_ABORT_UNLESS(UnittestThread, "%s in non-unittest thread with message:\n%s", what, msg.data());
  29. Y_ABORT_UNLESS(GetCurrentTest());
  30. if (RaiseErrorHandler) {
  31. RaiseErrorHandler(what, msg, fatalFailure);
  32. return;
  33. }
  34. // Default handler
  35. TBackTrace bt;
  36. bt.Capture();
  37. GetCurrentTest()->AddError(msg.data(), bt.PrintToString());
  38. if (!fatalFailure) {
  39. return;
  40. }
  41. throw TAssertException();
  42. }
  43. void ::NUnitTest::SetRaiseErrorHandler(::NUnitTest::TRaiseErrorHandler handler) {
  44. Y_ABORT_UNLESS(UnittestThread);
  45. RaiseErrorHandler = std::move(handler);
  46. }
  47. void ::NUnitTest::NPrivate::SetUnittestThread(bool unittestThread) {
  48. Y_ABORT_UNLESS(UnittestThread != unittestThread, "state check");
  49. UnittestThread = unittestThread;
  50. }
  51. void ::NUnitTest::NPrivate::SetCurrentTest(TTestBase* test) {
  52. Y_ABORT_UNLESS(!test || !currentTest, "state check");
  53. currentTest = test;
  54. }
  55. NUnitTest::TTestBase* ::NUnitTest::NPrivate::GetCurrentTest() {
  56. return currentTest;
  57. }
  58. struct TDiffColorizer {
  59. NColorizer::TColors Colors;
  60. bool Reverse = false;
  61. explicit TDiffColorizer(bool reverse = false)
  62. : Reverse(reverse)
  63. {
  64. }
  65. TString Special(TStringBuf str) const {
  66. return ToString(Colors.YellowColor()) + str;
  67. }
  68. TString Common(TArrayRef<const char> str) const {
  69. return ToString(Colors.OldColor()) + TString(str.begin(), str.end());
  70. }
  71. TString Left(TArrayRef<const char> str) const {
  72. return ToString(GetLeftColor()) + TString(str.begin(), str.end());
  73. }
  74. TString Right(TArrayRef<const char> str) const {
  75. return ToString(GetRightColor()) + TString(str.begin(), str.end());
  76. }
  77. TStringBuf GetLeftColor() const {
  78. return Reverse ? Colors.RedColor() : Colors.GreenColor();
  79. }
  80. TStringBuf GetRightColor() const {
  81. return Reverse ? Colors.GreenColor() : Colors.RedColor();
  82. }
  83. };
  84. struct TTraceDiffFormatter {
  85. bool Reverse = false;
  86. explicit TTraceDiffFormatter(bool reverse = false)
  87. : Reverse(reverse)
  88. {
  89. }
  90. TString Special(TStringBuf str) const {
  91. return ToString(str);
  92. }
  93. TString Common(TArrayRef<const char> str) const {
  94. return TString(str.begin(), str.end());
  95. }
  96. TString Left(TArrayRef<const char> str) const {
  97. return NUnitTest::GetFormatTag("good") +
  98. TString(str.begin(), str.end()) +
  99. NUnitTest::GetResetTag();
  100. }
  101. TString Right(TArrayRef<const char> str) const {
  102. return NUnitTest::GetFormatTag("bad") +
  103. TString(str.begin(), str.end()) +
  104. NUnitTest::GetResetTag();
  105. }
  106. };
  107. TString NUnitTest::GetFormatTag(const char* name) {
  108. return Sprintf("[[%s]]", name);
  109. }
  110. TString NUnitTest::GetResetTag() {
  111. return TString("[[rst]]");
  112. }
  113. TString NUnitTest::ColoredDiff(TStringBuf s1, TStringBuf s2, const TString& delims, bool reverse) {
  114. TStringStream res;
  115. TVector<NDiff::TChunk<char>> chunks;
  116. NDiff::InlineDiff(chunks, s1, s2, delims);
  117. if (NUnitTest::ShouldColorizeDiff) {
  118. NDiff::PrintChunks(res, TDiffColorizer(reverse), chunks);
  119. } else {
  120. res << NUnitTest::GetResetTag();
  121. NDiff::PrintChunks(res, TTraceDiffFormatter(reverse), chunks);
  122. }
  123. return res.Str();
  124. }
  125. static TString MakeTestName(const NUnitTest::ITestSuiteProcessor::TTest& test) {
  126. return TStringBuilder() << test.unit->name << "::" << test.name;
  127. }
  128. static size_t CountTests(const TMap<TString, size_t>& testErrors, bool succeeded) {
  129. size_t cnt = 0;
  130. for (const auto& t : testErrors) {
  131. if (succeeded && t.second == 0) {
  132. ++cnt;
  133. } else if (!succeeded && t.second > 0) {
  134. ++cnt;
  135. }
  136. }
  137. return cnt;
  138. }
  139. NUnitTest::ITestSuiteProcessor::ITestSuiteProcessor() = default;
  140. NUnitTest::ITestSuiteProcessor::~ITestSuiteProcessor() = default;
  141. void NUnitTest::ITestSuiteProcessor::Start() {
  142. OnStart();
  143. }
  144. void NUnitTest::ITestSuiteProcessor::End() {
  145. OnEnd();
  146. }
  147. void NUnitTest::ITestSuiteProcessor::UnitStart(const TUnit& unit) {
  148. CurTestErrors_.clear();
  149. OnUnitStart(&unit);
  150. }
  151. void NUnitTest::ITestSuiteProcessor::UnitStop(const TUnit& unit) {
  152. OnUnitStop(&unit);
  153. }
  154. void NUnitTest::ITestSuiteProcessor::Error(const TError& descr) {
  155. AddTestError(*descr.test);
  156. OnError(&descr);
  157. }
  158. void NUnitTest::ITestSuiteProcessor::BeforeTest(const TTest& test) {
  159. OnBeforeTest(&test);
  160. }
  161. void NUnitTest::ITestSuiteProcessor::Finish(const TFinish& descr) {
  162. AddTestFinish(*descr.test);
  163. OnFinish(&descr);
  164. }
  165. unsigned NUnitTest::ITestSuiteProcessor::GoodTests() const noexcept {
  166. return CountTests(TestErrors_, true);
  167. }
  168. unsigned NUnitTest::ITestSuiteProcessor::FailTests() const noexcept {
  169. return CountTests(TestErrors_, false);
  170. }
  171. unsigned NUnitTest::ITestSuiteProcessor::GoodTestsInCurrentUnit() const noexcept {
  172. return CountTests(CurTestErrors_, true);
  173. }
  174. unsigned NUnitTest::ITestSuiteProcessor::FailTestsInCurrentUnit() const noexcept {
  175. return CountTests(CurTestErrors_, false);
  176. }
  177. bool NUnitTest::ITestSuiteProcessor::CheckAccess(TString /*name*/, size_t /*num*/) {
  178. return true;
  179. }
  180. bool NUnitTest::ITestSuiteProcessor::CheckAccessTest(TString /*suite*/, const char* /*name*/) {
  181. return true;
  182. }
  183. void NUnitTest::ITestSuiteProcessor::Run(std::function<void()> f, const TString& /*suite*/, const char* /*name*/, const bool /*forceFork*/) {
  184. f();
  185. }
  186. void NUnitTest::ITestSuiteProcessor::SetForkTestsParams(bool forkTests, bool isForked) {
  187. ForkTests_ = forkTests;
  188. IsForked_ = isForked;
  189. }
  190. bool NUnitTest::ITestSuiteProcessor::GetIsForked() const {
  191. return IsForked_;
  192. }
  193. bool NUnitTest::ITestSuiteProcessor::GetForkTests() const {
  194. return ForkTests_;
  195. }
  196. void NUnitTest::ITestSuiteProcessor::OnStart() {
  197. }
  198. void NUnitTest::ITestSuiteProcessor::OnEnd() {
  199. }
  200. void NUnitTest::ITestSuiteProcessor::OnUnitStart(const TUnit* /*unit*/) {
  201. }
  202. void NUnitTest::ITestSuiteProcessor::OnUnitStop(const TUnit* /*unit*/) {
  203. }
  204. void NUnitTest::ITestSuiteProcessor::OnError(const TError* /*error*/) {
  205. }
  206. void NUnitTest::ITestSuiteProcessor::OnFinish(const TFinish* /*finish*/) {
  207. }
  208. void NUnitTest::ITestSuiteProcessor::OnBeforeTest(const TTest* /*test*/) {
  209. }
  210. void NUnitTest::ITestSuiteProcessor::AddTestError(const TTest& test) {
  211. const TString name = MakeTestName(test);
  212. ++TestErrors_[name];
  213. ++CurTestErrors_[name];
  214. }
  215. void NUnitTest::ITestSuiteProcessor::AddTestFinish(const TTest& test) {
  216. const TString name = MakeTestName(test);
  217. TestErrors_[name]; // zero errors if not touched
  218. CurTestErrors_[name]; // zero errors if not touched
  219. }
  220. NUnitTest::ITestBaseFactory::ITestBaseFactory() {
  221. Register();
  222. }
  223. NUnitTest::ITestBaseFactory::~ITestBaseFactory() = default;
  224. void NUnitTest::ITestBaseFactory::Register() noexcept {
  225. TTestFactory::Instance().Register(this);
  226. }
  227. NUnitTest::TTestBase::TTestBase() noexcept
  228. : Parent_(nullptr)
  229. , TestErrors_()
  230. , CurrentSubtest_()
  231. {
  232. }
  233. NUnitTest::TTestBase::~TTestBase() = default;
  234. TString NUnitTest::TTestBase::TypeId() const {
  235. return TypeName(*this);
  236. }
  237. void NUnitTest::TTestBase::SetUp() {
  238. }
  239. void NUnitTest::TTestBase::TearDown() {
  240. }
  241. void NUnitTest::TTestBase::AddError(const char* msg, const TString& backtrace, TTestContext* context) {
  242. ++TestErrors_;
  243. const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
  244. const NUnitTest::ITestSuiteProcessor::TTest test = {&unit, CurrentSubtest_};
  245. const NUnitTest::ITestSuiteProcessor::TError err = {&test, msg, backtrace, context};
  246. Processor()->Error(err);
  247. }
  248. void NUnitTest::TTestBase::AddError(const char* msg, TTestContext* context) {
  249. AddError(msg, TString(), context);
  250. }
  251. void NUnitTest::TTestBase::RunAfterTest(std::function<void()> f) {
  252. with_lock (AfterTestFunctionsLock_) {
  253. AfterTestFunctions_.emplace_back(std::move(f));
  254. }
  255. }
  256. bool NUnitTest::TTestBase::CheckAccessTest(const char* test) {
  257. return Processor()->CheckAccessTest(Name(), test);
  258. }
  259. void NUnitTest::TTestBase::BeforeTest(const char* func) {
  260. const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
  261. const NUnitTest::ITestSuiteProcessor::TTest test = {&unit, func};
  262. rusage.Fill();
  263. Processor()->BeforeTest(test);
  264. }
  265. void NUnitTest::TTestBase::Finish(const char* func, TTestContext* context) {
  266. TRusage finishRusage = TRusage::Get();
  267. context->Metrics["ru_rss"] = finishRusage.MaxRss - rusage.MaxRss;
  268. context->Metrics["ru_major_pagefaults"] = finishRusage.MajorPageFaults - rusage.MajorPageFaults;
  269. context->Metrics["ru_utime"] = (finishRusage.Utime - rusage.Utime).MicroSeconds();
  270. context->Metrics["ru_stime"] = (finishRusage.Stime - rusage.Stime).MicroSeconds();
  271. const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
  272. const NUnitTest::ITestSuiteProcessor::TTest test = {&unit, func};
  273. const NUnitTest::ITestSuiteProcessor::TFinish finish = {&test, context, TestErrors_ == 0};
  274. Processor()->Finish(finish);
  275. }
  276. void NUnitTest::TTestBase::AtStart() {
  277. const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
  278. Processor()->UnitStart(unit);
  279. }
  280. void NUnitTest::TTestBase::AtEnd() {
  281. const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
  282. Processor()->UnitStop(unit);
  283. }
  284. void NUnitTest::TTestBase::Run(std::function<void()> f, const TString& suite, const char* name, const bool forceFork) {
  285. TestErrors_ = 0;
  286. CurrentSubtest_ = name;
  287. Processor()->Run(f, suite, name, forceFork);
  288. }
  289. void NUnitTest::TTestBase::BeforeTest() {
  290. SetUp();
  291. }
  292. void NUnitTest::TTestBase::AfterTest() {
  293. TearDown();
  294. TVector<std::function<void()>> afterTestFunctions;
  295. with_lock (AfterTestFunctionsLock_) {
  296. afterTestFunctions.swap(AfterTestFunctions_);
  297. }
  298. for (auto i = afterTestFunctions.rbegin(); i != afterTestFunctions.rend(); ++i) {
  299. std::function<void()>& f = *i;
  300. if (f) {
  301. f();
  302. }
  303. }
  304. }
  305. bool NUnitTest::TTestBase::GetIsForked() const {
  306. return Processor()->GetIsForked();
  307. }
  308. bool NUnitTest::TTestBase::GetForkTests() const {
  309. return Processor()->GetForkTests();
  310. }
  311. NUnitTest::ITestSuiteProcessor* NUnitTest::TTestBase::Processor() const noexcept {
  312. return Parent_->Processor();
  313. }
  314. NUnitTest::TTestBase::TCleanUp::TCleanUp(TTestBase* base)
  315. : Base_(base)
  316. {
  317. ::NUnitTest::NPrivate::SetCurrentTest(base);
  318. ::NUnitTest::NPrivate::SetUnittestThread(true);
  319. Base_->BeforeTest();
  320. }
  321. NUnitTest::TTestBase::TCleanUp::~TCleanUp() {
  322. try {
  323. Base_->AfterTest();
  324. } catch (...) {
  325. Base_->AddError(CurrentExceptionMessage().data());
  326. }
  327. ::NUnitTest::NPrivate::SetUnittestThread(false);
  328. ::NUnitTest::NPrivate::SetCurrentTest(nullptr);
  329. }
  330. namespace {
  331. /*
  332. * by default do nothing
  333. */
  334. class TCommonProcessor: public NUnitTest::ITestSuiteProcessor {
  335. public:
  336. TCommonProcessor() = default;
  337. ~TCommonProcessor() override = default;
  338. };
  339. struct TCmp {
  340. template <class T>
  341. inline bool operator()(const T& l, const T& r) const noexcept {
  342. return stricmp(Fix(l.Name().data()), Fix(r.Name().data())) < 0;
  343. }
  344. static inline const char* Fix(const char* n) noexcept {
  345. if (*n == 'T') {
  346. return n + 1;
  347. }
  348. return n;
  349. }
  350. };
  351. }
  352. NUnitTest::TTestFactory::TTestFactory(ITestSuiteProcessor* processor)
  353. : Processor_(processor)
  354. {
  355. }
  356. NUnitTest::TTestFactory::~TTestFactory() = default;
  357. NUnitTest::TTestFactory& NUnitTest::TTestFactory::Instance() {
  358. static TCommonProcessor p;
  359. static TTestFactory f(&p);
  360. return f;
  361. }
  362. unsigned NUnitTest::TTestFactory::Execute() {
  363. Items_.QuickSort(TCmp());
  364. Processor_->Start();
  365. TSet<TString> types;
  366. size_t cnt = 0;
  367. for (TIntrusiveList<ITestBaseFactory>::TIterator factory = Items_.Begin(); factory != Items_.End(); ++factory) {
  368. if (!Processor_->CheckAccess(factory->Name(), cnt++)) {
  369. continue;
  370. }
  371. THolder<TTestBase> test(factory->ConstructTest());
  372. #ifdef _unix_ // on Windows RTTI causes memory leaks
  373. TString type = test->TypeId();
  374. if (types.insert(type).second == false) {
  375. warnx("Duplicate suite found: %s (%s). Probably you have copy-pasted suite without changing it name", factory->Name().c_str(), type.c_str());
  376. return 1;
  377. }
  378. #endif // _unix_
  379. test->Parent_ = this;
  380. #ifdef UT_SKIP_EXCEPTIONS
  381. try {
  382. #endif
  383. test->Execute();
  384. #ifdef UT_SKIP_EXCEPTIONS
  385. } catch (...) {
  386. }
  387. #endif
  388. }
  389. Processor_->End();
  390. return bool(Processor_->FailTests());
  391. }
  392. void NUnitTest::TTestFactory::SetProcessor(ITestSuiteProcessor* processor) {
  393. Processor_ = processor;
  394. }
  395. void NUnitTest::TTestFactory::Register(ITestBaseFactory* b) noexcept {
  396. Items_.PushBack(b);
  397. }
  398. NUnitTest::ITestSuiteProcessor* NUnitTest::TTestFactory::Processor() const noexcept {
  399. return Processor_;
  400. }