aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/testing/unittest/junit.cpp
blob: f5fe84a937caa1644b3ff1c9ceb35de2d983fd56 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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