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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
 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;
 }
Beispiel #4
0
 private static XElement CreateClassesElement(InstrumentedAssembly assembly, HitsInfo hitsInfo)
 {
     return(new XElement(
                XName.Get("classes"),
                assembly.SourceFiles
                .Select(kv => CreateClassElement(kv.Key, kv.Value, hitsInfo))
                ));
 }
Beispiel #5
0
 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))
                ));
 }
Beispiel #6
0
 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))
                ));
 }
Beispiel #7
0
 private static XElement CrateSourcesElement(InstrumentationResult result, HitsInfo hitsInfo)
 {
     return(new XElement(
                XName.Get("sources"),
                new XElement("source",
                             new XText(result.SourcePath)
                             )
                ));
 }
Beispiel #8
0
        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)
                       ));
        }
Beispiel #9
0
        public static Summary CalculateSummaryStatic(
            InstrumentationResult result,
            float threshold)
        {
            var hitsInfo = HitsInfo.TryReadFromDirectory(result.HitsPath);

            return(CalculateFilesSummary(
                       result.GetSourceFiles(),
                       hitsInfo,
                       threshold));
        }
Beispiel #10
0
        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);
        }
Beispiel #11
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);
        }
Beispiel #12
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)
                       ));
        }
Beispiel #13
0
        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);
        }
Beispiel #14
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)
                       ));
        }
Beispiel #15
0
        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)
                       ));
        }
Beispiel #17
0
        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);
        }
Beispiel #18
0
 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)
                                            )));
 }
Beispiel #19
0
 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)
                                         )));
 }
Beispiel #20
0
 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)
                ));
 }
Beispiel #21
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()
            });
        }
Beispiel #22
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}%")
                       ));
        }
Beispiel #23
0
        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}");
                    }
                }
            }
        }
Beispiel #24
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
                       ));
        }
Beispiel #25
0
 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))
                        )));
 }
Beispiel #26
0
 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;
     }));;
 }
Beispiel #27
0
 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")
                        )));
 }
Beispiel #28
0
 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("&nbsp;");
                    }

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

                htmlWriter.WriteLine("</div>");
                htmlWriter.WriteLine("</body>");
                htmlWriter.WriteLine("</html>");
            }
        }
Beispiel #30
0
 private static XElement CreateConditionsElements(IEnumerable <InstrumentedCondition> conditions, HitsInfo hitsInfo)
 {
     return(new XElement(
                XName.Get("conditions"),
                conditions.Select((b, i) => CreateConditionElement(b, i, hitsInfo))
                ));
 }