1 module unit_threaded.runner; 2 3 import unit_threaded.factory; 4 import unit_threaded.testsuite; 5 import unit_threaded.io; 6 import unit_threaded.options; 7 import unit_threaded.testcase; 8 import unit_threaded.reflection: allTestCaseData; 9 10 import std.stdio; 11 import std.traits; 12 import std.typetuple; 13 import std.concurrency; 14 import std.conv; 15 import std.algorithm; 16 import core.thread; 17 18 19 /** 20 * Runs all tests in passed-in modules. Modules can be symbols 21 * or strings. Arguments are taken from the command-line. 22 * -s Can be passed to run in single-threaded mode. The rest 23 * of argv is considered to be test names to be run. 24 * Returns: integer suitable for program return code. 25 */ 26 int runTests(MODULES...)(string[] args) { 27 return runTests(args, allTestCaseData!MODULES); 28 } 29 30 int runTests(string[] args, in TestData[] testData) { 31 const options = getOptions(args); 32 33 if(options.list) { 34 writeln("Listing tests:"); 35 foreach(test; testData.map!(a => a.name)) { 36 writeln(test); 37 } 38 } 39 40 if(options.exit) return 0; 41 if(options.debugOutput) enableDebugOutput(); 42 if(options.forceEscCodes) forceEscCodes(); 43 44 immutable success = runTests(options, testData); 45 return success ? 0 : 1; 46 } 47 48 49 bool runTests(in Options options, in TestData[] testData) { 50 WriterThread.get(); //make sure this is up 51 scope(exit) WriterThread.get().join(); 52 53 //sleep to give WriterThread some time to set up. Otherwise, 54 //tests with output could write to stdout in the meanwhile 55 Thread.sleep(5.msecs); 56 57 auto testCases = createTestCases(testData, options.testsToRun); 58 if(!testCases) { 59 utWritelnRed("Error! No tests to run for args: "); 60 utWriteln(options.testsToRun); 61 return false; 62 } 63 64 auto suite = TestSuite(testCases); 65 immutable elapsed = suite.run(options); 66 67 if(!suite.numTestsRun) { 68 writeln("Did not run any tests!!!"); 69 return false; 70 } 71 72 utWriteln("\nTime taken: ", elapsed); 73 utWrite(suite.numTestsRun, " test(s) run, "); 74 const failuresStr = text(suite.numFailures, " failed"); 75 if(suite.numFailures) { 76 utWriteRed(failuresStr); 77 } else { 78 utWrite(failuresStr); 79 } 80 81 void printAbout(string attr)(in string msg) { 82 const num = testData.filter!(a => mixin("a. " ~ attr)).count; 83 if(num) { 84 utWrite(", "); 85 utWriteYellow(num, " " ~ msg); 86 } 87 } 88 89 printAbout!"hidden"("hidden"); 90 printAbout!"shouldFail"("failing as expected"); 91 92 utWriteln(".\n"); 93 94 if(!suite.passed) { 95 utWritelnRed("Unit tests failed!\n"); 96 return false; //oops 97 } 98 99 utWritelnGreen("OK!\n"); 100 101 return true; 102 }