private void WriteClass(ClassCoverageItem item) { if (item.filtered) { return; } // start class writer.WriteStartElement("class"); writer.WriteAttributeString("name", item.name); writer.WriteAttributeString("fullname", item.FullName.Replace('/', '.')); writer.WriteAttributeString("namespace", item.Namespace); WriteCoverage(item); // start source writer.WriteStartElement("source"); if (item.sourceFile != null) { writer.WriteAttributeString("sourceFile", item.sourceFile.sourceFile); int[] coverage = item.sourceFile.Coverage; foreach (MethodCoverageItem method in item.Methods) { int sum = 0; int length = method.endLine - method.startLine; for (int index = method.startLine; index < method.endLine; index++) { if (coverage[index] > 0) { sum++; } } if (length == 0) { continue; } writer.WriteStartElement("Method"); writer.WriteAttributeString("type", item.FullName); writer.WriteAttributeString("method", method.Name); writer.WriteAttributeString("coverage", "" + ((float)sum) / length); writer.WriteAttributeString("length", "" + length); writer.WriteEndElement(); } } else { } // end source writer.WriteEndElement(); // end class writer.WriteEndElement(); }
private void ProcessMethod(MethodDefinition monoMethod, MethodEntry entry, ClassCoverageItem klass, string methodName, string cov_info) #endif { if (entry == null) { // Compiler generated, abstract method etc. return; } LineNumberEntry[] lines = entry.LineNumbers; // DEBUG //if( cov_info == null ) // Console.WriteLine( lines.Length ); // DEBUG if (lines.Length == 0) { return; } int start_line = lines [0].Row; int end_line = lines [lines.Length - 1].Row; MethodCoverageItem method = new MethodCoverageItem(klass, methodName); method.startLine = start_line; method.endLine = end_line; #if USE_REFLECTION method.filtered = IsFiltered("[" + monoMethod.DeclaringType.Assembly + "]" + monoMethod.DeclaringType + "::" + monoMethod.Name); #else method.filtered = IsFiltered("[" + monoMethod.DeclaringType.Module.Name + "]" + monoMethod.DeclaringType + "::" + monoMethod.Name); #endif klass.methodsByMethod [monoMethod] = method; if (klass.sourceFile == null) { string sourceFile = entry.SourceFile.FileName; SourceFileCoverageData source = (SourceFileCoverageData)sources [sourceFile]; //Console.WriteLine( source ); if (source == null) { source = new SourceFileCoverageData(sourceFile); sources [sourceFile] = source; } klass.sourceFile = source; } computeMethodCoverage(method, lines, cov_info); }
private void WriteClass(ClassCoverageItem item) { if (item.filtered) { return; } writer.WriteStartElement("class"); writer.WriteAttributeString("name", item.name); writer.WriteAttributeString("fullname", item.FullName.Replace('/', '.')); writer.WriteAttributeString("namespace", item.Namespace); WriteCoverage(item); writer.WriteStartElement("source"); if (item.sourceFile != null) { writer.WriteAttributeString("sourceFile", item.sourceFile.sourceFile); StreamReader infile = new StreamReader(item.sourceFile.sourceFile, Encoding.ASCII); int[] coverage = item.sourceFile.Coverage; int pos = 1; while (infile.Peek() > -1) { int count; if ((coverage != null) && (pos < coverage.Length)) { count = coverage [pos]; } else { count = -1; } writer.WriteStartElement("l"); writer.WriteAttributeString("line", "" + pos); writer.WriteAttributeString("count", "" + count); string line = infile.ReadLine(); writer.WriteString(line); writer.WriteEndElement(); pos++; } } writer.WriteEndElement(); }
private void ProcessMethod(MethodBase monoMethod, MethodEntry entry, ClassCoverageItem klass, string methodName, string cov_info)
private ClassCoverageItem ProcessClass(TypeDefinition t) #endif { string className = t.FullName; int nsindex = className.LastIndexOf("."); string namespace2; string scopedName; if (nsindex == -1) { namespace2 = "<GLOBAL>"; scopedName = className; } else if (nsindex == 0) { namespace2 = "<GLOBAL>"; scopedName = className.Substring(1); } else { namespace2 = className.Substring(0, nsindex); scopedName = className.Substring(nsindex + 1); } // Create namespaces NamespaceCoverageItem ns = (NamespaceCoverageItem)namespaces [namespace2]; if (ns == null) { string nsPrefix = ""; foreach (String nsPart in namespace2.Split('.')) { if (nsPrefix == "") { nsPrefix = nsPart; } else { nsPrefix = nsPrefix + "." + nsPart; } NamespaceCoverageItem ns2 = (NamespaceCoverageItem)namespaces [nsPrefix]; if (ns2 == null) { if (ns == null) { ns2 = new NamespaceCoverageItem(this, nsPrefix); } else { ns2 = new NamespaceCoverageItem(ns, nsPrefix); } namespaces [nsPrefix] = ns2; } ns = ns2; } } ClassCoverageItem klass = (ClassCoverageItem)classes [className]; if (klass == null) { klass = new ClassCoverageItem(ns); klass.name_space = namespace2; klass.name = scopedName; klass.type = t; klass.parent = ns; #if USE_REFLECTION klass.filtered = IsFiltered("[" + t.Assembly + "]" + className); #else klass.filtered = IsFiltered("[" + t.Module.Name + "]" + className); #endif classes [className] = klass; } return(klass); }
private void computeMethodCoverage(MethodCoverageItem method, LineNumberEntry[] lines, string cov_info) { ClassCoverageItem klass = method.Class; SourceFileCoverageData source = klass.sourceFile; source.AddMethod(method); int nlines = method.endLine - method.startLine + 1; int[] coverage = new int [nlines]; if (cov_info == null) { for (int i = 0; i < nlines; ++i) { coverage [i] = 0; } } else { for (int i = 0; i < nlines; ++i) { coverage [i] = -1; } // Hand crafted parsing code since this is performance critical int pos = 0; int prev_offset = 0; while (pos < cov_info.Length) { int pos2 = cov_info.IndexOfAny(digits, pos); if (pos2 == -1) { break; } pos = cov_info.IndexOfAny(ws, pos2); if (pos == -1) { break; } int offset = parsePositiveInteger(cov_info, pos2); pos2 = cov_info.IndexOfAny(digits, pos); if (pos2 == -1) { break; } pos = cov_info.IndexOfAny(ws, pos2); int count = parsePositiveInteger(cov_info, pos2); offset += prev_offset; prev_offset = offset; int line1 = 0; int line2 = 0; bool found = GetSourceRangeFor(offset, method, lines, ref line1, ref line2); /* * if (found && (entry.Name.IndexOf ("Find") != -1)) { * Console.WriteLine ("OFFSET: " + offset + " " + line1 + ":" + line2); * } */ if (found) { for (int i = line1; i < line2 + 1; ++i) { if ((i >= method.startLine) && (i <= method.endLine)) { if (coverage [i - method.startLine] < count) { coverage [i - method.startLine] = count; } } } } } } int hit = 0; int missed = 0; for (int i = 0; i < nlines; ++i) { int count = coverage [i]; if (count > 0) { hit++; } else if (count == 0) { missed++; } } method.setCoverage(hit, missed); method.lineCoverage = coverage; }
public void ReadFromFile(string fileName) { namespaces = new Hashtable(); classes = new Hashtable(); long begin = DateTime.Now.Ticks / 10000; long msec = DateTime.Now.Ticks / 10000; long msec2; loadedAssemblies = new Hashtable(); symbolFiles = new Hashtable(); XmlDocument dom = new XmlDocument(); Progress("XML reading", 0); Console.Write("Loading " + fileName + "..."); dom.Load(new XmlTextReader(new FileStream(fileName, FileMode.Open))); Console.WriteLine(" Done."); msec2 = DateTime.Now.Ticks / 10000; Console.WriteLine("XML Reading: " + (msec2 - msec) + " msec"); msec = msec2; Progress("Load assemblies", 0.2); LoadAssemblies(dom); LoadFilters(dom); msec2 = DateTime.Now.Ticks / 10000; Console.WriteLine("Load assemblies: " + (msec2 - msec) + " msec"); msec = msec2; Progress("Load methods", 0.4); foreach (XmlNode n in dom.GetElementsByTagName("method")) { string assemblyName = n.Attributes ["assembly"].Value; string className = n.Attributes ["class"].Value; string methodName = n.Attributes ["name"].Value; string token = n.Attributes ["token"].Value; string cov_info = n.FirstChild.Value; int itok = int.Parse(token); #if USE_REFLECTION Assembly assembly = (Assembly)loadedAssemblies [assemblyName]; MonoSymbolFile symbolFile = (MonoSymbolFile)symbolFiles [assembly]; if (symbolFile == null) { continue; } Type t = LoadType(assembly, className); if (t == null) { Console.WriteLine("ERROR: Unable to resolve type " + className + " in " + assembly); continue; } ClassCoverageItem klass = ProcessClass(t); MethodEntry entry = symbolFile.GetMethodByToken(Int32.Parse(token)); Module[] modules = assembly.GetModules(); if (modules.Length > 1) { Console.WriteLine("WARNING: Assembly had more than one module. Using the first."); } Module module = modules[0]; MethodBase monoMethod = module.ResolveMethod(Int32.Parse(token)); ProcessMethod(monoMethod, entry, klass, methodName, cov_info); #else if ((TokenType)(itok & 0xff000000) != TokenType.Method) { continue; } AssemblyDefinition assembly = (AssemblyDefinition)loadedAssemblies [assemblyName]; MonoSymbolFile symbolFile = (MonoSymbolFile)symbolFiles [assembly]; if (symbolFile == null) { continue; } TypeDefinition t = LoadType(assembly, className); if (t == null) { Console.WriteLine("ERROR: Unable to resolve type " + className + " in " + assembly); continue; } ClassCoverageItem klass = ProcessClass(t); MethodEntry entry = symbolFile.GetMethodByToken(itok); MethodDefinition monoMethod = assembly.MainModule.LookupByToken( new MetadataToken((TokenType)(itok & 0xff000000), (uint)(itok & 0xffffff))) as MethodDefinition; //Console.WriteLine (monoMethod); ProcessMethod(monoMethod, entry, klass, methodName, cov_info); #endif } msec2 = DateTime.Now.Ticks / 10000; Console.WriteLine("Process methods: " + (msec2 - msec) + " msec"); msec = msec2; // Add info for klasses for which we have no coverage #if USE_REFLECTION foreach (Assembly assembly in loadedAssemblies.Values) { foreach (Type t in assembly.GetTypes()) { ProcessClass(t); } } // Add info for methods for which we have no coverage foreach (ClassCoverageItem klass in classes.Values) { foreach (MethodInfo mb in klass.type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly)) { MonoSymbolFile symbolFile = (MonoSymbolFile)symbolFiles [klass.type.Assembly]; if (symbolFile == null) { continue; } if (!klass.methodsByMethod.ContainsKey(mb)) { MethodEntry entry = symbolFile.GetMethod(mb); ProcessMethod(mb, entry, klass, mb.Name, null); } } } #else Progress("Not covered classes", 0.6); foreach (AssemblyDefinition assembly in loadedAssemblies.Values) { foreach (TypeDefinition t in assembly.MainModule.Types) { ProcessClass(t); } } Progress("Not covered methods", 0.7); // Add info for methods for which we have no coverage foreach (ClassCoverageItem klass in classes.Values) { foreach (MethodDefinition mb in klass.type.Methods) { MonoSymbolFile symbolFile = (MonoSymbolFile)symbolFiles [klass.type.Module.Assembly]; if (symbolFile == null) { continue; } if (!klass.methodsByMethod.ContainsKey(mb)) { MethodEntry entry = symbolFile.GetMethodByToken((int)mb.MetadataToken.ToUInt()); string name = GetMethodNameWithParameters(mb); ProcessMethod(mb, entry, klass, name, null); } } } #endif msec2 = DateTime.Now.Ticks / 10000; Console.WriteLine("Additional classes: " + (msec2 - msec) + " msec"); msec = msec2; Progress("Compute coverage", 0.9); // Compute coverage for all items computeCoverage(true); msec2 = DateTime.Now.Ticks / 10000; Console.WriteLine("Compute coverage: " + (msec2 - msec) + " msec"); msec = msec2; Console.WriteLine("All: " + (msec2 - begin) + " msec"); Progress("Done loading", 0.9); // Free memory symbolFiles = null; }
public MethodCoverageItem(ClassCoverageItem parent, String name) : base(parent) { this.name = name; }
private void WriteItem(CoverageItem item, Type stopLevel, int level) { if (item.filtered) { return; } if (item.hit + item.missed == 0) { // Filtered return; } if (level == 0) { return; } if (item.GetType() == stopLevel) { return; } if (item is CoverageModel) { writer.WriteStartElement("project"); writer.WriteAttributeString("name", "Project"); } else if (item is NamespaceCoverageItem) { NamespaceCoverageItem ns = (NamespaceCoverageItem)item; writer.WriteStartElement("namespace"); if (ns.ns == "<GLOBAL>") { writer.WriteAttributeString("name", "GLOBAL"); } else { writer.WriteAttributeString("name", ns.ns); } } else if (item is ClassCoverageItem) { ClassCoverageItem klass = (ClassCoverageItem)item; writer.WriteStartElement("class"); writer.WriteAttributeString("name", klass.name); writer.WriteAttributeString("fullname", klass.FullName.Replace('/', '.')); } WriteCoverage(item); if (item.ChildCount > 0) { foreach (CoverageItem child in item.children) { WriteItem(child, stopLevel, level - 1); } } writer.WriteEndElement(); }