RepeatProcessor.java

1
package pro.verron.officestamper.preset.processors.repeat;
2
3
import org.docx4j.XmlUtils;
4
import org.docx4j.openpackaging.exceptions.Docx4JException;
5
import org.docx4j.wml.ContentAccessor;
6
import org.docx4j.wml.P;
7
import org.docx4j.wml.PPr;
8
import org.docx4j.wml.SectPr;
9
import org.jspecify.annotations.Nullable;
10
import org.jvnet.jaxb2_commons.ppp.Child;
11
import org.slf4j.Logger;
12
import org.slf4j.LoggerFactory;
13
import pro.verron.officestamper.api.*;
14
import pro.verron.officestamper.preset.CommentProcessorFactory.IRepeatProcessor;
15
import pro.verron.officestamper.utils.wml.WmlFactory;
16
import pro.verron.officestamper.utils.wml.WmlUtils;
17
18
import java.util.ArrayList;
19
import java.util.List;
20
import java.util.Objects;
21
import java.util.Optional;
22
import java.util.function.Supplier;
23
24
import static java.util.Optional.ofNullable;
25
import static java.util.stream.Collectors.toCollection;
26
27
public class RepeatProcessor
28
        extends CommentProcessor
29
        implements IRepeatProcessor {
30
    private static final Logger log = LoggerFactory.getLogger(RepeatProcessor.class);
31
32
    /// Constructs a new instance of CommentProcessor to process comments and placeholders within a paragraph.
33
    ///
34
    /// @param context the context containing the paragraph, comment, and placeholder associated with the
35
    ///         processing of this CommentProcessor.
36
    public RepeatProcessor(ProcessorContext context) {
37
        super(context);
38
    }
39
40
    @Override
41
    public void repeat(@Nullable Iterable<Object> items) {
42 1 1. repeat : negated conditional → KILLED
        if (items == null) return;
43
        var comment = context().comment();
44
        var elements = comment.getElements();
45
        var contextHolder = context().contextHolder();
46
        var parent = comment.getParent();
47
        var siblings = parent.getContent();
48
        var firstElement = elements.getFirst();
49
        var previousSectionBreak = previousSectionBreak(firstElement, parent).orElse(documentSection(context().part()));
50
        var index = siblings.indexOf(firstElement);
51
        siblings.removeAll(elements);
52
        var iterator = items.iterator();
53
        // Iterates items; copies elements; conditionally adds section break; adds elements
54 1 1. repeat : negated conditional → KILLED
        while (iterator.hasNext()) {
55
            var item = iterator.next();
56
            var copiedElements = elements.stream()
57
                                         .map(XmlUtils::deepCopy)
58
                                         .collect(toCollection(ArrayList::new));
59 1 1. repeat : removed call to pro/verron/officestamper/utils/wml/WmlUtils::deleteCommentFromElements → TIMED_OUT
            WmlUtils.deleteCommentFromElements(comment.getId(), copiedElements);
60
            // Adds section break to last paragraph if needed
61 2 1. repeat : negated conditional → TIMED_OUT
2. repeat : negated conditional → KILLED
            if (iterator.hasNext() && containsSectionBreaks(copiedElements)) {
62
                var lastParagraph = lastParagraph(copiedElements).orElseGet(newEndParagraph(copiedElements));
63 1 1. repeat : negated conditional → KILLED
                if (!hasSectionBreak(lastParagraph)) {
64 1 1. repeat : removed call to pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::addSectionBreak → KILLED
                    addSectionBreak(previousSectionBreak, lastParagraph);
65
                }
66
            }
67
            siblings.addAll(index, copiedElements);
68 1 1. repeat : Replaced integer addition with subtraction → KILLED
            index += copiedElements.size();
69 3 1. repeat : removed call to java/util/ArrayList::forEach → TIMED_OUT
2. lambda$repeat$0 : removed call to org/jvnet/jaxb2_commons/ppp/Child::setParent → TIMED_OUT
3. lambda$repeat$0 : negated conditional → KILLED
            copiedElements.forEach(element -> {if (element instanceof Child child) child.setParent(parent);});
70
            var subContextKey = contextHolder.addBranch(item);
71 1 1. lambda$repeat$1 : replaced return value with Collections.emptyList for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::lambda$repeat$1 → KILLED
            Hooks.ofHooks(() -> copiedElements)
72 2 1. repeat : removed call to pro/verron/officestamper/utils/iterator/ResetableIterator::forEachRemaining → KILLED
2. lambda$repeat$2 : removed call to pro/verron/officestamper/api/Hook::setContextKey → KILLED
                 .forEachRemaining(hook -> hook.setContextKey(subContextKey));
73
        }
74
    }
75
76
    private static Optional<SectPr> previousSectionBreak(Object firstObject, ContentAccessor parent) {
77
        List<Object> parentContent = parent.getContent();
78
        int pIndex = parentContent.indexOf(firstObject);
79
80 1 1. previousSectionBreak : Replaced integer subtraction with addition → TIMED_OUT
        int i = pIndex - 1;
81 2 1. previousSectionBreak : changed conditional boundary → TIMED_OUT
2. previousSectionBreak : negated conditional → KILLED
        while (i >= 0) {
82 1 1. previousSectionBreak : negated conditional → TIMED_OUT
            if (parentContent.get(i) instanceof P prevParagraph) {
83
                // the first P preceding the object is the one carrying a section break
84 1 1. previousSectionBreak : replaced return value with Optional.empty for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::previousSectionBreak → TIMED_OUT
                return ofNullable(prevParagraph.getPPr()).map(PPr::getSectPr);
85
            }
86
            else log.debug("The previous sibling was not a P, continuing search");
87
            i--;
88
        }
89
        log.info("No previous section break found from : {}, first object index={}", parent, pIndex);
90
        return Optional.empty();
91
    }
92
93
    private static SectPr documentSection(DocxPart part) {
94
        try {
95 1 1. documentSection : replaced return value with null for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::documentSection → TIMED_OUT
            return part.document()
96
                       .getMainDocumentPart()
97
                       .getContents()
98
                       .getBody()
99
                       .getSectPr();
100
        } catch (Docx4JException e) {
101
            throw new OfficeStamperException(e);
102
        }
103
    }
104
105
    private static boolean containsSectionBreaks(ArrayList<Object> elements) {
106 2 1. containsSectionBreaks : replaced boolean return with false for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::containsSectionBreaks → TIMED_OUT
2. containsSectionBreaks : replaced boolean return with true for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::containsSectionBreaks → KILLED
        return elements.stream()
107
                       .filter(P.class::isInstance)
108
                       .map(P.class::cast)
109
                       .map(P::getPPr)
110
                       .filter(Objects::nonNull)
111
                       .map(PPr::getSectPr)
112
                       .anyMatch(Objects::nonNull);
113
    }
114
115
    private static Optional<P> lastParagraph(List<Object> elements) {
116 2 1. lastParagraph : replaced return value with Optional.empty for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::lastParagraph → KILLED
2. lastParagraph : negated conditional → KILLED
        if (elements.getLast() instanceof P paragraph) return Optional.of(paragraph);
117
        else return Optional.empty();
118
    }
119
120
    private static Supplier<P> newEndParagraph(ArrayList<Object> copiedElements) {
121 1 1. newEndParagraph : replaced return value with null for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::newEndParagraph → KILLED
        return () -> {
122
            var p = WmlFactory.newParagraph();
123 1 1. lambda$newEndParagraph$0 : removed call to java/util/ArrayList::addLast → KILLED
            copiedElements.addLast(p);
124 1 1. lambda$newEndParagraph$0 : replaced return value with null for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::lambda$newEndParagraph$0 → KILLED
            return p;
125
        };
126
    }
127
128
    private static boolean hasSectionBreak(P lastParagraph) {
129
        PPr pPr = lastParagraph.getPPr();
130 2 1. hasSectionBreak : replaced boolean return with true for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::hasSectionBreak → KILLED
2. hasSectionBreak : negated conditional → KILLED
        if (pPr == null) return false;
131
        SectPr sectPr = pPr.getSectPr();
132 2 1. hasSectionBreak : negated conditional → NO_COVERAGE
2. hasSectionBreak : replaced boolean return with true for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::hasSectionBreak → NO_COVERAGE
        return sectPr != null;
133
    }
134
135
    private static void addSectionBreak(SectPr sectPr, P paragraph) {
136
        PPr nextPPr = ofNullable(paragraph.getPPr()).orElseGet(WmlFactory::newPPr);
137 1 1. addSectionBreak : removed call to org/docx4j/wml/PPr::setSectPr → KILLED
        nextPPr.setSectPr(XmlUtils.deepCopy(sectPr));
138 1 1. addSectionBreak : removed call to org/docx4j/wml/P::setPPr → KILLED
        paragraph.setPPr(nextPPr);
139
    }
140
}

Mutations

42

1.1
Location : repeat
Killed by : pro.verron.officestamper.test.RegressionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.RegressionTests]/[test-template:test52(pro.verron.officestamper.test.RegressionTests$Conditions, java.lang.String)]/[test-template-invocation:#1]
negated conditional → KILLED

54

1.1
Location : repeat
Killed by : pro.verron.officestamper.test.RegressionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.RegressionTests]/[test-template:test52(pro.verron.officestamper.test.RegressionTests$Conditions, java.lang.String)]/[test-template-invocation:#1]
negated conditional → KILLED

59

1.1
Location : repeat
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::deleteCommentFromElements → TIMED_OUT

61

1.1
Location : repeat
Killed by : none
negated conditional → TIMED_OUT

2.2
Location : repeat
Killed by : pro.verron.officestamper.test.RegressionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.RegressionTests]/[test-template:test52(pro.verron.officestamper.test.RegressionTests$Conditions, java.lang.String)]/[test-template-invocation:#4]
negated conditional → KILLED

63

1.1
Location : repeat
Killed by : pro.verron.officestamper.test.ProcessorRepeatParagraphTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatParagraphTest]/[test-template:features(java.lang.String, pro.verron.officestamper.api.OfficeStamperConfiguration, java.lang.Object, org.docx4j.openpackaging.packages.WordprocessingMLPackage, java.lang.String)]/[test-template-invocation:#6]
negated conditional → KILLED

64

1.1
Location : repeat
Killed by : pro.verron.officestamper.test.ProcessorRepeatParagraphTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatParagraphTest]/[test-template:features(java.lang.String, pro.verron.officestamper.api.OfficeStamperConfiguration, java.lang.Object, org.docx4j.openpackaging.packages.WordprocessingMLPackage, java.lang.String)]/[test-template-invocation:#6]
removed call to pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::addSectionBreak → KILLED

68

1.1
Location : repeat
Killed by : pro.verron.officestamper.test.RegressionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.RegressionTests]/[test-template:test52(pro.verron.officestamper.test.RegressionTests$Conditions, java.lang.String)]/[test-template-invocation:#4]
Replaced integer addition with subtraction → KILLED

69

1.1
Location : repeat
Killed by : none
removed call to java/util/ArrayList::forEach → TIMED_OUT

2.2
Location : lambda$repeat$0
Killed by : pro.verron.officestamper.test.ProcessorRepeatDocPart_BadPlaceholderTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatDocPart_BadPlaceholderTest]/[test-template:testBadExpressionShouldNotBlockCallerThread(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#2]
negated conditional → KILLED

3.3
Location : lambda$repeat$0
Killed by : none
removed call to org/jvnet/jaxb2_commons/ppp/Child::setParent → TIMED_OUT

71

1.1
Location : lambda$repeat$1
Killed by : pro.verron.officestamper.test.RegressionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.RegressionTests]/[test-template:test52(pro.verron.officestamper.test.RegressionTests$Conditions, java.lang.String)]/[test-template-invocation:#2]
replaced return value with Collections.emptyList for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::lambda$repeat$1 → KILLED

72

1.1
Location : repeat
Killed by : pro.verron.officestamper.test.RegressionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.RegressionTests]/[test-template:test52(pro.verron.officestamper.test.RegressionTests$Conditions, java.lang.String)]/[test-template-invocation:#2]
removed call to pro/verron/officestamper/utils/iterator/ResetableIterator::forEachRemaining → KILLED

2.2
Location : lambda$repeat$2
Killed by : pro.verron.officestamper.test.RegressionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.RegressionTests]/[test-template:test52(pro.verron.officestamper.test.RegressionTests$Conditions, java.lang.String)]/[test-template-invocation:#2]
removed call to pro/verron/officestamper/api/Hook::setContextKey → KILLED

80

1.1
Location : previousSectionBreak
Killed by : none
Replaced integer subtraction with addition → TIMED_OUT

81

1.1
Location : previousSectionBreak
Killed by : pro.verron.officestamper.test.RegressionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.RegressionTests]/[test-template:test52(pro.verron.officestamper.test.RegressionTests$Conditions, java.lang.String)]/[test-template-invocation:#1]
negated conditional → KILLED

2.2
Location : previousSectionBreak
Killed by : none
changed conditional boundary → TIMED_OUT

82

1.1
Location : previousSectionBreak
Killed by : none
negated conditional → TIMED_OUT

84

1.1
Location : previousSectionBreak
Killed by : none
replaced return value with Optional.empty for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::previousSectionBreak → TIMED_OUT

95

1.1
Location : documentSection
Killed by : none
replaced return value with null for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::documentSection → TIMED_OUT

106

1.1
Location : containsSectionBreaks
Killed by : none
replaced boolean return with false for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::containsSectionBreaks → TIMED_OUT

2.2
Location : containsSectionBreaks
Killed by : pro.verron.officestamper.test.RegressionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.RegressionTests]/[test-template:test52(pro.verron.officestamper.test.RegressionTests$Conditions, java.lang.String)]/[test-template-invocation:#4]
replaced boolean return with true for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::containsSectionBreaks → KILLED

116

1.1
Location : lastParagraph
Killed by : pro.verron.officestamper.test.ProcessorRepeatParagraphTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatParagraphTest]/[test-template:features(java.lang.String, pro.verron.officestamper.api.OfficeStamperConfiguration, java.lang.Object, org.docx4j.openpackaging.packages.WordprocessingMLPackage, java.lang.String)]/[test-template-invocation:#6]
replaced return value with Optional.empty for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::lastParagraph → KILLED

2.2
Location : lastParagraph
Killed by : pro.verron.officestamper.test.ProcessorRepeatParagraphTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatParagraphTest]/[test-template:features(java.lang.String, pro.verron.officestamper.api.OfficeStamperConfiguration, java.lang.Object, org.docx4j.openpackaging.packages.WordprocessingMLPackage, java.lang.String)]/[test-template-invocation:#6]
negated conditional → KILLED

121

1.1
Location : newEndParagraph
Killed by : pro.verron.officestamper.test.ProcessorRepeatDocPartTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatDocPartTest]/[test-template:shouldKeepPageBreakOrientationWithSectionBreaksInsideCommentAndTableLastElement(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#2]
replaced return value with null for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::newEndParagraph → KILLED

123

1.1
Location : lambda$newEndParagraph$0
Killed by : pro.verron.officestamper.test.ProcessorRepeatDocPartTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatDocPartTest]/[test-template:shouldKeepPageBreakOrientationWithSectionBreaksInsideCommentAndTableLastElement(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#2]
removed call to java/util/ArrayList::addLast → KILLED

124

1.1
Location : lambda$newEndParagraph$0
Killed by : pro.verron.officestamper.test.ProcessorRepeatDocPartTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatDocPartTest]/[test-template:shouldKeepPageBreakOrientationWithSectionBreaksInsideCommentAndTableLastElement(pro.verron.officestamper.test.utils.ContextFactory)]/[test-template-invocation:#2]
replaced return value with null for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::lambda$newEndParagraph$0 → KILLED

130

1.1
Location : hasSectionBreak
Killed by : pro.verron.officestamper.test.ProcessorRepeatParagraphTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatParagraphTest]/[test-template:features(java.lang.String, pro.verron.officestamper.api.OfficeStamperConfiguration, java.lang.Object, org.docx4j.openpackaging.packages.WordprocessingMLPackage, java.lang.String)]/[test-template-invocation:#6]
replaced boolean return with true for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::hasSectionBreak → KILLED

2.2
Location : hasSectionBreak
Killed by : pro.verron.officestamper.test.ProcessorRepeatParagraphTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatParagraphTest]/[test-template:features(java.lang.String, pro.verron.officestamper.api.OfficeStamperConfiguration, java.lang.Object, org.docx4j.openpackaging.packages.WordprocessingMLPackage, java.lang.String)]/[test-template-invocation:#6]
negated conditional → KILLED

132

1.1
Location : hasSectionBreak
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : hasSectionBreak
Killed by : none
replaced boolean return with true for pro/verron/officestamper/preset/processors/repeat/RepeatProcessor::hasSectionBreak → NO_COVERAGE

137

1.1
Location : addSectionBreak
Killed by : pro.verron.officestamper.test.ProcessorRepeatParagraphTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatParagraphTest]/[test-template:features(java.lang.String, pro.verron.officestamper.api.OfficeStamperConfiguration, java.lang.Object, org.docx4j.openpackaging.packages.WordprocessingMLPackage, java.lang.String)]/[test-template-invocation:#6]
removed call to org/docx4j/wml/PPr::setSectPr → KILLED

138

1.1
Location : addSectionBreak
Killed by : pro.verron.officestamper.test.ProcessorRepeatParagraphTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ProcessorRepeatParagraphTest]/[test-template:features(java.lang.String, pro.verron.officestamper.api.OfficeStamperConfiguration, java.lang.Object, org.docx4j.openpackaging.packages.WordprocessingMLPackage, java.lang.String)]/[test-template-invocation:#6]
removed call to org/docx4j/wml/P::setPPr → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.0