diff --git a/src/CFamily.UnitTests/packages.lock.json b/src/CFamily.UnitTests/packages.lock.json
index 2b617620d5..040d7c822a 100644
--- a/src/CFamily.UnitTests/packages.lock.json
+++ b/src/CFamily.UnitTests/packages.lock.json
@@ -1606,7 +1606,8 @@
"DiffPlex": "[1.7.1, )",
"Microsoft.VisualStudio.Sdk": "[17.0.31902.203, )",
"SonarLint.VisualStudio.Core": "[1.0.0, )",
- "SonarLint.VisualStudio.Infrastructure.VS": "[1.0.0, )"
+ "SonarLint.VisualStudio.Infrastructure.VS": "[1.0.0, )",
+ "SonarLint.VisualStudio.SLCore": "[1.0.0, )"
}
},
"SonarLint.VisualStudio.Infrastructure.VS": {
diff --git a/src/Education.UnitTests/Layout/Logical/ContextualRuleDescriptionTabTests.cs b/src/Education.UnitTests/Layout/Logical/ContextualRuleDescriptionTabTests.cs
index 8ed06a49c6..b0278da4cf 100644
--- a/src/Education.UnitTests/Layout/Logical/ContextualRuleDescriptionTabTests.cs
+++ b/src/Education.UnitTests/Layout/Logical/ContextualRuleDescriptionTabTests.cs
@@ -45,6 +45,14 @@ public class ContextualRuleDescriptionTabTests
private const string ContextTabContent2 = "htmlcontent2";
private const string ContextTabXamlContent2 = "xamlcontent2";
+ [TestMethod]
+ public void Ctor_ContextContentTab_EnsuresHtmlIsXml()
+ {
+ var testSubject = new ContextualRuleDescriptionTab.ContextContentTab("title", "context", "
");
+
+ testSubject.HtmlContent.Should().BeEquivalentTo("");
+ }
+
[TestMethod]
public void Title_ReturnsCorrectTitle()
{
diff --git a/src/Education.UnitTests/Layout/Logical/NonContextualRuleDescriptionTabTests.cs b/src/Education.UnitTests/Layout/Logical/NonContextualRuleDescriptionTabTests.cs
index 1615718942..c7f3b8de1c 100644
--- a/src/Education.UnitTests/Layout/Logical/NonContextualRuleDescriptionTabTests.cs
+++ b/src/Education.UnitTests/Layout/Logical/NonContextualRuleDescriptionTabTests.cs
@@ -30,6 +30,14 @@ namespace SonarLint.VisualStudio.Education.UnitTests.Layout.Logical;
[TestClass]
public class NonContextualRuleDescriptionTabTests
{
+ [TestMethod]
+ public void Ctor_EnsuresHtmlIsXml()
+ {
+ var testSubject = new NonContextualRuleDescriptionTab("title", "");
+
+ testSubject.htmlContent.Should().BeEquivalentTo("");
+ }
+
[TestMethod]
public void ProduceVisualNode_ReturnsSingleContentSection()
{
diff --git a/src/Education.UnitTests/Layout/Logical/RichRuleDescriptionProviderTest.cs b/src/Education.UnitTests/Layout/Logical/RichRuleDescriptionProviderTest.cs
new file mode 100644
index 0000000000..846a84eb6d
--- /dev/null
+++ b/src/Education.UnitTests/Layout/Logical/RichRuleDescriptionProviderTest.cs
@@ -0,0 +1,86 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using System.Collections.Generic;
+using FluentAssertions;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using SonarLint.VisualStudio.Education.Layout.Logical;
+using SonarLint.VisualStudio.Education.Rule;
+using SonarLint.VisualStudio.SLCore.Protocol;
+using SonarLint.VisualStudio.SLCore.Service.Rules.Models;
+using SonarLint.VisualStudio.TestInfrastructure;
+
+namespace SonarLint.VisualStudio.Education.UnitTests.Layout.Logical;
+
+[TestClass]
+public class RichRuleDescriptionProviderTest
+{
+ [TestMethod]
+ public void MefCtor_CheckIsExported()
+ {
+ MefTestHelpers.CheckTypeCanBeImported();
+ }
+
+ [TestMethod]
+ public void MefCtor_CheckIsSingleton()
+ {
+ MefTestHelpers.CheckIsSingletonMefComponent();
+ }
+
+ [TestMethod]
+ public void Get_ReturnsCorrectStructure()
+ {
+ var richRuleDescriptionProvider = new RichRuleDescriptionProvider();
+ var ruleInfoMock = new Mock();
+ ruleInfoMock.SetupGet(x => x.RichRuleDescriptionDto).Returns(
+ new RuleSplitDescriptionDto("intro",
+ new List
+ {
+ new("tab 1",
+ Either.CreateLeft(
+ new RuleNonContextualSectionDto("content"))),
+ new("tab 2",
+ Either.CreateRight(
+ new RuleContextualSectionWithDefaultContextKeyDto("context2",
+ new List
+ {
+ new("context1content", "context1", "Context 1"),
+ new("context2content", "context2", "Context 2")
+ }))),
+ new("tab 3",
+ Either.CreateLeft(
+ new RuleNonContextualSectionDto("content"))),
+ }));
+
+
+ richRuleDescriptionProvider.GetRichRuleDescriptionModel(ruleInfoMock.Object).Should().BeEquivalentTo(
+ new RichRuleDescription("intro", new List
+ {
+ new NonContextualRuleDescriptionTab("tab 1", "content"),
+ new ContextualRuleDescriptionTab("tab 2", "context2", new List
+ {
+ new("Context 1", "context1", "context1content"),
+ new("Context 2", "context2", "context2content")
+ }),
+ new NonContextualRuleDescriptionTab("tab 3", "content"),
+ }));
+ }
+}
diff --git a/src/Education.UnitTests/Layout/Logical/RichRuleDescriptionTests.cs b/src/Education.UnitTests/Layout/Logical/RichRuleDescriptionTests.cs
index efb9f7905d..8bccd59e05 100644
--- a/src/Education.UnitTests/Layout/Logical/RichRuleDescriptionTests.cs
+++ b/src/Education.UnitTests/Layout/Logical/RichRuleDescriptionTests.cs
@@ -32,6 +32,14 @@ namespace SonarLint.VisualStudio.Education.UnitTests.Layout.Logical;
[TestClass]
public class RichRuleDescriptionTests
{
+ [TestMethod]
+ public void Ctor_EnsuresHtmlIsXml()
+ {
+ var testSubject = new RichRuleDescription( "", new List());
+
+ testSubject.introductionHtml.Should().BeEquivalentTo("");
+ }
+
[TestMethod]
public void ProduceVisualNode_ProducesMultiBlockSectionWithIntroAndTabs()
{
diff --git a/src/Education.UnitTests/Rule/RuleHelpTests.cs b/src/Education.UnitTests/Rule/RuleHelpTests.cs
deleted file mode 100644
index 5eb5e8f760..0000000000
--- a/src/Education.UnitTests/Rule/RuleHelpTests.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarLint for Visual Studio
- * Copyright (C) 2016-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-
-namespace SonarLint.VisualStudio.Education.UnitTests.Rule
-{
- [TestClass]
- public class RuleHelpTests
- {
-
- // [TestMethod]
- // public void Ctor_SetsProperties()
- // {
- // var context = new Context("some context key", "some display name");
- // var descriptionSection1 = new DescriptionSection("some descriptionSection key 1", "some htmlcontent 1", context);
- // var descriptionSection2 = new DescriptionSection("some descriptionSection key 2", "some htmlcontent 2");
- // var descriptionSections = new[] { descriptionSection1, descriptionSection2 };
- //
- // var educationPrinciples = new[] { "defense_in_depth", "never_trust_user_input" };
- // var defaultImpacts = new Dictionary();
- // defaultImpacts.Add(SoftwareQuality.Maintainability, SoftwareQualitySeverity.Medium);
- // defaultImpacts.Add(SoftwareQuality.Reliability, SoftwareQualitySeverity.Low);
- //
- // var tags = new string[] { "convention", "bad-practice" };
- //
- // var testSubject = new RuleInfo(
- // Language.CSharp.ServerLanguage.Key,
- // "xxx:S123",
- // "a description",
- // "the rule name",
- // RuleIssueSeverity.Blocker,
- // RuleIssueType.Vulnerability,
- // isActiveByDefault: true,
- // tags,
- // descriptionSections,
- // educationPrinciples,
- // "some user note",
- // CleanCodeAttribute.Respectful,
- // defaultImpacts);
- //
- // testSubject.LanguageKey.Should().Be(Language.CSharp.ServerLanguage.Key);
- // testSubject.FullRuleKey.Should().Be("xxx:S123");
- // testSubject.Description.Should().Be("a description");
- // testSubject.Name.Should().Be("the rule name");
- // testSubject.Severity.Should().Be(RuleIssueSeverity.Blocker);
- // testSubject.IssueType.Should().Be(RuleIssueType.Vulnerability);
- // testSubject.IsActiveByDefault.Should().BeTrue();
- // testSubject.Tags.Should().BeEquivalentTo(tags);
- // testSubject.DescriptionSections.Should().BeEquivalentTo(descriptionSections);
- // testSubject.EducationPrinciples.Should().BeEquivalentTo(educationPrinciples);
- // testSubject.HtmlNote.Should().Be("some user note");
- // testSubject.CleanCodeAttribute.Should().Be(CleanCodeAttribute.Respectful);
- // testSubject.DefaultImpacts.Should().BeEquivalentTo(defaultImpacts);
- // }
- }
-}
diff --git a/src/Education.UnitTests/Rule/RuleInfoTests.cs b/src/Education.UnitTests/Rule/RuleInfoTests.cs
index 254b2d491f..5dadf111c8 100644
--- a/src/Education.UnitTests/Rule/RuleInfoTests.cs
+++ b/src/Education.UnitTests/Rule/RuleInfoTests.cs
@@ -18,88 +18,138 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+using System;
+using System.Collections.Generic;
+using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
+using SonarLint.VisualStudio.Core;
+using SonarLint.VisualStudio.Core.Analysis;
+using SonarLint.VisualStudio.Education.Rule;
+using SonarLint.VisualStudio.SLCore.Service.Rules.Models;
namespace SonarLint.VisualStudio.Education.UnitTests.Rule
{
[TestClass]
public class RuleInfoTests
{
- // [TestMethod]
- // public void Ctor_NullCollectionsAreAllowed_SetToEmptyCollections()
- // {
- // var testSubject = new RuleInfo(
- // languageKey: null,
- // fullRuleKey: null,
- // description: null,
- // name: null,
- // RuleIssueSeverity.Unknown,
- // RuleIssueType.Unknown,
- // isActiveByDefault: false,
- // tags: null,
- // descriptionSections: null,
- // educationPrinciples: null,
- // htmlNote: null,
- // cleanCodeAttribute: null,
- // defaultImpacts: null);
- //
- // testSubject.Tags.Should().NotBeNull();
- // testSubject.DescriptionSections.Should().NotBeNull();
- // testSubject.EducationPrinciples.Should().NotBeNull();
- //
- // testSubject.Tags.Should().HaveCount(0);
- // testSubject.DescriptionSections.Should().HaveCount(0);
- // testSubject.EducationPrinciples.Should().HaveCount(0);
- // }
- //
- // [TestMethod]
- // public void WithCleanCodeTaxonomyDisabled_SetsCctPropertiesToNull()
- // {
- // var languageKey = "any";
- // var fullRuleKey = "any";
- // var description = "any";
- // var name = "any";
- // var ruleIssueSeverity = RuleIssueSeverity.Critical;
- // var ruleIssueType = RuleIssueType.Bug;
- // var isActiveByDefault = true;
- // IReadOnlyList tags = new []{ "any"};
- // IReadOnlyList descriptionSections = Array.Empty();
- // IReadOnlyList educationPrinciples = Array.Empty();
- // var htmlNote = "any";
- // CleanCodeAttribute? cleanCodeAttribute = CleanCodeAttribute.Focused;
- // Dictionary defaultImpacts = new Dictionary();
- //
- // var testSubject = new RuleInfo(
- // languageKey,
- // fullRuleKey,
- // description,
- // name,
- // ruleIssueSeverity,
- // ruleIssueType,
- // isActiveByDefault,
- // tags,
- // descriptionSections,
- // educationPrinciples,
- // htmlNote,
- // cleanCodeAttribute,
- // defaultImpacts);
- //
- // var expected = new RuleInfo(
- // languageKey,
- // fullRuleKey,
- // description,
- // name,
- // ruleIssueSeverity,
- // ruleIssueType,
- // isActiveByDefault,
- // tags,
- // descriptionSections,
- // educationPrinciples,
- // htmlNote,
- // null,
- // null);
- //
- // testSubject.WithCleanCodeTaxonomyDisabled().Should().BeEquivalentTo(expected);
- // }
+ [TestMethod]
+ public void Ctor_NullCollectionsAreAllowed_SetToEmptyCollections()
+ {
+ var testSubject = new RuleInfo(
+ languageKey: null,
+ fullRuleKey: null,
+ description: null,
+ name: null,
+ RuleIssueSeverity.Unknown,
+ RuleIssueType.Unknown,
+ isActiveByDefault: false,
+ tags: null,
+ educationPrinciples: null,
+ htmlNote: null,
+ richRuleDescriptionDto: null,
+ cleanCodeAttribute: null,
+ defaultImpacts: null);
+
+ testSubject.Tags.Should().NotBeNull();
+ testSubject.EducationPrinciples.Should().NotBeNull();
+
+ testSubject.Tags.Should().HaveCount(0);
+ testSubject.EducationPrinciples.Should().HaveCount(0);
+ }
+
+ [TestMethod]
+ public void WithCleanCodeTaxonomyDisabled_SetsCctPropertiesToNull()
+ {
+ var languageKey = "any";
+ var fullRuleKey = "any";
+ var description = "any";
+ var name = "any";
+ var ruleIssueSeverity = RuleIssueSeverity.Critical;
+ var ruleIssueType = RuleIssueType.Bug;
+ var isActiveByDefault = true;
+ IReadOnlyList tags = new []{ "any"};
+ IReadOnlyList educationPrinciples = Array.Empty();
+ var htmlNote = "any";
+ var richDescription = new RuleSplitDescriptionDto("any", new List());
+ CleanCodeAttribute? cleanCodeAttribute = CleanCodeAttribute.Focused;
+ Dictionary defaultImpacts = new Dictionary();
+
+ var testSubject = new RuleInfo(
+ languageKey,
+ fullRuleKey,
+ description,
+ name,
+ ruleIssueSeverity,
+ ruleIssueType,
+ isActiveByDefault,
+ tags,
+ educationPrinciples,
+ htmlNote,
+ richDescription,
+ cleanCodeAttribute,
+ defaultImpacts);
+
+ var expected = new RuleInfo(
+ languageKey,
+ fullRuleKey,
+ description,
+ name,
+ ruleIssueSeverity,
+ ruleIssueType,
+ isActiveByDefault,
+ tags,
+ educationPrinciples,
+ htmlNote,
+ richDescription,
+ null,
+ null);
+
+ testSubject.WithCleanCodeTaxonomyDisabled().Should().BeEquivalentTo(expected);
+ }
+
+ [TestMethod]
+ public void Ctor_SetsProperties()
+ {
+ var richDescription = new RuleSplitDescriptionDto("any", new List());
+
+ var educationPrinciples = new[] { "defense_in_depth", "never_trust_user_input" };
+ var defaultImpacts = new Dictionary();
+ defaultImpacts.Add(SoftwareQuality.Maintainability, SoftwareQualitySeverity.Medium);
+ defaultImpacts.Add(SoftwareQuality.Reliability, SoftwareQualitySeverity.Low);
+
+ var tags = new string[] { "convention", "bad-practice" };
+
+ var testSubject = new RuleInfo(
+ Language.CSharp.ServerLanguage.Key,
+ "xxx:S123",
+ "a description",
+ "the rule name",
+ RuleIssueSeverity.Blocker,
+ RuleIssueType.Vulnerability,
+ isActiveByDefault: true,
+ tags,
+ educationPrinciples,
+ "some user note",
+ richDescription,
+ CleanCodeAttribute.Respectful,
+ defaultImpacts);
+
+ testSubject.LanguageKey.Should().Be(Language.CSharp.ServerLanguage.Key);
+ testSubject.FullRuleKey.Should().Be("xxx:S123");
+ testSubject.Description.Should().Be("a description");
+ testSubject.Name.Should().Be("the rule name");
+ testSubject.Severity.Should().Be(RuleIssueSeverity.Blocker);
+ testSubject.IssueType.Should().Be(RuleIssueType.Vulnerability);
+ testSubject.IsActiveByDefault.Should().BeTrue();
+ testSubject.Tags.Should().BeEquivalentTo(tags);
+ testSubject.EducationPrinciples.Should().BeEquivalentTo(educationPrinciples);
+ testSubject.HtmlNote.Should().Be("some user note");
+ testSubject.RichRuleDescriptionDto.Should().BeSameAs(richDescription);
+ testSubject.CleanCodeAttribute.Should().Be(CleanCodeAttribute.Respectful);
+ testSubject.DefaultImpacts.Should().BeEquivalentTo(defaultImpacts);
+ }
+
}
+
+
}
diff --git a/src/Education.UnitTests/XamlGenerator/RuleHelpXamlBuilderTests.cs b/src/Education.UnitTests/XamlGenerator/RuleHelpXamlBuilderTests.cs
index f8a77ee8e1..a70d686ddc 100644
--- a/src/Education.UnitTests/XamlGenerator/RuleHelpXamlBuilderTests.cs
+++ b/src/Education.UnitTests/XamlGenerator/RuleHelpXamlBuilderTests.cs
@@ -1,60 +1,61 @@
-// /*
-// * SonarLint for Visual Studio
-// * Copyright (C) 2016-2024 SonarSource SA
-// * mailto:info AT sonarsource DOT com
-// *
-// * This program is free software; you can redistribute it and/or
-// * modify it under the terms of the GNU Lesser General Public
-// * License as published by the Free Software Foundation; either
-// * version 3 of the License, or (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// * Lesser General Public License for more details.
-// *
-// * You should have received a copy of the GNU Lesser General Public License
-// * along with this program; if not, write to the Free Software Foundation,
-// * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-// */
-//
-// using System.Collections.Generic;
-// using Microsoft.VisualStudio.TestTools.UnitTesting;
-// using Moq;
-// using SonarLint.VisualStudio.Education.XamlGenerator;
-// using SonarLint.VisualStudio.Rules;
-// using SonarLint.VisualStudio.TestInfrastructure;
-//
-// namespace SonarLint.VisualStudio.Education.UnitTests.XamlGenerator;
-//
-// [TestClass]
-// public class RuleHelpXamlBuilderTests
-// {
-// [TestMethod]
-// public void MefCtor_CheckExports()
-// {
-// MefTestHelpers.CheckTypeCanBeImported(
-// MefTestHelpers.CreateExport(),
-// MefTestHelpers.CreateExport());
-// }
-//
-// [DataTestMethod]
-// [DataRow(true)]
-// [DataRow(false)]
-// public void Create_ChoosesCorrectLayoutBuilder(bool isExtendedRule)
-// {
-// var selectedIssueContext = "abrakadabra";
-// var ruleInfoMock = new Mock();
-// ruleInfoMock.SetupGet(x => x.DescriptionSections).Returns(isExtendedRule
-// ? new List { new DescriptionSection(null, null), new DescriptionSection(null, null) }
-// : null);
-// var simpleRuleHelpXamlBuilderMock = new Mock();
-// var richRuleHelpXamlBuilderMock = new Mock();
-// var testSubject = new RuleHelpXamlBuilder(simpleRuleHelpXamlBuilderMock.Object, richRuleHelpXamlBuilderMock.Object);
-//
-// testSubject.Create(ruleInfoMock.Object, selectedIssueContext);
-//
-// simpleRuleHelpXamlBuilderMock.Verify(x => x.Create(ruleInfoMock.Object), isExtendedRule ? Times.Never : Times.Once);
-// richRuleHelpXamlBuilderMock.Verify(x => x.Create(ruleInfoMock.Object, selectedIssueContext), isExtendedRule ? Times.Once : Times.Never);
-// }
-// }
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using SonarLint.VisualStudio.Education.Rule;
+using SonarLint.VisualStudio.Education.XamlGenerator;
+using SonarLint.VisualStudio.SLCore.Service.Rules.Models;
+using SonarLint.VisualStudio.TestInfrastructure;
+
+namespace SonarLint.VisualStudio.Education.UnitTests.XamlGenerator;
+
+[TestClass]
+public class RuleHelpXamlBuilderTests
+{
+ [TestMethod]
+ public void MefCtor_CheckExports()
+ {
+ MefTestHelpers.CheckTypeCanBeImported(
+ MefTestHelpers.CreateExport(),
+ MefTestHelpers.CreateExport());
+ }
+
+ [DataTestMethod]
+ [DataRow(true)]
+ [DataRow(false)]
+ public void Create_ChoosesCorrectLayoutBuilder(bool isExtendedRule)
+ {
+ var selectedIssueContext = "abrakadabra";
+ var ruleInfoMock = new Mock();
+ ruleInfoMock.SetupGet(x => x.RichRuleDescriptionDto).Returns(isExtendedRule
+ ? new RuleSplitDescriptionDto("intro", new List())
+ : null);
+ var simpleRuleHelpXamlBuilderMock = new Mock();
+ var richRuleHelpXamlBuilderMock = new Mock();
+ var testSubject = new RuleHelpXamlBuilder(simpleRuleHelpXamlBuilderMock.Object, richRuleHelpXamlBuilderMock.Object);
+
+ testSubject.Create(ruleInfoMock.Object, selectedIssueContext);
+
+ simpleRuleHelpXamlBuilderMock.Verify(x => x.Create(ruleInfoMock.Object), isExtendedRule ? Times.Never : Times.Once);
+ richRuleHelpXamlBuilderMock.Verify(x => x.Create(ruleInfoMock.Object, selectedIssueContext), isExtendedRule ? Times.Once : Times.Never);
+ }
+}
diff --git a/src/Education.UnitTests/XamlGenerator/XamlGeneratorHelperTests.cs b/src/Education.UnitTests/XamlGenerator/XamlGeneratorHelperTests.cs
index 4ea64505a0..3c1ef1a093 100644
--- a/src/Education.UnitTests/XamlGenerator/XamlGeneratorHelperTests.cs
+++ b/src/Education.UnitTests/XamlGenerator/XamlGeneratorHelperTests.cs
@@ -52,7 +52,7 @@ public void WriteDocumentHeaderAndEndDocument_ExtendedDescription_ProduceCorrect
var xmlWriter = new XamlWriterFactory().Create(sb);
var ruleInfo = new RuleInfo("cs", "cs:123", "Hi
", "Hi", RuleIssueSeverity.Critical,
RuleIssueType.Vulnerability, true, new List(),
- new List(), "fix this pls
", null, null);
+ new List(), "fix this pls
", null,null, null);
var testSubject = CreateTestSubject(xmlWriter);
@@ -84,7 +84,7 @@ public void WriteDocumentHeaderAndEndDocument_ProduceCorrectStructure()
var xmlWriter = new XamlWriterFactory().Create(sb);
var ruleInfo = new RuleInfo("cs", "cs:123", "Hi
", "Hi", RuleIssueSeverity.Critical,
RuleIssueType.Vulnerability, true, new List(),
- new List(), null, null, null);
+ new List(), null, null, null, null);
IXamlGeneratorHelper testSubject = CreateTestSubject(xmlWriter);
testSubject.WriteDocumentHeader(ruleInfo);
@@ -117,7 +117,7 @@ public void WriteDocumentHeaderAndEndDocument_ProduceCorrectStructure_NewCCT()
var xmlWriter = new XamlWriterFactory().Create(sb);
var ruleInfo = new RuleInfo("cs", "cs:123", "Hi
", "Hi", RuleIssueSeverity.Critical,
RuleIssueType.Vulnerability, true, new List(),
- new List(), null, CleanCodeAttribute.Formatted, new Dictionary
+ new List(), null, null, CleanCodeAttribute.Formatted, new Dictionary
{
{ SoftwareQuality.Maintainability, SoftwareQualitySeverity.High},
{ SoftwareQuality.Security, SoftwareQualitySeverity.Low},
diff --git a/src/Education.UnitTests/packages.lock.json b/src/Education.UnitTests/packages.lock.json
index a1351ac397..2af787fa59 100644
--- a/src/Education.UnitTests/packages.lock.json
+++ b/src/Education.UnitTests/packages.lock.json
@@ -1554,7 +1554,8 @@
"DiffPlex": "[1.7.1, )",
"Microsoft.VisualStudio.Sdk": "[17.0.31902.203, )",
"SonarLint.VisualStudio.Core": "[1.0.0, )",
- "SonarLint.VisualStudio.Infrastructure.VS": "[1.0.0, )"
+ "SonarLint.VisualStudio.Infrastructure.VS": "[1.0.0, )",
+ "SonarLint.VisualStudio.SLCore": "[1.0.0, )"
}
},
"SonarLint.VisualStudio.Infrastructure.VS": {
@@ -1623,6 +1624,13 @@
"SonarLint.VisualStudio.Progress": "[1.0.0, )"
}
},
+ "SonarLint.VisualStudio.SLCore": {
+ "type": "Project",
+ "dependencies": {
+ "SonarLint.VisualStudio.Core": "[1.0.0, )",
+ "StreamJsonRpc": "[2.5.46, )"
+ }
+ },
"sonarqube.client": {
"type": "Project",
"dependencies": {
diff --git a/src/Education/Education.csproj b/src/Education/Education.csproj
index 8f9782d7bf..f75a692608 100644
--- a/src/Education/Education.csproj
+++ b/src/Education/Education.csproj
@@ -48,6 +48,7 @@
+
Menus.ctmenu
Designer
diff --git a/src/Education/Layout/Logical/ContextualRuleDescriptionTab.cs b/src/Education/Layout/Logical/ContextualRuleDescriptionTab.cs
index 795f16266f..3dd53bb834 100644
--- a/src/Education/Layout/Logical/ContextualRuleDescriptionTab.cs
+++ b/src/Education/Layout/Logical/ContextualRuleDescriptionTab.cs
@@ -23,6 +23,7 @@
using System.Linq;
using SonarLint.VisualStudio.Education.Layout.Visual;
using SonarLint.VisualStudio.Education.Layout.Visual.Tabs;
+using SonarLint.VisualStudio.Education.Rule;
namespace SonarLint.VisualStudio.Education.Layout.Logical
{
@@ -78,7 +79,7 @@ public ContextContentTab(string title, string contextKey, string htmlContent)
{
Title = title;
ContextKey = contextKey;
- HtmlContent = htmlContent;
+ HtmlContent = HtmlXmlCompatibilityHelper.EnsureHtmlIsXml(htmlContent);
}
public string Title { get; }
diff --git a/src/Education/Layout/Logical/NonContextualRuleDescriptionTab.cs b/src/Education/Layout/Logical/NonContextualRuleDescriptionTab.cs
index adb5cee61f..b9e55fb537 100644
--- a/src/Education/Layout/Logical/NonContextualRuleDescriptionTab.cs
+++ b/src/Education/Layout/Logical/NonContextualRuleDescriptionTab.cs
@@ -19,17 +19,18 @@
*/
using SonarLint.VisualStudio.Education.Layout.Visual;
+using SonarLint.VisualStudio.Education.Rule;
namespace SonarLint.VisualStudio.Education.Layout.Logical
{
internal class NonContextualRuleDescriptionTab : IRuleDescriptionTab
{
- private readonly string htmlContent;
+ internal /* for testing */ readonly string htmlContent;
public NonContextualRuleDescriptionTab(string title, string htmlContent)
{
Title = title;
- this.htmlContent = htmlContent;
+ this.htmlContent = HtmlXmlCompatibilityHelper.EnsureHtmlIsXml(htmlContent);
}
public string Title { get; }
diff --git a/src/Education/Layout/Logical/RichRuleDescription.cs b/src/Education/Layout/Logical/RichRuleDescription.cs
index 68987792d3..79f3d76f2f 100644
--- a/src/Education/Layout/Logical/RichRuleDescription.cs
+++ b/src/Education/Layout/Logical/RichRuleDescription.cs
@@ -22,6 +22,7 @@
using System.Linq;
using SonarLint.VisualStudio.Education.Layout.Visual;
using SonarLint.VisualStudio.Education.Layout.Visual.Tabs;
+using SonarLint.VisualStudio.Education.Rule;
namespace SonarLint.VisualStudio.Education.Layout.Logical
{
@@ -31,12 +32,12 @@ internal interface IRichRuleDescription : IVisualNodeProducer
internal class RichRuleDescription : IRichRuleDescription
{
- private readonly string introductionHtml;
+ internal /* for testing */ readonly string introductionHtml;
private readonly List tabs;
public RichRuleDescription(string introductionHtml, List tabs)
{
- this.introductionHtml = introductionHtml;
+ this.introductionHtml = HtmlXmlCompatibilityHelper.EnsureHtmlIsXml(introductionHtml);
this.tabs = tabs;
}
diff --git a/src/Education/Layout/Logical/RichRuleDescriptionConverter.cs b/src/Education/Layout/Logical/RichRuleDescriptionConverter.cs
deleted file mode 100644
index 2bca193820..0000000000
--- a/src/Education/Layout/Logical/RichRuleDescriptionConverter.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SonarLint for Visual Studio
- * Copyright (C) 2016-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-using SonarLint.VisualStudio.Education.Rule;
-
-namespace SonarLint.VisualStudio.Education.Layout.Logical
-{
- ///
- /// Provides from
- ///
- internal interface IRichRuleDescriptionProvider
- {
- IRichRuleDescription GetRichRuleDescriptionModel(IRuleInfo ruleInfo);
- }
-}
diff --git a/src/Education/Layout/Logical/RichRuleDescriptionProvider.cs b/src/Education/Layout/Logical/RichRuleDescriptionProvider.cs
new file mode 100644
index 0000000000..42824dd03f
--- /dev/null
+++ b/src/Education/Layout/Logical/RichRuleDescriptionProvider.cs
@@ -0,0 +1,62 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Linq;
+using SonarLint.VisualStudio.Education.Rule;
+using SonarLint.VisualStudio.SLCore.Service.Rules.Models;
+
+namespace SonarLint.VisualStudio.Education.Layout.Logical
+{
+ ///
+ /// Provides from
+ ///
+ internal interface IRichRuleDescriptionProvider
+ {
+ IRichRuleDescription GetRichRuleDescriptionModel(IRuleInfo ruleInfo);
+ }
+
+ [Export(typeof(IRichRuleDescriptionProvider))]
+ [PartCreationPolicy(CreationPolicy.Shared)]
+ internal class RichRuleDescriptionProvider : IRichRuleDescriptionProvider
+ {
+ public IRichRuleDescription GetRichRuleDescriptionModel(IRuleInfo ruleInfo) =>
+ new RichRuleDescription(ruleInfo.RichRuleDescriptionDto.introductionHtmlContent, CreateMainTabs(ruleInfo));
+
+ private static List CreateMainTabs(IRuleInfo ruleInfo) =>
+ ruleInfo.RichRuleDescriptionDto.tabs
+ .Select(tab => tab.content.Left is not null ? CreateNonContextualTab(tab) : CreateContextualTab(tab))
+ .ToList();
+
+ private static IRuleDescriptionTab CreateNonContextualTab(RuleDescriptionTabDto tab) =>
+ new NonContextualRuleDescriptionTab(tab.title, tab.content.Left.htmlContent);
+
+ private static IRuleDescriptionTab CreateContextualTab(RuleDescriptionTabDto tab) =>
+ new ContextualRuleDescriptionTab(tab.title,
+ tab.content.Right.defaultContextKey,
+ tab.content.Right.contextualSections
+ .Select(context =>
+ new ContextualRuleDescriptionTab.ContextContentTab(context.displayName,
+ context.contextKey,
+ context.htmlContent))
+ .ToList());
+ }
+}
diff --git a/src/Education/Rule/IRuleInfo.cs b/src/Education/Rule/IRuleInfo.cs
index 5651984fe9..b359e93710 100644
--- a/src/Education/Rule/IRuleInfo.cs
+++ b/src/Education/Rule/IRuleInfo.cs
@@ -26,6 +26,7 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using SonarLint.VisualStudio.Core.Analysis;
+using SonarLint.VisualStudio.SLCore.Service.Rules.Models;
namespace SonarLint.VisualStudio.Education.Rule
{
@@ -85,6 +86,8 @@ public interface IRuleInfo
IReadOnlyList EducationPrinciples { get; }
string HtmlNote { get; }
+
+ RuleSplitDescriptionDto RichRuleDescriptionDto { get; }
CleanCodeAttribute? CleanCodeAttribute { get; }
@@ -97,7 +100,7 @@ public class RuleInfo : IRuleInfo
{
public RuleInfo(string languageKey, string fullRuleKey, string description, string name,
RuleIssueSeverity severity, RuleIssueType issueType, bool isActiveByDefault,
- IReadOnlyList tags, IReadOnlyList educationPrinciples, string htmlNote,
+ IReadOnlyList tags, IReadOnlyList educationPrinciples, string htmlNote, RuleSplitDescriptionDto richRuleDescriptionDto,
CleanCodeAttribute? cleanCodeAttribute, Dictionary defaultImpacts)
{
LanguageKey = languageKey;
@@ -110,6 +113,7 @@ public RuleInfo(string languageKey, string fullRuleKey, string description, stri
Tags = tags ?? Array.Empty();
EducationPrinciples = educationPrinciples ?? Array.Empty();
HtmlNote = htmlNote;
+ RichRuleDescriptionDto = richRuleDescriptionDto;
CleanCodeAttribute = cleanCodeAttribute;
DefaultImpacts = defaultImpacts ?? new Dictionary();
}
@@ -133,6 +137,7 @@ public RuleInfo(string languageKey, string fullRuleKey, string description, stri
public IReadOnlyList EducationPrinciples { get; }
public string HtmlNote { get; }
+ public RuleSplitDescriptionDto RichRuleDescriptionDto { get; set; }
public CleanCodeAttribute? CleanCodeAttribute { get; }
@@ -149,6 +154,7 @@ public IRuleInfo WithCleanCodeTaxonomyDisabled() =>
Tags,
EducationPrinciples,
HtmlNote,
+ RichRuleDescriptionDto,
null,
null);
}
diff --git a/src/Education/Rule/RuleExtensions.cs b/src/Education/Rule/RuleExtensions.cs
index 40697606df..b5c3a69996 100644
--- a/src/Education/Rule/RuleExtensions.cs
+++ b/src/Education/Rule/RuleExtensions.cs
@@ -24,10 +24,7 @@ namespace SonarLint.VisualStudio.Education.Rule
{
public static class RuleExtensions
{
- public static bool IsRichRuleDescription(this IRuleInfo ruleInfo)
- {
- throw new NotImplementedException(); // will be re-implemented later
- // return ruleInfo.DescriptionSections != null && ruleInfo.DescriptionSections.Count > 1;
- }
+ public static bool IsRichRuleDescription(this IRuleInfo ruleInfo) =>
+ ruleInfo.RichRuleDescriptionDto != null;
}
}
diff --git a/src/Education/packages.lock.json b/src/Education/packages.lock.json
index f197f1d130..de20482796 100644
--- a/src/Education/packages.lock.json
+++ b/src/Education/packages.lock.json
@@ -1130,10 +1130,11 @@
"SonarLint.VisualStudio.Core": "[1.0.0, )"
}
},
- "SonarLint.VisualStudio.Rules": {
+ "SonarLint.VisualStudio.SLCore": {
"type": "Project",
"dependencies": {
- "SonarLint.VisualStudio.Core": "[1.0.0, )"
+ "SonarLint.VisualStudio.Core": "[1.0.0, )",
+ "StreamJsonRpc": "[2.5.46, )"
}
},
"sonarqube.client": {
diff --git a/src/Integration.Vsix.UnitTests/packages.lock.json b/src/Integration.Vsix.UnitTests/packages.lock.json
index faae7d1c45..0150669fef 100644
--- a/src/Integration.Vsix.UnitTests/packages.lock.json
+++ b/src/Integration.Vsix.UnitTests/packages.lock.json
@@ -1617,7 +1617,8 @@
"DiffPlex": "[1.7.1, )",
"Microsoft.VisualStudio.Sdk": "[17.0.31902.203, )",
"SonarLint.VisualStudio.Core": "[1.0.0, )",
- "SonarLint.VisualStudio.Infrastructure.VS": "[1.0.0, )"
+ "SonarLint.VisualStudio.Infrastructure.VS": "[1.0.0, )",
+ "SonarLint.VisualStudio.SLCore": "[1.0.0, )"
}
},
"SonarLint.VisualStudio.Infrastructure.VS": {
diff --git a/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithStrongNames.txt b/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithStrongNames.txt
index 2e16b9e54a..6338bdcbd8 100644
--- a/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithStrongNames.txt
+++ b/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithStrongNames.txt
@@ -1,7 +1,7 @@
---
################################
# Assembly references report
-# Report date/time: 2024-02-12T15:03:48.2745900Z
+# Report date/time: 2024-02-14T10:22:34.7734356Z
################################
#
# Generated by Devtility CheckAsmRefs v0.11.0.223
@@ -221,13 +221,14 @@ Referenced assemblies:
- 'PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
- 'SonarLint.VisualStudio.Core, Version=7.7.0.0, Culture=neutral, PublicKeyToken=c5b62af9de6d7244'
- 'SonarLint.VisualStudio.Infrastructure.VS, Version=7.7.0.0, Culture=neutral, PublicKeyToken=c5b62af9de6d7244'
+- 'SonarLint.VisualStudio.SLCore, Version=7.7.0.0, Culture=neutral, PublicKeyToken=c5b62af9de6d7244'
- 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.ComponentModel.Composition, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
-# Number of references: 19
+# Number of references: 20
---
Assembly: 'SonarLint.VisualStudio.Infrastructure.VS, Version=7.8.0.0, Culture=neutral, PublicKeyToken=c5b62af9de6d7244'
diff --git a/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithoutStrongNames.txt b/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithoutStrongNames.txt
index 9c516a378a..9c9d7d6e0e 100644
--- a/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithoutStrongNames.txt
+++ b/src/Integration.Vsix/AsmRef_Integration.Vsix_Baseline_WithoutStrongNames.txt
@@ -1,7 +1,7 @@
---
################################
# Assembly references report
-# Report date/time: 2024-02-12T15:03:48.2745900Z
+# Report date/time: 2024-02-14T10:22:34.7734356Z
################################
#
# Generated by Devtility CheckAsmRefs v0.11.0.223
@@ -221,13 +221,14 @@ Referenced assemblies:
- 'PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
- 'SonarLint.VisualStudio.Core, Version=7.7.0.0, Culture=neutral, PublicKeyToken=null'
- 'SonarLint.VisualStudio.Infrastructure.VS, Version=7.7.0.0, Culture=neutral, PublicKeyToken=null'
+- 'SonarLint.VisualStudio.SLCore, Version=7.7.0.0, Culture=neutral, PublicKeyToken=null'
- 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.ComponentModel.Composition, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
- 'System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
- 'System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
-# Number of references: 19
+# Number of references: 20
---
Assembly: 'SonarLint.VisualStudio.Infrastructure.VS, Version=7.8.0.0, Culture=neutral, PublicKeyToken=null'
diff --git a/src/Integration.Vsix/packages.lock.json b/src/Integration.Vsix/packages.lock.json
index 494dd3d992..c5576d48fb 100644
--- a/src/Integration.Vsix/packages.lock.json
+++ b/src/Integration.Vsix/packages.lock.json
@@ -1578,7 +1578,8 @@
"DiffPlex": "[1.7.1, )",
"Microsoft.VisualStudio.Sdk": "[17.0.31902.203, )",
"SonarLint.VisualStudio.Core": "[1.0.0, )",
- "SonarLint.VisualStudio.Infrastructure.VS": "[1.0.0, )"
+ "SonarLint.VisualStudio.Infrastructure.VS": "[1.0.0, )",
+ "SonarLint.VisualStudio.SLCore": "[1.0.0, )"
}
},
"SonarLint.VisualStudio.Infrastructure.VS": {
diff --git a/src/SLCore/Protocol/Either.cs b/src/SLCore/Protocol/Either.cs
index 1a52524ebc..d20d7e027d 100644
--- a/src/SLCore/Protocol/Either.cs
+++ b/src/SLCore/Protocol/Either.cs
@@ -18,6 +18,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+using System;
+
namespace SonarLint.VisualStudio.SLCore.Protocol
{
///
@@ -34,7 +36,7 @@ private Either()
public TLeft Left { get; private set; }
public TRight Right { get; private set; }
- public static Either CreateLeft(TLeft left) => new Either { Left = left };
- public static Either CreateRight(TRight right) => new Either { Right = right };
+ public static Either CreateLeft(TLeft left) => new() { Left = left ?? throw new ArgumentNullException(nameof(left))};
+ public static Either CreateRight(TRight right) => new() { Right = right ?? throw new ArgumentNullException(nameof(right))};
}
}