/// <summary> /// Processes the file. /// </summary> /// <param name="module">The module.</param> /// <param name="fileId">The file id.</param> /// <param name="classWithNamespace">The class.</param> /// <param name="filePath">The file path.</param> /// <returns>The <see cref="CodeFile"/>.</returns> private static CodeFile ProcessFile(XElement module, string fileId, ClassWithNamespace classWithNamespace, string filePath) { var methods = module .Elements("functions") .Elements("function") .Where(c => c.Attribute("namespace")?.Value == classWithNamespace.Namespace) .Where(c => c.Attribute("type_name").Value.Equals(classWithNamespace.ClassName, StringComparison.Ordinal) || c.Attribute("type_name").Value.StartsWith(classWithNamespace.ClassName + ".", StringComparison.Ordinal)) .Where(m => m.Elements("ranges").Elements("range").Any(r => r.Attribute("source_id").Value == fileId)) .ToArray(); var linesOfFile = methods .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), Coverage = l.Attribute("covered").Value.Equals("no") ? 0 : 1, Partial = l.Attribute("covered").Value.Equals("partial") }) .OrderBy(seqpnt => seqpnt.LineNumberEnd) .ToArray(); int[] coverage = new int[] { }; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[] { }; if (linesOfFile.Length > 0) { coverage = new int[linesOfFile[linesOfFile.LongLength - 1].LineNumberEnd + 1]; lineVisitStatus = new LineVisitStatus[linesOfFile[linesOfFile.LongLength - 1].LineNumberEnd + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var seqpnt in linesOfFile) { for (int lineNumber = seqpnt.LineNumberStart; lineNumber <= seqpnt.LineNumberEnd; lineNumber++) { coverage[lineNumber] = coverage[lineNumber] == -1 ? seqpnt.Coverage : Math.Min(coverage[lineNumber] + seqpnt.Coverage, 1); if (lineVisitStatus[lineNumber] != LineVisitStatus.Covered) { LineVisitStatus statusOfLine = seqpnt.Partial ? LineVisitStatus.PartiallyCovered : (seqpnt.Coverage == 1 ? LineVisitStatus.Covered : LineVisitStatus.NotCovered); lineVisitStatus[lineNumber] = (LineVisitStatus)Math.Max((int)lineVisitStatus[lineNumber], (int)statusOfLine); } } } } var codeFile = new CodeFile(filePath, coverage, lineVisitStatus); SetMethodMetrics(codeFile, methods); SetCodeElements(codeFile, methods); return(codeFile); }
/// <summary> /// Initializes a new instance of the <see cref="LineAnalysis" /> class. /// </summary> /// <param name="lineVisits">The number of line visits.</param> /// <param name="lineVisitStatus">The line visit status.</param> /// <param name="lineCoverageByTestMethod">The line coverage by test method.</param> /// <param name="lineNumber">The line number.</param> /// <param name="lineContent">Content of the line.</param> internal LineAnalysis(int lineVisits, LineVisitStatus lineVisitStatus, IDictionary <TestMethod, ShortLineAnalysis> lineCoverageByTestMethod, int lineNumber, string lineContent) : base(lineVisits, lineVisitStatus) { this.LineCoverageByTestMethod = lineCoverageByTestMethod; this.LineNumber = lineNumber; this.LineContent = lineContent; }
/// <summary> /// Processes the file. /// </summary> /// <param name="fileId">The id of the file.</param> /// <param name="class">The class.</param> /// <returns>The <see cref="CodeFile"/>.</returns> private CodeFile ProcessFile(string fileId, Class @class) { var assemblyElement = this.modules .Where(m => m.Attribute("Name").Value.Equals(@class.Assembly.Name)); var methodsOfFile = assemblyElement .Elements("Namespace") .Elements("Type") .Concat(assemblyElement.Elements("Type")) .Where(c => (c.Parent.Attribute("Name").Value + "." + c.Attribute("Name").Value).Equals(@class.Name)) .Descendants("Method") .ToArray(); var statements = methodsOfFile .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), Visited = c.Attribute("Covered").Value == "True" }) .OrderBy(seqpnt => seqpnt.LineNumberEnd) .ToArray(); int[] coverage = new int[] { }; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[] { }; if (statements.Length > 0) { coverage = new int[statements[statements.LongLength - 1].LineNumberEnd + 1]; lineVisitStatus = new LineVisitStatus[statements[statements.LongLength - 1].LineNumberEnd + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var statement in statements) { for (int lineNumber = statement.LineNumberStart; lineNumber <= statement.LineNumberEnd; lineNumber++) { int visits = statement.Visited ? 1 : 0; coverage[lineNumber] = coverage[lineNumber] == -1 ? visits : Math.Min(coverage[lineNumber] + visits, 1); lineVisitStatus[lineNumber] = lineVisitStatus[lineNumber] == LineVisitStatus.Covered || statement.Visited ? LineVisitStatus.Covered : LineVisitStatus.NotCovered; } } } string filePath = this.files.First(f => f.Attribute("Index").Value == fileId).Attribute("Name").Value; var codeFile = new CodeFile(filePath, coverage, lineVisitStatus); SetCodeElements(codeFile, fileId, methodsOfFile); return(codeFile); }
/// <summary> /// Processes the file. /// </summary> /// <param name="fileId">The file id.</param> /// <param name="class">The class.</param> /// <param name="filePath">The file path.</param> /// <returns>The <see cref="CodeFile"/>.</returns> private CodeFile ProcessFile(string fileId, Class @class, string filePath) { var methods = this.modules .Where(m => m.Element("ModuleName").Value.Equals(@class.Assembly.Name)) .Elements("NamespaceTable") .Elements("Class") .Where(c => (c.Parent.Element("NamespaceName").Value + "." + c.Element("ClassName").Value).Equals(@class.Name, StringComparison.Ordinal) || (c.Parent.Element("NamespaceName").Value + "." + c.Element("ClassName").Value).StartsWith(@class.Name + ".", StringComparison.Ordinal)) .Elements("Method") .Where(m => m.Elements("Lines").Elements("SourceFileID").Any(s => s.Value == fileId)) .ToArray(); SetMethodMetrics(methods, @class); var linesOfFile = methods .Elements("Lines") .Select(l => new { LineNumberStart = int.Parse(l.Element("LnStart").Value, CultureInfo.InvariantCulture), LineNumberEnd = int.Parse(l.Element("LnEnd").Value, CultureInfo.InvariantCulture), Coverage = int.Parse(l.Element("Coverage").Value, CultureInfo.InvariantCulture) }) .OrderBy(seqpnt => seqpnt.LineNumberEnd) .ToArray(); int[] coverage = new int[] { }; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[] { }; if (linesOfFile.Length > 0) { coverage = new int[linesOfFile[linesOfFile.LongLength - 1].LineNumberEnd + 1]; lineVisitStatus = new LineVisitStatus[linesOfFile[linesOfFile.LongLength - 1].LineNumberEnd + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var seqpnt in linesOfFile) { for (int lineNumber = seqpnt.LineNumberStart; lineNumber <= seqpnt.LineNumberEnd; lineNumber++) { int visits = seqpnt.Coverage < 2 ? 1 : 0; coverage[lineNumber] = coverage[lineNumber] == -1 ? visits : Math.Min(coverage[lineNumber] + visits, 1); lineVisitStatus[lineNumber] = lineVisitStatus[lineNumber] == LineVisitStatus.Covered || visits > 0 ? LineVisitStatus.Covered : LineVisitStatus.NotCovered; } } } var codeFile = new CodeFile(filePath, coverage, lineVisitStatus); SetCodeElements(codeFile, methods); return(codeFile); }
/// <summary> /// Processes the file. /// </summary> /// <param name="class">The class.</param> /// <param name="filePath">The file path.</param> /// <returns>The <see cref="CodeFile"/>.</returns> private CodeFile ProcessFile(Class @class, string filePath) { var lines = this.modules .Where(m => m.Attribute("name").Value.Equals(@class.Assembly.Name)) .Elements("classes") .Elements("class") .Where(c => c.Attribute("name").Value.Equals(@class.Name) || c.Attribute("name").Value.StartsWith(@class.Name + "$", StringComparison.Ordinal)) .Elements("lines") .Elements("line"); var linesOfFile = lines.Select(line => new { LineNumber = int.Parse(line.Attribute("number").Value, CultureInfo.InvariantCulture), Visits = int.Parse(line.Attribute("hits").Value, CultureInfo.InvariantCulture) }) .ToArray(); var branches = GetBranches(lines); int[] coverage = new int[] { }; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[] { }; if (linesOfFile.Length > 0) { coverage = new int[linesOfFile[linesOfFile.LongLength - 1].LineNumber + 1]; lineVisitStatus = new LineVisitStatus[linesOfFile[linesOfFile.LongLength - 1].LineNumber + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var line in linesOfFile) { coverage[line.LineNumber] = line.Visits; bool partiallyCovered = false; ICollection <Branch> branchesOfLine = null; if (branches.TryGetValue(line.LineNumber, out branchesOfLine)) { partiallyCovered = branchesOfLine.Any(b => b.BranchVisits == 0); } LineVisitStatus statusOfLine = line.Visits > 0 ? (partiallyCovered ? LineVisitStatus.PartiallyCovered : LineVisitStatus.Covered) : LineVisitStatus.NotCovered; lineVisitStatus[line.LineNumber] = statusOfLine; } } return(new CodeFile(filePath, coverage, lineVisitStatus, branches)); }
/// <summary> /// Processes the file. /// </summary> /// <param name="class">The class.</param> /// <param name="filePath">The file path.</param> /// <returns>The <see cref="CodeFile"/>.</returns> private CodeFile ProcessFile(Class @class, string filePath) { string fileId = this.fileIdByFilenameDictionary[filePath]; var methods = this.types .Where(type => type.Attribute("asm").Value.Equals(@class.Assembly.Name) && (type.Attribute("name").Value.Equals(@class.Name, StringComparison.Ordinal) || type.Attribute("name").Value.StartsWith(@class.Name + "<", StringComparison.Ordinal))) .Elements("method") .ToArray(); var seqpntsOfFile = methods.Elements("code") .Elements("pt") .Where(seqpnt => seqpnt.HasAttributeWithValue("fid", fileId)) .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), Visits = int.Parse(seqpnt.Attribute("visit").Value, CultureInfo.InvariantCulture) }) .OrderBy(seqpnt => seqpnt.LineNumberEnd) .ToArray(); int[] coverage = new int[] { }; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[] { }; if (seqpntsOfFile.Length > 0) { coverage = new int[seqpntsOfFile[seqpntsOfFile.LongLength - 1].LineNumberEnd + 1]; lineVisitStatus = new LineVisitStatus[seqpntsOfFile[seqpntsOfFile.LongLength - 1].LineNumberEnd + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var seqpnt in seqpntsOfFile) { for (int lineNumber = seqpnt.LineNumberStart; lineNumber <= seqpnt.LineNumberEnd; lineNumber++) { coverage[lineNumber] = coverage[lineNumber] == -1 ? seqpnt.Visits : coverage[lineNumber] + seqpnt.Visits; lineVisitStatus[lineNumber] = lineVisitStatus[lineNumber] == LineVisitStatus.Covered || seqpnt.Visits > 0 ? LineVisitStatus.Covered : LineVisitStatus.NotCovered; } } } var codeFile = new CodeFile(filePath, coverage, lineVisitStatus); SetCodeElements(codeFile, fileId, methods); return(codeFile); }
/// <summary> /// Merges the two tracked method coverage. /// </summary> /// <param name="existingTrackedMethodCoverage">The existing tracked method coverage.</param> /// <param name="lineCoverageByTestMethod">The new line coverage by test method.</param> /// <returns>The merged tracked method coverage.</returns> private static CoverageByTrackedMethod MergeCoverageByTrackedMethod(CoverageByTrackedMethod existingTrackedMethodCoverage, CoverageByTrackedMethod lineCoverageByTestMethod) { // Resize coverage array if neccessary if (lineCoverageByTestMethod.Coverage.LongLength > existingTrackedMethodCoverage.Coverage.LongLength) { int[] newLineCoverage = new int[lineCoverageByTestMethod.Coverage.LongLength]; Array.Copy(lineCoverageByTestMethod.Coverage, newLineCoverage, lineCoverageByTestMethod.Coverage.LongLength); for (long i = existingTrackedMethodCoverage.Coverage.LongLength; i < lineCoverageByTestMethod.Coverage.LongLength; i++) { newLineCoverage[i] = -1; } existingTrackedMethodCoverage.Coverage = newLineCoverage; } // Resize line visit status array if neccessary if (lineCoverageByTestMethod.LineVisitStatus.LongLength > existingTrackedMethodCoverage.LineVisitStatus.LongLength) { LineVisitStatus[] newLineVisitStatus = new LineVisitStatus[lineCoverageByTestMethod.LineVisitStatus.LongLength]; Array.Copy(lineCoverageByTestMethod.LineVisitStatus, newLineVisitStatus, lineCoverageByTestMethod.LineVisitStatus.LongLength); existingTrackedMethodCoverage.LineVisitStatus = newLineVisitStatus; } for (long i = 0; i < lineCoverageByTestMethod.Coverage.LongLength; i++) { int coverage = existingTrackedMethodCoverage.Coverage[i]; if (coverage < 0) { coverage = lineCoverageByTestMethod.Coverage[i]; } else if (lineCoverageByTestMethod.Coverage[i] > 0) { coverage += lineCoverageByTestMethod.Coverage[i]; } existingTrackedMethodCoverage.Coverage[i] = coverage; } for (long i = 0; i < lineCoverageByTestMethod.LineVisitStatus.LongLength; i++) { int lineVisitStatus = Math.Max((int)existingTrackedMethodCoverage.LineVisitStatus[i], (int)lineCoverageByTestMethod.LineVisitStatus[i]); existingTrackedMethodCoverage.LineVisitStatus[i] = (LineVisitStatus)lineVisitStatus; } return(existingTrackedMethodCoverage); }
/// <summary> /// Processes the file. /// </summary> /// <param name="class">The class.</param> /// <param name="filePath">The file path.</param> /// <returns>The <see cref="CodeFile"/>.</returns> private CodeFile ProcessFile(Class @class, string filePath) { var methodsOfClass = this.modules .Where(type => type.Attribute("assembly").Value.Equals(@class.Assembly.Name)) .Elements("method") .Where(m => m.Attribute("excluded").Value == "false") .Where(method => method.Attribute("class").Value.StartsWith(@class.Name, StringComparison.Ordinal)) .ToArray(); var seqpntsOfFile = methodsOfClass.Elements("seqpnt") .Where(seqpnt => seqpnt.Attribute("document").Value.Equals(filePath) && 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), Visits = int.Parse(seqpnt.Attribute("visitcount").Value, CultureInfo.InvariantCulture) }) .OrderBy(seqpnt => seqpnt.LineNumberEnd) .ToArray(); int[] coverage = new int[] { }; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[] { }; if (seqpntsOfFile.Length > 0) { coverage = new int[seqpntsOfFile[seqpntsOfFile.LongLength - 1].LineNumberEnd + 1]; lineVisitStatus = new LineVisitStatus[seqpntsOfFile[seqpntsOfFile.LongLength - 1].LineNumberEnd + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var seqpnt in seqpntsOfFile) { for (int lineNumber = seqpnt.LineNumberStart; lineNumber <= seqpnt.LineNumberEnd; lineNumber++) { coverage[seqpnt.LineNumberStart] = coverage[seqpnt.LineNumberStart] == -1 ? seqpnt.Visits : coverage[seqpnt.LineNumberStart] + seqpnt.Visits; lineVisitStatus[lineNumber] = lineVisitStatus[lineNumber] == LineVisitStatus.Covered || seqpnt.Visits > 0 ? LineVisitStatus.Covered : LineVisitStatus.NotCovered; } } } var codeFile = new CodeFile(filePath, coverage, lineVisitStatus); SetCodeElements(codeFile, methodsOfClass); return(codeFile); }
/// <summary> /// Converts the <see cref="LineVisitStatus" /> to the corresponding CSS class. /// </summary> /// <param name="lineVisitStatus">The line visit status.</param> /// <param name="lightcolor">if set to <c>true</c> a CSS class representing a light color is returned.</param> /// <returns>The corresponding CSS class.</returns> private static string ConvertToCssClass(LineVisitStatus lineVisitStatus, bool lightcolor) { if (lineVisitStatus == LineVisitStatus.Covered) { return(lightcolor ? "lightgreen" : "green"); } else if (lineVisitStatus == LineVisitStatus.NotCovered) { return(lightcolor ? "lightred" : "red"); } else { return(lightcolor ? "lightgray" : "gray"); } }
/// <summary> /// Processes the file. /// </summary> /// <param name="modules">The modules.</param> /// <param name="class">The class.</param> /// <param name="filePath">The file path.</param> /// <param name="numberOrLines">The number of lines in the file.</param> /// <returns>The <see cref="CodeFile"/>.</returns> private static CodeFile ProcessFile(XElement[] modules, Class @class, string filePath, out int numberOrLines) { var linesOfFile = modules .Where(m => m.Attribute("name").Value.Equals(@class.Assembly.Name)) .Elements("sourcefile") .Where(c => c.Attribute("name").Value.Equals(filePath)) .Elements("line") .Select(line => new JaCoCoLineCoverage() { LineNumber = int.Parse(line.Attribute("nr").Value, CultureInfo.InvariantCulture), MissedInstructions = int.Parse(line.Attribute("mi")?.Value ?? "0", CultureInfo.InvariantCulture), CoveredInstructions = int.Parse(line.Attribute("ci")?.Value ?? "0", CultureInfo.InvariantCulture), MissedBranches = int.Parse(line.Attribute("mb")?.Value ?? "0", CultureInfo.InvariantCulture), CoveredBranches = int.Parse(line.Attribute("cb")?.Value ?? "0", CultureInfo.InvariantCulture) }) .OrderBy(seqpnt => seqpnt.LineNumber) .ToArray(); var branches = GetBranches(linesOfFile); int[] coverage = new int[] { }; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[] { }; if (linesOfFile.Length > 0) { coverage = new int[linesOfFile[linesOfFile.LongLength - 1].LineNumber + 1]; lineVisitStatus = new LineVisitStatus[linesOfFile[linesOfFile.LongLength - 1].LineNumber + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var line in linesOfFile) { coverage[line.LineNumber] = line.CoveredInstructions > 0 ? 1 : 0; bool partiallyCovered = line.MissedInstructions > 0; LineVisitStatus statusOfLine = line.CoveredInstructions > 0 ? (partiallyCovered ? LineVisitStatus.PartiallyCovered : LineVisitStatus.Covered) : LineVisitStatus.NotCovered; lineVisitStatus[line.LineNumber] = statusOfLine; } } numberOrLines = coverage.Length - 1; return(new CodeFile(filePath, coverage, lineVisitStatus, branches)); }
/// <summary> /// Processes the file. /// </summary> /// <param name="methods">The methods.</param> /// <param name="class">The class.</param> /// <param name="filePath">The file path.</param> /// <returns>The <see cref="CodeFile"/>.</returns> private static CodeFile ProcessFile(XElement[] methods, Class @class, string filePath) { var methodsOfFile = methods .Where(m => m.Attribute("assembly").Value.Equals(@class.Assembly.Name)) .Where(m => m.Attribute("class").Value.Equals(@class.Name, StringComparison.Ordinal)) .Where(m => m.Attribute("filename").Value.Equals(filePath)) .Distinct() .ToArray(); var linesOfFile = methodsOfFile .Elements("statement") .Select(l => new { LineNumber = int.Parse(l.Attribute("line").Value, CultureInfo.InvariantCulture), Visits = int.Parse(l.Attribute("counter").Value, CultureInfo.InvariantCulture) }) .OrderBy(l => l.LineNumber) .ToArray(); int[] coverage = new int[] { }; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[] { }; if (linesOfFile.Length > 0) { coverage = new int[linesOfFile[linesOfFile.LongLength - 1].LineNumber + 1]; lineVisitStatus = new LineVisitStatus[linesOfFile[linesOfFile.LongLength - 1].LineNumber + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var line in linesOfFile) { int visits = line.Visits > 0 ? 1 : 0; coverage[line.LineNumber] = coverage[line.LineNumber] == -1 ? visits : Math.Min(coverage[line.LineNumber] + visits, 1); lineVisitStatus[line.LineNumber] = lineVisitStatus[line.LineNumber] == LineVisitStatus.Covered || line.Visits > 0 ? LineVisitStatus.Covered : LineVisitStatus.NotCovered; } } var codeFile = new CodeFile(filePath, coverage, lineVisitStatus); SetCodeElements(codeFile, methodsOfFile); return(codeFile); }
/// <summary> /// Converts the <see cref="LineVisitStatus" /> to the corresponding CSS class. /// </summary> /// <param name="lineVisitStatus">The line visit status.</param> /// <param name="lightcolor">if set to <c>true</c> a CSS class representing a light color is returned.</param> /// <returns>The corresponding CSS class.</returns> private static string ConvertToCssClass(LineVisitStatus lineVisitStatus, bool lightcolor) { switch (lineVisitStatus) { case LineVisitStatus.Covered: return(lightcolor ? "lightgreen" : "green"); case LineVisitStatus.NotCovered: return(lightcolor ? "lightred" : "red"); case LineVisitStatus.PartiallyCovered: return(lightcolor ? "lightorange" : "orange"); default: return(lightcolor ? "lightgray" : "gray"); } }
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); }
/// <summary> /// Merges the given file with the current instance. /// </summary> /// <param name="file">The file to merge.</param> internal void Merge(CodeFile file) { if (file == null) { throw new ArgumentNullException(nameof(file)); } // Resize coverage array if necessary if (file.lineCoverage.LongLength > this.lineCoverage.LongLength) { int[] newLineCoverage = new int[file.lineCoverage.LongLength]; Array.Copy(this.lineCoverage, newLineCoverage, this.lineCoverage.LongLength); for (long i = this.lineCoverage.LongLength; i < file.lineCoverage.LongLength; i++) { newLineCoverage[i] = -1; } this.lineCoverage = newLineCoverage; } // Resize line visit status array if necessary if (file.lineVisitStatus.LongLength > this.lineVisitStatus.LongLength) { LineVisitStatus[] newLineVisitStatus = new LineVisitStatus[file.lineVisitStatus.LongLength]; Array.Copy(this.lineVisitStatus, newLineVisitStatus, this.lineVisitStatus.LongLength); this.lineVisitStatus = newLineVisitStatus; } for (long i = 0; i < file.lineCoverage.LongLength; i++) { int coverage = this.lineCoverage[i]; if (coverage < 0) { coverage = file.lineCoverage[i]; } else if (file.lineCoverage[i] > 0) { coverage += file.lineCoverage[i]; } this.lineCoverage[i] = coverage; } for (long i = 0; i < file.lineVisitStatus.LongLength; i++) { int lineVisitStatus = Math.Max((int)this.lineVisitStatus[i], (int)file.lineVisitStatus[i]); this.lineVisitStatus[i] = (LineVisitStatus)lineVisitStatus; } foreach (var lineCoverageByTestMethod in file.lineCoveragesByTestMethod) { CoverageByTrackedMethod existingTrackedMethodCoverage = null; this.lineCoveragesByTestMethod.TryGetValue(lineCoverageByTestMethod.Key, out existingTrackedMethodCoverage); if (existingTrackedMethodCoverage == null) { this.lineCoveragesByTestMethod.Add(lineCoverageByTestMethod); } else { this.lineCoveragesByTestMethod[lineCoverageByTestMethod.Key] = MergeCoverageByTrackedMethod(existingTrackedMethodCoverage, lineCoverageByTestMethod.Value); } } foreach (var methodMetric in file.methodMetrics) { var existingMethodMetric = this.methodMetrics.FirstOrDefault(m => m.Equals(methodMetric)); if (existingMethodMetric != null) { existingMethodMetric.Merge(methodMetric); } else { this.AddMethodMetric(methodMetric); } } foreach (var codeElement in file.codeElements) { this.codeElements.Add(codeElement); } if (file.branches != null) { if (this.branches == null) { this.branches = new Dictionary <int, ICollection <Branch> >(); } foreach (var branchByLine in file.branches) { ICollection <Branch> existingBranches = null; if (this.branches.TryGetValue(branchByLine.Key, out existingBranches)) { foreach (var branch in branchByLine.Value) { Branch existingBranch = existingBranches.FirstOrDefault(b => b.Equals(branch)); if (existingBranch != null) { existingBranch.BranchVisits += branch.BranchVisits; } else { existingBranches.Add(branch); } } } else { this.branches.Add(branchByLine); } } } }
/// <summary> /// Performs the analysis of the source file. /// </summary> /// <param name="fileReader">The file reader.</param> /// <returns>The analysis result.</returns> internal FileAnalysis AnalyzeFile(IFileReader fileReader) { string error = null; string[] lines = fileReader.LoadFile(this.Path, out error); if (error != null) { Logger.Error(error); return(new FileAnalysis(this.Path, error)); } this.TotalLines = lines.Length; int currentLineNumber = 0; var result = new FileAnalysis(this.Path); ICollection <Branch> branchesOfLine = null; foreach (var line in lines) { currentLineNumber++; int visits = this.lineCoverage.Length > currentLineNumber ? this.lineCoverage[currentLineNumber] : -1; LineVisitStatus lineVisitStatus = this.lineVisitStatus.Length > currentLineNumber ? this.lineVisitStatus[currentLineNumber] : LineVisitStatus.NotCoverable; var lineCoverageByTestMethod = this.lineCoveragesByTestMethod .ToDictionary( l => l.Key, l => { if (l.Value.Coverage.Length > currentLineNumber) { return(new ShortLineAnalysis(l.Value.Coverage[currentLineNumber], l.Value.LineVisitStatus[currentLineNumber])); } else { return(new ShortLineAnalysis(-1, LineVisitStatus.NotCoverable)); } }); if (this.branches != null && this.branches.TryGetValue(currentLineNumber, out branchesOfLine)) { result.AddLineAnalysis( new LineAnalysis( visits, lineVisitStatus, lineCoverageByTestMethod, currentLineNumber, line.TrimEnd(), branchesOfLine.Count(b => b.BranchVisits > 0), branchesOfLine.Count)); } else { result.AddLineAnalysis( new LineAnalysis( visits, lineVisitStatus, lineCoverageByTestMethod, currentLineNumber, line.TrimEnd())); } } return(result); }
/// <summary> /// Initializes a new instance of the <see cref="ShortLineAnalysis" /> class. /// </summary> /// <param name="lineVisits">The number of line visits.</param> /// <param name="lineVisitStatus">The line visit status.</param> internal ShortLineAnalysis(int lineVisits, LineVisitStatus lineVisitStatus) { this.LineVisits = lineVisits; this.LineVisitStatus = lineVisitStatus; }
/// <summary> /// Performs the analysis of the source file. /// </summary> /// <returns>The analysis result.</returns> internal FileAnalysis AnalyzeFile() { if (!System.IO.File.Exists(this.Path)) { string error = string.Format(CultureInfo.InvariantCulture, " " + Resources.FileDoesNotExist, this.Path); Logger.Error(error); return(new FileAnalysis(this.Path, error)); } try { string[] lines = System.IO.File.ReadAllLines(this.Path); this.TotalLines = lines.Length; int currentLineNumber = 0; testlinescount = 0; newlinescount = 0; var result = new FileAnalysis(this.Path); ICollection <Branch> branchesOfLine = null; //string[] files = Directory.GetFiles(@"d:\test2\"); //string val = this.Path.Split('\\').Last(); Dictionary <int, string> diffvalue = new Dictionary <int, string>(); List <CompareHelper.BuildChanges> buildlineslist = new List <CompareHelper.BuildChanges>(); string[] fname = this.Path.Split('\\'); string temp = string.Empty; int len = fname.Length; temp = "\\" + fname[len - 1] + "_"; // + fname[len - 3] + "_" + fname[len - 2] + "_" string reportPath = @System.Configuration.ConfigurationManager.AppSettings["ComparePath"] + temp + "_report.xml"; if (File.Exists(reportPath)) { diffvalue = CompareHelper.Report(reportPath); } buildlineslist = Reporting.ReportGenerator.buildclasses; foreach (var line in lines) { currentLineNumber++; int visits = this.lineCoverage.Length > currentLineNumber ? this.lineCoverage[currentLineNumber] : -1; LineVisitStatus lineVisitStatus = this.lineVisitStatus.Length > currentLineNumber ? this.lineVisitStatus[currentLineNumber] : LineVisitStatus.NotCoverable; LineVisitStatus tempstatus = lineVisitStatus; if (diffvalue != null && diffvalue.Count > 0 && diffvalue.ContainsKey(currentLineNumber) && diffvalue[currentLineNumber].Contains(line) && lineVisitStatus != LineVisitStatus.NotCoverable)// && lineVisitStatus != LineVisitStatus.NotCoverable { ChangesCount.Add(currentLineNumber.ToString() + "###" + line); newlinescount++; lineVisitStatus = LineVisitStatus.newline; } else if (buildlineslist != null && buildlineslist.Any(x => x.buildlines.Contains(currentLineNumber.ToString() + "###" + line)) && tempstatus != LineVisitStatus.NotCoverable) { ChangesCount.Add(currentLineNumber.ToString() + "###" + line); newlinescount++; //lineVisitStatus = LineVisitStatus.newline; } if ((diffvalue != null && diffvalue.Count > 0 && diffvalue.ContainsKey(currentLineNumber) && diffvalue[currentLineNumber].Contains(line)) && (tempstatus == LineVisitStatus.Covered))//|| lineVisitStatus == LineVisitStatus.NotCoverable)) // { TestedlinesCount.Add(currentLineNumber.ToString() + "###" + line); testlinescount++; lineVisitStatus = LineVisitStatus.Covered; } if (buildlineslist != null && buildlineslist.Any(x => x.buildtestedlines.Contains(currentLineNumber.ToString() + "###" + line)) && tempstatus != LineVisitStatus.NotCoverable) { TestedlinesCount.Add(currentLineNumber.ToString() + "###" + line); testlinescount++; lineVisitStatus = LineVisitStatus.Covered; } var lineCoverageByTestMethod = this.lineCoveragesByTestMethod .ToDictionary( l => l.Key, l => { if (l.Value.Coverage.Length > currentLineNumber) { return(new ShortLineAnalysis(l.Value.Coverage[currentLineNumber], l.Value.LineVisitStatus[currentLineNumber])); } else { return(new ShortLineAnalysis(-1, LineVisitStatus.NotCoverable)); } }); if (this.branches != null && this.branches.TryGetValue(currentLineNumber, out branchesOfLine)) { result.AddLineAnalysis( new LineAnalysis( visits, lineVisitStatus, lineCoverageByTestMethod, currentLineNumber, line.TrimEnd(), branchesOfLine.Count(b => b.BranchVisits > 0), branchesOfLine.Count)); } else { result.AddLineAnalysis( new LineAnalysis( visits, lineVisitStatus, lineCoverageByTestMethod, currentLineNumber, line.TrimEnd())); } } return(result); } catch (IOException ex) { string error = string.Format(CultureInfo.InvariantCulture, " " + Resources.ErrorDuringReadingFile, this.Path, ex.Message); Logger.Error(error); return(new FileAnalysis(this.Path, error)); } catch (UnauthorizedAccessException ex) { string error = string.Format(CultureInfo.InvariantCulture, " " + Resources.ErrorDuringReadingFile, this.Path, ex.Message); Logger.Error(error); return(new FileAnalysis(this.Path, error)); } }
/// <summary> /// Processes the file. /// </summary> /// <param name="assembly">The assembly.</param> /// <param name="fileElement">The file element.</param> private void ProcessFile(Assembly assembly, XElement fileElement) { var @class = new Class(fileElement.Attribute("name").Value, assembly); var lines = fileElement.Elements("line") .ToArray(); var linesOfFile = lines .Where(line => line.Attribute("type").Value == "stmt") .Select(line => new { LineNumber = int.Parse(line.Attribute("num").Value, CultureInfo.InvariantCulture), Visits = line.Attribute("count").Value.ParseLargeInteger() }) .OrderBy(seqpnt => seqpnt.LineNumber) .ToArray(); var branches = GetBranches(lines); int[] coverage = new int[] { }; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[] { }; if (linesOfFile.Length > 0) { coverage = new int[linesOfFile[linesOfFile.LongLength - 1].LineNumber + 1]; lineVisitStatus = new LineVisitStatus[linesOfFile[linesOfFile.LongLength - 1].LineNumber + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var line in linesOfFile) { coverage[line.LineNumber] = line.Visits; bool partiallyCovered = false; ICollection <Branch> branchesOfLine = null; if (branches.TryGetValue(line.LineNumber, out branchesOfLine)) { partiallyCovered = branchesOfLine.Any(b => b.BranchVisits == 0); } LineVisitStatus statusOfLine = line.Visits > 0 ? (partiallyCovered ? LineVisitStatus.PartiallyCovered : LineVisitStatus.Covered) : LineVisitStatus.NotCovered; lineVisitStatus[line.LineNumber] = statusOfLine; } } var methodsOfFile = lines .Where(line => line.Attribute("type").Value == "method") .ToArray(); var codeFile = new CodeFile(fileElement.Attribute("path").Value, coverage, lineVisitStatus, branches); SetCodeElements(codeFile, methodsOfFile); @class.AddFile(codeFile); assembly.AddClass(@class); }
/// <summary> /// Converts the <see cref="LineVisitStatus" /> to the corresponding CSS class. /// </summary> /// <param name="lineVisitStatus">The line visit status.</param> /// <param name="lightcolor">if set to <c>true</c> a CSS class representing a light color is returned.</param> /// <returns>The corresponding CSS class.</returns> private static string ConvertToCssClass(LineVisitStatus lineVisitStatus, bool lightcolor) { if (lineVisitStatus == LineVisitStatus.Covered) { return lightcolor ? "lightgreen" : "green"; } else if (lineVisitStatus == LineVisitStatus.NotCovered) { return lightcolor ? "lightred" : "red"; } else { return lightcolor ? "lightgray" : "gray"; } }
/// <summary> /// Processes the file. /// </summary> /// <param name="fileIds">The file ids of the class.</param> /// <param name="class">The class.</param> /// <param name="filePath">The file path.</param> /// <returns>The <see cref="CodeFile"/>.</returns> private CodeFile ProcessFile(HashSet <string> fileIds, Class @class, string filePath) { var methods = this.modules .Where(m => m.Element("ModuleName").Value.Equals(@class.Assembly.Name)) .Elements("Classes") .Elements("Class") .Where(c => c.Element("FullName").Value.Equals(@class.Name) || c.Element("FullName").Value.StartsWith(@class.Name + "/", StringComparison.Ordinal)) .Elements("Methods") .Elements("Method") .ToArray(); var methodsOfFile = methods .Where(m => m.Element("FileRef") != null && fileIds.Contains(m.Element("FileRef").Attribute("uid").Value)) .ToArray(); SetMethodMetrics(methodsOfFile, @class); var seqpntsOfFile = methods .Elements("SequencePoints") .Elements("SequencePoint") .Where(seqpnt => (seqpnt.Attribute("fileid") != null && fileIds.Contains(seqpnt.Attribute("fileid").Value)) || (seqpnt.Attribute("fileid") == null && seqpnt.Parent.Parent.Element("FileRef") != null && fileIds.Contains(seqpnt.Parent.Parent.Element("FileRef").Attribute("uid").Value))) .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), Visits = int.Parse(seqpnt.Attribute("vc").Value, CultureInfo.InvariantCulture), TrackedMethodRefs = seqpnt.Elements("TrackedMethodRefs") .Elements("TrackedMethodRef") .Select(t => new { Visits = int.Parse(t.Attribute("vc").Value, CultureInfo.InvariantCulture), TrackedMethodId = t.Attribute("uid").Value }) }) .OrderBy(seqpnt => seqpnt.LineNumberEnd) .ToArray(); var branches = GetBranches(methods, fileIds); var coverageByTrackedMethod = seqpntsOfFile .SelectMany(s => s.TrackedMethodRefs) .Select(t => t.TrackedMethodId) .Distinct() .ToDictionary(id => id, id => new CoverageByTrackedMethod { Coverage = new int[] { }, LineVisitStatus = new LineVisitStatus[] { } }); int[] coverage = new int[] { }; LineVisitStatus[] lineVisitStatus = new LineVisitStatus[] { }; if (seqpntsOfFile.Length > 0) { coverage = new int[seqpntsOfFile[seqpntsOfFile.LongLength - 1].LineNumberEnd + 1]; lineVisitStatus = new LineVisitStatus[seqpntsOfFile[seqpntsOfFile.LongLength - 1].LineNumberEnd + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var trackedMethodCoverage in coverageByTrackedMethod) { trackedMethodCoverage.Value.Coverage = (int[])coverage.Clone(); trackedMethodCoverage.Value.LineVisitStatus = new LineVisitStatus[seqpntsOfFile[seqpntsOfFile.LongLength - 1].LineNumberEnd + 1]; } foreach (var seqpnt in seqpntsOfFile) { for (int lineNumber = seqpnt.LineNumberStart; lineNumber <= seqpnt.LineNumberEnd; lineNumber++) { int visits = coverage[lineNumber] == -1 ? seqpnt.Visits : coverage[lineNumber] + seqpnt.Visits; coverage[lineNumber] = visits; if (lineVisitStatus[lineNumber] != LineVisitStatus.Covered) { bool partiallyCovered = false; ICollection <Branch> branchesOfLine = null; // Use 'LineNumberStart' instead of 'lineNumber' here. Branches have line number of first line of seqpnt if (branches.TryGetValue(seqpnt.LineNumberStart, out branchesOfLine)) { partiallyCovered = branchesOfLine.Any(b => b.BranchVisits == 0); } LineVisitStatus statusOfLine = visits > 0 ? (partiallyCovered ? LineVisitStatus.PartiallyCovered : LineVisitStatus.Covered) : LineVisitStatus.NotCovered; lineVisitStatus[lineNumber] = (LineVisitStatus)Math.Max((int)lineVisitStatus[lineNumber], (int)statusOfLine); } if (visits > -1) { foreach (var trackedMethodCoverage in coverageByTrackedMethod) { if (trackedMethodCoverage.Value.Coverage[lineNumber] == -1) { trackedMethodCoverage.Value.Coverage[lineNumber] = 0; trackedMethodCoverage.Value.LineVisitStatus[lineNumber] = LineVisitStatus.NotCovered; } } } foreach (var trackedMethod in seqpnt.TrackedMethodRefs) { var trackedMethodCoverage = coverageByTrackedMethod[trackedMethod.TrackedMethodId]; int trackeMethodVisits = trackedMethodCoverage.Coverage[lineNumber] == -1 ? trackedMethod.Visits : trackedMethodCoverage.Coverage[lineNumber] + trackedMethod.Visits; LineVisitStatus statusOfLine = trackeMethodVisits > 0 ? (LineVisitStatus)Math.Min((int)LineVisitStatus.Covered, (int)lineVisitStatus[lineNumber]) : LineVisitStatus.NotCovered; trackedMethodCoverage.Coverage[lineNumber] = trackeMethodVisits; trackedMethodCoverage.LineVisitStatus[lineNumber] = statusOfLine; } } } } var codeFile = new CodeFile(filePath, coverage, lineVisitStatus, branches); foreach (var trackedMethodCoverage in coverageByTrackedMethod) { string name = null; // Sometimes no corresponding MethodRef element exists if (this.trackedMethods.TryGetValue(trackedMethodCoverage.Key, out name)) { string shortName = name.Substring(name.Substring(0, name.IndexOf(':') + 1).LastIndexOf('.') + 1); TestMethod testMethod = new TestMethod(name, shortName); codeFile.AddCoverageByTestMethod(testMethod, trackedMethodCoverage.Value); } } SetCodeElements(codeFile, methodsOfFile); return(codeFile); }
/// <summary> /// Initializes a new instance of the <see cref="LineAnalysis" /> class. /// </summary> /// <param name="lineVisits">The number of line visits.</param> /// <param name="lineVisitStatus">The line visit status.</param> /// <param name="lineCoverageByTestMethod">The line coverage by test method.</param> /// <param name="lineNumber">The line number.</param> /// <param name="lineContent">Content of the line.</param> /// <param name="coveredBranches">The covered branches.</param> /// <param name="totalBranches">The total branches.</param> internal LineAnalysis(int lineVisits, LineVisitStatus lineVisitStatus, IDictionary <TestMethod, ShortLineAnalysis> lineCoverageByTestMethod, int lineNumber, string lineContent, int coveredBranches, int totalBranches) : this(lineVisits, lineVisitStatus, lineCoverageByTestMethod, lineNumber, lineContent) { this.CoveredBranches = coveredBranches; this.TotalBranches = totalBranches; }
private void ProcessClass(Class @class, string fileName, string[] lines, ref int currentLine) { var codeElements = new List <CodeElement>(); 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 CodeElement(name, CodeElementType.Method, lineNumber, 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 file = new CodeFile(fileName, coverage, lineVisitStatus, branchesByLineNumber); foreach (var codeElement in codeElements) { file.AddCodeElement(codeElement); } @class.AddFile(file); }
/// <summary> /// Performs the analysis of the source file. /// </summary> /// <returns>The analysis result.</returns> internal FileAnalysis AnalyzeFile() { if (!System.IO.File.Exists(this.Path)) { string error = string.Format(CultureInfo.InvariantCulture, " " + Resources.FileDoesNotExist, this.Path); Logger.Error(error); return(new FileAnalysis(this.Path, error)); } try { string[] lines = System.IO.File.ReadAllLines(this.Path); this.TotalLines = lines.Length; int currentLineNumber = 0; var result = new FileAnalysis(this.Path); ICollection <Branch> branchesOfLine = null; foreach (var line in lines) { currentLineNumber++; int visits = this.lineCoverage.Length > currentLineNumber ? this.lineCoverage[currentLineNumber] : -1; LineVisitStatus lineVisitStatus = this.lineVisitStatus.Length > currentLineNumber ? this.lineVisitStatus[currentLineNumber] : LineVisitStatus.NotCoverable; var lineCoverageByTestMethod = this.lineCoveragesByTestMethod .ToDictionary( l => l.Key, l => { if (l.Value.Coverage.Length > currentLineNumber) { return(new ShortLineAnalysis(l.Value.Coverage[currentLineNumber], l.Value.LineVisitStatus[currentLineNumber])); } else { return(new ShortLineAnalysis(-1, LineVisitStatus.NotCoverable)); } }); if (this.branches != null && this.branches.TryGetValue(currentLineNumber, out branchesOfLine)) { result.AddLineAnalysis( new LineAnalysis( visits, lineVisitStatus, lineCoverageByTestMethod, currentLineNumber, line.TrimEnd(), branchesOfLine.Count(b => b.BranchVisits > 0), branchesOfLine.Count)); } else { result.AddLineAnalysis( new LineAnalysis( visits, lineVisitStatus, lineCoverageByTestMethod, currentLineNumber, line.TrimEnd())); } } return(result); } catch (IOException ex) { string error = string.Format(CultureInfo.InvariantCulture, " " + Resources.ErrorDuringReadingFile, this.Path, ex.Message); Logger.Error(error); return(new FileAnalysis(this.Path, error)); } catch (UnauthorizedAccessException ex) { string error = string.Format(CultureInfo.InvariantCulture, " " + Resources.ErrorDuringReadingFile, this.Path, ex.Message); Logger.Error(error); return(new FileAnalysis(this.Path, error)); } }