public void TestCalculateBranchCoverage_MultiModule()
        {
            CoverageSummary summary = new CoverageSummary();
            var             documentsFirstModule  = _averageCalculationMultiModule["module"];
            var             documentsSecondModule = _averageCalculationMultiModule["aditionalModule"];

            Assert.Equal(83.33, summary.CalculateBranchCoverage(_averageCalculationMultiModule).AverageModulePercent);
            Assert.Equal(100, summary.CalculateBranchCoverage(documentsFirstModule.First().Value).Percent);
            Assert.Equal(66.66, summary.CalculateBranchCoverage(documentsSecondModule.First().Value).Percent);
        }
Exemplo n.º 2
0
        public void TestCalculateLineCoverage_NoModules()
        {
            CoverageSummary summary = new CoverageSummary();
            var             modules = new Modules();

            Assert.Equal(0, summary.CalculateLineCoverage(modules).Percent);
            Assert.Equal(0, summary.CalculateLineCoverage(modules).AverageModulePercent);
            Assert.Equal(0, summary.CalculateBranchCoverage(modules).Percent);
            Assert.Equal(0, summary.CalculateBranchCoverage(modules).AverageModulePercent);
            Assert.Equal(0, summary.CalculateMethodCoverage(modules).Percent);
            Assert.Equal(0, summary.CalculateMethodCoverage(modules).AverageModulePercent);
        }
Exemplo n.º 3
0
        public void TestCalculateBranchCoveragePercentage_ArithmeticPrecisionCheck()
        {
            CoverageSummary summary = new CoverageSummary();

            var module   = _moduleArithmeticPrecision.First();
            var document = module.Value.First();
            var @class   = document.Value.First();
            var method   = @class.Value.First();

            Assert.Equal(16.66, summary.CalculateBranchCoverage(module.Value).Percent);
            Assert.Equal(16.66, summary.CalculateBranchCoverage(document.Value).Percent);
            Assert.Equal(16.66, summary.CalculateBranchCoverage(@class.Value).Percent);
            Assert.Equal(16.66, summary.CalculateBranchCoverage(method.Value.Branches).Percent);
        }
        public void TestCalculateBranchCoverage()
        {
            CoverageSummary summary = new CoverageSummary();

            var module   = _modules.First();
            var document = module.Value.First();
            var @class   = document.Value.First();
            var method   = @class.Value.First();

            Assert.Equal(1, summary.CalculateBranchCoverage(module.Value).Percent);
            Assert.Equal(1, summary.CalculateBranchCoverage(document.Value).Percent);
            Assert.Equal(1, summary.CalculateBranchCoverage(@class.Value).Percent);
            Assert.Equal(1, summary.CalculateBranchCoverage(method.Value.Branches).Percent);
        }
Exemplo n.º 5
0
        public void TestCalculateBranchCoveragePercentage_ArithmeticPrecisionCheck()
        {
            var summary = new CoverageSummary();

            System.Collections.Generic.KeyValuePair <string, Documents> module   = _moduleArithmeticPrecision.First();
            System.Collections.Generic.KeyValuePair <string, Classes>   document = module.Value.First();
            System.Collections.Generic.KeyValuePair <string, Methods>   @class   = document.Value.First();
            System.Collections.Generic.KeyValuePair <string, Method>    method   = @class.Value.First();

            Assert.Equal(16.66, summary.CalculateBranchCoverage(_moduleArithmeticPrecision).AverageModulePercent);
            Assert.Equal(16.66, summary.CalculateBranchCoverage(module.Value).Percent);
            Assert.Equal(16.66, summary.CalculateBranchCoverage(document.Value).Percent);
            Assert.Equal(16.66, summary.CalculateBranchCoverage(@class.Value).Percent);
            Assert.Equal(16.66, summary.CalculateBranchCoverage(method.Value.Branches).Percent);
        }
        public void TestCalculateBranchCoverage_SingleModule()
        {
            CoverageSummary summary = new CoverageSummary();

            var module   = _averageCalculationSingleModule.First();
            var document = module.Value.First();
            var @class   = document.Value.First();
            var method   = @class.Value.First();

            Assert.Equal(100, summary.CalculateBranchCoverage(_averageCalculationSingleModule).AverageModulePercent);
            Assert.Equal(100, summary.CalculateBranchCoverage(module.Value).Percent);
            Assert.Equal(100, summary.CalculateBranchCoverage(document.Value).Percent);
            Assert.Equal(100, summary.CalculateBranchCoverage(@class.Value).Percent);
            Assert.Equal(100, summary.CalculateBranchCoverage(method.Value.Branches).Percent);
        }
Exemplo n.º 7
0
        public void TestCalculateBranchCoverage_SingleModule()
        {
            var summary = new CoverageSummary();

            System.Collections.Generic.KeyValuePair <string, Documents> module   = _averageCalculationSingleModule.First();
            System.Collections.Generic.KeyValuePair <string, Classes>   document = module.Value.First();
            System.Collections.Generic.KeyValuePair <string, Methods>   @class   = document.Value.First();
            System.Collections.Generic.KeyValuePair <string, Method>    method   = @class.Value.First();

            Assert.Equal(100, summary.CalculateBranchCoverage(_averageCalculationSingleModule).AverageModulePercent);
            Assert.Equal(100, summary.CalculateBranchCoverage(module.Value).Percent);
            Assert.Equal(100, summary.CalculateBranchCoverage(document.Value).Percent);
            Assert.Equal(100, summary.CalculateBranchCoverage(@class.Value).Percent);
            Assert.Equal(100, summary.CalculateBranchCoverage(method.Value.Branches).Percent);
        }
Exemplo n.º 8
0
        public string Report(CoverageResult result, ISourceRootTranslator sourceRootTranslator)
        {
            if (result.Parameters.DeterministicReport)
            {
                throw new NotSupportedException("Deterministic report not supported by lcov reporter");
            }

            CoverageSummary summary = new CoverageSummary();
            List <string>   lcov    = new List <string>();

            foreach (var module in result.Modules)
            {
                foreach (var doc in module.Value)
                {
                    var docLineCoverage   = summary.CalculateLineCoverage(doc.Value);
                    var docBranchCoverage = summary.CalculateBranchCoverage(doc.Value);
                    var docMethodCoverage = summary.CalculateMethodCoverage(doc.Value);

                    lcov.Add("SF:" + doc.Key);
                    foreach (var @class in doc.Value)
                    {
                        foreach (var method in @class.Value)
                        {
                            // Skip all methods with no lines
                            if (method.Value.Lines.Count == 0)
                            {
                                continue;
                            }

                            lcov.Add($"FN:{method.Value.Lines.First().Key - 1},{method.Key}");
                            lcov.Add($"FNDA:{method.Value.Lines.First().Value},{method.Key}");

                            foreach (var line in method.Value.Lines)
                            {
                                lcov.Add($"DA:{line.Key},{line.Value}");
                            }

                            foreach (var branch in method.Value.Branches)
                            {
                                lcov.Add($"BRDA:{branch.Line},{branch.Offset},{branch.Path},{branch.Hits}");
                            }
                        }
                    }

                    lcov.Add($"LF:{docLineCoverage.Total}");
                    lcov.Add($"LH:{docLineCoverage.Covered}");

                    lcov.Add($"BRF:{docBranchCoverage.Total}");
                    lcov.Add($"BRH:{docBranchCoverage.Covered}");

                    lcov.Add($"FNF:{docMethodCoverage.Total}");
                    lcov.Add($"FNH:{docMethodCoverage.Covered}");

                    lcov.Add("end_of_record");
                }
            }

            return(string.Join(Environment.NewLine, lcov));
        }
Exemplo n.º 9
0
        public string Report(CoverageResult result)
        {
            CoverageSummary summary = new CoverageSummary();
            List <string>   lcov    = new List <string>();

            foreach (var module in result.Modules)
            {
                foreach (var doc in module.Value)
                {
                    var docLineCoverage   = summary.CalculateLineCoverage(doc.Value);
                    var docBranchCoverage = summary.CalculateBranchCoverage(doc.Value);
                    var docMethodCoverage = summary.CalculateMethodCoverage(doc.Value);

                    lcov.Add("SF:" + doc.Key);
                    foreach (var @class in doc.Value)
                    {
                        foreach (var method in @class.Value)
                        {
                            // Skip all methods with no lines
                            if (method.Value.Lines.Count == 0)
                            {
                                continue;
                            }

                            lcov.Add($"FN:{method.Value.Lines.First().Key - 1},{method.Key}");
                            lcov.Add($"FNDA:{method.Value.Lines.First().Value.Hits},{method.Key}");

                            foreach (var line in method.Value.Lines)
                            {
                                lcov.Add($"DA:{line.Key},{line.Value.Hits}");
                            }

                            foreach (var branchs in method.Value.Branches)
                            {
                                foreach (var branch in branchs.Value)
                                {
                                    lcov.Add($"BRDA:{branchs.Key},{branch.Offset},{branch.Path},{branch.Hits}");
                                }
                            }
                        }
                    }

                    lcov.Add($"LF:{docLineCoverage.Total}");
                    lcov.Add($"LH:{docLineCoverage.Covered}");

                    lcov.Add($"BRF:{docBranchCoverage.Total}");
                    lcov.Add($"BRH:{docBranchCoverage.Covered}");

                    lcov.Add($"FNF:{docMethodCoverage.Total}");
                    lcov.Add($"FNH:{docMethodCoverage.Covered}");

                    lcov.Add("end_of_record");
                }
            }

            return(string.Join(Environment.NewLine, lcov));
        }
        public string Report(CoverageResult result)
        {
            // Calculate coverage
            var summary               = new CoverageSummary();
            var overallLineCoverage   = summary.CalculateLineCoverage(result.Modules);
            var overallBranchCoverage = summary.CalculateBranchCoverage(result.Modules);
            var overallMethodCoverage = summary.CalculateMethodCoverage(result.Modules);

            // Report coverage
            var stringBuilder = new StringBuilder();

            OutputLineCoverage(overallLineCoverage, stringBuilder);
            OutputBranchCoverage(overallBranchCoverage, stringBuilder);
            OutputMethodCoverage(overallMethodCoverage, stringBuilder);

            // Return a placeholder
            return(stringBuilder.ToString());
        }
Exemplo n.º 11
0
        public string Report(CoverageResult result, ISourceRootTranslator sourceRootTranslator)
        {
            if (result.Parameters.DeterministicReport)
            {
                throw new NotSupportedException("Deterministic report not supported by teamcity reporter");
            }

            // Calculate coverage
            var summary               = new CoverageSummary();
            var overallLineCoverage   = summary.CalculateLineCoverage(result.Modules);
            var overallBranchCoverage = summary.CalculateBranchCoverage(result.Modules);
            var overallMethodCoverage = summary.CalculateMethodCoverage(result.Modules);

            // Report coverage
            var stringBuilder = new StringBuilder();

            OutputLineCoverage(overallLineCoverage, stringBuilder);
            OutputBranchCoverage(overallBranchCoverage, stringBuilder);
            OutputMethodCoverage(overallMethodCoverage, stringBuilder);

            // Return a placeholder
            return(stringBuilder.ToString());
        }
Exemplo n.º 12
0
        public string Report(CoverageResult result)
        {
            CoverageSummary summary         = new CoverageSummary();
            XDocument       xml             = new XDocument();
            XElement        coverage        = new XElement("CoverageSession");
            XElement        coverageSummary = new XElement("Summary");
            XElement        modules         = new XElement("Modules");

            int numClasses = 0, numMethods = 0;
            int visitedClasses = 0, visitedMethods = 0;

            int i = 1;

            foreach (var mod in result.Modules)
            {
                XElement module = new XElement("Module");
                module.Add(new XAttribute("hash", Guid.NewGuid().ToString().ToUpper()));

                XElement path = new XElement("ModulePath", mod.Key);
                XElement time = new XElement("ModuleTime", DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ss"));
                XElement name = new XElement("ModuleName", Path.GetFileNameWithoutExtension(mod.Key));

                module.Add(path);
                module.Add(time);
                module.Add(name);

                XElement files   = new XElement("Files");
                XElement classes = new XElement("Classes");

                foreach (var doc in mod.Value)
                {
                    XElement file = new XElement("File");
                    file.Add(new XAttribute("uid", i.ToString()));
                    file.Add(new XAttribute("fullPath", doc.Key));
                    files.Add(file);

                    foreach (var cls in doc.Value)
                    {
                        XElement @class       = new XElement("Class");
                        XElement classSummary = new XElement("Summary");

                        XElement className = new XElement("FullName", cls.Key);

                        XElement methods      = new XElement("Methods");
                        int      j            = 0;
                        var      classVisited = false;

                        foreach (var meth in cls.Value)
                        {
                            // Skip all methods with no lines
                            if (meth.Value.Lines.Count == 0)
                            {
                                continue;
                            }

                            var methLineCoverage         = summary.CalculateLineCoverage(meth.Value.Lines);
                            var methBranchCoverage       = summary.CalculateBranchCoverage(meth.Value.Branches);
                            var methCyclomaticComplexity = summary.CalculateCyclomaticComplexity(meth.Value.Branches);

                            XElement method = new XElement("Method");

                            method.Add(new XAttribute("cyclomaticComplexity", methCyclomaticComplexity.ToString()));
                            method.Add(new XAttribute("nPathComplexity", "0"));
                            method.Add(new XAttribute("sequenceCoverage", methLineCoverage.Percent.ToString()));
                            method.Add(new XAttribute("branchCoverage", methBranchCoverage.Percent.ToString()));
                            method.Add(new XAttribute("isConstructor", meth.Key.Contains("ctor").ToString()));
                            method.Add(new XAttribute("isGetter", meth.Key.Contains("get_").ToString()));
                            method.Add(new XAttribute("isSetter", meth.Key.Contains("set_").ToString()));
                            method.Add(new XAttribute("isStatic", (!meth.Key.Contains("get_") || !meth.Key.Contains("set_")).ToString()));

                            XElement methodName = new XElement("Name", meth.Key);

                            XElement fileRef = new XElement("FileRef");
                            fileRef.Add(new XAttribute("uid", i.ToString()));

                            XElement methodPoint = new XElement("MethodPoint");
                            methodPoint.Add(new XAttribute("vc", methLineCoverage.Covered.ToString()));
                            methodPoint.Add(new XAttribute("upsid", "0"));
                            methodPoint.Add(new XAttribute(XName.Get("type", "xsi"), "SequencePoint"));
                            methodPoint.Add(new XAttribute("ordinal", j.ToString()));
                            methodPoint.Add(new XAttribute("offset", j.ToString()));
                            methodPoint.Add(new XAttribute("sc", "0"));
                            methodPoint.Add(new XAttribute("sl", meth.Value.Lines.First().Key.ToString()));
                            methodPoint.Add(new XAttribute("ec", "1"));
                            methodPoint.Add(new XAttribute("el", meth.Value.Lines.Last().Key.ToString()));
                            methodPoint.Add(new XAttribute("bec", "0"));
                            methodPoint.Add(new XAttribute("bev", "0"));
                            methodPoint.Add(new XAttribute("fileid", i.ToString()));

                            // They're really just lines
                            XElement sequencePoints = new XElement("SequencePoints");
                            XElement branchPoints   = new XElement("BranchPoints");
                            XElement methodSummary  = new XElement("Summary");
                            int      k             = 0;
                            int      kBr           = 0;
                            var      methodVisited = false;

                            foreach (var lines in meth.Value.Lines)
                            {
                                XElement sequencePoint = new XElement("SequencePoint");
                                sequencePoint.Add(new XAttribute("vc", lines.Value.ToString()));
                                sequencePoint.Add(new XAttribute("upsid", lines.Key.ToString()));
                                sequencePoint.Add(new XAttribute("ordinal", k.ToString()));
                                sequencePoint.Add(new XAttribute("sl", lines.Key.ToString()));
                                sequencePoint.Add(new XAttribute("sc", "1"));
                                sequencePoint.Add(new XAttribute("el", lines.Key.ToString()));
                                sequencePoint.Add(new XAttribute("ec", "2"));
                                sequencePoint.Add(new XAttribute("bec", "0"));
                                sequencePoint.Add(new XAttribute("bev", "0"));
                                sequencePoint.Add(new XAttribute("fileid", i.ToString()));
                                sequencePoints.Add(sequencePoint);

                                if (lines.Value > 0)
                                {
                                    classVisited  = true;
                                    methodVisited = true;
                                }

                                k++;
                            }

                            foreach (var branche in meth.Value.Branches)
                            {
                                XElement branchPoint = new XElement("BranchPoint");
                                branchPoint.Add(new XAttribute("vc", branche.Hits.ToString()));
                                branchPoint.Add(new XAttribute("upsid", branche.Line.ToString()));
                                branchPoint.Add(new XAttribute("ordinal", branche.Ordinal.ToString()));
                                branchPoint.Add(new XAttribute("path", branche.Path.ToString()));
                                branchPoint.Add(new XAttribute("offset", branche.Offset.ToString()));
                                branchPoint.Add(new XAttribute("offsetend", branche.EndOffset.ToString()));
                                branchPoint.Add(new XAttribute("sl", branche.Line.ToString()));
                                branchPoint.Add(new XAttribute("fileid", i.ToString()));
                                branchPoints.Add(branchPoint);
                                kBr++;
                            }

                            numMethods++;
                            if (methodVisited)
                            {
                                visitedMethods++;
                            }

                            methodSummary.Add(new XAttribute("numSequencePoints", methLineCoverage.Total.ToString()));
                            methodSummary.Add(new XAttribute("visitedSequencePoints", methLineCoverage.Covered.ToString()));
                            methodSummary.Add(new XAttribute("numBranchPoints", methBranchCoverage.Total.ToString()));
                            methodSummary.Add(new XAttribute("visitedBranchPoints", methBranchCoverage.Covered.ToString()));
                            methodSummary.Add(new XAttribute("sequenceCoverage", methLineCoverage.Percent.ToString()));
                            methodSummary.Add(new XAttribute("branchCoverage", methBranchCoverage.Percent.ToString()));
                            methodSummary.Add(new XAttribute("maxCyclomaticComplexity", methCyclomaticComplexity.ToString()));
                            methodSummary.Add(new XAttribute("minCyclomaticComplexity", methCyclomaticComplexity.ToString()));
                            methodSummary.Add(new XAttribute("visitedClasses", "0"));
                            methodSummary.Add(new XAttribute("numClasses", "0"));
                            methodSummary.Add(new XAttribute("visitedMethods", methodVisited ? "1" : "0"));
                            methodSummary.Add(new XAttribute("numMethods", "1"));

                            method.Add(methodSummary);
                            method.Add(new XElement("MetadataToken"));
                            method.Add(methodName);
                            method.Add(fileRef);
                            method.Add(sequencePoints);
                            method.Add(branchPoints);
                            method.Add(methodPoint);
                            methods.Add(method);
                            j++;
                        }

                        numClasses++;
                        if (classVisited)
                        {
                            visitedClasses++;
                        }

                        var classLineCoverage            = summary.CalculateLineCoverage(cls.Value);
                        var classBranchCoverage          = summary.CalculateBranchCoverage(cls.Value);
                        var classMethodCoverage          = summary.CalculateMethodCoverage(cls.Value);
                        var classMaxCyclomaticComplexity = summary.CalculateMaxCyclomaticComplexity(cls.Value);
                        var classMinCyclomaticComplexity = summary.CalculateMinCyclomaticComplexity(cls.Value);

                        classSummary.Add(new XAttribute("numSequencePoints", classLineCoverage.Total.ToString()));
                        classSummary.Add(new XAttribute("visitedSequencePoints", classLineCoverage.Covered.ToString()));
                        classSummary.Add(new XAttribute("numBranchPoints", classBranchCoverage.Total.ToString()));
                        classSummary.Add(new XAttribute("visitedBranchPoints", classBranchCoverage.Covered.ToString()));
                        classSummary.Add(new XAttribute("sequenceCoverage", classLineCoverage.Percent.ToString()));
                        classSummary.Add(new XAttribute("branchCoverage", classBranchCoverage.Percent.ToString()));
                        classSummary.Add(new XAttribute("maxCyclomaticComplexity", classMaxCyclomaticComplexity.ToString()));
                        classSummary.Add(new XAttribute("minCyclomaticComplexity", classMinCyclomaticComplexity.ToString()));
                        classSummary.Add(new XAttribute("visitedClasses", classVisited ? "1" : "0"));
                        classSummary.Add(new XAttribute("numClasses", "1"));
                        classSummary.Add(new XAttribute("visitedMethods", classMethodCoverage.Covered.ToString()));
                        classSummary.Add(new XAttribute("numMethods", classMethodCoverage.Total.ToString()));

                        @class.Add(classSummary);
                        @class.Add(className);
                        @class.Add(methods);
                        classes.Add(@class);
                    }
                    i++;
                }

                module.Add(files);
                module.Add(classes);
                modules.Add(module);
            }

            var moduleLineCoverage            = summary.CalculateLineCoverage(result.Modules);
            var moduleBranchCoverage          = summary.CalculateLineCoverage(result.Modules);
            var moduleMaxCyclomaticComplexity = summary.CalculateMaxCyclomaticComplexity(result.Modules);
            var moduleMinCyclomaticComplexity = summary.CalculateMinCyclomaticComplexity(result.Modules);

            coverageSummary.Add(new XAttribute("numSequencePoints", moduleLineCoverage.Total.ToString()));
            coverageSummary.Add(new XAttribute("visitedSequencePoints", moduleLineCoverage.Covered.ToString()));
            coverageSummary.Add(new XAttribute("numBranchPoints", moduleBranchCoverage.Total.ToString()));
            coverageSummary.Add(new XAttribute("visitedBranchPoints", moduleBranchCoverage.Covered.ToString()));
            coverageSummary.Add(new XAttribute("sequenceCoverage", moduleLineCoverage.Percent.ToString()));
            coverageSummary.Add(new XAttribute("branchCoverage", moduleBranchCoverage.Percent.ToString()));
            coverageSummary.Add(new XAttribute("maxCyclomaticComplexity", moduleMaxCyclomaticComplexity.ToString()));
            coverageSummary.Add(new XAttribute("minCyclomaticComplexity", moduleMinCyclomaticComplexity.ToString()));
            coverageSummary.Add(new XAttribute("visitedClasses", visitedClasses.ToString()));
            coverageSummary.Add(new XAttribute("numClasses", numClasses.ToString()));
            coverageSummary.Add(new XAttribute("visitedMethods", visitedMethods.ToString()));
            coverageSummary.Add(new XAttribute("numMethods", numMethods.ToString()));

            coverage.Add(coverageSummary);
            coverage.Add(modules);
            xml.Add(coverage);

            var stream = new MemoryStream();

            xml.Save(stream);

            return(Encoding.UTF8.GetString(stream.ToArray()));
        }
Exemplo n.º 13
0
        public string Report(CoverageResult result, ISourceRootTranslator sourceRootTranslator)
        {
            if (result.Parameters.DeterministicReport)
            {
                throw new NotSupportedException("Deterministic report not supported by openCover reporter");
            }

            var summary         = new CoverageSummary();
            var xml             = new XDocument();
            var coverage        = new XElement("CoverageSession");
            var coverageSummary = new XElement("Summary");
            var modules         = new XElement("Modules");

            int numClasses = 0, numMethods = 0;
            int visitedClasses = 0, visitedMethods = 0;

            int i = 1;

            foreach (System.Collections.Generic.KeyValuePair <string, Documents> mod in result.Modules)
            {
                var module = new XElement("Module");
                module.Add(new XAttribute("hash", Guid.NewGuid().ToString().ToUpper()));

                var path = new XElement("ModulePath", mod.Key);
                var time = new XElement("ModuleTime", DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ss"));
                var name = new XElement("ModuleName", Path.GetFileNameWithoutExtension(mod.Key));

                module.Add(path);
                module.Add(time);
                module.Add(name);

                var files   = new XElement("Files");
                var classes = new XElement("Classes");

                foreach (System.Collections.Generic.KeyValuePair <string, Classes> doc in mod.Value)
                {
                    var file = new XElement("File");
                    file.Add(new XAttribute("uid", i.ToString()));
                    file.Add(new XAttribute("fullPath", doc.Key));
                    files.Add(file);

                    foreach (System.Collections.Generic.KeyValuePair <string, Methods> cls in doc.Value)
                    {
                        var @class       = new XElement("Class");
                        var classSummary = new XElement("Summary");

                        var className = new XElement("FullName", cls.Key);

                        var  methods      = new XElement("Methods");
                        int  j            = 0;
                        bool classVisited = false;

                        foreach (System.Collections.Generic.KeyValuePair <string, Method> meth in cls.Value)
                        {
                            // Skip all methods with no lines
                            if (meth.Value.Lines.Count == 0)
                            {
                                continue;
                            }

                            CoverageDetails methLineCoverage         = summary.CalculateLineCoverage(meth.Value.Lines);
                            CoverageDetails methBranchCoverage       = summary.CalculateBranchCoverage(meth.Value.Branches);
                            int             methCyclomaticComplexity = summary.CalculateCyclomaticComplexity(meth.Value.Branches);
                            int             methNpathComplexity      = summary.CalculateNpathComplexity(meth.Value.Branches);

                            var method = new XElement("Method");

                            method.Add(new XAttribute("cyclomaticComplexity", methCyclomaticComplexity.ToString()));
                            method.Add(new XAttribute("nPathComplexity", methCyclomaticComplexity.ToString()));
                            method.Add(new XAttribute("sequenceCoverage", methLineCoverage.Percent.ToString("G", CultureInfo.InvariantCulture)));
                            method.Add(new XAttribute("branchCoverage", methBranchCoverage.Percent.ToString("G", CultureInfo.InvariantCulture)));
                            method.Add(new XAttribute("isConstructor", meth.Key.Contains("ctor").ToString()));
                            method.Add(new XAttribute("isGetter", meth.Key.Contains("get_").ToString()));
                            method.Add(new XAttribute("isSetter", meth.Key.Contains("set_").ToString()));
                            method.Add(new XAttribute("isStatic", (!meth.Key.Contains("get_") || !meth.Key.Contains("set_")).ToString()));

                            var methodName = new XElement("Name", meth.Key);

                            var fileRef = new XElement("FileRef");
                            fileRef.Add(new XAttribute("uid", i.ToString()));

                            var methodPoint = new XElement("MethodPoint");
                            methodPoint.Add(new XAttribute("vc", methLineCoverage.Covered.ToString()));
                            methodPoint.Add(new XAttribute("uspid", "0"));
                            methodPoint.Add(new XAttribute(XName.Get("type", "xsi"), "SequencePoint"));
                            methodPoint.Add(new XAttribute("ordinal", j.ToString()));
                            methodPoint.Add(new XAttribute("offset", j.ToString()));
                            methodPoint.Add(new XAttribute("sc", "0"));
                            methodPoint.Add(new XAttribute("sl", meth.Value.Lines.First().Key.ToString()));
                            methodPoint.Add(new XAttribute("ec", "1"));
                            methodPoint.Add(new XAttribute("el", meth.Value.Lines.Last().Key.ToString()));
                            methodPoint.Add(new XAttribute("bec", "0"));
                            methodPoint.Add(new XAttribute("bev", "0"));
                            methodPoint.Add(new XAttribute("fileid", i.ToString()));

                            // They're really just lines
                            var  sequencePoints = new XElement("SequencePoints");
                            var  branchPoints   = new XElement("BranchPoints");
                            var  methodSummary  = new XElement("Summary");
                            int  k             = 0;
                            int  kBr           = 0;
                            bool methodVisited = false;

                            foreach (System.Collections.Generic.KeyValuePair <int, int> lines in meth.Value.Lines)
                            {
                                BranchInfo[]    lineBranches   = meth.Value.Branches.Where(branchInfo => branchInfo.Line == lines.Key).ToArray();
                                CoverageDetails branchCoverage = summary.CalculateBranchCoverage(lineBranches);

                                var sequencePoint = new XElement("SequencePoint");
                                sequencePoint.Add(new XAttribute("vc", lines.Value.ToString()));
                                sequencePoint.Add(new XAttribute("uspid", lines.Key.ToString()));
                                sequencePoint.Add(new XAttribute("ordinal", k.ToString()));
                                sequencePoint.Add(new XAttribute("sl", lines.Key.ToString()));
                                sequencePoint.Add(new XAttribute("sc", "1"));
                                sequencePoint.Add(new XAttribute("el", lines.Key.ToString()));
                                sequencePoint.Add(new XAttribute("ec", "2"));
                                sequencePoint.Add(new XAttribute("bec", branchCoverage.Total));
                                sequencePoint.Add(new XAttribute("bev", branchCoverage.Covered));
                                sequencePoint.Add(new XAttribute("fileid", i.ToString()));
                                sequencePoints.Add(sequencePoint);

                                if (lines.Value > 0)
                                {
                                    classVisited  = true;
                                    methodVisited = true;
                                }

                                k++;
                            }

                            foreach (BranchInfo branche in meth.Value.Branches)
                            {
                                var branchPoint = new XElement("BranchPoint");
                                branchPoint.Add(new XAttribute("vc", branche.Hits.ToString()));
                                branchPoint.Add(new XAttribute("uspid", branche.Line.ToString()));
                                branchPoint.Add(new XAttribute("ordinal", branche.Ordinal.ToString()));
                                branchPoint.Add(new XAttribute("path", branche.Path.ToString()));
                                branchPoint.Add(new XAttribute("offset", branche.Offset.ToString()));
                                branchPoint.Add(new XAttribute("offsetend", branche.EndOffset.ToString()));
                                branchPoint.Add(new XAttribute("sl", branche.Line.ToString()));
                                branchPoint.Add(new XAttribute("fileid", i.ToString()));
                                branchPoints.Add(branchPoint);
                                kBr++;
                            }

                            numMethods++;
                            if (methodVisited)
                            {
                                visitedMethods++;
                            }

                            methodSummary.Add(new XAttribute("numSequencePoints", methLineCoverage.Total.ToString()));
                            methodSummary.Add(new XAttribute("visitedSequencePoints", methLineCoverage.Covered.ToString()));
                            methodSummary.Add(new XAttribute("numBranchPoints", methBranchCoverage.Total.ToString()));
                            methodSummary.Add(new XAttribute("visitedBranchPoints", methBranchCoverage.Covered.ToString()));
                            methodSummary.Add(new XAttribute("sequenceCoverage", methLineCoverage.Percent.ToString("G", CultureInfo.InvariantCulture)));
                            methodSummary.Add(new XAttribute("branchCoverage", methBranchCoverage.Percent.ToString("G", CultureInfo.InvariantCulture)));
                            methodSummary.Add(new XAttribute("maxCyclomaticComplexity", methCyclomaticComplexity.ToString()));
                            methodSummary.Add(new XAttribute("minCyclomaticComplexity", methCyclomaticComplexity.ToString()));
                            methodSummary.Add(new XAttribute("visitedClasses", "0"));
                            methodSummary.Add(new XAttribute("numClasses", "0"));
                            methodSummary.Add(new XAttribute("visitedMethods", methodVisited ? "1" : "0"));
                            methodSummary.Add(new XAttribute("numMethods", "1"));

                            method.Add(methodSummary);
                            method.Add(new XElement("MetadataToken"));
                            method.Add(methodName);
                            method.Add(fileRef);
                            method.Add(sequencePoints);
                            method.Add(branchPoints);
                            method.Add(methodPoint);
                            methods.Add(method);
                            j++;
                        }

                        numClasses++;
                        if (classVisited)
                        {
                            visitedClasses++;
                        }

                        CoverageDetails classLineCoverage            = summary.CalculateLineCoverage(cls.Value);
                        CoverageDetails classBranchCoverage          = summary.CalculateBranchCoverage(cls.Value);
                        CoverageDetails classMethodCoverage          = summary.CalculateMethodCoverage(cls.Value);
                        int             classMaxCyclomaticComplexity = summary.CalculateMaxCyclomaticComplexity(cls.Value);
                        int             classMinCyclomaticComplexity = summary.CalculateMinCyclomaticComplexity(cls.Value);

                        classSummary.Add(new XAttribute("numSequencePoints", classLineCoverage.Total.ToString()));
                        classSummary.Add(new XAttribute("visitedSequencePoints", classLineCoverage.Covered.ToString()));
                        classSummary.Add(new XAttribute("numBranchPoints", classBranchCoverage.Total.ToString()));
                        classSummary.Add(new XAttribute("visitedBranchPoints", classBranchCoverage.Covered.ToString()));
                        classSummary.Add(new XAttribute("sequenceCoverage", classLineCoverage.Percent.ToString("G", CultureInfo.InvariantCulture)));
                        classSummary.Add(new XAttribute("branchCoverage", classBranchCoverage.Percent.ToString("G", CultureInfo.InvariantCulture)));
                        classSummary.Add(new XAttribute("maxCyclomaticComplexity", classMaxCyclomaticComplexity.ToString()));
                        classSummary.Add(new XAttribute("minCyclomaticComplexity", classMinCyclomaticComplexity.ToString()));
                        classSummary.Add(new XAttribute("visitedClasses", classVisited ? "1" : "0"));
                        classSummary.Add(new XAttribute("numClasses", "1"));
                        classSummary.Add(new XAttribute("visitedMethods", classMethodCoverage.Covered.ToString()));
                        classSummary.Add(new XAttribute("numMethods", classMethodCoverage.Total.ToString()));

                        @class.Add(classSummary);
                        @class.Add(className);
                        @class.Add(methods);
                        classes.Add(@class);
                    }
                    i++;
                }

                module.Add(files);
                module.Add(classes);
                modules.Add(module);
            }

            CoverageDetails moduleLineCoverage            = summary.CalculateLineCoverage(result.Modules);
            CoverageDetails moduleBranchCoverage          = summary.CalculateBranchCoverage(result.Modules);
            int             moduleMaxCyclomaticComplexity = summary.CalculateMaxCyclomaticComplexity(result.Modules);
            int             moduleMinCyclomaticComplexity = summary.CalculateMinCyclomaticComplexity(result.Modules);

            coverageSummary.Add(new XAttribute("numSequencePoints", moduleLineCoverage.Total.ToString()));
            coverageSummary.Add(new XAttribute("visitedSequencePoints", moduleLineCoverage.Covered.ToString()));
            coverageSummary.Add(new XAttribute("numBranchPoints", moduleBranchCoverage.Total.ToString()));
            coverageSummary.Add(new XAttribute("visitedBranchPoints", moduleBranchCoverage.Covered.ToString()));
            coverageSummary.Add(new XAttribute("sequenceCoverage", moduleLineCoverage.Percent.ToString("G", CultureInfo.InvariantCulture)));
            coverageSummary.Add(new XAttribute("branchCoverage", moduleBranchCoverage.Percent.ToString("G", CultureInfo.InvariantCulture)));
            coverageSummary.Add(new XAttribute("maxCyclomaticComplexity", moduleMaxCyclomaticComplexity.ToString()));
            coverageSummary.Add(new XAttribute("minCyclomaticComplexity", moduleMinCyclomaticComplexity.ToString()));
            coverageSummary.Add(new XAttribute("visitedClasses", visitedClasses.ToString()));
            coverageSummary.Add(new XAttribute("numClasses", numClasses.ToString()));
            coverageSummary.Add(new XAttribute("visitedMethods", visitedMethods.ToString()));
            coverageSummary.Add(new XAttribute("numMethods", numMethods.ToString()));

            coverage.Add(coverageSummary);
            coverage.Add(modules);
            xml.Add(coverage);

            var stream = new MemoryStream();

            xml.Save(stream);

            return(Encoding.UTF8.GetString(stream.ToArray()));
        }
Exemplo n.º 14
0
        static int Main(string[] args)
        {
            var logger = new ConsoleLogger();
            var app    = new CommandLineApplication();

            app.Name     = "coverlet";
            app.FullName = "Cross platform .NET Core code coverage tool";
            app.HelpOption("-h|--help");
            app.VersionOption("-v|--version", GetAssemblyVersion());

            CommandArgument module              = app.Argument("<ASSEMBLY>", "Path to the test assembly.");
            CommandOption   target              = app.Option("-t|--target", "Path to the test runner application.", CommandOptionType.SingleValue);
            CommandOption   targs               = app.Option("-a|--targetargs", "Arguments to be passed to the test runner.", CommandOptionType.SingleValue);
            CommandOption   output              = app.Option("-o|--output", "Output of the generated coverage report", CommandOptionType.SingleValue);
            CommandOption   formats             = app.Option("-f|--format", "Format of the generated coverage report.", CommandOptionType.MultipleValue);
            CommandOption   threshold           = app.Option("--threshold", "Exits with error if the coverage % is below value.", CommandOptionType.SingleValue);
            CommandOption   thresholdTypes      = app.Option("--threshold-type", "Coverage type to apply the threshold to.", CommandOptionType.MultipleValue);
            CommandOption   excludeFilters      = app.Option("--exclude", "Filter expressions to exclude specific modules and types.", CommandOptionType.MultipleValue);
            CommandOption   includeFilters      = app.Option("--include", "Filter expressions to include only specific modules and types.", CommandOptionType.MultipleValue);
            CommandOption   excludedSourceFiles = app.Option("--exclude-by-file", "Glob patterns specifying source files to exclude.", CommandOptionType.MultipleValue);
            CommandOption   mergeWith           = app.Option("--merge-with", "Path to existing coverage result to merge.", CommandOptionType.SingleValue);

            app.OnExecute(() =>
            {
                if (string.IsNullOrEmpty(module.Value) || string.IsNullOrWhiteSpace(module.Value))
                {
                    throw new CommandParsingException(app, "No test assembly specified.");
                }

                if (!target.HasValue())
                {
                    throw new CommandParsingException(app, "Target must be specified.");
                }

                Coverage coverage = new Coverage(module.Value, excludeFilters.Values.ToArray(), includeFilters.Values.ToArray(), excludedSourceFiles.Values.ToArray(), mergeWith.Value());
                coverage.PrepareModules();

                Process process                          = new Process();
                process.StartInfo.FileName               = target.Value();
                process.StartInfo.Arguments              = targs.HasValue() ? targs.Value() : string.Empty;
                process.StartInfo.CreateNoWindow         = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.Start();
                logger.LogInformation(process.StandardOutput.ReadToEnd());
                process.WaitForExit();

                var dOutput         = output.HasValue() ? output.Value() : Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar.ToString();
                var dThreshold      = threshold.HasValue() ? int.Parse(threshold.Value()) : 0;
                var dThresholdTypes = thresholdTypes.HasValue() ? thresholdTypes.Values : new List <string>(new string[] { "line", "branch", "method" });

                logger.LogInformation("\nCalculating coverage result...");

                var result    = coverage.GetCoverageResult();
                var directory = Path.GetDirectoryName(dOutput);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                foreach (var format in (formats.HasValue() ? formats.Values : new List <string>(new string[] { "json" })))
                {
                    var reporter = new ReporterFactory(format).CreateReporter();
                    if (reporter == null)
                    {
                        throw new Exception($"Specified output format '{format}' is not supported");
                    }

                    if (reporter.OutputType == ReporterOutputType.Console)
                    {
                        // Output to console
                        logger.LogInformation("  Outputting results to console");
                        logger.LogInformation(reporter.Report(result));
                    }
                    else
                    {
                        // Output to file
                        var filename = Path.GetFileName(dOutput);
                        filename     = (filename == string.Empty) ? $"coverage.{reporter.Extension}" : filename;
                        filename     = Path.HasExtension(filename) ? filename : $"{filename}.{reporter.Extension}";

                        var report = Path.Combine(directory, filename);
                        logger.LogInformation($"  Generating report '{report}'");
                        File.WriteAllText(report, reporter.Report(result));
                    }
                }

                var summary               = new CoverageSummary();
                var exceptionBuilder      = new StringBuilder();
                var coverageTable         = new ConsoleTable("Module", "Line", "Branch", "Method");
                var thresholdFailed       = false;
                var overallLineCoverage   = summary.CalculateLineCoverage(result.Modules);
                var overallBranchCoverage = summary.CalculateBranchCoverage(result.Modules);
                var overallMethodCoverage = summary.CalculateMethodCoverage(result.Modules);

                foreach (var _module in result.Modules)
                {
                    var linePercent   = summary.CalculateLineCoverage(_module.Value).Percent * 100;
                    var branchPercent = summary.CalculateBranchCoverage(_module.Value).Percent * 100;
                    var methodPercent = summary.CalculateMethodCoverage(_module.Value).Percent * 100;

                    coverageTable.AddRow(Path.GetFileNameWithoutExtension(_module.Key), $"{linePercent}%", $"{branchPercent}%", $"{methodPercent}%");

                    if (dThreshold > 0)
                    {
                        if (linePercent < dThreshold && dThresholdTypes.Contains("line"))
                        {
                            exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(_module.Key)}' has a line coverage '{linePercent}%' below specified threshold '{dThreshold}%'");
                            thresholdFailed = true;
                        }

                        if (branchPercent < dThreshold && dThresholdTypes.Contains("branch"))
                        {
                            exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(_module.Key)}' has a branch coverage '{branchPercent}%' below specified threshold '{dThreshold}%'");
                            thresholdFailed = true;
                        }

                        if (methodPercent < dThreshold && dThresholdTypes.Contains("method"))
                        {
                            exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(_module.Key)}' has a method coverage '{methodPercent}%' below specified threshold '{dThreshold}%'");
                            thresholdFailed = true;
                        }
                    }
                }

                logger.LogInformation(string.Empty);
                logger.LogInformation(coverageTable.ToStringAlternative());
                logger.LogInformation($"Total Line: {overallLineCoverage.Percent * 100}%");
                logger.LogInformation($"Total Branch: {overallBranchCoverage.Percent * 100}%");
                logger.LogInformation($"Total Method: {overallMethodCoverage.Percent * 100}%");

                if (thresholdFailed)
                {
                    throw new Exception(exceptionBuilder.ToString().TrimEnd(Environment.NewLine.ToCharArray()));
                }

                return(process.ExitCode == 0 ? 0 : process.ExitCode);
            });

            try
            {
                return(app.Execute(args));
            }
            catch (CommandParsingException ex)
            {
                logger.LogError(ex.Message);
                app.ShowHelp();
                return(1);
            }
            catch (Exception ex)
            {
                logger.LogError(ex.Message);
                return(1);
            }
        }
Exemplo n.º 15
0
        static int Main(string[] args)
        {
            var logger = new ConsoleLogger();
            var app    = new CommandLineApplication();

            app.Name     = "coverlet";
            app.FullName = "Cross platform .NET Core code coverage tool";
            app.HelpOption("-h|--help");
            app.VersionOption("-v|--version", GetAssemblyVersion());
            int exitCode = (int)CommandExitCodes.Success;

            CommandArgument          module              = app.Argument("<ASSEMBLY>", "Path to the test assembly.");
            CommandOption            target              = app.Option("-t|--target", "Path to the test runner application.", CommandOptionType.SingleValue);
            CommandOption            targs               = app.Option("-a|--targetargs", "Arguments to be passed to the test runner.", CommandOptionType.SingleValue);
            CommandOption            output              = app.Option("-o|--output", "Output of the generated coverage report", CommandOptionType.SingleValue);
            CommandOption <LogLevel> verbosity           = app.Option <LogLevel>("-v|--verbosity", "Sets the verbosity level of the command. Allowed values are quiet, minimal, normal, detailed.", CommandOptionType.SingleValue);
            CommandOption            formats             = app.Option("-f|--format", "Format of the generated coverage report.", CommandOptionType.MultipleValue);
            CommandOption            threshold           = app.Option("--threshold", "Exits with error if the coverage % is below value.", CommandOptionType.SingleValue);
            CommandOption            thresholdTypes      = app.Option("--threshold-type", "Coverage type to apply the threshold to.", CommandOptionType.MultipleValue);
            CommandOption            thresholdStat       = app.Option("--threshold-stat", "Coverage statistic used to enforce the threshold value.", CommandOptionType.SingleValue);
            CommandOption            excludeFilters      = app.Option("--exclude", "Filter expressions to exclude specific modules and types.", CommandOptionType.MultipleValue);
            CommandOption            includeFilters      = app.Option("--include", "Filter expressions to include only specific modules and types.", CommandOptionType.MultipleValue);
            CommandOption            excludedSourceFiles = app.Option("--exclude-by-file", "Glob patterns specifying source files to exclude.", CommandOptionType.MultipleValue);
            CommandOption            includeDirectories  = app.Option("--include-directory", "Include directories containing additional assemblies to be instrumented.", CommandOptionType.MultipleValue);
            CommandOption            excludeAttributes   = app.Option("--exclude-by-attribute", "Attributes to exclude from code coverage.", CommandOptionType.MultipleValue);
            CommandOption            includeTestAssembly = app.Option("--include-test-assembly", "Specifies whether to report code coverage of the test assembly.", CommandOptionType.NoValue);
            CommandOption            singleHit           = app.Option("--single-hit", "Specifies whether to limit code coverage hit reporting to a single hit for each location", CommandOptionType.NoValue);
            CommandOption            mergeWith           = app.Option("--merge-with", "Path to existing coverage result to merge.", CommandOptionType.SingleValue);
            CommandOption            useSourceLink       = app.Option("--use-source-link", "Specifies whether to use SourceLink URIs in place of file system paths.", CommandOptionType.NoValue);

            app.OnExecute(() =>
            {
                if (string.IsNullOrEmpty(module.Value) || string.IsNullOrWhiteSpace(module.Value))
                {
                    throw new CommandParsingException(app, "No test assembly specified.");
                }

                if (!target.HasValue())
                {
                    throw new CommandParsingException(app, "Target must be specified.");
                }

                if (verbosity.HasValue())
                {
                    // Adjust log level based on user input.
                    logger.Level = verbosity.ParsedValue;
                }

                // We add default exclusion filter if no specified
                if (excludeFilters.Values.Count == 0)
                {
                    excludeFilters.Values.Add("[xunit*]*");
                }

                Coverage coverage = new Coverage(module.Value,
                                                 includeFilters.Values.ToArray(),
                                                 includeDirectories.Values.ToArray(),
                                                 excludeFilters.Values.ToArray(),
                                                 excludedSourceFiles.Values.ToArray(),
                                                 excludeAttributes.Values.ToArray(),
                                                 includeTestAssembly.HasValue(),
                                                 singleHit.HasValue(),
                                                 mergeWith.Value(),
                                                 useSourceLink.HasValue(),
                                                 logger);
                coverage.PrepareModules();

                Process process                          = new Process();
                process.StartInfo.FileName               = target.Value();
                process.StartInfo.Arguments              = targs.HasValue() ? targs.Value() : string.Empty;
                process.StartInfo.CreateNoWindow         = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError  = true;
                process.OutputDataReceived              += (sender, eventArgs) =>
                {
                    if (!string.IsNullOrEmpty(eventArgs.Data))
                    {
                        logger.LogInformation(eventArgs.Data, important: true);
                    }
                };

                process.ErrorDataReceived += (sender, eventArgs) =>
                {
                    if (!string.IsNullOrEmpty(eventArgs.Data))
                    {
                        logger.LogError(eventArgs.Data);
                    }
                };

                process.Start();

                process.BeginErrorReadLine();
                process.BeginOutputReadLine();

                process.WaitForExit();

                var dOutput         = output.HasValue() ? output.Value() : Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar.ToString();
                var dThreshold      = threshold.HasValue() ? double.Parse(threshold.Value()) : 0;
                var dThresholdTypes = thresholdTypes.HasValue() ? thresholdTypes.Values : new List <string>(new string[] { "line", "branch", "method" });
                var dThresholdStat  = thresholdStat.HasValue() ? Enum.Parse <ThresholdStatistic>(thresholdStat.Value(), true) : Enum.Parse <ThresholdStatistic>("minimum", true);

                logger.LogInformation("\nCalculating coverage result...");

                var result    = coverage.GetCoverageResult();
                var directory = Path.GetDirectoryName(dOutput);
                if (directory == string.Empty)
                {
                    directory = Directory.GetCurrentDirectory();
                }
                else if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                foreach (var format in (formats.HasValue() ? formats.Values : new List <string>(new string[] { "json" })))
                {
                    var reporter = new ReporterFactory(format).CreateReporter();
                    if (reporter == null)
                    {
                        throw new Exception($"Specified output format '{format}' is not supported");
                    }

                    if (reporter.OutputType == ReporterOutputType.Console)
                    {
                        // Output to console
                        logger.LogInformation("  Outputting results to console", important: true);
                        logger.LogInformation(reporter.Report(result), important: true);
                    }
                    else
                    {
                        // Output to file
                        var filename = Path.GetFileName(dOutput);
                        filename     = (filename == string.Empty) ? $"coverage.{reporter.Extension}" : filename;
                        filename     = Path.HasExtension(filename) ? filename : $"{filename}.{reporter.Extension}";

                        var report = Path.Combine(directory, filename);
                        logger.LogInformation($"  Generating report '{report}'", important: true);
                        File.WriteAllText(report, reporter.Report(result));
                    }
                }

                var thresholdTypeFlags = ThresholdTypeFlags.None;

                foreach (var thresholdType in dThresholdTypes)
                {
                    if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Line;
                    }
                    else if (thresholdType.Equals("branch", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Branch;
                    }
                    else if (thresholdType.Equals("method", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Method;
                    }
                }

                var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
                var summary       = new CoverageSummary();
                int numModules    = result.Modules.Count;

                var totalLinePercent   = summary.CalculateLineCoverage(result.Modules).Percent;
                var totalBranchPercent = summary.CalculateBranchCoverage(result.Modules).Percent;
                var totalMethodPercent = summary.CalculateMethodCoverage(result.Modules).Percent;

                foreach (var _module in result.Modules)
                {
                    var linePercent   = summary.CalculateLineCoverage(_module.Value).Percent;
                    var branchPercent = summary.CalculateBranchCoverage(_module.Value).Percent;
                    var methodPercent = summary.CalculateMethodCoverage(_module.Value).Percent;

                    coverageTable.AddRow(Path.GetFileNameWithoutExtension(_module.Key), $"{linePercent}%", $"{branchPercent}%", $"{methodPercent}%");
                }

                logger.LogInformation(coverageTable.ToStringAlternative());

                coverageTable.Columns.Clear();
                coverageTable.Rows.Clear();

                coverageTable.AddColumn(new[] { "", "Line", "Branch", "Method" });
                coverageTable.AddRow("Total", $"{totalLinePercent}%", $"{totalBranchPercent}%", $"{totalMethodPercent}%");
                coverageTable.AddRow("Average", $"{totalLinePercent / numModules}%", $"{totalBranchPercent / numModules}%", $"{totalMethodPercent / numModules}%");

                logger.LogInformation(coverageTable.ToStringAlternative());
                if (process.ExitCode > 0)
                {
                    exitCode += (int)CommandExitCodes.TestFailed;
                }
                thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, dThreshold, thresholdTypeFlags, dThresholdStat);
                if (thresholdTypeFlags != ThresholdTypeFlags.None)
                {
                    exitCode += (int)CommandExitCodes.CoverageBelowThreshold;
                    var exceptionMessageBuilder = new StringBuilder();
                    if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {dThresholdStat.ToString().ToLower()} line coverage is below the specified {dThreshold}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {dThresholdStat.ToString().ToLower()} branch coverage is below the specified {dThreshold}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {dThresholdStat.ToString().ToLower()} method coverage is below the specified {dThreshold}");
                    }

                    throw new Exception(exceptionMessageBuilder.ToString());
                }

                return(exitCode);
            });

            try
            {
                return(app.Execute(args));
            }
            catch (CommandParsingException ex)
            {
                logger.LogError(ex.Message);
                app.ShowHelp();
                return((int)CommandExitCodes.CommandParsingException);
            }
            catch (Exception ex)
            {
                logger.LogError(ex.Message);
                return(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception);
            }
        }
Exemplo n.º 16
0
        public string Report(CoverageResult result)
        {
            CoverageSummary summary = new CoverageSummary();

            var lineCoverage   = summary.CalculateLineCoverage(result.Modules);
            var branchCoverage = summary.CalculateBranchCoverage(result.Modules);

            XDocument xml      = new XDocument();
            XElement  coverage = new XElement("coverage");

            coverage.Add(new XAttribute("line-rate", (summary.CalculateLineCoverage(result.Modules).Percent / 100).ToString(CultureInfo.InvariantCulture)));
            coverage.Add(new XAttribute("branch-rate", (summary.CalculateBranchCoverage(result.Modules).Percent / 100).ToString(CultureInfo.InvariantCulture)));
            coverage.Add(new XAttribute("version", "1.9"));
            coverage.Add(new XAttribute("timestamp", (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds));

            XElement sources  = new XElement("sources");
            var      rootDirs = GetRootDirs(result.Modules, result.UseSourceLink).ToList();

            rootDirs.ForEach(x => sources.Add(new XElement("source", x)));

            XElement packages = new XElement("packages");

            foreach (var module in result.Modules)
            {
                XElement package = new XElement("package");
                package.Add(new XAttribute("name", Path.GetFileNameWithoutExtension(module.Key)));
                package.Add(new XAttribute("line-rate", (summary.CalculateLineCoverage(module.Value).Percent / 100).ToString(CultureInfo.InvariantCulture)));
                package.Add(new XAttribute("branch-rate", (summary.CalculateBranchCoverage(module.Value).Percent / 100).ToString(CultureInfo.InvariantCulture)));
                package.Add(new XAttribute("complexity", summary.CalculateCyclomaticComplexity(module.Value)));

                XElement classes = new XElement("classes");
                foreach (var document in module.Value)
                {
                    foreach (var cls in document.Value)
                    {
                        XElement @class = new XElement("class");
                        @class.Add(new XAttribute("name", cls.Key));
                        @class.Add(new XAttribute("filename", GetRelativePathFromBase(rootDirs, document.Key, result.UseSourceLink)));
                        @class.Add(new XAttribute("line-rate", (summary.CalculateLineCoverage(cls.Value).Percent / 100).ToString(CultureInfo.InvariantCulture)));
                        @class.Add(new XAttribute("branch-rate", (summary.CalculateBranchCoverage(cls.Value).Percent / 100).ToString(CultureInfo.InvariantCulture)));
                        @class.Add(new XAttribute("complexity", summary.CalculateCyclomaticComplexity(cls.Value)));

                        XElement classLines = new XElement("lines");
                        XElement methods    = new XElement("methods");

                        foreach (var meth in cls.Value)
                        {
                            // Skip all methods with no lines
                            if (meth.Value.Lines.Count == 0)
                            {
                                continue;
                            }

                            XElement method = new XElement("method");
                            method.Add(new XAttribute("name", meth.Key.Split(':').Last().Split('(').First()));
                            method.Add(new XAttribute("signature", "(" + meth.Key.Split(':').Last().Split('(').Last()));
                            method.Add(new XAttribute("line-rate", (summary.CalculateLineCoverage(meth.Value.Lines).Percent / 100).ToString(CultureInfo.InvariantCulture)));
                            method.Add(new XAttribute("branch-rate", (summary.CalculateBranchCoverage(meth.Value.Branches).Percent / 100).ToString(CultureInfo.InvariantCulture)));

                            XElement lines = new XElement("lines");
                            foreach (var ln in meth.Value.Lines)
                            {
                                bool     isBranchPoint = meth.Value.Branches.Any(b => b.Line == ln.Key);
                                XElement line          = new XElement("line");
                                line.Add(new XAttribute("number", ln.Key.ToString()));
                                line.Add(new XAttribute("hits", ln.Value.ToString()));
                                line.Add(new XAttribute("branch", isBranchPoint.ToString()));

                                if (isBranchPoint)
                                {
                                    var branches           = meth.Value.Branches.Where(b => b.Line == ln.Key).ToList();
                                    var branchInfoCoverage = summary.CalculateBranchCoverage(branches);
                                    line.Add(new XAttribute("condition-coverage", $"{branchInfoCoverage.Percent.ToString(CultureInfo.InvariantCulture)}% ({branchInfoCoverage.Covered.ToString(CultureInfo.InvariantCulture)}/{branchInfoCoverage.Total.ToString(CultureInfo.InvariantCulture)})"));
                                    XElement conditions = new XElement("conditions");
                                    var      byOffset   = branches.GroupBy(b => b.Offset).ToDictionary(b => b.Key, b => b.ToList());
                                    foreach (var entry in byOffset)
                                    {
                                        XElement condition = new XElement("condition");
                                        condition.Add(new XAttribute("number", entry.Key));
                                        condition.Add(new XAttribute("type", entry.Value.Count() > 2 ? "switch" : "jump")); // Just guessing here
                                        condition.Add(new XAttribute("coverage", $"{summary.CalculateBranchCoverage(entry.Value).Percent.ToString(CultureInfo.InvariantCulture)}%"));
                                        conditions.Add(condition);
                                    }

                                    line.Add(conditions);
                                }


                                lines.Add(line);
                                classLines.Add(line);
                            }

                            method.Add(lines);
                            methods.Add(method);
                        }

                        @class.Add(methods);
                        @class.Add(classLines);
                        classes.Add(@class);
                    }
                }

                package.Add(classes);
                packages.Add(package);
            }

            coverage.Add(new XAttribute("lines-covered", lineCoverage.Covered.ToString(CultureInfo.InvariantCulture)));
            coverage.Add(new XAttribute("lines-valid", lineCoverage.Total.ToString(CultureInfo.InvariantCulture)));
            coverage.Add(new XAttribute("branches-covered", branchCoverage.Covered.ToString(CultureInfo.InvariantCulture)));
            coverage.Add(new XAttribute("branches-valid", branchCoverage.Total.ToString(CultureInfo.InvariantCulture)));

            coverage.Add(sources);
            coverage.Add(packages);
            xml.Add(coverage);

            var stream = new MemoryStream();

            xml.Save(stream);

            return(Encoding.UTF8.GetString(stream.ToArray()));
        }
Exemplo n.º 17
0
        public string Report(CoverageResult result)
        {
            CoverageSummary summary = new CoverageSummary();

            int totalLines = 0, coveredLines = 0, totalBranches = 0, coveredBranches = 0;

            XDocument xml      = new XDocument();
            XElement  coverage = new XElement("coverage");

            coverage.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(result.Modules).ToString()));
            coverage.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(result.Modules).ToString()));
            coverage.Add(new XAttribute("version", "1.9"));
            coverage.Add(new XAttribute("timestamp", ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString()));

            XElement sources  = new XElement("sources");
            var      basePath = GetBasePath(result.Modules);

            sources.Add(new XElement("source", basePath));

            XElement packages = new XElement("packages");

            foreach (var module in result.Modules)
            {
                XElement package = new XElement("package");
                package.Add(new XAttribute("name", Path.GetFileNameWithoutExtension(module.Key)));
                package.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(module.Value).ToString()));
                package.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(module.Value).ToString()));
                package.Add(new XAttribute("complexity", "0"));

                XElement classes = new XElement("classes");
                foreach (var document in module.Value)
                {
                    foreach (var cls in document.Value)
                    {
                        XElement @class = new XElement("class");
                        @class.Add(new XAttribute("name", cls.Key));
                        @class.Add(new XAttribute("filename", GetRelativePathFromBase(basePath, document.Key)));
                        @class.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(cls.Value).ToString()));
                        @class.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(cls.Value).ToString()));
                        @class.Add(new XAttribute("complexity", "0"));

                        XElement classLines = new XElement("lines");
                        XElement methods    = new XElement("methods");

                        foreach (var meth in cls.Value)
                        {
                            XElement method = new XElement("method");
                            method.Add(new XAttribute("name", meth.Key.Split(':')[2].Split('(')[0]));
                            method.Add(new XAttribute("signature", "(" + meth.Key.Split(':')[2].Split('(')[1]));
                            method.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(meth.Value).ToString()));
                            method.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(meth.Value).ToString()));

                            XElement lines = new XElement("lines");
                            foreach (var ln in meth.Value)
                            {
                                XElement line = new XElement("line");
                                line.Add(new XAttribute("number", ln.Key.ToString()));
                                line.Add(new XAttribute("hits", ln.Value.Hits.ToString()));
                                line.Add(new XAttribute("branch", ln.Value.IsBranchPoint.ToString()));

                                totalLines++;
                                if (ln.Value.Hits > 0)
                                {
                                    coveredLines++;
                                }


                                if (ln.Value.IsBranchPoint)
                                {
                                    line.Add(new XAttribute("condition-coverage", "100% (1/1)"));
                                    XElement conditions = new XElement("conditions");
                                    XElement condition  = new XElement("condition");
                                    condition.Add(new XAttribute("number", "0"));
                                    condition.Add(new XAttribute("type", "jump"));
                                    condition.Add(new XAttribute("coverage", "100%"));

                                    totalBranches++;
                                    if (ln.Value.Hits > 0)
                                    {
                                        coveredBranches++;
                                    }

                                    conditions.Add(condition);
                                    line.Add(conditions);
                                }


                                lines.Add(line);
                                classLines.Add(line);
                            }

                            method.Add(lines);
                            methods.Add(method);
                        }

                        @class.Add(methods);
                        @class.Add(classLines);
                        classes.Add(@class);
                    }
                }

                package.Add(classes);
                packages.Add(package);
            }

            coverage.Add(new XAttribute("lines-covered", coveredLines.ToString()));
            coverage.Add(new XAttribute("lines-valid", totalLines.ToString()));
            coverage.Add(new XAttribute("branches-covered", coveredBranches.ToString()));
            coverage.Add(new XAttribute("branches-valid", totalBranches.ToString()));

            coverage.Add(sources);
            coverage.Add(packages);
            xml.Add(coverage);

            var stream = new MemoryStream();

            xml.Save(stream);

            return(Encoding.UTF8.GetString(stream.ToArray()));
        }
Exemplo n.º 18
0
        public string Report(CoverageResult result)
        {
            CoverageSummary summary = new CoverageSummary();

            XmlDocument xml      = new XmlDocument();
            XmlElement  coverage = xml.CreateElement("coverage");

            coverage.SetAttribute("line-rate", summary.CalculateLineCoverage(result.Modules).ToString());
            coverage.SetAttribute("branch-rate", summary.CalculateBranchCoverage(result.Modules).ToString());
            coverage.SetAttribute("version", "1.9");
            coverage.SetAttribute("timestamp", ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString());

            XmlElement sources = xml.CreateElement("sources");

            foreach (var src in GetSources(result.Modules))
            {
                XmlElement source = xml.CreateElement("source");
                source.AppendChild(xml.CreateTextNode(src));
                sources.AppendChild(source);
            }

            XmlElement packages = xml.CreateElement("packages");

            foreach (var module in result.Modules)
            {
                XmlElement package = xml.CreateElement("package");
                package.SetAttribute("line-rate", summary.CalculateLineCoverage(module.Value).ToString());
                package.SetAttribute("branch-rate", summary.CalculateBranchCoverage(module.Value).ToString());
                package.SetAttribute("complexity", "0");

                XmlElement classes = xml.CreateElement("classes");
                foreach (var document in module.Value)
                {
                    foreach (var cls in document.Value)
                    {
                        XmlElement @class = xml.CreateElement("class");
                        @class.SetAttribute("name", cls.Key);
                        @class.SetAttribute("filename", Path.GetFileName(document.Key));
                        @class.SetAttribute("line-rate", summary.CalculateLineCoverage(cls.Value).ToString());
                        @class.SetAttribute("branch-rate", summary.CalculateBranchCoverage(cls.Value).ToString());
                        @class.SetAttribute("complexity", "0");

                        XmlElement methods = xml.CreateElement("methods");
                        foreach (var meth in cls.Value)
                        {
                            XmlElement method = xml.CreateElement("method");
                            method.SetAttribute("name", meth.Key.Split(':')[2].Split('(')[0]);
                            method.SetAttribute("signature", meth.Key);
                            method.SetAttribute("line-rate", summary.CalculateLineCoverage(meth.Value).ToString());
                            method.SetAttribute("branch-rate", summary.CalculateBranchCoverage(meth.Value).ToString());

                            XmlElement lines = xml.CreateElement("lines");
                            foreach (var ln in meth.Value)
                            {
                                XmlElement line = xml.CreateElement("line");
                                line.SetAttribute("number", ln.Key.ToString());
                                line.SetAttribute("hits", ln.Value.Hits.ToString());
                                line.SetAttribute("branch", ln.Value.IsBranchPoint.ToString());

                                lines.AppendChild(line);
                            }

                            method.AppendChild(lines);
                            methods.AppendChild(method);
                        }

                        @class.AppendChild(methods);
                        classes.AppendChild(@class);
                    }
                }

                package.AppendChild(classes);
                packages.AppendChild(package);
            }

            coverage.AppendChild(sources);
            coverage.AppendChild(packages);
            xml.AppendChild(coverage);

            StringWriter writer = new StringWriter();

            xml.Save(writer);

            return(writer.ToString());
        }
Exemplo n.º 19
0
        static int Main(string[] args)
        {
            IServiceCollection serviceCollection = new ServiceCollection();

            serviceCollection.AddTransient <IRetryHelper, RetryHelper>();
            serviceCollection.AddTransient <IProcessExitHandler, ProcessExitHandler>();
            serviceCollection.AddTransient <IFileSystem, FileSystem>();
            serviceCollection.AddTransient <ILogger, ConsoleLogger>();
            // We need to keep singleton/static semantics
            serviceCollection.AddSingleton <IInstrumentationHelper, InstrumentationHelper>();
            serviceCollection.AddSingleton <ISourceRootTranslator, SourceRootTranslator>(provider => new SourceRootTranslator(provider.GetRequiredService <ILogger>(), provider.GetRequiredService <IFileSystem>()));
            serviceCollection.AddSingleton <ICecilSymbolHelper, CecilSymbolHelper>();

            ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();

            var logger     = (ConsoleLogger)serviceProvider.GetService <ILogger>();
            var fileSystem = serviceProvider.GetService <IFileSystem>();

            var app = new CommandLineApplication
            {
                Name     = "coverlet",
                FullName = "Cross platform .NET Core code coverage tool"
            };

            app.HelpOption("-h|--help");
            app.VersionOption("-v|--version", GetAssemblyVersion());
            int exitCode = (int)CommandExitCodes.Success;

            CommandArgument          moduleOrAppDirectory = app.Argument("<ASSEMBLY|DIRECTORY>", "Path to the test assembly or application directory.");
            CommandOption            target                  = app.Option("-t|--target", "Path to the test runner application.", CommandOptionType.SingleValue);
            CommandOption            targs                   = app.Option("-a|--targetargs", "Arguments to be passed to the test runner.", CommandOptionType.SingleValue);
            CommandOption            output                  = app.Option("-o|--output", "Output of the generated coverage report", CommandOptionType.SingleValue);
            CommandOption <LogLevel> verbosity               = app.Option <LogLevel>("-v|--verbosity", "Sets the verbosity level of the command. Allowed values are quiet, minimal, normal, detailed.", CommandOptionType.SingleValue);
            CommandOption            formats                 = app.Option("-f|--format", "Format of the generated coverage report.", CommandOptionType.MultipleValue);
            CommandOption            threshold               = app.Option("--threshold", "Exits with error if the coverage % is below value.", CommandOptionType.SingleValue);
            CommandOption            thresholdTypes          = app.Option("--threshold-type", "Coverage type to apply the threshold to.", CommandOptionType.MultipleValue);
            CommandOption            thresholdStat           = app.Option("--threshold-stat", "Coverage statistic used to enforce the threshold value.", CommandOptionType.SingleValue);
            CommandOption            excludeFilters          = app.Option("--exclude", "Filter expressions to exclude specific modules and types.", CommandOptionType.MultipleValue);
            CommandOption            includeFilters          = app.Option("--include", "Filter expressions to include only specific modules and types.", CommandOptionType.MultipleValue);
            CommandOption            excludedSourceFiles     = app.Option("--exclude-by-file", "Glob patterns specifying source files to exclude.", CommandOptionType.MultipleValue);
            CommandOption            includeDirectories      = app.Option("--include-directory", "Include directories containing additional assemblies to be instrumented.", CommandOptionType.MultipleValue);
            CommandOption            excludeAttributes       = app.Option("--exclude-by-attribute", "Attributes to exclude from code coverage.", CommandOptionType.MultipleValue);
            CommandOption            includeTestAssembly     = app.Option("--include-test-assembly", "Specifies whether to report code coverage of the test assembly.", CommandOptionType.NoValue);
            CommandOption            singleHit               = app.Option("--single-hit", "Specifies whether to limit code coverage hit reporting to a single hit for each location", CommandOptionType.NoValue);
            CommandOption            skipAutoProp            = app.Option("--skipautoprops", "Neither track nor record auto-implemented properties.", CommandOptionType.NoValue);
            CommandOption            mergeWith               = app.Option("--merge-with", "Path to existing coverage result to merge.", CommandOptionType.SingleValue);
            CommandOption            useSourceLink           = app.Option("--use-source-link", "Specifies whether to use SourceLink URIs in place of file system paths.", CommandOptionType.NoValue);
            CommandOption            doesNotReturnAttributes = app.Option("--does-not-return-attribute", "Attributes that mark methods that do not return.", CommandOptionType.MultipleValue);

            app.OnExecute(() =>
            {
                if (string.IsNullOrEmpty(moduleOrAppDirectory.Value) || string.IsNullOrWhiteSpace(moduleOrAppDirectory.Value))
                {
                    throw new CommandParsingException(app, "No test assembly or application directory specified.");
                }

                if (!target.HasValue())
                {
                    throw new CommandParsingException(app, "Target must be specified.");
                }

                if (verbosity.HasValue())
                {
                    // Adjust log level based on user input.
                    logger.Level = verbosity.ParsedValue;
                }

                CoverageParameters parameters = new()
                {
                    IncludeFilters          = includeFilters.Values.ToArray(),
                    IncludeDirectories      = includeDirectories.Values.ToArray(),
                    ExcludeFilters          = excludeFilters.Values.ToArray(),
                    ExcludedSourceFiles     = excludedSourceFiles.Values.ToArray(),
                    ExcludeAttributes       = excludeAttributes.Values.ToArray(),
                    IncludeTestAssembly     = includeTestAssembly.HasValue(),
                    SingleHit               = singleHit.HasValue(),
                    MergeWith               = mergeWith.Value(),
                    UseSourceLink           = useSourceLink.HasValue(),
                    SkipAutoProps           = skipAutoProp.HasValue(),
                    DoesNotReturnAttributes = doesNotReturnAttributes.Values.ToArray()
                };

                ISourceRootTranslator sourceRootTranslator = serviceProvider.GetRequiredService <ISourceRootTranslator>();

                Coverage coverage = new(moduleOrAppDirectory.Value,
                                        parameters,
                                        logger,
                                        serviceProvider.GetRequiredService <IInstrumentationHelper>(),
                                        fileSystem,
                                        sourceRootTranslator,
                                        serviceProvider.GetRequiredService <ICecilSymbolHelper>());
                coverage.PrepareModules();

                Process process                          = new();
                process.StartInfo.FileName               = target.Value();
                process.StartInfo.Arguments              = targs.HasValue() ? targs.Value() : string.Empty;
                process.StartInfo.CreateNoWindow         = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError  = true;
                process.OutputDataReceived              += (sender, eventArgs) =>
                {
                    if (!string.IsNullOrEmpty(eventArgs.Data))
                    {
                        logger.LogInformation(eventArgs.Data, important: true);
                    }
                };

                process.ErrorDataReceived += (sender, eventArgs) =>
                {
                    if (!string.IsNullOrEmpty(eventArgs.Data))
                    {
                        logger.LogError(eventArgs.Data);
                    }
                };

                process.Start();

                process.BeginErrorReadLine();
                process.BeginOutputReadLine();

                process.WaitForExit();

                var dOutput         = output.HasValue() ? output.Value() : Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar.ToString();
                var dThresholdTypes = thresholdTypes.HasValue() ? thresholdTypes.Values : new List <string>(new string[] { "line", "branch", "method" });
                var dThresholdStat  = thresholdStat.HasValue() ? Enum.Parse <ThresholdStatistic>(thresholdStat.Value(), true) : Enum.Parse <ThresholdStatistic>("minimum", true);

                logger.LogInformation("\nCalculating coverage result...");

                var result = coverage.GetCoverageResult();

                var directory = Path.GetDirectoryName(dOutput);
                if (directory == string.Empty)
                {
                    directory = Directory.GetCurrentDirectory();
                }
                else if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                foreach (var format in formats.HasValue() ? formats.Values : new List <string>(new string[] { "json" }))
                {
                    var reporter = new ReporterFactory(format).CreateReporter();
                    if (reporter == null)
                    {
                        throw new Exception($"Specified output format '{format}' is not supported");
                    }

                    if (reporter.OutputType == ReporterOutputType.Console)
                    {
                        // Output to console
                        logger.LogInformation("  Outputting results to console", important: true);
                        logger.LogInformation(reporter.Report(result, sourceRootTranslator), important: true);
                    }
                    else
                    {
                        // Output to file
                        var filename = Path.GetFileName(dOutput);
                        filename     = (filename == string.Empty) ? $"coverage.{reporter.Extension}" : filename;
                        filename     = Path.HasExtension(filename) ? filename : $"{filename}.{reporter.Extension}";

                        var report = Path.Combine(directory, filename);
                        logger.LogInformation($"  Generating report '{report}'", important: true);
                        fileSystem.WriteAllText(report, reporter.Report(result, sourceRootTranslator));
                    }
                }

                var thresholdTypeFlagQueue = new Queue <ThresholdTypeFlags>();

                foreach (var thresholdType in dThresholdTypes)
                {
                    if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Line);
                    }
                    else if (thresholdType.Equals("branch", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Branch);
                    }
                    else if (thresholdType.Equals("method", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Method);
                    }
                }

                Dictionary <ThresholdTypeFlags, double> thresholdTypeFlagValues = new Dictionary <ThresholdTypeFlags, double>();
                if (threshold.HasValue() && threshold.Value().Contains(','))
                {
                    var thresholdValues = threshold.Value().Split(',', StringSplitOptions.RemoveEmptyEntries).Select(t => t.Trim());
                    if (thresholdValues.Count() != thresholdTypeFlagQueue.Count())
                    {
                        throw new Exception($"Threshold type flag count ({thresholdTypeFlagQueue.Count()}) and values count ({thresholdValues.Count()}) doesn't match");
                    }

                    foreach (var thresholdValue in thresholdValues)
                    {
                        if (double.TryParse(thresholdValue, out var value))
                        {
                            thresholdTypeFlagValues[thresholdTypeFlagQueue.Dequeue()] = value;
                        }
                        else
                        {
                            throw new Exception($"Invalid threshold value must be numeric");
                        }
                    }
                }
                else
                {
                    double thresholdValue = threshold.HasValue() ? double.Parse(threshold.Value()) : 0;

                    while (thresholdTypeFlagQueue.Any())
                    {
                        thresholdTypeFlagValues[thresholdTypeFlagQueue.Dequeue()] = thresholdValue;
                    }
                }

                var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
                var summary       = new CoverageSummary();

                var linePercentCalculation   = summary.CalculateLineCoverage(result.Modules);
                var branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules);
                var methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules);

                var totalLinePercent   = linePercentCalculation.Percent;
                var totalBranchPercent = branchPercentCalculation.Percent;
                var totalMethodPercent = methodPercentCalculation.Percent;

                var averageLinePercent   = linePercentCalculation.AverageModulePercent;
                var averageBranchPercent = branchPercentCalculation.AverageModulePercent;
                var averageMethodPercent = methodPercentCalculation.AverageModulePercent;

                foreach (var _module in result.Modules)
                {
                    var linePercent   = summary.CalculateLineCoverage(_module.Value).Percent;
                    var branchPercent = summary.CalculateBranchCoverage(_module.Value).Percent;
                    var methodPercent = summary.CalculateMethodCoverage(_module.Value).Percent;

                    coverageTable.AddRow(Path.GetFileNameWithoutExtension(_module.Key), $"{InvariantFormat(linePercent)}%", $"{InvariantFormat(branchPercent)}%", $"{InvariantFormat(methodPercent)}%");
                }

                logger.LogInformation(coverageTable.ToStringAlternative());

                coverageTable.Columns.Clear();
                coverageTable.Rows.Clear();

                coverageTable.AddColumn(new[] { "", "Line", "Branch", "Method" });
                coverageTable.AddRow("Total", $"{InvariantFormat(totalLinePercent)}%", $"{InvariantFormat(totalBranchPercent)}%", $"{InvariantFormat(totalMethodPercent)}%");
                coverageTable.AddRow("Average", $"{InvariantFormat(averageLinePercent)}%", $"{InvariantFormat(averageBranchPercent)}%", $"{InvariantFormat(averageMethodPercent)}%");

                logger.LogInformation(coverageTable.ToStringAlternative());
                if (process.ExitCode > 0)
                {
                    exitCode += (int)CommandExitCodes.TestFailed;
                }

                var thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, thresholdTypeFlagValues, dThresholdStat);
                if (thresholdTypeFlags != ThresholdTypeFlags.None)
                {
                    exitCode += (int)CommandExitCodes.CoverageBelowThreshold;
                    var exceptionMessageBuilder = new StringBuilder();
                    if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {dThresholdStat.ToString().ToLower()} line coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Line]}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {dThresholdStat.ToString().ToLower()} branch coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Branch]}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {dThresholdStat.ToString().ToLower()} method coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Method]}");
                    }
                    throw new Exception(exceptionMessageBuilder.ToString());
                }

                return(exitCode);
            });

            try
            {
                return(app.Execute(args));
            }
            catch (CommandParsingException ex)
            {
                logger.LogError(ex.Message);
                app.ShowHelp();
                return((int)CommandExitCodes.CommandParsingException);
            }
            catch (Win32Exception we) when(we.Source == "System.Diagnostics.Process")
            {
                logger.LogError($"Start process '{target.Value()}' failed with '{we.Message}'");
                return(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception);
            }
            catch (Exception ex)
            {
                logger.LogError(ex.Message);
                return(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception);
            }
        }
Exemplo n.º 20
0
        public override bool Execute()
        {
            try
            {
                Console.WriteLine("\nCalculating coverage result...");

                var coverage = InstrumentationTask.Coverage;
                var result   = coverage.GetCoverageResult();

                var directory = Path.GetDirectoryName(_output);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                var formats = _format.Split(',');
                foreach (var format in formats)
                {
                    var reporter = new ReporterFactory(format).CreateReporter();
                    if (reporter == null)
                    {
                        throw new Exception($"Specified output format '{format}' is not supported");
                    }

                    var filename = Path.GetFileName(_output);
                    filename = (filename == string.Empty) ? $"coverage.{reporter.Extension}" : filename;

                    var report = Path.Combine(directory, filename);
                    Console.WriteLine($"  Generating report '{report}'");
                    File.WriteAllText(report, reporter.Report(result));
                }

                var thresholdFailed  = false;
                var thresholdTypes   = _thresholdType.Split(',').Select(t => t.Trim());
                var summary          = new CoverageSummary();
                var exceptionBuilder = new StringBuilder();
                var coverageTable    = new ConsoleTable("Module", "Line", "Branch", "Method");

                foreach (var module in result.Modules)
                {
                    var linePercent   = summary.CalculateLineCoverage(module.Value).Percent * 100;
                    var branchPercent = summary.CalculateBranchCoverage(module.Value).Percent * 100;
                    var methodPercent = summary.CalculateMethodCoverage(module.Value).Percent * 100;

                    coverageTable.AddRow(Path.GetFileNameWithoutExtension(module.Key), $"{linePercent}%", $"{branchPercent}%", $"{methodPercent}%");

                    if (_threshold > 0)
                    {
                        if (linePercent < _threshold && thresholdTypes.Contains("line"))
                        {
                            exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(module.Key)}' has a line coverage '{linePercent}%' below specified threshold '{_threshold}%'");
                            thresholdFailed = true;
                        }

                        if (branchPercent < _threshold && thresholdTypes.Contains("branch"))
                        {
                            exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(module.Key)}' has a branch coverage '{branchPercent}%' below specified threshold '{_threshold}%'");
                            thresholdFailed = true;
                        }

                        if (methodPercent < _threshold && thresholdTypes.Contains("method"))
                        {
                            exceptionBuilder.AppendLine($"'{Path.GetFileNameWithoutExtension(module.Key)}' has a method coverage '{methodPercent}%' below specified threshold '{_threshold}%'");
                            thresholdFailed = true;
                        }
                    }
                }

                Console.WriteLine();
                Console.WriteLine(coverageTable.ToStringAlternative());

                if (thresholdFailed)
                {
                    throw new Exception(exceptionBuilder.ToString().TrimEnd(Environment.NewLine.ToCharArray()));
                }
            }
            catch (Exception ex)
            {
                Log.LogErrorFromException(ex);
                return(false);
            }

            return(true);
        }
Exemplo n.º 21
0
        public string Report(CoverageResult result)
        {
            CoverageSummary summary = new CoverageSummary();

            var lineCoverage   = summary.CalculateLineCoverage(result.Modules);
            var branchCoverage = summary.CalculateBranchCoverage(result.Modules);

            XDocument xml      = new XDocument();
            XElement  coverage = new XElement("coverage");

            coverage.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(result.Modules).Percent.ToString()));
            coverage.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(result.Modules).Percent.ToString()));
            coverage.Add(new XAttribute("version", "1.9"));
            coverage.Add(new XAttribute("timestamp", ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString()));

            XElement sources  = new XElement("sources");
            var      basePath = GetBasePath(result.Modules);

            sources.Add(new XElement("source", basePath));

            XElement packages = new XElement("packages");

            foreach (var module in result.Modules)
            {
                XElement package = new XElement("package");
                package.Add(new XAttribute("name", Path.GetFileNameWithoutExtension(module.Key)));
                package.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(module.Value).Percent.ToString()));
                package.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(module.Value).Percent.ToString()));
                package.Add(new XAttribute("complexity", "0"));

                XElement classes = new XElement("classes");
                foreach (var document in module.Value)
                {
                    foreach (var cls in document.Value)
                    {
                        XElement @class = new XElement("class");
                        @class.Add(new XAttribute("name", cls.Key));
                        @class.Add(new XAttribute("filename", GetRelativePathFromBase(basePath, document.Key)));
                        @class.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(cls.Value).Percent.ToString()));
                        @class.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(cls.Value).Percent.ToString()));
                        @class.Add(new XAttribute("complexity", "0"));

                        XElement classLines = new XElement("lines");
                        XElement methods    = new XElement("methods");

                        foreach (var meth in cls.Value)
                        {
                            // Skip all methods with no lines
                            if (meth.Value.Lines.Count == 0)
                            {
                                continue;
                            }

                            XElement method = new XElement("method");
                            method.Add(new XAttribute("name", meth.Key.Split(':')[2].Split('(')[0]));
                            method.Add(new XAttribute("signature", "(" + meth.Key.Split(':')[2].Split('(')[1]));
                            method.Add(new XAttribute("line-rate", summary.CalculateLineCoverage(meth.Value.Lines).Percent.ToString()));
                            method.Add(new XAttribute("branch-rate", summary.CalculateBranchCoverage(meth.Value.Branches).Percent.ToString()));

                            XElement lines = new XElement("lines");
                            foreach (var ln in meth.Value.Lines)
                            {
                                XElement line = new XElement("line");
                                line.Add(new XAttribute("number", ln.Key.ToString()));
                                line.Add(new XAttribute("hits", ln.Value.Hits.ToString()));
                                line.Add(new XAttribute("branch", meth.Value.Branches.ContainsKey(ln.Key).ToString()));

                                if (meth.Value.Branches.TryGetValue(ln.Key, out List <BranchInfo> branches))
                                {
                                    var branchInfoCoverage = summary.CalculateBranchCoverage(branches);
                                    line.Add(new XAttribute("condition-coverage", $"{branchInfoCoverage.Percent*100}% ({branchInfoCoverage.Covered}/{branchInfoCoverage.Total})"));
                                    XElement conditions = new XElement("conditions");
                                    var      byOffset   = branches.GroupBy(b => b.Offset).ToDictionary(b => b.Key, b => b.ToList());
                                    foreach (var entry in byOffset)
                                    {
                                        XElement condition = new XElement("condition");
                                        condition.Add(new XAttribute("number", entry.Key));
                                        condition.Add(new XAttribute("type", entry.Value.Count() > 2 ? "switch" : "jump")); // Just guessing here
                                        condition.Add(new XAttribute("coverage", $"{summary.CalculateBranchCoverage(entry.Value).Percent * 100}%"));
                                        conditions.Add(condition);
                                    }

                                    line.Add(conditions);
                                }


                                lines.Add(line);
                                classLines.Add(line);
                            }

                            method.Add(lines);
                            methods.Add(method);
                        }

                        @class.Add(methods);
                        @class.Add(classLines);
                        classes.Add(@class);
                    }
                }

                package.Add(classes);
                packages.Add(package);
            }

            coverage.Add(new XAttribute("lines-covered", lineCoverage.Covered.ToString()));
            coverage.Add(new XAttribute("lines-valid", lineCoverage.Total.ToString()));
            coverage.Add(new XAttribute("branches-covered", branchCoverage.Covered.ToString()));
            coverage.Add(new XAttribute("branches-valid", branchCoverage.Total.ToString()));

            coverage.Add(sources);
            coverage.Add(packages);
            xml.Add(coverage);

            var stream = new MemoryStream();

            xml.Save(stream);

            return(Encoding.UTF8.GetString(stream.ToArray()));
        }
Exemplo n.º 22
0
        public string Report(CoverageResult result)
        {
            CoverageSummary summary         = new CoverageSummary();
            XmlDocument     xml             = new XmlDocument();
            XmlElement      coverage        = xml.CreateElement("CoverageSession");
            XmlElement      coverageSummary = xml.CreateElement("Summary");

            XmlElement modules = xml.CreateElement("Modules");

            int numSequencePoints = 0, numBranchPoints = 0, numClasses = 0, numMethods = 0;
            int visitedSequencePoints = 0, visitedBranchPoints = 0, visitedClasses = 0, visitedMethods = 0;

            int i = 1;

            foreach (var mod in result.Modules)
            {
                XmlElement module = xml.CreateElement("Module");
                module.SetAttribute("hash", Guid.NewGuid().ToString().ToUpper());

                XmlElement path = xml.CreateElement("ModulePath");
                path.AppendChild(xml.CreateTextNode(mod.Key));

                XmlElement time = xml.CreateElement("ModuleTime");
                time.AppendChild(xml.CreateTextNode(DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ss")));

                XmlElement name = xml.CreateElement("ModuleName");
                name.AppendChild(xml.CreateTextNode(Path.GetFileNameWithoutExtension(mod.Key)));

                module.AppendChild(path);
                module.AppendChild(time);
                module.AppendChild(name);

                XmlElement files   = xml.CreateElement("Files");
                XmlElement classes = xml.CreateElement("Classes");

                foreach (var doc in mod.Value)
                {
                    XmlElement file = xml.CreateElement("File");
                    file.SetAttribute("uid", i.ToString());
                    file.SetAttribute("fullPath", doc.Key);
                    files.AppendChild(file);

                    foreach (var cls in doc.Value)
                    {
                        XmlElement @class       = xml.CreateElement("Class");
                        XmlElement classSummary = xml.CreateElement("Summary");

                        XmlElement className = xml.CreateElement("FullName");
                        className.AppendChild(xml.CreateTextNode(cls.Key));

                        XmlElement methods      = xml.CreateElement("Methods");
                        int        j            = 0;
                        var        classVisited = false;

                        foreach (var meth in cls.Value)
                        {
                            XmlElement method = xml.CreateElement("Method");

                            method.SetAttribute("cyclomaticComplexity", "0");
                            method.SetAttribute("nPathComplexity", "0");
                            method.SetAttribute("sequenceCoverage", summary.CalculateLineCoverage(meth.Value).ToString());
                            method.SetAttribute("branchCoverage", summary.CalculateBranchCoverage(meth.Value).ToString());
                            method.SetAttribute("isConstructor", meth.Key.Contains("ctor").ToString());
                            method.SetAttribute("isGetter", meth.Key.Contains("get_").ToString());
                            method.SetAttribute("isSetter", meth.Key.Contains("set_").ToString());
                            method.SetAttribute("isStatic", (!meth.Key.Contains("get_") || !meth.Key.Contains("set_")).ToString());

                            XmlElement methodName = xml.CreateElement("Name");
                            methodName.AppendChild(xml.CreateTextNode(meth.Key));

                            XmlElement fileRef = xml.CreateElement("FileRef");
                            fileRef.SetAttribute("uid", i.ToString());

                            XmlElement methodPoint = xml.CreateElement("MethodPoint");
                            methodPoint.SetAttribute("vc", meth.Value.Select(l => l.Value.Hits).Sum().ToString());
                            methodPoint.SetAttribute("upsid", "0");
                            methodPoint.SetAttribute("type", "xsi", "SequencePoint");
                            methodPoint.SetAttribute("ordinal", j.ToString());
                            methodPoint.SetAttribute("offset", j.ToString());
                            methodPoint.SetAttribute("sc", "0");
                            methodPoint.SetAttribute("sl", meth.Value.First().Key.ToString());
                            methodPoint.SetAttribute("ec", "1");
                            methodPoint.SetAttribute("el", meth.Value.Last().Key.ToString());
                            methodPoint.SetAttribute("bec", "0");
                            methodPoint.SetAttribute("bev", "0");
                            methodPoint.SetAttribute("fileid", i.ToString());

                            // They're really just lines
                            XmlElement sequencePoints = xml.CreateElement("SequencePoints");
                            XmlElement branchPoints   = xml.CreateElement("BranchPoints");
                            XmlElement methodSummary  = xml.CreateElement("Summary");
                            int        k             = 0;
                            int        kBr           = 0;
                            var        methodVisited = false;

                            foreach (var lines in meth.Value)
                            {
                                XmlElement sequencePoint = xml.CreateElement("SequencePoint");
                                sequencePoint.SetAttribute("vc", lines.Value.Hits.ToString());
                                sequencePoint.SetAttribute("upsid", lines.Key.ToString());
                                sequencePoint.SetAttribute("ordinal", k.ToString());
                                sequencePoint.SetAttribute("sl", lines.Key.ToString());
                                sequencePoint.SetAttribute("sc", "1");
                                sequencePoint.SetAttribute("el", lines.Key.ToString());
                                sequencePoint.SetAttribute("ec", "2");
                                sequencePoint.SetAttribute("bec", "0");
                                sequencePoint.SetAttribute("bev", "0");
                                sequencePoint.SetAttribute("fileid", i.ToString());
                                sequencePoints.AppendChild(sequencePoint);

                                if (lines.Value.IsBranchPoint)
                                {
                                    XmlElement branchPoint = xml.CreateElement("BranchPoint");
                                    branchPoint.SetAttribute("vc", lines.Value.Hits.ToString());
                                    branchPoint.SetAttribute("upsid", lines.Key.ToString());
                                    branchPoint.SetAttribute("ordinal", kBr.ToString());
                                    branchPoint.SetAttribute("sl", lines.Key.ToString());
                                    branchPoint.SetAttribute("fileid", i.ToString());
                                    branchPoints.AppendChild(branchPoint);
                                    kBr++;
                                    numBranchPoints++;
                                }

                                numSequencePoints++;
                                if (lines.Value.Hits > 0)
                                {
                                    visitedSequencePoints++;
                                    classVisited  = true;
                                    methodVisited = true;
                                    if (lines.Value.IsBranchPoint)
                                    {
                                        visitedBranchPoints++;
                                    }
                                }

                                k++;
                            }

                            numMethods++;
                            if (methodVisited)
                            {
                                visitedMethods++;
                            }

                            methodSummary.SetAttribute("numSequencePoints", meth.Value.Count().ToString());
                            methodSummary.SetAttribute("visitedSequencePoints", meth.Value.Where(l => l.Value.Hits > 0).Count().ToString());
                            methodSummary.SetAttribute("numBranchPoints", meth.Value.Where(l => l.Value.IsBranchPoint).Count().ToString());
                            methodSummary.SetAttribute("visitedBranchPoints", meth.Value.Where(l => l.Value.IsBranchPoint && l.Value.Hits > 0).Count().ToString());
                            methodSummary.SetAttribute("sequenceCoverage", summary.CalculateLineCoverage(meth.Value).ToString());
                            methodSummary.SetAttribute("branchCoverage", summary.CalculateBranchCoverage(meth.Value).ToString());
                            methodSummary.SetAttribute("maxCyclomaticComplexity", "0");
                            methodSummary.SetAttribute("minCyclomaticComplexity", "0");
                            methodSummary.SetAttribute("visitedClasses", "0");
                            methodSummary.SetAttribute("numClasses", "0");
                            methodSummary.SetAttribute("visitedMethods", methodVisited ? "1" : "0");
                            methodSummary.SetAttribute("numMethods", "1");

                            method.AppendChild(methodSummary);
                            method.AppendChild(xml.CreateElement("MetadataToken"));
                            method.AppendChild(methodName);
                            method.AppendChild(fileRef);
                            method.AppendChild(sequencePoints);
                            method.AppendChild(branchPoints);
                            method.AppendChild(methodPoint);
                            methods.AppendChild(method);
                            j++;
                        }

                        numClasses++;
                        if (classVisited)
                        {
                            visitedClasses++;
                        }

                        classSummary.SetAttribute("numSequencePoints", cls.Value.Select(c => c.Value.Count).Sum().ToString());
                        classSummary.SetAttribute("visitedSequencePoints", cls.Value.Select(c => c.Value.Where(l => l.Value.Hits > 0).Count()).Sum().ToString());
                        classSummary.SetAttribute("numBranchPoints", cls.Value.Select(c => c.Value.Count(l => l.Value.IsBranchPoint)).Sum().ToString());
                        classSummary.SetAttribute("visitedBranchPoints", cls.Value.Select(c => c.Value.Where(l => l.Value.Hits > 0 && l.Value.IsBranchPoint).Count()).Sum().ToString());
                        classSummary.SetAttribute("sequenceCoverage", summary.CalculateLineCoverage(cls.Value).ToString());
                        classSummary.SetAttribute("branchCoverage", summary.CalculateBranchCoverage(cls.Value).ToString());
                        classSummary.SetAttribute("maxCyclomaticComplexity", "0");
                        classSummary.SetAttribute("minCyclomaticComplexity", "0");
                        classSummary.SetAttribute("visitedClasses", classVisited ? "1" : "0");
                        classSummary.SetAttribute("numClasses", "1");
                        classSummary.SetAttribute("visitedMethods", "0");
                        classSummary.SetAttribute("numMethods", cls.Value.Count.ToString());

                        @class.AppendChild(classSummary);
                        @class.AppendChild(className);
                        @class.AppendChild(methods);
                        classes.AppendChild(@class);
                    }
                    i++;
                }

                module.AppendChild(files);
                module.AppendChild(classes);
                modules.AppendChild(module);
            }

            coverageSummary.SetAttribute("numSequencePoints", numSequencePoints.ToString());
            coverageSummary.SetAttribute("visitedSequencePoints", visitedSequencePoints.ToString());
            coverageSummary.SetAttribute("numBranchPoints", numBranchPoints.ToString());
            coverageSummary.SetAttribute("visitedBranchPoints", visitedBranchPoints.ToString());
            coverageSummary.SetAttribute("sequenceCoverage", summary.CalculateLineCoverage(result.Modules).ToString());
            coverageSummary.SetAttribute("branchCoverage", summary.CalculateLineCoverage(result.Modules).ToString());
            coverageSummary.SetAttribute("maxCyclomaticComplexity", "0");
            coverageSummary.SetAttribute("minCyclomaticComplexity", "0");
            coverageSummary.SetAttribute("visitedClasses", visitedClasses.ToString());
            coverageSummary.SetAttribute("numClasses", numClasses.ToString());
            coverageSummary.SetAttribute("visitedMethods", visitedMethods.ToString());
            coverageSummary.SetAttribute("numMethods", numMethods.ToString());

            coverage.AppendChild(coverageSummary);
            coverage.AppendChild(modules);
            xml.AppendChild(coverage);

            Utf8StringWriter writer = new Utf8StringWriter();

            xml.Save(writer);

            return(writer.ToString());
        }
Exemplo n.º 23
0
        public override bool Execute()
        {
            try
            {
                Console.WriteLine("\nCalculating coverage result...");

                IFileSystem fileSystem = ServiceProvider.GetService <IFileSystem>();
                if (InstrumenterState is null || !fileSystem.Exists(InstrumenterState.ItemSpec))
                {
                    _logger.LogError("Result of instrumentation task not found");
                    return(false);
                }

                Coverage coverage = null;
                using (Stream instrumenterStateStream = fileSystem.NewFileStream(InstrumenterState.ItemSpec, FileMode.Open))
                {
                    var instrumentationHelper = ServiceProvider.GetService <IInstrumentationHelper>();
                    // Task.Log is teared down after a task and thus the new MSBuildLogger must be passed to the InstrumentationHelper
                    // https://github.com/microsoft/msbuild/issues/5153
                    instrumentationHelper.SetLogger(_logger);
                    coverage = new Coverage(CoveragePrepareResult.Deserialize(instrumenterStateStream), this._logger, ServiceProvider.GetService <IInstrumentationHelper>(), fileSystem, ServiceProvider.GetService <ISourceRootTranslator>());
                }

                try
                {
                    fileSystem.Delete(InstrumenterState.ItemSpec);
                }
                catch (Exception ex)
                {
                    // We don't want to block coverage for I/O errors
                    _logger.LogWarning($"Exception during instrument state deletion, file name '{InstrumenterState.ItemSpec}' exception message '{ex.Message}'");
                }

                CoverageResult result = coverage.GetCoverageResult();

                var directory = Path.GetDirectoryName(_output);
                if (directory == string.Empty)
                {
                    directory = Directory.GetCurrentDirectory();
                }
                else if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                var formats = _format.Split(',');
                foreach (var format in formats)
                {
                    var reporter = new ReporterFactory(format).CreateReporter();
                    if (reporter == null)
                    {
                        throw new Exception($"Specified output format '{format}' is not supported");
                    }

                    if (reporter.OutputType == ReporterOutputType.Console)
                    {
                        // Output to console
                        Console.WriteLine("  Outputting results to console");
                        Console.WriteLine(reporter.Report(result));
                    }
                    else
                    {
                        ReportWriter writer = new ReportWriter(_coverletMultiTargetFrameworksCurrentTFM,
                                                               directory,
                                                               _output,
                                                               reporter,
                                                               fileSystem,
                                                               ServiceProvider.GetService <IConsole>(),
                                                               result);
                        writer.WriteReport();
                    }
                }

                var thresholdTypeFlags = ThresholdTypeFlags.None;
                var thresholdStat      = ThresholdStatistic.Minimum;

                foreach (var thresholdType in _thresholdType.Split(',').Select(t => t.Trim()))
                {
                    if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Line;
                    }
                    else if (thresholdType.Equals("branch", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Branch;
                    }
                    else if (thresholdType.Equals("method", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Method;
                    }
                }

                if (_thresholdStat.Equals("average", StringComparison.OrdinalIgnoreCase))
                {
                    thresholdStat = ThresholdStatistic.Average;
                }
                else if (_thresholdStat.Equals("total", StringComparison.OrdinalIgnoreCase))
                {
                    thresholdStat = ThresholdStatistic.Total;
                }

                var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
                var summary       = new CoverageSummary();
                int numModules    = result.Modules.Count;

                var linePercentCalculation   = summary.CalculateLineCoverage(result.Modules);
                var branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules);
                var methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules);

                var totalLinePercent   = linePercentCalculation.Percent;
                var totalBranchPercent = branchPercentCalculation.Percent;
                var totalMethodPercent = methodPercentCalculation.Percent;

                var averageLinePercent   = linePercentCalculation.AverageModulePercent;
                var averageBranchPercent = branchPercentCalculation.AverageModulePercent;
                var averageMethodPercent = methodPercentCalculation.AverageModulePercent;

                foreach (var module in result.Modules)
                {
                    var linePercent   = summary.CalculateLineCoverage(module.Value).Percent;
                    var branchPercent = summary.CalculateBranchCoverage(module.Value).Percent;
                    var methodPercent = summary.CalculateMethodCoverage(module.Value).Percent;

                    coverageTable.AddRow(Path.GetFileNameWithoutExtension(module.Key), $"{linePercent}%", $"{branchPercent}%", $"{methodPercent}%");
                }

                Console.WriteLine();
                Console.WriteLine(coverageTable.ToStringAlternative());

                coverageTable.Columns.Clear();
                coverageTable.Rows.Clear();

                coverageTable.AddColumn(new[] { "", "Line", "Branch", "Method" });
                coverageTable.AddRow("Total", $"{totalLinePercent}%", $"{totalBranchPercent}%", $"{totalMethodPercent}%");
                coverageTable.AddRow("Average", $"{averageLinePercent}%", $"{averageBranchPercent}%", $"{averageMethodPercent}%");

                Console.WriteLine(coverageTable.ToStringAlternative());

                thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, _threshold, thresholdTypeFlags, thresholdStat);
                if (thresholdTypeFlags != ThresholdTypeFlags.None)
                {
                    var exceptionMessageBuilder = new StringBuilder();
                    if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {_threshold}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {_threshold}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {_threshold}");
                    }

                    throw new Exception(exceptionMessageBuilder.ToString());
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex);
                return(false);
            }

            return(true);
        }
Exemplo n.º 24
0
        public override bool Execute()
        {
            try
            {
                Console.WriteLine("\nCalculating coverage result...");

                IFileSystem fileSystem = ServiceProvider.GetService <IFileSystem>();
                if (InstrumenterState is null || !fileSystem.Exists(InstrumenterState.ItemSpec))
                {
                    _logger.LogError("Result of instrumentation task not found");
                    return(false);
                }

                Coverage coverage = null;
                using (Stream instrumenterStateStream = fileSystem.NewFileStream(InstrumenterState.ItemSpec, FileMode.Open))
                {
                    IInstrumentationHelper instrumentationHelper = ServiceProvider.GetService <IInstrumentationHelper>();
                    // Task.Log is teared down after a task and thus the new MSBuildLogger must be passed to the InstrumentationHelper
                    // https://github.com/microsoft/msbuild/issues/5153
                    instrumentationHelper.SetLogger(_logger);
                    coverage = new Coverage(CoveragePrepareResult.Deserialize(instrumenterStateStream), _logger, ServiceProvider.GetService <IInstrumentationHelper>(), fileSystem, ServiceProvider.GetService <ISourceRootTranslator>());
                }

                try
                {
                    fileSystem.Delete(InstrumenterState.ItemSpec);
                }
                catch (Exception ex)
                {
                    // We don't want to block coverage for I/O errors
                    _logger.LogWarning($"Exception during instrument state deletion, file name '{InstrumenterState.ItemSpec}' exception message '{ex.Message}'");
                }

                CoverageResult result = coverage.GetCoverageResult();

                string directory = Path.GetDirectoryName(Output);
                if (directory == string.Empty)
                {
                    directory = Directory.GetCurrentDirectory();
                }
                else if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                string[] formats             = OutputFormat.Split(',');
                var      coverageReportPaths = new List <ITaskItem>(formats.Length);
                ISourceRootTranslator sourceRootTranslator = ServiceProvider.GetService <ISourceRootTranslator>();
                foreach (string format in formats)
                {
                    IReporter reporter = new ReporterFactory(format).CreateReporter();
                    if (reporter == null)
                    {
                        throw new Exception($"Specified output format '{format}' is not supported");
                    }

                    if (reporter.OutputType == ReporterOutputType.Console)
                    {
                        // Output to console
                        Console.WriteLine("  Outputting results to console");
                        Console.WriteLine(reporter.Report(result, sourceRootTranslator));
                    }
                    else
                    {
                        ReportWriter writer = new(CoverletMultiTargetFrameworksCurrentTFM,
                                                  directory,
                                                  Output,
                                                  reporter,
                                                  fileSystem,
                                                  ServiceProvider.GetService <IConsole>(),
                                                  result,
                                                  sourceRootTranslator);
                        string path     = writer.WriteReport();
                        var    metadata = new Dictionary <string, string> {
                            ["Format"] = format
                        };
                        coverageReportPaths.Add(new TaskItem(path, metadata));
                    }
                }

                ReportItems = coverageReportPaths.ToArray();

                var thresholdTypeFlagQueue = new Queue <ThresholdTypeFlags>();

                foreach (string thresholdType in ThresholdType.Split(',').Select(t => t.Trim()))
                {
                    if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Line);
                    }
                    else if (thresholdType.Equals("branch", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Branch);
                    }
                    else if (thresholdType.Equals("method", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlagQueue.Enqueue(ThresholdTypeFlags.Method);
                    }
                }

                var thresholdTypeFlagValues = new Dictionary <ThresholdTypeFlags, double>();
                if (Threshold.Contains(','))
                {
                    IEnumerable <string> thresholdValues = Threshold.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(t => t.Trim());
                    if (thresholdValues.Count() != thresholdTypeFlagQueue.Count)
                    {
                        throw new Exception($"Threshold type flag count ({thresholdTypeFlagQueue.Count}) and values count ({thresholdValues.Count()}) doesn't match");
                    }

                    foreach (string threshold in thresholdValues)
                    {
                        if (double.TryParse(threshold, out double value))
                        {
                            thresholdTypeFlagValues[thresholdTypeFlagQueue.Dequeue()] = value;
                        }
                        else
                        {
                            throw new Exception($"Invalid threshold value must be numeric");
                        }
                    }
                }
                else
                {
                    double thresholdValue = double.Parse(Threshold);

                    while (thresholdTypeFlagQueue.Any())
                    {
                        thresholdTypeFlagValues[thresholdTypeFlagQueue.Dequeue()] = thresholdValue;
                    }
                }

                ThresholdStatistic thresholdStat = ThresholdStatistic.Minimum;
                if (ThresholdStat.Equals("average", StringComparison.OrdinalIgnoreCase))
                {
                    thresholdStat = ThresholdStatistic.Average;
                }
                else if (ThresholdStat.Equals("total", StringComparison.OrdinalIgnoreCase))
                {
                    thresholdStat = ThresholdStatistic.Total;
                }

                var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
                var summary       = new CoverageSummary();

                CoverageDetails linePercentCalculation   = summary.CalculateLineCoverage(result.Modules);
                CoverageDetails branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules);
                CoverageDetails methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules);

                double totalLinePercent   = linePercentCalculation.Percent;
                double totalBranchPercent = branchPercentCalculation.Percent;
                double totalMethodPercent = methodPercentCalculation.Percent;

                double averageLinePercent   = linePercentCalculation.AverageModulePercent;
                double averageBranchPercent = branchPercentCalculation.AverageModulePercent;
                double averageMethodPercent = methodPercentCalculation.AverageModulePercent;

                foreach (KeyValuePair <string, Documents> module in result.Modules)
                {
                    double linePercent   = summary.CalculateLineCoverage(module.Value).Percent;
                    double branchPercent = summary.CalculateBranchCoverage(module.Value).Percent;
                    double methodPercent = summary.CalculateMethodCoverage(module.Value).Percent;

                    coverageTable.AddRow(Path.GetFileNameWithoutExtension(module.Key), $"{InvariantFormat(linePercent)}%", $"{InvariantFormat(branchPercent)}%", $"{InvariantFormat(methodPercent)}%");
                }

                Console.WriteLine();
                Console.WriteLine(coverageTable.ToStringAlternative());

                coverageTable.Columns.Clear();
                coverageTable.Rows.Clear();

                coverageTable.AddColumn(new[] { "", "Line", "Branch", "Method" });
                coverageTable.AddRow("Total", $"{InvariantFormat(totalLinePercent)}%", $"{InvariantFormat(totalBranchPercent)}%", $"{InvariantFormat(totalMethodPercent)}%");
                coverageTable.AddRow("Average", $"{InvariantFormat(averageLinePercent)}%", $"{InvariantFormat(averageBranchPercent)}%", $"{InvariantFormat(averageMethodPercent)}%");

                Console.WriteLine(coverageTable.ToStringAlternative());

                ThresholdTypeFlags thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, thresholdTypeFlagValues, thresholdStat);
                if (thresholdTypeFlags != ThresholdTypeFlags.None)
                {
                    var exceptionMessageBuilder = new StringBuilder();
                    if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine(
                            $"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Line]}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine(
                            $"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Branch]}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine(
                            $"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Method]}");
                    }

                    throw new Exception(exceptionMessageBuilder.ToString());
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex);
                return(false);
            }

            return(true);
        }
Exemplo n.º 25
0
        public override bool Execute()
        {
            try
            {
                Console.WriteLine("\nCalculating coverage result...");

                if (InstrumenterState is null || !File.Exists(InstrumenterState.ItemSpec))
                {
                    _logger.LogError("Result of instrumentation task not found");
                    return(false);
                }

                var coverage = new Coverage(CoveragePrepareResult.Deserialize(new FileStream(InstrumenterState.ItemSpec, FileMode.Open)), this._logger);
                var result   = coverage.GetCoverageResult();

                var directory = Path.GetDirectoryName(_output);
                if (directory == string.Empty)
                {
                    directory = Directory.GetCurrentDirectory();
                }
                else if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                var formats = _format.Split(',');
                foreach (var format in formats)
                {
                    var reporter = new ReporterFactory(format).CreateReporter();
                    if (reporter == null)
                    {
                        throw new Exception($"Specified output format '{format}' is not supported");
                    }

                    if (reporter.OutputType == ReporterOutputType.Console)
                    {
                        // Output to console
                        Console.WriteLine("  Outputting results to console");
                        Console.WriteLine(reporter.Report(result));
                    }
                    else
                    {
                        // Output to file
                        var filename = Path.GetFileName(_output);
                        filename = (filename == string.Empty) ? $"coverage.{reporter.Extension}" : filename;
                        filename = Path.HasExtension(filename) ? filename : $"{filename}.{reporter.Extension}";

                        var report = Path.Combine(directory, filename);
                        Console.WriteLine($"  Generating report '{report}'");
                        File.WriteAllText(report, reporter.Report(result));
                    }
                }

                var thresholdTypeFlags = ThresholdTypeFlags.None;
                var thresholdStat      = ThresholdStatistic.Minimum;

                foreach (var thresholdType in _thresholdType.Split(',').Select(t => t.Trim()))
                {
                    if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Line;
                    }
                    else if (thresholdType.Equals("branch", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Branch;
                    }
                    else if (thresholdType.Equals("method", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Method;
                    }
                }

                if (_thresholdStat.Equals("average", StringComparison.OrdinalIgnoreCase))
                {
                    thresholdStat = ThresholdStatistic.Average;
                }
                else if (_thresholdStat.Equals("total", StringComparison.OrdinalIgnoreCase))
                {
                    thresholdStat = ThresholdStatistic.Total;
                }

                var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
                var summary       = new CoverageSummary();
                int numModules    = result.Modules.Count;

                var linePercentCalculation   = summary.CalculateLineCoverage(result.Modules);
                var branchPercentCalculation = summary.CalculateBranchCoverage(result.Modules);
                var methodPercentCalculation = summary.CalculateMethodCoverage(result.Modules);

                var totalLinePercent   = linePercentCalculation.Percent;
                var totalBranchPercent = branchPercentCalculation.Percent;
                var totalMethodPercent = methodPercentCalculation.Percent;

                var averageLinePercent   = linePercentCalculation.AverageModulePercent;
                var averageBranchPercent = branchPercentCalculation.AverageModulePercent;
                var averageMethodPercent = methodPercentCalculation.AverageModulePercent;

                foreach (var module in result.Modules)
                {
                    var linePercent   = summary.CalculateLineCoverage(module.Value).Percent;
                    var branchPercent = summary.CalculateBranchCoverage(module.Value).Percent;
                    var methodPercent = summary.CalculateMethodCoverage(module.Value).Percent;

                    coverageTable.AddRow(Path.GetFileNameWithoutExtension(module.Key), $"{linePercent}%", $"{branchPercent}%", $"{methodPercent}%");
                }

                Console.WriteLine();
                Console.WriteLine(coverageTable.ToStringAlternative());

                coverageTable.Columns.Clear();
                coverageTable.Rows.Clear();

                coverageTable.AddColumn(new[] { "", "Line", "Branch", "Method" });
                coverageTable.AddRow("Total", $"{totalLinePercent}%", $"{totalBranchPercent}%", $"{totalMethodPercent}%");
                coverageTable.AddRow("Average", $"{averageLinePercent}%", $"{averageBranchPercent}%", $"{averageMethodPercent}%");

                Console.WriteLine(coverageTable.ToStringAlternative());

                thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, _threshold, thresholdTypeFlags, thresholdStat);
                if (thresholdTypeFlags != ThresholdTypeFlags.None)
                {
                    var exceptionMessageBuilder = new StringBuilder();
                    if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {_threshold}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {_threshold}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {_threshold}");
                    }

                    throw new Exception(exceptionMessageBuilder.ToString());
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex);
                return(false);
            }

            return(true);
        }
Exemplo n.º 26
0
        public override bool Execute()
        {
            try
            {
                Console.WriteLine("\nCalculating coverage result...");

                var coverage = InstrumentationTask.Coverage;
                var result   = coverage.GetCoverageResult();

                var directory = Path.GetDirectoryName(_output);
                if (directory == string.Empty)
                {
                    directory = Directory.GetCurrentDirectory();
                }
                else if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                var formats = _format.Split(',');
                foreach (var format in formats)
                {
                    var reporter = new ReporterFactory(format).CreateReporter();
                    if (reporter == null)
                    {
                        throw new Exception($"Specified output format '{format}' is not supported");
                    }

                    if (reporter.OutputType == ReporterOutputType.Console)
                    {
                        // Output to console
                        Console.WriteLine("  Outputting results to console");
                        Console.WriteLine(reporter.Report(result));
                    }
                    else
                    {
                        // Output to file
                        var filename = Path.GetFileName(_output);
                        filename = (filename == string.Empty) ? $"coverage.{reporter.Extension}" : filename;
                        filename = Path.HasExtension(filename) ? filename : $"{filename}.{reporter.Extension}";

                        var report = Path.Combine(directory, filename);
                        Console.WriteLine($"  Generating report '{report}'");

                        var resultContent = reporter.Report(result);

                        // Possible concurrency access to merge file between write/read on parallel testing
                        RetryHelper.Retry(() =>
                        {
                            using (var file = File.Open(report, FileMode.Create, FileAccess.Write, FileShare.None))
                            {
                                using (var writer = new StreamWriter(file))
                                {
                                    writer.Write(resultContent);
                                }
                            }
                        }, () => TimeSpan.FromMilliseconds(100), 5);
                    }
                }

                var thresholdTypeFlags = ThresholdTypeFlags.None;
                var thresholdStat      = ThresholdStatistic.Minimum;

                foreach (var thresholdType in _thresholdType.Split(',').Select(t => t.Trim()))
                {
                    if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Line;
                    }
                    else if (thresholdType.Equals("branch", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Branch;
                    }
                    else if (thresholdType.Equals("method", StringComparison.OrdinalIgnoreCase))
                    {
                        thresholdTypeFlags |= ThresholdTypeFlags.Method;
                    }
                }

                if (_thresholdStat.Equals("average", StringComparison.OrdinalIgnoreCase))
                {
                    thresholdStat = ThresholdStatistic.Average;
                }
                else if (_thresholdStat.Equals("total", StringComparison.OrdinalIgnoreCase))
                {
                    thresholdStat = ThresholdStatistic.Total;
                }

                var coverageTable = new ConsoleTable("Module", "Line", "Branch", "Method");
                var summary       = new CoverageSummary();
                int numModules    = result.Modules.Count;

                var totalLinePercent   = summary.CalculateLineCoverage(result.Modules).Percent * 100;
                var totalBranchPercent = summary.CalculateBranchCoverage(result.Modules).Percent * 100;
                var totalMethodPercent = summary.CalculateMethodCoverage(result.Modules).Percent * 100;

                foreach (var module in result.Modules)
                {
                    var linePercent   = summary.CalculateLineCoverage(module.Value).Percent * 100;
                    var branchPercent = summary.CalculateBranchCoverage(module.Value).Percent * 100;
                    var methodPercent = summary.CalculateMethodCoverage(module.Value).Percent * 100;

                    coverageTable.AddRow(Path.GetFileNameWithoutExtension(module.Key), $"{linePercent}%", $"{branchPercent}%", $"{methodPercent}%");
                }

                Console.WriteLine();
                Console.WriteLine(coverageTable.ToStringAlternative());

                coverageTable.Columns.Clear();
                coverageTable.Rows.Clear();

                coverageTable.AddColumn(new[] { "", "Line", "Branch", "Method" });
                coverageTable.AddRow("Total", $"{totalLinePercent}%", $"{totalBranchPercent}%", $"{totalMethodPercent}%");
                coverageTable.AddRow("Average", $"{totalLinePercent / numModules}%", $"{totalBranchPercent / numModules}%", $"{totalMethodPercent / numModules}%");

                Console.WriteLine(coverageTable.ToStringAlternative());

                thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, _threshold, thresholdTypeFlags, thresholdStat);
                if (thresholdTypeFlags != ThresholdTypeFlags.None)
                {
                    var exceptionMessageBuilder = new StringBuilder();
                    if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {_threshold}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {_threshold}");
                    }

                    if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None)
                    {
                        exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {_threshold}");
                    }

                    throw new Exception(exceptionMessageBuilder.ToString());
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex);
                return(false);
            }

            return(true);
        }