public CoverageResult GetCoverageResult() { CalculateCoverage(); Modules modules = new Modules(); foreach (var result in _results) { Documents documents = new Documents(); foreach (var doc in result.Documents.Values) { // Construct Line Results foreach (var line in doc.Lines.Values) { if (documents.TryGetValue(doc.Path, out Classes classes)) { if (classes.TryGetValue(line.Class, out Methods methods)) { if (methods.TryGetValue(line.Method, out Method method)) { documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } else { documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } else { documents[doc.Path].Add(line.Class, new Methods()); documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } else { documents.Add(doc.Path, new Classes()); documents[doc.Path].Add(line.Class, new Methods()); documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } // Construct Branch Results foreach (var branch in doc.Branches.Values) { if (documents.TryGetValue(doc.Path, out Classes classes)) { if (classes.TryGetValue(branch.Class, out Methods methods)) { if (methods.TryGetValue(branch.Method, out Method method)) { method.Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } else { documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } else { documents[doc.Path].Add(branch.Class, new Methods()); documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } else { documents.Add(doc.Path, new Classes()); documents[doc.Path].Add(branch.Class, new Methods()); documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } } modules.Add(Path.GetFileName(result.ModulePath), documents); _instrumentationHelper.RestoreOriginalModule(result.ModulePath, _identifier); } var coverageResult = new CoverageResult { Identifier = _identifier, Modules = modules, InstrumentedResults = _results }; if (!string.IsNullOrEmpty(_mergeWith) && !string.IsNullOrWhiteSpace(_mergeWith) && _fileSystem.Exists(_mergeWith)) { string json = _fileSystem.ReadAllText(_mergeWith); coverageResult.Merge(JsonConvert.DeserializeObject <Modules>(json)); } return(coverageResult); }
public CoverageResult GetCoverageResult() { CalculateCoverage(); Modules modules = new Modules(); foreach (var result in _results) { Documents documents = new Documents(); foreach (var doc in result.Documents.Values) { // Construct Line Results foreach (var line in doc.Lines.Values) { if (documents.TryGetValue(doc.Path, out Classes classes)) { if (classes.TryGetValue(line.Class, out Methods methods)) { if (methods.TryGetValue(line.Method, out Method method)) { documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } else { documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } else { documents[doc.Path].Add(line.Class, new Methods()); documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } else { documents.Add(doc.Path, new Classes()); documents[doc.Path].Add(line.Class, new Methods()); documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } // Construct Branch Results foreach (var branch in doc.Branches.Values) { if (documents.TryGetValue(doc.Path, out Classes classes)) { if (classes.TryGetValue(branch.Class, out Methods methods)) { if (methods.TryGetValue(branch.Method, out Method method)) { method.Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } else { documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } else { documents[doc.Path].Add(branch.Class, new Methods()); documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } else { documents.Add(doc.Path, new Classes()); documents[doc.Path].Add(branch.Class, new Methods()); documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } } modules.Add(Path.GetFileName(result.ModulePath), documents); _instrumentationHelper.RestoreOriginalModule(result.ModulePath, _identifier); } // In case of anonymous delegate compiler generate a custom class and passes it as type.method delegate. // If in delegate method we've a branches we need to move these to "actual" class/method that use it. // We search "method" with same "Line" of closure class method and add missing branches to it, // in this way we correctly report missing branch inside compiled generated anonymous delegate. List <string> compileGeneratedClassToRemove = null; foreach (var module in modules) { foreach (var document in module.Value) { foreach (var @class in document.Value) { foreach (var method in @class.Value) { foreach (var branch in method.Value.Branches) { if (BranchInCompilerGeneratedClass(method.Key)) { Method actualMethod = GetMethodWithSameLineInSameDocument(document.Value, @class.Key, branch.Line); if (actualMethod is null) { continue; } actualMethod.Branches.Add(branch); if (compileGeneratedClassToRemove is null) { compileGeneratedClassToRemove = new List <string>(); } if (!compileGeneratedClassToRemove.Contains(@class.Key)) { compileGeneratedClassToRemove.Add(@class.Key); } } } } } } } // After method/branches analysis of compiled generated class we can remove noise from reports if (!(compileGeneratedClassToRemove is null)) { foreach (var module in modules) { foreach (var document in module.Value) { foreach (var classToRemove in compileGeneratedClassToRemove) { document.Value.Remove(classToRemove); } } } } var coverageResult = new CoverageResult { Identifier = _identifier, Modules = modules, InstrumentedResults = _results, UseSourceLink = _useSourceLink }; if (!string.IsNullOrEmpty(_mergeWith) && !string.IsNullOrWhiteSpace(_mergeWith) && _fileSystem.Exists(_mergeWith)) { string json = _fileSystem.ReadAllText(_mergeWith); coverageResult.Merge(JsonConvert.DeserializeObject <Modules>(json)); } return(coverageResult); }
public CoverageResult GetCoverageResult() { CalculateCoverage(); var modules = new Modules(); foreach (InstrumenterResult result in _results) { var documents = new Documents(); foreach (Document doc in result.Documents.Values) { // Construct Line Results foreach (Line line in doc.Lines.Values) { if (documents.TryGetValue(doc.Path, out Classes classes)) { if (classes.TryGetValue(line.Class, out Methods methods)) { if (methods.TryGetValue(line.Method, out Method method)) { documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } else { documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } else { documents[doc.Path].Add(line.Class, new Methods()); documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } else { documents.Add(doc.Path, new Classes()); documents[doc.Path].Add(line.Class, new Methods()); documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } // Construct Branch Results foreach (Branch branch in doc.Branches.Values) { if (documents.TryGetValue(doc.Path, out Classes classes)) { if (classes.TryGetValue(branch.Class, out Methods methods)) { if (methods.TryGetValue(branch.Method, out Method method)) { method.Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } else { documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } else { documents[doc.Path].Add(branch.Class, new Methods()); documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } else { documents.Add(doc.Path, new Classes()); documents[doc.Path].Add(branch.Class, new Methods()); documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } } modules.Add(Path.GetFileName(result.ModulePath), documents); _instrumentationHelper.RestoreOriginalModule(result.ModulePath, Identifier); } // In case of anonymous delegate compiler generate a custom class and passes it as type.method delegate. // If in delegate method we've a branches we need to move these to "actual" class/method that use it. // We search "method" with same "Line" of closure class method and add missing branches to it, // in this way we correctly report missing branch inside compiled generated anonymous delegate. List <string> compileGeneratedClassToRemove = null; foreach (KeyValuePair <string, Documents> module in modules) { foreach (KeyValuePair <string, Classes> document in module.Value) { foreach (KeyValuePair <string, Methods> @class in document.Value) { // We fix only lamda generated class // https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNameKind.cs#L18 if ([email protected]("<>c")) { continue; } foreach (KeyValuePair <string, Method> method in @class.Value) { foreach (BranchInfo branch in method.Value.Branches) { if (BranchInCompilerGeneratedClass(method.Key)) { Method actualMethod = GetMethodWithSameLineInSameDocument(document.Value, @class.Key, branch.Line); if (actualMethod is null) { continue; } actualMethod.Branches.Add(branch); if (compileGeneratedClassToRemove is null) { compileGeneratedClassToRemove = new List <string>(); } if (!compileGeneratedClassToRemove.Contains(@class.Key)) { compileGeneratedClassToRemove.Add(@class.Key); } } } } } } } // After method/branches analysis of compiled generated class we can remove noise from reports if (compileGeneratedClassToRemove is not null) { foreach (KeyValuePair <string, Documents> module in modules) { foreach (KeyValuePair <string, Classes> document in module.Value) { foreach (string classToRemove in compileGeneratedClassToRemove) { document.Value.Remove(classToRemove); } } } } var coverageResult = new CoverageResult { Identifier = Identifier, Modules = modules, InstrumentedResults = _results, Parameters = _parameters }; if (!string.IsNullOrEmpty(_parameters.MergeWith) && !string.IsNullOrWhiteSpace(_parameters.MergeWith) && _fileSystem.Exists(_parameters.MergeWith)) { string json = _fileSystem.ReadAllText(_parameters.MergeWith); coverageResult.Merge(JsonConvert.DeserializeObject <Modules>(json)); } return(coverageResult); }
public CoverageResult GetCoverageResult() { CalculateCoverage(); Modules modules = new Modules(); foreach (var result in _results) { Documents documents = new Documents(); foreach (var doc in result.Documents.Values) { // Construct Line Results foreach (var line in doc.Lines.Values) { if (documents.TryGetValue(doc.Path, out Classes classes)) { if (classes.TryGetValue(line.Class, out Methods methods)) { if (methods.TryGetValue(line.Method, out Method method)) { documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } else { documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } else { documents[doc.Path].Add(line.Class, new Methods()); documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } else { documents.Add(doc.Path, new Classes()); documents[doc.Path].Add(line.Class, new Methods()); documents[doc.Path][line.Class].Add(line.Method, new Method()); documents[doc.Path][line.Class][line.Method].Lines.Add(line.Number, line.Hits); } } // Construct Branch Results foreach (var branch in doc.Branches.Values) { if (documents.TryGetValue(doc.Path, out Classes classes)) { if (classes.TryGetValue(branch.Class, out Methods methods)) { if (methods.TryGetValue(branch.Method, out Method method)) { method.Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } else { documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } else { documents[doc.Path].Add(branch.Class, new Methods()); documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } else { documents.Add(doc.Path, new Classes()); documents[doc.Path].Add(branch.Class, new Methods()); documents[doc.Path][branch.Class].Add(branch.Method, new Method()); documents[doc.Path][branch.Class][branch.Method].Branches.Add(new BranchInfo { Line = branch.Number, Hits = branch.Hits, Offset = branch.Offset, EndOffset = branch.EndOffset, Path = branch.Path, Ordinal = branch.Ordinal } ); } } } modules.Add(Path.GetFileName(result.ModulePath), documents); InstrumentationHelper.RestoreOriginalModule(result.ModulePath, _identifier); } var coverageResult = new CoverageResult { Identifier = _identifier, Modules = modules, InstrumentedResults = _results }; if (!string.IsNullOrEmpty(_mergeWith) && !string.IsNullOrWhiteSpace(_mergeWith) && File.Exists(_mergeWith)) { // Possible concurrency access to merge file between write/read on parallel testing var json = RetryHelper.Do(() => { using (var file = File.Open(_mergeWith, FileMode.Open, FileAccess.Read, FileShare.None)) { using (var reader = new StreamReader(file)) { return(reader.ReadToEnd()); } } }, () => TimeSpan.FromMilliseconds(100), 5); coverageResult.Merge(JsonConvert.DeserializeObject <Modules>(json)); } return(coverageResult); }