1 /**
2  * This module implements functions to run the unittests with
3  * command-line options.
4  */
5 
6 module unit_threaded.runner;
7 
8 import unit_threaded.testsuite;
9 import unit_threaded.options;
10 import unit_threaded.io : enableDebugOutput, forceEscCodes;
11 import unit_threaded.testcase : enableStackTrace, TestData;
12 import unit_threaded.reflection : allTestData;
13 
14 import std.conv : text;
15 import std.algorithm : map, filter, count;
16 
17 /**
18  * Runs all tests in passed-in modules. Modules can be symbols or
19  * strings. Generates a main function and substitutes the default D
20  * runtime unittest runner. This mixin should be used instead of
21  * $(D runTests) if Phobos is linked as a shared library.
22  */
23 mixin template runTestsMixin(Modules...) if(Modules.length > 0) {
24 
25     shared static this() {
26         import unit_threaded.testsuite : replaceModuleUnitTester;
27 
28         replaceModuleUnitTester;
29     }
30 
31     int main(string[] args) {
32         return runTests!Modules(args);
33     }
34 }
35 
36 /**
37  * Runs all tests in passed-in modules. Modules can be symbols
38  * or strings. Arguments are taken from the command-line.
39  * -s Can be passed to run in single-threaded mode. The rest
40  * of argv is considered to be test names to be run.
41  * Params:
42  *   args = Arguments passed to main.
43  * Returns: An integer suitable for the program's return code.
44  */
45 int runTests(Modules...)(string[] args) if(Modules.length > 0) {
46     return runTests(args, allTestData!Modules);
47 }
48 
49 /**
50  * Runs all tests in passed-in testData. Arguments are taken from the
51  * command-line. `-s` Can be passed to run in single-threaded mode. The
52  * rest of argv is considered to be test names to be run.
53  * Params:
54  *   args = Arguments passed to main.
55  *   testData = Data about the tests to run.
56  * Returns: An integer suitable for the program's return code.
57  */
58 int runTests(string[] args, in TestData[] testData) {
59     const options = getOptions(args);
60     handleCmdLineOptions(options, testData);
61     if (options.exit)
62         return 0;
63 
64     auto suite = TestSuite(options, testData);
65     return suite.run ? 0 : 1;
66 }
67 
68 private void handleCmdLineOptions(in Options options, in TestData[] testData) {
69     if (options.list) {
70         import std.stdio;
71 
72         writeln("Listing tests:");
73         foreach (test; testData.map!(a => a.name)) {
74             writeln(test);
75         }
76     }
77 
78     if (options.debugOutput)
79         enableDebugOutput();
80 
81     if (options.forceEscCodes)
82         forceEscCodes();
83 
84     if (options.stackTraces)
85         enableStackTrace();
86 }