diff options
5 files changed, 78 insertions, 15 deletions
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java index 9492aaa3f1c..da691f81916 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/RuleDescriptionFormatter.java @@ -23,6 +23,7 @@ import com.google.common.collect.MoreCollectors; import java.util.Collection; import java.util.Objects; import javax.annotation.CheckForNull; +import javax.annotation.Nullable; import org.sonar.db.rule.RuleDescriptionSectionDto; import org.sonar.db.rule.RuleDto; import org.sonar.markdown.Markdown; @@ -41,7 +42,7 @@ public class RuleDescriptionFormatter { } @CheckForNull - private static String retrieveDescription(Collection<RuleDescriptionSectionDto> ruleDescriptionSectionDtos, RuleDto.Format descriptionFormat) { + private String retrieveDescription(Collection<RuleDescriptionSectionDto> ruleDescriptionSectionDtos, RuleDto.Format descriptionFormat) { return ruleDescriptionSectionDtos.stream() .filter(RuleDescriptionSectionDto::isDefault) .collect(MoreCollectors.toOptional()) @@ -49,12 +50,11 @@ public class RuleDescriptionFormatter { .orElse(null); } - private static String toHtml(RuleDto.Format descriptionFormat, RuleDescriptionSectionDto ruleDescriptionSectionDto) { + public String toHtml(@Nullable RuleDto.Format descriptionFormat, RuleDescriptionSectionDto ruleDescriptionSectionDto) { if (MARKDOWN.equals(descriptionFormat)) { return Markdown.convertToHtml(ruleDescriptionSectionDto.getContent()); - } else { - return ruleDescriptionSectionDto.getContent(); } + return ruleDescriptionSectionDto.getContent(); } } diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java index 2268e2e408b..9a061046efe 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/RuleDescriptionFormatterTest.java @@ -27,7 +27,10 @@ import org.sonar.db.rule.RuleDto; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ASSESS_THE_PROBLEM_SECTION_KEY; import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ROOT_CAUSE_SECTION_KEY; +import static org.sonar.db.rule.RuleDescriptionSectionDto.DEFAULT_KEY; import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection; +import static org.sonar.db.rule.RuleDto.Format.HTML; +import static org.sonar.db.rule.RuleDto.Format.MARKDOWN; public class RuleDescriptionFormatterTest { @@ -37,7 +40,7 @@ public class RuleDescriptionFormatterTest { @Test public void getMarkdownDescriptionAsHtml() { - RuleDto rule = new RuleDto().setDescriptionFormat(RuleDto.Format.MARKDOWN).addRuleDescriptionSectionDto(MARKDOWN_SECTION).setType(RuleType.BUG); + RuleDto rule = new RuleDto().setDescriptionFormat(MARKDOWN).addRuleDescriptionSectionDto(MARKDOWN_SECTION).setType(RuleType.BUG); String html = ruleDescriptionFormatter.getDescriptionAsHtml(rule); assertThat(html).isEqualTo("<strong>md</strong> <code>description</code>"); } @@ -78,6 +81,25 @@ public class RuleDescriptionFormatterTest { assertThat(result).isNull(); } + @Test + public void toHtmlWithNullFormat() { + RuleDescriptionSectionDto section = createRuleDescriptionSection(DEFAULT_KEY, "whatever"); + String result = ruleDescriptionFormatter.toHtml(null, section); + assertThat(result).isEqualTo(section.getContent()); + } + + @Test + public void toHtmlWithMarkdownFormat() { + String result = ruleDescriptionFormatter.toHtml(MARKDOWN, MARKDOWN_SECTION); + assertThat(result).isEqualTo("<strong>md</strong> <code>description</code>"); + } + + @Test + public void toHtmlWithHtmlFormat() { + String result = ruleDescriptionFormatter.toHtml(HTML, HTML_SECTION); + assertThat(result).isEqualTo(HTML_SECTION.getContent()); + } + private static RuleDescriptionSectionDto createRuleDescriptionSection(String key, String content) { return RuleDescriptionSectionDto.builder().key(key).content(content).build(); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java index 18c7ff3cfba..e1c09617814 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleMapper.java @@ -376,18 +376,16 @@ public class RuleMapper { return ruleDescriptionSectionDtos.size() > 1 && s.isDefault(); } - private static Rules.Rule.DescriptionSection toDescriptionSection(RuleDto ruleDto, RuleDescriptionSectionDto section) { + private Rules.Rule.DescriptionSection toDescriptionSection(RuleDto ruleDto, RuleDescriptionSectionDto section) { + String htmlContent = ruleDescriptionFormatter.toHtml(ruleDto.getDescriptionFormat(), section); + String interpretedHtmlContent = macroInterpreter.interpret(htmlContent); + Rules.Rule.DescriptionSection.Builder sectionBuilder = Rules.Rule.DescriptionSection.newBuilder() .setKey(section.getKey()) - .setContent(retrieveDescriptionContent(ruleDto.getDescriptionFormat(), section)); + .setContent(interpretedHtmlContent); toProtobufContext(section.getContext()).ifPresent(sectionBuilder::setContext); - return sectionBuilder.build(); - } - private static String retrieveDescriptionContent(@Nullable RuleDto.Format format, RuleDescriptionSectionDto sectionDto) { - return MARKDOWN.equals(format) ? - Markdown.convertToHtml(sectionDto.getContent()) : - sectionDto.getContent(); + return sectionBuilder.build(); } private void setNotesFields(Rules.Rule.Builder ruleResponse, RuleDto ruleDto, Map<String, UserDto> usersByUuid, Set<String> fieldsToReturn) { diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java index 12de1415f02..da911be2d8e 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java @@ -86,6 +86,7 @@ import static org.assertj.guava.api.Assertions.entry; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.sonar.api.rule.Severity.BLOCKER; import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.RESOURCES_SECTION_KEY; import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection; @@ -463,6 +464,8 @@ public class SearchActionTest { @Test public void should_return_specified_fields() { + when(macroInterpreter.interpret(anyString())).thenAnswer(invocation -> invocation.getArgument(0)); + RuleDescriptionSectionDto section1context1 = createRuleDescriptionSectionWithContext(RESOURCES_SECTION_KEY, "<div>I want to fix with Spring</div>", "ctx1"); RuleDescriptionSectionDto section1context2 = createRuleDescriptionSectionWithContext(RESOURCES_SECTION_KEY, "<div>Another context</div>", "ctx2"); RuleDto rule = newRuleWithoutDescriptionSection() diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java index 0b0dd9fc73f..e8ea3918686 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java @@ -54,6 +54,7 @@ import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.sonar.api.server.rule.RuleDescriptionSection.RuleDescriptionSectionKeys.ASSESS_THE_PROBLEM_SECTION_KEY; @@ -313,7 +314,7 @@ public class ShowActionTest { assertThat(result.getRule().getHtmlDesc()).isEqualTo(INTERPRETED); assertThat(result.getRule().getTemplateKey()).isEqualTo(templateRule.getKey().toString()); - verify(macroInterpreter).interpret("<div>line1<br/>line2</div>"); + verify(macroInterpreter, times(2)).interpret("<div>line1<br/>line2</div>"); } @Test @@ -395,6 +396,45 @@ public class ShowActionTest { } @Test + public void show_rule_desc_sections_and_html_desc_with_macro() { + RuleDescriptionSectionDto section = createRuleDescriptionSection(DEFAULT_KEY, "<div>Testing macro: {rule:java:S001}</div>"); + RuleDto rule = createRuleWithDescriptionSections(section); + rule.setType(RuleType.SECURITY_HOTSPOT); + rule.setNoteUserUuid(userDto.getUuid()); + db.rules().insert(rule); + + ShowResponse result = ws.newRequest() + .setParam(PARAM_KEY, rule.getKey().toString()) + .executeProtobuf(ShowResponse.class); + Rule resultRule = result.getRule(); + + assertThat(resultRule.getHtmlDesc()).isEqualTo(INTERPRETED); + assertThat(resultRule.getDescriptionSections().getDescriptionSectionsList()) + .extracting(Rule.DescriptionSection::getKey, Rule.DescriptionSection::getContent) + .containsExactly(tuple(DEFAULT_KEY, INTERPRETED)); + } + + @Test + public void show_rule_desc_sections_and_markdown_desc_with_macro() { + RuleDescriptionSectionDto section = createRuleDescriptionSection(DEFAULT_KEY, "Testing macro: {rule:java:S001}"); + RuleDto rule = createRuleWithDescriptionSections(section); + rule.setDescriptionFormat(MARKDOWN); + rule.setType(RuleType.SECURITY_HOTSPOT); + rule.setNoteUserUuid(userDto.getUuid()); + db.rules().insert(rule); + + ShowResponse result = ws.newRequest() + .setParam(PARAM_KEY, rule.getKey().toString()) + .executeProtobuf(ShowResponse.class); + Rule resultRule = result.getRule(); + + assertThat(resultRule.getHtmlDesc()).isEqualTo(INTERPRETED); + assertThat(resultRule.getDescriptionSections().getDescriptionSectionsList()) + .extracting(Rule.DescriptionSection::getKey, Rule.DescriptionSection::getContent) + .containsExactly(tuple(DEFAULT_KEY, INTERPRETED)); + } + + @Test public void show_if_advanced_sections_and_default_filters_out_default() { when(macroInterpreter.interpret(anyString())).thenAnswer(invocation -> invocation.getArgument(0)); @@ -424,7 +464,7 @@ public class ShowActionTest { public void show_rule_markdown_description() { when(macroInterpreter.interpret(anyString())).thenAnswer(invocation -> invocation.getArgument(0)); - var section = createRuleDescriptionSection("default", "*toto is toto*"); + var section = createRuleDescriptionSection(DEFAULT_KEY, "*toto is toto*"); RuleDto rule = createRuleWithDescriptionSections(section); rule.setDescriptionFormat(MARKDOWN); |