diff --git a/.gitignore b/.gitignore index a9a94d914..f3f186f5a 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,8 @@ coverity.zip #SharpDevelop /**/OpenCover/coverage.xml + +#sonarqube +/.sonarqube +!tools/sonarqube/**/* +/main/OpenCover.SonarQube.sdf diff --git a/README.md b/README.md index 64fbe27a7..06002e2c4 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,11 @@ OpenCover is a code coverage tool for .NET 2 and above (Windows OSs only - no MO The latest releases can be downloaded from [releases](https://github.com/opencover/opencover/releases) or from the OpenCover mirror site on [bitbucket](https://bitbucket.org/shaunwilde/opencover/downloads). **Alternatively** why not try the [nuget](http://nuget.org/packages/opencover) package (this is the most popular). -[![Build status](https://img.shields.io/appveyor/ci/sawilde/opencover.svg)](https://ci.appveyor.com/project/sawilde/opencover) -[![Coverage](https://img.shields.io/coveralls/OpenCover/opencover/master.svg)](https://coveralls.io/r/OpenCover/opencover) -[![Coverity](https://scan.coverity.com/projects/3921/badge.svg)](https://scan.coverity.com/projects/opencover-opencover) -[![Nuget](https://img.shields.io/nuget/dt/opencover.svg)](http://nuget.org/packages/opencover) -[![Nuget](https://img.shields.io/nuget/v/opencover.svg)](http://nuget.org/packages/opencover) -[![Nuget](https://img.shields.io/nuget/vpre/opencover.svg)](http://nuget.org/packages/opencover) +| Build | [![Build status](https://img.shields.io/appveyor/ci/sawilde/opencover.svg)](https://ci.appveyor.com/project/sawilde/opencover) | +| --- | --- | +| **Coverage** | [![Coverage](https://img.shields.io/coveralls/OpenCover/opencover/master.svg)](https://coveralls.io/r/OpenCover/opencover) [![Coverity](https://scan.coverity.com/projects/3921/badge.svg)](https://scan.coverity.com/projects/opencover-opencover) | +| **Nuget** | [![Nuget](https://img.shields.io/nuget/dt/opencover.svg)](http://nuget.org/packages/opencover) [![Nuget](https://img.shields.io/nuget/v/opencover.svg)](http://nuget.org/packages/opencover) [![Nuget](https://img.shields.io/nuget/vpre/opencover.svg)](http://nuget.org/packages/opencover) | +| **Lead Times** | [![Issue Stats](http://issuestats.com/github/opencover/opencover/badge/pr)](http://issuestats.com/github/opencover/opencover) [![Issue Stats](http://issuestats.com/github/opencover/opencover/badge/issue)](http://issuestats.com/github/opencover/opencover) | ### Master The primary repo for the project is [on GitHub](https://github.com/opencover/opencover/) and is also where the [wiki](https://github.com/OpenCover/opencover/wiki) and [issues](https://github.com/OpenCover/opencover/wiki) are managed from. diff --git a/appveyor.yml b/appveyor.yml index de3d5422b..78cf48df7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,6 +9,10 @@ environment: secure: rw3Pk+YPWTG7xG7AaJx8wpxnYAOXM1/7HTRahQGuCHc= COVERITY_EMAIL: secure: lgy4M/uQ9jMlxmPzTIYWVE2GggvPntq6kfpO6Z0pjAs= + SONARQUBE_USER: + secure: +9YfPnwJzGsvdyto85pHwg== + SONARQUBE_PASSWORD: + secure: bGKR0fiOKZo/cNuigVxuUw== cache: - build/Version/opencover.snk - build/Version/opencover.public.snk @@ -21,6 +25,7 @@ build_script: } else { & .\build.bat create-release } + test: off artifacts: - path: main/bin/installer/*.msi @@ -71,6 +76,8 @@ notifications: on_build_status_changed: true on_success: - ps: >- - if ($env:APPVEYOR_SCHEDULED_BUILD -ne "True" -and $env:APPVEYOR_REPO_BRANCH -ne "coverity") { + if (-Not $env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_SCHEDULED_BUILD -ne "True" -and $env:APPVEYOR_REPO_BRANCH -ne "coverity") { + & .\build.bat sonarqube-build + } else { & .\build.bat dogfood-release - } \ No newline at end of file + } diff --git a/default.build b/default.build index 5edc0bbb1..0efc97524 100644 --- a/default.build +++ b/default.build @@ -16,6 +16,8 @@ + + @@ -78,13 +80,41 @@ + commandline='--form token=${coverity.token} --insecure --form email=${coverity.email} --form file=@coverity.zip --form version="${ci.fullBuildNumber}" --form description="${ci.fullBuildNumber}" https://scan.coverity.com/builds?project=OpenCover%2Fopencover' /> - + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + diff --git a/main/OpenCover.3rdParty.Signer/CrashReporterSigner.cs b/main/OpenCover.3rdParty.Signer/CrashReporterSigner.cs index f01331edf..b64bb6dd4 100644 --- a/main/OpenCover.3rdParty.Signer/CrashReporterSigner.cs +++ b/main/OpenCover.3rdParty.Signer/CrashReporterSigner.cs @@ -27,6 +27,7 @@ public static bool AlreadySigned(string baseFolder) } catch { + return false; } } return false; diff --git a/main/OpenCover.3rdParty.Signer/GendarmeSigner.cs b/main/OpenCover.3rdParty.Signer/GendarmeSigner.cs index 458f95d3e..cbfcaea7d 100644 --- a/main/OpenCover.3rdParty.Signer/GendarmeSigner.cs +++ b/main/OpenCover.3rdParty.Signer/GendarmeSigner.cs @@ -28,6 +28,7 @@ public static bool AlreadySigned(string baseFolder) } catch { + return false; } } return false; diff --git a/main/OpenCover.3rdParty.Signer/SigningExtensions.cs b/main/OpenCover.3rdParty.Signer/SigningExtensions.cs index 51d56d84e..f87ed2c29 100644 --- a/main/OpenCover.3rdParty.Signer/SigningExtensions.cs +++ b/main/OpenCover.3rdParty.Signer/SigningExtensions.cs @@ -11,7 +11,10 @@ public static void SignFile(this AssemblyDefinition definition, string outputPat using (var stream = new FileStream(key, FileMode.Open, FileAccess.Read)) { var keyPair = new StrongNameKeyPair(stream); - definition.Write(outputPath, new WriterParameters() { StrongNameKeyPair = keyPair }); + definition.Write(outputPath, new WriterParameters + { + StrongNameKeyPair = keyPair + }); } } } diff --git a/main/OpenCover.Console/OpenCover.Console.csproj b/main/OpenCover.Console/OpenCover.Console.csproj index 8b9b5581b..68291f2b5 100644 --- a/main/OpenCover.Console/OpenCover.Console.csproj +++ b/main/OpenCover.Console/OpenCover.Console.csproj @@ -54,6 +54,7 @@ false ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules true + false ..\bin\Release\ @@ -73,6 +74,7 @@ false false true + false ..\Icons\Icon.ico diff --git a/main/OpenCover.Console/Program.cs b/main/OpenCover.Console/Program.cs index 5e8076555..674439e5f 100644 --- a/main/OpenCover.Console/Program.cs +++ b/main/OpenCover.Console/Program.cs @@ -45,10 +45,9 @@ static int Main(string[] args) try { - //throw new NullReferenceException(); - CommandLineParser parser; - if (!ParseCommandLine(args, out parser)) return parser.ReturnCodeOffset + 1; + if (!ParseCommandLine(args, out parser)) + return parser.ReturnCodeOffset + 1; LogManager.GetRepository().Threshold = parser.LogLevel; @@ -58,7 +57,8 @@ static int Main(string[] args) var perfCounter = CreatePerformanceCounter(parser); string outputFile; - if (!GetFullOutputFile(parser, out outputFile)) return returnCodeOffset + 1; + if (!GetFullOutputFile(parser, out outputFile)) + return returnCodeOffset + 1; using (var container = new Bootstrapper(Logger)) { @@ -385,7 +385,8 @@ private static int RunProcess(CommandLineParser parser, Action private static void DisplayResults(CoverageSession coverageSession, ICommandLine parser, ILog logger) { - if (!logger.IsInfoEnabled) return; + if (!logger.IsInfoEnabled) + return; var altTotalClasses = 0; var altVisitedClasses = 0; @@ -403,15 +404,12 @@ from module in coverageSession.Modules.Where(x=>x.Classes != null) from @class in module.Classes.Where(c => !c.ShouldSerializeSkippedDueTo()) select @class) { - if (@class.Methods == null) continue; + if (@class.Methods == null) + continue; - if ((@class.Methods.Any(x => !x.ShouldSerializeSkippedDueTo() && x.SequencePoints.Any(y => y.VisitCount > 0)))) - { - } - else if ((@class.Methods.Any(x => x.FileRef != null))) - { - unvisitedClasses.Add(@class.FullName); - } + if (!(@class.Methods.Any(x => !x.ShouldSerializeSkippedDueTo() && x.SequencePoints.Any(y => y.VisitCount > 0)))) + if ((@class.Methods.Any(x => x.FileRef != null))) + unvisitedClasses.Add(@class.FullName); if (@class.Methods.Any(x => x.Visited)) { @@ -425,13 +423,9 @@ from @class in module.Classes.Where(c => !c.ShouldSerializeSkippedDueTo()) foreach (var method in @class.Methods.Where(x=> !x.ShouldSerializeSkippedDueTo())) { - if ((method.SequencePoints.Any(x => x.VisitCount > 0))) - { - } - else if (method.FileRef != null) - { - unvisitedMethods.Add(string.Format("{0}", method.FullName)); - } + if (!(method.SequencePoints.Any(x => x.VisitCount > 0))) + if (method.FileRef != null) + unvisitedMethods.Add(string.Format("{0}", method.FullName)); altTotalMethods += 1; if (method.Visited) @@ -587,6 +581,7 @@ private static bool ParseCommandLine(string[] args, out CommandLineParser parser using (var service = new ServiceController(parser.Target)) { var name = service.DisplayName; + System.Console.WriteLine("Service '{0}' found", name); } } catch (Exception) diff --git a/main/OpenCover.Console/ServiceEnvironmentManagement.cs b/main/OpenCover.Console/ServiceEnvironmentManagement.cs index c9284b714..8a1c53009 100644 --- a/main/OpenCover.Console/ServiceEnvironmentManagement.cs +++ b/main/OpenCover.Console/ServiceEnvironmentManagement.cs @@ -16,15 +16,12 @@ */ using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Text; using OpenCover.Framework; -using System.ServiceProcess; -using System.ComponentModel; namespace OpenCover.Console { @@ -58,7 +55,7 @@ public void PrepareServiceEnvironment(string serviceName, ServiceEnvironment env // variables in the registry for the service, otherwise it's better to temporarily set it for the account, // assuming we can find out the account SID // Network Service works better with environments is better on the service too - var serviceAccountName = MachineQualifiedServiceAccountName(this._serviceName); + var serviceAccountName = MachineQualifiedServiceAccountName(_serviceName); if (serviceAccountName != "LocalSystem") { _serviceAccountSid = LookupAccountSid(serviceAccountName); @@ -83,7 +80,7 @@ public static string MachineQualifiedServiceAccountName(string serviceName) { serviceAccountName = Environment.MachineName + serviceAccountName.Substring(1); } - else if (serviceAccountName.ToLower().Contains("localsystem")) + else if (serviceAccountName.ToLowerInvariant().Contains("localsystem")) { serviceAccountName = "NT Authority\\SYSTEM"; } @@ -202,8 +199,7 @@ private string[] GetServicesEnvironment() private static unsafe int wcslen(char* s) { char* e; - for (e = s; *e != '\0'; e++) - ; + for (e = s; *e != '\0'; e++){/* intentionally do nothing */} return (int)(e - s); } diff --git a/main/OpenCover.Framework/Bootstrapper.cs b/main/OpenCover.Framework/Bootstrapper.cs index fa66ba6c5..d40e8472b 100644 --- a/main/OpenCover.Framework/Bootstrapper.cs +++ b/main/OpenCover.Framework/Bootstrapper.cs @@ -81,7 +81,8 @@ public void Initialise(IFilter filter, /// 2 public void Dispose() { - if (_container == null) return; + if (_container == null) + return; _container.Dispose(); _container = null; } diff --git a/main/OpenCover.Framework/CommandLineParser.cs b/main/OpenCover.Framework/CommandLineParser.cs index b080b1ef9..b1a41e9f9 100644 --- a/main/OpenCover.Framework/CommandLineParser.cs +++ b/main/OpenCover.Framework/CommandLineParser.cs @@ -300,9 +300,9 @@ private static List ExtractFilters(string rawFilters) return (from Match myMatch in myRegex.Matches(rawFilters) where myMatch.Success select myMatch.Value.Trim()).ToList(); } - private static List ExtractSkipped(string skipped) + private static List ExtractSkipped(string skippedArg) { - if (string.IsNullOrWhiteSpace(skipped)) skipped = "All"; + var skipped = string.IsNullOrWhiteSpace(skippedArg) ? "All" : skippedArg; var options = skipped.Split(';'); var list = new List(); foreach (var option in options) @@ -334,7 +334,8 @@ private TimeSpan ParseTimeoutValue(string timeoutValue) var match = Regex.Match(timeoutValue, @"((?\d+)m)?((?\d+)s)?"); if (match.Success) { - int minutes = 0, seconds = 0; + int minutes = 0; + int seconds = 0; var minutesMatch = match.Groups["minutes"]; if (minutesMatch.Success) @@ -368,7 +369,8 @@ private static Exception ExceptionForInvalidArgumentValue(string argumentName, s private void ValidateArguments() { - if (PrintUsage || PrintVersion) return; + if (PrintUsage || PrintVersion) + return; if (string.IsNullOrWhiteSpace(Target)) { diff --git a/main/OpenCover.Framework/CommandLineParserBase.cs b/main/OpenCover.Framework/CommandLineParserBase.cs index dc03f7b86..345eb01d5 100644 --- a/main/OpenCover.Framework/CommandLineParserBase.cs +++ b/main/OpenCover.Framework/CommandLineParserBase.cs @@ -36,36 +36,51 @@ protected CommandLineParserBase(string[] arguments) /// protected void ParseArguments() { - if (_arguments == null) return; - if (ParsedArguments.Count > 0) return; + if (_arguments == null) + return; + if (ParsedArguments.Count > 0) + return; foreach (var argument in _arguments) { - var trimmed = argument.Trim(); - if (string.IsNullOrEmpty(trimmed)) continue; - - if (!trimmed.StartsWith("-")) - throw new InvalidOperationException(string.Format("The argument '{0}' is not recognised", argument)); - - trimmed = trimmed.Substring(1); - if (string.IsNullOrEmpty(trimmed)) continue; - - var colonidx = trimmed.IndexOf(':'); - if (colonidx>0) - { - var arg = trimmed.Substring(0, colonidx); - var val = trimmed.Substring(colonidx + 1); - if (!ParsedArguments.ContainsKey(arg)) - ParsedArguments.Add(arg, val); - else - ParsedArguments[arg] = (ParsedArguments[arg] + " " + val).Trim(); - } + string trimmed; + if (ExtractTrimmedArgument(argument, out trimmed)) + continue; + + ExtractArgumentValue(trimmed); + } + } + + private void ExtractArgumentValue(string trimmed) + { + var colonidx = trimmed.IndexOf(':'); + if (colonidx > 0) + { + var arg = trimmed.Substring(0, colonidx); + var val = trimmed.Substring(colonidx + 1); + if (!ParsedArguments.ContainsKey(arg)) + ParsedArguments.Add(arg, val); else - { - if (!ParsedArguments.ContainsKey(trimmed)) - ParsedArguments.Add(trimmed, String.Empty); - } + ParsedArguments[arg] = (ParsedArguments[arg] + " " + val).Trim(); } + else + { + if (!ParsedArguments.ContainsKey(trimmed)) + ParsedArguments.Add(trimmed, String.Empty); + } + } + + private static bool ExtractTrimmedArgument(string argument, out string trimmed) + { + trimmed = argument.Trim(); + if (string.IsNullOrEmpty(trimmed)) + return true; + + if (!trimmed.StartsWith("-")) + throw new InvalidOperationException(string.Format("The argument '{0}' is not recognised", argument)); + + trimmed = trimmed.Substring(1); + return string.IsNullOrEmpty(trimmed); } /// diff --git a/main/OpenCover.Framework/Communication/MessageHandler.cs b/main/OpenCover.Framework/Communication/MessageHandler.cs index 0ab052d15..b528444a9 100644 --- a/main/OpenCover.Framework/Communication/MessageHandler.cs +++ b/main/OpenCover.Framework/Communication/MessageHandler.cs @@ -108,6 +108,8 @@ public int StandardMessage(MSG_Type msgType, IManagedCommunicationBlock mcb, Act case MSG_Type.MSG_TrackProcess: writeSize = HandleTrackProcessMessage(pinnedMemory); break; + default: + throw new InvalidOperationException(); } return writeSize; diff --git a/main/OpenCover.Framework/Communication/Messages.cs b/main/OpenCover.Framework/Communication/Messages.cs index 34e618dd1..e2d34bee7 100644 --- a/main/OpenCover.Framework/Communication/Messages.cs +++ b/main/OpenCover.Framework/Communication/Messages.cs @@ -11,9 +11,13 @@ namespace OpenCover.Framework.Communication /// The command supportd by the host /// // ReSharper disable InconsistentNaming - // ReSharper disable once EnumUnderlyingTypeIsInt - public enum MSG_Type : int + public enum MSG_Type { + /// + /// This message is unknown of course + /// + MSG_Unknown = -1, + /// /// Does this assembly have any code that can be covered /// diff --git a/main/OpenCover.Framework/Filter.cs b/main/OpenCover.Framework/Filter.cs index 129c5eb80..b1534d5cf 100644 --- a/main/OpenCover.Framework/Filter.cs +++ b/main/OpenCover.Framework/Filter.cs @@ -10,7 +10,6 @@ using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using log4net; -using log4net.Repository.Hierarchy; using Mono.Cecil; using OpenCover.Framework.Filtering; @@ -39,7 +38,7 @@ public class Filter : IFilter /// Standard constructor /// /// Indicates if the input strings for this class are already Regular Expressions - public Filter(bool useRegexFilters = false) + public Filter(bool useRegexFilters) { InclusionFilters = new List(); ExclusionFilters = new List(); @@ -58,34 +57,51 @@ public Filter(bool useRegexFilters = false) /// as it is the class that is being filtered within these unless the class filter is * public bool UseAssembly(string processPath, string assemblyPath) { - var processName = string.Empty; - if (processPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) { // avoids ArgumentException - processName = Path.GetFileNameWithoutExtension(processPath); - } - var assemblyName = string.Empty; - if (assemblyPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) { // avoids ArgumentException - assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); - } - var matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyPath); - if (!string.IsNullOrEmpty(assemblyName) && assemblyName != assemblyPath) { matchingExclusionFilters.AddRange (ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); } - if (matchingExclusionFilters.Any(exclusionFilter => exclusionFilter.ClassName == ".*" && ((!string.IsNullOrEmpty(processName) && exclusionFilter.IsMatchingProcessName(processName)) || exclusionFilter.IsMatchingProcessName(processPath)))) - { + string assemblyName; + bool assemblyNameAdd; + IList matchingExclusionFilters; + if (!ExtractExclusionFilters(processPath, assemblyPath, out assemblyName, out assemblyNameAdd, out matchingExclusionFilters)) return false; - } if (matchingExclusionFilters.Any(exclusionFilter => exclusionFilter.ClassName != ".*")) - { return true; - } var matchingInclusionFilters = InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyPath); - if (!string.IsNullOrEmpty(assemblyName) && assemblyName != assemblyPath) { matchingInclusionFilters.AddRange (InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); } - if (matchingInclusionFilters.Any()) + if (assemblyNameAdd) + matchingInclusionFilters.AddRange(InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); + + return matchingInclusionFilters.Any(); + } + + private bool ExtractExclusionFilters(string processPath, string assemblyPath, out string assemblyName, + out bool assemblyNameAdd, out IList matchingExclusionFilters) + { + var processName = string.Empty; + var processNameAdd = false; + if (processPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) { - return true; + // avoids ArgumentException + processName = Path.GetFileNameWithoutExtension(processPath); + processNameAdd = !string.IsNullOrEmpty(processName) && processName != processPath; } - - return false; + assemblyName = string.Empty; + assemblyNameAdd = false; + if (assemblyPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) + { + // avoids ArgumentException + assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); + assemblyNameAdd = !string.IsNullOrEmpty(assemblyName) && assemblyName != assemblyPath; + } + matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyPath); + if (assemblyNameAdd) + { + matchingExclusionFilters.AddRange(ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); + } + return !matchingExclusionFilters.Any( + exclusionFilter => + exclusionFilter.ClassName == ".*" && + ((processNameAdd && exclusionFilter.IsMatchingProcessName(processName)) || + exclusionFilter.IsMatchingProcessName(processPath))); } /// @@ -102,20 +118,11 @@ public bool InstrumentClass(string processPath, string assemblyPath, string clas return false; } - var processName = string.Empty; - if (processPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) { // avoids ArgumentException - processName = Path.GetFileNameWithoutExtension(processPath); // can return null - } - var assemblyName = string.Empty; - if (assemblyPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) { // avoids ArgumentException - assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); // can return null - } - var matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyPath); - if (!string.IsNullOrEmpty(assemblyName) && assemblyName != assemblyPath) { matchingExclusionFilters.AddRange (ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); } - if (matchingExclusionFilters.Any(exclusionFilter => exclusionFilter.ClassName == ".*" && ((!string.IsNullOrEmpty(processName) && exclusionFilter.IsMatchingProcessName(processName)) || exclusionFilter.IsMatchingProcessName(processPath)))) - { + string assemblyName; + bool assemblyNameAdd; + IList matchingExclusionFilters; + if (!ExtractExclusionFilters(processPath, assemblyPath, out assemblyName, out assemblyNameAdd, out matchingExclusionFilters)) return false; - } if (matchingExclusionFilters .Where(exclusionFilter => exclusionFilter.ClassName != ".*") @@ -125,13 +132,10 @@ public bool InstrumentClass(string processPath, string assemblyPath, string clas } var matchingInclusionFilters = InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyPath); - if (!string.IsNullOrEmpty(assemblyName) && assemblyName != assemblyPath) { matchingInclusionFilters.AddRange (InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); } - if (matchingInclusionFilters.Any(inclusionFilter => inclusionFilter.IsMatchingClassName(className))) - { - return true; - } + if (assemblyNameAdd) + matchingInclusionFilters.AddRange(InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); - return false; + return matchingInclusionFilters.Any(inclusionFilter => inclusionFilter.IsMatchingClassName(className)); } @@ -154,22 +158,22 @@ public bool InstrumentClass(string assemblyPath, string className) /// public void AddFilter(string processAssemblyClassFilter) { - string _assemblyFilter; - string _classFilter; - string _processFilter; + string assemblyFilter; + string classFilter; + string processFilter; FilterType filterType; - GetAssemblyClassName(processAssemblyClassFilter, RegExFilters, out filterType, out _assemblyFilter, out _classFilter, out _processFilter); + GetAssemblyClassName(processAssemblyClassFilter, RegExFilters, out filterType, out assemblyFilter, out classFilter, out processFilter); try { if (!RegExFilters) { - _processFilter = (string.IsNullOrEmpty(_processFilter) ? "*" : _processFilter).ValidateAndEscape("<>|\""); // Path.GetInvalidPathChars except *? - _assemblyFilter = _assemblyFilter.ValidateAndEscape(); - _classFilter = _classFilter.ValidateAndEscape(); + processFilter = (string.IsNullOrEmpty(processFilter) ? "*" : processFilter).ValidateAndEscape("<>|\""); // Path.GetInvalidPathChars except *? + assemblyFilter = assemblyFilter.ValidateAndEscape(); + classFilter = classFilter.ValidateAndEscape(); } - var filter = new AssemblyAndClassFilter(_processFilter, _assemblyFilter, _classFilter); + var filter = new AssemblyAndClassFilter(processFilter, assemblyFilter, classFilter); if (filterType == FilterType.Inclusion) InclusionFilters.Add(filter); @@ -228,48 +232,72 @@ public void AddAttributeExclusionFilters(string[] exclusionFilters) /// /// Is this entity (method/type) excluded due to an attributeFilter /// - /// The entity to test + /// The entity to test /// - public bool ExcludeByAttribute(IMemberDefinition entity) + public bool ExcludeByAttribute(IMemberDefinition originalEntity) { if (ExcludedAttributes.Count == 0) return false; + var entity = originalEntity; while (true) { if (entity == null) return false; - if (ExcludeByAttribute((ICustomAttributeProvider)entity)) - return true; - - if (ExcludeByAttribute(entity.DeclaringType)) - return true; + bool excludeByAttribute; + if (IsExcludedByAttributeSimple(entity, out excludeByAttribute)) + return excludeByAttribute; - if (entity.DeclaringType == null || !entity.Name.StartsWith("<")) + MethodDefinition target; + if (!GetDeclaringMethod(entity, out target)) return false; - var match = Regex.Match(entity.Name, @"\<(?.+)\>.+"); - if (match.Groups["name"] == null) return false; - var name = match.Groups["name"].Value; - var target = entity.DeclaringType.Methods.FirstOrDefault(m => m.Name == name); - if (target == null) return false; - if (target.IsGetter) + if (target.IsGetter || target.IsSetter) { - var getMethod = entity.DeclaringType.Properties.FirstOrDefault(p => p.GetMethod == target); - entity = getMethod; - continue; - } - if (target.IsSetter) - { - var setMethod = entity.DeclaringType.Properties.FirstOrDefault(p => p.SetMethod == target); - entity = setMethod; + entity = entity.DeclaringType.Properties.FirstOrDefault(p => p.GetMethod == target || p.SetMethod == target); continue; } entity = target; } } + /// + /// Look for the declaring method e.g. if method is some type of lambda, getter/setter etc + /// + /// + /// + /// + private static bool GetDeclaringMethod(IMemberDefinition entity, out MethodDefinition target) + { + target = null; + var match = Regex.Match(entity.Name, @"\<(?.+)\>.+"); + if (match.Groups["name"] == null) + return false; + + var name = match.Groups["name"].Value; + target = entity.DeclaringType.Methods.FirstOrDefault(m => m.Name == name); + if (target == null) + return false; + return true; + } + + private bool IsExcludedByAttributeSimple(IMemberDefinition entity, out bool excludeByAttribute) + { + excludeByAttribute = true; + if (ExcludeByAttribute((ICustomAttributeProvider) entity)) + return true; + + if (ExcludeByAttribute(entity.DeclaringType)) + return true; + + if (entity.DeclaringType != null && entity.Name.StartsWith("<")) + return false; + + excludeByAttribute = false; + return true; + } + private bool ExcludeByAttribute(ICustomAttributeProvider entity) { return (from excludeAttribute in ExcludedAttributes @@ -285,10 +313,7 @@ where excludeAttribute.IsMatchingExpression(customAttribute.AttributeType.FullNa /// public bool ExcludeByAttribute(AssemblyDefinition entity) { - if (ExcludedAttributes.Count == 0) - return false; - - return ExcludeByAttribute((ICustomAttributeProvider)entity); + return ExcludedAttributes.Count != 0 && ExcludeByAttribute((ICustomAttributeProvider)entity); } /// @@ -357,18 +382,20 @@ public bool IsAutoImplementedProperty(MethodDefinition method) public bool InstrumentProcess(string processPath) { if (string.IsNullOrEmpty(processPath)) - { return false; - } - if (!ExclusionFilters.Any() && !InclusionFilters.Any()) return true; + + if (!ExclusionFilters.Any() && !InclusionFilters.Any()) + return true; var processName = string.Empty; + var processNameAdd = false; if (processPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) { // avoids ArgumentException processName = Path.GetFileNameWithoutExtension(processPath); + processNameAdd = !string.IsNullOrWhiteSpace(processName) && processName != processPath; } if (ExclusionFilters.Any()) { var matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForProcessName(processPath); - if (!string.IsNullOrWhiteSpace (processName) && processName != processPath) { + if (processNameAdd) { matchingExclusionFilters.AddRange(ExclusionFilters.GetMatchingFiltersForProcessName(processName)); } if (matchingExclusionFilters.Any @@ -384,7 +411,7 @@ public bool InstrumentProcess(string processPath) if (InclusionFilters.Any()) { var matchingInclusionFilters = InclusionFilters.GetMatchingFiltersForProcessName(processPath); - if (!string.IsNullOrWhiteSpace (processName) && processName != processPath) { + if (processNameAdd) { matchingInclusionFilters.AddRange(InclusionFilters.GetMatchingFiltersForProcessName(processName)); } return matchingInclusionFilters.Any(); diff --git a/main/OpenCover.Framework/Filtering/FilterHelper.cs b/main/OpenCover.Framework/Filtering/FilterHelper.cs index c0c80d49b..a30dae4fa 100644 --- a/main/OpenCover.Framework/Filtering/FilterHelper.cs +++ b/main/OpenCover.Framework/Filtering/FilterHelper.cs @@ -13,11 +13,9 @@ internal static string WrapWithAnchors(this string data) internal static string ValidateAndEscape(this string match, string notAllowed = @"\[]") { - if (match.IndexOfAny(notAllowed.ToCharArray()) >= 0) throw new InvalidOperationException(String.Format("The string is invalid for an filter name {0}", match)); - match = match.Replace(@"\", @"\\"); - match = match.Replace(@".", @"\."); - match = match.Replace(@"*", @".*"); - return match; + if (match.IndexOfAny(notAllowed.ToCharArray()) >= 0) + throw new InvalidOperationException(String.Format("The string is invalid for an filter name {0}", match)); + return match.Replace(@"\", @"\\").Replace(@".", @"\.").Replace(@"*", @".*"); } internal static IList GetMatchingFiltersForAssemblyName(this IEnumerable filters, string assemblyName) diff --git a/main/OpenCover.Framework/Filtering/RegexFilter.cs b/main/OpenCover.Framework/Filtering/RegexFilter.cs index ee1f01d91..5b432a243 100644 --- a/main/OpenCover.Framework/Filtering/RegexFilter.cs +++ b/main/OpenCover.Framework/Filtering/RegexFilter.cs @@ -5,24 +5,19 @@ namespace OpenCover.Framework.Filtering { internal class RegexFilter { - private readonly Lazy regex; + private readonly Lazy _regex; internal string FilterExpression { get; private set; } public RegexFilter(string filterExpression, bool shouldWrapExpression = true) { FilterExpression = filterExpression; - if (shouldWrapExpression) - { - filterExpression = filterExpression.WrapWithAnchors(); - } - - regex = new Lazy(() => new Regex(filterExpression)); + _regex = new Lazy(() => new Regex(shouldWrapExpression ? filterExpression.WrapWithAnchors() : filterExpression)); } public bool IsMatchingExpression(string input) { - return regex.Value.IsMatch(input); + return _regex.Value.IsMatch(input); } } } diff --git a/main/OpenCover.Framework/HelperExtensions.cs b/main/OpenCover.Framework/HelperExtensions.cs index aa3122f1d..ae3cd2777 100644 --- a/main/OpenCover.Framework/HelperExtensions.cs +++ b/main/OpenCover.Framework/HelperExtensions.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace OpenCover.Framework { diff --git a/main/OpenCover.Framework/Manager/MemoryManager.cs b/main/OpenCover.Framework/Manager/MemoryManager.cs index aab48c4c8..9c659b021 100644 --- a/main/OpenCover.Framework/Manager/MemoryManager.cs +++ b/main/OpenCover.Framework/Manager/MemoryManager.cs @@ -44,7 +44,6 @@ public class ManagedBlock protected string MakeName(string name, int id) { var newName = string.Format("{0}{1}{2}{3}", Namespace, name, Key, id); - //Console.WriteLine(newName); return newName; } } @@ -275,7 +274,8 @@ public void Initialise(string @namespace, string key, IEnumerable servic { lock (_lockObject) { - if (_isIntialised) return; + if (_isIntialised) + return; _namespace = @namespace; _key = key; _servicePrincipal = servicePrincipal.ToArray(); @@ -295,7 +295,8 @@ public ManagedBufferBlock AllocateMemoryBuffer(int bufferSize, out uint bufferId lock (_lockObject) { - if (!_isIntialised) return null; + if (!_isIntialised) + return null; bufferId = _bufferId++; var tuple = new ManagedBufferBlock { @@ -316,8 +317,12 @@ public ManagedBufferBlock AllocateMemoryBuffer(int bufferSize, out uint bufferId /// public IList GetBlocks { - get { - lock (_lockObject) { return _blocks; } + get + { + lock (_lockObject) + { + return _blocks; + } } } @@ -330,7 +335,8 @@ public void DeactivateMemoryBuffer(uint bufferId) lock (_lockObject) { var block = _blocks.FirstOrDefault(b => b.BufferId == bufferId); - if (block == null) return; + if (block == null) + return; block.Active = false; } } @@ -342,7 +348,8 @@ public void RemoveDeactivatedBlock(ManagedBufferBlock block) { lock (_lockObject) { - if (block.Active) return; + if (block.Active) + return; block.CommunicationBlock.Do(x => x.Dispose()); block.MemoryBlock.Do(x => x.Dispose()); _blocks.RemoveAt(_blocks.IndexOf(block)); diff --git a/main/OpenCover.Framework/Manager/ProfilerManager.cs b/main/OpenCover.Framework/Manager/ProfilerManager.cs index d10db9a74..8db9d40c8 100644 --- a/main/OpenCover.Framework/Manager/ProfilerManager.cs +++ b/main/OpenCover.Framework/Manager/ProfilerManager.cs @@ -39,17 +39,22 @@ public class ProfilerManager : IProfilerManager private ConcurrentQueue _messageQueue; - private readonly object syncRoot = new object (); + private readonly object _syncRoot = new object (); /// /// Syncronisation Root /// public object SyncRoot { get { - return syncRoot; + return _syncRoot; } } + /// + /// wait for how long + /// + internal static int BufferWaitCount { get; set; } + private static readonly ILog DebugLogger = LogManager.GetLogger("DebugLogger"); private class ThreadTermination @@ -192,13 +197,13 @@ private WaitCallback SaveVisitData(EventWaitHandle queueMgmt) }; } - /// - /// wait for how long - /// - internal static int BufferWaitCount = 30; - private bool _continueWait = true; + static ProfilerManager() + { + BufferWaitCount = 30; + } + private void ProcessMessages(WaitHandle[] handles) { var threadHandles = new List(); @@ -220,6 +225,8 @@ private void ProcessMessages(WaitHandle[] handles) } })); break; + default: + break; } } while (_continueWait); @@ -336,7 +343,7 @@ private WaitCallback ProcessBlock(ManagedBufferBlock block, } while (_messageQueue.Count > 200); } break; - case 2: + default: // 2 return; } } diff --git a/main/OpenCover.Framework/Model/InstrumentationModelBuilder.cs b/main/OpenCover.Framework/Model/InstrumentationModelBuilder.cs index 8c50055de..1492d89a2 100644 --- a/main/OpenCover.Framework/Model/InstrumentationModelBuilder.cs +++ b/main/OpenCover.Framework/Model/InstrumentationModelBuilder.cs @@ -9,6 +9,7 @@ using System.Security.Cryptography; using Mono.Cecil; using OpenCover.Framework.Symbols; +using OpenCover.Framework.Utility; namespace OpenCover.Framework.Model { @@ -34,15 +35,22 @@ public Module BuildModuleModel(bool full) private Module CreateModule(bool full) { var hash = string.Empty; + var timeStamp = DateTime.MinValue; if (System.IO.File.Exists(_symbolManager.ModulePath)) { + try { + timeStamp = System.IO.File.GetLastWriteTime(_symbolManager.ModulePath); + } catch (Exception e) { + e.InformUser(); + } hash = HashFile(_symbolManager.ModulePath); } var module = new Module { ModuleName = _symbolManager.ModuleName, - FullName = _symbolManager.ModulePath, - ModuleHash = hash + ModulePath = _symbolManager.ModulePath, + ModuleHash = hash, + ModuleTime = timeStamp }; module.Aliases.Add(_symbolManager.ModulePath); @@ -60,12 +68,12 @@ private Module CreateModule(bool full) public Module BuildModuleTestModel(Module module, bool full) { - module = module ?? CreateModule(full); - module.TrackedMethods = _symbolManager.GetTrackedMethods(); - return module; + var m = module ?? CreateModule(full); + m.TrackedMethods = _symbolManager.GetTrackedMethods(); + return m; } - private string HashFile(string sPath) + private static string HashFile(string sPath) { using (var sr = new StreamReader(sPath)) using (var prov = new SHA1CryptoServiceProvider()) diff --git a/main/OpenCover.Framework/Model/InstrumentationPoint.cs b/main/OpenCover.Framework/Model/InstrumentationPoint.cs index 68266f38f..6281c546d 100644 --- a/main/OpenCover.Framework/Model/InstrumentationPoint.cs +++ b/main/OpenCover.Framework/Model/InstrumentationPoint.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Threading; using System.Xml.Serialization; namespace OpenCover.Framework.Model @@ -13,7 +11,7 @@ namespace OpenCover.Framework.Model public class InstrumentationPoint { private static int _instrumentPoint; - private static object _addInstrumentPointSync = new object(); + private static readonly object LockObject = new object(); private static readonly List InstrumentPoints; static InstrumentationPoint() @@ -74,17 +72,17 @@ public static int GetVisitCount(uint spid) } /// - /// Add a number of recorded visit pints against this identifier + /// Add a number of recorded visit ppints against this identifier /// /// the sequence point identifier - NOTE 0 is not used /// the id of a tracked method - Note 0 means no method currently tracking - /// the number of visit points to add - public static bool AddVisitCount(uint spid, uint trackedMethodId, int sum = 1) + /// the number of visit points to add + public static bool AddVisitCount(uint spid, uint trackedMethodId, int amount) { if (spid != 0 && spid < InstrumentPoints.Count) { var point = InstrumentPoints[(int) spid]; - point.VisitCount += sum; + point.VisitCount += amount; if (point.VisitCount < 0) point.VisitCount = int.MaxValue; if (trackedMethodId != 0) @@ -93,12 +91,12 @@ public static bool AddVisitCount(uint spid, uint trackedMethodId, int sum = 1) var tracked = point._tracked.Find(x => x.UniqueId == trackedMethodId); if (tracked == null) { - tracked = new TrackedMethodRef {UniqueId = trackedMethodId, VisitCount = sum}; + tracked = new TrackedMethodRef {UniqueId = trackedMethodId, VisitCount = amount}; point._tracked.Add(tracked); } else { - tracked.VisitCount += sum; + tracked.VisitCount += amount; if (tracked.VisitCount < 0) tracked.VisitCount = int.MaxValue; } @@ -115,7 +113,7 @@ public static bool AddVisitCount(uint spid, uint trackedMethodId, int sum = 1) /// public InstrumentationPoint() { - lock (_addInstrumentPointSync) + lock (LockObject) { UniqueSequencePoint = (uint)++_instrumentPoint; InstrumentPoints.Add(this); @@ -165,7 +163,8 @@ public TrackedMethodRef[] TrackedMethodRefs set { _tracked = null; - if (value == null) return; + if (value == null) + return; _tracked = new List(value); } } diff --git a/main/OpenCover.Framework/Model/Method.cs b/main/OpenCover.Framework/Model/Method.cs index 9dc76a762..1da2bb5c7 100644 --- a/main/OpenCover.Framework/Model/Method.cs +++ b/main/OpenCover.Framework/Model/Method.cs @@ -31,15 +31,35 @@ public class Method : SummarySkippedEntity /// public FileRef FileRef { get; set; } + internal UInt32 FileRefUniqueId { + get { return FileRef == null? 0 : FileRef.UniqueId; } + } + /// /// A list of sequence points that have been produced for this method /// - public SequencePoint[] SequencePoints { get; set; } + public SequencePoint[] SequencePoints { + get { + return _sequencePoints; + } + set { + _sequencePoints = value ?? new SequencePoint[0]; + } + } + private SequencePoint[] _sequencePoints = new SequencePoint[0]; /// /// A list of branch points that have been identified for this method /// - public BranchPoint[] BranchPoints { get; set; } + public BranchPoint[] BranchPoints { + get { + return _branchPoints; + } + set { + _branchPoints = value ?? new BranchPoint[0]; + } + } + private BranchPoint[] _branchPoints = new BranchPoint[0]; /// /// A method point to identify the entry of a method @@ -111,7 +131,8 @@ public class Method : SummarySkippedEntity public override void MarkAsSkipped(SkippedMethod reason) { SkippedDueTo = reason; - if (MethodPoint != null) MethodPoint.IsSkipped = true; + if (MethodPoint != null) + MethodPoint.IsSkipped = true; MethodPoint = null; SequencePoints = null; BranchPoints = null; @@ -125,9 +146,9 @@ public override void MarkAsSkipped(SkippedMethod reason) internal bool IsGenerated { get { if (_resolvedIsGenerated == null) { - _resolvedIsGenerated = !String.IsNullOrWhiteSpace(this.FullName) - && this.FullName.Contains("__") // quick test before using regex heavy weapon - && isGeneratedMethodRegex.IsMatch(this.FullName); + _resolvedIsGenerated = !string.IsNullOrWhiteSpace(FullName) + && FullName.Contains("__") // quick test before using regex heavy weapon + && IsGeneratedMethodRegex.IsMatch(FullName); } return _resolvedIsGenerated == true; } @@ -138,14 +159,15 @@ internal bool IsGenerated { /// internal string CallName { get { - if (_resolvedCallName != null) { return _resolvedCallName; } // cached - _resolvedCallName = String.Empty; // init resolve value - if (!String.IsNullOrWhiteSpace(this.FullName)) { - int startIndex = this.FullName.IndexOf("::", StringComparison.Ordinal); + if (_resolvedCallName != null) + return _resolvedCallName; + _resolvedCallName = string.Empty; // init resolve value + if (!string.IsNullOrWhiteSpace(FullName)) { + var startIndex = FullName.IndexOf("::", StringComparison.Ordinal); startIndex += 2; - int finalIndex = this.FullName.IndexOf('(', startIndex); + var finalIndex = FullName.IndexOf('(', startIndex); if (startIndex > 1 && finalIndex > startIndex) { - _resolvedCallName = this.FullName // resolve cache + _resolvedCallName = FullName // resolve cache .Substring(startIndex, finalIndex - startIndex); } } @@ -153,10 +175,10 @@ internal string CallName { } } - private bool? _resolvedIsGenerated = null; - private string _resolvedCallName = null; - private static readonly RegexOptions regexOptions = RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture; - private static readonly Regex isGeneratedMethodRegex = new Regex(@"(<[^\s:>]+>\w__\w)", regexOptions); + private bool? _resolvedIsGenerated; + private string _resolvedCallName; + private const RegexOptions RegexOptions = System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Singleline | System.Text.RegularExpressions.RegexOptions.ExplicitCapture; + private static readonly Regex IsGeneratedMethodRegex = new Regex(@"(<[^\s:>]+>\w__\w)", RegexOptions); #endregion diff --git a/main/OpenCover.Framework/Model/Module.cs b/main/OpenCover.Framework/Model/Module.cs index 0a3b2bd6e..759704f56 100644 --- a/main/OpenCover.Framework/Model/Module.cs +++ b/main/OpenCover.Framework/Model/Module.cs @@ -4,6 +4,7 @@ // This source code is released under the MIT License; see the accompanying license file. // +using System; using System.Collections.Generic; using System.Xml.Serialization; @@ -25,7 +26,12 @@ public Module() /// /// The full path name to the module /// - public string FullName { get; set; } + public string ModulePath { get; set; } + + /// + /// GetlastWriteTime + /// + public DateTime ModuleTime { get; set; } /// /// A list of aliases diff --git a/main/OpenCover.Framework/Model/SequencePoint.cs b/main/OpenCover.Framework/Model/SequencePoint.cs index 1f1a62221..a335babcb 100644 --- a/main/OpenCover.Framework/Model/SequencePoint.cs +++ b/main/OpenCover.Framework/Model/SequencePoint.cs @@ -66,7 +66,15 @@ public class SequencePoint : InstrumentationPoint, IDocumentReference [XmlAttribute("url")] public string Document { get; set; } - internal List BranchPoints { get; set; } + internal List BranchPoints { + get{ + return _branchPoints; + } + set{ + _branchPoints = value ?? new List(); + } + } + private List _branchPoints = new List(); /// /// Property diff --git a/main/OpenCover.Framework/Persistance/BasePersistance.cs b/main/OpenCover.Framework/Persistance/BasePersistance.cs index 8bcf0630b..4c7dfe498 100644 --- a/main/OpenCover.Framework/Persistance/BasePersistance.cs +++ b/main/OpenCover.Framework/Persistance/BasePersistance.cs @@ -65,9 +65,9 @@ public void PersistModule(Module module) { if ( !existingModule.Aliases.Any( - x => x.Equals(module.FullName, StringComparison.InvariantCultureIgnoreCase))) + x => x.Equals(module.ModulePath, StringComparison.InvariantCultureIgnoreCase))) { - existingModule.Aliases.Add(module.FullName); + existingModule.Aliases.Add(module.ModulePath); } return; } @@ -157,46 +157,49 @@ public bool IsTracking(string modulePath) /// public virtual void Commit() { - if (CoverageSession.Modules != null) { - MarkSkippedMethods(); - TransformSequences(); - CalculateCoverage(); - if (CommandLine.HideSkipped != null && CommandLine.HideSkipped.Any()) { - foreach (var skippedMethod in CommandLine.HideSkipped.OrderBy(x => x)) - { - switch (skippedMethod) - { - case SkippedMethod.File: - RemoveSkippedMethods(SkippedMethod.File); - RemoveEmptyClasses(); - RemoveUnreferencedFiles(); - break; - case SkippedMethod.Filter: - RemoveSkippedModules(SkippedMethod.Filter); - RemoveSkippedClasses(SkippedMethod.Filter); - break; - case SkippedMethod.MissingPdb: - RemoveSkippedModules(SkippedMethod.MissingPdb); - break; - case SkippedMethod.Attribute: - RemoveSkippedClasses(SkippedMethod.Attribute); - RemoveSkippedMethods(SkippedMethod.Attribute); - RemoveEmptyClasses(); - break; - case SkippedMethod.AutoImplementedProperty: - RemoveSkippedMethods(SkippedMethod.Attribute); - RemoveEmptyClasses(); - break; - } - } - } - } + if (CoverageSession.Modules == null) + return; + MarkSkippedMethods(); + TransformSequences(); + CalculateCoverage(); + if (CommandLine.HideSkipped == null || !CommandLine.HideSkipped.Any()) + return; + foreach (var skippedMethod in CommandLine.HideSkipped.OrderBy(x => x)) + ProcessSkippedAction(skippedMethod); + } + private void ProcessSkippedAction(SkippedMethod skippedMethod) + { + switch (skippedMethod) + { + case SkippedMethod.File: + RemoveSkippedMethods(SkippedMethod.File); + RemoveEmptyClasses(); + RemoveUnreferencedFiles(); + break; + case SkippedMethod.Filter: + RemoveSkippedModules(SkippedMethod.Filter); + RemoveSkippedClasses(SkippedMethod.Filter); + break; + case SkippedMethod.MissingPdb: + RemoveSkippedModules(SkippedMethod.MissingPdb); + break; + case SkippedMethod.Attribute: + RemoveSkippedClasses(SkippedMethod.Attribute); + RemoveSkippedMethods(SkippedMethod.Attribute); + RemoveEmptyClasses(); + break; + case SkippedMethod.AutoImplementedProperty: + RemoveSkippedMethods(SkippedMethod.Attribute); + RemoveEmptyClasses(); + break; + } } private void RemoveSkippedModules(SkippedMethod skipped) { - if (CoverageSession.Modules == null) return; + if (CoverageSession.Modules == null) + return; var modules = CoverageSession.Modules; modules = modules.Where(x => x.SkippedDueTo != skipped).ToArray(); CoverageSession.Modules = modules; @@ -204,10 +207,12 @@ private void RemoveSkippedModules(SkippedMethod skipped) private void RemoveSkippedClasses(SkippedMethod skipped) { - if (CoverageSession.Modules == null) return; + if (CoverageSession.Modules == null) + return; foreach (var module in CoverageSession.Modules) { - if (module.Classes == null) continue; + if (module.Classes == null) + continue; var classes = module.Classes.Where(x => x.SkippedDueTo != skipped).ToArray(); module.Classes = classes; } @@ -215,13 +220,16 @@ private void RemoveSkippedClasses(SkippedMethod skipped) private void RemoveSkippedMethods(SkippedMethod skipped) { - if (CoverageSession.Modules == null) return; + if (CoverageSession.Modules == null) + return; foreach (var module in CoverageSession.Modules) { - if (module.Classes == null) continue; + if (module.Classes == null) + continue; foreach (var @class in module.Classes) { - if (@class.Methods == null) continue; + if (@class.Methods == null) + continue; var methods = @class.Methods.Where(x => x.SkippedDueTo != skipped).ToArray(); @class.Methods = methods; } @@ -230,22 +238,25 @@ private void RemoveSkippedMethods(SkippedMethod skipped) private void RemoveEmptyClasses() { - if (CoverageSession.Modules == null) return; + if (CoverageSession.Modules == null) + return; foreach (var module in CoverageSession.Modules) { - if (module.Classes == null) continue; + if (module.Classes == null) + continue; module.Classes = module.Classes.Where(@class => @class.Methods != null && @class.Methods.Any()).ToArray(); } } private void RemoveUnreferencedFiles() { - if (CoverageSession.Modules == null) return; + if (CoverageSession.Modules == null) + return; foreach (var module in CoverageSession.Modules) { module.Files = (from file in module.Files ?? new File[0] from @class in module.Classes ?? new Class[0] - where (@class.Methods ?? new Method[0]).Where(x=>x.FileRef != null).Any(x => x.FileRef.UniqueId == file.UniqueId) + where (@class.Methods ?? new Method[0]).Where(x=>x.FileRef != null).Any(x => x.FileRefUniqueId == file.UniqueId) select file).Distinct().ToArray(); } } @@ -272,86 +283,128 @@ private void CalculateCoverage() foreach (var @class in (module.Classes ?? new Class[0]).Where(x => x != null && !x.ShouldSerializeSkippedDueTo())) { foreach (var method in (@class.Methods ?? new Method[0]).Where(x => x != null && !x.ShouldSerializeSkippedDueTo())) - { - if (method.MethodPoint != null) - { - method.Visited = (method.MethodPoint.VisitCount > 0); - } + ProcessMethodData(method, @class); - method.Summary.NumBranchPoints = method.BranchPoints == null ? 0 : method.BranchPoints.Count(); - method.Summary.VisitedBranchPoints = method.BranchPoints == null ? 0 : method.BranchPoints.Count(pt => pt.VisitCount != 0); - method.Summary.NumSequencePoints = method.SequencePoints == null ? 0 : method.SequencePoints.Count(); - method.Summary.VisitedSequencePoints = method.SequencePoints == null ? 0 : method.SequencePoints.Count(pt => pt.VisitCount != 0); + ProcessClassData(@class, module); + } + ProcessModuleData(module); + } + CalculateCoverage(CoverageSession.Summary); + } - if (method.Summary.NumSequencePoints > 0) - method.Summary.NumBranchPoints += 1; + private void ProcessModuleData(Module module) + { + AddPoints(CoverageSession.Summary, module.Summary); + CalculateCoverage(module.Summary); - if (method.Summary.VisitedSequencePoints > 0) - method.Summary.VisitedBranchPoints += 1; + if (CoverageSession.Summary.MinCyclomaticComplexity == 0) + CoverageSession.Summary.MinCyclomaticComplexity = module.Summary.MinCyclomaticComplexity; - if (method.FileRef != null) - { - method.Summary.NumMethods = 1; - method.Summary.VisitedMethods = (method.Visited) ? 1 : 0; - } + CoverageSession.Summary.MinCyclomaticComplexity = Math.Min(CoverageSession.Summary.MinCyclomaticComplexity, + module.Summary.MinCyclomaticComplexity); + CoverageSession.Summary.MaxCyclomaticComplexity = Math.Max(CoverageSession.Summary.MaxCyclomaticComplexity, + module.Summary.MaxCyclomaticComplexity); + } - AddPoints(@class.Summary, method.Summary); - CalculateCoverage(method.Summary); + private static void ProcessClassData(Class @class, Module module) + { + @class.Summary.NumClasses = (@class.Summary.NumMethods > 0) ? 1 : 0; + @class.Summary.VisitedClasses = (@class.Summary.VisitedMethods > 0) ? 1 : 0; - method.SequenceCoverage = method.Summary.SequenceCoverage; - method.BranchCoverage = method.Summary.BranchCoverage; + AddPoints(module.Summary, @class.Summary); + CalculateCoverage(@class.Summary); - method.Summary.MinCyclomaticComplexity = method.Summary.MaxCyclomaticComplexity = Math.Max(1, method.CyclomaticComplexity); + if (module.Summary.MinCyclomaticComplexity == 0) + module.Summary.MinCyclomaticComplexity = @class.Summary.MinCyclomaticComplexity; - method.NPathComplexity = 0; - var nPaths = new Dictionary(); - if (method.BranchPoints != null && method.BranchPoints.Length != 0) { - foreach (var bp in method.BranchPoints) { - if (!Object.ReferenceEquals(bp, null) && nPaths.ContainsKey(bp.Offset)) { - nPaths[bp.Offset] += 1; - } else { - nPaths.Add(bp.Offset, 1); - } - } - } - foreach(var branches in nPaths.Values) { - if (method.NPathComplexity == 0) { - method.NPathComplexity = branches; - } else { - method.NPathComplexity *= branches; - } - } + module.Summary.MinCyclomaticComplexity = Math.Min(module.Summary.MinCyclomaticComplexity, + @class.Summary.MinCyclomaticComplexity); + module.Summary.MaxCyclomaticComplexity = Math.Max(module.Summary.MaxCyclomaticComplexity, + @class.Summary.MaxCyclomaticComplexity); + } - if (@class.Summary.MinCyclomaticComplexity == 0) - @class.Summary.MinCyclomaticComplexity = method.Summary.MinCyclomaticComplexity; - - @class.Summary.MinCyclomaticComplexity = Math.Min(@class.Summary.MinCyclomaticComplexity, method.CyclomaticComplexity); - @class.Summary.MaxCyclomaticComplexity = Math.Max(@class.Summary.MaxCyclomaticComplexity, method.CyclomaticComplexity); - } + private static void ProcessMethodData(Method method, Class @class) + { + if (method.MethodPoint != null) + { + method.Visited = (method.MethodPoint.VisitCount > 0); + } - @class.Summary.NumClasses = (@class.Summary.NumMethods > 0) ? 1 : 0; - @class.Summary.VisitedClasses = (@class.Summary.VisitedMethods > 0) ? 1 : 0; + method.Summary.NumBranchPoints = method.BranchPoints == null ? 0 : method.BranchPoints.Count(); + method.Summary.VisitedBranchPoints = method.BranchPoints == null + ? 0 + : method.BranchPoints.Count(pt => pt.VisitCount != 0); + method.Summary.NumSequencePoints = method.SequencePoints == null ? 0 : method.SequencePoints.Count(); + method.Summary.VisitedSequencePoints = method.SequencePoints == null + ? 0 + : method.SequencePoints.Count(pt => pt.VisitCount != 0); - AddPoints(module.Summary, @class.Summary); - CalculateCoverage(@class.Summary); + if (method.Summary.NumSequencePoints > 0) + method.Summary.NumBranchPoints += 1; - if (module.Summary.MinCyclomaticComplexity == 0) - module.Summary.MinCyclomaticComplexity = @class.Summary.MinCyclomaticComplexity; + if (method.Summary.VisitedSequencePoints > 0) + method.Summary.VisitedBranchPoints += 1; - module.Summary.MinCyclomaticComplexity = Math.Min(module.Summary.MinCyclomaticComplexity, @class.Summary.MinCyclomaticComplexity); - module.Summary.MaxCyclomaticComplexity = Math.Max(module.Summary.MaxCyclomaticComplexity, @class.Summary.MaxCyclomaticComplexity); - } + if (method.FileRef != null) + { + method.Summary.NumMethods = 1; + method.Summary.VisitedMethods = (method.Visited) ? 1 : 0; + } - AddPoints(CoverageSession.Summary, module.Summary); - CalculateCoverage(module.Summary); + AddPoints(@class.Summary, method.Summary); + CalculateCoverage(method.Summary); - if (CoverageSession.Summary.MinCyclomaticComplexity == 0) - CoverageSession.Summary.MinCyclomaticComplexity = module.Summary.MinCyclomaticComplexity; + method.SequenceCoverage = method.Summary.SequenceCoverage; + method.BranchCoverage = method.Summary.BranchCoverage; - CoverageSession.Summary.MinCyclomaticComplexity = Math.Min(CoverageSession.Summary.MinCyclomaticComplexity, module.Summary.MinCyclomaticComplexity); - CoverageSession.Summary.MaxCyclomaticComplexity = Math.Max(CoverageSession.Summary.MaxCyclomaticComplexity, module.Summary.MaxCyclomaticComplexity); + CalculateNPathComplexity(method); + + CalculateCyclomaticComplexity(method, @class); + } + + private static void CalculateCyclomaticComplexity(Method method, Class @class) + { + method.Summary.MinCyclomaticComplexity = Math.Max(1, method.CyclomaticComplexity); + method.Summary.MaxCyclomaticComplexity = method.Summary.MinCyclomaticComplexity; + + if (@class.Summary.MinCyclomaticComplexity == 0) + @class.Summary.MinCyclomaticComplexity = method.Summary.MinCyclomaticComplexity; + + @class.Summary.MinCyclomaticComplexity = Math.Min(@class.Summary.MinCyclomaticComplexity, + method.CyclomaticComplexity); + @class.Summary.MaxCyclomaticComplexity = Math.Max(@class.Summary.MaxCyclomaticComplexity, + method.CyclomaticComplexity); + } + + private static void CalculateNPathComplexity(Method method) + { + method.NPathComplexity = 0; + var nPaths = new Dictionary(); + if (method.BranchPoints != null && method.BranchPoints.Length != 0) + { + foreach (var bp in method.BranchPoints.Where(b => b != null)) + { + if (nPaths.ContainsKey(bp.Offset)) + { + nPaths[bp.Offset] += 1; + } + else + { + nPaths.Add(bp.Offset, 1); + } + } + } + foreach (var branches in nPaths.Values) + { + if (method.NPathComplexity == 0) + { + method.NPathComplexity = branches; + } + else + { + method.NPathComplexity *= branches; + } } - CalculateCoverage(CoverageSession.Summary); } private static void MapFileReferences(IEnumerable points, IDictionary filesDictionary) @@ -444,14 +497,14 @@ public bool GetBranchPointsForFunction(string modulePath, int functionToken, out private Method GetMethod(string modulePath, int functionToken, out Class @class) { @class = null; - //c = null; lock (Protection) { var module = CoverageSession.Modules .FirstOrDefault(x => x.Aliases.Any(path => path.Equals(modulePath, StringComparison.InvariantCultureIgnoreCase))); if (module == null) return null; - if (!_moduleMethodMap[module].ContainsKey(functionToken)) return null; + if (!_moduleMethodMap[module].ContainsKey(functionToken)) + return null; var pair = _moduleMethodMap[module][functionToken]; @class = pair.Key; return pair.Value; @@ -489,7 +542,7 @@ public void SaveVisitData(byte[] data) var spid = BitConverter.ToUInt32(data, idx); if (spid < (uint)MSG_IdType.IT_MethodEnter) { - if (!InstrumentationPoint.AddVisitCount(spid, _trackedMethodId)) + if (!InstrumentationPoint.AddVisitCount(spid, _trackedMethodId, 1)) { _logger.ErrorFormat("Failed to add a visit to {0} with tracking method {1}. Max point count is {2}", spid, _trackedMethodId, InstrumentationPoint.Count); @@ -548,8 +601,8 @@ private void TransformSequences() { TransformSequences_Initialize (methods); TransformSequences_JoinWithBranches (methods); TransformSequences_AddSources (module.Files, methods, sourceRepository); - TransformSequences_RemoveCompilerGeneratedBranches (methods, sourceRepository); - TransformSequences_RemoveFalsePositiveUnvisited (methods, sourceRepository); + TransformSequences_RemoveCompilerGeneratedBranches (methods, sourceRepository, module.ModuleTime); + TransformSequences_RemoveFalsePositiveUnvisited (methods, sourceRepository, module.ModuleTime); TransformSequences_ReduceBranches (methods); // last } } @@ -558,50 +611,17 @@ private void TransformSequences() { static void TransformSequences_Initialize (IEnumerable methods) { foreach (var method in methods) { - #region Cleanup - // remove nulls - if (method.SequencePoints == null) - method.SequencePoints = new SequencePoint[0]; - if (method.BranchPoints == null) - method.BranchPoints = new BranchPoint[0]; // No sequences in method, but branches present? => remove branches if (method.SequencePoints.Length == 0 && method.BranchPoints.Length != 0) { method.BranchPoints = new BranchPoint[0]; } - #endregion - } - } - - private static void TransformSequences_AddSources (IEnumerable files, IEnumerable methods, IDictionary sourceRepository) - { - if (files == null || !files.Any()) return; - - // Dictionary with stored source file names per module - var filesDictionary = new Dictionary(); - - foreach (var file in files. - Where (file => !String.IsNullOrWhiteSpace(file.FullPath) - && !filesDictionary.ContainsKey(file.FullPath))) - { - var source = CodeCoverageStringTextSource.GetSource(file.FullPath); - if (source != null && source.FileType == FileType.CSharp) sourceRepository.Add (file.UniqueId, source); - filesDictionary.Add(file.FullPath, file.UniqueId); - } - - foreach (var method in methods) { - #region Add file references - if (method.SequencePoints.Length != 0) - MapFileReferences(method.SequencePoints, filesDictionary); - if (method.BranchPoints.Length != 0) - MapFileReferences(method.BranchPoints, filesDictionary); - #endregion } } private static void TransformSequences_JoinWithBranches (IEnumerable methods) { foreach (var method in methods) { - #region Join BranchPoints children to SequencePoint parent + if (method.SequencePoints.Length != 0 && method.BranchPoints.Length != 0) { // Quick match branches to sequence using SP&BP sort order by IL offset // SP & BP are sorted by offset and code below expect both SP & BP to be sorted by offset @@ -623,35 +643,63 @@ private static void TransformSequences_JoinWithBranches (IEnumerable met } } } - #endregion } } - // Compiled for speed, treat as .Singleline for multiline SequencePoint, do not waste time to capture Groups (speed) - private static readonly RegexOptions regexOptions = RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture; - // "Contract" and "." and "Requires/Ensures" can be separated by spaces and newlines (valid c# syntax)! - private static readonly Regex contractRegex = new Regex(@"^Contract\s*\.\s*(Requi|Ensu)res", regexOptions); - - private static void TransformSequences_RemoveCompilerGeneratedBranches (IEnumerable methods, SourceRepository sourceRepository) + private static void TransformSequences_AddSources (IEnumerable files, IEnumerable methods, IDictionary sourceRepository) { + if (files == null || !files.Any()) + return; + + // Dictionary with stored source file names per module + var filesDictionary = new Dictionary(); + + foreach (var file in files. + Where (file => !String.IsNullOrWhiteSpace(file.FullPath) + && !filesDictionary.ContainsKey(file.FullPath))) + { + var source = CodeCoverageStringTextSource.GetSource(file.FullPath); // never reurns null + if (source.FileType == FileType.CSharp) + sourceRepository.Add (file.UniqueId, source); + filesDictionary.Add(file.FullPath, file.UniqueId); + } + foreach (var method in methods) { - - if (method == null - || method.FileRef == null - || method.FileRef.UniqueId == 0 - || method.SequencePoints == null - || method.SequencePoints.Length == 0 - ) { - continue; - } + if (method.SequencePoints.Length != 0) + MapFileReferences(method.SequencePoints, filesDictionary); + if (method.BranchPoints.Length != 0) + MapFileReferences(method.BranchPoints, filesDictionary); + } + } + private static void TransformSequences_RemoveCompilerGeneratedBranches (IEnumerable methods, SourceRepository sourceRepository, DateTime moduleTime) + { + foreach (var method in methods + .Where (m => m.FileRefUniqueId != 0 + && m.SequencePoints.Length != 0)) { + // Get method source if availabile - CodeCoverageStringTextSource source = sourceRepository.GetCodeCoverageStringTextSource(method.FileRef.UniqueId); + var source = sourceRepository.GetCodeCoverageStringTextSource(method.FileRefUniqueId); + if (source != null) { - // Do we have C# source? - if (source != null && source.FileType == FileType.CSharp ) { + if (source.IsChanged (moduleTime)) { + ("Source file is modified: " + source.FilePath).InformUser(); + return; + } + + if (!TransformSequences_RemoveCompilerGeneratedBranches (method, source)) { + return; // empty sequence found -> source.IsChanged (failed access to file-times) + } + } + } + } + + private static bool TransformSequences_RemoveCompilerGeneratedBranches (Method method, CodeCoverageStringTextSource source) + { + // Do we have C# source? + if (source.FileType == FileType.CSharp) { - #region Use sorted SequencePoint's offset and content to Remove Compiler Generated Branches + if (source.FileFound) { // initialize offset with unreachable values long startOffset = long.MinValue; @@ -660,66 +708,179 @@ private static void TransformSequences_RemoveCompilerGeneratedBranches (IEnumera if (!method.IsGenerated) { // order SequencePoints by source order (Line/Column) - var sourceLineOrderedSps = method.SequencePoints.OrderBy(sp => sp.StartLine).ThenBy(sp => sp.StartColumn).Where(sp => sp.FileId == method.FileRef.UniqueId).ToArray(); + var sourceLineOrderedSps = method.SequencePoints.OrderBy(sp => sp.StartLine).ThenBy(sp => sp.StartColumn).Where(sp => sp.FileId == method.FileRefUniqueId).ToArray(); // find getter/setter/static-method "{" offset - if (sourceLineOrderedSps.Length > 0 && sourceRepository.IsLeftCurlyBraceSequencePoint(sourceLineOrderedSps[0])) { + if (sourceLineOrderedSps.Length > 0 && source.GetText(sourceLineOrderedSps[0]) == "{") { startOffset = sourceLineOrderedSps[0].Offset; // find method "}" offset - if (sourceLineOrderedSps.Length > 1 && sourceRepository.IsRightCurlyBraceSequencePoint(sourceLineOrderedSps.Last())) { + if (sourceLineOrderedSps.Length > 1 && source.GetText(sourceLineOrderedSps.Last()) == "}") { finalOffset = sourceLineOrderedSps.Last().Offset; } } // find method "{" offset - else if (sourceLineOrderedSps.Length > 1 && sourceRepository.IsLeftCurlyBraceSequencePoint(sourceLineOrderedSps[1])) { + else if (sourceLineOrderedSps.Length > 1 && source.GetText(sourceLineOrderedSps[1]) == "{") { startOffset = sourceLineOrderedSps[1].Offset; // find method "}" offset - if (sourceLineOrderedSps.Length > 2 && sourceRepository.IsRightCurlyBraceSequencePoint(sourceLineOrderedSps.Last())) { - finalOffset = sourceLineOrderedSps.Last().Offset; - } - } else { // "{" not found, try to find "}" offset - if (sourceLineOrderedSps.Length > 1 && sourceRepository.IsRightCurlyBraceSequencePoint(sourceLineOrderedSps.Last())) { + if (sourceLineOrderedSps.Length > 2 && source.GetText(sourceLineOrderedSps.Last()) == "}") { finalOffset = sourceLineOrderedSps.Last().Offset; } + // "{" not found, try to find "}" offset + } else if (sourceLineOrderedSps.Length > 1 && source.GetText(sourceLineOrderedSps.Last()) == "}") { + finalOffset = sourceLineOrderedSps.Last().Offset; } } - // Method offsets found or not found, now check foreach sequence point + if (!TransformSequences_RemoveCompilerGeneratedBranches (method, source, startOffset, finalOffset)) { + return false; // return error/failure to caller + } + + } else { + + // Do as much possible without source + // This will remove generated branches within "{", "}" and "in" (single-line SequencePoints) + // but cannot remove Code Contract ccrewite generated branches foreach (var sp in method.SequencePoints) { - if (sp != null - && sp.FileId == method.FileRef.UniqueId - && sp.BranchPoints != null - && sp.BranchPoints.Count != 0) { - } else { - continue; + if (sp.BranchPoints.Count != 0 + && sp.StartLine == sp.EndLine + && sp.EndColumn - sp.StartColumn <= 2) { + + // Zero, one or two character sequence point should not contain branches + // Never found 0 character sequencePoint + // Never found 1 character sequencePoint except "{" and "}" + // Never found 2 character sequencePoint except "in" keyword + // Afaik, c# cannot express branch condition in one or two characters of source code + // "x|y" "if(x)" "while(x)" "switch(x){...}" "case:" "x?." "x??" "x==y" "x?y:z;" "for(...)" "foreach(...)" "x is y" + // "do" keyword does not generate SequencePoint + sp.BranchPoints = new List(); } + } + } + } + return true; + } - if (sp.Offset <= startOffset || sp.Offset >= finalOffset) { - // doRemoveBranches where .Offset <= startOffset"{" or finalOffset"}" <= .Offset - // this will exclude "{" and "}" compiler generated branches and majority of ccrewrite Code-Contract's + // Compiled for speed, treat as .Singleline for multiline SequencePoint, do not waste time to capture Groups (speed) + private static readonly RegexOptions regexOptions = RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture; + // "Contract" and "." and "Requires/Ensures" can be separated by spaces and newlines (valid c# syntax)! + private static readonly Regex contractRegex = new Regex(@"^Contract\s*\.\s*(Requi|Ensu)res", regexOptions); + + private static bool TransformSequences_RemoveCompilerGeneratedBranches (Method method, CodeCoverageStringTextSource source, long startOffset, long finalOffset) { + + // foreach sequence point + foreach (var sp in method.SequencePoints + .Where (sp => sp.FileId == method.FileRefUniqueId + && sp.BranchPoints.Count != 0)) { + + if (sp.Offset <= startOffset || sp.Offset >= finalOffset) { + // doRemoveBranches where .Offset <= startOffset"{" or finalOffset"}" <= .Offset + // this will exclude "{" and "}" compiler generated branches and majority of ccrewrite Code-Contract's + sp.BranchPoints = new List(); + + } else { // branches not removed + // check for other options by reading SequencePoint source + var text = source.GetText(sp); // text is never null + if (text == string.Empty) { + ("Empty sequence-point at line: " + sp.StartLine + " column: " + sp.StartColumn).InformUser(); + ("Source file: " + source.FilePath).InformUser(); + return false; // signal error to caller's caller loop (break) + } + // Contract.Requires/Ensures is occasionally left inside method offset + // Quick check for minimum length and "C" before using Regex + if (text.Length > 18 && text[0] == 'C') { + // Use Regex here! "Contract" and "." and "Requires/Ensures" + // can be separated by spaces and newlines + if (contractRegex.IsMatch(text)) { sp.BranchPoints = new List(); - } else { // branches not removed - // check for other options by reading SequencePoint source - var text = sourceRepository.GetSequencePointText(sp); - // Contract.Requires/Ensures is occasionally left inside method offset - // Quick check for "C" and minimum length before using Regex - if (text[0] == 'C' && text.Length > 18) { - // Use Regex here! "Contract" and "." and "Requires/Ensures" - // can be separated by spaces and newlines - if (contractRegex.IsMatch(text)) { - sp.BranchPoints = new List(); - } - // "in" keyword? - } else if (text == "in") { - // Remove generated ::MoveNext branches within "in" keyword - // Not always removed in CecilSymbolManager (enumerated KeyValuePair) - sp.BranchPoints = new List(); - } } + // "in" keyword? + } else if (text == "in") { + // Remove generated ::MoveNext branches within "in" keyword + // Not always removed in CecilSymbolManager (enumerated KeyValuePair) + sp.BranchPoints = new List(); } + } + } + return true; + } + + private static void TransformSequences_RemoveFalsePositiveUnvisited (IEnumerable methods, SourceRepository sourceRepository, DateTime moduleTime) + { + // From Methods with Source and visited SequencePoints + var sequencePointsQuery = methods + .Where (m => m.FileRefUniqueId != 0 && m.SequencePoints.Length != 0) + .SelectMany (m => m.SequencePoints) + .Where (sp => sp.FileId != 0 && sp.VisitCount != 0); + + var sequencePointsSet = new HashSet(new SequencePointComparer()); + var toRemoveMethodSequencePoint = new List>(); + + // Add unique visited SequencePoints to HashSet + foreach (var sp in sequencePointsQuery) { + if (!sequencePointsSet.Contains(sp)) { + sequencePointsSet.Add(sp); + } + } + + // Check generated methods + foreach (var method in methods + .Where (m => m.FileRefUniqueId != 0 + && m.SequencePoints.Length != 0 + && m.IsGenerated)) { + + // Select duplicate and false-positive unvisited sequence points + // (Sequence point duplicated by generated method and left unvisited) + foreach (var sp in method.SequencePoints + .Where (sp => sp.FileId == method.FileRefUniqueId + && sp.VisitCount == 0) ) { + + if (sequencePointsSet.Contains(sp)) { + // Unvisited duplicate found, add to remove list + toRemoveMethodSequencePoint.Add (new Tuple(method, sp)); + } + } + + // Get method source if availabile + var source = sourceRepository.GetCodeCoverageStringTextSource(method.FileRefUniqueId); + if (source != null && !source.IsChanged(moduleTime)) { + TransformSequences_RemoveFalsePositiveUnvisited (method, source, toRemoveMethodSequencePoint); + } - #endregion + } + + // Remove selected SequencePoints + foreach (var tuple in toRemoveMethodSequencePoint) { + tuple.Item1.SequencePoints = tuple.Item1.SequencePoints.Where(sp => sp != tuple.Item2).ToArray(); + } + } + + private static void TransformSequences_RemoveFalsePositiveUnvisited (Method method, CodeCoverageStringTextSource source, ICollection> toRemoveMethodSequencePoint) + { + // Select false unvisited right-curly-braces at generated "MoveNext" method + // (Curly braces moved to generated "MoveNext" method and left unvisited) + // Source is required here to identify curly braces + if (method.CallName == "MoveNext") { + // Do we have C# source? + if (source.FileFound && source.FileType == FileType.CSharp) { + + int countDown = 2; // remove up to two last right-curly-braces + foreach (var sp in method.SequencePoints.Reverse()) { + if (sp.FileId == method.FileRefUniqueId + && sp.IsSingleCharSequencePoint + && sp.VisitCount == 0) { // unvisited only + + if (countDown > 0) { + if (source.GetText(sp) == "}") { + toRemoveMethodSequencePoint.Add (new Tuple(method, sp)); + countDown -= 1; + } + } + else { + break; + } + } + } } } } @@ -733,14 +894,12 @@ private static void TransformSequences_ReduceBranches (IEnumerable metho { foreach (var method in methods) { - #region Merge Branch-Exits for each Sequence - // Collection of validBranchPoints (child/connected to parent SequencePoint) var validBranchPoints = new List(); var branchExits = new Dictionary(); foreach (var sp in method.SequencePoints) { // SequencePoint has branches attached? - if (sp.BranchPoints != null && sp.BranchPoints.Count != 0) { + if (sp.BranchPoints.Count != 0) { // Merge sp.BranchPoints using EndOffset as branchExits key branchExits.Clear(); foreach (var branchPoint in sp.BranchPoints) { @@ -769,210 +928,8 @@ private static void TransformSequences_ReduceBranches (IEnumerable metho // (Order by UniqueSequencePoint is equal to order by .Offset when .Offset is set) method.BranchPoints = validBranchPoints.OrderBy(bp => bp.UniqueSequencePoint).ToArray(); - #endregion } } - - private static void TransformSequences_RemoveFalsePositiveUnvisited (IEnumerable methods, SourceRepository sourceRepository) - { - // From Methods with Source and visited SequencePoints - var sequencePointsQuery = methods - .Where(m => m != null - && m.FileRef != null - && m.FileRef.UniqueId != 0 - && m.SequencePoints != null - && m.SequencePoints.Length != 0 - ) - .SelectMany (m => m.SequencePoints) - .Where(sp => sp != null && sp.FileId != 0 && sp.VisitCount != 0); - - var sequencePointsSet = new HashSet(new SequencePointComparer()); - var toRemoveMethodSequencePoint = new List>(); - - // Add unique visited SequencePoints to HashSet - foreach (var sp in sequencePointsQuery) { - if (!sequencePointsSet.Contains(sp)) { - sequencePointsSet.Add(sp); - } - } - - // select false-positive-unvisited - foreach (var method in methods) { - if (method != null - && method.FileRef != null - && method.FileRef.UniqueId != 0 - && method.SequencePoints != null - && method.SequencePoints.Length != 0 - && method.IsGenerated) { - } else { - continue; - } - - // Select duplicate and false-positive unvisited sequence points - // (Sequence point duplicated by generated method and left unvisited) - foreach (var sp in method.SequencePoints) { - if (sp != null - && sp.FileId == method.FileRef.UniqueId - && sp.VisitCount == 0) { // unvisited only - } else { - continue; - } - if (sequencePointsSet.Contains(sp)) { - // Unvisited duplicate found, add to remove list - toRemoveMethodSequencePoint.Add(new Tuple(method,sp)); - } - } - - // Select false unvisited right-curly-braces at generated "MoveNext" method - // (Curly braces moved to generated "MoveNext" method and left unvisited) - if (method.CallName == "MoveNext") { - int countDown = 2; // remove up to two last right-curly-braces - foreach (var sp in method.SequencePoints.Reverse()) { - if (sp != null - && sp.FileId != 0 - && sp.StartLine == sp.EndLine - && sp.StartColumn + 1 == sp.EndColumn - && sp.VisitCount == 0 // unvisited only - ) { - } else { - continue; - } - if (countDown > 0) { - if (sourceRepository.IsRightCurlyBraceSequencePoint(sp)) { - toRemoveMethodSequencePoint.Add(new Tuple(method, sp)); - countDown -= 1; - } - } - else { - break; - } - } - } - } - - // Remove selected SequencePoints - foreach (var tuple in toRemoveMethodSequencePoint) { - var cleanSequencePoints = new List(); - foreach (var sp in tuple.Item1.SequencePoints.Where(sp => sp != tuple.Item2)) { - cleanSequencePoints.Add(sp); - } - tuple.Item1.SequencePoints = cleanSequencePoints.ToArray(); - } - - #region ToDo - /* Problems: - * - * - * 1) Compiler can duplicate sequence point (found in DBCL project) - * Solution: DONE - * Remove unvisited duplicate? - * - * 2) Compiler can move SequencePoint into compiler generated method - * Solution? - * Identify compiler generated methods - * Match each with user method - * Move SequencePoints & branches into user method - * - * 3) Right braces at IEnumerator - * - * 100663434 - <_SetItems>b__b * System.Boolean DD.Collections.BitSetArray::<_SetItems>b__b(System.Int32) - * - * - Duplicate SP! * - * - * - * - * - * - Generated Method * - * - * 100663435 - <_SetItems>b__b_0* System.Boolean DD.Collections.BitSetArray::BitSetArray_<_SetItems>b__b_0(System.Int32) - * - * - Duplicate SP! * - * - * - * - * - * - User Method * - * - * 100663375 - * System.Void DD.Collections.BitSetArray::_SetItems(System.Collections.Generic.IEnumerable`1<System.Int32>) - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - */ - #endregion - } - } } diff --git a/main/OpenCover.Framework/ProfilerRegistration.cs b/main/OpenCover.Framework/ProfilerRegistration.cs index 21c1a7833..d076f9735 100644 --- a/main/OpenCover.Framework/ProfilerRegistration.cs +++ b/main/OpenCover.Framework/ProfilerRegistration.cs @@ -29,7 +29,7 @@ public class ExitApplicationWithoutReportingException : Exception /// Intentionally not unit tested - as this is calling regsvr32 which does what it does and does not need more testing from me /// [ExcludeFromCoverage("Intentionally not unit tested - as this is calling regsvr32 which does what it does and does not need more testing from me")] - public class ProfilerRegistration + public static class ProfilerRegistration { private const string UserRegistrationString = "/n /i:user"; @@ -62,7 +62,10 @@ public static void Unregister(Registration registration) private static void ExecuteRegsvr32(bool userRegistration, bool register) { ExecuteRegsvr32(userRegistration, register, false); - if (Environment.Is64BitOperatingSystem) { ExecuteRegsvr32(userRegistration, register, true); } + if (Environment.Is64BitOperatingSystem) + { + ExecuteRegsvr32(userRegistration, register, true); + } } private static int ExecuteProcess(ProcessStartInfo psi) diff --git a/main/OpenCover.Framework/Service/IProfilerCommunication.cs b/main/OpenCover.Framework/Service/IProfilerCommunication.cs index 2c17dab2a..eb9a760f3 100644 --- a/main/OpenCover.Framework/Service/IProfilerCommunication.cs +++ b/main/OpenCover.Framework/Service/IProfilerCommunication.cs @@ -3,27 +3,11 @@ // // This source code is released under the MIT License; see the accompanying license file. // -using System; -using System.Net.Security; + using OpenCover.Framework.Model; namespace OpenCover.Framework.Service { - //public class SequencePoint - //{ - // public UInt32 Ordinal { get; set; } - // public UInt32 UniqueId { get; set; } - // public int Offset { get; set; } - //} - - //public class BranchPoint - //{ - // public UInt32 Ordinal { get; set; } - // public UInt32 UniqueId { get; set; } - // public int Offset { get; set; } - // public int Path { get; set; } - //} - /// /// Defines the tye of operations the profiler will make /// diff --git a/main/OpenCover.Framework/Service/ProfilerCommunication.cs b/main/OpenCover.Framework/Service/ProfilerCommunication.cs index 21a367242..34ce65cd3 100644 --- a/main/OpenCover.Framework/Service/ProfilerCommunication.cs +++ b/main/OpenCover.Framework/Service/ProfilerCommunication.cs @@ -4,6 +4,7 @@ // This source code is released under the MIT License; see the accompanying license file. // using System; +using System.IO; using System.Linq; using OpenCover.Framework.Model; using OpenCover.Framework.Persistance; @@ -27,12 +28,12 @@ public ProfilerCommunication(IFilter filter, public bool TrackAssembly(string processPath, string modulePath, string assemblyName) { - if (_persistance.IsTracking(modulePath)) return true; + if (_persistance.IsTracking(modulePath)) + return true; Module module = null; var builder = _instrumentationModelBuilderFactory.CreateModelBuilder(modulePath, assemblyName); - var assemblyPath = assemblyName; - if (modulePath.Contains (assemblyName)) { assemblyPath = modulePath; } - if (!_filter.UseAssembly(processPath, assemblyPath)) + + if (!_filter.UseAssembly(processPath, assemblyName)) { module = builder.BuildModuleModel(false); module.MarkAsSkipped(SkippedMethod.Filter); diff --git a/main/OpenCover.Framework/Strategy/TrackedMethodStrategyManager.cs b/main/OpenCover.Framework/Strategy/TrackedMethodStrategyManager.cs index 664b1abb0..af3fc0209 100644 --- a/main/OpenCover.Framework/Strategy/TrackedMethodStrategyManager.cs +++ b/main/OpenCover.Framework/Strategy/TrackedMethodStrategyManager.cs @@ -31,7 +31,8 @@ public TrackedMethodStrategyProxy() public TrackedMethod[] GetTrackedMethods(string assembly) { var definition = AssemblyDefinition.ReadAssembly(assembly); - if (definition == null) return new TrackedMethod[0]; + if (definition == null) + return new TrackedMethod[0]; var trackedmethods = new List(); foreach (var trackedMethodStrategy in _strategies) @@ -89,7 +90,8 @@ public TrackedMethod[] GetTrackedMethods(string assembly) public void Dispose() { _proxy = null; - if (_domain == null) return; + if (_domain == null) + return; try { AppDomain.Unload(_domain); diff --git a/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs b/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs index b9b61d16e..ef5533a43 100644 --- a/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs +++ b/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs @@ -15,7 +15,6 @@ using OpenCover.Framework.Model; using OpenCover.Framework.Strategy; using log4net; -using OpenCover.Framework.Utility; using File = OpenCover.Framework.Model.File; using SequencePoint = OpenCover.Framework.Model.SequencePoint; @@ -34,7 +33,7 @@ public static MethodBody SafeGetMethodBody(this MethodDefinition methodDefinitio } catch (Exception) { - //Console.WriteLine("Exception whilst trying to get the body of method {0}", methodDefinition.FullName); + return null; } return null; } @@ -73,7 +72,7 @@ private SymbolFolder FindSymbolFolder() { var origFolder = Path.GetDirectoryName(ModulePath); - var searchFolders = new List() { origFolder, _commandLine.TargetDir }; + var searchFolders = new List { origFolder, _commandLine.TargetDir }; if (_commandLine.SearchDirs != null) searchFolders.AddRange(_commandLine.SearchDirs); searchFolders.Add(Environment.CurrentDirectory); @@ -93,21 +92,15 @@ private static SymbolFolder FindSymbolsFolder(string fileName, string targetfold if (!string.IsNullOrEmpty(targetfolder) && Directory.Exists(targetfolder)) { var name = Path.GetFileName(fileName); - //Console.WriteLine(targetfolder); if (name != null) { - if (System.IO.File.Exists(Path.Combine(targetfolder, - Path.GetFileNameWithoutExtension(fileName) + ".pdb"))) - { - if (System.IO.File.Exists(Path.Combine(targetfolder, name))) + if (System.IO.File.Exists(Path.Combine(targetfolder, Path.GetFileNameWithoutExtension(fileName) + ".pdb")) && + System.IO.File.Exists(Path.Combine(targetfolder, name))) return new SymbolFolder(targetfolder, new PdbReaderProvider()); - } - if (System.IO.File.Exists(Path.Combine(targetfolder, fileName + ".mdb"))) - { - if (System.IO.File.Exists(Path.Combine(targetfolder, name))) + if (System.IO.File.Exists(Path.Combine(targetfolder, fileName + ".mdb")) && + System.IO.File.Exists(Path.Combine(targetfolder, name))) return new SymbolFolder(targetfolder, new MdbReaderProvider()); - } } } return null; @@ -118,7 +111,8 @@ private void LoadSourceAssembly() try { var symbolFolder = FindSymbolFolder(); - if (symbolFolder == null) return; + if (symbolFolder == null) + return; var folder = symbolFolder.TargetFolder ?? Environment.CurrentDirectory; var parameters = new ReaderParameters @@ -155,12 +149,9 @@ public AssemblyDefinition SourceAssembly { Environment.CurrentDirectory = currentPath; } - if (_sourceAssembly == null) + if (_sourceAssembly == null && _logger.IsDebugEnabled) { - if (_logger.IsDebugEnabled) - { - _logger.DebugFormat("Cannot instrument {0} as no PDB/MDB could be loaded", ModulePath); - } + _logger.DebugFormat("Cannot instrument {0} as no PDB/MDB could be loaded", ModulePath); } } return _sourceAssembly; @@ -179,12 +170,15 @@ public File[] GetFiles() public Class[] GetInstrumentableTypes() { - if (SourceAssembly == null) return new Class[0]; + if (SourceAssembly == null) + return new Class[0]; var classes = new List(); IEnumerable typeDefinitions = SourceAssembly.MainModule.Types; var assemblyPath = ModuleName; - if (ModulePath.Contains (assemblyPath)) { assemblyPath = ModulePath; } + if (ModulePath.Contains(assemblyPath)) + assemblyPath = ModulePath; + GetInstrumentableTypes(typeDefinitions, classes, _filter, assemblyPath); return classes.ToArray(); } @@ -193,41 +187,51 @@ private static void GetInstrumentableTypes(IEnumerable typeDefin { foreach (var typeDefinition in typeDefinitions) { - if (typeDefinition.IsEnum) continue; - if (typeDefinition.IsInterface && typeDefinition.IsAbstract) continue; - var @class = new Class { FullName = typeDefinition.FullName }; - if (!filter.InstrumentClass(assemblyPath, @class.FullName)) - { - @class.MarkAsSkipped(SkippedMethod.Filter); - } - else if (filter.ExcludeByAttribute(typeDefinition)) - { - @class.MarkAsSkipped(SkippedMethod.Attribute); - } + if (typeDefinition.IsEnum) + continue; + if (typeDefinition.IsInterface && typeDefinition.IsAbstract) + continue; - var list = new List(); - if (!@class.ShouldSerializeSkippedDueTo()) - { - var files = from methodDefinition in typeDefinition.Methods - where methodDefinition.SafeGetMethodBody() != null && methodDefinition.Body.Instructions != null - from instruction in methodDefinition.Body.Instructions - where instruction.SequencePoint != null - select instruction.SequencePoint.Document.Url; - - list.AddRange(files.Distinct()); - } + var @class = BuildClass(filter, assemblyPath, typeDefinition); // only instrument types that are not structs and have instrumentable points - if (!typeDefinition.IsValueType || list.Count > 0) - { - @class.Files = list.Distinct().Select(file => new File { FullPath = file }).ToArray(); + if (!typeDefinition.IsValueType || @class.Files.Maybe(f => f.Length) > 0) classes.Add(@class); - } + if (typeDefinition.HasNestedTypes) GetInstrumentableTypes(typeDefinition.NestedTypes, classes, filter, assemblyPath); } } + private static Class BuildClass(IFilter filter, string assemblyPath, TypeDefinition typeDefinition) + { + var @class = new Class {FullName = typeDefinition.FullName}; + if (!filter.InstrumentClass(assemblyPath, @class.FullName)) + { + @class.MarkAsSkipped(SkippedMethod.Filter); + } + else if (filter.ExcludeByAttribute(typeDefinition)) + { + @class.MarkAsSkipped(SkippedMethod.Attribute); + } + + var list = new List(); + if (!@class.ShouldSerializeSkippedDueTo()) + { + var files = from methodDefinition in typeDefinition.Methods + where methodDefinition.SafeGetMethodBody() != null && methodDefinition.Body.Instructions != null + from instruction in methodDefinition.Body.Instructions + where instruction.SequencePoint != null + select instruction.SequencePoint.Document.Url; + + list.AddRange(files.Distinct()); + } + + if (!typeDefinition.IsValueType || list.Count > 0) + @class.Files = list.Distinct().Select(file => new File {FullPath = file}).ToArray(); + return @class; + } + public Method[] GetMethodsForType(Class type, File[] files) { var methods = new List(); @@ -266,9 +270,8 @@ private static void BuildMethods(ICollection methods, File[] files, IFil { foreach (var methodDefinition in typeDefinition.Methods) { - if (methodDefinition.IsAbstract) continue; - if (methodDefinition.IsGetter) continue; - if (methodDefinition.IsSetter) continue; + if (methodDefinition.IsAbstract || methodDefinition.IsGetter || methodDefinition.IsSetter) + continue; var method = BuildMethod(files, filter, methodDefinition, false, commandLine); methods.Add(method); @@ -355,7 +358,8 @@ public int GetCyclomaticComplexityForToken(int token) private void BuildMethodMap() { - if (_methodMap.Count > 0) return; + if (_methodMap.Count > 0) + return; IEnumerable typeDefinitions = SourceAssembly.MainModule.Types; BuildMethodMap(typeDefinitions); } @@ -379,7 +383,8 @@ private void BuildMethodMap(IEnumerable typeDefinitions) private void GetSequencePointsForToken(int token, List list) { var methodDefinition = GetMethodDefinition(token); - if (methodDefinition == null) return; + if (methodDefinition == null) + return; try { UInt32 ordinal = 0; @@ -405,20 +410,22 @@ private void GetSequencePointsForToken(int token, List list) } } - private static Regex isMovenext = new Regex(@"\<[^\s>]+\>\w__\w(\w)?::MoveNext\(\)$", RegexOptions.Compiled | RegexOptions.ExplicitCapture); + private static readonly Regex IsMovenext = new Regex(@"\<[^\s>]+\>\w__\w(\w)?::MoveNext\(\)$", RegexOptions.Compiled | RegexOptions.ExplicitCapture); private void GetBranchPointsForToken(int token, List list) { var methodDefinition = GetMethodDefinition(token); - if (methodDefinition == null) return; + if (methodDefinition == null) + return; try { UInt32 ordinal = 0; var safeMethodBody = methodDefinition.SafeGetMethodBody(); - if (safeMethodBody == null) return; + if (safeMethodBody == null) + return; var instructions = safeMethodBody.Instructions; // if method is a generated MoveNext skip first branch (could be a switch or a branch) - var skipFirstBranch = isMovenext.IsMatch(methodDefinition.FullName); + var skipFirstBranch = IsMovenext.IsMatch(methodDefinition.FullName); foreach (var instruction in instructions.Where(instruction => instruction.OpCode.FlowControl == FlowControl.Cond_Branch)) { @@ -428,7 +435,8 @@ private void GetBranchPointsForToken(int token, List list) continue; } - if (BranchIsInGeneratedFinallyBlock(instruction, methodDefinition)) continue; + if (BranchIsInGeneratedFinallyBlock(instruction, methodDefinition)) + continue; var pathCounter = 0; @@ -618,7 +626,8 @@ private List GetBranchPath(Instruction instruction) private Instruction FindClosestSequencePoints(MethodBody methodBody, Instruction instruction) { var sequencePointsInMethod = methodBody.Instructions.Where(HasValidSequencePoint).ToList(); - if (!sequencePointsInMethod.Any()) return null; + if (!sequencePointsInMethod.Any()) + return null; var idx = sequencePointsInMethod.BinarySearch(instruction, new InstructionByOffsetComparer()); Instruction prev; if (idx < 0) @@ -657,13 +666,15 @@ private MethodDefinition GetMethodDefinition(int token) private void GetCyclomaticComplexityForToken(int token, ref int complexity) { var methodDefinition = GetMethodDefinition(token); - if (methodDefinition == null) return; + if (methodDefinition == null) + return; complexity = Gendarme.Rules.Maintainability.AvoidComplexMethodsRule.GetCyclomaticComplexity(methodDefinition); } public TrackedMethod[] GetTrackedMethods() { - if (SourceAssembly==null) return null; + if (SourceAssembly==null) + return null; var modulePath = ModulePath; if (!System.IO.File.Exists(modulePath)) diff --git a/main/OpenCover.Framework/Utility/CodeCoverageStringTextSource.cs b/main/OpenCover.Framework/Utility/CodeCoverageStringTextSource.cs index 182395305..1f25bb0c3 100644 --- a/main/OpenCover.Framework/Utility/CodeCoverageStringTextSource.cs +++ b/main/OpenCover.Framework/Utility/CodeCoverageStringTextSource.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Text; using OpenCover.Framework.Model; @@ -31,30 +30,71 @@ public enum FileType : byte { public class CodeCoverageStringTextSource { /// - /// File Type by file name extension + /// File Type guessed by file-name extension /// - public FileType FileType = FileType.Unsupported; - private readonly string textSource; - private struct lineInfo { + public FileType FileType { get { return _fileType; } } + private readonly FileType _fileType = FileType.Unsupported; + + /// + /// Path to source file + /// + public string FilePath { get { return _filePath; } } + private readonly string _filePath = string.Empty; + + /// + /// Source file found or not + /// + public bool FileFound { get { return _fileFound; } } + private readonly bool _fileFound; + + /// + /// Last write DateTime + /// + public DateTime FileTime { get { return _fileTime; } } + private readonly DateTime _fileTime = DateTime.MinValue; + + private readonly string _textSource; + + private struct LineInfo { public int Offset; public int Length; } - private readonly lineInfo[] lines = new lineInfo[0]; + private readonly LineInfo[] _lines; /// /// Constructor /// /// - public CodeCoverageStringTextSource(string source) + /// + public CodeCoverageStringTextSource(string source, string filePath = "") { - if (string.IsNullOrEmpty(source)) { - this.textSource = string.Empty; - } else { - this.textSource = source; + _fileFound = source != null; + + if (!string.IsNullOrWhiteSpace (filePath)) { + _filePath = filePath; + if (_filePath.IndexOfAny(Path.GetInvalidPathChars()) < 0 + && Path.GetExtension(_filePath).ToLowerInvariant() == ".cs" ) { + _fileType = FileType.CSharp; + } + if (_fileFound) { + try { + _fileTime = System.IO.File.GetLastWriteTime (this._filePath); + } catch (Exception e) { + e.InformUser(); + } + } + } - lineInfo line; - var lineInfoList = new List(); + _textSource = string.IsNullOrEmpty(source) ? string.Empty : source; + + _lines = InitLines (); + + } + + private LineInfo[] InitLines () + { + var lineInfoList = new List(); int offset = 0; int counter = 0; bool newLine = false; @@ -62,12 +102,12 @@ public CodeCoverageStringTextSource(string source) bool lf = false; const ushort carriageReturn = 0xD; const ushort lineFeed = 0xA; - - if (textSource != string.Empty) { - foreach ( ushort ch in textSource ) { - switch (ch) { + if (_textSource != string.Empty) { + LineInfo line; + foreach (var ch in _textSource) { + switch ((ushort)ch) { case carriageReturn: - if (lf||cr) { + if (lf || cr) { lf = false; newLine = true; // cr after cr|lf } else { @@ -82,7 +122,7 @@ public CodeCoverageStringTextSource(string source) } break; default: - if (cr||lf) { + if (cr || lf) { cr = false; lf = false; newLine = true; // any non-line-end char after any line-end @@ -91,24 +131,25 @@ public CodeCoverageStringTextSource(string source) } if (newLine) { // newLine detected - add line newLine = false; - line = new lineInfo(); - line.Offset = offset; - line.Length = counter - offset; + line = new LineInfo + { + Offset = offset, + Length = counter - offset + }; lineInfoList.Add(line); offset = counter; } ++counter; } - // Add last line - line = new lineInfo(); - line.Offset = offset; - line.Length = counter - offset; + line = new LineInfo + { + Offset = offset, + Length = counter - offset + }; lineInfoList.Add(line); - - // Store to readonly field - lines = lineInfoList.ToArray(); } + return lineInfoList.ToArray(); } /// Return text/source using SequencePoint line/col info @@ -116,71 +157,70 @@ public CodeCoverageStringTextSource(string source) /// /// public string GetText(SequencePoint sp) { - return this.GetText(sp.StartLine, sp.StartColumn, sp.EndLine, sp.EndColumn ); + return GetText(sp.StartLine, sp.StartColumn, sp.EndLine, sp.EndColumn ); } /// Return text at Line/Column/EndLine/EndColumn position /// Line and Column counting starts at 1. /// - /// - /// - /// - /// + /// + /// + /// + /// /// - public string GetText(int Line, int Column, int EndLine, int EndColumn) { + public string GetText(int startLine, int startColumn, int endLine, int endColumn) { var text = new StringBuilder(); string line; bool argOutOfRange; - if (Line==EndLine) { + if (startLine==endLine) { #region One-Line request - line = GetLine(Line); + line = GetLine(startLine); - argOutOfRange = Column > EndColumn || Column > line.Length; - if (!argOutOfRange) { - if (Column < 1) { Column = 1; } - if (EndColumn > line.Length + 1) { EndColumn = line.Length + 1; } - text.Append(line.Substring (Column-1, EndColumn-Column)); + argOutOfRange = startColumn > endColumn || startColumn > line.Length; + if (!argOutOfRange) + { + var actualStartColumn = (startColumn < 1) ? 1 : startColumn; + var actualEndColumn = (endColumn > line.Length + 1) ? line.Length + 1 : endColumn; + text.Append(line.Substring(actualStartColumn - 1, actualEndColumn - actualStartColumn)); } #endregion - } else if (Line line.Length; + argOutOfRange = startColumn > line.Length; if (!argOutOfRange) { - if (Column < 1) { Column = 1; } - text.Append (line.Substring (Column-1)); + var actualStartColumn = (startColumn < 1) ? 1 : startColumn; + text.Append(line.Substring(actualStartColumn - 1)); } #endregion #region More than two lines - for ( int lineIndex = Line + 1; lineIndex < EndLine; lineIndex++ ) { + for ( int lineIndex = startLine + 1; lineIndex < endLine; lineIndex++ ) { text.Append ( GetLine ( lineIndex ) ); } #endregion #region Last line - line = GetLine(EndLine); + line = GetLine(endLine); - argOutOfRange = EndColumn < 1; + argOutOfRange = endColumn < 1; if (!argOutOfRange) { - if (EndColumn > line.Length + 1) { EndColumn = line.Length + 1; } - text.Append(line.Substring(0,EndColumn-1)); + var actualEndColumn = (endColumn > line.Length + 1) ? line.Length + 1 : endColumn; + text.Append(line.Substring(0, actualEndColumn - 1)); } #endregion #endregion - } else { - ; - } + } return text.ToString(); } @@ -189,51 +229,52 @@ public string GetText(int Line, int Column, int EndLine, int EndColumn) { /// public int LinesCount { get { - return lines.Length; + return _lines.Length; } } /// Return SequencePoint enumerated line /// - /// + /// /// - public string GetLine ( int LineNo ) { + public string GetLine ( int lineNo ) { - string retString = String.Empty; + string retString = string.Empty; - if ( LineNo > 0 && LineNo <= lines.Length ) { - lineInfo lineInfo = lines[LineNo-1]; - retString = textSource.Substring(lineInfo.Offset, lineInfo.Length); + if ( lineNo > 0 && lineNo <= _lines.Length ) { + LineInfo lineInfo = _lines[lineNo-1]; + retString = _textSource.Substring(lineInfo.Offset, lineInfo.Length); } return retString; } - + + /// + /// True if referenceTime != 0 and FileTime > referenceTime + /// + /// + /// + public bool IsChanged (DateTime referenceTime) { + return referenceTime != DateTime.MinValue && _fileTime > referenceTime; + } + /// /// Get line-parsed source from file name /// - /// + /// /// - public static CodeCoverageStringTextSource GetSource(string filename) { + public static CodeCoverageStringTextSource GetSource(string filePath) { - var retSource = new CodeCoverageStringTextSource (string.Empty); + var retSource = new CodeCoverageStringTextSource (null, filePath); // null indicates source-file not found try { - using (Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read)) + using (Stream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) using (var reader = new StreamReader (stream, Encoding.Default, true)) { stream.Position = 0; - retSource = new CodeCoverageStringTextSource(reader.ReadToEnd()); - switch (Path.GetExtension(filename).ToLowerInvariant()) { - case ".cs": - retSource.FileType = FileType.CSharp; - break; - default: - retSource.FileType = FileType.Unsupported; - break; - } + retSource = new CodeCoverageStringTextSource(reader.ReadToEnd(), filePath); } } catch (Exception e) { - // Source is optional (excess-branch removal), application can continue without it - LogHelper.InformUser(e); // Do not throw ExitApplicationWithoutReportingException + // Source is optional (for excess-branch removal), application can continue without it + e.InformUser(); // Do not throw ExitApplicationWithoutReportingException } return retSource; } diff --git a/main/OpenCover.Framework/Utility/IPerfCounters.cs b/main/OpenCover.Framework/Utility/IPerfCounters.cs index d0158b4a1..5eff8140d 100644 --- a/main/OpenCover.Framework/Utility/IPerfCounters.cs +++ b/main/OpenCover.Framework/Utility/IPerfCounters.cs @@ -13,7 +13,7 @@ public interface IPerfCounters /// /// Report on the size of the memory queue /// - int CurrentMemoryQueueSize { set; } + long CurrentMemoryQueueSize { get; set; } /// /// Increment the number of blocks received diff --git a/main/OpenCover.Framework/Utility/LogHelper.cs b/main/OpenCover.Framework/Utility/LogHelper.cs index 0b7c43333..c3d7e1f56 100644 --- a/main/OpenCover.Framework/Utility/LogHelper.cs +++ b/main/OpenCover.Framework/Utility/LogHelper.cs @@ -15,13 +15,15 @@ namespace OpenCover.Framework.Utility /// public static class LogHelper { + const string loggerName = "OpenCover"; + /// /// Use to inform user about handled exception where appropriate (failed IO, Access Rights etc..) /// /// public static void InformUser(this Exception e) { - LogManager.GetLogger("OpenCover").InfoFormat ("An {0} occured: {1} ", e.GetType(), e.Message); + LogManager.GetLogger(loggerName).InfoFormat ("An {0} occured: {1} ", e.GetType(), e.Message); } /// @@ -30,7 +32,7 @@ public static void InformUser(this Exception e) /// public static void InformUser(this string message) { - LogManager.GetLogger("OpenCover").InfoFormat (message); + LogManager.GetLogger(loggerName).InfoFormat (message); } } } diff --git a/main/OpenCover.Framework/Utility/PerfCounters.cs b/main/OpenCover.Framework/Utility/PerfCounters.cs index a8feb4832..5c65768ea 100644 --- a/main/OpenCover.Framework/Utility/PerfCounters.cs +++ b/main/OpenCover.Framework/Utility/PerfCounters.cs @@ -14,7 +14,11 @@ public class PerfCounters : IPerfCounters /// /// get the current queue size /// - public int CurrentMemoryQueueSize { set { _memoryQueue.RawValue = value; } } + public long CurrentMemoryQueueSize + { + get { return _memoryQueue.RawValue; } + set { _memoryQueue.RawValue = value; } + } /// /// Increment the block size @@ -33,7 +37,6 @@ public PerfCounters() ResetCounters(); } - //private const string InstanceName = "OpenCover"; private const string CategoryName = "OpenCover"; private const string MemoryQueue = "MemoryQueue"; private const string QueueThroughput = "QueueThroughput"; @@ -77,13 +80,14 @@ public class NullPerfCounter : IPerfCounters /// A null performance counters implementation /// // ReSharper disable once UnusedAutoPropertyAccessor.Local - public int CurrentMemoryQueueSize { set; private get; } + public long CurrentMemoryQueueSize { set; get; } /// /// Increment the number of blocks received /// public void IncrementBlocksReceived() { + // null implementation } /// @@ -91,6 +95,7 @@ public void IncrementBlocksReceived() /// public void ResetCounters() { + // null implementation } } } \ No newline at end of file diff --git a/main/OpenCover.Framework/Utility/SourceRepository.cs b/main/OpenCover.Framework/Utility/SourceRepository.cs index e730ebd2b..649c238fa 100644 --- a/main/OpenCover.Framework/Utility/SourceRepository.cs +++ b/main/OpenCover.Framework/Utility/SourceRepository.cs @@ -53,24 +53,6 @@ public string GetSequencePointText (SequencePoint sp) { } return ""; } - /// - /// True if SequencePoint source-string == "{" - /// ATTN: Do not use within .Where (condition) - /// - /// - /// - public bool IsLeftCurlyBraceSequencePoint (SequencePoint sp) { - return sp.IsSingleCharSequencePoint && this.GetSequencePointText(sp) == "{"; - } - /// - /// True if SequencePoint source-string == "}" - /// ATTN: Do not use within .Where (condition) - /// - /// - /// - public bool IsRightCurlyBraceSequencePoint (SequencePoint sp) { - return sp.IsSingleCharSequencePoint && this.GetSequencePointText(sp) == "}"; - } #region IDictionary implementation diff --git a/main/OpenCover.Integration.Test/ProfilerBaseFixture.cs b/main/OpenCover.Integration.Test/ProfilerBaseFixture.cs index 704fb0a5d..cf105d241 100644 --- a/main/OpenCover.Integration.Test/ProfilerBaseFixture.cs +++ b/main/OpenCover.Integration.Test/ProfilerBaseFixture.cs @@ -39,7 +39,7 @@ public abstract class ProfilerBaseFixture [SetUp] public void SetUp() { - _filter = new Filter(); + _filter = new Filter(false); _filter.AddFilter("-[mscorlib]*"); _filter.AddFilter("-[System]*"); _filter.AddFilter("-[System.*]*"); diff --git a/main/OpenCover.SonarQube.sln b/main/OpenCover.SonarQube.sln new file mode 100644 index 000000000..263a5cfb5 --- /dev/null +++ b/main/OpenCover.SonarQube.sln @@ -0,0 +1,170 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.Console", "OpenCover.Console\OpenCover.Console.csproj", "{42EA7A31-2D5C-4B50-ACEA-D56C3BAB0CC2}" + ProjectSection(ProjectDependencies) = postProject + {EE9B358A-335C-43E9-BC35-853807C5E776} = {EE9B358A-335C-43E9-BC35-853807C5E776} + {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E} = {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.Test", "OpenCover.Test\OpenCover.Test.csproj", "{BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.Simple.Target", "OpenCover.Simple.Target\OpenCover.Simple.Target.csproj", "{27AD5F08-0625-4093-8782-F7936737FAB7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.Framework", "OpenCover.Framework\OpenCover.Framework.csproj", "{C6F40A34-101B-4BAF-A2F4-6EA28A264F57}" + ProjectSection(ProjectDependencies) = postProject + {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E} = {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Root", "Root", "{1E02E180-E417-4810-B8AF-939CB3DB4939}" + ProjectSection(SolutionItems) = preProject + ..\appveyor.yml = ..\appveyor.yml + ..\default.build = ..\default.build + ..\ReleaseNotes.tmp = ..\ReleaseNotes.tmp + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{4337F24C-830C-4A9A-987B-2348F9222C39}" + ProjectSection(SolutionItems) = preProject + ..\build\environment.build = ..\build\environment.build + ..\build\installer.build = ..\build\installer.build + ..\build\opencover.build = ..\build\opencover.build + ..\build\version.build = ..\build\version.build + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.Integration.Test", "OpenCover.Integration.Test\OpenCover.Integration.Test.csproj", "{C5533EEB-9AEF-4CC9-8E76-3FFE57D09C23}" + ProjectSection(ProjectDependencies) = postProject + {BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2} = {BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.MSBuild", "OpenCover.MSBuild\OpenCover.MSBuild.csproj", "{746A6B40-4570-40CB-BBE5-CEECEE9E220F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{C4B551F8-0420-40EE-B5F8-67487627BFDD}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.Config = .nuget\NuGet.Config + .nuget\NuGet.exe = .nuget\NuGet.exe + .nuget\NuGet.targets = .nuget\NuGet.targets + .nuget\packages.config = .nuget\packages.config + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.Specs", "OpenCover.Specs\OpenCover.Specs.csproj", "{5A908D9D-617E-408F-ACED-9E505693DE96}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.Extensions", "OpenCover.Extensions\OpenCover.Extensions.csproj", "{EE9B358A-335C-43E9-BC35-853807C5E776}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.Support", "OpenCover.Support\OpenCover.Support.csproj", "{31B0FAA6-A63F-46FC-96EE-697235DA2BB0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.UITest", "OpenCover.UITest\OpenCover.UITest.csproj", "{E8513153-6298-411D-9BD9-0DB0CC708D34}" + ProjectSection(ProjectDependencies) = postProject + {27AD5F08-0625-4093-8782-F7936737FAB7} = {27AD5F08-0625-4093-8782-F7936737FAB7} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenCover.3rdParty.Signer", "OpenCover.3rdParty.Signer\OpenCover.3rdParty.Signer.csproj", "{0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {42EA7A31-2D5C-4B50-ACEA-D56C3BAB0CC2}.Debug|x64.ActiveCfg = Debug|Any CPU + {42EA7A31-2D5C-4B50-ACEA-D56C3BAB0CC2}.Debug|x64.Build.0 = Debug|Any CPU + {42EA7A31-2D5C-4B50-ACEA-D56C3BAB0CC2}.Debug|x86.ActiveCfg = Debug|Any CPU + {42EA7A31-2D5C-4B50-ACEA-D56C3BAB0CC2}.Debug|x86.Build.0 = Debug|Any CPU + {42EA7A31-2D5C-4B50-ACEA-D56C3BAB0CC2}.Release|x64.ActiveCfg = Release|Any CPU + {42EA7A31-2D5C-4B50-ACEA-D56C3BAB0CC2}.Release|x64.Build.0 = Release|Any CPU + {42EA7A31-2D5C-4B50-ACEA-D56C3BAB0CC2}.Release|x86.ActiveCfg = Release|Any CPU + {42EA7A31-2D5C-4B50-ACEA-D56C3BAB0CC2}.Release|x86.Build.0 = Release|Any CPU + {BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2}.Debug|x64.ActiveCfg = Debug|Any CPU + {BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2}.Debug|x64.Build.0 = Debug|Any CPU + {BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2}.Debug|x86.ActiveCfg = Debug|Any CPU + {BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2}.Debug|x86.Build.0 = Debug|Any CPU + {BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2}.Release|x64.ActiveCfg = Release|Any CPU + {BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2}.Release|x64.Build.0 = Release|Any CPU + {BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2}.Release|x86.ActiveCfg = Release|Any CPU + {BDFCE9C6-A116-45AF-94DC-F491D0CE8EB2}.Release|x86.Build.0 = Release|Any CPU + {27AD5F08-0625-4093-8782-F7936737FAB7}.Debug|x64.ActiveCfg = Debug|x64 + {27AD5F08-0625-4093-8782-F7936737FAB7}.Debug|x64.Build.0 = Debug|x64 + {27AD5F08-0625-4093-8782-F7936737FAB7}.Debug|x86.ActiveCfg = Debug|x86 + {27AD5F08-0625-4093-8782-F7936737FAB7}.Debug|x86.Build.0 = Debug|x86 + {27AD5F08-0625-4093-8782-F7936737FAB7}.Release|x64.ActiveCfg = Release|x64 + {27AD5F08-0625-4093-8782-F7936737FAB7}.Release|x64.Build.0 = Release|x64 + {27AD5F08-0625-4093-8782-F7936737FAB7}.Release|x86.ActiveCfg = Release|x86 + {27AD5F08-0625-4093-8782-F7936737FAB7}.Release|x86.Build.0 = Release|x86 + {C6F40A34-101B-4BAF-A2F4-6EA28A264F57}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6F40A34-101B-4BAF-A2F4-6EA28A264F57}.Debug|x64.Build.0 = Debug|Any CPU + {C6F40A34-101B-4BAF-A2F4-6EA28A264F57}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6F40A34-101B-4BAF-A2F4-6EA28A264F57}.Debug|x86.Build.0 = Debug|Any CPU + {C6F40A34-101B-4BAF-A2F4-6EA28A264F57}.Release|x64.ActiveCfg = Release|Any CPU + {C6F40A34-101B-4BAF-A2F4-6EA28A264F57}.Release|x64.Build.0 = Release|Any CPU + {C6F40A34-101B-4BAF-A2F4-6EA28A264F57}.Release|x86.ActiveCfg = Release|Any CPU + {C6F40A34-101B-4BAF-A2F4-6EA28A264F57}.Release|x86.Build.0 = Release|Any CPU + {C5533EEB-9AEF-4CC9-8E76-3FFE57D09C23}.Debug|x64.ActiveCfg = Debug|Any CPU + {C5533EEB-9AEF-4CC9-8E76-3FFE57D09C23}.Debug|x64.Build.0 = Debug|Any CPU + {C5533EEB-9AEF-4CC9-8E76-3FFE57D09C23}.Debug|x86.ActiveCfg = Debug|Any CPU + {C5533EEB-9AEF-4CC9-8E76-3FFE57D09C23}.Debug|x86.Build.0 = Debug|Any CPU + {C5533EEB-9AEF-4CC9-8E76-3FFE57D09C23}.Release|x64.ActiveCfg = Release|Any CPU + {C5533EEB-9AEF-4CC9-8E76-3FFE57D09C23}.Release|x64.Build.0 = Release|Any CPU + {C5533EEB-9AEF-4CC9-8E76-3FFE57D09C23}.Release|x86.ActiveCfg = Release|Any CPU + {C5533EEB-9AEF-4CC9-8E76-3FFE57D09C23}.Release|x86.Build.0 = Release|Any CPU + {746A6B40-4570-40CB-BBE5-CEECEE9E220F}.Debug|x64.ActiveCfg = Debug|Any CPU + {746A6B40-4570-40CB-BBE5-CEECEE9E220F}.Debug|x64.Build.0 = Debug|Any CPU + {746A6B40-4570-40CB-BBE5-CEECEE9E220F}.Debug|x86.ActiveCfg = Debug|Any CPU + {746A6B40-4570-40CB-BBE5-CEECEE9E220F}.Debug|x86.Build.0 = Debug|Any CPU + {746A6B40-4570-40CB-BBE5-CEECEE9E220F}.Release|x64.ActiveCfg = Release|Any CPU + {746A6B40-4570-40CB-BBE5-CEECEE9E220F}.Release|x64.Build.0 = Release|Any CPU + {746A6B40-4570-40CB-BBE5-CEECEE9E220F}.Release|x86.ActiveCfg = Release|Any CPU + {746A6B40-4570-40CB-BBE5-CEECEE9E220F}.Release|x86.Build.0 = Release|Any CPU + {5A908D9D-617E-408F-ACED-9E505693DE96}.Debug|x64.ActiveCfg = Debug|Any CPU + {5A908D9D-617E-408F-ACED-9E505693DE96}.Debug|x64.Build.0 = Debug|Any CPU + {5A908D9D-617E-408F-ACED-9E505693DE96}.Debug|x86.ActiveCfg = Debug|Any CPU + {5A908D9D-617E-408F-ACED-9E505693DE96}.Debug|x86.Build.0 = Debug|Any CPU + {5A908D9D-617E-408F-ACED-9E505693DE96}.Release|x64.ActiveCfg = Release|Any CPU + {5A908D9D-617E-408F-ACED-9E505693DE96}.Release|x64.Build.0 = Release|Any CPU + {5A908D9D-617E-408F-ACED-9E505693DE96}.Release|x86.ActiveCfg = Release|Any CPU + {5A908D9D-617E-408F-ACED-9E505693DE96}.Release|x86.Build.0 = Release|Any CPU + {EE9B358A-335C-43E9-BC35-853807C5E776}.Debug|x64.ActiveCfg = Debug|Any CPU + {EE9B358A-335C-43E9-BC35-853807C5E776}.Debug|x64.Build.0 = Debug|Any CPU + {EE9B358A-335C-43E9-BC35-853807C5E776}.Debug|x86.ActiveCfg = Debug|Any CPU + {EE9B358A-335C-43E9-BC35-853807C5E776}.Debug|x86.Build.0 = Debug|Any CPU + {EE9B358A-335C-43E9-BC35-853807C5E776}.Release|x64.ActiveCfg = Release|Any CPU + {EE9B358A-335C-43E9-BC35-853807C5E776}.Release|x64.Build.0 = Release|Any CPU + {EE9B358A-335C-43E9-BC35-853807C5E776}.Release|x86.ActiveCfg = Release|Any CPU + {EE9B358A-335C-43E9-BC35-853807C5E776}.Release|x86.Build.0 = Release|Any CPU + {31B0FAA6-A63F-46FC-96EE-697235DA2BB0}.Debug|x64.ActiveCfg = Debug|Any CPU + {31B0FAA6-A63F-46FC-96EE-697235DA2BB0}.Debug|x64.Build.0 = Debug|Any CPU + {31B0FAA6-A63F-46FC-96EE-697235DA2BB0}.Debug|x86.ActiveCfg = Debug|Any CPU + {31B0FAA6-A63F-46FC-96EE-697235DA2BB0}.Debug|x86.Build.0 = Debug|Any CPU + {31B0FAA6-A63F-46FC-96EE-697235DA2BB0}.Release|x64.ActiveCfg = Release|Any CPU + {31B0FAA6-A63F-46FC-96EE-697235DA2BB0}.Release|x64.Build.0 = Release|Any CPU + {31B0FAA6-A63F-46FC-96EE-697235DA2BB0}.Release|x86.ActiveCfg = Release|Any CPU + {31B0FAA6-A63F-46FC-96EE-697235DA2BB0}.Release|x86.Build.0 = Release|Any CPU + {E8513153-6298-411D-9BD9-0DB0CC708D34}.Debug|x64.ActiveCfg = Debug|Any CPU + {E8513153-6298-411D-9BD9-0DB0CC708D34}.Debug|x64.Build.0 = Debug|Any CPU + {E8513153-6298-411D-9BD9-0DB0CC708D34}.Debug|x86.ActiveCfg = Debug|Any CPU + {E8513153-6298-411D-9BD9-0DB0CC708D34}.Debug|x86.Build.0 = Debug|Any CPU + {E8513153-6298-411D-9BD9-0DB0CC708D34}.Release|x64.ActiveCfg = Release|Any CPU + {E8513153-6298-411D-9BD9-0DB0CC708D34}.Release|x64.Build.0 = Release|Any CPU + {E8513153-6298-411D-9BD9-0DB0CC708D34}.Release|x86.ActiveCfg = Release|Any CPU + {E8513153-6298-411D-9BD9-0DB0CC708D34}.Release|x86.Build.0 = Release|Any CPU + {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E}.Debug|x64.ActiveCfg = Debug|Any CPU + {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E}.Debug|x64.Build.0 = Debug|Any CPU + {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E}.Debug|x86.ActiveCfg = Debug|Any CPU + {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E}.Debug|x86.Build.0 = Debug|Any CPU + {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E}.Release|x64.ActiveCfg = Release|Any CPU + {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E}.Release|x64.Build.0 = Release|Any CPU + {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E}.Release|x86.ActiveCfg = Release|Any CPU + {0B94C4BF-762B-4722-BF5A-30E7F6D2CB7E}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {4337F24C-830C-4A9A-987B-2348F9222C39} = {1E02E180-E417-4810-B8AF-939CB3DB4939} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.2\lib\NET35 + EndGlobalSection +EndGlobal diff --git a/main/OpenCover.Specs/Steps/PackagingSteps.cs b/main/OpenCover.Specs/Steps/PackagingSteps.cs index ee738ac2c..c28d65c4e 100644 --- a/main/OpenCover.Specs/Steps/PackagingSteps.cs +++ b/main/OpenCover.Specs/Steps/PackagingSteps.cs @@ -17,14 +17,16 @@ public class PackagingSteps public void DeleteZipFolder() { var folder = (string)ScenarioContext.Current["targetFolder"]; - if (Directory.Exists(folder)) Directory.Delete(folder, true); + if (Directory.Exists(folder)) + Directory.Delete(folder, true); } [AfterScenario("msitag")] public void DeleteMsiFolder() { var folder = Path.GetFullPath(Path.Combine((string)ScenarioContext.Current["targetFolder"], "..")); - if (Directory.Exists(folder)) Directory.Delete(folder, true); + if (Directory.Exists(folder)) + Directory.Delete(folder, true); } private static dynamic GetTargetPackage(string folder, string ext) @@ -43,26 +45,36 @@ private static dynamic GetTargetPackage(string folder, string ext) [Given(@"I have a valid zip package in the output folder")] public void GivenIHaveAValidZipPackageInTheOutputFolder() { - var target = GetTargetPackage("zip", "zip"); - - Assert.NotNull(target, "Could not find a valid ZIP file."); - - var targetFile = Path.GetFullPath(target.File); - var targetFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "zipFolder")); - var targetOutput = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "zipoutput.xml")); - - if (File.Exists(targetOutput)) File.Delete(targetOutput); + string targetFolder; + string targetOutput; + var targetFile = BuildTargets("zip", "zip", "zipFolder", "zipoutput.xml", out targetFolder, out targetOutput); ScenarioContext.Current["targetZip"] = targetFile; ScenarioContext.Current["targetFolder"] = targetFolder; ScenarioContext.Current["targetOutput"] = targetOutput; } + private static dynamic BuildTargets(string folder, string ext, string dir, string xml, out string targetFolder, out string targetOutput) + { + var target = GetTargetPackage(folder, ext); + + Assert.NotNull(target, "Could not find a valid file."); + + var targetFile = Path.GetFullPath(target.File); + targetFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, dir)); + targetOutput = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, xml)); + + if (File.Exists(targetOutput)) + File.Delete(targetOutput); + return targetFile; + } + [Given(@"I (?:unzip|unpack) that package into a deployment folder")] public void GivenIUnzipThatPackageIntoADeploymentFolder() { var folder = (string)ScenarioContext.Current["targetFolder"]; - if (Directory.Exists(folder)) Directory.Delete(folder, true); + if (Directory.Exists(folder)) + Directory.Delete(folder, true); var zip = new ZipFile((string)ScenarioContext.Current["targetZip"]); zip.ExtractAll(folder); zip.Dispose(); @@ -71,15 +83,9 @@ public void GivenIUnzipThatPackageIntoADeploymentFolder() [Given(@"I have a valid nugetpackage in the output folder")] public void GivenIHaveAValidNugetpackageInTheOutputFolder() { - var target = GetTargetPackage("nugetpackage", "nupkg"); - - Assert.NotNull(target, "Could not find a valid NUGET file."); - - var targetFile = Path.GetFullPath(target.File); - var targetFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "nuFolder")); - var targetOutput = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "nuoutput.xml")); - - if (File.Exists(targetOutput)) File.Delete(targetOutput); + string targetFolder; + string targetOutput; + var targetFile = BuildTargets("nugetpackage", "nupkg", "nuFolder", "nuoutput.xml", out targetFolder, out targetOutput); ScenarioContext.Current["targetZip"] = targetFile; ScenarioContext.Current["targetFolder"] = targetFolder; @@ -89,15 +95,9 @@ public void GivenIHaveAValidNugetpackageInTheOutputFolder() [Given(@"I have a valid installer in the output folder")] public void GivenIHaveAValidInstallerInTheOutputFolder() { - var target = GetTargetPackage("installer", "msi"); - - Assert.NotNull(target, "Could not find a valid MSI file."); - - var targetFile = Path.GetFullPath(target.File); - var targetFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "msiFolder")); - var targetOutput = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "msioutput.xml")); - - if (File.Exists(targetOutput)) File.Delete(targetOutput); + string targetFolder; + string targetOutput; + var targetFile = BuildTargets("installer", "msi", "msiFolder", "msioutput.xml", out targetFolder, out targetOutput); ScenarioContext.Current["targetMsi"] = targetFile; ScenarioContext.Current["targetFolder"] = targetFolder; @@ -108,14 +108,18 @@ public void GivenIHaveAValidInstallerInTheOutputFolder() public void GivenIInstallThatPackageIntoADeploymentFolder() { var folder = (string)ScenarioContext.Current["targetFolder"]; - if (Directory.Exists(folder)) Directory.Delete(folder, true); + if (Directory.Exists(folder)) + Directory.Delete(folder, true); var installer = (string)ScenarioContext.Current["targetMsi"]; var msiExec = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "msiexec.exe"); - var startInfo = new ProcessStartInfo(msiExec); - startInfo.Arguments = string.Format("/qn /a {0} TARGETDIR={1}", installer, folder); - startInfo.UseShellExecute = false; + var startInfo = new ProcessStartInfo(msiExec) + { + Arguments = string.Format("/qn /a {0} TARGETDIR={1}", installer, folder), + UseShellExecute = false + }; var process = Process.Start(startInfo); + Assert.NotNull(process); process.WaitForExit(); ScenarioContext.Current["targetFolder"] = Path.Combine(folder, "[ApplicationFolderName]"); @@ -124,7 +128,7 @@ public void GivenIInstallThatPackageIntoADeploymentFolder() [When(@"I execute the deployed OpenCover against the (x\d\d) target application")] public void WhenIExecuteTheDeployedOpenCoverAgainstTheXTargetApplication(string binFolder) { - this.WhenIExecuteTheDeployedOpenCoverAgainstTheXTargetApplicationInSubfolder(binFolder, string.Empty); + WhenIExecuteTheDeployedOpenCoverAgainstTheXTargetApplicationInSubfolder(binFolder, string.Empty); } [When(@"I execute the deployed OpenCover against the (x\d\d) target application in subfolder (.*)")] @@ -136,14 +140,18 @@ public void WhenIExecuteTheDeployedOpenCoverAgainstTheXTargetApplicationInSubfol var outputXml = string.Format(@"{0}\{1}_{2}{3}", Path.GetDirectoryName(output), Path.GetFileNameWithoutExtension(output), binFolder, Path.GetExtension(output)); - if (File.Exists(outputXml)) File.Delete(outputXml); + if (File.Exists(outputXml)) + File.Delete(outputXml); var openCover = Path.Combine(folder, subfolder, "OpenCover.Console.exe"); var target = Path.Combine(folder, string.Format(@"Samples\{0}\OpenCover.Simple.Target.exe", binFolder)); - var startInfo = new ProcessStartInfo(openCover); - startInfo.Arguments = string.Format(@"-register:user ""-target:{0}"" ""-output:{1}""", target, outputXml); - startInfo.UseShellExecute = false; + var startInfo = new ProcessStartInfo(openCover) + { + Arguments = string.Format(@"-register:user ""-target:{0}"" ""-output:{1}""", target, outputXml), + UseShellExecute = false + }; var process = Process.Start(startInfo); + Assert.NotNull(process); process.WaitForExit(); } diff --git a/main/OpenCover.Support/Fakes/FakesHelper.cs b/main/OpenCover.Support/Fakes/FakesHelper.cs index bc8506f8b..bbe70067c 100644 --- a/main/OpenCover.Support/Fakes/FakesHelper.cs +++ b/main/OpenCover.Support/Fakes/FakesHelper.cs @@ -4,7 +4,7 @@ namespace OpenCover.Support.Fakes { - public class FakesHelper + public static class FakesHelper { private const string CorEnableProfiling = "COR_ENABLE_PROFILING"; private const string CorProfiler = "COR_PROFILER"; @@ -15,13 +15,7 @@ public class FakesHelper public static void LoadOpenCoverProfilerInstead(object data) { var dict = data as IDictionary; - if (dict == null) - return; - - if (!dict.ContainsKey(CorEnableProfiling) || dict[CorEnableProfiling] != "1") - return; - - if (!dict.ContainsKey(CorProfiler) || dict[CorProfiler] == OpenCoverProfilerGuid) + if (dict == null || IsAnotherProfilerAttached(dict)) return; var currentProfiler = dict[CorProfiler]; @@ -36,6 +30,17 @@ public static void LoadOpenCoverProfilerInstead(object data) dict[CorProfiler] = OpenCoverProfilerGuid; } + private static bool IsAnotherProfilerAttached(IDictionary dict) + { + if (!dict.ContainsKey(CorEnableProfiling) || dict[CorEnableProfiling] != "1") + return true; + + if (!dict.ContainsKey(CorProfiler) || dict[CorProfiler] == OpenCoverProfilerGuid) + return true; + + return false; + } + public static void PretendWeLoadedFakesProfiler(object data) { var enabled = Environment.GetEnvironmentVariable(CorEnableProfiling); diff --git a/main/OpenCover.Support/UITesting/UITestingHelper.cs b/main/OpenCover.Support/UITesting/UITestingHelper.cs index 19fe3f99d..8968291f5 100644 --- a/main/OpenCover.Support/UITesting/UITestingHelper.cs +++ b/main/OpenCover.Support/UITesting/UITestingHelper.cs @@ -8,12 +8,13 @@ namespace OpenCover.Support.UITesting { // ReSharper disable once InconsistentNaming - public class UITestingHelper + public static class UITestingHelper { public static void PropagateRequiredEnvironmentVariables(object data) { var pi = data as ProcessStartInfo; - if (pi == null) return; + if (pi == null) + return; foreach (var ev in from DictionaryEntry ev in Environment.GetEnvironmentVariables() where (ev.Key.ToString().StartsWith("COR", StringComparison.InvariantCultureIgnoreCase) || ev.Key.ToString().StartsWith("OPEN", StringComparison.InvariantCultureIgnoreCase) || diff --git a/main/OpenCover.Test/Console/OutputTests.cs b/main/OpenCover.Test/Console/OutputTests.cs new file mode 100644 index 000000000..889709cd9 --- /dev/null +++ b/main/OpenCover.Test/Console/OutputTests.cs @@ -0,0 +1,33 @@ +using System; +using System.Diagnostics; +using System.IO; +using NUnit.Framework; + +// ReSharper disable once CheckNamespace +namespace OpenCover.Test.ConsoleEx +{ + [TestFixture] + public class OutputTests + { + [Test] + public void OutputHasPreferred32BitDisabled() + { + var pi = new ProcessStartInfo() + { + FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\corflags.exe"), + Arguments = "OpenCover.Console.exe", + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardOutput = true + }; + + var process = Process.Start(pi); + Assert.IsNotNull(process); + var output = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + Console.WriteLine(output); + + Assert.IsTrue(output.Contains("32BITPREF : 0")); + } + } +} diff --git a/main/OpenCover.Test/Framework/Communication/MessageHandlerTests.cs b/main/OpenCover.Test/Framework/Communication/MessageHandlerTests.cs index a47970ffb..d073d7d08 100644 --- a/main/OpenCover.Test/Framework/Communication/MessageHandlerTests.cs +++ b/main/OpenCover.Test/Framework/Communication/MessageHandlerTests.cs @@ -488,5 +488,18 @@ public void ExceptionDuring_MSG_TrackProcess_ReturnsTrackAsFalse() // assert Assert.AreEqual(false, response.track); } + + [Test] + public void Unsupported_MSG_Type_Throws_Exception() + { + // arrange + Container.GetMock() + .Setup(x => x.PtrToStructure(It.IsAny())) + .Returns(new MSG_TrackMethod_Request()); + + // act + Assert.Throws(() => Instance.StandardMessage(MSG_Type.MSG_Unknown, _mockCommunicationBlock.Object, (i, block) => { }, block => { })); + + } } } diff --git a/main/OpenCover.Test/Framework/FilterTests.cs b/main/OpenCover.Test/Framework/FilterTests.cs index ccc9e0f50..8cff9a559 100644 --- a/main/OpenCover.Test/Framework/FilterTests.cs +++ b/main/OpenCover.Test/Framework/FilterTests.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Mono.Cecil; using Mono.Collections.Generic; @@ -106,7 +105,7 @@ public void AddFilter_ThrowsException_WhenInvalid_AssemblyClassPair( [ValueSource("_invalidFilterExpressions")]string assemblyClassPair) { // arrange - var filter = new Filter(); + var filter = new Filter(false); // act/assert Assert.Catch(() => filter.AddFilter(assemblyClassPair), @@ -118,7 +117,7 @@ public void AddFilter_Adds_ValidAssemblyClassPair( [ValueSource("_filterExpressions")]FilterData assemblyClassPair) { // arrange - var filter = new Filter(); + var filter = new Filter(false); // act filter.AddFilter(assemblyClassPair.FilterExpression); @@ -204,7 +203,7 @@ public void UseAssembly_Tests( [ValueSource("_useAssemblyData")]UseAssemblyData data) { // arrange - var filter = new Filter(); + var filter = new Filter(false); data.Filters.ForEach(filter.AddFilter); // act @@ -342,7 +341,7 @@ public void InstrumentClass_Tests( [ValueSource("_instrumentClassData")]InstrumentClassData data) { // arrange - var filter = new Filter(); + var filter = new Filter(false); data.Filters.ForEach(filter.AddFilter); // act @@ -357,7 +356,7 @@ public void InstrumentClass_Tests( [Test] public void AddAttributeExclusionFilters_HandlesNull() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddAttributeExclusionFilters(null); @@ -367,7 +366,7 @@ public void AddAttributeExclusionFilters_HandlesNull() [Test] public void AddAttributeExclusionFilters_Handles_Null_Elements() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddAttributeExclusionFilters(new[] { null, "" }); @@ -377,7 +376,7 @@ public void AddAttributeExclusionFilters_Handles_Null_Elements() [Test] public void AddAttributeExclusionFilters_Escapes_Elements_And_Matches() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddAttributeExclusionFilters(new[] { ".*" }); @@ -387,7 +386,7 @@ public void AddAttributeExclusionFilters_Escapes_Elements_And_Matches() [Test] public void Entity_Is_Not_Excluded_If_No_Filters_Set() { - var filter = new Filter(); + var filter = new Filter(false); var entity = new Mock(); Assert.IsFalse(filter.ExcludeByAttribute(entity.Object)); @@ -396,7 +395,7 @@ public void Entity_Is_Not_Excluded_If_No_Filters_Set() [Test] public void AddFileExclusionFilters_HandlesNull() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddFileExclusionFilters(null); @@ -406,7 +405,7 @@ public void AddFileExclusionFilters_HandlesNull() [Test] public void AddFileExclusionFilters_Handles_Null_Elements() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddFileExclusionFilters(new[] { null, "" }); @@ -416,7 +415,7 @@ public void AddFileExclusionFilters_Handles_Null_Elements() [Test] public void AddFileExclusionFilters_Escapes_Elements_And_Matches() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddFileExclusionFilters(new[] { ".*" }); @@ -426,7 +425,7 @@ public void AddFileExclusionFilters_Escapes_Elements_And_Matches() [Test] public void AddTestFileFilters_HandlesNull() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddTestFileFilters(null); @@ -436,7 +435,7 @@ public void AddTestFileFilters_HandlesNull() [Test] public void AssemblyIsIncludedForTestMethodGatheringWhenFilterMatches() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddTestFileFilters(new[] { "A*" }); @@ -448,7 +447,7 @@ public void AssemblyIsIncludedForTestMethodGatheringWhenFilterMatches() [Test] public void AddTestFileFilters_Handles_Null_Elements() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddTestFileFilters(new[] { null, "" }); @@ -458,7 +457,7 @@ public void AddTestFileFilters_Handles_Null_Elements() [Test] public void AddTestFileFilters_Escapes_Elements_And_Matches() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddTestFileFilters(new[] { ".*" }); @@ -505,7 +504,7 @@ public void AddTestFileFilters_DoesNotWrap_ForRegexFilters() [Test] public void File_Is_Not_Excluded_If_No_Filters_Set() { - var filter = new Filter(); + var filter = new Filter(false); Assert.IsFalse(filter.ExcludeByFile("xyz.cs")); } @@ -513,7 +512,7 @@ public void File_Is_Not_Excluded_If_No_Filters_Set() [Test] public void File_Is_Not_Excluded_If_No_File_Not_Supplied() { - var filter = new Filter(); + var filter = new Filter(false); Assert.IsFalse(filter.ExcludeByFile("")); } @@ -521,7 +520,7 @@ public void File_Is_Not_Excluded_If_No_File_Not_Supplied() [Test] public void File_Is_Not_Excluded_If_Does_Not_Match_Filter() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddFileExclusionFilters(new[] { "XXX.*" }); Assert.IsFalse(filter.ExcludeByFile("YYY.cs")); @@ -530,7 +529,7 @@ public void File_Is_Not_Excluded_If_Does_Not_Match_Filter() [Test] public void File_Is_Excluded_If_Matches_Filter() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddFileExclusionFilters(new[] { "XXX.*" }); Assert.IsTrue(filter.ExcludeByFile("XXX.cs")); @@ -543,7 +542,7 @@ public void Can_Identify_Excluded_Methods() var type = sourceAssembly.MainModule.Types.First(x => x.FullName == typeof(Samples.Concrete).FullName); - var filter = new Filter(); + var filter = new Filter(false); filter.AddAttributeExclusionFilters(new[] { "*ExcludeMethodAttribute" }); foreach (var methodDefinition in type.Methods) @@ -561,7 +560,7 @@ public void Can_Identify_Excluded_Properties() var type = sourceAssembly.MainModule.Types.First(x => x.FullName == typeof(Samples.Concrete).FullName); - var filter = new Filter(); + var filter = new Filter(false); filter.AddAttributeExclusionFilters(new[] { "*ExcludeMethodAttribute" }); foreach (var propertyDefinition in type.Properties) @@ -577,7 +576,7 @@ public void Can_Identify_Excluded_Anonymous_Issue99() var type = sourceAssembly.MainModule.Types.First(x => x.FullName == typeof(Samples.Anonymous).FullName); - var filter = new Filter(); + var filter = new Filter(false); filter.AddAttributeExclusionFilters(new[] { "*ExcludeMethodAttribute" }); foreach (var methodDefinition in type.Methods.Where(x => x.Name.Contains("EXCLUDE"))) @@ -594,7 +593,7 @@ public void Can_Identify_Included_Anonymous_Issue99() var type = sourceAssembly.MainModule.Types.First(x => x.FullName == typeof(Samples.Anonymous).FullName); - var filter = new Filter(); + var filter = new Filter(false); filter.AddAttributeExclusionFilters(new[] { "*ExcludeMethodAttribute" }); foreach (var methodDefinition in type.Methods.Where(x => x.Name.Contains("INCLUDE"))) @@ -607,7 +606,7 @@ public void Can_Identify_Included_Anonymous_Issue99() [Test] public void Handles_Issue117() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddAttributeExclusionFilters(new[] { "*ExcludeMethodAttribute" }); var mockDefinition = new Mock(); @@ -627,7 +626,7 @@ public void Can_Identify_Excluded_Assemblies() var sourceAssembly = AssemblyDefinition.ReadAssembly(typeof(Samples.Concrete).Assembly.Location); // act - var filter = new Filter(); + var filter = new Filter(false); Assert.False(filter.ExcludeByAttribute(sourceAssembly)); // assert @@ -670,7 +669,7 @@ public void Can_Identify_Excluded_Types(string typeName) var sourceAssembly = AssemblyDefinition.ReadAssembly(typeof(Samples.Concrete).Assembly.Location); // act - var filter = new Filter(); + var filter = new Filter(false); var allTypes = AllTypes(sourceAssembly.MainModule); var typeDefinition = allTypes.First(x => x.Name == typeName); @@ -698,7 +697,7 @@ public void CanIdentify_AutoImplementedProperties() var type = sourceAssembly.MainModule.Types.First(x => x.FullName == typeof(Samples.DeclaredMethodClass).FullName); // act/assert - var filter = new Filter(); + var filter = new Filter(false); var wasTested = false; foreach (var methodDefinition in type.Methods .Where(x => x.IsGetter || x.IsSetter).Where(x => x.Name.EndsWith("AutoProperty"))) @@ -877,6 +876,7 @@ public void Can_BuildFilter_From_CommandLine(string[] commandLine, bool matchAss // issue found by user #329 [TestCase(@"+[Open*]* -[OpenCover.T*]* -[*nunit*]*", @"C:\Release\nunit-console.exe.exe", true, true)] + #endregion #region Cover last branches with invalid path chars (Path.GetInvalidPathChars) diff --git a/main/OpenCover.Test/Framework/Model/InstrumentationModelBuilderTests.cs b/main/OpenCover.Test/Framework/Model/InstrumentationModelBuilderTests.cs index fee20efd6..92f7b3758 100644 --- a/main/OpenCover.Test/Framework/Model/InstrumentationModelBuilderTests.cs +++ b/main/OpenCover.Test/Framework/Model/InstrumentationModelBuilderTests.cs @@ -31,7 +31,7 @@ public void BuildModuleModel_Gets_ModulePath_From_SymbolReader() // assert Assert.IsNotNull(module); - Assert.AreEqual("ModulePath", module.FullName); + Assert.AreEqual("ModulePath", module.ModulePath); Assert.AreEqual("ModulePath", module.Aliases[0]); } diff --git a/main/OpenCover.Test/Framework/Persistance/BasePersistenceTests.cs b/main/OpenCover.Test/Framework/Persistance/BasePersistenceTests.cs index 7f5edcd22..e77eb052e 100644 --- a/main/OpenCover.Test/Framework/Persistance/BasePersistenceTests.cs +++ b/main/OpenCover.Test/Framework/Persistance/BasePersistenceTests.cs @@ -52,9 +52,9 @@ public void Can_Add_SeveralModules_To_Session() //arrange // act - var module1 = new Module {ModuleHash = "123", FullName = "Path1", Classes = new Class[0]}; + var module1 = new Module {ModuleHash = "123", ModulePath = "Path1", Classes = new Class[0]}; module1.Aliases.Add("Path1"); - var module2 = new Module {ModuleHash = "123", FullName = "Path2", Classes = new Class[0]}; + var module2 = new Module {ModuleHash = "123", ModulePath = "Path2", Classes = new Class[0]}; module2.Aliases.Add("Path2"); Instance.PersistModule(module1); Instance.PersistModule(module2); @@ -84,7 +84,7 @@ public void Can_GetBranchPoints_Of_MethodByToken() BranchPoint[] pts; var module = new Module { - FullName = "ModulePath", + ModulePath = "ModulePath", Classes = new[] { new Class @@ -118,7 +118,7 @@ public void Can_GetFullClassName_Of_MethodByToken() // arrange var module = new Module { - FullName = "ModulePath", + ModulePath = "ModulePath", Classes = new[] { new Class {FullName = "namespace.class", Methods = new[] {new Method {MetadataToken = 1001}}} @@ -143,7 +143,7 @@ public void Can_GetSequencePoints_Of_MethodByToken() InstrumentationPoint[] pts; var module = new Module { - FullName = "ModulePath", + ModulePath = "ModulePath", Classes = new[] { new Class @@ -181,9 +181,9 @@ public void Can_Merge_Modules_In_Session_When_HashMatched() .Returns(true); // act - var module1 = new Module {ModuleHash = "123", FullName = "Path1", Classes = new Class[0]}; + var module1 = new Module {ModuleHash = "123", ModulePath = "Path1", Classes = new Class[0]}; module1.Aliases.Add("Path1"); - var module2 = new Module {ModuleHash = "123", FullName = "Path2", Classes = new Class[0]}; + var module2 = new Module {ModuleHash = "123", ModulePath = "Path2", Classes = new Class[0]}; module2.Aliases.Add("Path2"); Instance.PersistModule(module1); Instance.PersistModule(module2); @@ -416,7 +416,7 @@ public void GeBranchPoints_GetsZeroPoints_When_FunctionNotKnown() // arrange var module = new Module { - FullName = "ModuleName", + ModulePath = "ModuleName", Classes = new[] { new Class @@ -445,7 +445,7 @@ public void GetSequencePoints_GetsPoints_When_ModuleAndFunctionKnown_FirstPointI var methodPoint = new InstrumentationPoint {VisitCount = 2000}; var module = new Module { - FullName = "ModulePath", + ModulePath = "ModulePath", Classes = new[] { @@ -486,7 +486,7 @@ public void GetSequencePoints_GetsPoints_When_ModuleAndFunctionKnown_FirstPointI var seqPoint = new SequencePoint {VisitCount = 1000}; var module = new Module { - FullName = "ModulePath", + ModulePath = "ModulePath", Classes = new[] { @@ -525,7 +525,7 @@ public void GetSequencePoints_GetsZeroPoints_When_FunctionNotKnown() // arrange var module = new Module { - FullName = "ModuleName", + ModulePath = "ModuleName", Classes = new[] { new Class @@ -553,7 +553,7 @@ public void GetSequencePoints_GetsZeroPoints_When_ModuleNotKnown() // arrange Instance.PersistModule(new Module { - FullName = "ModuleName", + ModulePath = "ModuleName", Classes = new[] { @@ -639,7 +639,7 @@ public void HideSkipped_With_File_Removes_EmptyClasses() var module = new Module { - FullName = "Keep", + ModulePath = "Keep", Classes = new[] { new Class @@ -694,7 +694,7 @@ public void HideSkipped_With_File_Removes_UnreferencedFiles() Instance.PersistModule(new Module { - FullName = "Keep", + ModulePath = "Keep", Files = new[] {new File {UniqueId = 1, FullPath = "KeepFile"}, new File {UniqueId = 2}}, Classes = new[] { @@ -734,7 +734,7 @@ public void HideSkipped_With_X_Removes_SkippedClasses( @class.MarkAsSkipped(reason); Instance.PersistModule(new Module { - FullName = "Keep", + ModulePath = "Keep", Classes = new[] { @class, @@ -764,7 +764,7 @@ public void HideSkipped_With_X_Removes_SkippedMethods( var module = new Module { - FullName = "Keep", + ModulePath = "Keep", Classes = new[] { new Class @@ -802,17 +802,17 @@ public void HideSkipped_With_X_Removes_SkippedModules( .SetupGet(x => x.HideSkipped) .Returns(new List {reason}); - var module = new Module {FullName = "Skipped"}; + var module = new Module {ModulePath = "Skipped"}; module.MarkAsSkipped(reason); Instance.PersistModule(module); - Instance.PersistModule(new Module {FullName = "Keep"}); + Instance.PersistModule(new Module {ModulePath = "Keep"}); // act Instance.Commit(); // assert Assert.AreEqual(1, Instance.CoverageSession.Modules.Count()); - Assert.AreEqual("Keep", Instance.CoverageSession.Modules[0].FullName); + Assert.AreEqual("Keep", Instance.CoverageSession.Modules[0].ModulePath); } /// @@ -827,7 +827,7 @@ public void var point = new InstrumentationPoint {IsSkipped = false}; var module = new Module { - FullName = "Keep", + ModulePath = "Keep", Classes = new[] { new Class {Methods = new[] {new Method {MethodPoint = point}, new Method()}}, @@ -864,7 +864,7 @@ public void public void IsTracking_Fase_IfModuleSkipped() { // arrange - var module = new Module {FullName = "ModulePath"}; + var module = new Module {ModulePath = "ModulePath"}; module.MarkAsSkipped(SkippedMethod.Filter); module.Aliases.Add("ModulePath"); @@ -881,7 +881,7 @@ public void IsTracking_Fase_IfModuleSkipped() public void IsTracking_True_IfModuleKnown() { // arrange - var module = new Module {FullName = "ModulePath", Classes = new Class[0]}; + var module = new Module {ModulePath = "ModulePath", Classes = new Class[0]}; module.Aliases.Add("ModulePath"); Instance.PersistModule(module); diff --git a/main/OpenCover.Test/Framework/Persistance/FilePersistenceTests.cs b/main/OpenCover.Test/Framework/Persistance/FilePersistenceTests.cs index 9bec80951..e3bcabfbf 100644 --- a/main/OpenCover.Test/Framework/Persistance/FilePersistenceTests.cs +++ b/main/OpenCover.Test/Framework/Persistance/FilePersistenceTests.cs @@ -61,7 +61,9 @@ public void CanLoadExistingFileWhenInitialising() var moduleHash = Guid.NewGuid().ToString(); var persistence = new FilePersistance(_mockCommandLine.Object, _mockLogger.Object); persistence.Initialise(_filePath, false); - var point = new SequencePoint(); + var point = new SequencePoint() + // BranchPoints within SequencePoint shorther than 3 characters will be removed + {StartLine = 1, EndLine = 1, StartColumn = 1, EndColumn = 4}; var branchPoint = new BranchPoint{Path = 0, OffsetPoints = new List()}; var branchPoint2 = new BranchPoint { Path = 1, OffsetPoints = new List{1,2}}; var file = new OpenCover.Framework.Model.File(); diff --git a/main/OpenCover.Test/Framework/Symbols/CecilSymbolManagerTests.cs b/main/OpenCover.Test/Framework/Symbols/CecilSymbolManagerTests.cs index 1f05e2d39..77fb938d3 100644 --- a/main/OpenCover.Test/Framework/Symbols/CecilSymbolManagerTests.cs +++ b/main/OpenCover.Test/Framework/Symbols/CecilSymbolManagerTests.cs @@ -661,7 +661,7 @@ public void Can_Exclude_A_Method_By_An_FileFilter() public void Can_Exclude_AutoImplmentedProperties() { // arrange - var filter = new Filter(); + var filter = new Filter(false); _mockFilter .Setup(x => x.InstrumentClass(It.IsAny(), It.IsAny())) .Returns(true); diff --git a/main/OpenCover.Test/Framework/Utility/CodeCoverageStringTextSourceTest.cs b/main/OpenCover.Test/Framework/Utility/CodeCoverageStringTextSourceTest.cs index 7d56732a9..674582471 100644 --- a/main/OpenCover.Test/Framework/Utility/CodeCoverageStringTextSourceTest.cs +++ b/main/OpenCover.Test/Framework/Utility/CodeCoverageStringTextSourceTest.cs @@ -333,7 +333,7 @@ public void CountLinesLineFeed() } [Test] - public void CountLinesCarriageReturn() + public void CountLinesCrLf() { // arrange @@ -384,7 +384,9 @@ public void GetSource() // assert Assert.True (!ReferenceEquals(source, null)); - Assert.True (source.FileType == FileType.Unsupported); + Assert.True (source.FileType == FileType.CSharp); + Assert.True (source.FilePath == cSharpFileName); + Assert.False (source.FileFound); // arrange System.IO.File.WriteAllLines(cSharpFileName, lines); @@ -396,6 +398,8 @@ public void GetSource() // assert Assert.True (!ReferenceEquals(source, null)); Assert.True (source.FileType == FileType.CSharp); + Assert.True (source.FilePath == cSharpFileName); + Assert.True (source.FileFound); // arrange System.IO.File.WriteAllLines(vBasicFileName, lines); @@ -407,6 +411,8 @@ public void GetSource() // assert Assert.True (!ReferenceEquals(source, null)); Assert.True (source.FileType == FileType.Unsupported); + Assert.True (source.FilePath == vBasicFileName); + Assert.True (source.FileFound); } } diff --git a/main/OpenCover.Test/Framework/Utility/SourceRepositoryTest.cs b/main/OpenCover.Test/Framework/Utility/SourceRepositoryTest.cs index 088eed646..c0f15358e 100644 --- a/main/OpenCover.Test/Framework/Utility/SourceRepositoryTest.cs +++ b/main/OpenCover.Test/Framework/Utility/SourceRepositoryTest.cs @@ -189,10 +189,6 @@ public void CreateGetSourceAndSequencePoints() Assert.True (sRepo.GetSequencePointText(spLeft) == "{"); Assert.True (sRepo.GetSequencePointText(spRight) == "}"); - Assert.True (sRepo.IsLeftCurlyBraceSequencePoint(spLeft)); - Assert.True (sRepo.IsRightCurlyBraceSequencePoint(spRight)); - Assert.False (sRepo.IsLeftCurlyBraceSequencePoint(spRight)); - Assert.False (sRepo.IsRightCurlyBraceSequencePoint(spLeft)); } } } diff --git a/main/OpenCover.Test/OpenCover.Test.csproj b/main/OpenCover.Test/OpenCover.Test.csproj index eb9d68d34..fc1ac316c 100644 --- a/main/OpenCover.Test/OpenCover.Test.csproj +++ b/main/OpenCover.Test/OpenCover.Test.csproj @@ -139,6 +139,7 @@ MoqFramework\UnityAutoMockContainer.cs + @@ -197,9 +198,7 @@ OpenCover.Support - - - + diff --git a/main/OpenCover.Test/Samples/SimpleXUnit.cs b/main/OpenCover.Test/Samples/SimpleXUnit.cs index 14259e2d2..d1d7d6fdf 100644 --- a/main/OpenCover.Test/Samples/SimpleXUnit.cs +++ b/main/OpenCover.Test/Samples/SimpleXUnit.cs @@ -13,7 +13,7 @@ public class SimpleXUnit [Fact] public void AddAttributeExclusionFilters_Handles_Null_Elements() { - var filter = new Filter(); + var filter = new Filter(false); filter.AddAttributeExclusionFilters(new[] { null, "" }); diff --git a/tools/sonarqube/MSBuild.SonarQube.Runner.exe b/tools/sonarqube/MSBuild.SonarQube.Runner.exe new file mode 100644 index 000000000..8823dac26 Binary files /dev/null and b/tools/sonarqube/MSBuild.SonarQube.Runner.exe differ diff --git a/tools/sonarqube/SonarQube.Analysis.xml b/tools/sonarqube/SonarQube.Analysis.xml new file mode 100644 index 000000000..1fda76a6d --- /dev/null +++ b/tools/sonarqube/SonarQube.Analysis.xml @@ -0,0 +1,33 @@ + + + + http://sonar.many-monkeys.com:9000 + + + + + + \ No newline at end of file diff --git a/tools/sonarqube/SonarQube.Common.dll b/tools/sonarqube/SonarQube.Common.dll new file mode 100644 index 000000000..d9b9b1f8f Binary files /dev/null and b/tools/sonarqube/SonarQube.Common.dll differ