TemplateProcessor.java

1
package com.renomad.minum.templating;
2
3
import java.util.*;
4
import java.util.stream.Collectors;
5
6
import static com.renomad.minum.utils.SerializationUtils.tokenizer;
7
8
/**
9
 * This class provides methods for working with templates.
10
 * <p>
11
 * The first step is to write a template.  Here is an example:
12
 * </p>
13
 * <pre>
14
 * Hello, my name is {{name}}
15
 * </pre>
16
 * <p>
17
 * Then, feed that string into the {@link #buildProcessor} method, like
18
 * this:
19
 * </p>
20
 * <pre>
21
 * {@code
22
 *   String input = "Hello, my name is {{name}}"
23
 *   TemplateProcessor helloProcessor = TemplateProcessor.buildProcessor(input);
24
 * }
25
 * </pre>
26
 * <p>
27
 * The returned value ("helloProcessor") can be rendered with different values. For
28
 * example:
29
 * </p>
30
 * <pre>
31
 * {@code
32
 *   Map<String,String> myMap = Map.of("name", "Susanne");
33
 *   String fullyRenderedString = helloProcessor.renderTemplate(myMap);
34
 * }
35
 * </pre>
36
 * <p>
37
 *     The result is:
38
 * </p>
39
 * <pre>
40
 *     {@code Hello, my name is Susanne}
41
 * </pre>
42
 */
43
public final class TemplateProcessor {
44
45
    /**
46
     * template sections by indentation
47
     */
48
    private Map<Integer, List<TemplateSection>> templatesSectionsByIndent;
49
    private List<Map<String, String>> dataList = new ArrayList<>();
50
    private final Set<String> keysFoundInTemplate;
51
    private final Set<String> keysRegisteredForInnerTemplates;
52
    private final String originalText;
53
    /**
54
     * This value is used to calculate a quick estimate of how many
55
     * bytes of memory we will need for the buffer holding our generated string
56
     */
57
    private final static double SIZE_ESTIMATE_MODIFIER = 1.1;
58
    private final int estimatedSize;
59
    private Map<String, TemplateProcessor> innerTemplates;
60
61
    /**
62
     * Instantiate a new object with a list of {@link TemplateSection}.
63
     */
64
    private TemplateProcessor(List<TemplateSection> templateSections, String originalText) {
65
        this.templatesSectionsByIndent = new HashMap<>();
66
        this.templatesSectionsByIndent.put(0, templateSections);
67
        keysFoundInTemplate = new HashSet<>();
68
        keysRegisteredForInnerTemplates = new HashSet<>();
69
        this.originalText = originalText;
70
        this.innerTemplates = new HashMap<>();
71 1 1. <init> : Replaced double multiplication with division → KILLED
        estimatedSize = (int) Math.round(originalText.length() * SIZE_ESTIMATE_MODIFIER);
72
    }
73
74
    /**
75
     * Given a map of key names -> value, render a template.
76
     */
77
    public String renderTemplate(Map<String, String> myMap) {
78 1 1. renderTemplate : removed call to com/renomad/minum/templating/TemplateProcessor::registerData → KILLED
        registerData(List.of(myMap));
79
80 1 1. renderTemplate : replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::renderTemplate → KILLED
        return internalRender(true).toString();
81
    }
82
83
    /**
84
     * Given a list of maps of key names -> value, render a template
85
     * multiple times.
86
     */
87
    public String renderTemplate(List<Map<String, String>> myMap) {
88 1 1. renderTemplate : removed call to com/renomad/minum/templating/TemplateProcessor::registerData → KILLED
        registerData(myMap);
89
90 1 1. renderTemplate : replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::renderTemplate → KILLED
        return internalRender(true).toString();
91
    }
92
93
    /**
94
     * Recursively assembles the template and sub-templates
95
     */
96
    public String renderTemplate() {
97 1 1. renderTemplate : replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::renderTemplate → KILLED
        return internalRender(true).toString();
98
    }
99
100
    /**
101
     * Render the template and any nested sub-templates.  All templates
102
     * must have data registered before running this method.
103
     * @param runWithChecks Default: true.  Check that there is a 1-to-1 correspondence between
104
     *                      the keys provided and keys in the template and sub-templates, throwing
105
     *                      an exception if there are any errors. Also check that the maps
106
     *                      of data are consistent.  This should be set true unless there is a reason
107
     *                      to aim for maximum performance, which is actually not
108
     *                      valuable in most cases, since the bottleneck is the business algorithms, database,
109
     *                      and HTTP processing.
110
     */
111
    public String renderTemplate(boolean runWithChecks) {
112 1 1. renderTemplate : replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::renderTemplate → KILLED
        return internalRender(runWithChecks).toString();
113
    }
114
115
    /**
116
     * Assign data.  Keys must match to template.
117
     */
118
    public void registerData(List<Map<String, String>> dataList) {
119 1 1. registerData : negated conditional → KILLED
        if (dataList == null){
120
            throw new TemplateRenderException("provided data cannot be null");
121 1 1. registerData : negated conditional → KILLED
        } else if (dataList.isEmpty()) {
122
            throw new TemplateRenderException("No data provided in registerData call");
123
        }
124
125
        this.dataList = dataList;
126
    }
127
128
    /**
129
     * Builds a {@link TemplateProcessor} from a string
130
     * containing a proper template.  Templated values
131
     * are surrounded by double-curly-braces, i.e. {{foo}} or {{ foo }}
132
     */
133
    public static TemplateProcessor buildProcessor(String template) {
134 2 1. buildProcessor : negated conditional → KILLED
2. buildProcessor : negated conditional → KILLED
        if (template == null || template.isEmpty()) {
135
            throw new TemplateRenderException("The input to building a template must be a non-empty string");
136
        }
137
        var tp = new TemplateProcessor(new ArrayList<>(), template);
138
        List<TemplateSection> tSections = tp.renderToTemplateSections(template);
139
        Set<String> keysFound = tSections.stream()
140 2 1. lambda$buildProcessor$0 : replaced boolean return with true for com/renomad/minum/templating/TemplateProcessor::lambda$buildProcessor$0 → KILLED
2. lambda$buildProcessor$0 : replaced boolean return with false for com/renomad/minum/templating/TemplateProcessor::lambda$buildProcessor$0 → KILLED
                .filter(x -> x.templateType.equals(TemplateType.DYNAMIC_TEXT))
141 1 1. lambda$buildProcessor$1 : replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::lambda$buildProcessor$1 → KILLED
                .map(x -> x.key)
142
                .collect(Collectors.toSet());
143
        tp.keysFoundInTemplate.addAll(keysFound);
144
        tp.templatesSectionsByIndent.put(0, tSections);
145
146 1 1. buildProcessor : replaced return value with null for com/renomad/minum/templating/TemplateProcessor::buildProcessor → KILLED
        return tp;
147
    }
148
149
    private ArrayList<TemplateSection> renderToTemplateSections(String template) {
150
        // this value holds the entire template after processing, comprised
151
        // of an ordered list of TemplateSections
152
        var tSections = new ArrayList<TemplateSection>();
153
154
        // these values are used for logging and setting proper indentation
155
        int rowNumber = 1;
156
        int columnNumber = 1;
157
        // this value records the indent of the beginning of template keys,
158
        // so we can properly indent the values later.
159
        int startOfKey = 0;
160
161
        StringBuilder builder = new StringBuilder();
162
        // this flag is to help us understand whether we are currently reading the
163
        // name of a template literal.
164
        // e.g. in the case of hello {{ name }}, "name" is the literal.
165
        boolean isInsideTemplateKeyLiteral = false;
166 2 1. renderToTemplateSections : changed conditional boundary → KILLED
2. renderToTemplateSections : negated conditional → KILLED
        for (int i = 0; i < template.length(); i++) {
167
            char charAtCursor = template.charAt(i);
168
169 6 1. renderToTemplateSections : negated conditional → KILLED
2. renderToTemplateSections : changed conditional boundary → KILLED
3. renderToTemplateSections : Replaced integer addition with subtraction → KILLED
4. renderToTemplateSections : negated conditional → KILLED
5. renderToTemplateSections : negated conditional → KILLED
6. renderToTemplateSections : Replaced integer addition with subtraction → KILLED
            if (charAtCursor == '{' && (i + 1) < template.length() && template.charAt(i + 1) == '{') {
170
                isInsideTemplateKeyLiteral = true;
171 1 1. renderToTemplateSections : Replaced integer subtraction with addition → KILLED
                startOfKey = columnNumber - 1;
172 1 1. renderToTemplateSections : Changed increment from 1 to -1 → TIMED_OUT
                i += 1;
173
                builder = processSectionInside(builder, tSections);
174 7 1. renderToTemplateSections : Replaced integer addition with subtraction → KILLED
2. renderToTemplateSections : negated conditional → KILLED
3. renderToTemplateSections : negated conditional → KILLED
4. renderToTemplateSections : changed conditional boundary → KILLED
5. renderToTemplateSections : negated conditional → KILLED
6. renderToTemplateSections : negated conditional → KILLED
7. renderToTemplateSections : Replaced integer addition with subtraction → KILLED
            } else if (isInsideTemplateKeyLiteral && charAtCursor == '}' && (i + 1) < template.length() && template.charAt(i + 1) == '}') {
175
                isInsideTemplateKeyLiteral = false;
176 1 1. renderToTemplateSections : Changed increment from 1 to -1 → KILLED
                i += 1;
177
                builder = processSectionOutside(builder, tSections, startOfKey);
178
                startOfKey = 0;
179
            } else {
180
                builder.append(charAtCursor);
181
182
                /*
183
                 if we're at the end of the template, it's our last chance to
184
                 add a substring (we can't be adding to a key, since if we're
185
                 at the end, and it's not a closing brace, it's a malformed
186
                 template.
187
                 */
188 2 1. renderToTemplateSections : negated conditional → KILLED
2. renderToTemplateSections : Replaced integer subtraction with addition → KILLED
                if (i == template.length() - 1) {
189 1 1. renderToTemplateSections : negated conditional → KILLED
                    if (isInsideTemplateKeyLiteral) {
190
                        // if we're exiting this string while inside a template literal, then
191
                        // we're reading a corrupted input, and we should make that clear
192
                        // to our caller.
193 2 1. renderToTemplateSections : changed conditional boundary → KILLED
2. renderToTemplateSections : negated conditional → KILLED
                        String templateSample = template.length() > 10 ? template.substring(0, 10) + "..." : template;
194
                        throw new TemplateParseException(
195
                                "parsing failed for string starting with \"" + templateSample + "\" at line " + rowNumber + " and column " + columnNumber);
196
                    }
197
                    tSections.add(new TemplateSection(null, builder.toString(), null, TemplateType.STATIC_TEXT, 0));
198
                }
199
            }
200
201 1 1. renderToTemplateSections : negated conditional → KILLED
            if (charAtCursor == '\n') {
202 1 1. renderToTemplateSections : Changed increment from 1 to -1 → KILLED
                rowNumber += 1;
203
                columnNumber = 1;
204
            } else {
205 1 1. renderToTemplateSections : Changed increment from 1 to -1 → KILLED
                columnNumber += 1;
206
            }
207
208
        }
209 1 1. renderToTemplateSections : replaced return value with null for com/renomad/minum/templating/TemplateProcessor::renderToTemplateSections → KILLED
        return tSections;
210
    }
211
212
    private static StringBuilder processSectionInside(StringBuilder builder, List<TemplateSection> tSections) {
213 1 1. processSectionInside : negated conditional → KILLED
        if (!builder.isEmpty()) {
214
            tSections.add(new TemplateSection(null, builder.toString(), null, TemplateType.STATIC_TEXT, 0));
215
            builder = new StringBuilder();
216
        }
217 1 1. processSectionInside : replaced return value with null for com/renomad/minum/templating/TemplateProcessor::processSectionInside → KILLED
        return builder;
218
    }
219
220
    private static StringBuilder processSectionOutside(StringBuilder builder,
221
                                               List<TemplateSection> tSections,
222
                                               int indent) {
223
        String key = builder.toString().trim();
224
        tSections.add(new TemplateSection(key, "", null, TemplateType.DYNAMIC_TEXT, indent));
225
        builder = new StringBuilder();
226 1 1. processSectionOutside : replaced return value with null for com/renomad/minum/templating/TemplateProcessor::processSectionOutside → KILLED
        return builder;
227
    }
228
229
    /**
230
     * Binds an inner template to a key of this template.
231
     */
232
    public TemplateProcessor registerInnerTemplate(String key, TemplateProcessor innerTemplate) {
233 2 1. registerInnerTemplate : negated conditional → KILLED
2. registerInnerTemplate : negated conditional → KILLED
        if (key == null || key.isBlank()) {
234
            throw new TemplateRenderException("The key must be a valid non-blank string");
235
        }
236 1 1. registerInnerTemplate : negated conditional → KILLED
        if (innerTemplate == null) {
237
            throw new TemplateRenderException("The template must not be null");
238
        }
239 1 1. registerInnerTemplate : negated conditional → KILLED
        if (this.equals(innerTemplate)) {
240
            throw new TemplateRenderException("Disallowed to register a template to itself as an inner template");
241
        }
242 1 1. registerInnerTemplate : negated conditional → KILLED
        if (keysRegisteredForInnerTemplates.contains(key)) {
243
            throw new TemplateRenderException("key is already registered for use in another template: " + key);
244
        }
245
246
        // get the indent we should apply to each line after the first
247
        // by seeing what indent exists in the template sections and
248
        // creating a separate indented version for each one
249
        Set<Integer> necessaryIndentations = this.templatesSectionsByIndent.get(0).stream()
250 2 1. lambda$registerInnerTemplate$2 : replaced boolean return with true for com/renomad/minum/templating/TemplateProcessor::lambda$registerInnerTemplate$2 → SURVIVED
2. lambda$registerInnerTemplate$2 : replaced boolean return with false for com/renomad/minum/templating/TemplateProcessor::lambda$registerInnerTemplate$2 → KILLED
                .filter(x -> key.equals(x.key))
251 1 1. lambda$registerInnerTemplate$3 : replaced Integer return value with 0 for com/renomad/minum/templating/TemplateProcessor::lambda$registerInnerTemplate$3 → KILLED
                .map(x -> x.indent).collect(Collectors.toSet());
252
253
        // make sure we have one for zero as well.
254
        necessaryIndentations.add(0);
255
256
257
        var copyOfInnerTemplate = new TemplateProcessor(innerTemplate.templatesSectionsByIndent.get(0), innerTemplate.getOriginalText());
258
        copyOfInnerTemplate.keysFoundInTemplate.addAll(innerTemplate.keysFoundInTemplate);
259
        copyOfInnerTemplate.keysRegisteredForInnerTemplates.addAll(innerTemplate.keysRegisteredForInnerTemplates);
260
        copyOfInnerTemplate.innerTemplates = new HashMap<>(innerTemplate.innerTemplates);
261
        this.innerTemplates.put(key, copyOfInnerTemplate);
262
263 1 1. registerInnerTemplate : removed call to java/util/Map::clear → SURVIVED
        copyOfInnerTemplate.templatesSectionsByIndent.clear();
264
265
        // a non-configurable ceiling limit to avoid runaway loops
266
        int MAXIMUM_LINES_ALLOWED = 10_000_000;
267
        String originalText = copyOfInnerTemplate.getOriginalText();
268
        List<String> lines = tokenizer(originalText, '\n', MAXIMUM_LINES_ALLOWED);
269
270
        // if, after splitting on newlines, we have more than one line, we'll indent the remaining
271
        // lines so that they end up at the same column as the first line.
272
        for (int indentation : necessaryIndentations) {
273
            var indentedInnerTemplateText = new StringBuilder(lines.getFirst());
274 2 1. registerInnerTemplate : negated conditional → KILLED
2. registerInnerTemplate : changed conditional boundary → KILLED
            for (int i = 1; i < lines.size(); i++) {
275 1 1. registerInnerTemplate : negated conditional → KILLED
                if (lines.get(i).isEmpty()) {
276
                    indentedInnerTemplateText.append('\n');
277
                } else {
278
                    indentedInnerTemplateText.append('\n').append(" ".repeat(indentation)).append(lines.get(i));
279
                }
280
            }
281
            List<TemplateSection> tSections = renderToTemplateSections(indentedInnerTemplateText.toString());
282
            copyOfInnerTemplate.templatesSectionsByIndent.put(indentation, tSections);
283
284
            // now, loop through all the template sections, replacing them appropriately with
285
            // new data labeled as INNER_TEMPLATE.
286
            Map<Integer, List<TemplateSection>> revisedTemplateSectionsByIndent = new HashMap<>();
287
            for (var templateSectionsByIndent : templatesSectionsByIndent.entrySet()) {
288
                List<TemplateSection> revisedList = new ArrayList<>();
289
                for (TemplateSection templateSection : templateSectionsByIndent.getValue()) {
290 1 1. registerInnerTemplate : negated conditional → KILLED
                    if (key.equals(templateSection.key)) {
291
                        revisedList.add(new TemplateSection(templateSection.key,
292
                                templateSection.staticData,
293
                                copyOfInnerTemplate,
294
                                TemplateType.INNER_TEMPLATE,
295
                                templateSection.indent));
296
                    } else {
297
                        revisedList.add(templateSection);
298
                    }
299
                }
300
                revisedTemplateSectionsByIndent.put(templateSectionsByIndent.getKey(), revisedList);
301
            }
302
            templatesSectionsByIndent = revisedTemplateSectionsByIndent;
303
304
            this.keysRegisteredForInnerTemplates.add(key);
305
        }
306
307 1 1. registerInnerTemplate : replaced return value with null for com/renomad/minum/templating/TemplateProcessor::registerInnerTemplate → KILLED
        return copyOfInnerTemplate;
308
    }
309
310
    /**
311
     * Returns the original unchanged template string
312
     */
313
    public String getOriginalText() {
314 1 1. getOriginalText : replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::getOriginalText → KILLED
        return originalText;
315
    }
316
317
    /**
318
     * now, loop through the lists of data we were given, with the
319
     * internal template sections in hand
320
     */
321
    private StringBuilder internalRender(boolean runWithChecks) {
322 1 1. internalRender : negated conditional → KILLED
        if (runWithChecks) {
323 1 1. internalRender : removed call to com/renomad/minum/templating/TemplateProcessor::correctnessCheck → KILLED
            correctnessCheck();
324
        }
325
        int capacity = calculateEstimatedSize();
326
        StringBuilder parts = new StringBuilder(capacity);
327 1 1. internalRender : replaced return value with null for com/renomad/minum/templating/TemplateProcessor::internalRender → KILLED
        return internalRender(0, parts);
328
    }
329
330
    /**
331
     * This examines the currently registered data lists and template keys
332
     * and confirms they are aligned.  It will throw an exception if they
333
     * are not perfectly correlated.
334
     * <br>
335
     *
336
     */
337
    private void correctnessCheck() {
338
        HashSet<String> copyOfKeysInTemplate = new HashSet<>(keysFoundInTemplate);
339
        copyOfKeysInTemplate.removeAll(this.innerTemplates.keySet());
340
341 1 1. correctnessCheck : negated conditional → KILLED
        if (this.dataList.isEmpty()) {
342 1 1. correctnessCheck : negated conditional → KILLED
            if (!copyOfKeysInTemplate.isEmpty()) {
343
                // at this point we know there is no data provided but the template
344
                // requires data, so throw an exception.
345
346
                throw new TemplateRenderException("No data was provided for these keys: " + copyOfKeysInTemplate);
347
            }
348
        } else {
349
350
            // check for inconsistencies between maps in the data list
351
            Set<String> keysInFirstMap = this.dataList.getFirst().keySet();
352
            for (Map<String, String> data : this.dataList) {
353 1 1. correctnessCheck : negated conditional → KILLED
                if (!data.keySet().equals(keysInFirstMap)) {
354
                    Set<String> result = differenceBetweenSets(data.keySet(), keysInFirstMap);
355
                    throw new TemplateRenderException("In registered data, the maps were inconsistent on these keys: " + result);
356
                }
357
            }
358
359
            // ensure consistency between the registered data and the template keys
360
            HashSet<String> copyOfTemplateKeys = new HashSet<>(copyOfKeysInTemplate);
361
            copyOfTemplateKeys.removeAll(keysInFirstMap);
362 1 1. correctnessCheck : negated conditional → KILLED
            if (!copyOfTemplateKeys.isEmpty()) {
363
                throw new TemplateRenderException("These keys in the template were not provided data: " + copyOfTemplateKeys);
364
            }
365
366
            HashSet<String> copyOfDataKeys = new HashSet<>(keysInFirstMap);
367
            copyOfDataKeys.removeAll(copyOfKeysInTemplate);
368 1 1. correctnessCheck : negated conditional → KILLED
            if (!copyOfDataKeys.isEmpty()) {
369
                throw new TemplateRenderException("These keys in the data did not match anything in the template: " + copyOfDataKeys);
370
            }
371
        }
372
373
        for (TemplateProcessor tp : this.innerTemplates.values()) {
374 1 1. correctnessCheck : removed call to com/renomad/minum/templating/TemplateProcessor::correctnessCheck → KILLED
            tp.correctnessCheck();
375
        }
376
377
    }
378
379
    private static Set<String> differenceBetweenSets(Set<String> set1, Set<String> set2) {
380
        Set<String> union = new HashSet<>(set2);
381
        union.addAll(set1);
382
        Set<String> intersection = new HashSet<>(set2);
383
        intersection.retainAll(set1);
384
385
        Set<String> result = new HashSet<>(union);
386
        result.removeAll(intersection);
387 1 1. differenceBetweenSets : replaced return value with Collections.emptySet for com/renomad/minum/templating/TemplateProcessor::differenceBetweenSets → KILLED
        return result;
388
    }
389
390
    /**
391
     * build up a calculated size estimate for this and all
392
     * nested templates.
393
     */
394
    private int calculateEstimatedSize() {
395
        // the size of the datalist specifies how many times we will render ourselves.
396 1 1. calculateEstimatedSize : negated conditional → KILLED
        int sizeMultiplier = this.dataList.isEmpty() ? 1 : this.dataList.size();
397 1 1. calculateEstimatedSize : Replaced integer multiplication with division → KILLED
        int fullCalculatedSize = sizeMultiplier * estimatedSize;
398
        for (TemplateProcessor innerProcessor : this.innerTemplates.values()) {
399 1 1. calculateEstimatedSize : Replaced integer addition with subtraction → KILLED
            fullCalculatedSize += innerProcessor.calculateEstimatedSize();
400
        }
401 1 1. calculateEstimatedSize : replaced int return with 0 for com/renomad/minum/templating/TemplateProcessor::calculateEstimatedSize → KILLED
        return fullCalculatedSize;
402
    }
403
404
    private StringBuilder internalRender(int indent, StringBuilder parts) {
405
        Map<String, String> myDataMap = Map.of();
406
        List<TemplateSection> templateSections = templatesSectionsByIndent.get(indent);
407
        int templateSectionsSize = templateSections.size();
408
        int dataListIndex = 0;
409 1 1. internalRender : negated conditional → KILLED
        if (!dataList.isEmpty()) {
410
            myDataMap = dataList.get(dataListIndex);
411
        }
412
413
        // build ourself out for each map of data given
414
        while (true) {
415 2 1. internalRender : changed conditional boundary → KILLED
2. internalRender : negated conditional → KILLED
            for (int i = 0; i < templateSectionsSize; i++) {
416
                TemplateSection templateSection = templateSections.get(i);
417
                switch (templateSection.templateType) {
418
                    case STATIC_TEXT -> parts.append(templateSection.staticData);
419
                    case DYNAMIC_TEXT -> parts.append(myDataMap.get(templateSection.key));
420
                    default -> templateSection.templateProcessor.internalRender(templateSection.indent, parts);
421
                }
422
423
            }
424 1 1. internalRender : Changed increment from 1 to -1 → KILLED
            dataListIndex += 1;
425 3 1. internalRender : changed conditional boundary → KILLED
2. internalRender : negated conditional → KILLED
3. internalRender : negated conditional → KILLED
            if (!dataList.isEmpty() && dataListIndex < dataList.size()) {
426
                myDataMap = dataList.get(dataListIndex);
427
                parts.append("\n").repeat(" ", indent);
428
            } else {
429 1 1. internalRender : replaced return value with null for com/renomad/minum/templating/TemplateProcessor::internalRender → KILLED
                return parts;
430
            }
431
        }
432
    }
433
434
    /**
435
     * Returns the reference to an inner template, to enable registering
436
     * data and sub-templates.
437
     */
438
    public TemplateProcessor getInnerTemplate(String innerTemplateKey) {
439 1 1. getInnerTemplate : replaced return value with null for com/renomad/minum/templating/TemplateProcessor::getInnerTemplate → KILLED
        return this.innerTemplates.get(innerTemplateKey);
440
    }
441
}
442

Mutations

71

1.1
Location : <init>
Killed by : com.renomad.minum.FunctionalTests
Replaced double multiplication with division → KILLED

78

1.1
Location : renderTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
removed call to com/renomad/minum/templating/TemplateProcessor::registerData → KILLED

80

1.1
Location : renderTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::renderTemplate → KILLED

88

1.1
Location : renderTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
removed call to com/renomad/minum/templating/TemplateProcessor::registerData → KILLED

90

1.1
Location : renderTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::renderTemplate → KILLED

97

1.1
Location : renderTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::renderTemplate → KILLED

112

1.1
Location : renderTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::renderTemplate → KILLED

119

1.1
Location : registerData
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

121

1.1
Location : registerData
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

134

1.1
Location : buildProcessor
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

2.2
Location : buildProcessor
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

140

1.1
Location : lambda$buildProcessor$0
Killed by : com.renomad.minum.templating.TemplatingTests
replaced boolean return with true for com/renomad/minum/templating/TemplateProcessor::lambda$buildProcessor$0 → KILLED

2.2
Location : lambda$buildProcessor$0
Killed by : com.renomad.minum.templating.TemplatingTests
replaced boolean return with false for com/renomad/minum/templating/TemplateProcessor::lambda$buildProcessor$0 → KILLED

141

1.1
Location : lambda$buildProcessor$1
Killed by : com.renomad.minum.templating.TemplatingTests
replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::lambda$buildProcessor$1 → KILLED

146

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

166

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
changed conditional boundary → KILLED

2.2
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

169

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

2.2
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
changed conditional boundary → KILLED

3.3
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
Replaced integer addition with subtraction → KILLED

4.4
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

5.5
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

6.6
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
Replaced integer addition with subtraction → KILLED

171

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
Replaced integer subtraction with addition → KILLED

172

1.1
Location : renderToTemplateSections
Killed by : none
Changed increment from 1 to -1 → TIMED_OUT

174

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
Replaced integer addition with subtraction → KILLED

2.2
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

3.3
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

4.4
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
changed conditional boundary → KILLED

5.5
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

6.6
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

7.7
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
Replaced integer addition with subtraction → KILLED

176

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
Changed increment from 1 to -1 → KILLED

188

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

2.2
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
Replaced integer subtraction with addition → KILLED

189

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

193

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
changed conditional boundary → KILLED

2.2
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

201

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

202

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
Changed increment from 1 to -1 → KILLED

205

1.1
Location : renderToTemplateSections
Killed by : com.renomad.minum.templating.TemplatingTests
Changed increment from 1 to -1 → KILLED

209

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

213

1.1
Location : processSectionInside
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

217

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

226

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

233

1.1
Location : registerInnerTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

2.2
Location : registerInnerTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

236

1.1
Location : registerInnerTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

239

1.1
Location : registerInnerTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

242

1.1
Location : registerInnerTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

250

1.1
Location : lambda$registerInnerTemplate$2
Killed by : none
replaced boolean return with true for com/renomad/minum/templating/TemplateProcessor::lambda$registerInnerTemplate$2 → SURVIVED
Covering tests

2.2
Location : lambda$registerInnerTemplate$2
Killed by : com.renomad.minum.templating.TemplatingTests
replaced boolean return with false for com/renomad/minum/templating/TemplateProcessor::lambda$registerInnerTemplate$2 → KILLED

251

1.1
Location : lambda$registerInnerTemplate$3
Killed by : com.renomad.minum.templating.TemplatingTests
replaced Integer return value with 0 for com/renomad/minum/templating/TemplateProcessor::lambda$registerInnerTemplate$3 → KILLED

263

1.1
Location : registerInnerTemplate
Killed by : none
removed call to java/util/Map::clear → SURVIVED
Covering tests

274

1.1
Location : registerInnerTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

2.2
Location : registerInnerTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
changed conditional boundary → KILLED

275

1.1
Location : registerInnerTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

290

1.1
Location : registerInnerTemplate
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

307

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

314

1.1
Location : getOriginalText
Killed by : com.renomad.minum.templating.TemplatingTests
replaced return value with "" for com/renomad/minum/templating/TemplateProcessor::getOriginalText → KILLED

322

1.1
Location : internalRender
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

323

1.1
Location : internalRender
Killed by : com.renomad.minum.templating.TemplatingTests
removed call to com/renomad/minum/templating/TemplateProcessor::correctnessCheck → KILLED

327

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

341

1.1
Location : correctnessCheck
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

342

1.1
Location : correctnessCheck
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

353

1.1
Location : correctnessCheck
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

362

1.1
Location : correctnessCheck
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

368

1.1
Location : correctnessCheck
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

374

1.1
Location : correctnessCheck
Killed by : com.renomad.minum.templating.TemplatingTests
removed call to com/renomad/minum/templating/TemplateProcessor::correctnessCheck → KILLED

387

1.1
Location : differenceBetweenSets
Killed by : com.renomad.minum.templating.TemplatingTests
replaced return value with Collections.emptySet for com/renomad/minum/templating/TemplateProcessor::differenceBetweenSets → KILLED

396

1.1
Location : calculateEstimatedSize
Killed by : com.renomad.minum.FunctionalTests
negated conditional → KILLED

397

1.1
Location : calculateEstimatedSize
Killed by : com.renomad.minum.FunctionalTests
Replaced integer multiplication with division → KILLED

399

1.1
Location : calculateEstimatedSize
Killed by : com.renomad.minum.templating.TemplatingTests
Replaced integer addition with subtraction → KILLED

401

1.1
Location : calculateEstimatedSize
Killed by : com.renomad.minum.FunctionalTests
replaced int return with 0 for com/renomad/minum/templating/TemplateProcessor::calculateEstimatedSize → KILLED

409

1.1
Location : internalRender
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

415

1.1
Location : internalRender
Killed by : com.renomad.minum.templating.TemplatingTests
changed conditional boundary → KILLED

2.2
Location : internalRender
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

424

1.1
Location : internalRender
Killed by : com.renomad.minum.templating.TemplatingTests
Changed increment from 1 to -1 → KILLED

425

1.1
Location : internalRender
Killed by : com.renomad.minum.templating.TemplatingTests
changed conditional boundary → KILLED

2.2
Location : internalRender
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

3.3
Location : internalRender
Killed by : com.renomad.minum.templating.TemplatingTests
negated conditional → KILLED

429

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

439

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

Active mutators

Tests examined


Report generated by PIT 1.17.0