// Verifies the results for the given web.config file path. private static void VerifyResults(string webConfigPath, IList <Diagnostic> allDiagnostics, string languageVersion) { var actualIssues = allDiagnostics.Where(d => d.Location.GetLineSpan().Path.EndsWith(webConfigPath)); var expectedIssues = IssueLocationCollector.GetExpectedIssueLocations(SourceText.From(File.ReadAllText(webConfigPath)).Lines).ToList(); DiagnosticVerifier.CompareActualToExpected(languageVersion, actualIssues, expectedIssues, false); }
public static void VerifyAnalyzer(string path, SonarDiagnosticAnalyzer diagnosticAnalyzer, ParseOptions options = null, params MetadataReference[] additionalReferences) { var file = new FileInfo(path); var parseOptions = GetParseOptionsAlternatives(options, file.Extension); var issueLocationCollector = new IssueLocationCollector(); using (var workspace = new AdhocWorkspace()) { var document = GetDocument(file, GeneratedAssemblyName, workspace, additionalReferences: additionalReferences); var project = document.Project; foreach (var parseOption in parseOptions) { if (parseOption != null) { project = project.WithParseOptions(parseOption); } var compilation = project.GetCompilationAsync().Result; var diagnostics = GetDiagnostics(compilation, diagnosticAnalyzer); var expectedIssues = issueLocationCollector .GetExpectedIssueLocations(compilation.SyntaxTrees.First().GetText().Lines) .ToList(); foreach (var diagnostic in diagnostics) { var location = diagnostic.Location; var message = diagnostic.GetMessage(); string issueId; VerifyIssue(expectedIssues, issue => issue.IsPrimary, location, message, out issueId); var sortedAdditionalLocations = diagnostic.AdditionalLocations .OrderBy(x => x.GetLineNumberToReport()) .ThenBy(x => x.GetLineSpan().StartLinePosition.Character) .ToList(); for (int i = 0; i < sortedAdditionalLocations.Count; i++) { location = sortedAdditionalLocations[i]; diagnostic.Properties.TryGetValue(i.ToString(), out message); VerifyIssue(expectedIssues, issue => issue.IssueId == issueId && !issue.IsPrimary, location, message, out issueId); } } if (expectedIssues.Count != 0) { Execute.Assertion.FailWith($"Issue expected but not raised on line(s) {string.Join(",", expectedIssues.Select(i => i.LineNumber))}."); } } } }
public void GetExpectedIssueLocations_No_Comments() { var code = @"public class Foo { public void Bar(object o) { Console.WriteLine(o); } }"; var locations = IssueLocationCollector.GetExpectedIssueLocations(SourceText.From(code).Lines); locations.Should().BeEmpty(); }
private static void VerifyAnalyzer(IEnumerable <DocumentInfo> documents, string fileExtension, SonarDiagnosticAnalyzer diagnosticAnalyzer, ParseOptions options = null, params MetadataReference[] additionalReferences) { var parseOptions = GetParseOptionsAlternatives(options, fileExtension); using (var workspace = new AdhocWorkspace()) { var project = CreateProject(fileExtension, GeneratedAssemblyName, workspace, additionalReferences); documents.ToList().ForEach(document => project = project.AddDocument(document.Name, document.Content).Project); // side effect on purpose (project is immutable) var issueLocationCollector = new IssueLocationCollector(); foreach (var parseOption in parseOptions) { if (parseOption != null) { project = project.WithParseOptions(parseOption); } var compilation = project.GetCompilationAsync().Result; var diagnostics = GetDiagnostics(compilation, diagnosticAnalyzer); var expectedIssues = issueLocationCollector .GetExpectedIssueLocations(compilation.SyntaxTrees.Skip(1).First().GetText().Lines) .ToList(); foreach (var diagnostic in diagnostics) { string issueId; VerifyIssue(expectedIssues, issue => issue.IsPrimary, diagnostic.Location, diagnostic.GetMessage(), out issueId); diagnostic.AdditionalLocations .Select((location, i) => diagnostic.GetSecondaryLocation(i)) .OrderBy(x => x.Location.GetLineNumberToReport()) .ThenBy(x => x.Location.GetLineSpan().StartLinePosition.Character) .ToList() .ForEach(secondaryLocation => { VerifyIssue(expectedIssues, issue => issue.IssueId == issueId && !issue.IsPrimary, secondaryLocation.Location, secondaryLocation.Message, out issueId); }); } if (expectedIssues.Count != 0) { Execute.Assertion.FailWith($"Issue expected but not raised on line(s) {string.Join(",", expectedIssues.Select(i => i.LineNumber))}."); } } } }
public void GetExpectedIssueLocations_Multiple_PrimaryIds() { var code = @"public class Foo { public void Bar(object o) // Noncompliant [myId1] { Console.WriteLine(o); // Noncompliant [myId1] } }"; Action action = () => IssueLocationCollector.GetExpectedIssueLocations(SourceText.From(code).Lines); action.Should().Throw <InvalidOperationException>() .WithMessage("Primary location with id [myId1] found on multiple lines: 3, 5"); }
public void GetExpectedIssueLocations_OnlyCommentedNoncompliant() { var code = @"public class MyNoncompliantClass { public void NoncompliantMethod(object o) { Console.WriteLine(o); // Noncompliant } }"; var locations = IssueLocationCollector.GetExpectedIssueLocations(SourceText.From(code).Lines); locations.Should().ContainSingle(); locations.Select(l => l.IsPrimary).Should().Equal(new[] { true }); locations.Select(l => l.LineNumber).Should().Equal(new[] { 5 }); }
public void GetExpectedIssueLocations_Invalid_Type_Format() { var code = @"public class Foo { public void Bar(object o) // Is Noncompliant { Console.WriteLine(o); } }"; Action action = () => IssueLocationCollector.GetExpectedIssueLocations(SourceText.From(code).Lines); action.Should().Throw <InvalidOperationException>() .WithMessage(@"Line 2 looks like it contains comment for noncompliant code, but it is not recognized as one of the expected pattern. Either remove the Noncompliant/Secondary word or precise pattern '^^' from the comment, or fix the pattern."); }
public void GetExpectedIssueLocations_Redundant_Locations() { var code = @"public class Foo { public void Bar(object o) // Noncompliant ^17#3 // ^^^ { Console.WriteLine(o); } }"; Action action = () => IssueLocationCollector.GetExpectedIssueLocations(SourceText.From(code).Lines); action.Should().Throw <InvalidOperationException>() .WithMessage("Unexpected redundant issue location on line 3. Issue location can be set either " + "with 'precise issue location' or 'exact column location' pattern but not both."); }
public void GetExpectedIssueLocations_Locations_VB() { var code = @" Public Class Foo Public Sub Bar(o As Object) ' Noncompliant ' Noncompliant@+1 Console.WriteLine(o) End Sub End Class"; var locations = IssueLocationCollector.GetExpectedIssueLocations(SourceText.From(code).Lines); locations.Should().HaveCount(2); locations.Select(l => l.IsPrimary).Should().Equal(new[] { true, true }); locations.Select(l => l.LineNumber).Should().Equal(new[] { 4, 6 }); }
public void GetExpectedIssueLocations_Locations_CS() { var code = @" public class Foo { public void Bar(object o) // Noncompliant { // Noncompliant@+1 Console.WriteLine(o); } }"; var locations = IssueLocationCollector.GetExpectedIssueLocations(SourceText.From(code).Lines); locations.Should().HaveCount(2); locations.Select(l => l.IsPrimary).Should().Equal(new[] { true, true }); locations.Select(l => l.LineNumber).Should().Equal(new[] { 4, 7 }); }
public void GetExpectedIssueLocations_ExactColumns() { var code = @"public class Foo { public void Bar(object o) // Noncompliant ^17#3 // Secondary@-1 ^28#1 { Console.WriteLine(o); } }"; var locations = IssueLocationCollector.GetExpectedIssueLocations(SourceText.From(code).Lines); locations.Should().HaveCount(2); locations.Select(l => l.IsPrimary).Should().BeEquivalentTo(new[] { true, false }); locations.Select(l => l.LineNumber).Should().Equal(new[] { 3, 3 }); locations.Select(l => l.Start).Should().Equal(new[] { 16, 27 }); locations.Select(l => l.Length).Should().Equal(new[] { 3, 1 }); }
public void GetExpectedIssueLocations_Locations_Xml() { var code = @"<Root> <SelfClosing /><!-- Noncompliant --> <SelfClosing /><!-- Noncompliant with additional comment and new line --> <InsideWithSpace><!-- Noncompliant--></InsideWithSpace> <InsideNoSpace><!--Secondary--></InsideNoSpace> <Innocent><!--Noncompliant@+1--></Innocent> <Guilty /> <!-- Noncompliant - this should not be detected as expected issue --> </Root>"; var locations = IssueLocationCollector.GetExpectedIssueLocations(SourceText.From(code).Lines); locations.Should().HaveCount(5); locations.Select(l => l.IsPrimary).Should().Equal(new[] { true, true, true, false, true }); locations.Select(l => l.LineNumber).Should().Equal(new[] { 2, 3, 5, 6, 8 }); }
public static void VerifyAnalyzer(IEnumerable <string> paths, SonarDiagnosticAnalyzer diagnosticAnalyzer, ParseOptions options = null, params MetadataReference[] additionalReferences) { if (paths == null || !paths.Any()) { throw new ArgumentException("Please specify at least one file path to analyze.", nameof(paths)); } var files = paths.Select(path => new FileInfo(path)).ToList(); if (files.Select(file => file.Extension).Distinct().Count() != 1) { throw new ArgumentException("Please use a collection of paths with the same extension", nameof(paths)); } var parseOptions = files.SelectMany(file => GetParseOptionsAlternatives(options, file.Extension)).Distinct(); var issueLocationCollector = new IssueLocationCollector(); using (var workspace = new AdhocWorkspace()) { var project = CreateProject(files[0], GeneratedAssemblyName, workspace, additionalReferences); files.ForEach(file => project = project.AddDocument(file)); // side effect on purpose (project is immutable) foreach (var parseOption in parseOptions) { if (parseOption != null) { project = project.WithParseOptions(parseOption); } var compilation = project.GetCompilationAsync().Result; var diagnostics = GetDiagnostics(compilation, diagnosticAnalyzer); var expectedIssues = issueLocationCollector .GetExpectedIssueLocations(compilation.SyntaxTrees.Skip(1).First().GetText().Lines) .ToList(); foreach (var diagnostic in diagnostics) { string issueId; VerifyIssue(expectedIssues, issue => issue.IsPrimary, diagnostic.Location, diagnostic.GetMessage(), out issueId); diagnostic.AdditionalLocations .Select((location, i) => diagnostic.GetSecondaryLocation(i)) .OrderBy(x => x.Location.GetLineNumberToReport()) .ThenBy(x => x.Location.GetLineSpan().StartLinePosition.Character) .ToList() .ForEach(secondaryLocation => { VerifyIssue(expectedIssues, issue => issue.IssueId == issueId && !issue.IsPrimary, secondaryLocation.Location, secondaryLocation.Message, out issueId); }); } if (expectedIssues.Count != 0) { Execute.Assertion.FailWith($"Issue expected but not raised on line(s) {string.Join(",", expectedIssues.Select(i => i.LineNumber))}."); } } } }
private static void VerifyAnalyzer(IEnumerable <DocumentInfo> documents, string fileExtension, DiagnosticAnalyzer diagnosticAnalyzer, ParseOptions options = null, Action <DiagnosticAnalyzer, Compilation> additionalVerify = null, params MetadataReference[] additionalReferences) { try { HookSuppression(); var parseOptions = GetParseOptionsAlternatives(options, fileExtension); using (var workspace = new AdhocWorkspace()) { var project = CreateProject(fileExtension, GeneratedAssemblyName, workspace, additionalReferences); project = documents.Aggregate(project, (p, doc) => p.AddDocument(doc.Name, doc.Content).Project); // side effect on purpose (project is immutable) var issueLocationCollector = new IssueLocationCollector(); foreach (var parseOption in parseOptions) { if (parseOption != null) { project = project.WithParseOptions(parseOption); } var compilation = project.GetCompilationAsync().Result; var diagnostics = GetDiagnostics(compilation, diagnosticAnalyzer); var expectedIssues = issueLocationCollector .GetExpectedIssueLocations(compilation.SyntaxTrees.Skip(1).First().GetText().Lines) .ToList(); foreach (var diagnostic in diagnostics) { VerifyIssue(expectedIssues, issue => issue.IsPrimary, diagnostic.Location, diagnostic.GetMessage(), out var issueId); diagnostic.AdditionalLocations .Select((location, i) => diagnostic.GetSecondaryLocation(i)) .OrderBy(x => x.Location.GetLineNumberToReport()) .ThenBy(x => x.Location.GetLineSpan().StartLinePosition.Character) .ToList() .ForEach(secondaryLocation => { VerifyIssue(expectedIssues, issue => issue.IssueId == issueId && !issue.IsPrimary, secondaryLocation.Location, secondaryLocation.Message, out issueId); }); } if (expectedIssues.Count != 0) { Execute.Assertion.FailWith($"Issue expected but not raised on line(s) {string.Join(",", expectedIssues.Select(i => i.LineNumber))}."); } // When there are no diagnostics reported from the test (for example the FileLines analyzer // does not report in each call to Verifier.VerifyAnalyzer) we skip the check for the extension // method. if (diagnostics.Any()) { ExtensionMethodsCalledForAllDiagnostics(diagnosticAnalyzer).Should().BeTrue("The ReportDiagnosticWhenActive should be used instead of ReportDiagnostic"); } additionalVerify?.Invoke(diagnosticAnalyzer, compilation); } } } finally { UnHookSuppression(); } }