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 immutable 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 suite = TestSuite(createTests!MOD_SYMBOLS(options.tests)); 62 immutable elapsed = suite.run(options.multiThreaded); 63 64 if(!suite.numTestsRun) { 65 writeln("Did not run any tests!!!"); 66 return false; 67 } 68 69 utWriteln("\nTime taken: ", elapsed, " seconds"); 70 utWriteln(suite.numTestsRun, " test(s) run, ", 71 suite.numFailures, " failed.\n"); 72 73 if(!suite.passed) { 74 utWritelnRed("Unit tests failed!\n"); 75 return false; //oops 76 } 77 78 utWritelnGreen("OK!\n"); 79 80 return true; 81 } 82 83 /** 84 * Runs all tests in passed-in modules. Modules are strings. 85 */ 86 bool runTests(MOD_STRINGS...)(in Options options) if(allSatisfy!(isSomeString, typeof(MOD_STRINGS))) { 87 mixin(getImportTestsCompileString!MOD_STRINGS()); //e.g. import foo, bar, baz; 88 static immutable runStr = getRunTestsCompileString!MOD_STRINGS(); 89 mixin(getRunTestsCompileString!MOD_STRINGS()); //e.g. runTests!(foo, bar, baz)(); 90 } 91 92 private string getImportTestsCompileString(MOD_STRINGS...)() { 93 return "import " ~ getModulesCompileString!MOD_STRINGS() ~ ";"; 94 } 95 96 private string getRunTestsCompileString(MOD_STRINGS...)() { 97 return "return runTests!(" ~ getModulesCompileString!MOD_STRINGS() ~ ")(options);"; 98 } 99 100 private string getModulesCompileString(MOD_STRINGS...)() { 101 import std.array; 102 string[] modules; 103 foreach(mod; MOD_STRINGS) modules ~= mod; 104 return join(modules, ", "); 105 }