123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- #include "registar.h"
- #include <library/cpp/diff/diff.h>
- #include <library/cpp/colorizer/colors.h>
- #include <util/generic/bt_exception.h>
- #include <util/random/fast.h>
- #include <util/string/printf.h>
- #include <util/system/backtrace.h>
- #include <util/system/guard.h>
- #include <util/system/tls.h>
- #include <util/system/error.h>
- #include <util/string/cast.h>
- bool NUnitTest::ShouldColorizeDiff = true;
- TString NUnitTest::RandomString(size_t len, ui32 seed) {
- TReallyFastRng32 rand(seed);
- TString ret;
- ret.reserve(len);
- for (size_t i = 0; i < len; ++i) {
- ret.push_back(char(rand.Uniform(1, 128)));
- }
- return ret;
- }
- Y_POD_STATIC_THREAD(bool)
- UnittestThread;
- Y_POD_STATIC_THREAD(NUnitTest::TTestBase*)
- currentTest;
- ::NUnitTest::TRaiseErrorHandler RaiseErrorHandler;
- void ::NUnitTest::NPrivate::RaiseError(const char* what, const TString& msg, bool fatalFailure) {
- Y_ABORT_UNLESS(UnittestThread, "%s in non-unittest thread with message:\n%s", what, msg.data());
- Y_ABORT_UNLESS(GetCurrentTest());
- if (RaiseErrorHandler) {
- RaiseErrorHandler(what, msg, fatalFailure);
- return;
- }
- // Default handler
- TBackTrace bt;
- bt.Capture();
- GetCurrentTest()->AddError(msg.data(), bt.PrintToString());
- if (!fatalFailure) {
- return;
- }
- throw TAssertException();
- }
- void ::NUnitTest::SetRaiseErrorHandler(::NUnitTest::TRaiseErrorHandler handler) {
- Y_ABORT_UNLESS(UnittestThread);
- RaiseErrorHandler = std::move(handler);
- }
- void ::NUnitTest::NPrivate::SetUnittestThread(bool unittestThread) {
- Y_ABORT_UNLESS(UnittestThread != unittestThread, "state check");
- UnittestThread = unittestThread;
- }
- void ::NUnitTest::NPrivate::SetCurrentTest(TTestBase* test) {
- Y_ABORT_UNLESS(!test || !currentTest, "state check");
- currentTest = test;
- }
- NUnitTest::TTestBase* ::NUnitTest::NPrivate::GetCurrentTest() {
- return currentTest;
- }
- struct TDiffColorizer {
- NColorizer::TColors Colors;
- bool Reverse = false;
- explicit TDiffColorizer(bool reverse = false)
- : Reverse(reverse)
- {
- }
- TString Special(TStringBuf str) const {
- return ToString(Colors.YellowColor()) + str;
- }
- TString Common(TArrayRef<const char> str) const {
- return ToString(Colors.OldColor()) + TString(str.begin(), str.end());
- }
- TString Left(TArrayRef<const char> str) const {
- return ToString(GetLeftColor()) + TString(str.begin(), str.end());
- }
- TString Right(TArrayRef<const char> str) const {
- return ToString(GetRightColor()) + TString(str.begin(), str.end());
- }
- TStringBuf GetLeftColor() const {
- return Reverse ? Colors.RedColor() : Colors.GreenColor();
- }
- TStringBuf GetRightColor() const {
- return Reverse ? Colors.GreenColor() : Colors.RedColor();
- }
- };
- struct TTraceDiffFormatter {
- bool Reverse = false;
- explicit TTraceDiffFormatter(bool reverse = false)
- : Reverse(reverse)
- {
- }
- TString Special(TStringBuf str) const {
- return ToString(str);
- }
- TString Common(TArrayRef<const char> str) const {
- return TString(str.begin(), str.end());
- }
- TString Left(TArrayRef<const char> str) const {
- return NUnitTest::GetFormatTag("good") +
- TString(str.begin(), str.end()) +
- NUnitTest::GetResetTag();
- }
- TString Right(TArrayRef<const char> str) const {
- return NUnitTest::GetFormatTag("bad") +
- TString(str.begin(), str.end()) +
- NUnitTest::GetResetTag();
- }
- };
- TString NUnitTest::GetFormatTag(const char* name) {
- return Sprintf("[[%s]]", name);
- }
- TString NUnitTest::GetResetTag() {
- return TString("[[rst]]");
- }
- TString NUnitTest::ColoredDiff(TStringBuf s1, TStringBuf s2, const TString& delims, bool reverse) {
- TStringStream res;
- TVector<NDiff::TChunk<char>> chunks;
- NDiff::InlineDiff(chunks, s1, s2, delims);
- if (NUnitTest::ShouldColorizeDiff) {
- NDiff::PrintChunks(res, TDiffColorizer(reverse), chunks);
- } else {
- res << NUnitTest::GetResetTag();
- NDiff::PrintChunks(res, TTraceDiffFormatter(reverse), chunks);
- }
- return res.Str();
- }
- static TString MakeTestName(const NUnitTest::ITestSuiteProcessor::TTest& test) {
- return TStringBuilder() << test.unit->name << "::" << test.name;
- }
- static size_t CountTests(const TMap<TString, size_t>& testErrors, bool succeeded) {
- size_t cnt = 0;
- for (const auto& t : testErrors) {
- if (succeeded && t.second == 0) {
- ++cnt;
- } else if (!succeeded && t.second > 0) {
- ++cnt;
- }
- }
- return cnt;
- }
- NUnitTest::ITestSuiteProcessor::ITestSuiteProcessor() = default;
- NUnitTest::ITestSuiteProcessor::~ITestSuiteProcessor() = default;
- void NUnitTest::ITestSuiteProcessor::Start() {
- OnStart();
- }
- void NUnitTest::ITestSuiteProcessor::End() {
- OnEnd();
- }
- void NUnitTest::ITestSuiteProcessor::UnitStart(const TUnit& unit) {
- CurTestErrors_.clear();
- OnUnitStart(&unit);
- }
- void NUnitTest::ITestSuiteProcessor::UnitStop(const TUnit& unit) {
- OnUnitStop(&unit);
- }
- void NUnitTest::ITestSuiteProcessor::Error(const TError& descr) {
- AddTestError(*descr.test);
- OnError(&descr);
- }
- void NUnitTest::ITestSuiteProcessor::BeforeTest(const TTest& test) {
- OnBeforeTest(&test);
- }
- void NUnitTest::ITestSuiteProcessor::Finish(const TFinish& descr) {
- AddTestFinish(*descr.test);
- OnFinish(&descr);
- }
- unsigned NUnitTest::ITestSuiteProcessor::GoodTests() const noexcept {
- return CountTests(TestErrors_, true);
- }
- unsigned NUnitTest::ITestSuiteProcessor::FailTests() const noexcept {
- return CountTests(TestErrors_, false);
- }
- unsigned NUnitTest::ITestSuiteProcessor::GoodTestsInCurrentUnit() const noexcept {
- return CountTests(CurTestErrors_, true);
- }
- unsigned NUnitTest::ITestSuiteProcessor::FailTestsInCurrentUnit() const noexcept {
- return CountTests(CurTestErrors_, false);
- }
- bool NUnitTest::ITestSuiteProcessor::CheckAccess(TString /*name*/, size_t /*num*/) {
- return true;
- }
- bool NUnitTest::ITestSuiteProcessor::CheckAccessTest(TString /*suite*/, const char* /*name*/) {
- return true;
- }
- void NUnitTest::ITestSuiteProcessor::Run(std::function<void()> f, const TString& /*suite*/, const char* /*name*/, const bool /*forceFork*/) {
- f();
- }
- void NUnitTest::ITestSuiteProcessor::SetForkTestsParams(bool forkTests, bool isForked) {
- ForkTests_ = forkTests;
- IsForked_ = isForked;
- }
- bool NUnitTest::ITestSuiteProcessor::GetIsForked() const {
- return IsForked_;
- }
- bool NUnitTest::ITestSuiteProcessor::GetForkTests() const {
- return ForkTests_;
- }
- void NUnitTest::ITestSuiteProcessor::OnStart() {
- }
- void NUnitTest::ITestSuiteProcessor::OnEnd() {
- }
- void NUnitTest::ITestSuiteProcessor::OnUnitStart(const TUnit* /*unit*/) {
- }
- void NUnitTest::ITestSuiteProcessor::OnUnitStop(const TUnit* /*unit*/) {
- }
- void NUnitTest::ITestSuiteProcessor::OnError(const TError* /*error*/) {
- }
- void NUnitTest::ITestSuiteProcessor::OnFinish(const TFinish* /*finish*/) {
- }
- void NUnitTest::ITestSuiteProcessor::OnBeforeTest(const TTest* /*test*/) {
- }
- void NUnitTest::ITestSuiteProcessor::AddTestError(const TTest& test) {
- const TString name = MakeTestName(test);
- ++TestErrors_[name];
- ++CurTestErrors_[name];
- }
- void NUnitTest::ITestSuiteProcessor::AddTestFinish(const TTest& test) {
- const TString name = MakeTestName(test);
- TestErrors_[name]; // zero errors if not touched
- CurTestErrors_[name]; // zero errors if not touched
- }
- NUnitTest::ITestBaseFactory::ITestBaseFactory() {
- Register();
- }
- NUnitTest::ITestBaseFactory::~ITestBaseFactory() = default;
- void NUnitTest::ITestBaseFactory::Register() noexcept {
- TTestFactory::Instance().Register(this);
- }
- NUnitTest::TTestBase::TTestBase() noexcept
- : Parent_(nullptr)
- , TestErrors_()
- , CurrentSubtest_()
- {
- }
- NUnitTest::TTestBase::~TTestBase() = default;
- TString NUnitTest::TTestBase::TypeId() const {
- return TypeName(*this);
- }
- void NUnitTest::TTestBase::SetUp() {
- }
- void NUnitTest::TTestBase::TearDown() {
- }
- void NUnitTest::TTestBase::AddError(const char* msg, const TString& backtrace, TTestContext* context) {
- ++TestErrors_;
- const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
- const NUnitTest::ITestSuiteProcessor::TTest test = {&unit, CurrentSubtest_};
- const NUnitTest::ITestSuiteProcessor::TError err = {&test, msg, backtrace, context};
- Processor()->Error(err);
- }
- void NUnitTest::TTestBase::AddError(const char* msg, TTestContext* context) {
- AddError(msg, TString(), context);
- }
- void NUnitTest::TTestBase::RunAfterTest(std::function<void()> f) {
- with_lock (AfterTestFunctionsLock_) {
- AfterTestFunctions_.emplace_back(std::move(f));
- }
- }
- bool NUnitTest::TTestBase::CheckAccessTest(const char* test) {
- return Processor()->CheckAccessTest(Name(), test);
- }
- void NUnitTest::TTestBase::BeforeTest(const char* func) {
- const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
- const NUnitTest::ITestSuiteProcessor::TTest test = {&unit, func};
- rusage.Fill();
- Processor()->BeforeTest(test);
- }
- void NUnitTest::TTestBase::Finish(const char* func, TTestContext* context) {
- TRusage finishRusage = TRusage::Get();
- context->Metrics["ru_rss"] = finishRusage.MaxRss - rusage.MaxRss;
- context->Metrics["ru_major_pagefaults"] = finishRusage.MajorPageFaults - rusage.MajorPageFaults;
- context->Metrics["ru_utime"] = (finishRusage.Utime - rusage.Utime).MicroSeconds();
- context->Metrics["ru_stime"] = (finishRusage.Stime - rusage.Stime).MicroSeconds();
- const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
- const NUnitTest::ITestSuiteProcessor::TTest test = {&unit, func};
- const NUnitTest::ITestSuiteProcessor::TFinish finish = {&test, context, TestErrors_ == 0};
- Processor()->Finish(finish);
- }
- void NUnitTest::TTestBase::AtStart() {
- const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
- Processor()->UnitStart(unit);
- }
- void NUnitTest::TTestBase::AtEnd() {
- const NUnitTest::ITestSuiteProcessor::TUnit unit = {Name()};
- Processor()->UnitStop(unit);
- }
- void NUnitTest::TTestBase::Run(std::function<void()> f, const TString& suite, const char* name, const bool forceFork) {
- TestErrors_ = 0;
- CurrentSubtest_ = name;
- Processor()->Run(f, suite, name, forceFork);
- }
- void NUnitTest::TTestBase::BeforeTest() {
- SetUp();
- }
- void NUnitTest::TTestBase::AfterTest() {
- TearDown();
- TVector<std::function<void()>> afterTestFunctions;
- with_lock (AfterTestFunctionsLock_) {
- afterTestFunctions.swap(AfterTestFunctions_);
- }
- for (auto i = afterTestFunctions.rbegin(); i != afterTestFunctions.rend(); ++i) {
- std::function<void()>& f = *i;
- if (f) {
- f();
- }
- }
- }
- bool NUnitTest::TTestBase::GetIsForked() const {
- return Processor()->GetIsForked();
- }
- bool NUnitTest::TTestBase::GetForkTests() const {
- return Processor()->GetForkTests();
- }
- NUnitTest::ITestSuiteProcessor* NUnitTest::TTestBase::Processor() const noexcept {
- return Parent_->Processor();
- }
- NUnitTest::TTestBase::TCleanUp::TCleanUp(TTestBase* base)
- : Base_(base)
- {
- ::NUnitTest::NPrivate::SetCurrentTest(base);
- ::NUnitTest::NPrivate::SetUnittestThread(true);
- Base_->BeforeTest();
- }
- NUnitTest::TTestBase::TCleanUp::~TCleanUp() {
- try {
- Base_->AfterTest();
- } catch (...) {
- Base_->AddError(CurrentExceptionMessage().data());
- }
- ::NUnitTest::NPrivate::SetUnittestThread(false);
- ::NUnitTest::NPrivate::SetCurrentTest(nullptr);
- }
- namespace {
- /*
- * by default do nothing
- */
- class TCommonProcessor: public NUnitTest::ITestSuiteProcessor {
- public:
- TCommonProcessor() = default;
- ~TCommonProcessor() override = default;
- };
- struct TCmp {
- template <class T>
- inline bool operator()(const T& l, const T& r) const noexcept {
- return stricmp(Fix(l.Name().data()), Fix(r.Name().data())) < 0;
- }
- static inline const char* Fix(const char* n) noexcept {
- if (*n == 'T') {
- return n + 1;
- }
- return n;
- }
- };
- }
- NUnitTest::TTestFactory::TTestFactory(ITestSuiteProcessor* processor)
- : Processor_(processor)
- {
- }
- NUnitTest::TTestFactory::~TTestFactory() = default;
- NUnitTest::TTestFactory& NUnitTest::TTestFactory::Instance() {
- static TCommonProcessor p;
- static TTestFactory f(&p);
- return f;
- }
- unsigned NUnitTest::TTestFactory::Execute() {
- Items_.QuickSort(TCmp());
- Processor_->Start();
- TSet<TString> types;
- size_t cnt = 0;
- for (TIntrusiveList<ITestBaseFactory>::TIterator factory = Items_.Begin(); factory != Items_.End(); ++factory) {
- if (!Processor_->CheckAccess(factory->Name(), cnt++)) {
- continue;
- }
- THolder<TTestBase> test(factory->ConstructTest());
- #ifdef _unix_ // on Windows RTTI causes memory leaks
- TString type = test->TypeId();
- if (types.insert(type).second == false) {
- warnx("Duplicate suite found: %s (%s). Probably you have copy-pasted suite without changing it name", factory->Name().c_str(), type.c_str());
- return 1;
- }
- #endif // _unix_
- test->Parent_ = this;
- #ifdef UT_SKIP_EXCEPTIONS
- try {
- #endif
- test->Execute();
- #ifdef UT_SKIP_EXCEPTIONS
- } catch (...) {
- }
- #endif
- }
- Processor_->End();
- return bool(Processor_->FailTests());
- }
- void NUnitTest::TTestFactory::SetProcessor(ITestSuiteProcessor* processor) {
- Processor_ = processor;
- }
- void NUnitTest::TTestFactory::Register(ITestBaseFactory* b) noexcept {
- Items_.PushBack(b);
- }
- NUnitTest::ITestSuiteProcessor* NUnitTest::TTestFactory::Processor() const noexcept {
- return Processor_;
- }
|