public void ShouldMergeTests() { var contexts = new[] { new HitContext( "Sample.UnitTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Sample.UnitTests.UnitTest1", "XUnitTest2", new Dictionary <int, int> { { 8, 1 }, }), new HitContext( "Sample.UnitTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Sample.UnitTests.UnitTest1", "XUnitTest2", new Dictionary <int, int> { { 8, 1 }, }) }; var hits = new HitsInfo(contexts); hits.GetHitCount(8).Should().Be(2); hits.GetHitContexts(8).Should().HaveCount(1); hits.GetHitContexts(8).First().GetHitCount(8).Should().Be(2); }
public static int IsHigherThanThreshold(InstrumentationResult result, float threshold) { var hits = HitsInfo.TryReadFromDirectory(result.HitsPath); var files = result.GetSourceFiles(); var totalLines = 0; var totalCoveredLines = 0; foreach (var kvFile in files) { var lines = kvFile.Value.Sequences .SelectMany(i => i.GetLines()) .Distinct() .Count(); var coveredLines = kvFile.Value.Sequences .Where(h => hits.WasHit(h.HitId)) .SelectMany(i => i.GetLines()) .Distinct() .Count(); totalLines += lines; totalCoveredLines += coveredLines; } var totalCoveragePercentage = (float)totalCoveredLines / totalLines; var isHigherThanThreshold = totalCoveragePercentage >= threshold; return(isHigherThanThreshold ? 0 : 1); }
private static CloverCounter CountFileMetrics(SourceFile file, HitsInfo hits) { var counter = CountMetrics(file.Sequences, hits); counter.Lines = file.Sequences.Max(instruction => instruction.EndLine); counter.Classes = file.Sequences.GroupBy(t => t.Method.Class).Count(); return counter; }
private static XElement CreateClassesElement(InstrumentedAssembly assembly, HitsInfo hitsInfo) { return(new XElement( XName.Get("classes"), assembly.SourceFiles .Select(kv => CreateClassElement(kv.Key, kv.Value, hitsInfo)) )); }
private static XElement CratePackagesElement(InstrumentationResult result, HitsInfo hitsInfo) { return(new XElement( XName.Get("packages"), result.Assemblies .Where(a => a.SourceFiles.Count > 0) .Select(a => CreatePackageElement(a, hitsInfo)) )); }
private static XElement CreateMethodsElement(SourceFile sourceFile, HitsInfo hitsInfo) { return(new XElement( XName.Get("methods"), sourceFile.Sequences .GroupBy(i => i.Method) .Select(g => CreateMethodElement(g.Key, g, hitsInfo)) )); }
private static XElement CrateSourcesElement(InstrumentationResult result, HitsInfo hitsInfo) { return(new XElement( XName.Get("sources"), new XElement("source", new XText(result.SourcePath) ) )); }
private static XElement CreateCoverageElement(InstrumentationResult result, HitsInfo hits) { var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); return(new XElement( XName.Get("coverage"), new XAttribute(XName.Get("generated"), timestamp), new XAttribute(XName.Get("clover"), "4.1.0"), CreateProjectElement(result, timestamp, hits) )); }
public static Summary CalculateSummaryStatic( InstrumentationResult result, float threshold) { var hitsInfo = HitsInfo.TryReadFromDirectory(result.HitsPath); return(CalculateFilesSummary( result.GetSourceFiles(), hitsInfo, threshold)); }
public void ShouldMergeTestsCorrectly() { var contexts = new[] { new HitContext( "Sample.UnitTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Sample.UnitTests.UnitTest1", "XUnitTest2", new Dictionary <int, int> { { 17, 2500000 }, { 19, 2500000 }, { 20, 50 }, { 21, 2500000 }, { 22, 2500000 }, { 23, 2500050 }, { 24, 50 }, { 33, 1 }, { 34, 1 }, { 35, 1 }, { 37, 1 }, { 38, 50 }, { 39, 50 }, { 40, 51 } }), new HitContext( "Sample.UnitTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Sample.UnitTests.UnitTest1", "NUnitTest2", new Dictionary <int, int> { { 9, 1 }, { 10, 1 }, { 11, 1 }, { 13, 1 }, { 14, 50 }, { 15, 50 }, { 16, 51 }, { 17, 2500000 }, { 19, 2500000 }, { 20, 50 }, { 21, 2500000 }, { 22, 2500000 }, { 23, 2500050 }, { 24, 50 } }) }; var hits = new HitsInfo(contexts); hits.GetHitCount(17).Should().Be(5000000); hits.GetHitContexts(17).Count().Should().Be(2); hits.GetHitContexts(17).First().GetHitCount(17).Should().Be(2500000); }
public Summary CalculateFilesSummary( IEnumerable <SourceFile> sourceFiles, HitsInfo hitsInfo, float threshold) { var summary = new Summary(); summary.Statements = sourceFiles.Sum(x => x.Sequences .Count()); summary.CoveredStatements = sourceFiles.Sum(x => x.Sequences .Where(h => hitsInfo.WasHit(h.HitId)) .Count()); summary.Lines = sourceFiles.Sum(x => x.Sequences .SelectMany(s => s.GetLines()) .Distinct() .Count()); summary.CoveredLines = sourceFiles.Sum(x => x.Sequences .Where(h => hitsInfo.WasHit(h.HitId)) .SelectMany(s => s.GetLines()) .Distinct() .Count()); summary.Branches = sourceFiles.Sum(x => x.Sequences .SelectMany(s => s.Conditions) .SelectMany(c => c.Branches) .Count()); summary.CoveredBranches = sourceFiles.Sum(x => x.Sequences .SelectMany(s => s.Conditions) .SelectMany(c => c.Branches) .Where(b => hitsInfo.WasHit(b.HitId)) .Count()); summary.StatementsPercentage = summary.Statements == 0 ? 1 : (float)summary.CoveredStatements / summary.Statements; summary.StatementsCoveragePass = summary.StatementsPercentage >= threshold; summary.LinesPercentage = summary.Lines == 0 ? 1 : (float)summary.CoveredLines / summary.Lines; summary.LinesCoveragePass = summary.LinesPercentage >= threshold; summary.BranchesPercentage = summary.Branches == 0 ? 1 : (float)summary.CoveredBranches / summary.Branches; summary.BranchesCoveragePass = summary.BranchesPercentage >= threshold; return(summary); }
private static XElement CreateCoverageElement(InstrumentationResult result, HitsInfo hitsInfo) { var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); var allLines = result.GetSourceFiles() .SelectMany(kvFile => kvFile.Value.Sequences) .SelectMany(i => i.GetLines()) .Distinct() .Count(); var coveredLines = result.GetSourceFiles() .SelectMany(kvFile => kvFile.Value.Sequences) .Where(h => hitsInfo.WasHit(h.HitId)) .SelectMany(i => i.GetLines()) .Distinct() .Count(); var allBranches = result.GetSourceFiles() .SelectMany(kvFile => kvFile.Value.Sequences) .SelectMany(i => i.Conditions) .SelectMany(c => c.Branches) .Count(); var coveredBranches = result.GetSourceFiles() .SelectMany(kvFile => kvFile.Value.Sequences) .SelectMany(i => i.Conditions) .SelectMany(c => c.Branches) .Where(b => hitsInfo.WasHit(b.HitId)) .Count(); var lineRate = allLines == 0 ? 1d : (double)coveredLines / (double)allLines; var branchRate = allBranches == 0 ? 1d : (double)coveredBranches / (double)allBranches; return(new XElement( XName.Get("coverage"), new XAttribute(XName.Get("lines-valid"), allLines), new XAttribute(XName.Get("lines-covered"), coveredLines), new XAttribute(XName.Get("line-rate"), lineRate), new XAttribute(XName.Get("branches-valid"), allBranches), new XAttribute(XName.Get("branches-covered"), coveredBranches), new XAttribute(XName.Get("branch-rate"), branchRate), new XAttribute(XName.Get("complexity"), 0), new XAttribute(XName.Get("timestamp"), timestamp), new XAttribute(XName.Get("version"), "1.0.0"), CrateSourcesElement(result, hitsInfo), CratePackagesElement(result, hitsInfo) )); }
public virtual int Execute(InstrumentationResult result, float threshold) { var hits = HitsInfo.TryReadFromDirectory(result.HitsPath); var files = result.GetSourceFiles(); SetFileColumnLength(files.Keys.Select(s => s.Length).Concat(new[] { 10 }).Max()); WriteHeader(); var totalLines = 0; var totalCoveredLines = 0; foreach (var kvFile in files) { var lines = kvFile.Value.Sequences .SelectMany(i => i.GetLines()) .Distinct() .Count(); var coveredLines = kvFile.Value.Sequences .Where(h => hits.WasHit(h.HitId)) .SelectMany(i => i.GetLines()) .Distinct() .Count(); totalLines += lines; totalCoveredLines += coveredLines; var coveragePercentage = (float)coveredLines / lines; var fileColor = coveragePercentage >= threshold ? ConsoleColor.Green : ConsoleColor.Red; WriteReport(kvFile, lines, coveredLines, coveragePercentage, fileColor); } WriteDetailedReport(result, files, hits); var totalCoveragePercentage = (float)totalCoveredLines / totalLines; var isHigherThanThreshold = totalCoveragePercentage >= threshold; var totalsColor = isHigherThanThreshold ? ConsoleColor.Green : ConsoleColor.Red; WriteFooter(totalLines, totalCoveredLines, totalCoveragePercentage, threshold, totalsColor); return(isHigherThanThreshold ? 0 : 1); }
private static XElement CreatePackageElement(InstrumentedAssembly assembly, HitsInfo hitsInfo) { var allLines = assembly.SourceFiles .SelectMany(kvFile => kvFile.Value.Sequences) .SelectMany(i => i.GetLines()) .Distinct() .Count(); var coveredLines = assembly.SourceFiles .SelectMany(kvFile => kvFile.Value.Sequences) .Where(h => hitsInfo.WasHit(h.HitId)) .SelectMany(i => i.GetLines()) .Distinct() .Count(); var allBranches = assembly.SourceFiles .SelectMany(kvFile => kvFile.Value.Sequences) .SelectMany(i => i.Conditions) .SelectMany(c => c.Branches) .Count(); var coveredBranches = assembly.SourceFiles .SelectMany(kvFile => kvFile.Value.Sequences) .SelectMany(i => i.Conditions) .SelectMany(c => c.Branches) .Where(b => hitsInfo.WasHit(b.HitId)) .Count(); var lineRate = allLines == 0 ? 1d : (double)coveredLines / (double)allLines; var branchRate = allBranches == 0 ? 1d : (double)coveredBranches / (double)allBranches; return(new XElement( XName.Get("package"), new XAttribute(XName.Get("name"), assembly.Name), new XAttribute(XName.Get("line-rate"), lineRate), new XAttribute(XName.Get("branch-rate"), branchRate), new XAttribute(XName.Get("complexity"), 0), CreateClassesElement(assembly, hitsInfo) )); }
public void Execute(InstrumentationResult result, IFileInfo output) { var hits = HitsInfo.TryReadFromDirectory(result.HitsPath); var document = new XDocument( new XDeclaration("1.0", "utf-8", null), CreateCoverageElement(result, hits) ); var xmlWriterSettings = new XmlWriterSettings { Indent = true }; output.Directory.Create(); using (var sw = output.CreateText()) using (var writer = XmlWriter.Create(sw, xmlWriterSettings)) { document.WriteTo(writer); } }
private static XElement CreateClassElement(SourceFile sourceFile, HitsInfo hitsInfo) { var allLines = sourceFile.Sequences .SelectMany(i => i.GetLines()) .Distinct() .Count(); var coveredLines = sourceFile.Sequences .Where(h => hitsInfo.WasHit(h.HitId)) .SelectMany(i => i.GetLines()) .Distinct() .Count(); var allBranches = sourceFile.Sequences .SelectMany(i => i.Conditions) .SelectMany(c => c.Branches) .Count(); var coveredBranches = sourceFile.Sequences .SelectMany(i => i.Conditions) .SelectMany(c => c.Branches) .Where(b => hitsInfo.WasHit(b.HitId)) .Count(); var lineRate = allLines == 0 ? 1d : (double)coveredLines / (double)allLines; var branchRate = allBranches == 0 ? 1d : (double)coveredBranches / (double)allBranches; return(new XElement( XName.Get("class"), new XAttribute(XName.Get("name"), sourceFile.Path), new XAttribute(XName.Get("filename"), sourceFile.Path), new XAttribute(XName.Get("line-rate"), lineRate), new XAttribute(XName.Get("branch-rate"), branchRate), new XAttribute(XName.Get("complexity"), 0), CreateMethodsElement(sourceFile, hitsInfo), CreateLinesElement(sourceFile.Sequences, hitsInfo) )); }
public int Execute( InstrumentationResult result, float threshold, bool noFail) { var hitsInfo = HitsInfo.TryReadFromDirectory(result.HitsPath); var files = result.GetSourceFiles(); var summary = SummaryFactory.CalculateFilesSummary(files, hitsInfo, threshold); var tableRows = SummaryFactory.GetSummaryGrid(files, hitsInfo, threshold); var consoleTable = new ConsoleTable { Header = CreateHeader(), Body = tableRows.Where(r => !r.Root).Select(f => CreateRow(f)).ToArray(), Footer = CreateFooter(summary) }; consoleTable.WriteTable(); return(noFail || summary.LinesCoveragePass ? 0 : 1); }
private static IEnumerable <XElement> CreateFilesElement(InstrumentedAssembly assembly, HitsInfo hits) { return(assembly.SourceFiles.Select(file => new XElement( XName.Get("file"), new XAttribute(XName.Get("name"), Path.GetFileName(file.Path)), new XAttribute(XName.Get("path"), file.Path), CreateMetricsElement(CountFileMetrics(file, hits)), CreateClassesElement(file.Sequences, hits), CreateLinesElement(file.Sequences, hits) ))); }
private static IEnumerable <XElement> CreatePackagesElement(InstrumentationResult result, HitsInfo hits) { return(result.Assemblies.Select(assembly => new XElement( XName.Get("package"), new XAttribute(XName.Get("name"), assembly.Name), CreateMetricsElement(CountPackageMetrics(assembly, hits)), CreateFilesElement(assembly, hits) ))); }
private static XElement CreateProjectElement(InstrumentationResult result, long timestamp, HitsInfo hits) { return(new XElement( XName.Get("project"), new XAttribute(XName.Get("timestamp"), timestamp), new XAttribute(XName.Get("name"), result.SourcePath), CreateMetricsElement(CountProjectMetrics(result, hits)), CreatePackagesElement(result, hits) )); }
private static CloverCounter CountMetrics(IEnumerable <InstrumentedSequence> instructions, HitsInfo hits) { var localInstructions = instructions.ToArray(); var coveredInstructions = localInstructions .Where(instruction => hits.WasHit(instruction.HitId)).ToArray(); return(new CloverCounter { Statements = localInstructions.Length, CoveredStatements = coveredInstructions.Length, Methods = localInstructions .GroupBy(instruction => instruction.Method.FullName) .Count(), CoveredMethods = coveredInstructions .GroupBy(instruction => instruction.Method.FullName) .Count() }); }
private static XElement CreateConditionElement(InstrumentedCondition condition, int index, HitsInfo hitsInfo) { var allBranches = condition.Branches; var coveredBranches = allBranches .Where(b => hitsInfo.WasHit(b.HitId)) .Count(); var coverage = allBranches.Length == 0 ? 0 : coveredBranches * 100 / allBranches.Length; return(new XElement( XName.Get("condition"), new XAttribute(XName.Get("number"), index), new XAttribute(XName.Get("type"), "jump"), new XAttribute(XName.Get("coverage"), $"{coverage}%") )); }
public List <SummaryRow> GetSummaryGrid( SourceFile[] sourceFiles, HitsInfo hitsInfo, float threshold) { var rows = new List <SummaryRow> { new SummaryRow { Level = 0, Name = "All Files", FullName = "All Files", SourceFiles = sourceFiles, Root = true, Summary = CalculateFilesSummary(sourceFiles, hitsInfo, threshold) } }; var allItems = sourceFiles .Select(file => ( file.Path.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }), file )).ToArray(); AddRowsRecursive(allItems, 1, string.Empty); return(rows); void AddRowsRecursive( IEnumerable <(string[] parts, SourceFile sourceFile)> items, int level, string baseName) { var groups = items .GroupBy(x => x.parts.ElementAtOrDefault(level - 1)) .Where(g => g.Key != null); foreach (var group in groups) { var groupSourceFiles = group.Select(x => x.sourceFile).ToArray(); var name = groupSourceFiles.Length == 1 ? string.Join(Path.DirectorySeparatorChar.ToString(), group.First().parts.Skip(level - 1)) : group.Key; var row = new SummaryRow { Level = level, Name = name, FullName = $"{baseName}{name}", Folder = group.Count() > 1, File = group.Count() == 1, SourceFiles = groupSourceFiles, Summary = CalculateFilesSummary( groupSourceFiles, hitsInfo, threshold) }; rows.Add(row); if (group.Count() > 1) { AddRowsRecursive(group, level + 1, $"{baseName}{Path.DirectorySeparatorChar}{group.Key}"); } } } }
private static XElement CreateLineElement(int line, IEnumerable <InstrumentedSequence> instructions, HitsInfo hitsInfo) { var conditions = instructions .SelectMany(i => i.Conditions) .ToArray(); var allBranches = conditions .SelectMany(c => c.Branches) .Count(); var coveredBranches = conditions .SelectMany(c => c.Branches) .Where(b => hitsInfo.WasHit(b.HitId)) .Count(); var hits = instructions.Sum(i => hitsInfo.GetHitCount(i.HitId)); var conditionCoverage = allBranches == 0 ? 0 : coveredBranches * 100 / allBranches; return(new XElement( XName.Get("line"), new XAttribute(XName.Get("number"), line), new XAttribute(XName.Get("hits"), hits), new XAttribute(XName.Get("branch"), allBranches > 0 ? "true" : "false"), new XAttribute(XName.Get("condition-coverage"), $"{conditionCoverage}% ({coveredBranches}/{allBranches})"), allBranches > 0 ? CreateConditionsElements(conditions, hitsInfo) : null )); }
private static IEnumerable <XElement> CreateClassesElement(IEnumerable <InstrumentedSequence> instructions, HitsInfo hits) { return(instructions .GroupBy(instruction => instruction.Method.Class) .Select(classes => new XElement( XName.Get("class"), new XAttribute(XName.Get("name"), classes.Key), CreateMetricsElement(CountMetrics(classes, hits)) ))); }
private static CloverCounter CountProjectMetrics(InstrumentationResult result, HitsInfo hits) { return(result.Assemblies .Select(t => CountPackageMetrics(t, hits)) .Aggregate(new CloverCounter(), (counter, next) => { counter.Add(next); counter.Packages += 1; return counter; }));; }
private static IEnumerable <XElement> CreateLinesElement(IEnumerable <InstrumentedSequence> instructions, HitsInfo hits) { return(instructions .SelectMany(t => t.GetLines(), (i, l) => new { instructionId = i.HitId, line = l }) .Select(instruction => new XElement( XName.Get("line"), new XAttribute(XName.Get("num"), instruction.line), new XAttribute(XName.Get("count"), hits.GetHitCount(instruction.instructionId)), new XAttribute(XName.Get("type"), "stmt") ))); }
private static CloverCounter CountPackageMetrics(InstrumentedAssembly assembly, HitsInfo hits) { return(assembly.SourceFiles .Select(t => CountFileMetrics(t, hits)) .Aggregate(new CloverCounter(), (counter, next) => { counter.Add(next); counter.Files += 1; return counter; })); }
public void Generate( InstrumentationResult result, SourceFile sourceFile, HitsInfo hitsInfo, float threshold, string outputFile) { var lines = File.ReadAllLines(Path.Combine(result.SourcePath, sourceFile.Path)); _fileSystem.Directory.CreateDirectory(Path.GetDirectoryName(outputFile)); var summary = _summaryFactory.CalculateFilesSummary(new[] { sourceFile }, hitsInfo, threshold); var lineCoverageClass = summary.LinesCoveragePass ? "green" : "red"; var statementsCoverageClass = summary.StatementsCoveragePass ? "green" : "red"; var branchCoverageClass = summary.BranchesCoveragePass ? "green" : "red"; using (var htmlWriter = (TextWriter)File.CreateText(outputFile)) { htmlWriter.WriteLine("<html>"); htmlWriter.WriteLine("<style>"); htmlWriter.WriteLine(ResourceUtils.GetContent("MiniCover.Reports.Html.Shared.css")); htmlWriter.WriteLine(ResourceUtils.GetContent("MiniCover.Reports.Html.SourceFile.css")); htmlWriter.WriteLine("</style>"); htmlWriter.WriteLine("<script>"); htmlWriter.WriteLine(ResourceUtils.GetContent("MiniCover.Reports.Html.Shared.js")); htmlWriter.WriteLine("</script>"); htmlWriter.WriteLine("<body>"); htmlWriter.WriteLine("<h2>Summary</h2>"); htmlWriter.WriteLine("<table>"); htmlWriter.WriteLine($"<tr><th>Generated on</th><td>{DateTime.Now}</td></tr>"); htmlWriter.WriteLine($"<tr><th>Line Coverage</th><td class=\"{lineCoverageClass}\">{summary.LinesPercentage:P} ({summary.CoveredLines}/{summary.Lines})</td></tr>"); htmlWriter.WriteLine($"<tr><th>Statements Coverage</th><td class=\"{branchCoverageClass}\">{summary.StatementsPercentage:P} ({summary.CoveredStatements}/{summary.Statements})</td></tr>"); htmlWriter.WriteLine($"<tr><th>Branch Coverage</th><td class=\"{branchCoverageClass}\">{summary.BranchesPercentage:P} ({summary.CoveredBranches}/{summary.Branches})</td></tr>"); htmlWriter.WriteLine($"<tr><th>Threshold</th><td>{threshold:P}</td></tr>"); htmlWriter.WriteLine("</table>"); htmlWriter.WriteLine("<h2>Code</h2>"); htmlWriter.WriteLine("<div class=\"legend\">"); htmlWriter.Write("<label>Legend:</label>"); htmlWriter.Write("<div class=\"hit\">Covered</div>"); htmlWriter.Write("<div class=\"partial\">Partially covered</div>"); htmlWriter.Write("<div class=\"not-hit\">Not covered</div>"); htmlWriter.WriteLine("</div>"); htmlWriter.WriteLine("<div class=\"code\">"); for (var l = 1; l <= lines.Length; l++) { var line = lines[l - 1]; var instructions = sourceFile.Sequences .Where(i => i.GetLines().Contains(l)) .ToArray(); var lineHitCount = instructions.Sum(a => hitsInfo.GetHitCount(a.HitId)); var lineClasses = new List <string> { "line" }; if (lineHitCount > 0) { if (instructions.Any(i => !hitsInfo.WasHit(i.HitId) || i.Conditions.SelectMany(x => x.Branches).Any(b => !hitsInfo.WasHit(b.HitId)))) { lineClasses.Add("partial"); } else { lineClasses.Add("hit"); } } else if (instructions.Length > 0) { lineClasses.Add("not-hit"); } htmlWriter.Write($"<div class=\"{string.Join(" ", lineClasses)}\">"); htmlWriter.Write($"<div class=\"line-number\">{l}</div>"); htmlWriter.Write("<div class=\"line-content\">"); if (line.Length > 0) { for (var c = 1; c <= line.Length; c++) { var character = line[c - 1].ToString(); foreach (var instruction in instructions) { if (instruction.StartLine == l && instruction.StartColumn == c || instruction.StartLine < l && c == 1) { var statementIdClass = $"s-{instruction.HitId}"; var statementClasses = new List <string> { "statement", statementIdClass }; if (hitsInfo.WasHit(instruction.HitId)) { statementClasses.Add("hit"); if (instruction.Conditions.SelectMany(x => x.Branches).Any(b => !hitsInfo.WasHit(b.HitId))) { statementClasses.Add("partial"); } } else { statementClasses.Add("not-hit"); } htmlWriter.Write($"<div data-hover-target=\".{statementIdClass}\" data-activate-target=\".{statementIdClass}\" class=\"{string.Join(" ", statementClasses)}\">"); if (instruction.EndLine == l) { var hitCount = hitsInfo.GetHitCount(instruction.HitId); var contexts = hitsInfo.GetHitContexts(instruction.HitId) .Distinct() .ToArray(); htmlWriter.Write($"<div class=\"statement-info {statementIdClass}\">"); htmlWriter.Write($"<div>Id: {instruction.HitId}</div>"); htmlWriter.Write($"<div>Hits: {hitCount}</div>"); if (instruction.Conditions.Length > 0) { var conditionIndex = 0; foreach (var condition in instruction.Conditions) { htmlWriter.Write($"<div>Condition {++conditionIndex}:"); htmlWriter.Write("<ul>"); var branchIndex = 0; foreach (var branch in condition.Branches) { var branchHitCount = hitsInfo.GetHitCount(branch.HitId); htmlWriter.Write($"<li>Branch {++branchIndex}: {FormatHits(branchHitCount)}</li>"); } htmlWriter.Write("</ul>"); htmlWriter.Write("</div>"); } } if (contexts.Length > 0) { htmlWriter.Write("<div>Contexts:"); htmlWriter.Write("<ul>"); foreach (var context in contexts) { var contextHitCount = context.GetHitCount(instruction.HitId); var description = $"{context.ClassName}.{context.MethodName}"; htmlWriter.Write($"<li>{WebUtility.HtmlEncode(description)}: {FormatHits(contextHitCount)}</li>"); } htmlWriter.Write("</ul></div>"); } htmlWriter.Write("</div>"); } } } htmlWriter.Write(WebUtility.HtmlEncode(character)); foreach (var instruction in instructions) { if (instruction.EndLine == l && instruction.EndColumn == c + 1 || instruction.EndLine > l && c == line.Length) { htmlWriter.Write("</div>"); } } } } else { htmlWriter.WriteLine(" "); } htmlWriter.Write("</div>"); htmlWriter.WriteLine("</div>"); } htmlWriter.WriteLine("</div>"); htmlWriter.WriteLine("</body>"); htmlWriter.WriteLine("</html>"); } }
private static XElement CreateConditionsElements(IEnumerable <InstrumentedCondition> conditions, HitsInfo hitsInfo) { return(new XElement( XName.Get("conditions"), conditions.Select((b, i) => CreateConditionElement(b, i, hitsInfo)) )); }