Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Analyze invalid option values #77

Merged
merged 3 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Kysect.CommonLib.BaseTypes.Extensions;
using Kysect.CommonLib.Logging;
using Kysect.Configuin.EditorConfig;
using Kysect.Configuin.MsLearn;
using Kysect.Configuin.MsLearn.Models;
Expand Down Expand Up @@ -45,33 +44,18 @@ public override int Execute([NotNull] CommandContext context, [NotNull] Settings
settings.MsLearnRepositoryPath.ThrowIfNull();

var editorConfigAnalyzer = new EditorConfigAnalyzer();
IEditorConfigAnalyzeReporter reporter = new EditorConfigAnalyzeLogReporter(_logger);

string editorConfigContent = _editorConfigContentProvider.Provide(settings.EditorConfigPath);
EditorConfigSettings editorConfigSettings = _editorConfigSettingsParser.Parse(editorConfigContent);
MsLearnDocumentationRawInfo msLearnDocumentationRawInfo = _msLearnDocumentationInfoReader.Provide(settings.MsLearnRepositoryPath);
RoslynRules roslynRules = _msLearnDocumentationParser.Parse(msLearnDocumentationRawInfo);
EditorConfigMissedConfiguration editorConfigMissedConfiguration = editorConfigAnalyzer.GetMissedConfigurations(editorConfigSettings, roslynRules);

if (editorConfigMissedConfiguration.StyleRuleSeverity.Any())
{
_logger.LogInformation("Missed style rules:");
foreach (RoslynRuleId roslynRuleId in editorConfigMissedConfiguration.StyleRuleSeverity)
_logger.LogTabInformation(1, roslynRuleId.ToString());
}

if (editorConfigMissedConfiguration.QualityRuleSeverity.Any())
{
_logger.LogInformation("Missed quality rules:");
foreach (RoslynRuleId roslynRuleId in editorConfigMissedConfiguration.QualityRuleSeverity)
_logger.LogTabInformation(1, roslynRuleId.ToString());
}
EditorConfigMissedConfiguration editorConfigMissedConfiguration = editorConfigAnalyzer.GetMissedConfigurations(editorConfigSettings, roslynRules);
IReadOnlyCollection<EditorConfigInvalidOptionValue> incorrectOptionValues = editorConfigAnalyzer.GetIncorrectOptionValues(editorConfigSettings, roslynRules);

if (editorConfigMissedConfiguration.StyleRuleOptions.Any())
{
_logger.LogInformation("Missed options:");
foreach (string styleRuleOption in editorConfigMissedConfiguration.StyleRuleOptions)
_logger.LogTabInformation(1, styleRuleOption);
}
reporter.ReportMissedConfigurations(editorConfigMissedConfiguration);
reporter.ReportIncorrectOptionValues(incorrectOptionValues);

return 0;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Kysect.CommonLib.Collections.Extensions;
using Kysect.CommonLib.Logging;
using Kysect.Configuin.RoslynModels;
using Microsoft.Extensions.Logging;

namespace Kysect.Configuin.EditorConfig;

public class EditorConfigAnalyzeLogReporter : IEditorConfigAnalyzeReporter
{
private readonly ILogger _logger;

public EditorConfigAnalyzeLogReporter(ILogger logger)
{
_logger = logger;
}

public void ReportMissedConfigurations(EditorConfigMissedConfiguration editorConfigMissedConfiguration)
{
if (editorConfigMissedConfiguration.StyleRuleSeverity.Any())
{
_logger.LogInformation("Missed style rules:");
foreach (RoslynRuleId roslynRuleId in editorConfigMissedConfiguration.StyleRuleSeverity)
_logger.LogTabInformation(1, roslynRuleId.ToString());
}

if (editorConfigMissedConfiguration.QualityRuleSeverity.Any())
{
_logger.LogInformation("Missed quality rules:");
foreach (RoslynRuleId roslynRuleId in editorConfigMissedConfiguration.QualityRuleSeverity)
_logger.LogTabInformation(1, roslynRuleId.ToString());
}

if (editorConfigMissedConfiguration.StyleRuleOptions.Any())
{
_logger.LogInformation("Missed options:");
foreach (string styleRuleOption in editorConfigMissedConfiguration.StyleRuleOptions)
_logger.LogTabInformation(1, styleRuleOption);
}
}

public void ReportIncorrectOptionValues(IReadOnlyCollection<EditorConfigInvalidOptionValue> incorrectOptionValues)
{
if (incorrectOptionValues.Any())
_logger.LogInformation("Incorrect option value:");

foreach (EditorConfigInvalidOptionValue editorConfigInvalidOptionValue in incorrectOptionValues)
{
string availableOptions = editorConfigInvalidOptionValue.AvailableOptions.ToSingleString(o => o.Value);
_logger.LogTabInformation(1, $"Option {editorConfigInvalidOptionValue.Key} has value {editorConfigInvalidOptionValue.Value} but available values: [{availableOptions}]");
}
}
}
18 changes: 18 additions & 0 deletions Sources/Kysect.Configuin.EditorConfig/EditorConfigAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,22 @@ public EditorConfigMissedConfiguration GetMissedConfigurations(EditorConfigSetti

return new EditorConfigMissedConfiguration(missedStyleRules, missedQualityRules, missedOptions);
}

public IReadOnlyCollection<EditorConfigInvalidOptionValue> GetIncorrectOptionValues(EditorConfigSettings editorConfigSettings, RoslynRules roslynRules)
{
var result = new List<EditorConfigInvalidOptionValue>();

var optionAvailableValues = roslynRules.GetOptions().ToDictionary(o => o.Name, o => o.Values);

foreach ((string key, string value) in editorConfigSettings.Settings.OfType<RoslynOptionEditorConfigSetting>())
{
if (!optionAvailableValues.TryGetValue(key, out IReadOnlyCollection<RoslynStyleRuleOptionValue>? values))
values = Array.Empty<RoslynStyleRuleOptionValue>();

if (!values.Any(v => v.Value.Equals(value, StringComparison.InvariantCultureIgnoreCase)))
result.Add(new EditorConfigInvalidOptionValue(key, value, values));
}

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@ namespace Kysect.Configuin.EditorConfig;
public record EditorConfigMissedConfiguration(
IReadOnlyCollection<RoslynRuleId> StyleRuleSeverity,
IReadOnlyCollection<RoslynRuleId> QualityRuleSeverity,
IReadOnlyCollection<string> StyleRuleOptions);
IReadOnlyCollection<string> StyleRuleOptions
);


public record EditorConfigInvalidOptionValue(
string Key,
string Value,
IReadOnlyCollection<RoslynStyleRuleOptionValue> AvailableOptions
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Kysect.Configuin.EditorConfig;

public interface IEditorConfigAnalyzeReporter
{
void ReportMissedConfigurations(EditorConfigMissedConfiguration editorConfigMissedConfiguration);
void ReportIncorrectOptionValues(IReadOnlyCollection<EditorConfigInvalidOptionValue> incorrectOptionValues);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

public record RoslynStyleRuleOption(
string Name,
IReadOnlyCollection<RoslynStyleRuleOptionValue> Options,
IReadOnlyCollection<RoslynStyleRuleOptionValue> Values,
string? DefaultValue,
string? CsharpCodeSample);
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@ namespace Kysect.Configuin.Tests.EditorConfig;

public class EditorConfigAnalyzerTests
{
private readonly EditorConfigAnalyzer _editorConfigAnalyzer;

public EditorConfigAnalyzerTests()
{
_editorConfigAnalyzer = new EditorConfigAnalyzer();
}

[Test]
public void GetMissedConfigurations_AllOptionAreMissed_ReturnAllOptions()
{
var editorConfigAnalyzer = new EditorConfigAnalyzer();

var editorConfigSettings = new EditorConfigSettings(Array.Empty<IEditorConfigSetting>());
var roslynRules = new RoslynRules(new[] { WellKnownRoslynRuleDefinitions.CA1064() }, new[] { WellKnownRoslynRuleDefinitions.IDE0040() });

EditorConfigMissedConfiguration editorConfigMissedConfiguration = editorConfigAnalyzer.GetMissedConfigurations(editorConfigSettings, roslynRules);
EditorConfigMissedConfiguration editorConfigMissedConfiguration = _editorConfigAnalyzer.GetMissedConfigurations(editorConfigSettings, roslynRules);

editorConfigMissedConfiguration.QualityRuleSeverity
.Should().HaveCount(1)
Expand All @@ -35,8 +40,6 @@ public void GetMissedConfigurations_AllOptionAreMissed_ReturnAllOptions()
[Test]
public void GetMissedConfigurations_AllOptionExists_ReturnAllOptions()
{
var editorConfigAnalyzer = new EditorConfigAnalyzer();

var editorConfigSettings = new EditorConfigSettings(new IEditorConfigSetting[]
{
new RoslynSeverityEditorConfigSetting(WellKnownRoslynRuleDefinitions.IDE0040().RuleId, RoslynRuleSeverity.Warning),
Expand All @@ -46,10 +49,71 @@ public void GetMissedConfigurations_AllOptionExists_ReturnAllOptions()

var roslynRules = new RoslynRules(new[] { WellKnownRoslynRuleDefinitions.CA1064() }, new[] { WellKnownRoslynRuleDefinitions.IDE0040() });

EditorConfigMissedConfiguration editorConfigMissedConfiguration = editorConfigAnalyzer.GetMissedConfigurations(editorConfigSettings, roslynRules);
EditorConfigMissedConfiguration editorConfigMissedConfiguration = _editorConfigAnalyzer.GetMissedConfigurations(editorConfigSettings, roslynRules);

editorConfigMissedConfiguration.QualityRuleSeverity.Should().BeEmpty();
editorConfigMissedConfiguration.StyleRuleSeverity.Should().BeEmpty();
editorConfigMissedConfiguration.StyleRuleOptions.Should().BeEmpty();
}

[Test]
public void GetIncorrectOptionValues_AllOptionsValid_NoElementReturn()
{
var editorConfigSettings = new EditorConfigSettings(new IEditorConfigSetting[]
{
new RoslynOptionEditorConfigSetting(WellKnownRoslynRuleDefinitions.IDE0040().Options.Single().Name, "always")
});

var roslynRules = new RoslynRules(Array.Empty<RoslynQualityRule>(), new[] { WellKnownRoslynRuleDefinitions.IDE0040() });

IReadOnlyCollection<EditorConfigInvalidOptionValue> invalidOptionValues = _editorConfigAnalyzer.GetIncorrectOptionValues(editorConfigSettings, roslynRules);

invalidOptionValues.Should().BeEmpty();
}

[Test]
public void GetIncorrectOptionValues_ForInvalidOptionValue_ReturnInvalidOption()
{
string incorrectOptionValue = "null";
RoslynStyleRuleOption selectedOptions = WellKnownRoslynRuleDefinitions.IDE0040().Options.Single();

var editorConfigSettings = new EditorConfigSettings(new IEditorConfigSetting[]
{
new RoslynOptionEditorConfigSetting(selectedOptions.Name, incorrectOptionValue)
});

var roslynRules = new RoslynRules(Array.Empty<RoslynQualityRule>(), new[] { WellKnownRoslynRuleDefinitions.IDE0040() });
var expected = new EditorConfigInvalidOptionValue(
selectedOptions.Name,
incorrectOptionValue,
selectedOptions.Values);

IReadOnlyCollection<EditorConfigInvalidOptionValue> invalidOptionValues = _editorConfigAnalyzer.GetIncorrectOptionValues(editorConfigSettings, roslynRules);

invalidOptionValues.Should().HaveCount(1)
.And.Subject.ElementAt(0).Should().BeEquivalentTo(expected);
}

[Test]
public void GetIncorrectOptionValues_ForInvalidOptionKey_ReturnInvalidOption()
{
string incorrectOptionKey = "null";
string incorrectOptionValue = "null";

var editorConfigSettings = new EditorConfigSettings(new IEditorConfigSetting[]
{
new RoslynOptionEditorConfigSetting(incorrectOptionKey, incorrectOptionValue)
});

var roslynRules = new RoslynRules(Array.Empty<RoslynQualityRule>(), new[] { WellKnownRoslynRuleDefinitions.IDE0040() });
var expected = new EditorConfigInvalidOptionValue(
incorrectOptionKey,
incorrectOptionValue,
Array.Empty<RoslynStyleRuleOptionValue>());

IReadOnlyCollection<EditorConfigInvalidOptionValue> invalidOptionValues = _editorConfigAnalyzer.GetIncorrectOptionValues(editorConfigSettings, roslynRules);

invalidOptionValues.Should().HaveCount(1)
.And.Subject.ElementAt(0).Should().BeEquivalentTo(expected);
}
}