Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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)
                       ));
        }
Exemplo n.º 3
0
        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
                       ));
        }
Exemplo n.º 4
0
        private static XElement CreateMethodElement(InstrumentedMethod method, IEnumerable <InstrumentedSequence> instructions, HitsInfo hitsInfo)
        {
            var allLines = instructions
                           .SelectMany(i => i.GetLines())
                           .Distinct()
                           .Count();

            var coveredLines = instructions
                               .Where(h => hitsInfo.WasHit(h.HitId))
                               .SelectMany(i => i.GetLines())
                               .Distinct()
                               .Count();

            var allBranches = instructions
                              .SelectMany(i => i.Conditions)
                              .SelectMany(c => c.Branches)
                              .Count();

            var coveredBranches = instructions
                                  .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;

            var openParametersIndex = method.FullName.IndexOf("(");
            var signature           = method.FullName.Substring(openParametersIndex);

            return(new XElement(
                       XName.Get("method"),
                       new XAttribute(XName.Get("name"), method.Name),
                       new XAttribute(XName.Get("signature"), signature),
                       new XAttribute(XName.Get("line-rate"), lineRate),
                       new XAttribute(XName.Get("branch-rate"), branchRate),
                       new XAttribute(XName.Get("complexity"), 0),
                       CreateLinesElement(instructions, hitsInfo)
                       ));
        }
Exemplo n.º 5
0
        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)
                       ));
        }
Exemplo n.º 6
0
        private static XElement CreateClassElement(string fileName, 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"), fileName),
                       new XAttribute(XName.Get("filename"), fileName),
                       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)
                       ));
        }
Exemplo n.º 7
0
        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}%")
                       ));
        }
Exemplo n.º 8
0
        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()
            });
        }
        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("&nbsp;");
                    }

                    htmlWriter.Write("</div>");
                    htmlWriter.WriteLine("</div>");
                }

                htmlWriter.WriteLine("</div>");
                htmlWriter.WriteLine("</body>");
                htmlWriter.WriteLine("</html>");
            }
        }
Exemplo n.º 10
0
        protected override void WriteDetailedReport(InstrumentationResult result, IDictionary <string, SourceFile> files, HitsInfo hitsInfo)
        {
            foreach (var kvFile in files)
            {
                var lines = File.ReadAllLines(Path.Combine(result.SourcePath, kvFile.Key));

                var fileName = GetHtmlFileName(kvFile.Key);

                Directory.CreateDirectory(Path.GetDirectoryName(fileName));

                using (var htmlWriter = (TextWriter)File.CreateText(fileName))
                {
                    htmlWriter.WriteLine("<html>");
                    htmlWriter.WriteLine("<style>");
                    htmlWriter.WriteLine("details summary::-webkit-details-marker {");
                    htmlWriter.WriteLine("display: none;");
                    htmlWriter.WriteLine("}");
                    htmlWriter.WriteLine("</style>");
                    htmlWriter.WriteLine("<body style=\"font-family: monospace;\">");

                    var uncoveredLineNumbers = new HashSet <int>();
                    var coveredLineNumbers   = new HashSet <int>();
                    foreach (var i in kvFile.Value.Sequences)
                    {
                        if (hitsInfo.WasHit(i.HitId))
                        {
                            coveredLineNumbers.UnionWith(i.GetLines());
                        }
                        else
                        {
                            uncoveredLineNumbers.UnionWith(i.GetLines());
                        }
                    }

                    var l = 0;
                    foreach (var line in lines)
                    {
                        l++;
                        var style = "white-space: pre;";
                        if (coveredLineNumbers.Contains(l))
                        {
                            style += BgColorGreen;
                            style += CursorPointer;
                        }
                        else if (uncoveredLineNumbers.Contains(l))
                        {
                            style += BgColorRed;
                        }
                        else
                        {
                            style += BgColorNeutral;
                        }

                        var instructions = kvFile.Value.Sequences
                                           .Where(i => i.GetLines().Contains(l))
                                           .ToArray();

                        var counter = instructions.Sum(a => hitsInfo.GetHitCount(a.HitId));

                        var codeContent = !string.IsNullOrEmpty(line)
                            ? WebUtility.HtmlEncode(line)
                            : "&nbsp;";

                        var contexts = instructions
                                       .SelectMany(i => hitsInfo.GetHitContexts(i.HitId))
                                       .Distinct()
                                       .ToArray();

                        var hitCountHtml = coveredLineNumbers.Contains(l) || uncoveredLineNumbers.Contains(l)
                            ? $"<span style=\"display: inline-block; width: 30px; font-size: 10px;\">{counter}x</span>"
                            : "<span style=\"display: inline-block; width: 30px; font-size: 10px;\"></span>";

                        if (coveredLineNumbers.Contains(l))
                        {
                            htmlWriter.WriteLine($"<details>");
                            htmlWriter.WriteLine($"<summary style=\"{style}\">{hitCountHtml}{codeContent}</summary>");

                            htmlWriter.WriteLine("<ul>");
                            foreach (var context in contexts)
                            {
                                var count       = instructions.Sum(i => context.GetHitCount(i.HitId));
                                var description = $"{context.ClassName}.{context.MethodName}";
                                htmlWriter.WriteLine($"<li>{WebUtility.HtmlEncode(description)}: {count}x</li>");
                            }
                            htmlWriter.WriteLine("</ul>");

                            htmlWriter.WriteLine($"</details>");
                        }
                        else
                        {
                            htmlWriter.WriteLine($"<div style=\"{style}\">{hitCountHtml}{codeContent}</div>");
                        }
                    }

                    htmlWriter.WriteLine("</body>");
                    htmlWriter.WriteLine("</html>");
                }
            }
        }