PlaceholderHooker.java

1
package pro.verron.officestamper.api;
2
3
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
4
import org.docx4j.utils.TraversalUtilVisitor;
5
import org.docx4j.wml.P;
6
import pro.verron.officestamper.utils.wml.WmlUtils;
7
8
import java.util.ArrayList;
9
import java.util.List;
10
import java.util.regex.Pattern;
11
12
import static pro.verron.officestamper.utils.wml.WmlUtils.asString;
13
import static pro.verron.officestamper.utils.wml.WmlUtils.insertSmartTag;
14
15
/// The [PlaceholderHooker] class is a pre-processor that prepares inline placeholders in a `WordprocessingML`
16
/// document. It searches for placeholders that match a given pattern and wraps them with a specified XML element to
17
/// ensure proper processing by the OfficeStamper engine.
18
///
19
/// This pre-processor is typically used to identify and mark inline expressions within paragraphs, making them
20
/// recognizable for subsequent processing steps.
21
public class PlaceholderHooker
22
        implements PreProcessor {
23
24
    private final Pattern pattern;
25
    private final String element;
26
27
28
    /// Constructs a new [PlaceholderHooker] instance with the specified regular expression and XML element
29
    /// name.
30
    ///
31
    /// @param regex the regular expression pattern used to identify inline placeholders in the document. This
32
    ///         pattern should contain at least two capturing groups where the second group represents the actual
33
    ///         placeholder content.
34
    /// @param element the name of the XML element to wrap around identified placeholders. This element will be
35
    ///         used to mark the placeholders for further processing.
36
    public PlaceholderHooker(String regex, String element) {
37
        this(Pattern.compile(regex, Pattern.DOTALL), element);
38
    }
39
40
41
    /// Constructs a new [PlaceholderHooker] instance with the specified pattern and XML element name.
42
    ///
43
    /// @param pattern the compiled regular expression pattern used to identify inline placeholders in the
44
    ///         document. This pattern should contain at least two capturing groups where the second group represents
45
    ///         the actual placeholder content.
46
    /// @param element the name of the XML element to wrap around identified placeholders. This element will be
47
    ///         used to mark the placeholders for further processing.
48
    public PlaceholderHooker(Pattern pattern, String element) {
49
        this.pattern = pattern;
50
        this.element = element;
51
    }
52
53
    @Override
54
    public void process(WordprocessingMLPackage document) {
55
        var visitor = new ParagraphCollector(pattern);
56 1 1. process : removed call to pro/verron/officestamper/utils/wml/WmlUtils::visitDocument → KILLED
        WmlUtils.visitDocument(document, visitor);
57
        for (var paragraph : visitor.paragraphs()) {
58
            var string = asString(paragraph);
59
            var matcher = pattern.matcher(string);
60
            // Iterates matches; replaces placeholder with a smart tag
61 1 1. process : negated conditional → KILLED
            while (matcher.find()) {
62
                var start = matcher.start(1);
63
                var end = matcher.end(1);
64
                var placeholder = matcher.group(2);
65
                var newContent = insertSmartTag(element, paragraph, placeholder, start, end);
66
                var content = paragraph.getContent();
67 1 1. process : removed call to java/util/List::clear → KILLED
                content.clear();
68
                content.addAll(newContent);
69
                string = asString(paragraph);
70
                matcher = pattern.matcher(string);
71
            }
72
        }
73
    }
74
75
    /// A [TraversalUtilVisitor] implementation that collects paragraphs matching a given pattern.
76
    ///
77
    /// This class is used to traverse a document and collect all paragraph elements ([P]) that match a specified
78
    /// regular expression pattern. The collected paragraphs can be retrieved using the [#paragraphs()] method.
79
    public static class ParagraphCollector
80
            extends TraversalUtilVisitor<P> {
81
82
        private final Pattern pattern;
83
        private final List<P> results = new ArrayList<>();
84
85
86
        /// Constructs a new [ParagraphCollector] with the specified pattern.
87
        ///
88
        /// @param pattern the regular expression pattern to match against paragraphs
89
        public ParagraphCollector(Pattern pattern) {
90
            this.pattern = pattern;
91
        }
92
93
        @Override
94
        public void apply(P element) {
95
            var matcher = pattern.asPredicate();
96
            var string = asString(element);
97 1 1. apply : negated conditional → KILLED
            if (matcher.test(string)) {
98
                results.add(element);
99
            }
100
        }
101
102
        /// Returns the list of collected paragraphs that matched the pattern.
103
        ///
104
        /// @return an unmodifiable list of paragraphs matching the specified pattern
105
        public List<P> paragraphs() {
106 1 1. paragraphs : replaced return value with Collections.emptyList for pro/verron/officestamper/api/PlaceholderHooker$ParagraphCollector::paragraphs → KILLED
            return results;
107
        }
108
    }
109
}

Mutations

56

1.1
Location : process
Killed by : pro.verron.officestamper.test.SpelInjectionTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.SpelInjectionTest]/[test-template:spelInjectionTest(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#2]
removed call to pro/verron/officestamper/utils/wml/WmlUtils::visitDocument → KILLED

61

1.1
Location : process
Killed by : pro.verron.officestamper.test.SpelInjectionTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.SpelInjectionTest]/[test-template:spelInjectionTest(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#2]
negated conditional → KILLED

67

1.1
Location : process
Killed by : pro.verron.officestamper.test.DefaultTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.DefaultTests]/[test-template:features(pro.verron.officestamper.api.OfficeStamperConfiguration, java.lang.Object, org.docx4j.openpackaging.packages.WordprocessingMLPackage, java.lang.String)]/[test-template-invocation:#35]
removed call to java/util/List::clear → KILLED

97

1.1
Location : apply
Killed by : pro.verron.officestamper.test.SpelInjectionTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.SpelInjectionTest]/[test-template:spelInjectionTest(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#2]
negated conditional → KILLED

106

1.1
Location : paragraphs
Killed by : pro.verron.officestamper.test.SpelInjectionTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.SpelInjectionTest]/[test-template:spelInjectionTest(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#2]
replaced return value with Collections.emptyList for pro/verron/officestamper/api/PlaceholderHooker$ParagraphCollector::paragraphs → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.0