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.writer_thread; 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 const options = getOptions(args); 28 if(options.list) { 29 writeln("Listing tests:"); 30 foreach(test; getTestNames!MODULES()) { 31 writeln(test); 32 } 33 } 34 35 if(options.exit) return 0; 36 if(options.debugOutput) enableDebugOutput(); 37 38 immutable success = runTests!MODULES(options); 39 return success ? 0 : 1; 40 } 41 42 private auto getTestNames(MOD_SYMBOLS...)() if(!anySatisfy!(isSomeString, typeof(MOD_SYMBOLS))) { 43 return map!(a => a.name)(getTestClassesAndFunctions!MOD_SYMBOLS()); 44 } 45 46 private auto getTestNames(MOD_STRINGS...)() if(allSatisfy!(isSomeString, typeof(MOD_STRINGS))) { 47 mixin(getImportTestsCompileString!MOD_STRINGS()); //e.g. import foo, bar, baz; 48 mixin("return map!(a => a.name)(getTestClassesAndFunctions!(" ~ 49 getModulesCompileString!MOD_STRINGS() ~ ")());"); 50 } 51 52 /** 53 * Runs all tests in passed-in modules. Modules are symbols. 54 */ 55 bool runTests(MOD_SYMBOLS...)(in Options options) if(!anySatisfy!(isSomeString, typeof(MOD_SYMBOLS))) { 56 WriterThread.get(); //make sure this is up 57 //sleep to give WriterThread some time to set up. Otherwise, 58 //tests with output could write to stdout in the meanwhile 59 Thread.sleep(dur!"msecs"(5)); 60 61 auto tests = createTests!MOD_SYMBOLS(options.tests); 62 if(!tests) { 63 utWritelnRed("Error! No tests to run for args: "); 64 utWriteln(options.tests); 65 return false; 66 } 67 68 auto suite = TestSuite(tests); 69 immutable elapsed = suite.run(options.multiThreaded); 70 71 if(!suite.numTestsRun) { 72 writeln("Did not run any tests!!!"); 73 return false; 74 } 75 76 utWriteln("\nTime taken: ", elapsed, " seconds"); 77 utWriteln(suite.numTestsRun, " test(s) run, ", 78 suite.numFailures, " failed.\n"); 79 80 if(!suite.passed) { 81 utWritelnRed("Unit tests failed!\n"); 82 return false; //oops 83 } 84 85 utWritelnGreen("OK!\n"); 86 87 return true; 88 } 89 90 /** 91 * Runs all tests in passed-in modules. Modules are strings. 92 */ 93 bool runTests(MOD_STRINGS...)(in Options options) if(allSatisfy!(isSomeString, typeof(MOD_STRINGS))) { 94 mixin(getImportTestsCompileString!MOD_STRINGS()); //e.g. import foo, bar, baz; 95 static immutable runStr = getRunTestsCompileString!MOD_STRINGS(); 96 mixin(getRunTestsCompileString!MOD_STRINGS()); //e.g. runTests!(foo, bar, baz)(); 97 } 98 99 private string getImportTestsCompileString(MOD_STRINGS...)() { 100 return "import " ~ getModulesCompileString!MOD_STRINGS() ~ ";"; 101 } 102 103 private string getRunTestsCompileString(MOD_STRINGS...)() { 104 return "return runTests!(" ~ getModulesCompileString!MOD_STRINGS() ~ ")(options);"; 105 } 106 107 private string getModulesCompileString(MOD_STRINGS...)() { 108 import std.array; 109 string[] modules; 110 foreach(mod; MOD_STRINGS) modules ~= mod; 111 return join(modules, ", "); 112 }