@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} |
@@ -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) { |
@@ -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() |
@@ -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 | |||
@@ -394,6 +395,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); |