diff --git a/src/Extension/Extension.csproj b/src/Extension/Extension.csproj
index dd65de9..7f6fb2a 100644
--- a/src/Extension/Extension.csproj
+++ b/src/Extension/Extension.csproj
@@ -78,8 +78,10 @@
+
+
+
-
diff --git a/src/Extension/Helpers/SolutionHelper.cs b/src/Extension/Helpers/SolutionHelper.cs
index 6dd7483..d31c8c9 100644
--- a/src/Extension/Helpers/SolutionHelper.cs
+++ b/src/Extension/Helpers/SolutionHelper.cs
@@ -1,4 +1,6 @@
using System.IO;
+using System.Threading.Tasks;
+using Community.VisualStudio.Toolkit;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
@@ -9,6 +11,29 @@ namespace Extension.Helpers
///
internal static class SolutionHelper
{
+ ///
+ /// Returns the solution's root dir, or in Open Folder mode, the open folder's path.
+ ///
+ ///
+ internal static async Task GetSolutionDir()
+ {
+ var serviceProvider = await GetServiceProvider();
+ return serviceProvider == null ? null : GetSolutionDir(serviceProvider);
+ }
+
+ ///
+ /// Returns the that is used to retrieve the solution directory.
+ ///
+ ///
+ internal static async Task GetServiceProvider()
+ {
+ return await ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
+ {
+ await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+ return await VS.GetMefServiceAsync();
+ });
+ }
+
///
/// Returns the solution's root dir, or in Open Folder mode, the open folder's path.
///
diff --git a/src/Extension/Rosie/CodigaCodeAnalysisConfig.cs b/src/Extension/Rosie/CodigaCodeAnalysisConfig.cs
deleted file mode 100644
index ee3caf7..0000000
--- a/src/Extension/Rosie/CodigaCodeAnalysisConfig.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Extension.Rosie
-{
- ///
- /// Stores the ruleset names deserialized from the Codiga config file.
- ///
- ///
- public class CodigaCodeAnalysisConfig
- {
- public List? Rulesets { get; set; }
-
- ///
- /// Returns the ruleset names having filtered out null values from them.
- ///
- /// This is for covering the case where the config file is configured like this:
- ///
- /// rulesets:
- /// -
- ///
- ///
- public List? GetRulesets()
- {
- return Rulesets?.Where(ruleset => ruleset != null).ToList();
- }
- }
-}
diff --git a/src/Extension/Rosie/CodigaConfigFileUtil.cs b/src/Extension/Rosie/CodigaConfigFileUtil.cs
index 730e5aa..a41a427 100644
--- a/src/Extension/Rosie/CodigaConfigFileUtil.cs
+++ b/src/Extension/Rosie/CodigaConfigFileUtil.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Text.RegularExpressions;
using Extension.Helpers;
+using Extension.Rosie.Model.Codiga;
using Extension.SnippetFormats;
using Microsoft.VisualStudio.Shell;
using YamlDotNet.Serialization;
@@ -34,6 +35,8 @@ public static class CodigaConfigFileUtil
private static readonly Regex CodigaRulesetNamePattern = new Regex("^[a-z0-9][a-z0-9-]{4,31}$");
private const string CodigaConfigFileName = "codiga.yml";
+ private const string RULESETS = "rulesets";
+ private const string IGNORE = "ignore";
///
/// Looks up the Codiga config file in the provided Solution's root directory,
@@ -76,64 +79,77 @@ public static void CreateCodigaConfigFile(LanguageUtils.LanguageEnumeration lang
}
///
- /// Collects the list of valid ruleset names from the provided configuration object.
+ /// Deserializes the provided raw YAML string (the content of the Codiga config file) to a
+ /// object, so that ruleset names, ignore prefixes, etc. can be accessed later.
+ ///
+ /// It deserializes it using dynamic typing.
///
- /// The configuration containing the rulesets.
- /// The list of ruleset names or empty list if there is no config or no ruleset.
- public static List CollectRulesetNames(CodigaCodeAnalysisConfig? config)
+ /// The content of the Codiga config file
+ /// The deserialized config file, or in case deserialization failed.
+ public static CodigaCodeAnalysisConfig DeserializeConfig(string rawYamlConfig)
{
- return config?.Rulesets == null
- ? new List()
- : config.Rulesets
+ if (string.IsNullOrWhiteSpace(rawYamlConfig))
+ return CodigaCodeAnalysisConfig.EMPTY;
+
+ try
+ {
+ var codigaConfig = new CodigaCodeAnalysisConfig();
+ var semiRawConfig = ConfigDeserializer.Deserialize(rawYamlConfig);
+ if (semiRawConfig is Dictionary
internal static async void ShowDefaultRulesetCreationInfoBarAsync(InfoBarHolder infoBarHolder)
{
- var serviceProvider = await ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
- {
- await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
- return await VS.GetMefServiceAsync();
- });
+ var serviceProvider = await SolutionHelper.GetServiceProvider();
if (SolutionSettings.IsShouldNotifyUserToCreateCodigaConfig(serviceProvider)
&& CodigaConfigFileUtil.FindCodigaConfigFile(serviceProvider) == null)
diff --git a/src/Extension/Rosie/Model/Codiga/CodigaCodeAnalysisConfig.cs b/src/Extension/Rosie/Model/Codiga/CodigaCodeAnalysisConfig.cs
new file mode 100644
index 0000000..4ed701f
--- /dev/null
+++ b/src/Extension/Rosie/Model/Codiga/CodigaCodeAnalysisConfig.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+
+namespace Extension.Rosie.Model.Codiga
+{
+ ///
+ /// Represents a codiga.yml configuration file.
+ ///
+ ///
+ public class CodigaCodeAnalysisConfig
+ {
+ public static readonly CodigaCodeAnalysisConfig EMPTY = new CodigaCodeAnalysisConfig();
+
+ private List? _rulesets;
+
+ public List Rulesets
+ {
+ get => _rulesets ?? new List();
+ set => _rulesets = value;
+ }
+
+ ///
+ /// Stores [ruleset name -> ruleset ignore configuration] mappings.
+ ///
+ /// Using a map instead of a List<RulesetIgnore>, so that we can query the ruleset
+ /// configs by name, without having to filter the list by the ruleset name.
+ ///
+ public IDictionary Ignore { get; } = new Dictionary();
+ }
+}
\ No newline at end of file
diff --git a/src/Extension/Rosie/Model/Codiga/RuleIgnore.cs b/src/Extension/Rosie/Model/Codiga/RuleIgnore.cs
new file mode 100644
index 0000000..5898474
--- /dev/null
+++ b/src/Extension/Rosie/Model/Codiga/RuleIgnore.cs
@@ -0,0 +1,97 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Extension.Rosie.Model.Codiga
+{
+ ///
+ /// Represents a rule ignore configuration element in the codiga.yml file.
+ ///
+ /// This is the element right under a ruleset name property, e.g.:
+ ///
+ /// - rule1:
+ /// - prefix: /path/to/file/to/ignore
+ ///
+ /// or
+ ///
+ /// - rule2:
+ /// - prefix:
+ /// - /path1
+ /// - /path2
+ ///
+ ///
+ public class RuleIgnore
+ {
+ public string RuleName { get; }
+
+ ///
+ /// The list of prefix values under the prefix property.
+ ///
+ /// In case multiple prefix properties are defined under the same rule config,
+ /// they are all added to this list.
+ ///
+ /// For example, in case of:
+ ///
+ /// ignore:
+ /// - my-python-ruleset:
+ /// - rule1:
+ /// - prefix:
+ /// - /path1
+ /// - /path2
+ /// - prefix: /path3
+ ///
+ /// all of /path1, /path2 and /path3 are stored here.
+ ///
+ /// In case a prefix property contains the same value multiple times,
+ /// they are deduplicated and only once instance is stored, for example:
+ ///
+ /// ignore:
+ /// - my-python-ruleset:
+ /// - rule1:
+ /// - prefix:
+ /// - /path1
+ /// - /path1
+ ///
+ ///
+ public List Prefixes { get; } = new List();
+
+ public RuleIgnore(string ruleName)
+ {
+ RuleName = ruleName;
+ }
+
+ public RuleIgnore(string ruleName, object ruleIgnore)
+ {
+ RuleName = ruleName;
+ if (ruleIgnore is List prefixIgnores)
+ {
+ foreach (var prefixIgnore in prefixIgnores)
+ {
+ if (prefixIgnore is Dictionary prefixIgnoreDict)
+ {
+ var prefixIgnoreValue = prefixIgnoreDict.Values.FirstOrDefault();
+ /*
+ A 'prefix' property can have a single String value:
+ - prefix: /path/to/file/to/ignore
+ */
+ if (prefixIgnoreValue is string value)
+ Prefixes = new List { value };
+
+ /*
+ A 'prefix' property can also have multiple String values as a list:
+ - prefix:
+ - /path1
+ - /path2
+ */
+ else if (prefixIgnoreValue is List prefixes)
+ //It filters out null and non-String prefix values
+ Prefixes = prefixes
+ .Where(prefix => prefix != null)
+ .OfType()
+ .Distinct()
+ .ToList();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/Extension/Rosie/Model/Codiga/RulesetIgnore.cs b/src/Extension/Rosie/Model/Codiga/RulesetIgnore.cs
new file mode 100644
index 0000000..2fe9e6c
--- /dev/null
+++ b/src/Extension/Rosie/Model/Codiga/RulesetIgnore.cs
@@ -0,0 +1,75 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Extension.Rosie.Model.Codiga
+{
+ ///
+ /// Represents a ruleset ignore configuration element in the codiga.yml file.
+ ///
+ /// This is the element right under the root-level ignore property, e.g.:
+ ///
+ /// - my-python-ruleset:
+ /// - rule1:
+ /// - prefix: /path/to/file/to/ignore
+ ///
+ ///
+ public class RulesetIgnore
+ {
+ public string RulesetName { get; }
+
+ ///
+ /// Stores [rule name -> rule ignore configuration] mappings.
+ ///
+ /// Using a map instead of a List<RuleIgnore>, so that we can query the ruleset
+ /// configs by name, without having to filter the list by the ruleset name.
+ ///
+ public IDictionary RuleIgnores { get; } = new Dictionary();
+
+ ///
+ /// Saves the ruleset name and the rule ignore configuration from its value.
+ ///
+ /// the ruleset name
+ /// the value associated to the ruleset name property in codiga.yml
+ public RulesetIgnore(string rulesetName, object ruleIgnoresConfig)
+ {
+ RulesetName = rulesetName;
+
+ if (ruleIgnoresConfig is List ruleIgnores)
+ {
+ foreach (var ruleIgnore in ruleIgnores)
+ {
+ var ruleIgn = ruleIgnore switch
+ {
+ /*
+ A rule ignore config can be a single rule name without any prefix value:
+ - rulename
+ */
+ string ruleName => new RuleIgnore(ruleName),
+
+ /*
+ A rule ignore config can be a Map of the rule name and its object value,
+ with one or more prefix values:
+ - rulename:
+ - prefix: /path/to/file/to/ignore
+ as a {[rulename -> prefix: /path/to/file/to/ignore]} map
+
+ - rulename2:
+ - prefix:
+ - /path1
+ - /path2
+ as a {[rulename2 -> prefix: /path1, /path2]} map
+ */
+ Dictionary ruleIgnoreDict =>
+ new RuleIgnore(
+ ruleIgnoreDict.Keys.FirstOrDefault() as string,
+ ruleIgnoreDict.Values.FirstOrDefault()),
+ _ => null
+ };
+
+ if (ruleIgn != null)
+ RuleIgnores.Add(ruleIgn.RuleName, ruleIgn);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Extension/Rosie/Model/RosieRule.cs b/src/Extension/Rosie/Model/RosieRule.cs
index 889e53a..eb1ecf3 100644
--- a/src/Extension/Rosie/Model/RosieRule.cs
+++ b/src/Extension/Rosie/Model/RosieRule.cs
@@ -4,6 +4,8 @@ namespace Extension.Rosie.Model
{
public class RosieRule
{
+ public string RulesetName { get; }
+ public string RuleName { get; }
public string Id { get; }
public string ContentBase64 { get; }
public string Language { get; }
@@ -12,6 +14,8 @@ public class RosieRule
public string Pattern { get; }
public RosieRule(string rulesetName, Rule rule) {
+ RulesetName = rulesetName;
+ RuleName = rule.Name;
Id = rulesetName + "/" + rule.Name;
ContentBase64 = rule.Content;
Language = rule.Language;
diff --git a/src/Extension/Rosie/RosieClient.cs b/src/Extension/Rosie/RosieClient.cs
index 62fda5f..c2ede14 100644
--- a/src/Extension/Rosie/RosieClient.cs
+++ b/src/Extension/Rosie/RosieClient.cs
@@ -93,7 +93,7 @@ public RosieClient(Func fileNameProvider, Func
internal DateTime ConfigFileLastWriteTime { get; set; } = DateTime.MinValue;
- ///
- /// Ruleset names stored locally in the codiga.yml config file.
- ///
- public IList RulesetNames { get; set; }
+ public CodigaCodeAnalysisConfig CodigaConfig { get; set; }
///
/// The cache is considered initialized with rules right after the response is received from ,
@@ -88,11 +88,14 @@ private RosieRulesCache(ICodigaClientProvider clientProvider)
{
_clientProvider = clientProvider;
_cachedRules = new ConcurrentDictionary();
- RulesetNames = new SynchronizedCollection();
+ CodigaConfig = CodigaCodeAnalysisConfig.EMPTY;
}
public static void Initialize(bool startPolling = true)
{
+ TextWriterTraceListener tr1 = new TextWriterTraceListener(Console.Out);
+ Debug.Listeners.Add(tr1);
+
Instance = new RosieRulesCache();
if (startPolling)
Instance.StartPolling();
@@ -196,22 +199,23 @@ private async Task UpdateCacheFromModifiedCodigaConfigFileAsync(string codigaCon
{
ConfigFileLastWriteTime = File.GetLastWriteTime(codigaConfigFile);
var rawCodigaConfig = File.ReadAllText(codigaConfigFile);
- var rulesetNames = CodigaConfigFileUtil.DeserializeConfig(rawCodigaConfig)?.GetRulesets();
+ var codigaConfig = CodigaConfigFileUtil.DeserializeConfig(rawCodigaConfig);
//If the config file is not configured properly, we clear the cache
- if (rulesetNames == null)
+ if (codigaConfig.Rulesets.Count == 0)
{
ClearCache();
return;
}
- RulesetNames = rulesetNames;
+ CodigaConfig = codigaConfig;
//If there is at least on ruleset name, we can make a request with them
- if (RulesetNames.Count > 0)
+ if (CodigaConfig.Rulesets.Count > 0)
{
try
{
- var rulesetsForClient = await client.GetRulesetsForClientAsync(rulesetNames);
+ Debug.WriteLine($"Fetching rulesets last updated timestamp at {DateTime.Now}");
+ var rulesetsForClient = await client.GetRulesetsForClientAsync(codigaConfig.Rulesets);
IsInitializedWithRules = true;
if (rulesetsForClient == null)
return;
@@ -233,7 +237,8 @@ due to an issue in how the Codiga server collects the rules.
codiga.yml was updated locally with a non-existent ruleset, or a ruleset that has an earlier timestamp
than the latest updated one, so the rulesets configured don't result in an updated timestamp from the server.
*/
- long timestampFromServer = await client.GetRulesetsLastUpdatedTimestampAsync(rulesetNames);
+ Debug.WriteLine($"Fetching rulesets last updated timestamp at {DateTime.Now}");
+ long timestampFromServer = await client.GetRulesetsLastUpdatedTimestampAsync(codigaConfig.Rulesets);
if (timestampFromServer != RulesetslastUpdatedTimeStamp)
RulesetslastUpdatedTimeStamp = timestampFromServer;
@@ -257,18 +262,20 @@ due to an issue in how the Codiga server collects the rules.
///
private async Task UpdateCacheFromChangesOnServerAsync(ICodigaClient client)
{
- if (RulesetNames.Count == 0)
+ if (CodigaConfig.Rulesets.Count == 0)
return;
try
{
//Retrieve the last updated timestamp for the rulesets
- var timestampFromServer = await client.GetRulesetsLastUpdatedTimestampAsync(RulesetNames.ToImmutableList());
+ Debug.WriteLine($"Fetching rulesets last updated timestamp at {DateTime.Now}");
+ var timestampFromServer = await client.GetRulesetsLastUpdatedTimestampAsync(CodigaConfig.Rulesets.ToImmutableList());
IsInitializedWithRules = true;
//If there was a change on the server, we can get and cache the rulesets
if (RulesetslastUpdatedTimeStamp != timestampFromServer)
{
- var rulesetsForClient = await client.GetRulesetsForClientAsync(RulesetNames.ToImmutableList());
+ Debug.WriteLine($"Fetching rulesets at {DateTime.Now}");
+ var rulesetsForClient = await client.GetRulesetsForClientAsync(CodigaConfig.Rulesets.ToImmutableList());
if (rulesetsForClient == null)
return;
@@ -338,21 +345,70 @@ private async Task NotifyActiveDocumentForTagUpdateAsync()
#region Get rules
///
- /// Returns the s for the provided language.
+ /// Returns the list of s for the argument language and file path,
+ /// that will be sent to the Rosie service for analysis.
///
- /// The language to get the rules for.
+ /// The language to get the rules for
+ /// the absolute path of the file being analyzed.
+ /// Required to pass in for the ignore configuration.
+ /// The solution root directory.
+ /// Null only in case of production code, so we can retrieve the proper root directory.
/// The rules for the given language.
- public IReadOnlyList GetRosieRulesForLanguage(LanguageEnumeration language)
+ public async Task> GetRosieRules(LanguageEnumeration language, string pathOfAnalyzedFile, string? solutionDirectory = null)
{
+ var solutionDir = solutionDirectory ?? await SolutionHelper.GetSolutionDir();
+ if (solutionDir == null)
+ return NoRule;
+
var cachedLanguageType = GetCachedLanguageTypeOf(language);
if (_cachedRules.ContainsKey(cachedLanguageType))
{
var cachedRules = _cachedRules[cachedLanguageType];
- return cachedRules != null ? cachedRules.RosieRules : NoRule;
+ var rosieRulesForLanguage = cachedRules != null ? cachedRules.RosieRules : NoRule;
+
+ if (rosieRulesForLanguage.Count > 0)
+ {
+ //Replaces backslash '\' symbols with forward slashes '/', so that in case of Windows specific paths,
+ // we still can compare the relative paths properly.
+ string relativePathOfAnalyzedFile = pathOfAnalyzedFile.Replace(solutionDir, "").Replace("\\", "/");
+
+ //Returns the RosieRules that either don't have an ignore rule, or their prefixes don't match the currently analyzed file's path
+ return rosieRulesForLanguage
+ .Where(rosieRule =>
+ {
+ //If there is no ruleset ignore or rule ignore for the current RosieRule, then we keep it/don't ignore it.
+ if (!CodigaConfig.Ignore.ContainsKey(rosieRule.RulesetName)
+ || !CodigaConfig.Ignore[rosieRule.RulesetName].RuleIgnores
+ .ContainsKey(rosieRule.RuleName))
+ return true;
+
+ var ruleIgnore = CodigaConfig.Ignore[rosieRule.RulesetName].RuleIgnores[rosieRule.RuleName];
+
+ //If there is no prefix specified for the current rule ignore config,
+ // we don't keep the rule/ignore it.
+ if (ruleIgnore.Prefixes.Count == 0)
+ return false;
+
+ return ruleIgnore.Prefixes
+ //Since the leading / is optional, we remove it
+ .Select(RemoveLeadingSlash)
+ //./, /. and .. sequences are not allowed in prefixes, therefore we consider them not matching the file path.
+ //. symbols in general are allowed to be able to target exact file paths with their file extensions.
+ .All(prefix =>
+ prefix.Contains("..")
+ || prefix.Contains("./")
+ || prefix.Contains("/.")
+ || !RemoveLeadingSlash(relativePathOfAnalyzedFile).StartsWith(prefix));
+ }).ToList();
+ }
}
return NoRule;
}
+ private static string RemoveLeadingSlash(string path) {
+ return path.StartsWith("/") ? path.Substring(1) : path;
+ }
+
///
/// Since, besides JavaScript files, rules for TypeScript files are also handled under the same JavaScript Rosie language
/// type, we have to return JavaScript rules for TypeScript files as well.
@@ -365,7 +421,7 @@ private static LanguageEnumeration GetCachedLanguageTypeOf(LanguageEnumeration f
///
/// Returns the cached rules for the provided language and rule id.
///
- /// Null value for non-existent mapping for a language is already handled in .
+ /// Null value for non-existent mapping for a language is already handled in .
///
/// It should not return null when retrieving the rule for the rule id, since in RosieApiImpl#GetAnnotations()
/// the s and their ids are based on the values cached here.
@@ -386,8 +442,7 @@ private void ClearCache()
{
if (_cachedRules.Count > 0)
_cachedRules.Clear();
- if (RulesetNames.Count > 0)
- RulesetNames.Clear();
+ CodigaConfig = CodigaCodeAnalysisConfig.EMPTY;
RulesetslastUpdatedTimeStamp = -1L;
}
diff --git a/src/Extension/source.extension.cs b/src/Extension/source.extension.cs
index f6c83ab..769f634 100644
--- a/src/Extension/source.extension.cs
+++ b/src/Extension/source.extension.cs
@@ -11,7 +11,7 @@ internal sealed partial class Vsix
public const string Name = "Codiga";
public const string Description = @"Code Snippets for 15+ languages and Code Analysis with Custom Rules.";
public const string Language = "en-US";
- public const string Version = "0.0.14";
+ public const string Version = "0.0.15";
public const string Author = "Codiga";
public const string Tags = "";
}
diff --git a/src/Extension/source.extension.vsixmanifest b/src/Extension/source.extension.vsixmanifest
index 90b67b1..e2e6802 100644
--- a/src/Extension/source.extension.vsixmanifest
+++ b/src/Extension/source.extension.vsixmanifest
@@ -1,7 +1,7 @@
-
+
Codiga
Code Snippets for 15+ languages and Code Analysis with Custom Rules.
https://www.codiga.io/
diff --git a/src/Tests/Rosie/CodigaConfigFileUtilTest.cs b/src/Tests/Rosie/CodigaConfigFileUtilTest.cs
index 735350d..71b5256 100644
--- a/src/Tests/Rosie/CodigaConfigFileUtilTest.cs
+++ b/src/Tests/Rosie/CodigaConfigFileUtilTest.cs
@@ -1,5 +1,6 @@
using System.IO;
using Extension.Rosie;
+using Extension.Rosie.Model.Codiga;
using Extension.SnippetFormats;
using NUnit.Framework;
using static Tests.ServiceProviderMockSupport;
@@ -14,38 +15,52 @@ internal class CodigaConfigFileUtilTest
{
private string _codigaConfigFile;
- #region DeserializeConfig negative cases
+ #region DeserializeConfig
[Test]
- public void DeserializeConfig_should_return_null_for_null_raw_config()
+ public void DeserializeConfig_should_return_empty_config_for_null_raw_config()
{
var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(null);
- Assert.That(codigaConfigFile, Is.Null);
+ Assert.That(codigaConfigFile, Is.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
}
[Test]
- public void DeserializeConfig_should_return_null_for_empty_raw_config()
+ public void DeserializeConfig_should_return_empty_config_for_empty_raw_config()
{
var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig("");
- Assert.That(codigaConfigFile, Is.Null);
+ Assert.That(codigaConfigFile, Is.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
}
[Test]
- public void DeserializeConfig_should_return_null_for_whitespace_only_raw_config()
+ public void DeserializeConfig_should_return_empty_config_for_whitespace_only_raw_config()
{
var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(" ");
- Assert.That(codigaConfigFile, Is.Null);
+ Assert.That(codigaConfigFile, Is.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
}
+
+ [Test]
+ public void DeserializeConfig_should_return_empty_config_for_malformed_rulesets_list()
+ {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+- my-csharp-ruleset
+- rules:
+ - some-rule
+- my-other-ruleset");
- #endregion
-
- #region CollectRulesetNames positive cases
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ var rulesetNames = codigaConfigFile.Rulesets;
+ Assert.That(rulesetNames, Has.Count.EqualTo(2));
+ Assert.That(rulesetNames, Contains.Item("my-csharp-ruleset"));
+ Assert.That(rulesetNames, Contains.Item("my-other-ruleset"));
+ }
+
[Test]
- public void CollectRulesetNames_should_return_non_empty_ruleset_names()
+ public void DeserializeConfig_should_return_non_empty_ruleset_names()
{
var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
rulesets:
@@ -54,7 +69,7 @@ public void CollectRulesetNames_should_return_non_empty_ruleset_names()
- an_Inv@lid-name
");
- var rulesetNames = CodigaConfigFileUtil.CollectRulesetNames(codigaConfigFile);
+ var rulesetNames = codigaConfigFile.Rulesets;
Assert.That(rulesetNames, Has.Count.EqualTo(2));
Assert.That(rulesetNames, Contains.Item("my-csharp-ruleset"));
@@ -62,20 +77,20 @@ public void CollectRulesetNames_should_return_non_empty_ruleset_names()
}
[Test]
- public void CollectRulesetNames_should_return_no_ruleset_name_for_empty_rulesets_list()
+ public void DeserializeConfig_should_return_no_ruleset_name_for_empty_rulesets_list()
{
var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
rulesets:
-
");
- var rulesetNames = CodigaConfigFileUtil.CollectRulesetNames(codigaConfigFile);
+ var rulesetNames = codigaConfigFile.Rulesets;
Assert.That(rulesetNames, Is.Empty);
}
[Test]
- public void CollectRulesetNames_should_return_filtered_ruleset_names_when_there_is_empty_list_item()
+ public void DeserializeConfig_should_return_filtered_ruleset_names_when_there_is_empty_list_item()
{
var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
rulesets:
@@ -85,7 +100,7 @@ public void CollectRulesetNames_should_return_filtered_ruleset_names_when_there_
- some-ruleset
");
- var rulesetNames = CodigaConfigFileUtil.CollectRulesetNames(codigaConfigFile);
+ var rulesetNames = codigaConfigFile.Rulesets;
Assert.That(rulesetNames, Has.Count.EqualTo(3));
Assert.That(rulesetNames, Contains.Item("my-csharp-ruleset"));
@@ -94,7 +109,7 @@ public void CollectRulesetNames_should_return_filtered_ruleset_names_when_there_
}
[Test]
- public void CollectRulesetNames_should_return_filtered_ruleset_names_when_there_is_non_plain_text_list_item()
+ public void DeserializeConfig_should_return_filtered_ruleset_names_when_there_is_non_plain_text_list_item()
{
var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
rulesets:
@@ -104,57 +119,370 @@ public void CollectRulesetNames_should_return_filtered_ruleset_names_when_there_
- my-other-ruleset
");
- var rulesetNames = CodigaConfigFileUtil.CollectRulesetNames(codigaConfigFile);
+ var rulesetNames = codigaConfigFile.Rulesets;
Assert.That(rulesetNames, Has.Count.EqualTo(2));
Assert.That(rulesetNames, Contains.Item("my-csharp-ruleset"));
Assert.That(rulesetNames, Contains.Item("my-other-ruleset"));
}
- #endregion
-
- #region CollectRulesetNames negative cases
-
[Test]
- public void CollectRulesetNames_should_return_no_ruleset_name_for_missing_ruleset_property()
+ public void DeserializeConfig_should_return_no_ruleset_name_for_missing_ruleset_property()
{
var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
not-rulesets:
- my-csharp-ruleset
- my-other-ruleset");
- var rulesetNames = CodigaConfigFileUtil.CollectRulesetNames(codigaConfigFile);
+ var rulesetNames = codigaConfigFile.Rulesets;
Assert.That(rulesetNames, Is.Empty);
}
[Test]
- public void CollectRulesetNames_should_return_no_ruleset_name_for_non_sequence_empty_rulesets_list()
+ public void DeserializeConfig_should_return_no_ruleset_name_for_non_sequence_empty_rulesets_list()
{
var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
rulesets:
");
- var rulesetNames = CodigaConfigFileUtil.CollectRulesetNames(codigaConfigFile);
+ var rulesetNames = codigaConfigFile.Rulesets;
Assert.That(rulesetNames, Is.Empty);
}
[Test]
- public void CollectRulesetNames_should_return_no_ruleset_name_for_non_sequence_rulesets_property()
+ public void DeserializeConfig_should_return_no_ruleset_name_for_non_sequence_rulesets_property()
{
var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
rulesets:
rules:");
- var rulesetNames = CodigaConfigFileUtil.CollectRulesetNames(codigaConfigFile);
+ var rulesetNames = codigaConfigFile.Rulesets;
Assert.That(rulesetNames, Is.Empty);
}
- #endregion
+ [Test]
+ public void DeserializeConfig_should_return_empty_ignore_config_for_non_property_ignore() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore");
+
+ Assert.That(codigaConfigFile, Is.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_no_ignore_item() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Is.Empty);
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_blank_ignore_item() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - ");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Is.Empty);
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_empty_ignore_config_for_string_ignore_item() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Is.Empty);
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_empty_ruleset_name_ignore_property() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Is.Empty);
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_string_rule_name_ignore_property() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Is.Empty);
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_empty_rule_name_ignore_property() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Is.Empty);
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_string_prefix_ignore_property() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Is.Empty);
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_empty_prefix_ignore_property() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix:");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Is.Empty);
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_blank_prefix() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix: ");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Is.Empty);
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_single_prefix() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix: /path/to/file/to/ignore");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[0], Is.EqualTo("/path/to/file/to/ignore"));
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_single_prefix_as_list() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix:
+ - /path/to/file/to/ignore");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[0], Is.EqualTo("/path/to/file/to/ignore"));
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_multiple_prefixes_as_list() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix:
+ - /path1
+ - /path2");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Has.Count.EqualTo(2));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[0], Is.EqualTo("/path1"));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[1], Is.EqualTo("/path2"));
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_multiple_rule_ignores() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix:
+ - /path1
+ - /path2
+ - rule2");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(2));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Has.Count.EqualTo(2));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[0], Is.EqualTo("/path1"));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[1], Is.EqualTo("/path2"));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule2"].Prefixes, Is.Empty);
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_without_rulesets() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix:
+ - /path1
+ - /path2");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Has.Count.EqualTo(2));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[0], Is.EqualTo("/path1"));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[1], Is.EqualTo("/path2"));
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_duplicate_prefix_properties() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix:
+ - /path1
+ - /path2
+ - prefix: /path3");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[0], Is.EqualTo("/path3"));
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_duplicate_prefix_values() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix:
+ - /path1
+ - /path1");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes, Has.Count.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[0], Is.EqualTo("/path1"));
+ }
+
+ [Test]
+ public void DeserializeConfig_should_return_ignore_config_for_multiple_ruleset_ignores() {
+ var codigaConfigFile = CodigaConfigFileUtil.DeserializeConfig(@"
+rulesets:
+ - my-python-ruleset
+ - my-other-ruleset
+ignore:
+ - my-python-ruleset:
+ - rule1:
+ - prefix:
+ - /path1
+ - /path2
+ - rule2
+ - my-other-ruleset:
+ - rule3:
+ - prefix: /another/path");
+
+ Assert.That(codigaConfigFile, Is.Not.EqualTo(CodigaCodeAnalysisConfig.EMPTY));
+ Assert.That(codigaConfigFile.Ignore.Count, Is.EqualTo(2));
+
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores.Count, Is.EqualTo(2));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes.Count, Is.EqualTo(2));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[0], Is.EqualTo("/path1"));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule1"].Prefixes[1], Is.EqualTo("/path2"));
+ Assert.That(codigaConfigFile.Ignore["my-python-ruleset"].RuleIgnores["rule2"].Prefixes, Is.Empty);
+
+ Assert.That(codigaConfigFile.Ignore["my-other-ruleset"].RuleIgnores.Count, Is.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-other-ruleset"].RuleIgnores["rule3"].Prefixes.Count, Is.EqualTo(1));
+ Assert.That(codigaConfigFile.Ignore["my-other-ruleset"].RuleIgnores["rule3"].Prefixes[0], Is.EqualTo("/another/path"));
+ }
+
+ #endregion
- #region FindCodigaConfigFile
+ #region FindCodigaConfigFile
[Test]
public void FindCodigaConfigFile_should_return_null_for_missing_solution_root()
diff --git a/src/Tests/Rosie/RosieRulesCacheTest.cs b/src/Tests/Rosie/RosieRulesCacheTest.cs
index 6f1c1db..172233c 100644
--- a/src/Tests/Rosie/RosieRulesCacheTest.cs
+++ b/src/Tests/Rosie/RosieRulesCacheTest.cs
@@ -1,15 +1,18 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EnvDTE;
using Extension.Caching;
using Extension.Rosie;
-using Extension.SnippetFormats;
+using Extension.Rosie.Model;
+using Extension.Rosie.Model.Codiga;
using GraphQLClient;
using Moq;
using NUnit.Framework;
+using LanguageEnumeration = Extension.SnippetFormats.LanguageUtils.LanguageEnumeration;
namespace Tests.Rosie
{
@@ -26,6 +29,8 @@ internal class RosieRulesCacheTest
private string? _codigaConfigFile;
private ICodigaClientProvider _clientProvider;
private RosieRulesCache? _cache;
+ private string? _pythonFile;
+ private string? _javaScriptFile;
///
/// Initializes the test with a Solution directory with a mock Solution,
@@ -41,6 +46,8 @@ public void Setup()
_solutionDirPath = Path.GetTempPath();
_codigaConfigFile = $"{_solutionDirPath}codiga.yml";
+ _pythonFile = $"{_solutionDirPath}python_file.py";
+ _javaScriptFile = $"{_solutionDirPath}javascript_file.js";
_solution = new Mock();
//Necessary to mock for CodigaConfigFileUtil.FindCodigaConfigFile()
@@ -65,7 +72,7 @@ public async Task HandleCacheUpdateAsync_should_clear_cache_and_return_no_config
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
+ - single-ruleset-single-language");
Assert.That(RosieRulesCache.IsInitializedWithRules, Is.False);
@@ -78,11 +85,13 @@ public async Task HandleCacheUpdateAsync_should_clear_cache_and_return_no_config
var updateResult = await _cache.HandleCacheUpdateAsync();
Assert.AreEqual(updateResult, RosieRulesCache.UpdateResult.NoConfigFile);
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
+
Assert.Multiple(() =>
{
- Assert.That(_cache.RulesetNames, Is.Empty);
- Assert.That(_cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python),
- Is.Empty);
+ Assert.That(_cache.CodigaConfig.Rulesets, Is.Empty);
+ Assert.That(rules, Is.Empty);
Assert.That(RosieRulesCache.IsInitializedWithRules, Is.True);
});
}
@@ -93,14 +102,16 @@ public async Task HandleCacheUpdateAsync_should_populate_empty_cache_from_codiga
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
+ - single-ruleset-single-language");
var updateResult = await _cache.HandleCacheUpdateAsync();
Assert.AreEqual(updateResult, RosieRulesCache.UpdateResult.Success);
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
+
Assert.Multiple(() =>
{
- var rules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
Assert.That(rules[0].Id, Is.EqualTo($"python-ruleset/{RulesetsForClientTestSupport.PythonRule1.Name}"));
Assert.That(rules[1].Id, Is.EqualTo($"python-ruleset/{RulesetsForClientTestSupport.PythonRule2.Name}"));
Assert.That(rules[2].Id, Is.EqualTo($"python-ruleset/{RulesetsForClientTestSupport.PythonRule3.Name}"));
@@ -113,11 +124,13 @@ public async Task HandleCacheUpdateAsync_should_update_non_empty_cache_from_codi
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
+ - single-ruleset-single-language");
await _cache.HandleCacheUpdateAsync();
- var rules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
+
+ Assert.That(rules, Has.Count.EqualTo(3));
Assert.Multiple(() =>
{
Assert.That(rules[0].Id, Is.EqualTo($"python-ruleset/{RulesetsForClientTestSupport.PythonRule1.Name}"));
@@ -127,15 +140,17 @@ public async Task HandleCacheUpdateAsync_should_update_non_empty_cache_from_codi
await UpdateCodigaConfig(@"
rulesets:
- - multipleRulesetsSingleLanguage");
+ - multi-rulesets-single-language");
var updateResult = await _cache.HandleCacheUpdateAsync();
Assert.AreEqual(updateResult, RosieRulesCache.UpdateResult.Success);
+ Assert.That(rules, Has.Count.EqualTo(3));
+
+ var rulesMulti = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.Multiple(() =>
{
- var rulesMulti = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
Assert.That(rulesMulti[0].Id,
Is.EqualTo($"python-ruleset/{RulesetsForClientTestSupport.PythonRule1.Name}"));
Assert.That(rulesMulti[1].Id,
@@ -151,20 +166,23 @@ public async Task HandleCacheUpdateAsync_should_update_non_empty_cache_from_serv
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
+ - single-ruleset-single-language");
_cache.UpdateCacheFrom(RulesetsForClientTestSupport.SingleRulesetMultipleLanguages());
_cache.RulesetslastUpdatedTimeStamp = 102L;
_cache.ConfigFileLastWriteTime = File.GetLastWriteTime(_codigaConfigFile);
- _cache.RulesetNames = new List { "singleRulesetSingleLanguage" };
+ _cache.CodigaConfig = new CodigaCodeAnalysisConfig
+ {
+ Rulesets = new List { "single-ruleset-single-language" }
+ };
- var rules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.That(rules.Count, Is.EqualTo(2));
Assert.That(_cache.RulesetslastUpdatedTimeStamp, Is.EqualTo(102L));
await _cache.HandleCacheUpdateAsync();
- var updatedRules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var updatedRules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.That(updatedRules.Count, Is.EqualTo(3));
Assert.That(_cache.RulesetslastUpdatedTimeStamp, Is.EqualTo(101L));
}
@@ -179,7 +197,7 @@ public async Task
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
+ - single-ruleset-single-language");
await _cache.HandleCacheUpdateAsync();
@@ -198,8 +216,8 @@ public async Task
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
-
+ - single-ruleset-single-language");
+
await _cache.HandleCacheUpdateAsync();
Assert.IsFalse(_cache.IsEmpty());
@@ -219,11 +237,11 @@ public async Task
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
-
+ - single-ruleset-single-language");
+
await _cache.HandleCacheUpdateAsync();
- var rules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.Multiple(() =>
{
Assert.That(rules[0].Id, Is.EqualTo($"python-ruleset/{RulesetsForClientTestSupport.PythonRule1.Name}"));
@@ -233,11 +251,11 @@ public async Task
await UpdateCodigaConfig(@"
rulesets:
- - erroredRuleset");
-
+ - errored-ruleset");
+
await _cache.HandleCacheUpdateAsync();
- var updatedRules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var updatedRules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.Multiple(() =>
{
Assert.That(updatedRules[0].Id,
@@ -255,15 +273,15 @@ public async Task
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
-
+ - single-ruleset-single-language");
+
await _cache.HandleCacheUpdateAsync();
Assert.IsFalse(_cache.IsEmpty());
await UpdateCodigaConfig(@"
rulesets:
- - nonExistentRuleset");
+ - non-existent-ruleset");
await _cache.HandleCacheUpdateAsync();
@@ -276,18 +294,18 @@ public async Task
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
-
+ - single-ruleset-single-language");
+
await _cache.HandleCacheUpdateAsync();
_cache.RulesetslastUpdatedTimeStamp = 100L;
await UpdateCodigaConfig(@"
rulesets:
- - singleRulesetMultipleLanguagesDefaultTimestamp");
+ - single-set-multi-lang-def-ts");
await _cache.HandleCacheUpdateAsync();
- var updatedRules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var updatedRules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.That(updatedRules, Has.Count.EqualTo(2));
Assert.That(_cache.RulesetslastUpdatedTimeStamp, Is.EqualTo(100L));
}
@@ -298,18 +316,18 @@ public async Task
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
-
+ - single-ruleset-single-language");
+
await _cache.HandleCacheUpdateAsync();
_cache.RulesetslastUpdatedTimeStamp = 100L;
await UpdateCodigaConfig(@"
rulesets:
- - singleRulesetMultipleLanguages");
+ - single-ruleset-multi-languages");
await _cache.HandleCacheUpdateAsync();
- var updatedRules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var updatedRules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.That(updatedRules, Has.Count.EqualTo(2));
Assert.That(_cache.RulesetslastUpdatedTimeStamp, Is.EqualTo(102L));
}
@@ -342,19 +360,22 @@ public async Task
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
+ - single-ruleset-single-language");
_cache.UpdateCacheFrom(RulesetsForClientTestSupport.SingleRulesetMultipleLanguages());
- _cache.RulesetNames = new List { "singleRulesetSingleLanguage" };
+ _cache.CodigaConfig = new CodigaCodeAnalysisConfig
+ {
+ Rulesets = new List { "single-ruleset-single-language" }
+ };
_cache.RulesetslastUpdatedTimeStamp = 101L;
_cache.ConfigFileLastWriteTime = File.GetLastWriteTime(_codigaConfigFile);
- var rules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.That(rules, Has.Count.EqualTo(2));
Assert.That(_cache.RulesetslastUpdatedTimeStamp, Is.EqualTo(101L));
await _cache.HandleCacheUpdateAsync();
- var updatedRules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var updatedRules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.That(updatedRules, Has.Count.EqualTo(2));
Assert.That(_cache.RulesetslastUpdatedTimeStamp, Is.EqualTo(101L));
}
@@ -364,19 +385,22 @@ public async Task UpdateCacheFromChangesOnServerAsync_should_update_cache()
{
InitConfigAndCache(@"
rulesets:
- - singleRulesetSingleLanguage");
+ - single-ruleset-single-language");
_cache.UpdateCacheFrom(RulesetsForClientTestSupport.SingleRulesetMultipleLanguages());
- _cache.RulesetNames = new List { "singleRulesetSingleLanguage" };
+ _cache.CodigaConfig = new CodigaCodeAnalysisConfig
+ {
+ Rulesets = new List { "single-ruleset-single-language" }
+ };
_cache.RulesetslastUpdatedTimeStamp = 102L;
_cache.ConfigFileLastWriteTime = File.GetLastWriteTime(_codigaConfigFile);
- var rules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.That(rules, Has.Count.EqualTo(2));
Assert.That(_cache.RulesetslastUpdatedTimeStamp, Is.EqualTo(102L));
await _cache.HandleCacheUpdateAsync();
- var updatedRules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var updatedRules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.That(updatedRules, Has.Count.EqualTo(3));
Assert.That(_cache.RulesetslastUpdatedTimeStamp, Is.EqualTo(101L));
}
@@ -390,11 +414,11 @@ public async Task should_store_rules_from_multiple_rulesets_for_multiple_languag
{
InitConfigAndCache(@"
rulesets:
- - multipleRulesetsMultipleLanguages");
+ - multi-rulesets-multi-languages");
await _cache.HandleCacheUpdateAsync();
- var rules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Python);
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Python, _pythonFile, _solutionDirPath);
Assert.That(rules, Has.Count.EqualTo(2));
Assert.Multiple(() =>
{
@@ -402,23 +426,397 @@ public async Task should_store_rules_from_multiple_rulesets_for_multiple_languag
Assert.That(rules[1].Id, Is.EqualTo($"python-ruleset/{RulesetsForClientTestSupport.PythonRule5.Name}"));
});
- var updatedRules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Java);
+ var updatedRules = await _cache.GetRosieRules(LanguageEnumeration.Java,
+ $"{_solutionDirPath}JavaFile.java", _solutionDirPath);
Assert.That(updatedRules, Has.Count.EqualTo(1));
Assert.That(updatedRules[0].Id,
Is.EqualTo($"mixed-ruleset/{RulesetsForClientTestSupport.JavaRule1.Name}"));
}
-
+
+ #endregion
+
+ #region GetRosieRules
+
[Test]
- public async Task GetRosieRulesForLanguage_should_return_javascript_rules_for_typescript() {
+ public async Task GetRosieRules_should_return_rules_for_empty_ignore_config()
+ {
InitConfigAndCache(@"
rulesets:
- - javascriptRuleset");
-
+ - javascript-ruleset");
+
await _cache.HandleCacheUpdateAsync();
-
- var rules = _cache.GetRosieRulesForLanguage(LanguageUtils.LanguageEnumeration.Typescript);
- Assert.That(rules, Has.Count.EqualTo(3));
- Assert.That(rules, Has.All.Property("Language").EqualTo("Javascript"));
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 3,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2",
+ "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task GetRosieRules_should_not_filter_rules_for_ignore_config_with_no_ruleset()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ ");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 3,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2",
+ "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task GetRosieRules_should_not_filter_rules_for_ignore_config_with_no_rule()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 3,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2",
+ "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task GetRosieRules_should_filter_rules_for_ignore_config_with_no_prefix()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 2,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task
+ GetRosieRules_should_filter_rule_for_ignore_config_with_one_matching_prefix_with_leading_slash()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix: /javascript");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 2,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task
+ GetRosieRules_should_filter_rules_with_ignore_config_with_one_matching_prefix_without_leading_slash()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix: javascript");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 2,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task GetRosieRules_should_filter_rules_with_ignore_config_with_one_matching_file_path_prefix()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix: /javascript_file.js");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 2,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task GetRosieRules_should_filter_rules_with_ignore_config_with_one_matching_directory_path_prefix()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix: /directory");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript,
+ $"{_solutionDirPath}directory/javascript_file.js", _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 2,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task GetRosieRules_should_not_filter_rules_with_ignore_config_with_one_prefix_not_matching()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix: not-matching");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 3,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task
+ GetRosieRules_should_not_filter_rules_with_ignore_config_with_one_prefix_containing_double_dots()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix: javascript_file..js");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 3,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task
+ GetRosieRules_should_not_filter_rules_with_ignore_config_with_one_prefix_containing_single_dot_as_folder()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix: directory/./javascript_file.js");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript,
+ $"{_solutionDirPath}directory/sub/javascript_file.js", _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 3,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task
+ GetRosieRules_should_not_filter_rules_with_ignore_config_with_one_prefix_containing_double_dots_as_folder()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix: directory/../javascript_file.js");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript,
+ $"{_solutionDirPath}directory/sub/javascript_file.js", _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 3,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task GetRosieRules_should_filter_rules_with_ignore_config_with_one_matching_prefix_of_multiple()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix:
+ - not/matching
+ - javascript_file.js");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 2,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task GetRosieRules_should_filter_rules_with_ignore_config_with_multiple_matching_prefixes()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix:
+ - /javascript
+ - javascript_file.js");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 2,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task GetRosieRules_should_not_filter_rules_with_ignore_config_with_multiple_prefixes_not_matching()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix:
+ - not-matching
+ - also/not/matching");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 3,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task
+ GetRosieRules_should_filter_rules_with_ignore_config_with_multiple_rule_ignore_configurations()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - javascript_rule_2:
+ - prefix: javascript_file..js
+ - javascript_rule_3:
+ - prefix:
+ - /javascript_fi");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 2,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2");
+ }
+
+ [Test]
+ public async Task GetRosieRules_should_not_filter_rules_when_rule_doesnt_belong_to_ruleset()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - javascript-ruleset:
+ - non_javascript_rule:
+ - prefix: javascript_file..js");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 3,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2", "javascript-ruleset/javascript_rule_3");
+ }
+
+ [Test]
+ public async Task
+ GetRosieRules_should_not_filter_rules_when_ruleset_ignore_is_not_present_in_rulesets_property()
+ {
+ InitConfigAndCache(@"
+rulesets:
+ - javascript-ruleset
+ignore:
+ - not-configured-ruleset:
+ - javascript_rule_2:
+ - prefix: javascript_file.js");
+
+ await _cache.HandleCacheUpdateAsync();
+
+ var rules = await _cache.GetRosieRules(LanguageEnumeration.Javascript, _javaScriptFile, _solutionDirPath);
+
+ ValidateRuleCountAndRuleIds(rules,
+ 3,
+ "javascript-ruleset/javascript_rule_1", "javascript-ruleset/javascript_rule_2", "javascript-ruleset/javascript_rule_3");
+ }
+
+ private void ValidateRuleCountAndRuleIds(IReadOnlyList rules, int count,
+ params string[] expectedRuleIds)
+ {
+ Assert.That(rules, Has.Count.EqualTo(count));
+
+ var actualRuleIds = rules.Select(rule => rule.Id).ToList();
+ CollectionAssert.AreEqual(actualRuleIds, expectedRuleIds);
}
#endregion
@@ -450,7 +848,7 @@ private void InitCodigaConfig(string rawConfig)
private async Task UpdateCodigaConfig(string rawConfig)
{
File.Delete(_codigaConfigFile);
-
+
//This delay ensures that the last write time of the new config file is different than the
// one in the rules cache. In the CI pipeline the test execution tends to be so fast
// that it is executed in the same millisecond, resulting in the exact same last write time.
@@ -463,7 +861,7 @@ private async Task UpdateCodigaConfig(string rawConfig)
{
return;
}
-
+
InitCodigaConfig(rawConfig);
}
diff --git a/src/Tests/Rosie/RulesetsForClientTestSupport.cs b/src/Tests/Rosie/RulesetsForClientTestSupport.cs
index c9b965b..dab4b9e 100644
--- a/src/Tests/Rosie/RulesetsForClientTestSupport.cs
+++ b/src/Tests/Rosie/RulesetsForClientTestSupport.cs
@@ -82,18 +82,18 @@ public static class RulesetsForClientTestSupport
switch (rulesetNames.ToList()[0])
{
- case "singleRulesetSingleLanguage":
+ case "single-ruleset-single-language":
return SingleRulesetSingleLanguage(); //Python
- case "singleRulesetMultipleLanguagesDefaultTimestamp":
- case "singleRulesetMultipleLanguages":
+ case "single-set-multi-lang-def-ts":
+ case "single-ruleset-multi-languages":
return SingleRulesetMultipleLanguages(); //Python, Java
- case "multipleRulesetsSingleLanguage":
+ case "multi-rulesets-single-language":
return MultipleRulesetsSingleLanguage(); //Python
- case "multipleRulesetsMultipleLanguages":
+ case "multi-rulesets-multi-languages":
return MultipleRulesetsMultipleLanguages(); //Python, Java
- case "erroredRuleset":
+ case "errored-ruleset":
return null;
- case "javascriptRuleset":
+ case "javascript-ruleset":
return JavascriptRulesets();
default:
return ImmutableList.Create();
@@ -104,12 +104,12 @@ public static long GetRulesetsLastTimestamp(IReadOnlyCollection rulesetN
{
return rulesetNames.ToList()[0] switch
{
- "singleRulesetSingleLanguage" => 101L,
- "singleRulesetMultipleLanguagesDefaultTimestamp" => 100L,
- "singleRulesetMultipleLanguages" => 102L,
- "multipleRulesetsSingleLanguage" => 103L,
- "multipleRulesetsMultipleLanguages" => 104L,
- "javascriptRuleset" => 105L,
+ "single-ruleset-single-language" => 101L,
+ "single-set-multi-lang-def-ts" => 100L,
+ "single-ruleset-multi-languages" => 102L,
+ "multi-rulesets-single-language" => 103L,
+ "multi-rulesets-multi-languages" => 104L,
+ "javascript-ruleset" => 105L,
_ => -1L
};
}
@@ -171,7 +171,7 @@ private static IReadOnlyCollection MultipleRulesetsMultipleLa
private static IReadOnlyCollection JavascriptRulesets() {
var rules = new List { JavaScriptRule1, JavaScriptRule2, JavaScriptRule3};
- var ruleset = new RuleSetsForClient { Id = 5678, Name = "javascriptRuleset", Rules = rules };
+ var ruleset = new RuleSetsForClient { Id = 5678, Name = "javascript-ruleset", Rules = rules };
return ImmutableList.Create(ruleset);
}