trial.reporters.xunit 106/107(99%) line coverage

      
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
29238
300
31238
32238
33238
34238
35238
360
37238
380
390
400
410
420
430
440
450
460
470
481
491
500
510
520
531
540
550
560
570
580
590
600
610
621
631
640
650
66129
6742
6842
690
7042
710
720
730
740
750
760
770
780
790
800
810
820
830
8447
85273
860
870
88273
89273
9047
91226
924
933
940
9547
9646
970
980
9947
1000
1010
1020
10347
1040
1050
1060
1070
1080
1090
1100
1110
1120
1130
1140
1150
1161
1171
1181
1190
1201
1211
1221
1231
1240
1251
1260
1271
1280
1291
1300
1312
1320
1330
1340
1350
1360
1370
1380
1390
1401
1411
1421
1430
1441
1451
1461
1471
1480
1491
1500
1511
1520
1531
1540
1552
1560
1570
1580
1590
1600
1610
1620
1630
1640
1651
1661
1671
1680
1691
1701
1711
1721
1730
1741
1750
1761
1770
1781
1790
1802
1810
1820
1830
1840
1850
1860
1870
1880
1890
1900
1911
1921
1931
1940
1951
1961
1971
1981
1990
2001
2010
2021
2030
2041
2050
2062
2070
2080
2090
2100
2110
2120
2130
2140
2150
2161
2171
2181
2191
2200
2211
2220
2232
2240
2250
2260
2270
2280
2290
2300
2310
2320
2330
2340
2350
236228
237228
2380
239228
2403
2412
2420
2432
2440
2451
2460
247225
2481
249224
2501
2510
2520
253228
2540
255228
2560
2570
2580
2590
2600
2610
2621
2630
2641
2651
2661
2671
2680
2691
2700
2712
2720
2730
2740
2750
2760
2771
2781
2791
2801
2811
2821
2830
2841
2852
2860
2870
2880
/++ A module containing the XUnitReporter Copyright: © 2017 Szabo Bogdan License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. Authors: Szabo Bogdan +/ module trial.reporters.xunit; import std.stdio; import std.array; import std.conv; import std.datetime; import std.string; import std.algorithm; import std.file; import std.path; import std.uuid; import std.range; import trial.interfaces; import trial.reporters.writer; version (Have_fluent_asserts) { version = Have_fluent_asserts_core; } private string escapeXUnit(string data) { string escapedData = data.dup; escapedData = escapedData.replace(`&`, `&`); escapedData = escapedData.replace(`"`, `"`); escapedData = escapedData.replace(`'`, `'`); escapedData = escapedData.replace(`<`, `<`); escapedData = escapedData.replace(`>`, `>`); return escapedData; } /// The XUnit reporter creates a xml containing the test results class XUnitReporter : ILifecycleListener { private { immutable string destination; } this(string destination) { this.destination = destination; } void begin(ulong testCount) { if(exists(destination)) { std.file.rmdirRecurse(destination); } } void update() {} void end(SuiteResult[] result) { if(!exists(destination)) { destination.mkdirRecurse; } foreach(item; result) { string uuid = randomUUID.toString; string xml = `<?xml version="1.0" encoding="UTF-8"?>` ~ "\n"~ `<testsuites>` ~ "\n" ~ XUnitSuiteXml(item, uuid).toString ~ "\n</testsuites>\n"; std.file.write(buildPath(destination, item.name ~ ".xml"), xml); } } } struct XUnitSuiteXml { /// The suite result SuiteResult result; /// The suite id string uuid; /// Converts the suiteResult to a xml string string toString() { auto epoch = SysTime.fromUnixTime(0); string tests = result.tests.map!(a => XUnitTestXml(a, uuid).toString).array.join("\n"); auto failures = result.tests.filter!(a => a.status == TestResult.Status.failure).count; auto skipped = result.tests.filter!(a => a.status == TestResult.Status.skip).count; auto errors = result.tests.filter!(a => a.status != TestResult.Status.success && a.status != TestResult.Status.skip && a.status != TestResult.Status.failure).count; if(tests != "") { tests = "\n" ~ tests; } auto xml = ` <testsuite name="` ~ result.name ~ `" errors="` ~ errors.to!string ~ `" skipped="` ~ skipped.to!string ~ `" tests="` ~ result.tests.length.to!string ~ `" failures="` ~ failures.to!string ~ `" time="0" timestamp="` ~ result.begin.toISOExtString ~ `">` ~ tests ~ ` </testsuite>`; return xml; } } version(unittest) { version(Have_fluent_asserts_core) { import fluent.asserts; } } /// XUnitTestXml should transform a suite with a success test unittest { auto epoch = SysTime.fromUnixTime(0); auto result = SuiteResult("Test Suite"); result.begin = Clock.currTime; TestResult test = new TestResult("Test"); test.begin = Clock.currTime; test.end = Clock.currTime; test.status = TestResult.Status.success; result.end = Clock.currTime; result.tests = [ test ]; auto xunit = XUnitSuiteXml(result); xunit.toString.should.equal(` <testsuite name="` ~ result.name.escapeXUnit ~ `" errors="0" skipped="0" tests="1" failures="0" time="0" timestamp="`~result.begin.toISOExtString~`"> <testcase name="Test"> </testcase> </testsuite>`); } /// XUnitTestXml should transform a suite with a failed test unittest { auto epoch = SysTime.fromUnixTime(0); auto result = SuiteResult("Test Suite"); result.begin = Clock.currTime; TestResult test = new TestResult("Test"); test.begin = Clock.currTime; test.end = Clock.currTime; test.status = TestResult.Status.failure; result.end = Clock.currTime; result.tests = [ test ]; auto xunit = XUnitSuiteXml(result); xunit.toString.should.equal(` <testsuite name="` ~ result.name.escapeXUnit ~ `" errors="0" skipped="0" tests="1" failures="1" time="0" timestamp="`~result.begin.toISOExtString~`"> <testcase name="Test"> <failure/> </testcase> </testsuite>`); } /// XUnitTestXml should transform a suite with a skipped test unittest { auto epoch = SysTime.fromUnixTime(0); auto result = SuiteResult("Test Suite"); result.begin = Clock.currTime; TestResult test = new TestResult("Test"); test.begin = Clock.currTime; test.end = Clock.currTime; test.status = TestResult.Status.skip; result.end = Clock.currTime; result.tests = [ test ]; auto xunit = XUnitSuiteXml(result); xunit.toString.should.equal(` <testsuite name="` ~ result.name.escapeXUnit ~ `" errors="0" skipped="1" tests="1" failures="0" time="0" timestamp="`~result.begin.toISOExtString~`"> <testcase name="Test"> <skipped/> </testcase> </testsuite>`); } /// XUnitTestXml should transform a suite with a unknown test unittest { auto epoch = SysTime.fromUnixTime(0); auto result = SuiteResult("Test Suite"); result.begin = Clock.currTime; TestResult test = new TestResult("Test"); test.begin = Clock.currTime; test.end = Clock.currTime; test.status = TestResult.Status.unknown; result.end = Clock.currTime; result.tests = [ test ]; auto xunit = XUnitSuiteXml(result); xunit.toString.should.equal(` <testsuite name="` ~ result.name.escapeXUnit ~ `" errors="1" skipped="0" tests="1" failures="0" time="0" timestamp="`~result.begin.toISOExtString~`"> <testcase name="Test"> <error message="unknown status">unknown</error> </testcase> </testsuite>`); } /// XUnitTestXml should transform an empty suite unittest { auto epoch = SysTime.fromUnixTime(0); auto result = SuiteResult("Test Suite"); result.begin = Clock.currTime; result.end = Clock.currTime; auto xunit = XUnitSuiteXml(result); xunit.toString.should.equal(` <testsuite name="` ~ result.name.escapeXUnit ~ `" errors="0" skipped="0" tests="0" failures="0" time="0" timestamp="` ~ result.begin.toISOExtString ~ `"> </testsuite>`); } struct XUnitTestXml { /// TestResult result; /// string uuid; /// Return the string representation of the test string toString() { auto time = (result.end -result.begin).total!"msecs"; string xml = ` <testcase name="` ~ result.name.escapeXUnit ~ `">` ~ "\n"; if(result.status == TestResult.Status.failure) { if(result.throwable !is null) { auto lines = result.throwable.msg.split("\n") ~ "no message"; xml ~= ` <failure message="` ~ lines[0].escapeXUnit ~ `">` ~ result.throwable.to!string.escapeXUnit ~ `</failure>` ~ "\n"; } else { xml ~= ` <failure/>` ~ "\n"; } } else if(result.status == TestResult.Status.skip) { xml ~= ` <skipped/>` ~ "\n"; } else if(result.status != TestResult.Status.success) { xml ~= ` <error message="unknown status">` ~ result.status.to!string.escapeXUnit ~ `</error>` ~ "\n"; } xml ~= ` </testcase>`; return xml; } } /// XUnitTestXml should transform a success test unittest { auto epoch = SysTime.fromUnixTime(0); TestResult result = new TestResult("Test"); result.begin = Clock.currTime; result.end = Clock.currTime; result.status = TestResult.Status.success; auto allure = XUnitTestXml(result); allure.toString.strip.should.equal(`<testcase name="Test">` ~ "\n </testcase>"); } /// XUnitTestXml should transform a failing test unittest { auto epoch = SysTime.fromUnixTime(0); TestResult result = new TestResult("Test"); result.begin = Clock.currTime; result.end = Clock.currTime; result.status = TestResult.Status.failure; result.throwable = new Exception("message"); auto xunit = XUnitTestXml(result); xunit.toString.strip.should.equal(`<testcase name="Test">` ~ "\n" ~ ` <failure message="message">` ~ result.throwable.to!string ~ `</failure>` ~ "\n" ~ ` </testcase>`); }