/// <summary> /// Extracts the methods/properties of the given <see cref="XElement">XElements</see>. /// </summary> /// <param name="codeFile">The code file.</param> /// <param name="methodsOfFile">The methods of the file.</param> /// <param name="numberOrLines">The number of lines in the file.</param> private static void SetCodeElements(CodeFile codeFile, IEnumerable <XElement> methodsOfFile, int numberOrLines) { var codeElements = new List <CodeElementBase>(); foreach (var method in methodsOfFile) { var signature = method.Attribute("signature"); if (signature == null) { continue; } string methodName = signature.Value; int lineNumber = int.Parse(method.Attribute("num").Value, CultureInfo.InvariantCulture); codeElements.Add(new CodeElementBase(methodName, lineNumber)); var complexity = method.Attribute("complexity"); if (complexity != null) { var metrics = new List <Metric>() { new Metric( ReportResources.CyclomaticComplexity, ParserBase.CyclomaticComplexityUri, MetricType.CodeQuality, decimal.Parse(complexity.Value, CultureInfo.InvariantCulture), MetricMergeOrder.LowerIsBetter) }; var methodMetric = new MethodMetric(methodName, methodName, metrics) { Line = lineNumber }; codeFile.AddMethodMetric(methodMetric); } } for (int i = 0; i < codeElements.Count; i++) { var codeElement = codeElements[i]; int lastLine = numberOrLines; if (i < codeElements.Count - 1) { lastLine = codeElements[i + 1].FirstLine - 1; } codeFile.AddCodeElement(new CodeElement( codeElement.Name, CodeElementType.Method, codeElement.FirstLine, lastLine, codeFile.CoverageQuota(codeElement.FirstLine, lastLine))); } }
public void Merge_MergeOneMethodMetric_MethodMetricIsStored() { var sut = new CodeFile("C:\\temp\\Program.cs", new int[] { -1, -1, -1, 0, 0, 0, 1, 1, 1 }, new LineVisitStatus[] { LineVisitStatus.NotCoverable, LineVisitStatus.NotCoverable, LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered, LineVisitStatus.NotCovered, LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.Covered, LineVisitStatus.Covered }); var methodMetric = new MethodMetric("Test", "Test", Enumerable.Empty <Metric>()); sut.AddMethodMetric(methodMetric); var codeFileToMerge = new CodeFile("C:\\temp\\Program.cs", new int[] { -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1 }, new LineVisitStatus[] { LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered, LineVisitStatus.Covered }); sut.Merge(codeFileToMerge); Assert.Equal(methodMetric, sut.MethodMetrics.First()); Assert.Single(sut.MethodMetrics); }
/// <summary> /// Extracts the metrics from the given <see cref="XElement">XElements</see>. /// </summary> /// <param name="codeFile">The code file.</param> /// <param name="methodsOfFile">The methods of the file.</param> private static void SetMethodMetrics(CodeFile codeFile, IEnumerable <XElement> methodsOfFile) { foreach (var method in methodsOfFile) { string fullName = method.Element("MethodName").Value; // Exclude properties and lambda expressions if (fullName.StartsWith("get_", StringComparison.Ordinal) || fullName.StartsWith("set_", StringComparison.Ordinal) || lambdaMethodNameRegex.IsMatch(fullName)) { continue; } fullName = ExtractMethodName(fullName, method.Element("MethodKeyName").Value); string shortName = methodRegex.Replace(fullName, m => string.Format(CultureInfo.InvariantCulture, "{0}({1})", m.Groups["MethodName"].Value, m.Groups["Arguments"].Value.Length > 0 ? "..." : string.Empty)); var metrics = new[] { new Metric( ReportResources.BlocksCovered, ParserBase.CodeCoverageUri, MetricType.CoverageAbsolute, int.Parse(method.Element("BlocksCovered").Value, CultureInfo.InvariantCulture)), new Metric( ReportResources.BlocksNotCovered, ParserBase.CodeCoverageUri, MetricType.CoverageAbsolute, int.Parse(method.Element("BlocksNotCovered").Value, CultureInfo.InvariantCulture), MetricMergeOrder.LowerIsBetter) }; var methodMetric = new MethodMetric(fullName, shortName, metrics); var seqpnt = method .Elements("Lines") .Elements("LnStart") .FirstOrDefault(); if (seqpnt != null) { methodMetric.Line = int.Parse(seqpnt.Value, CultureInfo.InvariantCulture); } codeFile.AddMethodMetric(methodMetric); } }
/// <summary> /// Extracts the methods/properties of the given <see cref="XElement">XElements</see>. /// </summary> /// <param name="codeFile">The code file.</param> /// <param name="methodsOfFile">The methods of the file.</param> private static void SetCodeElements(CodeFile codeFile, IEnumerable <XElement> methodsOfFile) { foreach (var method in methodsOfFile) { var signature = method.Attribute("signature"); if (signature == null) { continue; } string methodName = signature.Value; int lineNumber = int.Parse(method.Attribute("num").Value, CultureInfo.InvariantCulture); codeFile.AddCodeElement(new CodeElement(methodName, CodeElementType.Method, lineNumber, lineNumber)); var complexity = method.Attribute("complexity"); if (complexity != null) { var metrics = new List <Metric>() { new Metric( ReportResources.CyclomaticComplexity, ParserBase.CyclomaticComplexityUri, MetricType.CodeQuality, decimal.Parse(complexity.Value, CultureInfo.InvariantCulture), MetricMergeOrder.LowerIsBetter) }; var methodMetric = new MethodMetric(methodName, methodName, metrics) { Line = lineNumber }; codeFile.AddMethodMetric(methodMetric); } } }
/// <summary> /// Extracts the metrics from the given <see cref="XElement">XElements</see>. /// </summary> /// <param name="codeFile">The code file.</param> /// <param name="methodsOfFile">The methods of the file.</param> private static void SetMethodMetrics(CodeFile codeFile, IEnumerable <XElement> methodsOfFile) { foreach (var method in methodsOfFile) { string fullName = method.Attribute("name").Value + method.Attribute("desc").Value; if (fullName.StartsWith("lambda$")) { continue; } string shortName = methodRegex.Replace(fullName, m => string.Format(CultureInfo.InvariantCulture, "{0}({1})", m.Groups["MethodName"].Value, m.Groups["Arguments"].Value.Length > 0 ? "..." : string.Empty)); var metrics = new List <Metric>(); var lineRate = method.Elements("counter") .Where(e => e.Attribute("type") != null && e.Attribute("type").Value == "LINE") .FirstOrDefault(); if (lineRate != null) { decimal missed = decimal.Parse(lineRate.Attribute("missed").Value, CultureInfo.InvariantCulture); decimal covered = decimal.Parse(lineRate.Attribute("covered").Value, CultureInfo.InvariantCulture); decimal total = missed + covered; metrics.Add(new Metric( ReportResources.Coverage, ParserBase.CodeCoverageUri, MetricType.CoveragePercentual, total == 0 ? (decimal?)null : Math.Round((100 * covered) / total, 2, MidpointRounding.AwayFromZero))); } else { // If no line rate available, do not add branch coverage too continue; } var branchRate = method.Elements("counter") .Where(e => e.Attribute("type") != null && e.Attribute("type").Value == "BRANCH") .FirstOrDefault(); if (branchRate != null) { decimal missed = decimal.Parse(branchRate.Attribute("missed").Value, CultureInfo.InvariantCulture); decimal covered = decimal.Parse(branchRate.Attribute("covered").Value, CultureInfo.InvariantCulture); decimal total = missed + covered; metrics.Add(new Metric( ReportResources.BranchCoverage, ParserBase.CodeCoverageUri, MetricType.CoveragePercentual, total == 0 ? (decimal?)null : Math.Round((100 * covered) / total, 2, MidpointRounding.AwayFromZero))); } else { // If no branch coverage is available, add default to avoid empty columns metrics.Add(new Metric( ReportResources.BranchCoverage, ParserBase.CodeCoverageUri, MetricType.CoveragePercentual, null)); } var methodMetric = new MethodMetric(fullName, shortName, metrics); methodMetric.Line = method.Attribute("line") != null?int.Parse(method.Attribute("line").Value, CultureInfo.InvariantCulture) : default(int?); codeFile.AddMethodMetric(methodMetric); } }
/// <summary> /// Extracts the metrics from the given <see cref="XElement">XElements</see>. /// </summary> /// <param name="codeFile">The code file.</param> /// <param name="methodsOfFile">The methods of the file.</param> private static void SetMethodMetrics(CodeFile codeFile, IEnumerable <XElement> methodsOfFile) { foreach (var method in methodsOfFile) { string fullName = method.Attribute("name").Value + method.Attribute("signature").Value; fullName = ExtractMethodName(fullName, method.Parent.Parent.Attribute("name").Value); if (fullName.Contains("__") && lambdaMethodNameRegex.IsMatch(fullName)) { continue; } string shortName = GetShortMethodName(fullName); var metrics = new List <Metric>(); var lineRate = method.Attribute("line-rate"); if (lineRate != null) { decimal?value = null; if (!"NaN".Equals(lineRate.Value, StringComparison.OrdinalIgnoreCase)) { value = Math.Round(100 * decimal.Parse(lineRate.Value, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture), 2, MidpointRounding.AwayFromZero); } metrics.Add(new Metric( ReportResources.Coverage, ParserBase.CodeCoverageUri, MetricType.CoveragePercentual, value)); } var branchRate = method.Attribute("branch-rate"); if (branchRate != null) { decimal?value = null; if (!"NaN".Equals(branchRate.Value, StringComparison.OrdinalIgnoreCase)) { value = Math.Round(100 * decimal.Parse(branchRate.Value, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture), 2, MidpointRounding.AwayFromZero); } metrics.Add(new Metric( ReportResources.BranchCoverage, ParserBase.CodeCoverageUri, MetricType.CoveragePercentual, value)); } var cyclomaticComplexityAttribute = method.Attribute("complexity"); if (cyclomaticComplexityAttribute != null) { decimal?value = null; if (!"NaN".Equals(cyclomaticComplexityAttribute.Value, StringComparison.OrdinalIgnoreCase)) { value = Math.Round(decimal.Parse(cyclomaticComplexityAttribute.Value, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture), 2, MidpointRounding.AwayFromZero); } metrics.Insert( 0, new Metric( ReportResources.CyclomaticComplexity, ParserBase.CyclomaticComplexityUri, MetricType.CodeQuality, value, MetricMergeOrder.LowerIsBetter)); } var methodMetric = new MethodMetric(fullName, shortName, metrics); var line = method .Elements("lines") .Elements("line") .FirstOrDefault(); if (line != null) { methodMetric.Line = int.Parse(line.Attribute("number").Value, CultureInfo.InvariantCulture); } codeFile.AddMethodMetric(methodMetric); } }
/// <summary> /// Extracts the metrics from the given <see cref="XElement">XElements</see>. /// </summary> /// <param name="codeFile">The code file.</param> /// <param name="methodsOfFile">The methods of the file.</param> private static void SetMethodMetrics(CodeFile codeFile, IEnumerable <XElement> methodsOfFile) { foreach (var method in methodsOfFile) { string fullName = method.Attribute("name").Value + method.Attribute("signature").Value; fullName = ExtractMethodName(fullName, method.Parent.Parent.Attribute("name").Value); if (lambdaMethodNameRegex.IsMatch(fullName)) { continue; } string shortName = methodRegex.Replace(fullName, m => string.Format(CultureInfo.InvariantCulture, "{0}({1})", m.Groups["MethodName"].Value, m.Groups["Arguments"].Value.Length > 0 ? "..." : string.Empty)); var metrics = new List <Metric>(); var lineRate = method.Attribute("line-rate"); if (lineRate != null) { decimal?value = null; if (!"NaN".Equals(lineRate.Value, StringComparison.OrdinalIgnoreCase)) { value = Math.Round(100 * decimal.Parse(lineRate.Value, CultureInfo.InvariantCulture), 2, MidpointRounding.AwayFromZero); } metrics.Add(new Metric( ReportResources.Coverage, ParserBase.CodeCoverageUri, MetricType.CoveragePercentual, value)); } var branchRate = method.Attribute("branch-rate"); if (branchRate != null) { decimal?value = null; if (!"NaN".Equals(branchRate.Value, StringComparison.OrdinalIgnoreCase)) { value = Math.Round(100 * decimal.Parse(branchRate.Value, CultureInfo.InvariantCulture), 2, MidpointRounding.AwayFromZero); } metrics.Add(new Metric( ReportResources.BranchCoverage, ParserBase.CodeCoverageUri, MetricType.CoveragePercentual, value)); } var cyclomaticComplexityAttribute = method.Attribute("complexity"); if (cyclomaticComplexityAttribute != null) { decimal?value = null; if (!"NaN".Equals(cyclomaticComplexityAttribute.Value, StringComparison.OrdinalIgnoreCase)) { value = Math.Round(decimal.Parse(cyclomaticComplexityAttribute.Value, CultureInfo.InvariantCulture), 2, MidpointRounding.AwayFromZero); } metrics.Insert( 0, new Metric( ReportResources.CyclomaticComplexity, ParserBase.CyclomaticComplexityUri, MetricType.CodeQuality, value)); } var methodMetric = new MethodMetric(fullName, shortName, metrics); var line = method .Elements("lines") .Elements("line") .FirstOrDefault(); if (line != null) { methodMetric.Line = int.Parse(line.Attribute("number").Value, CultureInfo.InvariantCulture); } /* If cobertura file is merged from different files, a class and therefore method can exist several times. * The first result is used. */ if (codeFile.MethodMetrics.Any(m => m.Equals(methodMetric))) { continue; } codeFile.AddMethodMetric(methodMetric); } }
/// <summary> /// Extracts the metrics from the given <see cref="XElement">XElements</see>. /// </summary> /// <param name="codeFile">The code file.</param> /// <param name="methodsOfFile">The methods of the file.</param> private static void SetMethodMetrics(CodeFile codeFile, IEnumerable <XElement> methodsOfFile) { foreach (var methodGroup in methodsOfFile.GroupBy(m => m.Element("Name").Value)) { var method = methodGroup.First(); // Exclude properties and lambda expressions if (method.Attribute("skippedDueTo") != null || method.HasAttributeWithValue("isGetter", "true") || method.HasAttributeWithValue("isSetter", "true") || lambdaMethodNameRegex.IsMatch(methodGroup.Key)) { continue; } var metrics = new List <Metric>() { new Metric( ReportResources.CyclomaticComplexity, ParserBase.CyclomaticComplexityUri, MetricType.CodeQuality, methodGroup.Max(m => int.Parse(m.Attribute("cyclomaticComplexity").Value, CultureInfo.InvariantCulture))), new Metric( ReportResources.SequenceCoverage, ParserBase.CodeCoverageUri, MetricType.CoveragePercentual, methodGroup.Max(m => decimal.Parse(m.Attribute("sequenceCoverage").Value, CultureInfo.InvariantCulture))), new Metric( ReportResources.BranchCoverage, ParserBase.CodeCoverageUri, MetricType.CoveragePercentual, methodGroup.Max(m => decimal.Parse(m.Attribute("branchCoverage").Value, CultureInfo.InvariantCulture))) }; var npathComplexityAttributes = methodGroup.Select(m => m.Attribute("nPathComplexity")).Where(a => a != null).ToArray(); if (npathComplexityAttributes.Length > 0) { metrics.Insert( 1, new Metric( ReportResources.NPathComplexity, ParserBase.NPathComplexityUri, MetricType.CodeQuality, npathComplexityAttributes .Select(a => int.Parse(a.Value, CultureInfo.InvariantCulture)) .Max(a => a < 0 ? int.MaxValue : a))); } var crapScoreAttributes = methodGroup.Select(m => m.Attribute("crapScore")).Where(a => a != null).ToArray(); if (crapScoreAttributes.Length > 0) { metrics.Add(new Metric( ReportResources.CrapScore, ParserBase.CrapScoreUri, MetricType.CodeQuality, crapScoreAttributes.Max(a => decimal.Parse(a.Value, CultureInfo.InvariantCulture)))); } string fullName = ExtractMethodName(methodGroup.Key); string shortName = methodRegex.Replace(fullName, m => string.Format(CultureInfo.InvariantCulture, "{0}({1})", m.Groups["MethodName"].Value, m.Groups["Arguments"].Value.Length > 0 ? "..." : string.Empty)); var methodMetric = new MethodMetric(fullName, shortName, metrics); var seqpnt = method .Elements("SequencePoints") .Elements("SequencePoint") .FirstOrDefault(); if (seqpnt != null) { methodMetric.Line = int.Parse(seqpnt.Attribute("sl").Value, CultureInfo.InvariantCulture); } codeFile.AddMethodMetric(methodMetric); } }