TemplateSection.java

1
package com.renomad.minum.templating;
2
3
import java.util.List;
4
import java.util.Map;
5
6
import static com.renomad.minum.utils.Invariants.mustBeTrue;
7
import static com.renomad.minum.utils.SerializationUtils.tokenizer;
8
9
/**
10
 * Represents one item in the list that will eventually be cooked
11
 * up into a fully-rendered string.  This record is the magic
12
 * ingredient to an easy templating system. If it has a key,
13
 * then this object will be getting replaced during final string rendering.  If it has a substring,
14
 * then the substring gets concatenated unchanged when the final string
15
 * is rendered.
16
 */
17
class TemplateSection {
18
19
    final String key;
20
    private final String subString;
21
    private final int indent;
22
    private RenderingResult result;
23
24
    /**
25
     * @param indent the column number, measured from the left, of the first character of this template key.  This is used
26
     *               to indent the subsequent lines of text when there are newlines in the replacement
27
     *               text. For example, if the indent is 5, and the value is "a", then it should indent like this:
28
     *               <br>
29
     *               <pre>{@code
30
     *               12345
31
     *                   a
32
     *               }</pre>
33
     * @param key the name of the key, e.g. "name", or "color"
34
     * @param subString the template content around the keys.  For example, in the text
35
     *                  of "my favorite color is {{ color }} and I like it",
36
     *                  it would generate three template sections - "my favorite color is" would be
37
     *                  the first subString, then a key of "color", then a third subString of "and I like it"
38
     */
39
    public TemplateSection(String key, String subString, int indent) {
40
        this.key = key;
41
        this.subString = subString;
42
        this.indent = indent;
43
    }
44
45
    /**
46
     * It would be absurd to send a million lines to a browser, much
47
     * less ten million.  This is here to set an upper limit on
48
     * the tokenizer loop, to prevent certain attacks.
49
     */
50
    static final int MAXIMUM_LINES_ALLOWED = 10_000_000;
51
52
    public RenderingResult render(Map<String, String> myMap) {
53
        mustBeTrue(subString != null || key != null, "Either the key or substring must exist");
54 1 1. render : negated conditional → KILLED
        if (subString != null) {
55 1 1. render : negated conditional → KILLED
            if (result == null) {
56
                mustBeTrue(key == null, "If this object has a substring, then it must not have a key");
57
                result = new RenderingResult(subString, null);
58
            }
59 1 1. render : replaced return value with null for com/renomad/minum/templating/TemplateSection::render → KILLED
            return result;
60
        } else {
61
            String value = myMap.get(key);
62 1 1. render : negated conditional → KILLED
            if (value == null) throw new TemplateRenderException("Missing a value for key {"+key+"}");
63
            List<String> lines = tokenizer(value, '\n', MAXIMUM_LINES_ALLOWED);
64
65
            // if, after splitting on newlines, we have more than one line, we'll indent the remaining
66
            // lines so that they end up at the same column as the first line.
67
            var stringBuilder = new StringBuilder(lines.getFirst());
68 2 1. render : changed conditional boundary → KILLED
2. render : negated conditional → KILLED
            for (int i = 1; i < lines.size(); i++) {
69 1 1. render : negated conditional → KILLED
                if (lines.get(i).isEmpty()) {
70
                    stringBuilder.append('\n');
71
                } else {
72 1 1. render : Replaced integer subtraction with addition → KILLED
                    stringBuilder.append('\n').append(" ".repeat(indent - 1)).append(lines.get(i));
73
                }
74
            }
75 1 1. render : replaced return value with null for com/renomad/minum/templating/TemplateSection::render → KILLED
            return new RenderingResult(stringBuilder.toString(), key);
76
        }
77
    }
78
79
}

Mutations

54

1.1
Location : render
Killed by : com.renomad.minum.templating.TemplateSectionTests.test_HavingKeyAndSubstring(com.renomad.minum.templating.TemplateSectionTests)
negated conditional → KILLED

55

1.1
Location : render
Killed by : com.renomad.minum.templating.TemplateSectionTests.test_HavingKeyAndSubstring(com.renomad.minum.templating.TemplateSectionTests)
negated conditional → KILLED

59

1.1
Location : render
Killed by : com.renomad.minum.templating.TemplatingTests
replaced return value with null for com/renomad/minum/templating/TemplateSection::render → KILLED

62

1.1
Location : render
Killed by : com.renomad.minum.templating.TemplateSectionTests.test_indenting_edgeCase_NoIndent(com.renomad.minum.templating.TemplateSectionTests)
negated conditional → KILLED

68

1.1
Location : render
Killed by : com.renomad.minum.templating.TemplateSectionTests.test_indenting_edgeCase_NoIndent(com.renomad.minum.templating.TemplateSectionTests)
changed conditional boundary → KILLED

2.2
Location : render
Killed by : com.renomad.minum.templating.TemplateSectionTests.test_indenting_edgeCase_NoIndent(com.renomad.minum.templating.TemplateSectionTests)
negated conditional → KILLED

69

1.1
Location : render
Killed by : com.renomad.minum.templating.TemplateSectionTests.test_indenting_edgeCase_WithIndent(com.renomad.minum.templating.TemplateSectionTests)
negated conditional → KILLED

72

1.1
Location : render
Killed by : com.renomad.minum.templating.TemplateSectionTests.test_indenting_edgeCase_WithIndent(com.renomad.minum.templating.TemplateSectionTests)
Replaced integer subtraction with addition → KILLED

75

1.1
Location : render
Killed by : com.renomad.minum.templating.TemplateSectionTests.test_indenting_edgeCase_NoIndent(com.renomad.minum.templating.TemplateSectionTests)
replaced return value with null for com/renomad/minum/templating/TemplateSection::render → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0