From eecbb2646481d051629bd2990fdf9d745266fc5a Mon Sep 17 00:00:00 2001
From: Pavel Mikula
<57188685+pavel-mikula-sonarsource@users.noreply.github.com>
Date: Wed, 5 Feb 2025 09:51:38 +0100
Subject: [PATCH] SCAN4NET-231 Cleanup RoslynAnalyzerProviderTest (#2313)
---
.../RoslynAnalyzerProviderTests.cs | 376 ++++++++----------
.../Roslyn/RoslynAnalyzerProvider.cs | 2 +-
.../Roslyn/RoslynSonarLint.cs | 6 +-
3 files changed, 161 insertions(+), 223 deletions(-)
diff --git a/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynAnalyzerProviderTests.cs b/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynAnalyzerProviderTests.cs
index 6def106b6..21a0e9363 100644
--- a/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynAnalyzerProviderTests.cs
+++ b/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynAnalyzerProviderTests.cs
@@ -73,7 +73,7 @@ public void RoslynConfig_NoAssemblies()
context.AssertInfoMessages("No Roslyn analyzer plugins were specified so no Roslyn analyzers will be run for cs");
context.AssertCorrectRulesets();
context.AssertExpectedAssemblies([]);
- context.AssertExpectedPluginsRequested([]);
+ context.AssertEmptyPluginsRequested();
}
[DataTestMethod]
@@ -112,89 +112,21 @@ public void RoslynConfig_ValidProfile_WithLegacy(string language)
{"sonar.cs.foo", "bar"},
{"sonar.vbnet.foo", "bar"},
{"sonar.cs.analyzer.security.pluginKey", "securitycsharpfrontend" },
- {"sonar.cs.analyzer.security.pluginVersion", "1.42.0" },
+ {"sonar.cs.analyzer.security.pluginVersion", "2.34.0" },
{"sonar.cs.analyzer.security.staticResourceName", "SecurityAnalyzer.zip" },
{"sonaranalyzer.security.cs.pluginKey", "OLDSecurityCSharpFrontend" },
{"sonaranalyzer.security.cs.pluginVersion", "OLDSecurityCSharpFrontend" },
{"sonaranalyzer.security.cs.staticResourceName", "OLDSecurityCSharpFrontend" },
});
var context = new Context(TestContext, sonarProperties, [[@"c:\assembly1.dll"], [@"d:\foo\assembly2.dll"]], null, language);
- var securityProperties = language == RoslynAnalyzerProvider.CSharpLanguage ?
- """
-
-
- sonar.cs.analyzer.security.pluginKey
- securitycsharpfrontend
-
-
- sonar.cs.analyzer.security.pluginVersion
- 1.42.0
-
-
- sonar.cs.analyzer.security.staticResourceName
- SecurityAnalyzer.zip
-
- """ : string.Empty;
- var expectedSonarLintXml = $"""
-
-
-
-
- sonar.{language}.analyzer.dotnet.pluginKey
- {language}
-
-
- sonar.{language}.analyzer.dotnet.pluginVersion
- 1.42.0
-
-
- sonar.{language}.analyzer.dotnet.staticResourceName
- SonarAnalyzer.zip
-
-
- sonar.{language}.testPropertyPattern
- foo
-
-
- sonar.{language}.foo
- bar
- {securityProperties}
-
-
-
- {language}-S1116
-
-
- key
- value
-
-
-
-
- {language}-S1125
-
-
-
-
-
-
- """;
+
context.AssertCorrectAnalyzerSettings();
context.AssertNoWarningsOrErrors();
context.AssertInfoMessages($"Provisioning analyzer assemblies for {language}...");
context.AssertCorrectRulesets();
context.AssertExpectedAssemblies(@"c:\assembly1.dll", @"d:\foo\assembly2.dll");
- var expectedPlugins = new List()
- {
- new() { Key = "wintellect", Version = "1.13.0", StaticResourceName = "wintellect.zip" },
- new() { Key = language, Version = "1.42.0", StaticResourceName = "SonarAnalyzer.zip" },
- };
- if (language == RoslynAnalyzerProvider.CSharpLanguage)
- {
- expectedPlugins.Add(new() { Key = "securitycsharpfrontend", Version = "1.42.0", StaticResourceName = "SecurityAnalyzer.zip" });
- }
- context.AssertExpectedPluginsRequested(expectedPlugins);
- context.AssertExpectedAdditionalFileExists(expectedSonarLintXml);
+ context.AssertExpectedPluginsRequested();
+ context.AssertExpectedAdditionalFileExists(ExpectedSonarLintXml(language));
}
[DataTestMethod]
@@ -227,49 +159,19 @@ public void RoslynConfig_ValidProfile_LegacyOnly(string language)
{"sonar.cs.testPropertyPattern", "foo"},
{"sonar.sources", "**/*.*"},
{"sonar.cs.foo", "bar"},
- {"sonar.vbnet.foo", "bar"}
+ {"sonar.vbnet.foo", "bar"},
+ {"sonaranalyzer.security.cs.pluginKey", "securitycsharpfrontend" },
+ {"sonaranalyzer.security.cs.pluginVersion", "2.34.0" },
+ {"sonaranalyzer.security.cs.staticResourceName", "SecurityAnalyzer.zip" },
});
var context = new Context(TestContext, sonarProperties, [[@"c:\assembly1.dll"], [@"d:\foo\assembly2.dll"]], null, language);
- var expectedSonarLintXml = $"""
-
-
-
-
- sonar.{language}.testPropertyPattern
- foo
-
-
- sonar.{language}.foo
- bar
-
-
-
-
- {language}-S1116
-
-
- key
- value
-
-
-
-
- {language}-S1125
-
-
-
-
-
-
- """;
+
context.AssertCorrectAnalyzerSettings();
context.AssertNoWarningsOrErrors();
context.AssertCorrectRulesets();
context.AssertExpectedAssemblies(@"c:\assembly1.dll", @"d:\foo\assembly2.dll");
- context.AssertExpectedPluginsRequested([
- new() { Key = "wintellect", Version = "1.13.0", StaticResourceName = "wintellect.zip" },
- new() { Key = language, Version = "1.42.0", StaticResourceName = "SonarAnalyzer.zip" }]);
- context.AssertExpectedAdditionalFileExists(expectedSonarLintXml);
+ context.AssertExpectedPluginsRequested();
+ context.AssertExpectedAdditionalFileExists(ExpectedSonarLintXml(language));
}
[DataTestMethod]
@@ -294,86 +196,18 @@ public void RoslynConfig_ValidProfile_WithoutLegacy(string language)
{"sonar.cs.foo", "bar"},
{"sonar.vbnet.foo", "bar"},
{"sonar.cs.analyzer.security.pluginKey", "securitycsharpfrontend"},
- {"sonar.cs.analyzer.security.pluginVersion", "1.13.0"},
+ {"sonar.cs.analyzer.security.pluginVersion", "2.34.0"},
{"sonar.cs.analyzer.security.staticResourceName", "SecurityAnalyzer.zip"},
});
var context = new Context(TestContext, sonarProperties, [[@"c:\assembly1.dll"], [@"d:\foo\assembly2.dll"]], null, language);
- var securityProperties = language == RoslynAnalyzerProvider.CSharpLanguage ?
- """
-
-
- sonar.cs.analyzer.security.pluginKey
- securitycsharpfrontend
-
-
- sonar.cs.analyzer.security.pluginVersion
- 1.13.0
-
-
- sonar.cs.analyzer.security.staticResourceName
- SecurityAnalyzer.zip
-
- """ : string.Empty;
- var expectedSonarLintXml = $"""
-
-
-
-
- sonar.{language}.analyzer.dotnet.pluginKey
- {language}
-
-
- sonar.{language}.analyzer.dotnet.pluginVersion
- 1.42.0
-
-
- sonar.{language}.analyzer.dotnet.staticResourceName
- SonarAnalyzer.zip
-
-
- sonar.{language}.testPropertyPattern
- foo
-
-
- sonar.{language}.foo
- bar
- {securityProperties}
-
-
-
- {language}-S1116
-
-
- key
- value
-
-
-
-
- {language}-S1125
-
-
-
-
-
-
- """;
+
context.AssertCorrectAnalyzerSettings();
context.AssertNoWarningsOrErrors();
context.AssertInfoMessages($"Provisioning analyzer assemblies for {language}...");
context.AssertCorrectRulesets();
context.AssertExpectedAssemblies(@"c:\assembly1.dll", @"d:\foo\assembly2.dll");
- var expectedPlugins = new List()
- {
- new() { Key = "wintellect", Version = "1.13.0", StaticResourceName = "wintellect.zip" },
- new() { Key = language, Version = "1.42.0", StaticResourceName = "SonarAnalyzer.zip" },
- };
- if (language == RoslynAnalyzerProvider.CSharpLanguage)
- {
- expectedPlugins.Add(new() { Key = "securitycsharpfrontend", Version = "1.13.0", StaticResourceName = "SecurityAnalyzer.zip" });
- }
- context.AssertExpectedPluginsRequested(expectedPlugins);
- context.AssertExpectedAdditionalFileExists(expectedSonarLintXml);
+ context.AssertExpectedPluginsRequested();
+ context.AssertExpectedAdditionalFileExists(ExpectedSonarLintXml(language));
}
[DataTestMethod]
@@ -394,13 +228,83 @@ public void RoslynConfig_IncompletePluginIgnored(string analyzerIdProperty, stri
context.AssertInfoMessages("No Roslyn analyzer plugins were specified so no Roslyn analyzers will be run for cs");
context.AssertCorrectRulesets();
context.AssertExpectedAssemblies([]);
- context.AssertExpectedPluginsRequested([]);
+ context.AssertEmptyPluginsRequested();
}
private static BuildSettings CreateSettings(string rootDir) =>
BuildSettings.CreateNonTeamBuildSettingsForTesting(rootDir);
- private class Context
+ private static string ExpectedSonarLintXml(string language) =>
+ language switch
+ {
+ RoslynAnalyzerProvider.CSharpLanguage => $"""
+
+
+
+
+ sonar.cs.testPropertyPattern
+ foo
+
+
+ sonar.cs.foo
+ bar
+
+
+
+
+ cs-S1116
+
+
+ key
+ value
+
+
+
+
+ cs-S1125
+
+
+
+
+
+
+ """,
+ RoslynAnalyzerProvider.VBNetLanguage => """
+
+
+
+
+ sonar.vbnet.testPropertyPattern
+ foo
+
+
+ sonar.vbnet.foo
+ bar
+
+
+
+
+ vbnet-S1116
+
+
+ key
+ value
+
+
+
+
+ vbnet-S1125
+
+
+
+
+
+
+ """,
+ _ => throw new NotSupportedException($"Unexpected language: {language}")
+ };
+
+ private sealed class Context
{
private readonly TestContext testContext;
private readonly TestLogger logger = new();
@@ -420,10 +324,10 @@ public Context(TestContext testContext, ListPropertiesProvider properties, List<
ActualSettings = sut.SetupAnalyzer();
}
- public void AssertCorrectRulesets(string expectedRules = null)
+ public void AssertCorrectRulesets()
{
- CheckRuleset(ActualSettings.RulesetPath, false, expectedRules);
- CheckRuleset(ActualSettings.DeactivatedRulesetPath, true, expectedRules);
+ CheckRuleset(ActualSettings.RulesetPath, false);
+ CheckRuleset(ActualSettings.DeactivatedRulesetPath, true);
}
public void AssertNoWarningsOrErrors()
@@ -467,8 +371,22 @@ public void AssertExpectedAssemblies(params string[] expected)
ActualSettings.AnalyzerPlugins.Should().HaveCount(expected.Length, "Too many assembly file paths returned");
}
- public void AssertExpectedPluginsRequested(IEnumerable plugins) =>
- analyzerInstaller.AssertOnlyExpectedPluginsRequested(plugins);
+ public void AssertEmptyPluginsRequested() =>
+ analyzerInstaller.AssertOnlyExpectedPluginsRequested([]);
+
+ public void AssertExpectedPluginsRequested()
+ {
+ var expectedPlugins = new List()
+ {
+ new() { Key = "wintellect", Version = "1.13.0", StaticResourceName = "wintellect.zip" },
+ new() { Key = language, Version = "1.42.0", StaticResourceName = "SonarAnalyzer.zip" },
+ };
+ if (language == RoslynAnalyzerProvider.CSharpLanguage)
+ {
+ expectedPlugins.Add(new() { Key = "securitycsharpfrontend", Version = "2.34.0", StaticResourceName = "SecurityAnalyzer.zip" });
+ }
+ analyzerInstaller.AssertOnlyExpectedPluginsRequested(expectedPlugins);
+ }
public void AssertExpectedAdditionalFileExists(string expectedContent, string expectedFileName = "SonarLint.xml")
{
@@ -490,37 +408,61 @@ public void AssertExpectedAdditionalFileExists(string expectedContent, string ex
}
}
- private static List CreateRules() =>
- [
- new("csharpsquid", "cs-S1116", true) { Parameters = new() { { "key", "value" } } },
- new("csharpsquid", "cs-S1125", true),
- new("roslyn.wintellect", "Wintellect003", true),
- new("csharpsquid", "cs-S1000", false),
- new("vbnet", "vbnet-S1116", true) { Parameters = new() { { "key", "value" } } },
- new("vbnet", "vbnet-S1125", true),
- new("vbnet", "vbnet-S1000", false),
- new("roslyn.sonaranalyzer.security.cs", "SECURITY2076", true)
- ];
-
- private void CheckRuleset(string ruleSetPath, bool isDeactivated, string expectedRules = null)
+ private List CreateRules() =>
+ language switch
+ {
+ RoslynAnalyzerProvider.CSharpLanguage =>
+ [
+ new("csharpsquid", "cs-S1116", true) { Parameters = new() { { "key", "value" } } },
+ new("csharpsquid", "cs-S1125", true),
+ new("roslyn.wintellect", "Wintellect003", true),
+ new("csharpsquid", "cs-S1000", false),
+ new("roslyn.sonaranalyzer.security.cs", "SECURITY2076", true)
+ ],
+ RoslynAnalyzerProvider.VBNetLanguage => // VB.NET language will never receive roslyn.sonaranalyzer.security.cs rules, because those are only in the C# QP
+ [
+ new("roslyn.wintellect", "Wintellect003", true),
+ new("vbnet", "vbnet-S1116", true) { Parameters = new() { { "key", "value" } } },
+ new("vbnet", "vbnet-S1125", true),
+ new("vbnet", "vbnet-S1000", false),
+ ],
+ _ => throw new NotSupportedException($"Unexpected language: {language}")
+ };
+
+ private string ExpectedRuleSetFormat() =>
+ language switch
+ {
+ RoslynAnalyzerProvider.CSharpLanguage => """
+
+
+
+
+
+
+
+
+
+
+ """,
+ RoslynAnalyzerProvider.VBNetLanguage => """
+
+
+
+
+
+
+
+
+
+ """,
+ _ => throw new NotSupportedException($"Unexpected language: {language}")
+ };
+
+ private void CheckRuleset(string ruleSetPath, bool isDeactivated)
{
var expectedFileName = isDeactivated ? $"Sonar-{language}-none.ruleset" : $"Sonar-{language}.ruleset";
var expectedRule = isDeactivated ? "None" : "Warning";
- var expectedContent = string.Format(expectedRules ?? """
-
-
-
-
-
-
-
-
-
-
-
-
-
- """, expectedRule);
+ var expectedContent = string.Format(ExpectedRuleSetFormat(), expectedRule);
ruleSetPath.Should().NotBeNullOrEmpty("Ruleset file path should be set");
Path.IsPathRooted(ruleSetPath).Should().BeTrue("Ruleset file path should be absolute");
Path.GetFileName(ruleSetPath).Should().Be(expectedFileName, "Ruleset file does not have the expected name");
diff --git a/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynAnalyzerProvider.cs b/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynAnalyzerProvider.cs
index 44e3b294a..b8661ddc3 100644
--- a/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynAnalyzerProvider.cs
+++ b/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynAnalyzerProvider.cs
@@ -123,7 +123,7 @@ private Plugin[] CreatePlugins()
{
candidates.Remove(LegacyServerPropertyPrefix + language);
}
- if (candidates.ContainsKey(string.Format(ServerPropertyFormat, language) + ".security") || language == VBNetLanguage)
+ if (candidates.ContainsKey(string.Format(ServerPropertyFormat, language) + ".security"))
{
candidates.Remove("sonaranalyzer.security.cs");
}
diff --git a/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynSonarLint.cs b/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynSonarLint.cs
index d2b6e382f..cc5717bd7 100644
--- a/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynSonarLint.cs
+++ b/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynSonarLint.cs
@@ -18,10 +18,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using SonarScanner.MSBuild.Common;
using SonarScanner.MSBuild.PreProcessor.Roslyn.Model;
namespace SonarScanner.MSBuild.PreProcessor.Roslyn;
@@ -43,7 +39,7 @@ public static string GenerateXml(IEnumerable activeRules, IAnalysisPr
builder.AppendLine(" ");
foreach (var pair in settings)
{
- if (!Utilities.IsSecuredServerProperty(pair.Id))
+ if (!Utilities.IsSecuredServerProperty(pair.Id) && !pair.Id.StartsWith($"sonar.{language}.analyzer.")) // sonar.cs.analyzer are used to talk only to this scanner, not analyzers
{
WriteSetting(builder, pair.Id, pair.Value);
}