trial.executor.single 71/71(100%) 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
299
309
310
320
330
340
353
361
371
380
390
402
410
420
430
440
450
4611
4711
4811
4911
500
510
520
530
540
5511
5611
5711
580
590
600
610
620
639
640
650
660
670
680
699
700
711
720
730
748
758
768
770
780
790
800
810
820
83213
84213
850
86213
87213
880
89213
900
91213
92213
930
94213
950
960
970
98213
99211
1000
1010
1021
1030
1040
1050
1061
1071
1080
1090
110213
1110
112213
1130
1140
1150
1160
1170
1180
119213
120213
1210
122213
1230
12447
1250
12639
12739
12839
1290
1300
13147
13247
1330
1340
135213
136213
137213
138213
1390
140213
1410
1420
1430
1440
1450
1460
1470
1480
1490
1500
1511
1521
1531
1540
1550
1561
1570
1580
1591
1601
1610
1620
1631
1641
1650
1662
1672
1680
1690
1700
1710
1720
1730
1741
1751
1761
1770
1780
1791
1800
1810
1821
1831
1840
1850
1861
1870
1881
1891
1900
1910
1921
1930
1941
1950
1962
1972
1980
/++ A module containing the single threaded runner 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.executor.single; public import trial.interfaces; import trial.runner; import std.datetime; import trial.step; import trial.stackresult; /** The default test executor runs test in sequential order in a single thread */ class DefaultExecutor : ITestExecutor, IStepLifecycleListener, IAttachmentListener { private { SuiteResult suiteResult; TestResult testResult; StepResult currentStep; StepResult[] stepStack; } this() { suiteResult = SuiteResult("unknown"); } /// Called when an attachment is ready void attach(ref const Attachment attachment) { if(currentStep is null) { suiteResult.attachments ~= Attachment(attachment.name, attachment.file, attachment.mime); return; } currentStep.attachments ~= Attachment(attachment.name, attachment.file, attachment.mime); } /// Add the step result and update the other listeners on every step void begin(string suite, string test, ref StepResult step) { currentStep.steps ~= step; stepStack ~= currentStep; currentStep = step; LifeCycleListeners.instance.update(); } /// Update the other listeners on every step void end(string suite, string test, ref StepResult step) { currentStep = stepStack[stepStack.length - 1]; stepStack = stepStack[0 .. $ - 1]; LifeCycleListeners.instance.update(); } /// It does nothing SuiteResult[] beginExecution(ref const(TestCase)[]) { return []; } /// Return the result for the last executed suite SuiteResult[] endExecution() { if (suiteResult.begin == SysTime.fromUnixTime(0)) { return []; } LifeCycleListeners.instance.update(); LifeCycleListeners.instance.end(suiteResult); return [suiteResult]; } private { void createTestResult(const(TestCase) testCase) { testResult = testCase.toTestResult; testResult.begin = Clock.currTime; testResult.status = TestResult.Status.started; currentStep = testResult; stepStack = []; Step.suite = testCase.suiteName; Step.test = testCase.name; LifeCycleListeners.instance.begin(testCase.suiteName, testResult); try { testCase.func(); testResult.status = TestResult.Status.success; } catch (PendingTestException) { testResult.status = TestResult.Status.pending; } catch (Throwable t) { testResult.status = TestResult.Status.failure; testResult.throwable = t.toTestException; } testResult.end = Clock.currTime; LifeCycleListeners.instance.end(testCase.suiteName, testResult); } } /// Execute a test case SuiteResult[] execute(ref const(TestCase) testCase) { SuiteResult[] result; LifeCycleListeners.instance.update(); if (suiteResult.name != testCase.suiteName) { if (suiteResult.begin != SysTime.fromUnixTime(0)) { suiteResult.end = Clock.currTime; LifeCycleListeners.instance.end(suiteResult); result = [suiteResult]; } suiteResult = SuiteResult(testCase.suiteName, Clock.currTime, Clock.currTime); LifeCycleListeners.instance.begin(suiteResult); } createTestResult(testCase); suiteResult.tests ~= testResult; currentStep = null; LifeCycleListeners.instance.update(); return result; } } version(unittest) { import fluent.asserts; } /// Executing a test case that throws a PendingTestException should mark the test result /// as pending instead of a failure unittest { auto old = LifeCycleListeners.instance; LifeCycleListeners.instance = new LifeCycleListeners; LifeCycleListeners.instance.add(new DefaultExecutor); scope (exit) { LifeCycleListeners.instance = old; } void test() { throw new PendingTestException(); } auto testCase = const TestCase("Some.Suite", "test name", &test, []); auto result = [testCase].runTests; result.length.should.equal(1); result[0].tests[0].status.should.equal(TestResult.Status.pending); } /// Executing a test case should set the right begin and end times unittest { import core.thread; auto old = LifeCycleListeners.instance; LifeCycleListeners.instance = new LifeCycleListeners; LifeCycleListeners.instance.add(new DefaultExecutor); scope (exit) { LifeCycleListeners.instance = old; } void test() { Thread.sleep(1.msecs); } auto testCase = const TestCase("Some.Suite", "test name", &test, []); auto begin = Clock.currTime; auto result = [ testCase ].runTests; import std.stdio; writeln(result); auto testResult = result[0].tests[0]; testResult.begin.should.be.greaterThan(begin); testResult.end.should.be.greaterThan(begin + 1.msecs); }