aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/testing/unittest
diff options
context:
space:
mode:
authoralexv-smirnov <alex@ydb.tech>2023-03-16 13:59:59 +0300
committeralexv-smirnov <alex@ydb.tech>2023-03-16 13:59:59 +0300
commit648fc9d7949c88a6ebaaf110289b8b4536bb9a16 (patch)
treec46c89a2e46516c986af3e4ecb44d927bbdfcbac /library/cpp/testing/unittest
parent4568fe3f6ddb72499ef17f5e0a1e7e2475a9570b (diff)
downloadydb-648fc9d7949c88a6ebaaf110289b8b4536bb9a16.tar.gz
JUnitXML output for unittest
Diffstat (limited to 'library/cpp/testing/unittest')
-rw-r--r--library/cpp/testing/unittest/CMakeLists.darwin-x86_64.txt2
-rw-r--r--library/cpp/testing/unittest/CMakeLists.linux-aarch64.txt2
-rw-r--r--library/cpp/testing/unittest/CMakeLists.linux-x86_64.txt2
-rw-r--r--library/cpp/testing/unittest/CMakeLists.windows-x86_64.txt2
-rw-r--r--library/cpp/testing/unittest/junit.cpp104
-rw-r--r--library/cpp/testing/unittest/junit.h82
-rw-r--r--library/cpp/testing/unittest/utmain.cpp22
-rw-r--r--library/cpp/testing/unittest/ya.make2
8 files changed, 218 insertions, 0 deletions
diff --git a/library/cpp/testing/unittest/CMakeLists.darwin-x86_64.txt b/library/cpp/testing/unittest/CMakeLists.darwin-x86_64.txt
index 64dc3e1a7a..1aeaa1a60b 100644
--- a/library/cpp/testing/unittest/CMakeLists.darwin-x86_64.txt
+++ b/library/cpp/testing/unittest/CMakeLists.darwin-x86_64.txt
@@ -11,6 +11,7 @@ add_library(cpp-testing-unittest)
target_link_libraries(cpp-testing-unittest PUBLIC
contrib-libs-cxxsupp
yutil
+ contrib-libs-libxml
library-cpp-colorizer
library-cpp-dbg_output
library-cpp-diff
@@ -21,6 +22,7 @@ target_link_libraries(cpp-testing-unittest PUBLIC
target_sources(cpp-testing-unittest PRIVATE
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/gtest.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/checks.cpp
+ ${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/junit.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/plugin.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/registar.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/tests_data.cpp
diff --git a/library/cpp/testing/unittest/CMakeLists.linux-aarch64.txt b/library/cpp/testing/unittest/CMakeLists.linux-aarch64.txt
index 860a713a0b..bb5187334f 100644
--- a/library/cpp/testing/unittest/CMakeLists.linux-aarch64.txt
+++ b/library/cpp/testing/unittest/CMakeLists.linux-aarch64.txt
@@ -12,6 +12,7 @@ target_link_libraries(cpp-testing-unittest PUBLIC
contrib-libs-linux-headers
contrib-libs-cxxsupp
yutil
+ contrib-libs-libxml
library-cpp-colorizer
library-cpp-dbg_output
library-cpp-diff
@@ -22,6 +23,7 @@ target_link_libraries(cpp-testing-unittest PUBLIC
target_sources(cpp-testing-unittest PRIVATE
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/gtest.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/checks.cpp
+ ${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/junit.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/plugin.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/registar.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/tests_data.cpp
diff --git a/library/cpp/testing/unittest/CMakeLists.linux-x86_64.txt b/library/cpp/testing/unittest/CMakeLists.linux-x86_64.txt
index 860a713a0b..bb5187334f 100644
--- a/library/cpp/testing/unittest/CMakeLists.linux-x86_64.txt
+++ b/library/cpp/testing/unittest/CMakeLists.linux-x86_64.txt
@@ -12,6 +12,7 @@ target_link_libraries(cpp-testing-unittest PUBLIC
contrib-libs-linux-headers
contrib-libs-cxxsupp
yutil
+ contrib-libs-libxml
library-cpp-colorizer
library-cpp-dbg_output
library-cpp-diff
@@ -22,6 +23,7 @@ target_link_libraries(cpp-testing-unittest PUBLIC
target_sources(cpp-testing-unittest PRIVATE
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/gtest.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/checks.cpp
+ ${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/junit.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/plugin.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/registar.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/tests_data.cpp
diff --git a/library/cpp/testing/unittest/CMakeLists.windows-x86_64.txt b/library/cpp/testing/unittest/CMakeLists.windows-x86_64.txt
index 64dc3e1a7a..1aeaa1a60b 100644
--- a/library/cpp/testing/unittest/CMakeLists.windows-x86_64.txt
+++ b/library/cpp/testing/unittest/CMakeLists.windows-x86_64.txt
@@ -11,6 +11,7 @@ add_library(cpp-testing-unittest)
target_link_libraries(cpp-testing-unittest PUBLIC
contrib-libs-cxxsupp
yutil
+ contrib-libs-libxml
library-cpp-colorizer
library-cpp-dbg_output
library-cpp-diff
@@ -21,6 +22,7 @@ target_link_libraries(cpp-testing-unittest PUBLIC
target_sources(cpp-testing-unittest PRIVATE
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/gtest.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/checks.cpp
+ ${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/junit.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/plugin.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/registar.cpp
${CMAKE_SOURCE_DIR}/library/cpp/testing/unittest/tests_data.cpp
diff --git a/library/cpp/testing/unittest/junit.cpp b/library/cpp/testing/unittest/junit.cpp
new file mode 100644
index 0000000000..f5fe84a937
--- /dev/null
+++ b/library/cpp/testing/unittest/junit.cpp
@@ -0,0 +1,104 @@
+#include "junit.h"
+
+#include <libxml/xmlwriter.h>
+#include <util/system/fs.h>
+#include <util/system/file.h>
+
+namespace NUnitTest {
+
+#define CHECK_CALL(expr) if ((expr) < 0) { \
+ Cerr << "Faield to write to xml" << Endl; \
+ return; \
+}
+
+#define XML_STR(s) ((const xmlChar*)(s))
+
+void TJUnitProcessor::Save() {
+ TString path = FileName;
+ auto sz = path.size();
+ TFile lockFile;
+ TFile reportFile;
+ TString lockFileName;
+ const int MaxReps = 200;
+#if defined(_win_)
+ const char dirSeparator = '\\';
+#else
+ const char dirSeparator = '/';
+#endif
+ if ((sz == 0) or (path[sz - 1] == dirSeparator)) {
+ if (sz > 0) {
+ NFs::MakeDirectoryRecursive(path);
+ }
+ TString reportFileName;
+ for (int i = 0; i < MaxReps; i++) {
+ TString suffix = (i > 0) ? ("-" + std::to_string(i)) : "";
+ lockFileName = path + ExecName + suffix + ".lock";
+ try {
+ lockFile = TFile(lockFileName, EOpenModeFlag::CreateNew);
+ } catch (const TFileError&) {}
+ if (lockFile.IsOpen()) {
+ // Inside a lock, ensure the .xml file does not exist
+ reportFileName = path + ExecName + suffix + ".xml";
+ try {
+ reportFile = TFile(reportFileName, EOpenModeFlag::OpenExisting | EOpenModeFlag::RdOnly);
+ } catch (const TFileError&) {
+ break;
+ }
+ reportFile.Close();
+ lockFile.Close();
+ NFs::Remove(lockFileName);
+ }
+ }
+ if (!lockFile.IsOpen()) {
+ Cerr << "Could not find a vacant file name to write report, maximum number of reports: " << MaxReps << Endl;
+ Y_FAIL("Cannot write report");
+ }
+ path = reportFileName;
+ }
+ auto file = xmlNewTextWriterFilename(path.c_str(), 0);
+ if (!file) {
+ Cerr << "Failed to open xml file for writing: " << path.c_str() << Endl;
+ return;
+ }
+
+ CHECK_CALL(xmlTextWriterStartDocument(file, nullptr, "UTF-8", nullptr));
+ CHECK_CALL(xmlTextWriterStartElement(file, XML_STR("testsuites")));
+ CHECK_CALL(xmlTextWriterWriteAttribute(file, XML_STR("tests"), XML_STR(ToString(GetTestsCount()).c_str())));
+ CHECK_CALL(xmlTextWriterWriteAttribute(file, XML_STR("failures"), XML_STR(ToString(GetFailuresCount()).c_str())));
+
+ for (const auto& [suiteName, suite] : Suites) {
+ CHECK_CALL(xmlTextWriterStartElement(file, XML_STR("testsuite")));
+ CHECK_CALL(xmlTextWriterWriteAttribute(file, XML_STR("name"), XML_STR(suiteName.c_str())));
+ CHECK_CALL(xmlTextWriterWriteAttribute(file, XML_STR("id"), XML_STR(suiteName.c_str())));
+ CHECK_CALL(xmlTextWriterWriteAttribute(file, XML_STR("tests"), XML_STR(ToString(suite.GetTestsCount()).c_str())));
+ CHECK_CALL(xmlTextWriterWriteAttribute(file, XML_STR("failures"), XML_STR(ToString(suite.GetFailuresCount()).c_str())));
+
+ for (const auto& [testName, test] : suite.Cases) {
+ CHECK_CALL(xmlTextWriterStartElement(file, XML_STR("testcase")));
+ CHECK_CALL(xmlTextWriterWriteAttribute(file, XML_STR("name"), XML_STR(testName.c_str())));
+ CHECK_CALL(xmlTextWriterWriteAttribute(file, XML_STR("id"), XML_STR(testName.c_str())));
+
+ for (const auto& failure : test.Failures) {
+ CHECK_CALL(xmlTextWriterStartElement(file, XML_STR("failure")));
+ CHECK_CALL(xmlTextWriterWriteAttribute(file, XML_STR("message"), XML_STR(failure.c_str())));
+ CHECK_CALL(xmlTextWriterWriteAttribute(file, XML_STR("type"), XML_STR("ERROR")));
+ CHECK_CALL(xmlTextWriterEndElement(file));
+ }
+
+ CHECK_CALL(xmlTextWriterEndElement(file));
+ }
+
+ CHECK_CALL(xmlTextWriterEndElement(file));
+ }
+
+ CHECK_CALL(xmlTextWriterEndElement(file));
+ CHECK_CALL(xmlTextWriterEndDocument(file));
+ xmlFreeTextWriter(file);
+
+ if (lockFile.IsOpen()) {
+ lockFile.Close();
+ NFs::Remove(lockFileName.c_str());
+ }
+}
+
+} // namespace NUnitTest
diff --git a/library/cpp/testing/unittest/junit.h b/library/cpp/testing/unittest/junit.h
new file mode 100644
index 0000000000..f5113c290e
--- /dev/null
+++ b/library/cpp/testing/unittest/junit.h
@@ -0,0 +1,82 @@
+#include "registar.h"
+
+namespace NUnitTest {
+
+class TJUnitProcessor : public ITestSuiteProcessor {
+ struct TTestCase {
+ TString Name;
+ bool Success;
+ TVector<TString> Failures;
+
+ size_t GetFailuresCount() const {
+ return Failures.size();
+ }
+ };
+
+ struct TTestSuite {
+ TMap<TString, TTestCase> Cases;
+
+ size_t GetTestsCount() const {
+ return Cases.size();
+ }
+
+ size_t GetFailuresCount() const {
+ size_t sum = 0;
+ for (const auto& [name, testCase] : Cases) {
+ sum += testCase.GetFailuresCount();
+ }
+ return sum;
+ }
+ };
+
+public:
+ TJUnitProcessor(TString file, TString exec)
+ : FileName(file)
+ , ExecName(exec)
+ {
+ }
+
+ ~TJUnitProcessor() {
+ Save();
+ }
+
+ void OnError(const TError* descr) override {
+ auto* testCase = GetTestCase(descr->test);
+ testCase->Failures.emplace_back(descr->msg);
+ }
+
+ void OnFinish(const TFinish* descr) override {
+ GetTestCase(descr->test)->Success = descr->Success;
+ }
+
+private:
+ TTestCase* GetTestCase(const TTest* test) {
+ auto& suite = Suites[test->unit->name];
+ return &suite.Cases[test->name];
+ }
+
+ void Save();
+
+ size_t GetTestsCount() const {
+ size_t sum = 0;
+ for (const auto& [name, suite] : Suites) {
+ sum += suite.GetTestsCount();
+ }
+ return sum;
+ }
+
+ size_t GetFailuresCount() const {
+ size_t sum = 0;
+ for (const auto& [name, suite] : Suites) {
+ sum += suite.GetFailuresCount();
+ }
+ return sum;
+ }
+
+private:
+ TString FileName;
+ TString ExecName;
+ TMap<TString, TTestSuite> Suites;
+};
+
+} // namespace NUnitTest
diff --git a/library/cpp/testing/unittest/utmain.cpp b/library/cpp/testing/unittest/utmain.cpp
index a55b6f399b..4e10da24e5 100644
--- a/library/cpp/testing/unittest/utmain.cpp
+++ b/library/cpp/testing/unittest/utmain.cpp
@@ -1,3 +1,4 @@
+#include "junit.h"
#include "plugin.h"
#include "registar.h"
#include "utmain.h"
@@ -668,6 +669,16 @@ int NUnitTest::RunMain(int argc, char** argv) {
};
EListType listTests = DONT_LIST;
+ TString oo(getenv("Y_UNITTEST_OUTPUT"));
+ if (oo.StartsWith("xml:")) {
+ TStringBuf fileName = oo;
+ fileName = fileName.SubString(4, TStringBuf::npos);
+ processor.BeQuiet();
+ NUnitTest::ShouldColorizeDiff = false;
+ processor.SetTraceProcessor(new TJUnitProcessor(TString(fileName), argv[0]));
+ }
+
+
for (size_t i = 1; i < (size_t)argc; ++i) {
const char* name = argv[i];
@@ -723,6 +734,17 @@ int NUnitTest::RunMain(int argc, char** argv) {
TString param(argv[i]);
size_t assign = param.find('=');
Singleton<::NPrivate::TTestEnv>()->AddTestParam(param.substr(0, assign), param.substr(assign + 1));
+ } else if (strcmp(name, "--output") == 0) {
+ ++i;
+ Y_ENSURE((int)i < argc);
+ TString param(argv[i]);
+ if (param.StartsWith("xml:")) {
+ TStringBuf fileName = param;
+ fileName = fileName.SubString(4, TStringBuf::npos);
+ processor.BeQuiet();
+ NUnitTest::ShouldColorizeDiff = false;
+ processor.SetTraceProcessor(new TJUnitProcessor(TString(fileName), argv[0]));
+ }
} else if (TString(name).StartsWith("--")) {
return DoUsage(argv[0]), 1;
} else if (*name == '-') {
diff --git a/library/cpp/testing/unittest/ya.make b/library/cpp/testing/unittest/ya.make
index 74bc67e83f..f9fa7a09b3 100644
--- a/library/cpp/testing/unittest/ya.make
+++ b/library/cpp/testing/unittest/ya.make
@@ -3,6 +3,7 @@ LIBRARY()
PROVIDES(test_framework)
PEERDIR(
+ contrib/libs/libxml
library/cpp/colorizer
library/cpp/dbg_output
library/cpp/diff
@@ -14,6 +15,7 @@ PEERDIR(
SRCS(
gtest.cpp
checks.cpp
+ junit.cpp
plugin.cpp
registar.cpp
tests_data.cpp