/// <summary> /// Reads metadata for a given coverage node. /// </summary> private void ReadMetadata() { CoverageNodeModel node = SelectedCoverageRow?.Model.ClosestAncestor(CoverageNodeType.Module); if (node != null) { //TODO (testing): hide this behind a service interface var ofd = new OpenFileDialog { Filter = ".NET Assembly (*.exe;*.dll)|*.exe;*.dll", Multiselect = false, FileName = node.Name, }; if (ofd.ShowDialog(Owner) == true) { MetadataHelper helper; try { helper = new MetadataHelper(ofd.FileName); } catch (BadImageFormatException) { MessageBox.Show(Owner, "The selected file is not a valid .NET assembly."); return; } helper.LoadMetadataFor(node); } } }
/// <summary> /// Loads a method's metadata. /// </summary> /// <param name="methodNode">The method node to read into.</param> /// <param name="declaringType">The method's declaring type.</param> /// <param name="methodInfo">The method info.</param> private void LoadMethodMetadata(CoverageNodeModel methodNode, Type declaringType, MethodBase methodInfo) { Debug.Assert(methodNode != null); Debug.Assert(methodNode.NodeType == CoverageNodeType.Function); Debug.Assert(methodNode.Parent != null); Debug.Assert(methodNode.Parent.NodeType == CoverageNodeType.Type); Module mod = GetModule(methodNode); methodNode.Name = GetCleanMethodName(methodInfo); if (methodInfo.IsSpecialName) { foreach (var prop in declaringType.GetProperties(LoadFlags)) { if (methodInfo.Equals(prop.GetMethod) || methodInfo.Equals(prop.SetMethod)) { methodNode.CodeType = CodeElementType.Property; break; } } } methodNode.HasReadMetadata = true; }
private static CoverageNodeModel ReadNamespace(NamespaceCoverageInfo ns) { var model = new CoverageNodeModel(CoverageNodeType.Namespace); if (!string.IsNullOrEmpty(ns.NamespaceName)) { model.Name = ns.NamespaceName; } else { model.Name = "Global Types"; } model.BlocksCovered = ns.BlocksCovered; model.BlocksNotCovered = ns.BlocksNotCovered; model.LinesCovered = ns.LinesCovered; model.LinesPartiallyCovered = ns.LinesPartiallyCovered; model.LinesNotCovered = ns.LinesNotCovered; model.AdditionalData[nameof(ns.ModuleName)] = ns.ModuleName; model.AdditionalData[nameof(ns.NamespaceKeyName)] = ns.NamespaceKeyName; foreach (var cls in ns.Classes) { model.Children.Add(ReadClass(cls)); } return(model); }
private static CoverageNodeModel ReadClass(ClassCoverageInfo cls) { var model = new CoverageNodeModel(CoverageNodeType.Type); if (!string.IsNullOrEmpty(cls.ClassName)) { model.Name = cls.ClassName; } else { model.Name = "Global Functions"; } model.LinesCovered = cls.LinesCovered; model.LinesPartiallyCovered = cls.LinesPartiallyCovered; model.LinesNotCovered = cls.LinesNotCovered; model.BlocksCovered = cls.BlocksCovered; model.BlocksNotCovered = cls.BlocksNotCovered; model.AdditionalData[nameof(cls.ClassKeyName)] = cls.ClassKeyName; model.AdditionalData[nameof(cls.NamespaceKeyName)] = cls.NamespaceKeyName; foreach (var meth in cls.Methods) { model.Children.Add(ReadFunction(meth)); } return(model); }
private static CoverageDSPriv CreateSerializable(CoverageNodeModel model) { var file = new CoverageDSPriv(); file.Modules = model.Children.Select(CreateSerializableModule).ToArray(); file.SourceFileNames = (SourceFileInfo[])(model.AdditionalData["SourceFileNames"]); return(file); }
/// <summary> /// Gets the module containing the code for the coverage node. /// </summary> /// <param name="node">The node to get the module for.</param> /// <returns>The module for the code, or null if the module is not found.</returns> private Module GetModule(CoverageNodeModel node) { node = node?.ClosestAncestor(CoverageNodeType.Module); if (node != null) { return(_asm.GetModule(node.Name)); } return(null); }
private static CoverageNodeModel ReadFile(CoverageDSPriv file) { var model = new CoverageNodeModel(CoverageNodeType.CoverageFile); foreach (var mod in file.Modules) { model.Children.Add(ReadModule(mod)); } model.AdditionalData[nameof(file.SourceFileNames)] = file.SourceFileNames; return(model); }
/// <summary> /// Loads a class's metadata. /// </summary> /// <param name="classNode">The class node to read into.</param> private void LoadTypeMetadata(CoverageNodeModel classNode) { Debug.Assert(classNode != null); Debug.Assert(classNode.NodeType == CoverageNodeType.Type); Module mod = GetModule(classNode); string lookupName = GetNamespaceQualifiedName(classNode); Type type = mod.GetType(lookupName); string className = GetCleanTypeName(type); classNode.Name = className; foreach (var ctor in type.GetConstructors(LoadFlags)) { // ".cctor", ".ctor" - see: ECMA-335, II.10.5 Special Members string coverageName = (ctor.IsStatic ? ".cctor" : ".ctor") + GetCoverageParameterString(ctor); var node = classNode.Children.FirstOrDefault(m => m.Name == coverageName); if (node != null) { LoadMethodMetadata(node, type, ctor); } } foreach (var method in type.GetMethods(LoadFlags)) { string coverageName = method.Name + GetCoverageParameterString(method); var node = classNode.Children.FirstOrDefault(m => m.Name == coverageName); if (node != null) { LoadMethodMetadata(node, type, method); } } if (type.IsValueType) { classNode.CodeType = CodeElementType.Struct; } classNode.HasReadMetadata = true; }
private static NamespaceCoverageInfo CreateSerializableNamespace(CoverageNodeModel model) { var ns = new NamespaceCoverageInfo(); ns.BlocksCovered = model.BlocksCovered; ns.BlocksNotCovered = model.BlocksNotCovered; ns.LinesCovered = model.LinesCovered; ns.LinesNotCovered = model.LinesNotCovered; ns.LinesPartiallyCovered = model.LinesPartiallyCovered; ns.ModuleName = (string)model.AdditionalData[nameof(ns.ModuleName)]; ns.NamespaceKeyName = (string)model.AdditionalData[nameof(ns.NamespaceKeyName)]; ns.NamespaceName = model.Name; ns.Classes = model.Children.Select(CreateSerializableClass).ToArray(); return(ns); }
private static ModuleCoverageInfo CreateSerializableModule(CoverageNodeModel model) { var module = new ModuleCoverageInfo(); module.ModuleName = model.Name; module.ImageSize = (int)model.AdditionalData[nameof(module.ImageSize)]; module.ImageLinkTime = (int)model.AdditionalData[nameof(module.ImageLinkTime)]; module.LinesCovered = model.LinesCovered; module.LinesPartiallyCovered = model.LinesPartiallyCovered; module.LinesNotCovered = model.LinesNotCovered; module.BlocksCovered = model.BlocksCovered; module.BlocksNotCovered = model.BlocksNotCovered; module.Namespaces = model.Children.Select(CreateSerializableNamespace).ToArray(); return(module); }
private static MethodCoverageInfo CreateSerializableFunction(CoverageNodeModel model) { var meth = new MethodCoverageInfo(); meth.MethodKeyName = (string)model.AdditionalData[nameof(meth.MethodKeyName)]; meth.MethodName = model.Name; meth.MethodFullName = (string)model.AdditionalData[nameof(meth.MethodFullName)]; meth.LinesCovered = model.LinesCovered; meth.LinesPartiallyCovered = model.LinesPartiallyCovered; meth.LinesNotCovered = model.LinesNotCovered; meth.BlocksCovered = model.BlocksCovered; meth.BlocksNotCovered = model.BlocksNotCovered; meth.Lines = (LineCoverageInfo[])model.AdditionalData[nameof(meth.Lines)]; return(meth); }
private static ClassCoverageInfo CreateSerializableClass(CoverageNodeModel model) { var cls = new ClassCoverageInfo(); cls.ClassKeyName = (string)model.AdditionalData[nameof(cls.ClassKeyName)]; cls.ClassName = model.Name; cls.LinesCovered = model.LinesCovered; cls.LinesNotCovered = model.LinesNotCovered; cls.LinesPartiallyCovered = model.LinesPartiallyCovered; cls.BlocksCovered = model.BlocksCovered; cls.BlocksNotCovered = model.BlocksNotCovered; cls.NamespaceKeyName = (string)model.AdditionalData[nameof(cls.NamespaceKeyName)]; cls.Methods = model.Children.Select(CreateSerializableFunction).ToArray(); return(cls); }
private static CoverageNodeModel ReadFunction(MethodCoverageInfo meth) { var model = new CoverageNodeModel(CoverageNodeType.Function); model.Name = meth.MethodName; model.LinesCovered = meth.LinesCovered; model.LinesPartiallyCovered = meth.LinesPartiallyCovered; model.LinesNotCovered = meth.LinesNotCovered; model.BlocksCovered = meth.BlocksCovered; model.BlocksNotCovered = meth.BlocksNotCovered; model.AdditionalData[nameof(meth.MethodKeyName)] = meth.MethodKeyName; model.AdditionalData[nameof(meth.MethodFullName)] = meth.MethodFullName; model.AdditionalData[nameof(meth.Lines)] = meth.Lines; return(model); }
/// <summary> /// Loads the metadata for the given model. /// </summary> /// <param name="model">The model to read into.</param> public void LoadMetadataFor(CoverageNodeModel model) { if (!model.HasReadMetadata) { switch (model.NodeType) { case CoverageNodeType.CoverageFile: case CoverageNodeType.Module: case CoverageNodeType.Namespace: // nothing to simplify break; case CoverageNodeType.Type: LoadTypeMetadata(model); break; case CoverageNodeType.Function: { // read the metadata for the declaring type. var cls = model.ClosestAncestor(CoverageNodeType.Type); if (cls != null) { LoadMetadataFor(cls); } break; } default: throw Utility.UnreachableCode("Unexpected coverage node type."); } foreach (var child in model.Children) { LoadMetadataFor(child); } } }
/// <summary> /// Gets the namespace-qualified name of the given coverage node. /// </summary> /// <param name="model">The coverage node to get the qualified name of.</param> /// <returns>The name of the coverage node, up to and including namespaces.</returns> private static string GetNamespaceQualifiedName(CoverageNodeModel model) { var parts = new Stack <string>(); while (model != null && model.NodeType != CoverageNodeType.CoverageFile && model.NodeType != CoverageNodeType.Module) { if (model.NodeType != CoverageNodeType.Type) { parts.Push(model.Name); } else { // replace '.' in nested class names with '+'s parts.Push(model.Name.Replace('.', '+')); } model = model.Parent; } return(string.Join(".", parts)); }
private static CoverageNodeModel ReadModule(ModuleCoverageInfo mod) { var model = new CoverageNodeModel(CoverageNodeType.Module); model.Name = mod.ModuleName; model.AdditionalData[nameof(mod.ImageSize)] = mod.ImageSize; model.AdditionalData[nameof(mod.ImageLinkTime)] = mod.ImageLinkTime; model.LinesCovered = mod.LinesCovered; model.LinesPartiallyCovered = mod.LinesPartiallyCovered; model.LinesNotCovered = mod.LinesNotCovered; model.BlocksCovered = mod.BlocksCovered; model.BlocksNotCovered = mod.BlocksNotCovered; foreach (var ns in mod.Namespaces) { model.Children.Add(ReadNamespace(ns)); } return(model); }