/// <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) { string methodName = method.Attribute("name").Value + method.Attribute("signature").Value; methodName = ExtractMethodName(methodName, method.Parent.Parent.Attribute("name").Value); if (methodName.Contains("__") && lambdaMethodNameRegex.IsMatch(methodName)) { continue; } methodName = GetShortMethodName(methodName); var lines = method.Elements("lines") .Elements("line"); if (lines.Any()) { int firstLine = int.Parse(lines.First().Attribute("number").Value, CultureInfo.InvariantCulture); int lastLine = int.Parse(lines.Last().Attribute("number").Value, CultureInfo.InvariantCulture); codeFile.AddCodeElement(new CodeElement( methodName, CodeElementType.Method, firstLine, lastLine, codeFile.CoverageQuota(firstLine, lastLine))); } } }
/// <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))); } }
/// <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) { if (method.Attribute("skippedDueTo") != null || lambdaMethodNameRegex.IsMatch(method.Element("Name").Value)) { continue; } string methodName = ExtractMethodName(method.Element("Name").Value); methodName = methodName.Substring(methodName.LastIndexOf(':') + 1); CodeElementType type = CodeElementType.Method; if (method.HasAttributeWithValue("isGetter", "true") || method.HasAttributeWithValue("isSetter", "true")) { type = CodeElementType.Property; methodName = methodName.Substring(4); } var seqpnts = method .Elements("SequencePoints") .Elements("SequencePoint") .Select(seqpnt => new { LineNumberStart = int.Parse(seqpnt.Attribute("sl").Value, CultureInfo.InvariantCulture), LineNumberEnd = seqpnt.Attribute("el") != null ? int.Parse(seqpnt.Attribute("el").Value, CultureInfo.InvariantCulture) : int.Parse(seqpnt.Attribute("sl").Value, CultureInfo.InvariantCulture) }) .ToArray(); if (seqpnts.Length > 0) { int firstLine = seqpnts.Min(s => s.LineNumberStart); int lastLine = seqpnts.Max(s => s.LineNumberEnd); codeFile.AddCodeElement(new CodeElement( methodName, type, firstLine, lastLine, codeFile.CoverageQuota(firstLine, lastLine))); } } }
/// <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) { if (lambdaMethodNameRegex.IsMatch(method.Attribute("name").Value)) { continue; } string methodName = ExtractMethodName(method.Attribute("name").Value, method.Attribute("type_name").Value); CodeElementType type = CodeElementType.Method; if (methodName.StartsWith("get_", StringComparison.OrdinalIgnoreCase) || methodName.StartsWith("set_", StringComparison.OrdinalIgnoreCase)) { type = CodeElementType.Property; methodName = methodName.Substring(4); } var seqpnts = method .Elements("ranges") .Elements("range") .Where(l => l.Attribute("start_line").Value != "15732480") .Select(l => new { LineNumberStart = int.Parse(l.Attribute("start_line").Value, CultureInfo.InvariantCulture), LineNumberEnd = int.Parse(l.Attribute("end_line").Value, CultureInfo.InvariantCulture) }) .ToArray(); if (seqpnts.Length > 0) { int firstLine = seqpnts.Min(s => s.LineNumberStart); int lastLine = seqpnts.Max(s => s.LineNumberEnd); codeFile.AddCodeElement(new CodeElement( methodName, type, firstLine, lastLine, codeFile.CoverageQuota(firstLine, lastLine))); } } }
/// <summary> /// Extracts the methods/properties of the given <see cref="XElement">XElements</see>. /// </summary> /// <param name="codeFile">The code file.</param> /// <param name="fileId">The id of the file.</param> /// <param name="methods">The methods.</param> private static void SetCodeElements(CodeFile codeFile, string fileId, IEnumerable <XElement> methods) { foreach (var method in methods) { string methodName = ExtractMethodName(method.Parent.Attribute("Name").Value, method.Attribute("Name").Value); if (lambdaMethodNameRegex.IsMatch(methodName)) { continue; } CodeElementType type = CodeElementType.Method; if (methodName.StartsWith("get_", StringComparison.OrdinalIgnoreCase) || methodName.StartsWith("set_", StringComparison.OrdinalIgnoreCase)) { type = CodeElementType.Property; methodName = methodName.Substring(4); } var seqpnts = method .Elements("Statement") .Where(c => c.Attribute("FileIndex").Value == fileId) .Select(c => new { LineNumberStart = int.Parse(c.Attribute("Line").Value, CultureInfo.InvariantCulture), LineNumberEnd = int.Parse(c.Attribute("EndLine").Value, CultureInfo.InvariantCulture) }) .ToArray(); if (seqpnts.Length > 0) { int firstLine = seqpnts.Min(s => s.LineNumberStart); int lastLine = seqpnts.Max(s => s.LineNumberEnd); codeFile.AddCodeElement(new CodeElement( methodName, type, seqpnts.Min(s => s.LineNumberStart), seqpnts.Max(s => s.LineNumberEnd), codeFile.CoverageQuota(firstLine, lastLine))); } } }
/// <summary> /// Extracts the methods/properties of the given <see cref="XElement">XElements</see>. /// </summary> /// <param name="codeFile">The code file.</param> /// <param name="methodsOfClass">The methods of the class.</param> private static void SetCodeElements(CodeFile codeFile, IEnumerable <XElement> methodsOfClass) { foreach (var method in methodsOfClass) { string methodName = method.Attribute("name").Value; if (lambdaMethodNameRegex.IsMatch(methodName)) { continue; } CodeElementType type = CodeElementType.Method; if (methodName.StartsWith("get_", StringComparison.OrdinalIgnoreCase) || methodName.StartsWith("set_", StringComparison.OrdinalIgnoreCase)) { type = CodeElementType.Property; methodName = methodName.Substring(4); } var seqpnts = method .Elements("seqpnt") .Where(seqpnt => seqpnt.Attribute("document").Value.Equals(codeFile.Path) && seqpnt.Attribute("line").Value != "16707566") .Select(seqpnt => new { LineNumberStart = int.Parse(seqpnt.Attribute("line").Value, CultureInfo.InvariantCulture), LineNumberEnd = int.Parse(seqpnt.Attribute("endline").Value, CultureInfo.InvariantCulture) }) .ToArray(); if (seqpnts.Length > 0) { int firstLine = seqpnts.Min(s => s.LineNumberStart); int lastLine = seqpnts.Max(s => s.LineNumberEnd); codeFile.AddCodeElement(new CodeElement( methodName, type, firstLine, lastLine, codeFile.CoverageQuota(firstLine, lastLine))); } } }
/// <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) { string methodName = method.Attribute("name").Value + method.Attribute("desc").Value; if (methodName.StartsWith("lambda$")) { continue; } methodName = methodRegex.Replace(methodName, m => string.Format(CultureInfo.InvariantCulture, "{0}({1})", m.Groups["MethodName"].Value, m.Groups["Arguments"].Value)); int lineNumber = int.Parse(method.Attribute("line")?.Value ?? "0", CultureInfo.InvariantCulture); codeElements.Add(new CodeElementBase(methodName, lineNumber)); } codeElements.Sort((x, y) => x.FirstLine.CompareTo(y.FirstLine)); 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))); } }
/// <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) { string methodName = method.Attribute("name").Value; if (lambdaMethodNameRegex.IsMatch(methodName)) { continue; } CodeElementType type = CodeElementType.Method; if (methodName.StartsWith("get_", StringComparison.OrdinalIgnoreCase) || methodName.StartsWith("set_", StringComparison.OrdinalIgnoreCase)) { type = CodeElementType.Property; methodName = methodName.Substring(4); } var lineNumbers = method .Elements("statement") .Select(l => int.Parse(l.Attribute("line").Value, CultureInfo.InvariantCulture)) .ToArray(); if (lineNumbers.Length > 0) { int firstLine = lineNumbers.Min(); int lastLine = lineNumbers.Max(); codeFile.AddCodeElement(new CodeElement( methodName, type, firstLine, lastLine, codeFile.CoverageQuota(firstLine, lastLine))); } } }
private void ProcessCoverage(Class @class, string fileName, string[] lines) { var codeElements = new List <CodeElementBase>(); int maxiumLineNumber = -1; var visitsByLine = new Dictionary <int, int>(); var branchesByLineNumber = new Dictionary <int, ICollection <Branch> >(); foreach (var line in lines) { var match = lineCoverageRegex.Match(line); if (match.Success) { int lineNumber = int.Parse(match.Groups["LineNumber"].Value, CultureInfo.InvariantCulture); maxiumLineNumber = Math.Max(maxiumLineNumber, lineNumber); string visitsText = match.Groups["Visits"].Value; if (visitsText != "-") { int visits = 0; if (visitsText != "#####" && visitsText != "=====") { visits = visitsText.ParseLargeInteger(); } if (visitsByLine.ContainsKey(lineNumber)) { visitsByLine[lineNumber] += visits; } else { visitsByLine[lineNumber] = visits; } } } else { match = branchCoverageRegex.Match(line); if (match.Success) { var branch = new Branch( match.Groups["Visits"].Success ? match.Groups["Visits"].Value.ParseLargeInteger() : 0, match.Groups["Number"].Value); ICollection <Branch> branches = null; if (branchesByLineNumber.TryGetValue(maxiumLineNumber, out branches)) { HashSet <Branch> branchesHashset = (HashSet <Branch>)branches; if (branchesHashset.Contains(branch)) { // Not perfect for performance, but Hashset has no GetElement method branchesHashset.First(b => b.Equals(branch)).BranchVisits += branch.BranchVisits; } else { branches.Add(branch); } } else { branches = new HashSet <Branch>(); branches.Add(branch); branchesByLineNumber.Add(maxiumLineNumber, branches); } } else if (line.StartsWith("function ")) { string name = line.Substring(9, line.IndexOf(' ', 9) - 9); codeElements.Add(new CodeElementBase(name, maxiumLineNumber + 1)); } } } int[] coverage = new int[maxiumLineNumber + 1]; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[maxiumLineNumber + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var kv in visitsByLine) { coverage[kv.Key] = kv.Value; if (lineVisitStatus[kv.Key] != LineVisitStatus.Covered) { bool partiallyCovered = false; ICollection <Branch> branchesOfLine = null; if (branchesByLineNumber.TryGetValue(kv.Key, out branchesOfLine)) { partiallyCovered = branchesOfLine.Any(b => b.BranchVisits == 0); } LineVisitStatus statusOfLine = kv.Value > 0 ? (partiallyCovered ? LineVisitStatus.PartiallyCovered : LineVisitStatus.Covered) : LineVisitStatus.NotCovered; lineVisitStatus[kv.Key] = (LineVisitStatus)Math.Max((int)lineVisitStatus[kv.Key], (int)statusOfLine); } } var codeFile = new CodeFile(fileName, coverage, lineVisitStatus, branchesByLineNumber); for (int i = 0; i < codeElements.Count; i++) { var codeElement = codeElements[i]; int lastLine = maxiumLineNumber; 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))); } @class.AddFile(codeFile); }
private void ProcessClass(Class @class, string fileName, string[] lines, ref int currentLine) { var codeElements = new List <CodeElementBase>(); int maxiumLineNumber = -1; var visitsByLine = new Dictionary <int, int>(); var branchesByLineNumber = new Dictionary <int, ICollection <Branch> >(); while (true) { string line = lines[currentLine]; if (line == "end_of_record") { break; } currentLine++; if (line.StartsWith("FN:")) { line = line.Substring(3); int lineNumber = int.Parse(line.Substring(0, line.IndexOf(',')), CultureInfo.InvariantCulture); string name = line.Substring(line.IndexOf(',') + 1); codeElements.Add(new CodeElementBase(name, lineNumber)); } else if (line.StartsWith("BRDA:")) { line = line.Substring(5); string[] tokens = line.Split(','); int lineNumber = int.Parse(tokens[0], CultureInfo.InvariantCulture); var branch = new Branch( "-".Equals(tokens[3]) ? 0 : int.Parse(tokens[3], CultureInfo.InvariantCulture), $"{tokens[0]}_{tokens[1]}_{tokens[2]}"); ICollection <Branch> branches = null; if (branchesByLineNumber.TryGetValue(lineNumber, out branches)) { HashSet <Branch> branchesHashset = (HashSet <Branch>)branches; if (branchesHashset.Contains(branch)) { // Not perfect for performance, but Hashset has no GetElement method branchesHashset.First(b => b.Equals(branch)).BranchVisits += branch.BranchVisits; } else { branches.Add(branch); } } else { branches = new HashSet <Branch>(); branches.Add(branch); branchesByLineNumber.Add(lineNumber, branches); } } else if (line.StartsWith("DA:")) { line = line.Substring(3); int lineNumber = int.Parse(line.Substring(0, line.IndexOf(',')), CultureInfo.InvariantCulture); int visits = line.Substring(line.IndexOf(',') + 1).ParseLargeInteger(); maxiumLineNumber = Math.Max(maxiumLineNumber, lineNumber); if (visitsByLine.ContainsKey(lineNumber)) { visitsByLine[lineNumber] += visits; } else { visitsByLine[lineNumber] = visits; } } } int[] coverage = new int[maxiumLineNumber + 1]; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[maxiumLineNumber + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var kv in visitsByLine) { coverage[kv.Key] = kv.Value; if (lineVisitStatus[kv.Key] != LineVisitStatus.Covered) { bool partiallyCovered = false; ICollection <Branch> branchesOfLine = null; if (branchesByLineNumber.TryGetValue(kv.Key, out branchesOfLine)) { partiallyCovered = branchesOfLine.Any(b => b.BranchVisits == 0); } LineVisitStatus statusOfLine = kv.Value > 0 ? (partiallyCovered ? LineVisitStatus.PartiallyCovered : LineVisitStatus.Covered) : LineVisitStatus.NotCovered; lineVisitStatus[kv.Key] = (LineVisitStatus)Math.Max((int)lineVisitStatus[kv.Key], (int)statusOfLine); } } var codeFile = new CodeFile(fileName, coverage, lineVisitStatus, branchesByLineNumber); for (int i = 0; i < codeElements.Count; i++) { var codeElement = codeElements[i]; int lastLine = maxiumLineNumber; 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))); } @class.AddFile(codeFile); }