public Covered Merge(Covered other) { if (other.MethodName != MethodName) { throw new Exception("Can't merge with different names"); } if (other.SequencePoints.Length != SequencePoints.Length) { throw new Exception("uhhhh"); } var inner = new SequencePoint[SequencePoints.Length]; for (var i = 0; i < SequencePoints.Length; i++) { var selfPoint = SequencePoints[i]; var otherPoint = other.SequencePoints[i]; if (selfPoint.Visited) { inner[i] = selfPoint; } else { inner[i] = otherPoint; } } return(new Covered(MethodName, inner)); }
public void Click([Frozen] Cell cell, Covered sut) { // Act sut.Click(); // Assert cell.CoverState.Should().BeOfType <Uncovered>(); }
public void RightClick([Frozen] Cell cell, Covered sut) { // Act sut.RightClick(); // Assert cell.CoverState.Should().BeOfType <Flaged>(); }
public void SquareRoot_ThrowsOnNegative() { var covered = new Covered(); new Action(() => covered.SquareRoot(-25)).Should().Throw <NotImplementedException>(); }
public void SquareRoot_ThrowsOnNonIntegerRoot() { var covered = new Covered(); new Action(() => covered.SquareRoot(37)).Should().Throw <NotImplementedException>(); }
static Dictionary <string, TestResult> ShardAndCollect(List <string> testNames, out List <Covered> covered) { var finished = 0; // all this just so we can make sure the subprocesses die when their parent does var _ = new Extern.SECURITY_ATTRIBUTES { }; var job = Extern.CreateJobObject(ref _, "LinqAF.TestRunner"); var info = new Extern.JOBOBJECT_BASIC_LIMIT_INFORMATION(); info.LimitFlags = 0x2000; // JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE var extendedInfo = new Extern.JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); extendedInfo.BasicLimitInformation = info; int length = Marshal.SizeOf(typeof(Extern.JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); var extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!Extern.SetInformationJobObject(job, Extern.JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) { throw new Exception("Wat"); } var results = new Dictionary <string, TestResult>(); var runningProcesses = new List <Tuple <Process, Thread, Thread> >(); var pendingProcessStarts = new Queue <ProcessStartInfo>(); string currentProcFile; using (var proc = Process.GetCurrentProcess()) { currentProcFile = proc.MainModule.FileName; } var coveredRefLock = new object(); IEnumerable <Covered> coveredRef = null; foreach (var name in testNames) { var procStart = new ProcessStartInfo { FileName = currentProcFile, Arguments = name, CreateNoWindow = true, RedirectStandardError = true, RedirectStandardOutput = true, UseShellExecute = false }; pendingProcessStarts.Enqueue(procStart); } Func <int> getPendingProcessStartsCount = () => { lock (pendingProcessStarts) { return(pendingProcessStarts.Count); } }; while (getPendingProcessStartsCount() > 0 || runningProcesses.Count > 0) { Thread.Sleep(TimeSpan.FromSeconds(1)); for (var i = runningProcesses.Count - 1; i >= 0; i--) { var t = runningProcesses[i]; var proc = t.Item1; var outThread = t.Item2; var errThread = t.Item3; if (!outThread.IsAlive && !errThread.IsAlive && proc.HasExited) { runningProcesses.RemoveAt(i); proc.Dispose(); } } if (runningProcesses.Count >= UseProceses()) { continue; } if (getPendingProcessStartsCount() > 0) { ProcessStartInfo next; lock (pendingProcessStarts) { next = pendingProcessStarts.Dequeue(); } var newProc = Process.Start(next); Extern.AssignProcessToJobObject(job, newProc.Handle); if (Debugger.IsAttached) { AttachDebugger(newProc); } var outThread = new Thread( () => { while (!newProc.HasExited) { // need to read it off, but needn't actually print it var toWrite = newProc.StandardOutput.ReadLine(); //Console.WriteLine($"[Proc: {newProc.Id}]: {toWrite}"); } } ); var errThread = new Thread( () => { var needsHandling = new StringBuilder(); while (!newProc.HasExited) { int c; while ((c = newProc.StandardError.Read()) != -1) { needsHandling.Append((char)c); } } var json = needsHandling.ToString(); dynamic data; try { data = JSON.DeserializeDynamic(json); } catch (Exception e) { Console.WriteLine($"[Proc: {newProc.Id}] ({next.Arguments}) ~~CRASHED~~"); Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); Console.WriteLine("Rescheduling"); lock (pendingProcessStarts) { pendingProcessStarts.Enqueue(next); } return; } foreach (var entry in data) { string name = entry.TestName; string errorMessage = entry.ErrorMessage; string testCoverageEncoded = entry.TestCoverageEncoded; lock (results) { results[name] = new TestResult { ErrorMessage = errorMessage, Coverage = null }; } double coverageRate; var parsedCoverage = Covered.DecodeList(testCoverageEncoded); if (parsedCoverage != null) { lock (coveredRefLock) { if (coveredRef == null) { coveredRef = parsedCoverage; coverageRate = double.NaN; } else { coveredRef = Covered.Merge(coveredRef.Concat(parsedCoverage).AsEnumerable()); } var total100 = coveredRef.Count(c => c.CoveragePercent >= 100); var total = coveredRef.Count(); coverageRate = Math.Round(((double)total100) / (double)total * 100.0, 1); } } else { coverageRate = double.NaN; } var num = Interlocked.Increment(ref finished); if (errorMessage == null) { if (!double.IsNaN(coverageRate)) { Console.WriteLine($"[Proc: {newProc.Id}] ({num}/{testNames.Count}): {name} PASSED (covered methods: {coverageRate}%)"); } else { Console.WriteLine($"[Proc: {newProc.Id}] ({num}/{testNames.Count}): {name} PASSED"); } } else { Console.WriteLine($"[Proc: {newProc.Id}] ({num}/{testNames.Count}): {name} !!FAILED!!"); } } } ); outThread.IsBackground = true; errThread.IsBackground = true; outThread.Start(); errThread.Start(); runningProcesses.Add(Tuple.Create(newProc, outThread, errThread)); } } covered = coveredRef?.ToList(); return(results); }
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(); }
public void ReturnToString(Covered sut) { // Assert sut.ToString().Should().Be("."); }