From b80ef6582fbdd7bd6a3272d733ad74f45d4ca454 Mon Sep 17 00:00:00 2001 From: Fredi Kats Date: Fri, 8 Sep 2023 20:12:16 +0400 Subject: [PATCH] Implement rule description parsing for CA* --- .../Markdown/MarkdownCodeStyleFormatter.cs | 2 ++ .../MsLearnDocumentationParser.cs | 19 +++++++++++++++++-- .../MarkdownCodeStyleFormatterTests.cs | 3 +++ .../MsLearnDocumentationParserTests.cs | 7 ++----- .../WellKnownRoslynRuleDefinitions.cs | 12 +++++++----- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Sources/Kysect.Configuin.Core/CodeStyleGeneration/Markdown/MarkdownCodeStyleFormatter.cs b/Sources/Kysect.Configuin.Core/CodeStyleGeneration/Markdown/MarkdownCodeStyleFormatter.cs index dabe9a4..c779689 100644 --- a/Sources/Kysect.Configuin.Core/CodeStyleGeneration/Markdown/MarkdownCodeStyleFormatter.cs +++ b/Sources/Kysect.Configuin.Core/CodeStyleGeneration/Markdown/MarkdownCodeStyleFormatter.cs @@ -70,6 +70,8 @@ public string FormatQualityRule(CodeStyleRoslynQualityRuleConfiguration rule) builder.AddH2($"{rule.Rule.Title} ({rule.Rule.RuleId})"); builder.AddEmptyLine(); builder.AddText($"Severity: {rule.Severity}"); + builder.AddEmptyLine(); + builder.AddText(rule.Rule.Description); return builder.Build(); } diff --git a/Sources/Kysect.Configuin.Core/MsLearnDocumentation/MsLearnDocumentationParser.cs b/Sources/Kysect.Configuin.Core/MsLearnDocumentation/MsLearnDocumentationParser.cs index a57150e..ebb7648 100644 --- a/Sources/Kysect.Configuin.Core/MsLearnDocumentation/MsLearnDocumentationParser.cs +++ b/Sources/Kysect.Configuin.Core/MsLearnDocumentation/MsLearnDocumentationParser.cs @@ -143,13 +143,14 @@ public IReadOnlyCollection ParseQualityRules(string info) IReadOnlyCollection ruleIds = ParseQualityRuleTableIdRow(ruleId); + string description = ParseCaRuleDescription(markdownHeadedBlocks); + return ruleIds .Select(id => new RoslynQualityRule( id, title.Value, category.Value, - // TODO: #41 parse description - description: string.Empty)) + description)) .ToList(); } @@ -160,6 +161,20 @@ public IReadOnlyCollection ParseAdditionalFormattingOptio return ParseOptions(markdownHeadedBlocks); } + private string ParseCaRuleDescription(IReadOnlyCollection markdownHeadedBlocks) + { + MarkdownHeadedBlock? headedBlock = markdownHeadedBlocks.FirstOrDefault(b => b.HeaderText == "Rule description"); + if (headedBlock is null) + throw new ConfiguinException("Quality rule page does not contains Rule description block."); + + string overviewText = headedBlock + .Content + .Select(_textExtractor.ExtractText) + .Aggregate((a, b) => $"{a}{Environment.NewLine}{b}"); + + return overviewText; + } + private IReadOnlyCollection ParseQualityRuleTableIdRow(MsLearnPropertyValueDescriptionTableRow ruleId) { if (ruleId.Value.Contains("-")) diff --git a/Sources/Kysect.Configuin.Tests/CodeStyleGeneration/MarkdownCodeStyleFormatterTests.cs b/Sources/Kysect.Configuin.Tests/CodeStyleGeneration/MarkdownCodeStyleFormatterTests.cs index c73306d..122dd4b 100644 --- a/Sources/Kysect.Configuin.Tests/CodeStyleGeneration/MarkdownCodeStyleFormatterTests.cs +++ b/Sources/Kysect.Configuin.Tests/CodeStyleGeneration/MarkdownCodeStyleFormatterTests.cs @@ -99,6 +99,9 @@ public void FormatQualityRule_ForCA1064_ReturnExpected() Severity: Warning + An internal exception is only visible inside its own internal scope. After the exception falls outside the internal scope, only the base exception can be used to catch the exception. If the internal exception is inherited from xref:System.Exception, xref:System.SystemException, or xref:System.ApplicationException, the external code will not have sufficient information to know what to do with the exception. + But, if the code has a public exception that later is used as the base for an internal exception, it is reasonable to assume the code further out will be able to do something intelligent with the base exception. The public exception will have more information than what is provided by xref:System.Exception, xref:System.SystemException, or xref:System.ApplicationException. + """; RoslynQualityRule ca1064 = WellKnownRoslynRuleDefinitions.CA1064(); diff --git a/Sources/Kysect.Configuin.Tests/MsLearnDocumentation/MsLearnDocumentationParserTests.cs b/Sources/Kysect.Configuin.Tests/MsLearnDocumentation/MsLearnDocumentationParserTests.cs index fcfa301..4260da4 100644 --- a/Sources/Kysect.Configuin.Tests/MsLearnDocumentation/MsLearnDocumentationParserTests.cs +++ b/Sources/Kysect.Configuin.Tests/MsLearnDocumentation/MsLearnDocumentationParserTests.cs @@ -8,6 +8,7 @@ namespace Kysect.Configuin.Tests.MsLearnDocumentation; +// TODO: extract all rule descriptions to WellKnownRoslynRuleDefinitions public class MsLearnDocumentationParserTests { private static readonly MsLearnRepositoryPathProvider MsLearnRepositoryPathProvider = TestImplementations.CreateRepositoryPathProvider(); @@ -159,13 +160,11 @@ public void ParseQualityRule_CA1865_CA1867_ReturnExpectedResult() { string fileText = GetPathToCa("ca1865-ca1867.md"); - // TODO: parse description var expected = new RoslynQualityRule( RoslynRuleId.Parse("CA1865"), "Use 'string.Method(char)' instead of 'string.Method(string)' for string with single char", category: "Performance", - // TODO: parse description? - description: string.Empty); + description: "The overload that takes a char parameter performs better than the overload that takes a string parameter."); IReadOnlyCollection qualityRules = _parser.ParseQualityRules(fileText); @@ -296,9 +295,7 @@ public void Parse_CodeStyleRefactoringOptions_ReturnExpectedResult() codeStyleRefactoringOptions.ElementAt(0).Should().BeEquivalentTo(dotnet_style_operator_placement_when_wrapping); } - // TODO: remove ignore [Test] - [Ignore("Need to fix all related problems")] public void Parse_MsDocsRepository_FinishWithoutError() { MsLearnDocumentationInfoLocalProvider repositoryPathProvider = TestImplementations.CreateDocumentationInfoLocalProvider(); diff --git a/Sources/Kysect.Configuin.Tests/Resources/WellKnownRoslynRuleDefinitions.cs b/Sources/Kysect.Configuin.Tests/Resources/WellKnownRoslynRuleDefinitions.cs index 9e3653d..2ca9748 100644 --- a/Sources/Kysect.Configuin.Tests/Resources/WellKnownRoslynRuleDefinitions.cs +++ b/Sources/Kysect.Configuin.Tests/Resources/WellKnownRoslynRuleDefinitions.cs @@ -69,10 +69,12 @@ class MyClass public static RoslynQualityRule CA1064() { return new RoslynQualityRule( - RoslynRuleId.Parse("CA1064"), - "Exceptions should be public", - "Design", - // TODO: parse description - string.Empty); + ruleId: RoslynRuleId.Parse("CA1064"), + title: "Exceptions should be public", + category: "Design", + description: """ + An internal exception is only visible inside its own internal scope. After the exception falls outside the internal scope, only the base exception can be used to catch the exception. If the internal exception is inherited from xref:System.Exception, xref:System.SystemException, or xref:System.ApplicationException, the external code will not have sufficient information to know what to do with the exception. + But, if the code has a public exception that later is used as the base for an internal exception, it is reasonable to assume the code further out will be able to do something intelligent with the base exception. The public exception will have more information than what is provided by xref:System.Exception, xref:System.SystemException, or xref:System.ApplicationException. + """); } } \ No newline at end of file