1 module unit_threaded.testsuite; 2 3 import unit_threaded.testcase; 4 import unit_threaded.io; 5 import unit_threaded.options; 6 import std.datetime; 7 import std.parallelism: taskPool; 8 import std.concurrency; 9 import std.stdio; 10 import std.conv; 11 import std.algorithm; 12 13 14 auto runTest(TestCase test) { 15 return test(); 16 } 17 18 /** 19 * Responsible for running tests 20 */ 21 struct TestSuite { 22 this(TestCase[] tests) { 23 _tests = tests; 24 } 25 26 auto run(in Options options) { 27 auto tests = getTests(options); 28 _stopWatch.start(); 29 30 if(options.multiThreaded) { 31 _failures = reduce!q{a ~ b}(_failures, taskPool.amap!runTest(tests)); 32 } else { 33 foreach(test; tests) _failures ~= test(); 34 } 35 36 handleFailures(); 37 38 _stopWatch.stop(); 39 return cast(Duration)_stopWatch.peek(); 40 } 41 42 @property ulong numTestsRun() const { 43 return _tests.map!"a.numTestsRun".reduce!"a+b"; 44 } 45 46 @property ulong numFailures() const pure nothrow { 47 return _failures.length; 48 } 49 50 @property bool passed() const pure nothrow { 51 return numFailures() == 0; 52 } 53 54 private: 55 56 TestCase[] _tests; 57 string[] _failures; 58 StopWatch _stopWatch; 59 60 auto getTests(in Options options) { 61 auto tests = _tests; 62 if(options.random) { 63 import std.random; 64 auto generator = Random(options.seed); 65 tests.randomShuffle(generator); 66 utWriteln("Running tests in random order. To repeat this run, use --seed ", options.seed); 67 } 68 return tests; 69 } 70 71 void handleFailures() { 72 if(_failures) utWriteln(""); 73 foreach(failure; _failures) { 74 utWrite("Test ", failure, " "); 75 utWriteRed("failed"); 76 utWriteln("."); 77 } 78 if(_failures) writeln(""); 79 } 80 }