/// <summary> /// Processes the given assembly. /// </summary> /// <param name="module">The module.</param> /// <returns>The <see cref="Assembly"/>.</returns> private static Assembly ProcessAssembly(XElement module) { string assemblyName = module.Attribute("name").Value; Logger.DebugFormat(" " + Resources.CurrentAssembly, assemblyName); var classNames = module .Elements("functions") .Elements("function") .Select(f => f.Attribute("type_name").Value) .Where(c => !c.Contains("<>") && !c.StartsWith("$", StringComparison.OrdinalIgnoreCase)) .Select(t => { int nestedClassSeparatorIndex = t.IndexOf('.'); return nestedClassSeparatorIndex > -1 ? t.Substring(0, nestedClassSeparatorIndex) : t; }) .Distinct() .OrderBy(name => name) .ToArray(); var assembly = new Assembly(assemblyName); Parallel.ForEach(classNames, className => assembly.AddClass(ProcessClass(module, assembly, className))); return assembly; }
public void Constructor() { string assemblyName = "C:\\test\\TestAssembly.dll"; var sut = new Assembly(assemblyName); Assert.AreEqual(assemblyName, sut.Name, "Not equal"); Assert.AreEqual("TestAssembly.dll", sut.ShortName, "Not equal"); }
public void AddClass_AddSingleClass_ClassIsStored() { var sut = new Assembly("C:\\test\\TestAssembly.dll"); var @class = new Class("Test", sut); sut.AddClass(@class); Assert.AreEqual(@class, sut.Classes.First(), "Not equal"); Assert.AreEqual(1, sut.Classes.Count(), "Wrong number of classes"); }
public void AddFile_AddSingleFile_FileIsStored() { var assembly = new Assembly("C:\\test\\TestAssembly.dll"); var sut = new Class("Test", assembly); var file = new CodeFile("C:\\temp\\Program.cs", new int[0]); sut.AddFile(file); Assert.AreEqual(file, sut.Files.First(), "Not equal"); Assert.AreEqual(1, sut.Files.Count(), "Wrong number of classes"); }
public void Constructor() { Assembly assembly = new Assembly("C:\\test\\TestAssembly.dll"); string classname = "TestClass"; var sut = new Class(classname, assembly); Assert.AreEqual(assembly, sut.Assembly, "Not equal"); Assert.AreEqual(classname, sut.Name, "Not equal"); }
public void Merge_MergeAssemblyWithOneClass_ClassIsStored() { var sut = new Assembly("C:\\test\\TestAssembly.dll"); var assemblyToMerge = new Assembly("C:\\test\\TestAssembly.dll"); var @class = new Class("Test", sut); assemblyToMerge.AddClass(@class); sut.Merge(assemblyToMerge); Assert.AreEqual(@class, sut.Classes.First(), "Not equal"); Assert.AreEqual(1, sut.Classes.Count(), "Wrong number of classes"); }
public void Equals() { string assemblyName = "C:\\test\\TestAssembly.dll"; var target1 = new Assembly(assemblyName); var target2 = new Assembly(assemblyName); var target3 = new Assembly("Test.dll"); Assert.IsTrue(target1.Equals(target2), "Objects are not equal"); Assert.IsFalse(target1.Equals(target3), "Objects are equal"); Assert.IsFalse(target1.Equals(null), "Objects are equal"); Assert.IsFalse(target1.Equals(new object()), "Objects are equal"); }
public void Equals() { Assembly assembly = new Assembly("C:\\test\\TestAssembly.dll"); string classname = "TestClass"; var target1 = new Class(classname, assembly); var target2 = new Class(classname, assembly); var target3 = new Class(classname + "123", assembly); Assert.IsTrue(target1.Equals(target2), "Objects are not equal"); Assert.IsFalse(target1.Equals(target3), "Objects are equal"); Assert.IsFalse(target1.Equals(null), "Objects are equal"); Assert.IsFalse(target1.Equals(new object()), "Objects are equal"); }
/// <summary> /// Initializes a new instance of the <see cref="Class"/> class. /// </summary> /// <param name="name">The name of the class.</param> /// <param name="assembly">The assembly.</param> internal Class(string name, Assembly assembly) { if (name == null) { throw new ArgumentNullException(nameof(name)); } if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } this.Name = name; this.Assembly = assembly; }
/// <summary> /// Initializes a new instance of the <see cref="Class"/> class. /// </summary> /// <param name="name">The name of the class.</param> /// <param name="assembly">The assembly.</param> public Class(string name, Assembly assembly) { if (name == null) { throw new ArgumentNullException("name"); } if (assembly == null) { throw new ArgumentNullException("assembly"); } this.Name = name; this.Assembly = assembly; }
public void Merge_MergeClassWithOneFileAndOneMethodMetric_FileIsStored() { var assembly = new Assembly("C:\\test\\TestAssembly.dll"); var sut = new Class("Test", assembly); var classToMerge = new Class("Test", assembly); var file = new CodeFile("C:\\temp\\Program.cs", new int[0]); var methodMetric = new MethodMetric("Test"); classToMerge.AddFile(file); classToMerge.AddMethodMetric(methodMetric); sut.Merge(classToMerge); Assert.AreEqual(file, sut.Files.First(), "Not equal"); Assert.AreEqual(1, sut.Files.Count(), "Wrong number of classes"); Assert.AreEqual(methodMetric, sut.MethodMetrics.First(), "Not equal"); Assert.AreEqual(1, sut.MethodMetrics.Count(), "Wrong number of method metrics"); }
/// <summary> /// Processes the given assembly. /// </summary> /// <param name="assemblyName">Name of the assembly.</param> /// <returns>The <see cref="Assembly"/>.</returns> private Assembly ProcessAssembly(string assemblyName) { Logger.DebugFormat(" " + Resources.CurrentAssembly, assemblyName); var classNames = this.types .Where(type => type.Attribute("asm").Value.Equals(assemblyName) && !type.Attribute("name").Value.Contains("__")) .Select(type => type.Attribute("name").Value) .OrderBy(name => name) .Distinct() .ToArray(); var assembly = new Assembly(assemblyName); Parallel.ForEach(classNames, className => assembly.AddClass(this.ProcessClass(assembly, className))); return assembly; }
/// <summary> /// Processes the given class. /// </summary> /// <param name="assembly">The assembly.</param> /// <param name="className">Name of the class.</param> /// <returns>The <see cref="Class"/>.</returns> private Class ProcessClass(Assembly assembly, string className) { var filesOfClass = this.modules .Where(module => module.Attribute("assembly").Value.Equals(assembly.Name)).Elements("method") .Where(method => method.Attribute("class").Value.Equals(className)) .Elements("seqpnt").Select(seqpnt => seqpnt.Attribute("document").Value) .Distinct() .ToArray(); var @class = new Class(className, assembly); foreach (var file in filesOfClass) { @class.AddFile(this.ProcessFile(@class, file)); } return @class; }
/// <summary> /// Processes the given assembly. /// </summary> /// <param name="assemblyName">Name of the assembly.</param> /// <returns>The <see cref="Assembly"/>.</returns> private Assembly ProcessAssembly(string assemblyName) { logger.DebugFormat(" " + Resources.CurrentAssembly, assemblyName); var classNames = this.modules .Where(module => module.Attribute("assembly").Value.Equals(assemblyName)) .Elements("method") .Select(method => method.Attribute("class").Value) .Where(value => !value.Contains("__")) .Distinct() .OrderBy(name => name) .ToArray(); var assembly = new Assembly(assemblyName); Parallel.ForEach(classNames, className => assembly.AddClass(this.ProcessClass(assembly, className))); return assembly; }
public void Merge_MergeClassWithCoverageQuota_FileIsStored() { var assembly = new Assembly("C:\\test\\TestAssembly.dll"); var sut = new Class("Test", assembly); var classToMerge = new Class("Test", assembly) { CoverageQuota = 15 }; sut.Merge(classToMerge); Assert.AreEqual(15, sut.CoverageQuota); classToMerge = new Class("Test", assembly) { CoverageQuota = 20 }; sut.Merge(classToMerge); Assert.AreEqual(20, sut.CoverageQuota); }
/// <summary> /// Processes the given assembly. /// </summary> /// <param name="assemblyName">Name of the assembly.</param> /// <returns>The <see cref="Assembly"/>.</returns> private Assembly ProcessAssembly(string assemblyName) { Logger.DebugFormat(" " + Resources.CurrentAssembly, assemblyName); var assemblyElement = this.modules .Where(m => m.Attribute("Name").Value.Equals(assemblyName)); var classNames = assemblyElement .Elements("Namespace") .Elements("Type") .Concat(assemblyElement.Elements("Type")) .Where(c => !c.Attribute("Name").Value.Contains("__")) .Select(c => c.Parent.Attribute("Name").Value + "." + c.Attribute("Name").Value) .Distinct() .OrderBy(name => name) .ToArray(); var assembly = new Assembly(assemblyName); Parallel.ForEach(classNames, className => assembly.AddClass(this.ProcessClass(assembly, className))); return assembly; }
/// <summary> /// Processes the given assembly. /// </summary> /// <param name="module">The module.</param> /// <returns>The <see cref="Assembly"/>.</returns> private static Assembly ProcessAssembly(XElement module) { string assemblyName = module.Attribute("name").Value; Logger.DebugFormat(" " + Resources.CurrentAssembly, assemblyName); var classNames = module .Elements("functions") .Elements("function") .Select(f => f.Attribute("type_name").Value) .Where(c => !c.Contains("__") && !c.Contains("<") && !c.Contains(".")) .Distinct() .OrderBy(name => name) .ToArray(); var assembly = new Assembly(assemblyName); Parallel.ForEach(classNames, className => assembly.AddClass(ProcessClass(module, assembly, className))); return assembly; }
/// <summary> /// Processes the given class. /// </summary> /// <param name="module">The module.</param> /// <param name="assembly">The assembly.</param> /// <param name="className">Name of the class.</param> /// <returns>The <see cref="Class"/>.</returns> private static Class ProcessClass(XElement module, Assembly assembly, string className) { var fileIdsOfClass = module .Elements("functions") .Elements("function") .Where(c => c.Attribute("type_name").Value.Equals(className, StringComparison.Ordinal) || c.Attribute("type_name").Value.StartsWith(className + ".", StringComparison.Ordinal)) .Elements("ranges") .Elements("range") .Select(r => r.Attribute("source_id").Value) .Distinct(); var @class = new Class(className, assembly); var files = module.Elements("source_files").Elements("source_file"); foreach (var fileId in fileIdsOfClass) { string file = files.First(f => f.Attribute("id").Value == fileId).Attribute("path").Value; @class.AddFile(ProcessFile(module, fileId, @class, file)); } return @class; }
/// <summary> /// Adds the given assembly. /// </summary> /// <param name="assembly">The assembly.</param> protected internal void AddAssembly(Assembly assembly) { this.assemblies.Add(assembly); }
/// <summary> /// Processes the given assembly. /// </summary> /// <param name="assemblyName">Name of the assembly.</param> /// <returns>The <see cref="Assembly"/>.</returns> private Assembly ProcessAssembly(string assemblyName) { Logger.DebugFormat(" " + Resources.CurrentAssembly, assemblyName); var classNames = this.modules .Where(m => m.Element("ModuleName").Value.Equals(assemblyName)) .Elements("NamespaceTable") .Elements("Class") .Elements("ClassName") .Where(c => !c.Value.Contains("<>") && !c.Value.StartsWith("$", StringComparison.OrdinalIgnoreCase)) .Select(c => { string fullname = c.Value; int nestedClassSeparatorIndex = fullname.IndexOf('.'); fullname = nestedClassSeparatorIndex > -1 ? fullname.Substring(0, nestedClassSeparatorIndex) : fullname; return c.Parent.Parent.Element("NamespaceName").Value + "." + fullname; }) .Distinct() .OrderBy(name => name) .ToArray(); var assembly = new Assembly(assemblyName); Parallel.ForEach(classNames, className => assembly.AddClass(this.ProcessClass(assembly, className))); return assembly; }
/// <summary> /// Processes the given class. /// </summary> /// <param name="assembly">The assembly.</param> /// <param name="className">Name of the class.</param> /// <returns>The <see cref="Class"/>.</returns> private Class ProcessClass(Assembly assembly, string className) { var fileIdsOfClass = this.modules .Where(m => m.Element("ModuleName").Value.Equals(assembly.Name)) .Elements("NamespaceTable") .Elements("Class") .Where(c => (c.Parent.Element("NamespaceName").Value + "." + c.Element("ClassName").Value).Equals(className, StringComparison.Ordinal) || (c.Parent.Element("NamespaceName").Value + "." + c.Element("ClassName").Value).StartsWith(className + ".", StringComparison.Ordinal)) .Elements("Method") .Elements("Lines") .Elements("SourceFileID") .Select(m => m.Value) .Distinct(); var @class = new Class(className, assembly); foreach (var fileId in fileIdsOfClass) { string file = this.files.First(f => f.Element("SourceFileID").Value == fileId).Element("SourceFileName").Value; @class.AddFile(this.ProcessFile(fileId, @class, file)); } return @class; }
/// <summary> /// Adds the coverage information of an assembly to the report. /// </summary> /// <param name="assembly">The assembly.</param> public void SummaryAssembly(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException("assembly"); } string row = string.Format( CultureInfo.InvariantCulture, @"\textbf{{{0}}} & \textbf{{{1}}}\\", EscapeLatexChars(assembly.Name), assembly.CoverageQuota.HasValue ? assembly.CoverageQuota.Value.ToString(CultureInfo.InvariantCulture) + @"\%" : string.Empty); this.reportTextWriter.WriteLine(row); }
/// <summary> /// Adds the coverage information of an assembly to the report. /// </summary> /// <param name="assembly">The assembly.</param> public void SummaryAssembly(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException("assembly"); } string row = string.Format( CultureInfo.InvariantCulture, @"\textbf{{{0}}} & \textbf{{{1}\%}}\\", EscapeLatexChars(assembly.Name), assembly.CoverageQuota); this.reportBuilder.AppendLine(row); }
/// <summary> /// Processes the given class. /// </summary> /// <param name="fileIdsByFilename">Dictionary containing the file ids by filename.</param> /// <param name="assembly">The assembly.</param> /// <param name="className">Name of the class.</param> /// <returns>The <see cref="Class"/>.</returns> private Class ProcessClass(Dictionary<string, HashSet<string>> fileIdsByFilename, Assembly assembly, string className) { var methods = this.modules .Where(m => m.Element("ModuleName").Value.Equals(assembly.Name)) .Elements("Classes") .Elements("Class") .Where(c => c.Element("FullName").Value.Equals(className) || c.Element("FullName").Value.StartsWith(className + "/", StringComparison.Ordinal)) .Elements("Methods") .Elements("Method"); var fileIdsOfClassInSequencePoints = methods .Elements("SequencePoints") .Elements("SequencePoint") .Where(seqpnt => seqpnt.Attribute("fileid") != null && seqpnt.Attribute("fileid").Value != "0") .Select(seqpnt => seqpnt.Attribute("fileid").Value) .ToArray(); // Only required for backwards compatibility, older versions of OpenCover did not apply fileid for partial classes var fileIdsOfClassInFileRef = methods .Where(m => m.Element("FileRef") != null) .Select(m => m.Element("FileRef").Attribute("uid").Value) .ToArray(); var fileIdsOfClass = fileIdsOfClassInSequencePoints .Concat(fileIdsOfClassInFileRef) .Distinct() .ToHashSet(); var filesOfClass = this.files .Where(file => fileIdsOfClass.Contains(file.Attribute("uid").Value)) .Select(file => file.Attribute("fullPath").Value) .Distinct() .ToArray(); var @class = new Class(className, assembly); foreach (var file in filesOfClass) { @class.AddFile(this.ProcessFile(fileIdsByFilename[file], @class, file)); } @class.CoverageQuota = this.GetCoverageQuotaOfClass(assembly, className); return @class; }
/// <summary> /// Gets the coverage quota of a class. /// This method is used to get coverage quota if line coverage is not available. /// </summary> /// <param name="assembly">The assembly.</param> /// <param name="className">Name of the class.</param> /// <returns>The coverage quota.</returns> private decimal? GetCoverageQuotaOfClass(Assembly assembly, string className) { var methodGroups = this.modules .Where(m => m.Element("ModuleName").Value.Equals(assembly.Name)) .Elements("Classes") .Elements("Class") .Where(c => c.Element("FullName").Value.Equals(className) || c.Element("FullName").Value.StartsWith(className + "/", StringComparison.Ordinal)) .Elements("Methods") .Elements("Method") .Where(m => m.Attribute("skippedDueTo") == null && m.Element("FileRef") == null && !m.Element("Name").Value.EndsWith(".ctor()", StringComparison.OrdinalIgnoreCase)) .GroupBy(m => m.Element("Name").Value) .ToArray(); int visitedMethods = methodGroups.Count(g => g.Any(m => m.Attribute("visited").Value == "true")); return (methodGroups.Length == 0) ? (decimal?)null : (decimal)Math.Truncate(1000 * (double)visitedMethods / (double)methodGroups.Length) / 10; }
/// <summary> /// Processes the given assembly. /// </summary> /// <param name="assemblyName">Name of the assembly.</param> /// <returns>The <see cref="Assembly"/>.</returns> private Assembly ProcessAssembly(string assemblyName) { Logger.DebugFormat(" " + Resources.CurrentAssembly, assemblyName); var fileIdsByFilename = this.modules .Where(m => m.Element("ModuleName").Value.Equals(assemblyName)) .Elements("Files") .Elements("File") .GroupBy(f => f.Attribute("fullPath").Value, f => f.Attribute("uid").Value) .ToDictionary(g => g.Key, g => g.ToHashSet()); var classNames = this.modules .Where(m => m.Element("ModuleName").Value.Equals(assemblyName)) .Elements("Classes") .Elements("Class") .Where(c => !c.Element("FullName").Value.Contains("__") && !c.Element("FullName").Value.Contains("<") && c.Attribute("skippedDueTo") == null) .Select(c => { string fullname = c.Element("FullName").Value; int nestedClassSeparatorIndex = fullname.IndexOf('/'); return nestedClassSeparatorIndex > -1 ? fullname.Substring(0, nestedClassSeparatorIndex) : fullname; }) .Distinct() .OrderBy(name => name) .ToArray(); var assembly = new Assembly(assemblyName); Parallel.ForEach(classNames, className => assembly.AddClass(this.ProcessClass(fileIdsByFilename, assembly, className))); return assembly; }
/// <summary> /// Adds the coverage information of an assembly to the report. /// </summary> /// <param name="assembly">The assembly.</param> public void SummaryAssembly(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException("assembly"); } var coverage = new XElement( "Assembly", new XAttribute("name", assembly.Name), new XAttribute("classes", assembly.Classes.Count()), new XAttribute("coverage", assembly.CoverageQuota), new XAttribute("coveredlines", assembly.CoveredLines), new XAttribute("coverablelines", assembly.CoverableLines), new XAttribute("totallines", assembly.TotalLines)); this.currentElement.Add(coverage); this.currentAssembly = coverage; }
/// <summary> /// Adds the coverage information of an assembly to the report. /// </summary> /// <param name="assembly">The assembly.</param> public void SummaryAssembly(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException(nameof(assembly)); } this.reportTextWriter.Write("<tr>"); this.reportTextWriter.Write("<th>{0}</th>", WebUtility.HtmlEncode(assembly.Name)); this.reportTextWriter.Write("<th class=\"right\">{0}</th>", assembly.CoveredLines); this.reportTextWriter.Write("<th class=\"right\">{0}</th>", assembly.CoverableLines - assembly.CoveredLines); this.reportTextWriter.Write("<th class=\"right\">{0}</th>", assembly.CoverableLines); this.reportTextWriter.Write("<th class=\"right\">{0}</th>", assembly.TotalLines.GetValueOrDefault()); this.reportTextWriter.Write( "<th title=\"{0}\" class=\"right\">{1}</th>", assembly.CoverageQuota.HasValue ? CoverageType.LineCoverage.ToString() : string.Empty, assembly.CoverageQuota.HasValue ? assembly.CoverageQuota.Value.ToString(CultureInfo.InvariantCulture) + "%" : string.Empty); this.reportTextWriter.Write("<th>{0}</th>", CreateCoverageTable(assembly.CoverageQuota)); this.reportTextWriter.Write( "<th class=\"right\">{0}</th>", assembly.BranchCoverageQuota.HasValue ? assembly.BranchCoverageQuota.Value.ToString(CultureInfo.InvariantCulture) + "%" : string.Empty); this.reportTextWriter.Write("<th>{0}</th>", CreateCoverageTable(assembly.BranchCoverageQuota)); this.reportTextWriter.WriteLine("</tr>"); }
/// <summary> /// Adds the coverage information of an assembly to the report. /// </summary> /// <param name="assembly">The assembly.</param> public void SummaryAssembly(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException("assembly"); } if (this.closeAssemblyNode) { this.reportTextWriter.WriteEndElement(); } this.reportTextWriter.WriteStartElement("Assembly"); this.reportTextWriter.WriteAttributeString("name", assembly.Name); this.reportTextWriter.WriteAttributeString("classes", assembly.Classes.Count().ToString(CultureInfo.InvariantCulture)); this.reportTextWriter.WriteAttributeString("coverage", assembly.CoverageQuota.HasValue ? assembly.CoverageQuota.Value.ToString(CultureInfo.InvariantCulture) : string.Empty); this.reportTextWriter.WriteAttributeString("coveredlines", assembly.CoveredLines.ToString(CultureInfo.InvariantCulture)); this.reportTextWriter.WriteAttributeString("coverablelines", assembly.CoverableLines.ToString(CultureInfo.InvariantCulture)); this.reportTextWriter.WriteAttributeString("totallines", assembly.TotalLines.HasValue ? assembly.TotalLines.Value.ToString(CultureInfo.InvariantCulture) : string.Empty); this.closeAssemblyNode = true; }
/// <summary> /// Processes the given class. /// </summary> /// <param name="assembly">The assembly.</param> /// <param name="className">Name of the class.</param> /// <returns>The <see cref="Class"/>.</returns> private Class ProcessClass(Assembly assembly, string className) { var fileIdsOfClass = this.types .Where(type => type.Attribute("asm").Value.Equals(assembly.Name) && (type.Attribute("name").Value.Equals(className, StringComparison.Ordinal) || type.Attribute("name").Value.StartsWith(className + "<", StringComparison.Ordinal))) .Elements("method") .Elements("code") .Elements("pt") .Where(pt => pt.Attribute("fid") != null) .Select(pt => pt.Attribute("fid").Value) .Distinct() .ToHashSet(); var filesOfClass = this.files .Where(file => fileIdsOfClass.Contains(file.Attribute("id").Value)) .Select(file => file.Attribute("url").Value) .ToArray(); var @class = new Class(className, assembly); foreach (var file in filesOfClass) { @class.AddFile(this.ProcessFile(@class, file)); } return @class; }