static void Main(string[] args) { const bool defaultSuppressCoverage = true; // set false to collect coverage, true to not var run = new List <Test>(); var asm = Assembly.Load("LinqAF.Tests"); List <Covered> covered; Dictionary <string, TestResult> results; var masterProcess = false; IDisposable redirecting; if (args.Length == 0) { redirecting = RedirectOut(); var tests = new List <string>(); foreach (var @class in asm.GetTypes()) { if (@class.GetCustomAttribute <TestClassAttribute>() != null) { tests.AddRange(QueueTests(@class, suppressCoverage: defaultSuppressCoverage).Select(t => t.Name).AsEnumerable()); } } tests = tests.OrderBy(x => x).ToList(); Console.WriteLine($"Queuing {tests.Count} tests on {UseProceses()} different processes"); results = ShardAndCollect(tests, out covered); masterProcess = true; } else { redirecting = null; covered = null; var suppressCoverage = args.Length > 1 ? args[1] == "no-coverage" : defaultSuppressCoverage; var testNames = new HashSet <string>(args[0].Split(';')); var classes = testNames.Select(t => t.Substring(0, t.IndexOf('.'))).ToList(); foreach (var @class in asm.GetTypes()) { if (@class.GetCustomAttribute <TestClassAttribute>() != null) { if (classes.Contains(@class.Name)) { var testsOnClass = QueueTests(@class, suppressCoverage); var toRun = testsOnClass.Where(c => testNames.Contains(c.Name)).AsEnumerable(); run.AddRange(toRun); } } } results = new Dictionary <string, TestResult>(); foreach (var test in run.OrderBy(r => r.Name)) { List <Covered> coverage; string errorMessage; if (!test.Run(out coverage, out errorMessage)) { results[test.Name] = new TestResult { ErrorMessage = errorMessage, Coverage = null }; } else { results[test.Name] = new TestResult { ErrorMessage = null, Coverage = coverage }; } } var data = results.Select(kv => new { TestName = kv.Key, ErrorMessage = kv.Value.ErrorMessage, TestCoverageEncoded = Covered.EncodeList(kv.Value.Coverage) }).ToList(); var json = JSON.Serialize(data, Options.PrettyPrint); Console.Error.Write(json); } var passedCount = results.Count(kv => kv.Value.ErrorMessage == null); var runCount = results.Count; Console.WriteLine($"{passedCount}/{runCount} tests passed"); foreach (var kv in results) { if (kv.Value.ErrorMessage != null) { Console.WriteLine($"Failed: {kv.Key}"); Console.WriteLine(kv.Value.ErrorMessage); } } if (masterProcess) { Console.WriteLine(); if (covered != null) { covered.Sort((x, y) => - (x.CoveragePercent.CompareTo(y.CoveragePercent))); var totalMethods = covered.Count; var at100 = covered.Count(c => c.CoveragePercent >= 100); var covPer = ((double)at100) / (double)totalMethods * 100.0; Console.WriteLine($"{at100}/{totalMethods} methods ({Math.Round(covPer, 1)}%) at 100% code coverage"); Console.WriteLine("Press any key to dump 0% coverage methods"); Console.ReadKey(); foreach (var method in covered.Where(p => p.CoveragePercent <= 0)) { Console.WriteLine($"\t{method.NiceMethodName} at {Math.Round(method.CoveragePercent, 1)}% coverage"); } } #if DEBUG Console.WriteLine(); Console.WriteLine("Press any key to exit"); Console.ReadKey(); #endif } redirecting?.Dispose(); }