public void AddCoverageByTestMethod_AddCoverageByTestMethodForExistingMethod_CoverageInformationIsMerged() { var sut = new CodeFile("C:\\temp\\Program.cs", new int[0], new LineVisitStatus[0]); var testMethod = new TestMethod("TestFull", "Test"); var coverageByTrackedMethod = new CoverageByTrackedMethod() { Coverage = new int[] { -1, -1, -1, -1, 0, 0, 0, 1, 1, 1 }, LineVisitStatus = new LineVisitStatus[] { LineVisitStatus.NotCoverable, LineVisitStatus.NotCoverable, LineVisitStatus.NotCoverable, LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered, LineVisitStatus.NotCovered, LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.Covered, LineVisitStatus.Covered } }; var repeatedCoverageByTrackedMethod = new CoverageByTrackedMethod() { Coverage = new int[] { -1, 0, 1, -1, 1, 0, 1, -1, 1, 0 }, LineVisitStatus = new LineVisitStatus[] { LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.NotCoverable, LineVisitStatus.Covered, LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.NotCoverable, LineVisitStatus.Covered, LineVisitStatus.NotCovered } }; sut.AddCoverageByTestMethod(testMethod, coverageByTrackedMethod); sut.AddCoverageByTestMethod(testMethod, repeatedCoverageByTrackedMethod); Assert.Contains(testMethod, sut.TestMethods); // using AnalyseFile() to retrieve merged coverage by test method var lineAnalyses = sut.AnalyzeFile(new CachingFileReader(0)).Lines; var testMethodCoverage = lineAnalyses.Take(9).Select(l => l.LineCoverageByTestMethod).ToArray(); Assert.True(testMethodCoverage.All(coverage => coverage.ContainsKey(testMethod)), "All lines should be covered by given test method"); var actualLineVisits = testMethodCoverage.Select(c => c[testMethod].LineVisits).ToArray(); var actualLineVisitStatuses = testMethodCoverage.Select(c => c[testMethod].LineVisitStatus).ToArray(); Assert.Equal(new int[] { 0, 1, -1, 1, 0, 1, 1, 2, 1 }, actualLineVisits); Assert.Equal(new LineVisitStatus[] { LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.NotCoverable, LineVisitStatus.Covered, LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.Covered, LineVisitStatus.Covered, LineVisitStatus.Covered }, actualLineVisitStatuses); }
public void AnalyzeFile_ExistingFileWithTrackedMethods_AnalysisIsReturned() { var sut = new CodeFile("C:\\temp\\Program.cs", new int[] { -2, -1, 0, 1 }); var testMethod = new TestMethod("TestFull", "Test"); sut.AddCoverageByTestMethod(testMethod, new int[] { -2, 1, -1, 0 }); var fileAnalysis = sut.AnalyzeFile(); Assert.AreEqual(1, fileAnalysis.Lines.First().LineCoverageByTestMethod[testMethod].LineVisits); Assert.AreEqual(LineVisitStatus.Covered, fileAnalysis.Lines.First().LineCoverageByTestMethod[testMethod].LineVisitStatus); }
public void Merge_MergeCodeFileWithEqualLengthCoverageArray_CoverageInformationIsUpdated() { var sut = new CodeFile("C:\\temp\\Program.cs", new int[] { -1, -1, -1, 0, 0, 0, 1, 1, 1 }); var codeFileToMerge = new CodeFile("C:\\temp\\Program.cs", new int[] { -1, 0, 1, -1, 0, 1, -1, 0, 1 }); var testMethod = new TestMethod("TestFull", "Test"); codeFileToMerge.AddCoverageByTestMethod(testMethod, new int[] { -1, -1, -1, 0, 0, 0, 1, 1, 1 }); sut.Merge(codeFileToMerge); Assert.AreEqual(8, sut.CoverableLines, "Not equal"); Assert.AreEqual(5, sut.CoveredLines, "Not equal"); Assert.IsTrue(sut.TestMethods.Contains(testMethod)); }
public void AnalyzeFile_ExistingFileWithTrackedMethods_AnalysisIsReturned() { var sut = new CodeFile("C:\\temp\\Program.cs", new int[] { -2, -1, 0, 1 }, new LineVisitStatus[] { LineVisitStatus.NotCoverable, LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered, LineVisitStatus.Covered }); var testMethod = new TestMethod("TestFull", "Test"); sut.AddCoverageByTestMethod(testMethod, new CoverageByTrackedMethod() { Coverage = new int[] { -2, 2, -1, 0 }, LineVisitStatus = new LineVisitStatus[] { LineVisitStatus.NotCoverable, LineVisitStatus.Covered, LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered } }); var fileAnalysis = sut.AnalyzeFile(new CachingFileReader(0)); Assert.Equal(2, fileAnalysis.Lines.First().LineCoverageByTestMethod[testMethod].LineVisits); Assert.Equal(LineVisitStatus.Covered, fileAnalysis.Lines.First().LineCoverageByTestMethod[testMethod].LineVisitStatus); }
public void Merge_MergeCodeFileWithLongerCoverageArray_CoverageInformationIsUpdated() { var branches = new Dictionary <int, ICollection <Branch> >() { { 1, new List <Branch>() { new Branch(1, "1"), new Branch(0, "2") } }, { 2, new List <Branch>() { new Branch(0, "3"), new Branch(2, "4") } } }; 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 }, branches); var testMethod = new TestMethod("TestFull", "Test"); sut.AddCoverageByTestMethod(testMethod, new CoverageByTrackedMethod() { Coverage = new int[] { -1, -1, -1, 0, 0, 0, 1, 1, 1 }, LineVisitStatus = new LineVisitStatus[] { LineVisitStatus.NotCoverable, LineVisitStatus.NotCoverable, LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered, LineVisitStatus.NotCovered, LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.Covered, LineVisitStatus.Covered } }); var branches2 = new Dictionary <int, ICollection <Branch> >() { { 1, new List <Branch>() { new Branch(4, "1"), new Branch(3, "5") } }, { 3, new List <Branch>() { new Branch(0, "3"), new Branch(2, "4") } } }; 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 }, branches2); testMethod = new TestMethod("TestFull", "Test"); codeFileToMerge.AddCoverageByTestMethod(testMethod, new CoverageByTrackedMethod() { Coverage = new int[] { -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1 }, LineVisitStatus = 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(10, sut.CoverableLines); Assert.Equal(6, sut.CoveredLines); Assert.Equal(4, sut.CoveredBranches); Assert.Equal(7, sut.TotalBranches); }
public void Merge_MergeCodeFileWithEqualLengthCoverageArray_CoverageInformationIsUpdated() { 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 codeFileToMerge = new CodeFile("C:\\temp\\Program.cs", new int[] { -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 }); var testMethod = new TestMethod("TestFull", "Test"); codeFileToMerge.AddCoverageByTestMethod(testMethod, new CoverageByTrackedMethod() { Coverage = new int[] { -1, -1, -1, 0, 0, 0, 1, 1, 1 }, LineVisitStatus = new LineVisitStatus[] { LineVisitStatus.NotCoverable, LineVisitStatus.NotCoverable, LineVisitStatus.NotCoverable, LineVisitStatus.NotCovered, LineVisitStatus.NotCovered, LineVisitStatus.NotCovered, LineVisitStatus.Covered, LineVisitStatus.Covered, LineVisitStatus.Covered } }); sut.Merge(codeFileToMerge); Assert.Equal(8, sut.CoverableLines); Assert.Equal(5, sut.CoveredLines); Assert.Null(sut.CoveredBranches); Assert.Null(sut.TotalBranches); Assert.Contains(testMethod, sut.TestMethods); }
/// <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(); int[] coverage = new int[] { }; var branches = GetBranches(methods, fileIds); var trackedMethodsCoverage = seqpntsOfFile .SelectMany(s => s.TrackedMethodRefs) .Select(t => t.TrackedMethodId) .Distinct() .ToDictionary(id => id, id => new int[] { }); if (seqpntsOfFile.Length > 0) { coverage = new int[seqpntsOfFile[seqpntsOfFile.LongLength - 1].LineNumberEnd + 1]; for (int i = 0; i < coverage.Length; i++) { coverage[i] = -1; } foreach (var name in trackedMethodsCoverage.Keys.ToArray()) { trackedMethodsCoverage[name] = (int[])coverage.Clone(); } 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 (visits > -1) { foreach (var trackedMethodCoverage in trackedMethodsCoverage) { if (trackedMethodCoverage.Value[lineNumber] == -1) { trackedMethodCoverage.Value[lineNumber] = 0; } } } foreach (var trackedMethod in seqpnt.TrackedMethodRefs) { var trackedMethodCoverage = trackedMethodsCoverage[trackedMethod.TrackedMethodId]; trackedMethodCoverage[lineNumber] = trackedMethodCoverage[lineNumber] == -1 ? trackedMethod.Visits : trackedMethodCoverage[lineNumber] + trackedMethod.Visits; } } } } var codeFile = new CodeFile(filePath, coverage, branches); foreach (var trackedMethodCoverage in trackedMethodsCoverage) { 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); } } return(codeFile); }
/// <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); }