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