MarkdownService.java

1
package edu.ucsb.cs.scaffold.services;
2
3
import java.util.Set;
4
import org.commonmark.node.AbstractVisitor;
5
import org.commonmark.node.HtmlBlock;
6
import org.commonmark.node.HtmlInline;
7
import org.commonmark.node.Image;
8
import org.commonmark.node.Link;
9
import org.commonmark.node.Node;
10
import org.commonmark.node.Paragraph;
11
import org.commonmark.node.Text;
12
import org.commonmark.parser.Parser;
13
import org.commonmark.renderer.html.HtmlRenderer;
14
import org.commonmark.renderer.markdown.MarkdownRenderer;
15
import org.commonmark.renderer.text.TextContentRenderer;
16
import org.owasp.html.HtmlPolicyBuilder;
17
import org.owasp.html.PolicyFactory;
18
import org.springframework.stereotype.Service;
19
20
/**
21
 * Cleans user-supplied Markdown before it is stored. Markdown itself has no invalid syntax (every
22
 * string is a valid CommonMark document), so "linting" takes the form of reformatting to canonical
23
 * CommonMark. The security-relevant part is sanitizing raw HTML embedded in the Markdown: only the
24
 * HTML nodes of the parsed document are run through the OWASP sanitizer, so code samples such as
25
 * <code>if a &lt; b:</code> in text or code blocks are left untouched.
26
 */
27
@Service
28
public class MarkdownService {
29
30
  private static final Set<String> ALLOWED_LINK_SCHEMES = Set.of("http", "https", "mailto");
31
32
  private static final PolicyFactory HTML_POLICY =
33
      new HtmlPolicyBuilder()
34
          .allowElements(
35
              "p",
36
              "b",
37
              "i",
38
              "em",
39
              "strong",
40
              "a",
41
              "h1",
42
              "h2",
43
              "h3",
44
              "h4",
45
              "h5",
46
              "h6",
47
              "ul",
48
              "ol",
49
              "li",
50
              "code",
51
              "pre",
52
              "blockquote",
53
              "hr",
54
              "br",
55
              "table",
56
              "thead",
57
              "tbody",
58
              "tr",
59
              "th",
60
              "td",
61
              "span",
62
              "div",
63
              "img")
64
          .allowAttributes("href")
65
          .onElements("a")
66
          .allowAttributes("class")
67
          .onElements("code", "span", "div")
68
          .allowAttributes("src", "alt")
69
          .onElements("img")
70
          .allowUrlProtocols("http", "https", "mailto")
71
          .requireRelNofollowOnLinks()
72
          .toFactory();
73
74
  private final Parser parser = Parser.builder().build();
75
  private final MarkdownRenderer markdownRenderer = MarkdownRenderer.builder().build();
76
  private final TextContentRenderer textContentRenderer = TextContentRenderer.builder().build();
77
  private final HtmlRenderer htmlRenderer = HtmlRenderer.builder().build();
78
79
  /**
80
   * Sanitizes raw HTML embedded in the Markdown (dropping anything the OWASP policy rejects,
81
   * including scripts and javascript: URLs), removes unsafe link/image destinations, and reformats
82
   * the result to canonical CommonMark.
83
   *
84
   * @param markdown the raw Markdown, may be null
85
   * @return the cleaned Markdown, or null if the input was null
86
   */
87
  public String clean(String markdown) {
88 1 1. clean : negated conditional → KILLED
    if (markdown == null) {
89 1 1. clean : replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::clean → KILLED
      return null;
90
    }
91
    Node document = parser.parse(markdown);
92 1 1. clean : removed call to org/commonmark/node/Node::accept → KILLED
    document.accept(
93
        new AbstractVisitor() {
94
          @Override
95
          public void visit(HtmlBlock htmlBlock) {
96
            String safe = HTML_POLICY.sanitize(htmlBlock.getLiteral());
97 1 1. visit : negated conditional → KILLED
            if (safe.isBlank()) {
98 1 1. visit : removed call to org/commonmark/node/HtmlBlock::unlink → KILLED
              htmlBlock.unlink();
99
            } else {
100 1 1. visit : removed call to org/commonmark/node/HtmlBlock::setLiteral → KILLED
              htmlBlock.setLiteral(safe);
101
            }
102
          }
103
104
          @Override
105
          public void visit(HtmlInline htmlInline) {
106
            String safe = HTML_POLICY.sanitize(htmlInline.getLiteral());
107 1 1. visit : negated conditional → KILLED
            if (safe.isBlank()) {
108 1 1. visit : removed call to org/commonmark/node/HtmlInline::unlink → KILLED
              htmlInline.unlink();
109
            } else {
110 1 1. visit : removed call to org/commonmark/node/HtmlInline::setLiteral → KILLED
              htmlInline.setLiteral(safe);
111
            }
112
          }
113
114
          @Override
115
          public void visit(Link link) {
116 1 1. visit : removed call to org/commonmark/node/Link::setDestination → KILLED
            link.setDestination(safeDestination(link.getDestination()));
117 1 1. visit : removed call to edu/ucsb/cs/scaffold/services/MarkdownService$1::visitChildren → KILLED
            visitChildren(link);
118
          }
119
120
          @Override
121
          public void visit(Image image) {
122 1 1. visit : removed call to org/commonmark/node/Image::setDestination → KILLED
            image.setDestination(safeDestination(image.getDestination()));
123 1 1. visit : removed call to edu/ucsb/cs/scaffold/services/MarkdownService$1::visitChildren → KILLED
            visitChildren(image);
124
          }
125
        });
126 1 1. clean : replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::clean → KILLED
    return markdownRenderer.render(document).strip();
127
  }
128
129
  /**
130
   * Like {@link #clean}, but for short single-line-ish fields such as concept/subconcept labels,
131
   * which have no legitimate use for embedded raw HTML. Rather than sanitizing (and possibly
132
   * dropping) HTML-looking fragments, any raw HTML is turned into literal text, so that CS notation
133
   * such as {@code List<Integer>} or {@code Node<T>} round-trips intact instead of being silently
134
   * stripped by the HTML sanitizer (which can otherwise reduce a label to nothing and make it fail
135
   * the "label may not be empty" check). The result is still safe to render with {@link
136
   * #toInlineHtml}, since that runs its own HTML sanitization pass at display time.
137
   *
138
   * @param markdown the raw Markdown, may be null
139
   * @return the cleaned Markdown, or null if the input was null
140
   */
141
  public String cleanLabel(String markdown) {
142 1 1. cleanLabel : negated conditional → KILLED
    if (markdown == null) {
143 1 1. cleanLabel : replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::cleanLabel → KILLED
      return null;
144
    }
145
    Node document = parser.parse(markdown);
146 1 1. cleanLabel : removed call to org/commonmark/node/Node::accept → KILLED
    document.accept(
147
        new AbstractVisitor() {
148
          @Override
149
          public void visit(HtmlBlock htmlBlock) {
150
            Paragraph replacement = new Paragraph();
151 1 1. visit : removed call to org/commonmark/node/Paragraph::appendChild → KILLED
            replacement.appendChild(new Text(htmlBlock.getLiteral()));
152 1 1. visit : removed call to org/commonmark/node/HtmlBlock::insertAfter → KILLED
            htmlBlock.insertAfter(replacement);
153 1 1. visit : removed call to org/commonmark/node/HtmlBlock::unlink → KILLED
            htmlBlock.unlink();
154
          }
155
156
          @Override
157
          public void visit(HtmlInline htmlInline) {
158 1 1. visit : removed call to org/commonmark/node/HtmlInline::insertAfter → KILLED
            htmlInline.insertAfter(new Text(htmlInline.getLiteral()));
159 1 1. visit : removed call to org/commonmark/node/HtmlInline::unlink → KILLED
            htmlInline.unlink();
160
          }
161
162
          @Override
163
          public void visit(Link link) {
164 1 1. visit : removed call to org/commonmark/node/Link::setDestination → KILLED
            link.setDestination(safeDestination(link.getDestination()));
165 1 1. visit : removed call to edu/ucsb/cs/scaffold/services/MarkdownService$2::visitChildren → KILLED
            visitChildren(link);
166
          }
167
168
          @Override
169
          public void visit(Image image) {
170 1 1. visit : removed call to org/commonmark/node/Image::setDestination → KILLED
            image.setDestination(safeDestination(image.getDestination()));
171 1 1. visit : removed call to edu/ucsb/cs/scaffold/services/MarkdownService$2::visitChildren → KILLED
            visitChildren(image);
172
          }
173
        });
174 1 1. cleanLabel : replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::cleanLabel → KILLED
    return markdownRenderer.render(document).strip();
175
  }
176
177
  /**
178
   * Renders Markdown to HTML for direct display (e.g. via {@code dangerouslySetInnerHTML} on the
179
   * frontend). The rendered HTML is itself run through the OWASP sanitizer before being returned,
180
   * so the result is safe to inject even if the stored Markdown was never cleaned (e.g. seed data
181
   * inserted directly via SQL).
182
   *
183
   * @param markdown the raw Markdown, may be null
184
   * @return sanitized HTML, or null if the input was null
185
   */
186
  public String toHtml(String markdown) {
187 1 1. toHtml : negated conditional → KILLED
    if (markdown == null) {
188 1 1. toHtml : replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::toHtml → KILLED
      return null;
189
    }
190
    String html = htmlRenderer.render(parser.parse(markdown));
191 1 1. toHtml : replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::toHtml → KILLED
    return HTML_POLICY.sanitize(html).strip();
192
  }
193
194
  /**
195
   * Like {@link #toHtml}, but for short, single-line Markdown meant to be displayed inline (e.g. a
196
   * concept label shown inside a {@code <span>}): the block-level {@code <p>} wrapper CommonMark
197
   * would normally add around a single paragraph is stripped, since nesting a block element inside
198
   * an inline container is invalid HTML.
199
   *
200
   * @param markdown the raw Markdown, may be null
201
   * @return sanitized inline HTML, or null if the input was null
202
   */
203
  public String toInlineHtml(String markdown) {
204
    String html = toHtml(markdown);
205
    // == -1 rather than < 0: indexOf with a fromIndex of 3 can only return -1 or >= 3, so the
206
    // two are equivalent, but < 0 leaves an unkillable "boundary" mutant (<= 0) for pitest.
207 1 1. toInlineHtml : negated conditional → KILLED
    if (html != null
208 1 1. toInlineHtml : negated conditional → KILLED
        && html.startsWith("<p>")
209 1 1. toInlineHtml : negated conditional → KILLED
        && html.endsWith("</p>")
210 1 1. toInlineHtml : negated conditional → KILLED
        && html.indexOf("<p>", "<p>".length()) == -1) {
211 2 1. toInlineHtml : replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::toInlineHtml → KILLED
2. toInlineHtml : Replaced integer subtraction with addition → KILLED
      return html.substring("<p>".length(), html.length() - "</p>".length());
212
    }
213 1 1. toInlineHtml : replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::toInlineHtml → KILLED
    return html;
214
  }
215
216
  /**
217
   * Returns the length of the plain text this Markdown renders to, with runs of whitespace
218
   * collapsed to a single space. Used to enforce limits on the <i>rendered</i> length of a field
219
   * independent of how verbose the Markdown markup is.
220
   */
221
  public int renderedLength(String markdown) {
222 1 1. renderedLength : negated conditional → KILLED
    if (markdown == null) {
223
      return 0;
224
    }
225
    String text = textContentRenderer.render(parser.parse(markdown));
226 1 1. renderedLength : replaced int return with 0 for edu/ucsb/cs/scaffold/services/MarkdownService::renderedLength → KILLED
    return text.strip().replaceAll("\\s+", " ").length();
227
  }
228
229
  /** Allows relative destinations and http/https/mailto; anything else is dropped. */
230
  static String safeDestination(String destination) {
231
    int colon = destination.indexOf(':');
232 2 1. safeDestination : changed conditional boundary → KILLED
2. safeDestination : negated conditional → KILLED
    if (colon < 0) {
233 1 1. safeDestination : replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::safeDestination → KILLED
      return destination;
234
    }
235
    String scheme = destination.substring(0, colon).toLowerCase();
236 1 1. safeDestination : negated conditional → KILLED
    return ALLOWED_LINK_SCHEMES.contains(scheme) ? destination : "";
237
  }
238
}

Mutations

88

1.1
Location : clean
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_returns_null_for_null_input()]
negated conditional → KILLED

89

1.1
Location : clean
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_returns_null_for_null_input()]
replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::clean → KILLED

92

1.1
Location : clean
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_keeps_allowed_inline_html_tags()]
removed call to org/commonmark/node/Node::accept → KILLED

97

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_keeps_an_allowed_html_block_with_its_class_attribute()]
negated conditional → KILLED

98

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_removes_script_blocks_entirely()]
removed call to org/commonmark/node/HtmlBlock::unlink → KILLED

100

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_strips_a_disallowed_attribute_from_an_html_block_that_stays_non_blank()]
removed call to org/commonmark/node/HtmlBlock::setLiteral → KILLED

107

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_keeps_allowed_inline_html_tags()]
negated conditional → KILLED

108

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_keeps_allowed_inline_html_tags()]
removed call to org/commonmark/node/HtmlInline::unlink → KILLED

110

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_keeps_allowed_inline_html_tags()]
removed call to org/commonmark/node/HtmlInline::setLiteral → KILLED

116

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_drops_javascript_link_destinations()]
removed call to org/commonmark/node/Link::setDestination → KILLED

117

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_sanitizes_an_image_nested_inside_a_links_text()]
removed call to edu/ucsb/cs/scaffold/services/MarkdownService$1::visitChildren → KILLED

122

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_drops_javascript_image_destinations()]
removed call to org/commonmark/node/Image::setDestination → KILLED

123

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_sanitizes_a_link_nested_inside_an_images_alt_text()]
removed call to edu/ucsb/cs/scaffold/services/MarkdownService$1::visitChildren → KILLED

126

1.1
Location : clean
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:clean_leaves_code_spans_untouched()]
replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::clean → KILLED

142

1.1
Location : cleanLabel
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_returns_null_for_null_input()]
negated conditional → KILLED

143

1.1
Location : cleanLabel
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_returns_null_for_null_input()]
replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::cleanLabel → KILLED

146

1.1
Location : cleanLabel
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_preserves_a_label_that_is_only_html_like_text()]
removed call to org/commonmark/node/Node::accept → KILLED

151

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_neutralizes_a_script_tag_as_literal_text()]
removed call to org/commonmark/node/Paragraph::appendChild → KILLED

152

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_neutralizes_a_script_tag_as_literal_text()]
removed call to org/commonmark/node/HtmlBlock::insertAfter → KILLED

153

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_neutralizes_a_script_tag_as_literal_text()]
removed call to org/commonmark/node/HtmlBlock::unlink → KILLED

158

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_preserves_html_like_generics_syntax_as_literal_text()]
removed call to org/commonmark/node/HtmlInline::insertAfter → KILLED

159

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_preserves_html_like_generics_syntax_as_literal_text()]
removed call to org/commonmark/node/HtmlInline::unlink → KILLED

164

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_drops_javascript_link_destinations()]
removed call to org/commonmark/node/Link::setDestination → KILLED

165

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_sanitizes_an_image_nested_inside_a_links_text()]
removed call to edu/ucsb/cs/scaffold/services/MarkdownService$2::visitChildren → KILLED

170

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_drops_javascript_image_destinations()]
removed call to org/commonmark/node/Image::setDestination → KILLED

171

1.1
Location : visit
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_sanitizes_a_link_nested_inside_an_images_alt_text()]
removed call to edu/ucsb/cs/scaffold/services/MarkdownService$2::visitChildren → KILLED

174

1.1
Location : cleanLabel
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:cleanLabel_reformats_markdown_to_canonical_commonmark()]
replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::cleanLabel → KILLED

187

1.1
Location : toHtml
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:toHtml_returns_null_for_null_input()]
negated conditional → KILLED

188

1.1
Location : toHtml
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:toHtml_returns_null_for_null_input()]
replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::toHtml → KILLED

191

1.1
Location : toHtml
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:toHtml_renders_a_fenced_code_block_as_pre_code()]
replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::toHtml → KILLED

207

1.1
Location : toInlineHtml
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:toInlineHtml_returns_null_for_null_input()]
negated conditional → KILLED

208

1.1
Location : toInlineHtml
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:toInlineHtml_strips_the_paragraph_wrapper_from_plain_text()]
negated conditional → KILLED

209

1.1
Location : toInlineHtml
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:toInlineHtml_returns_the_full_html_unchanged_when_it_does_not_end_with_a_p_tag()]
negated conditional → KILLED

210

1.1
Location : toInlineHtml
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:toInlineHtml_strips_the_paragraph_wrapper_from_plain_text()]
negated conditional → KILLED

211

1.1
Location : toInlineHtml
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:toInlineHtml_strips_the_paragraph_wrapper_from_plain_text()]
replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::toInlineHtml → KILLED

2.2
Location : toInlineHtml
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:toInlineHtml_strips_the_paragraph_wrapper_from_plain_text()]
Replaced integer subtraction with addition → KILLED

213

1.1
Location : toInlineHtml
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:toInlineHtml_returns_null_for_null_input()]
replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::toInlineHtml → KILLED

222

1.1
Location : renderedLength
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:renderedLength_is_zero_for_null_input()]
negated conditional → KILLED

226

1.1
Location : renderedLength
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:renderedLength_counts_plain_text()]
replaced int return with 0 for edu/ucsb/cs/scaffold/services/MarkdownService::renderedLength → KILLED

232

1.1
Location : safeDestination
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:safeDestination_drops_a_destination_whose_first_character_is_a_colon()]
changed conditional boundary → KILLED

2.2
Location : safeDestination
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:safeDestination_allows_relative_urls_without_a_scheme()]
negated conditional → KILLED

233

1.1
Location : safeDestination
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:safeDestination_allows_relative_urls_without_a_scheme()]
replaced return value with "" for edu/ucsb/cs/scaffold/services/MarkdownService::safeDestination → KILLED

236

1.1
Location : safeDestination
Killed by : edu.ucsb.cs.scaffold.services.MarkdownServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs.scaffold.services.MarkdownServiceTests]/[method:safeDestination_drops_other_schemes()]
negated conditional → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0