1
2
3
4
5
6 #include <cmajor/rt/UnitTest.hpp>
7 #include <cmajor/rt/InitDone.hpp>
8 #include <sngxml/dom/Document.hpp>
9 #include <sngxml/dom/Element.hpp>
10 #include <soulng/util/CodeFormatter.hpp>
11 #include <soulng/util/Unicode.hpp>
12 #include <fstream>
13 #include <memory>
14 #include <string>
15 #include <vector>
16
17 namespace cmajor { namespace rt {
18
19 using namespace soulng::unicode;
20
21 const int assertionResultEmpty = 0;
22 const int assertionResultPassed = 1;
23 const int assertionResulFailed = 2;
24
25 struct AssertionResult
26 {
27 AssertionResult(int result_, int32_t line_) : result(result_), line(line_) {}
28 int result;
29 int32_t line;
30 };
31
32 class UnitTestEngine
33 {
34 public:
35 static void Init();
36 static void Done();
37 static UnitTestEngine& Instance() { return *instance; }
38 void StartUnitTest(int32_t numAssertions_, const char* unitTestFilePath_);
39 void EndUnitTest(const char* testName, int32_t exitCode);
40 void SetUnitTestAssertionResult(int32_t assertionIndex, bool assertionResult, int32_t line);
41 void SetUnitTestException(const std::string& exceptionStr_) { exceptionStr = exceptionStr_; }
42 private:
43 static std::unique_ptr<UnitTestEngine> instance;
44 int numAssertions;
45 std::string unitTestFilePath;
46 std::string exceptionStr;
47 std::vector<AssertionResult> assertionResults;
48 };
49
50 std::unique_ptr<UnitTestEngine> UnitTestEngine::instance;
51
52 void UnitTestEngine::Init()
53 {
54 instance.reset(new UnitTestEngine());
55 }
56
57 void UnitTestEngine::Done()
58 {
59 instance.reset();
60 }
61
62 void UnitTestEngine::StartUnitTest(int32_t numAssertions_, const char* unitTestFilePath_)
63 {
64 numAssertions = numAssertions_;
65 unitTestFilePath = unitTestFilePath_;
66 for (int32_t i = 0; i < numAssertions; ++i)
67 {
68 assertionResults.push_back(AssertionResult(assertionResultEmpty, 0));
69 }
70 }
71
72 void UnitTestEngine::EndUnitTest(const char* testName, int32_t exitCode)
73 {
74 std::ofstream testXmlFile(unitTestFilePath);
75 sngxml::dom::Document document;
76 std::unique_ptr<sngxml::dom::Element> testElement(new sngxml::dom::Element(U"test"));
77 testElement->SetAttribute(U"name", ToUtf32(testName));
78 for (int32_t i = 0; i < numAssertions; ++i)
79 {
80 std::unique_ptr<sngxml::dom::Element> assertionElement(new sngxml::dom::Element(U"assertion"));
81 assertionElement->SetAttribute(U"index", ToUtf32(std::to_string(i)));
82 const AssertionResult& assertionResult = assertionResults[i];
83 std::u32string assertionResultStr = U"empty";
84 if (assertionResult.result == assertionResultPassed)
85 {
86 assertionResultStr = U"passed";
87 }
88 else if (assertionResult.result == assertionResulFailed)
89 {
90 assertionResultStr = U"failed";
91 }
92 assertionElement->SetAttribute(U"result", assertionResultStr);
93 assertionElement->SetAttribute(U"line", ToUtf32(std::to_string(assertionResult.line)));
94 testElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(assertionElement.release()));
95 }
96 testElement->SetAttribute(U"exitCode", ToUtf32(std::to_string(exitCode)));
97 testElement->SetAttribute(U"count", ToUtf32(std::to_string(numAssertions)));
98 if (!exceptionStr.empty())
99 {
100 testElement->SetAttribute(U"exception", ToUtf32(exceptionStr));
101 }
102 document.AppendChild(std::unique_ptr<sngxml::dom::Node>(testElement.release()));
103 soulng::util::CodeFormatter formatter(testXmlFile);
104 formatter.SetIndentSize(2);
105 document.Write(formatter);
106 }
107
108 void UnitTestEngine::SetUnitTestAssertionResult(int32_t assertionIndex, bool assertionResult, int32_t line)
109 {
110 AssertionResult& ar = assertionResults[assertionIndex];
111 if (assertionResult)
112 {
113 if (ar.result == assertionResultEmpty || ar.result == assertionResultPassed)
114 {
115 assertionResults[assertionIndex] = AssertionResult(assertionResultPassed, line);
116 }
117 else
118 {
119 assertionResults[assertionIndex] = AssertionResult(assertionResulFailed, line);
120 }
121 }
122 else
123 {
124 assertionResults[assertionIndex] = AssertionResult(assertionResulFailed, line);
125 }
126 }
127
128 } }
129
130 extern "C" void RtStartUnitTest(int32_t numAssertions, const char* unitTestFilePath, int64_t numberOfPolymorphicClassIds, const uint64_t* polymorphicClassIdArray,
131 int64_t numberOfStaticClassIds, const uint64_t* staticClassIdArray)
132 {
133 RtInit(numberOfPolymorphicClassIds, polymorphicClassIdArray, numberOfStaticClassIds, staticClassIdArray, nullptr);
134 cmajor::rt::UnitTestEngine::Init();
135 cmajor::rt::UnitTestEngine::Instance().StartUnitTest(numAssertions, unitTestFilePath);
136 }
137
138 extern "C" void RtEndUnitTest(const char* testName, int32_t exitCode)
139 {
140 cmajor::rt::UnitTestEngine::Instance().EndUnitTest(testName, exitCode);
141 cmajor::rt::UnitTestEngine::Done();
142 RtDone();
143 RtExit(exitCode);
144 }
145
146 extern "C" void RtSetUnitTestAssertionResult(int32_t assertionIndex, bool assertionResult, int32_t line)
147 {
148 cmajor::rt::UnitTestEngine::Instance().SetUnitTestAssertionResult(assertionIndex, assertionResult, line);
149 }
150
151 extern "C" void RtSetUnitTestException(const char* exceptionStr)
152 {
153 cmajor::rt::UnitTestEngine::Instance().SetUnitTestException(exceptionStr);
154 }