WmlUtils.java

1
package pro.verron.officestamper.utils.wml;
2
3
import jakarta.xml.bind.JAXBElement;
4
import org.docx4j.TraversalUtil;
5
import org.docx4j.finders.CommentFinder;
6
import org.docx4j.mce.AlternateContent;
7
import org.docx4j.model.structure.HeaderFooterPolicy;
8
import org.docx4j.model.structure.SectionWrapper;
9
import org.docx4j.model.styles.StyleUtil;
10
import org.docx4j.openpackaging.exceptions.Docx4JException;
11
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
12
import org.docx4j.openpackaging.parts.JaxbXmlPart;
13
import org.docx4j.openpackaging.parts.WordprocessingML.CommentsPart;
14
import org.docx4j.utils.TraversalUtilVisitor;
15
import org.docx4j.vml.CTShadow;
16
import org.docx4j.vml.CTTextbox;
17
import org.docx4j.vml.VmlShapeElements;
18
import org.docx4j.wml.*;
19
import org.docx4j.wml.Comments.Comment;
20
import org.jspecify.annotations.Nullable;
21
import org.jvnet.jaxb2_commons.ppp.Child;
22
import org.slf4j.Logger;
23
import org.slf4j.LoggerFactory;
24
import pro.verron.officestamper.utils.UtilsException;
25
import pro.verron.officestamper.utils.openpackaging.OpenpackagingFactory;
26
27
import java.math.BigInteger;
28
import java.util.*;
29
import java.util.function.Consumer;
30
import java.util.function.Predicate;
31
import java.util.stream.Stream;
32
33
import static java.util.Collections.emptyList;
34
import static java.util.Optional.empty;
35
import static java.util.Optional.ofNullable;
36
import static java.util.stream.Collectors.joining;
37
import static org.docx4j.XmlUtils.unwrap;
38
import static pro.verron.officestamper.utils.wml.WmlFactory.*;
39
40
/// Utility class with methods to help in the interaction with
41
/// [WordprocessingMLPackage] documents and their elements,
42
/// such as comments, parents, and child elements.
43
public final class WmlUtils {
44
45
    private static final String PRESERVE = "preserve";
46
    private static final Logger log = LoggerFactory.getLogger(WmlUtils.class);
47
48
    private WmlUtils() {
49
        throw new UtilsException("Utility class shouldn't be instantiated");
50
    }
51
52
    /// Attempts to find the first parent of a given child element that is an
53
    /// instance of the specified class within the
54
    /// defined search depth.
55
    ///
56
    /// @param child the [Child] element from which the search for a parent
57
    /// begins.
58
    /// @param clazz the [Class] type to match for the parent
59
    /// @param depth the maximum amount levels to traverse up the parent
60
    /// hierarchy
61
    /// @param <T>   the type of the parent class to search for
62
    /// @return an [Optional] containing the first parent matching the specified
63
    /// class, or an empty [Optional] if no
64
    ///         match found.
65
    public static <T> Optional<T> getFirstParentWithClass(Child child, Class<T> clazz, int depth) {
66
        var parent = child.getParent();
67
        var currentDepth = 0;
68 2 1. getFirstParentWithClass : changed conditional boundary → NO_COVERAGE
2. getFirstParentWithClass : negated conditional → NO_COVERAGE
        while (currentDepth <= depth) {
69 1 1. getFirstParentWithClass : Changed increment from 1 to -1 → NO_COVERAGE
            currentDepth++;
70 1 1. getFirstParentWithClass : negated conditional → NO_COVERAGE
            if (parent == null) return empty();
71 2 1. getFirstParentWithClass : replaced return value with Optional.empty for pro/verron/officestamper/utils/wml/WmlUtils::getFirstParentWithClass → NO_COVERAGE
2. getFirstParentWithClass : negated conditional → NO_COVERAGE
            if (clazz.isInstance(parent)) return Optional.of(clazz.cast(parent));
72 1 1. getFirstParentWithClass : negated conditional → NO_COVERAGE
            if (parent instanceof Child next) parent = next.getParent();
73
        }
74
        return empty();
75
    }
76
77
    /// Extracts a list of comment elements from the specified
78
    /// [WordprocessingMLPackage] document.
79
    ///
80
    /// @param document the [WordprocessingMLPackage] document from which to
81
    /// extract comment elements
82
    /// @return a list of [Child] objects representing the extracted comment
83
    /// elements
84
    public static List<Child> extractCommentElements(WordprocessingMLPackage document) {
85
        var commentFinder = new CommentFinder();
86 1 1. extractCommentElements : removed call to org/docx4j/TraversalUtil::visit → NO_COVERAGE
        TraversalUtil.visit(document, true, commentFinder);
87 1 1. extractCommentElements : replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils::extractCommentElements → NO_COVERAGE
        return commentFinder.getCommentElements();
88
    }
89
90
    /// Finds a comment with the given ID in the specified
91
    /// [WordprocessingMLPackage] document.
92
    ///
93
    /// @param document the [WordprocessingMLPackage] document to search for
94
    /// the comment
95
    /// @param id       the ID of the comment to find
96
    /// @return an [Optional] containing the [Comment] if found, or an empty
97
    /// [Optional] if not found.
98
    public static Optional<Comment> findComment(WordprocessingMLPackage document, BigInteger id) {
99
        var name = OpenpackagingFactory.newPartName("/word/comments.xml");
100
        var parts = document.getParts();
101
        var wordComments = (CommentsPart) parts.get(name);
102
        var comments = getComments(wordComments);
103 1 1. findComment : replaced return value with Optional.empty for pro/verron/officestamper/utils/wml/WmlUtils::findComment → NO_COVERAGE
        return comments.getComment().stream().filter(idEqual(id)).findFirst();
104
    }
105
106
    private static Comments getComments(CommentsPart wordComments) {
107
        try {
108 1 1. getComments : replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::getComments → NO_COVERAGE
            return wordComments.getContents();
109
        } catch (Docx4JException e) {
110
            throw new UtilsException(e);
111
        }
112
    }
113
114
    private static Predicate<Comment> idEqual(BigInteger id) {
115 1 1. idEqual : replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::idEqual → NO_COVERAGE
        return comment -> {
116
            var commentId = comment.getId();
117 2 1. lambda$idEqual$0 : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::lambda$idEqual$0 → NO_COVERAGE
2. lambda$idEqual$0 : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::lambda$idEqual$0 → NO_COVERAGE
            return commentId.equals(id);
118
        };
119
    }
120
121
122
    /// Removes the specified child element from its parent container. Depending
123
    /// on the type of the parent element, the
124
    /// removal process is delegated to the appropriate helper method. If the
125
    /// child is contained within a table cell and
126
    /// the cell is empty after removal, an empty paragraph is added to the
127
    /// cell.
128
    ///
129
    /// @param child the [Child] element to be removed
130
    /// @throws UtilsException if the parent of the child element is of an
131
    /// unexpected type
132
    public static void remove(Child child) {
133
        switch (child.getParent()) {
134 1 1. remove : removed call to pro/verron/officestamper/utils/wml/WmlUtils::remove → NO_COVERAGE
            case ContentAccessor parent -> remove(parent, child);
135 1 1. remove : removed call to pro/verron/officestamper/utils/wml/WmlUtils::remove → NO_COVERAGE
            case CTFootnotes parent -> remove(parent, child);
136 1 1. remove : removed call to pro/verron/officestamper/utils/wml/WmlUtils::remove → NO_COVERAGE
            case CTEndnotes parent -> remove(parent, child);
137 1 1. remove : removed call to pro/verron/officestamper/utils/wml/WmlUtils::remove → NO_COVERAGE
            case SdtRun parent -> remove(parent, child);
138
            default -> throw new UtilsException("Unexpected value: " + child.getParent());
139
        }
140 2 1. remove : negated conditional → NO_COVERAGE
2. remove : removed call to pro/verron/officestamper/utils/wml/WmlUtils::ensureValidity → NO_COVERAGE
        if (child.getParent() instanceof Tc cell) ensureValidity(cell);
141
    }
142
143
    private static void remove(ContentAccessor parent, Child child) {
144
        var siblings = parent.getContent();
145
        var iterator = siblings.listIterator();
146 1 1. remove : negated conditional → NO_COVERAGE
        while (iterator.hasNext()) {
147 1 1. remove : negated conditional → NO_COVERAGE
            if (equals(iterator.next(), child)) {
148 1 1. remove : removed call to java/util/ListIterator::remove → NO_COVERAGE
                iterator.remove();
149
                break;
150
            }
151
        }
152
    }
153
154
    @SuppressWarnings("SuspiciousMethodCalls")
155
    private static void remove(CTFootnotes parent, Child child) {
156
        parent.getFootnote().remove(child);
157
    }
158
159
    @SuppressWarnings("SuspiciousMethodCalls")
160
    private static void remove(CTEndnotes parent, Child child) {
161
        parent.getEndnote().remove(child);
162
    }
163
164
    private static void remove(SdtRun parent, Child child) {
165
        parent.getSdtContent().getContent().remove(child);
166
    }
167
168
    /// Utility method to ensure the validity of a table cell by adding an empty
169
    /// paragraph if necessary.
170
    ///
171
    /// @param cell the [Tc] to be checked and updated.
172
    public static void ensureValidity(Tc cell) {
173 1 1. ensureValidity : negated conditional → NO_COVERAGE
        if (!containsAnElementOfAnyClasses(cell.getContent(), P.class, Tbl.class)) {
174 1 1. ensureValidity : removed call to pro/verron/officestamper/utils/wml/WmlUtils::addEmptyParagraph → NO_COVERAGE
            addEmptyParagraph(cell);
175
        }
176
    }
177
178
    private static boolean equals(Object o1, Object o2) {
179 1 1. equals : negated conditional → NO_COVERAGE
        if (o1 instanceof JAXBElement<?> e1) o1 = e1.getValue();
180 1 1. equals : negated conditional → NO_COVERAGE
        if (o2 instanceof JAXBElement<?> e2) o2 = e2.getValue();
181 2 1. equals : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::equals → NO_COVERAGE
2. equals : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::equals → NO_COVERAGE
        return Objects.equals(o1, o2);
182
    }
183
184
    private static boolean containsAnElementOfAnyClasses(Collection<Object> collection, Class<?>... classes) {
185 4 1. lambda$containsAnElementOfAnyClasses$0 : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::lambda$containsAnElementOfAnyClasses$0 → NO_COVERAGE
2. containsAnElementOfAnyClasses : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::containsAnElementOfAnyClasses → NO_COVERAGE
3. containsAnElementOfAnyClasses : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::containsAnElementOfAnyClasses → NO_COVERAGE
4. lambda$containsAnElementOfAnyClasses$0 : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::lambda$containsAnElementOfAnyClasses$0 → NO_COVERAGE
        return collection.stream().anyMatch(element -> isAnElementOfAnyClasses(element, classes));
186
    }
187
188
    private static void addEmptyParagraph(Tc cell) {
189
        var emptyParagraph = WmlFactory.newParagraph();
190
        var cellContent = cell.getContent();
191
        cellContent.add(emptyParagraph);
192
    }
193
194
    private static boolean isAnElementOfAnyClasses(Object element, Class<?>... classes) {
195
        for (var clazz : classes) {
196 2 1. isAnElementOfAnyClasses : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::isAnElementOfAnyClasses → NO_COVERAGE
2. isAnElementOfAnyClasses : negated conditional → NO_COVERAGE
            if (clazz.isInstance(unwrapJAXBElement(element))) return true;
197
        }
198 1 1. isAnElementOfAnyClasses : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::isAnElementOfAnyClasses → NO_COVERAGE
        return false;
199
    }
200
201
    private static Object unwrapJAXBElement(Object element) {
202 2 1. unwrapJAXBElement : replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::unwrapJAXBElement → NO_COVERAGE
2. unwrapJAXBElement : negated conditional → NO_COVERAGE
        return element instanceof JAXBElement<?> jaxbElement ? jaxbElement.getValue() : element;
203
    }
204
205
    /// Extracts textual content from a given object, handling various object
206
    /// types, such as runs, text elements, and
207
    /// other specific constructs. The method accounts for different cases, such
208
    /// as run breaks, hyphens, and other
209
    /// document-specific constructs, and converts them into corresponding
210
    /// string representations.
211
    ///
212
    /// @param content the object from which text content is to be extracted.
213
    /// This could be of various types
214
    ///         such as [R], [JAXBElement], [Text] or specific document
215
    /// elements.
216
    /// @return a string representation of the extracted textual content. If the
217
    /// object's type is not handled, an empty
218
    ///         string is returned.
219
    public static String asString(Object content) {
220 1 1. asString : replaced return value with "" for pro/verron/officestamper/utils/wml/WmlUtils::asString → NO_COVERAGE
        return switch (content) {
221
            case P paragraph -> asString(paragraph.getContent());
222
            case R run -> asString(run.getContent());
223 1 1. asString : negated conditional → NO_COVERAGE
            case JAXBElement<?> jaxbElement when jaxbElement.getName().getLocalPart().equals("instrText") ->
224
                    "<instrText>";
225 1 1. asString : negated conditional → NO_COVERAGE
            case JAXBElement<?> jaxbElement when !jaxbElement.getName().getLocalPart().equals("instrText") ->
226
                    asString(jaxbElement.getValue());
227
            case Text text -> asString(text);
228
            case R.Tab _ -> "\t";
229
            case R.Cr _ -> "\n";
230 1 1. asString : negated conditional → NO_COVERAGE
            case Br br when br.getType() == null -> "\n";
231 1 1. asString : negated conditional → NO_COVERAGE
            case Br br when br.getType() == STBrType.PAGE -> "\n";
232 1 1. asString : negated conditional → NO_COVERAGE
            case Br br when br.getType() == STBrType.COLUMN -> "\n";
233 1 1. asString : negated conditional → NO_COVERAGE
            case Br br when br.getType() == STBrType.TEXT_WRAPPING -> "\n";
234
235
            case R.NoBreakHyphen _ -> "‑";
236
            case R.SoftHyphen _ -> "\u00AD";
237 4 1. asString : negated conditional → NO_COVERAGE
2. asString : negated conditional → NO_COVERAGE
3. asString : negated conditional → NO_COVERAGE
4. asString : negated conditional → NO_COVERAGE
            case R.LastRenderedPageBreak _, R.AnnotationRef _, R.CommentReference _, Drawing _ -> "";
238
            case FldChar _ -> "<fldchar>";
239
            case CTFtnEdnRef ref -> "<ref(%s)>".formatted(ref.getId());
240
            case R.Sym sym -> "<sym(%s, %s)>".formatted(sym.getFont(), sym.getChar());
241
            case List<?> list -> list.stream().map(WmlUtils::asString).collect(joining());
242 2 1. asString : negated conditional → NO_COVERAGE
2. asString : negated conditional → NO_COVERAGE
            case ProofErr _, CTShadow _ -> "";
243
            case SdtRun sdtRun -> asString(sdtRun.getSdtContent());
244
            case ContentAccessor contentAccessor -> asString(contentAccessor.getContent());
245
            case Pict pict -> "<pict(%s)>".formatted(pict.getAnchorId());
246
            case VmlShapeElements vmlShapeElements -> asString(vmlShapeElements.getEGShapeElements());
247
            case CTTextbox textbox -> asString(textbox.getTxbxContent());
248 2 1. asString : negated conditional → NO_COVERAGE
2. asString : negated conditional → NO_COVERAGE
            case CommentRangeStart _, CommentRangeEnd _ -> "";
249
            case AlternateContent ac -> {
250
                var choices = ac.getChoice();
251 1 1. asString : Replaced integer addition with subtraction → NO_COVERAGE
                yield "<alternateContent(%d)>".formatted(choices.size() + 1);
252
            }
253
            default -> {
254
                log.debug("Unhandled object type: {}", content.getClass());
255
                yield "";
256
            }
257
        };
258
    }
259
260
    private static String asString(Text text) {
261
        // According to specs, the 'space' value can be empty or 'preserve'.
262
        // In the first case, we are supposed to ignore spaces around the
263
        // 'text' value.
264
        var value = text.getValue();
265
        var space = text.getSpace();
266 2 1. asString : negated conditional → NO_COVERAGE
2. asString : replaced return value with "" for pro/verron/officestamper/utils/wml/WmlUtils::asString → NO_COVERAGE
        return Objects.equals(space, PRESERVE) ? value : value.trim();
267
    }
268
269
    /// Inserts a smart tag with the specified element type into the given
270
    /// paragraph at the position of the expression.
271
    ///
272
    /// @param element    the element type for the smart tag
273
    /// @param paragraph  the [P] paragraph to insert the smart tag into
274
    /// @param expression the expression to replace with the smart tag
275
    /// @param start      the start index of the expression
276
    /// @param end        the end index of the expression
277
    public static void insertSmartTag(String element, P paragraph, String expression, int start, int end) {
278
        var run = newRun(expression);
279
        var smartTag = newSmartTag("officestamper", newCtAttr("type", element), run);
280 1 1. insertSmartTag : removed call to java/util/Optional::ifPresent → NO_COVERAGE
        findFirstAffectedRunPr(paragraph, start, end).ifPresent(run::setRPr);
281 1 1. insertSmartTag : removed call to pro/verron/officestamper/utils/wml/WmlUtils::replace → NO_COVERAGE
        replace(paragraph, List.of(smartTag), start, end);
282
    }
283
284
    /// Finds the first affected run properties within the specified range.
285
    ///
286
    /// @param contentAccessor the [ContentAccessor] to search in
287
    /// @param start           the start index of the range
288
    /// @param end             the end index of the range
289
    /// @return an [Optional] containing the [RPr] if found, or an empty
290
    /// [Optional] if not found
291
    public static Optional<RPr> findFirstAffectedRunPr(ContentAccessor contentAccessor, int start, int end) {
292
        var iterator = new DocxIterator(contentAccessor).selectClass(R.class);
293
        var runs = StandardRun.wrap(iterator);
294
295 2 1. lambda$findFirstAffectedRunPr$0 : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::lambda$findFirstAffectedRunPr$0 → NO_COVERAGE
2. lambda$findFirstAffectedRunPr$0 : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::lambda$findFirstAffectedRunPr$0 → NO_COVERAGE
        var affectedRuns = runs.stream().filter(run -> run.isTouchedByRange(start, end)).toList();
296
297
        var firstRun = affectedRuns.getFirst();
298
        var firstRunPr = firstRun.getPr();
299 1 1. findFirstAffectedRunPr : replaced return value with Optional.empty for pro/verron/officestamper/utils/wml/WmlUtils::findFirstAffectedRunPr → NO_COVERAGE
        return ofNullable(firstRunPr);
300
    }
301
302
    /// Replaces content within the specified range with the provided insert
303
    /// objects.
304
    ///
305
    /// @param contentAccessor the [ContentAccessor] in which to replace content
306
    /// @param insert          the list of objects to insert
307
    /// @param startIndex      the start index of the range to replace
308
    /// @param endIndex        the end index of the range to replace
309
    public static void replace(ContentAccessor contentAccessor, List<Object> insert, int startIndex, int endIndex) {
310
        var iterator = new DocxIterator(contentAccessor).selectClass(R.class);
311
        var runs = StandardRun.wrap(iterator);
312 2 1. lambda$replace$0 : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::lambda$replace$0 → NO_COVERAGE
2. lambda$replace$0 : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::lambda$replace$0 → NO_COVERAGE
        var affectedRuns = runs.stream().filter(run -> run.isTouchedByRange(startIndex, endIndex)).toList();
313
314
        var firstRun = affectedRuns.getFirst();
315
        var firstR = firstRun.run();
316
        var firstSiblings = ((ContentAccessor) firstR.getParent()).getContent();
317
        var firstIndex = firstSiblings.indexOf(firstRun.run());
318
319 1 1. replace : negated conditional → NO_COVERAGE
        boolean singleRun = affectedRuns.size() == 1;
320 1 1. replace : negated conditional → NO_COVERAGE
        if (singleRun) {
321 2 1. replace : Replaced integer subtraction with addition → NO_COVERAGE
2. replace : negated conditional → NO_COVERAGE
            boolean expressionSpansCompleteRun = endIndex - startIndex == firstRun.length();
322 1 1. replace : negated conditional → NO_COVERAGE
            boolean expressionAtStartOfRun = startIndex == firstRun.startIndex();
323 1 1. replace : negated conditional → NO_COVERAGE
            boolean expressionAtEndOfRun = endIndex == firstRun.endIndex();
324 4 1. replace : negated conditional → NO_COVERAGE
2. replace : changed conditional boundary → NO_COVERAGE
3. replace : negated conditional → NO_COVERAGE
4. replace : changed conditional boundary → NO_COVERAGE
            boolean expressionWithinRun = startIndex > firstRun.startIndex() && endIndex <= firstRun.endIndex();
325
326 1 1. replace : negated conditional → NO_COVERAGE
            if (expressionSpansCompleteRun) {
327 1 1. replace : removed call to pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::replace → NO_COVERAGE
                firstRun.replace(startIndex, endIndex, "");
328
                firstSiblings.addAll(firstIndex, insert);
329 1 1. replace : negated conditional → NO_COVERAGE
            } else if (expressionAtStartOfRun) {
330 1 1. replace : removed call to pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::replace → NO_COVERAGE
                firstRun.replace(startIndex, endIndex, "");
331
                firstSiblings.addAll(firstIndex, insert);
332 1 1. replace : negated conditional → NO_COVERAGE
            } else if (expressionAtEndOfRun) {
333 1 1. replace : removed call to pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::replace → NO_COVERAGE
                firstRun.replace(startIndex, endIndex, "");
334 1 1. replace : Replaced integer addition with subtraction → NO_COVERAGE
                firstSiblings.addAll(firstIndex + 1, insert);
335 1 1. replace : negated conditional → NO_COVERAGE
            } else if (expressionWithinRun) {
336
                var originalRun = firstRun.run();
337
                var originalRPr = originalRun.getRPr();
338
                var newStartRun = create(firstRun.left(startIndex), originalRPr);
339
                var newEndRun = create(firstRun.right(endIndex), originalRPr);
340
                firstSiblings.remove(firstIndex);
341
                firstSiblings.addAll(firstIndex, wrap(newStartRun, insert, newEndRun));
342
            }
343
        } else {
344
            StandardRun lastRun = affectedRuns.getLast();
345 1 1. replace : removed call to pro/verron/officestamper/utils/wml/WmlUtils::removeExpression → NO_COVERAGE
            removeExpression(firstSiblings, firstRun, startIndex, endIndex, lastRun, affectedRuns);
346
            // add replacement run between first and last run
347 1 1. replace : Replaced integer addition with subtraction → NO_COVERAGE
            firstSiblings.addAll(firstIndex + 1, insert);
348
        }
349
    }
350
351
    /// Creates a new run with the specified text and the specified run style.
352
    ///
353
    /// @param text the initial text of the [R].
354
    /// @param rPr  the [RPr] to apply to the run
355
    /// @return the newly created [R].
356
    public static R create(String text, RPr rPr) {
357
        R newStartRun = newRun(text);
358 1 1. create : removed call to org/docx4j/wml/R::setRPr → NO_COVERAGE
        newStartRun.setRPr(rPr);
359 1 1. create : replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::create → NO_COVERAGE
        return newStartRun;
360
    }
361
362
    private static Collection<?> wrap(R prefix, Collection<?> elements, R suffix) {
363
        var merge = new ArrayList<>();
364
        merge.add(prefix);
365
        merge.addAll(elements);
366
        merge.add(suffix);
367 1 1. wrap : replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils::wrap → NO_COVERAGE
        return merge;
368
    }
369
370
    private static void removeExpression(List<Object> contents, StandardRun firstRun, int matchStartIndex, int matchEndIndex, StandardRun lastRun, List<StandardRun> affectedRuns) {
371
        // remove the expression from the first run
372 1 1. removeExpression : removed call to pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::replace → NO_COVERAGE
        firstRun.replace(matchStartIndex, matchEndIndex, "");
373
        // remove all runs between first and last
374
        for (StandardRun run : affectedRuns) {
375 2 1. removeExpression : negated conditional → NO_COVERAGE
2. removeExpression : negated conditional → NO_COVERAGE
            if (!Objects.equals(run, firstRun) && !Objects.equals(run, lastRun)) {
376
                contents.remove(run.run());
377
            }
378
        }
379
        // remove the expression from the last run
380 1 1. removeExpression : removed call to pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::replace → NO_COVERAGE
        lastRun.replace(matchStartIndex, matchEndIndex, "");
381
    }
382
383
    /// Creates a new run with the specified text and inherits the style of the
384
    /// parent paragraph.
385
    ///
386
    /// @param text        the initial text of the [R].
387
    /// @param paragraphPr the [PPr] to apply to the run
388
    /// @return the newly created [R].
389
    public static R create(String text, PPr paragraphPr) {
390
        R run = newRun(text);
391 1 1. create : removed call to pro/verron/officestamper/utils/wml/WmlUtils::applyParagraphStyle → NO_COVERAGE
        applyParagraphStyle(run, paragraphPr);
392 1 1. create : replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::create → NO_COVERAGE
        return run;
393
    }
394
395
    /// Applies the style of the given paragraph to the given content object (if
396
    /// the content object is a [R]).
397
    ///
398
    /// @param run         the [R] to which the style should be applied.
399
    /// @param paragraphPr the [PPr] containing the style to apply
400
    public static void applyParagraphStyle(R run, @Nullable PPr paragraphPr) {
401 1 1. applyParagraphStyle : negated conditional → NO_COVERAGE
        if (paragraphPr == null) return;
402
        var runPr = paragraphPr.getRPr();
403 1 1. applyParagraphStyle : negated conditional → NO_COVERAGE
        if (runPr == null) return;
404
        RPr runProperties = new RPr();
405
        StyleUtil.apply(runPr, runProperties);
406 1 1. applyParagraphStyle : removed call to org/docx4j/wml/R::setRPr → NO_COVERAGE
        run.setRPr(runProperties);
407
    }
408
409
    /// Sets the text of the given run to the given value.
410
    ///
411
    /// @param run  the [R] whose text to change.
412
    /// @param text the text to set.
413
    public static void setText(R run, String text) {
414 1 1. setText : removed call to java/util/List::clear → NO_COVERAGE
        run.getContent().clear();
415
        Text textObj = newText(text);
416
        run.getContent().add(textObj);
417
    }
418
419
    /// Replaces all occurrences of the specified expression with the provided
420
    /// run objects.
421
    ///
422
    /// @param contentAccessor the [ContentAccessor] in which to replace the
423
    /// expression
424
    /// @param expression      the expression to replace
425
    /// @param insert          the list of objects to insert
426
    /// @param onRPr           a consumer to handle [RPr] properties
427
    public static void replaceExpressionWithRun(ContentAccessor contentAccessor, String expression, List<Object> insert, Consumer<RPr> onRPr) {
428
        var text = asString(contentAccessor);
429
        int matchStartIndex = text.indexOf(expression);
430 1 1. replaceExpressionWithRun : negated conditional → NO_COVERAGE
        if (matchStartIndex == -1) return; /*nothing to replace*/
431
432 1 1. replaceExpressionWithRun : Replaced integer addition with subtraction → NO_COVERAGE
        int matchEndIndex = matchStartIndex + expression.length();
433 1 1. replaceExpressionWithRun : removed call to java/util/Optional::ifPresent → NO_COVERAGE
        findFirstAffectedRunPr(contentAccessor, matchStartIndex, matchEndIndex).ifPresent(onRPr);
434 1 1. replaceExpressionWithRun : removed call to pro/verron/officestamper/utils/wml/WmlUtils::replace → NO_COVERAGE
        replace(contentAccessor, insert, matchStartIndex, matchEndIndex);
435
    }
436
437
    /// Checks if the given [CTSmartTagRun] contains an element that matches the
438
    /// expected element.
439
    ///
440
    /// @param tag             the [CTSmartTagRun] object to be evaluated
441
    /// @param expectedElement the expected element to compare against
442
    /// @return true if the actual element of the given tag matches the expected
443
    /// element, false otherwise
444
    public static boolean isTagElement(CTSmartTagRun tag, String expectedElement) {
445
        var actualElement = tag.getElement();
446 2 1. isTagElement : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::isTagElement → NO_COVERAGE
2. isTagElement : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::isTagElement → NO_COVERAGE
        return Objects.equals(expectedElement, actualElement);
447
    }
448
449
    /// Sets or updates an attribute for the specified smart tag. This method
450
    /// ensures that the provided attribute
451
    /// key-value pair is added to the smart tag's attribute list. If the
452
    /// attribute already exists, its value is
453
    /// updated. If the smart tag or its attribute metadata is null, they are
454
    /// initialized.
455
    ///
456
    /// @param smartTag       the smart tag object to modify
457
    /// @param attributeKey   the key of the attribute to set or update
458
    /// @param attributeValue the value to assign to the specified attribute key
459
    public static void setTagAttribute(CTSmartTagRun smartTag, String attributeKey, String attributeValue) {
460
        var smartTagPr = smartTag.getSmartTagPr();
461 1 1. setTagAttribute : negated conditional → NO_COVERAGE
        if (smartTagPr == null) {
462
            smartTagPr = new CTSmartTagPr();
463 1 1. setTagAttribute : removed call to org/docx4j/wml/CTSmartTagRun::setSmartTagPr → NO_COVERAGE
            smartTag.setSmartTagPr(smartTagPr);
464
        }
465
        var smartTagPrAttr = smartTagPr.getAttr();
466 1 1. setTagAttribute : negated conditional → NO_COVERAGE
        if (smartTagPrAttr == null) {
467
            smartTagPrAttr = new ArrayList<>();
468 1 1. setTagAttribute : removed call to org/docx4j/wml/CTSmartTagRun::setSmartTagPr → NO_COVERAGE
            smartTag.setSmartTagPr(smartTagPr);
469
        }
470
        for (CTAttr attribute : smartTagPrAttr) {
471 1 1. setTagAttribute : negated conditional → NO_COVERAGE
            if (attributeKey.equals(attribute.getName())) {
472 1 1. setTagAttribute : removed call to org/docx4j/wml/CTAttr::setVal → NO_COVERAGE
                attribute.setVal(attributeValue);
473
                return;
474
            }
475
        }
476
        var ctAttr = newAttribute(attributeKey, attributeValue);
477
        smartTagPrAttr.add(ctAttr);
478
    }
479
480
    /// Creates a new attribute object with the specified key and value.
481
    ///
482
    /// @param attributeKey   the key for the new attribute
483
    /// @param attributeValue the value for the new attribute
484
    /// @return a CTAttr object representing the new attribute
485
    public static CTAttr newAttribute(String attributeKey, String attributeValue) {
486 1 1. newAttribute : replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::newAttribute → NO_COVERAGE
        return newCtAttr(attributeKey, attributeValue);
487
    }
488
489
    /// Deletes all elements associated with the specified comment from the
490
    /// provided list of items.
491
    ///
492
    /// @param commentId the ID of the comment to be deleted
493
    /// @param items     the list of items from which elements associated with
494
    /// the comment will be deleted
495
    public static void deleteCommentFromElements(BigInteger commentId, List<Object> items) {
496
        record DeletableItems(List<Object> container, List<Object> items) {
497
            static List<DeletableItems> findAll(List<Object> items, BigInteger commentId) {
498 2 1. lambda$findAll$0 : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::lambda$findAll$0 → NO_COVERAGE
2. lambda$findAll$0 : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::lambda$findAll$0 → NO_COVERAGE
                Predicate<BigInteger> predicate = bi -> Objects.equals(bi, commentId);
499
                List<DeletableItems> elementsToRemove = new ArrayList<>();
500 1 1. findAll : removed call to java/util/List::forEach → NO_COVERAGE
                items.forEach(item -> {
501
                    Object unwrapped = unwrap(item);
502
                    // Recursively finds deletable items associated with
503
                    // comment ID
504
                    elementsToRemove.addAll(switch (unwrapped) {
505
                        case CTSmartTagRun str when str.getContent()
506
                                .stream()
507 4 1. lambda$findAll$2 : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::lambda$findAll$2 → NO_COVERAGE
2. lambda$findAll$2 : negated conditional → NO_COVERAGE
3. lambda$findAll$2 : negated conditional → NO_COVERAGE
4. lambda$findAll$1 : negated conditional → NO_COVERAGE
                                .anyMatch(i -> i instanceof CommentRangeStart crs && predicate.test(crs.getId())) ->
508
                                from(items, item);
509 1 1. lambda$findAll$1 : negated conditional → NO_COVERAGE
                        case CommentRangeStart crs when predicate.test(crs.getId()) -> from(items, item);
510 1 1. lambda$findAll$1 : negated conditional → NO_COVERAGE
                        case CommentRangeEnd cre when predicate.test(cre.getId()) -> from(items, item);
511 1 1. lambda$findAll$1 : negated conditional → NO_COVERAGE
                        case R.CommentReference rcr when predicate.test(rcr.getId()) -> from(items, item);
512
                        case ContentAccessor ca -> findAll(ca, commentId);
513
                        case SdtRun sdtRun -> findAll(sdtRun, commentId);
514
                        default -> emptyList();
515
                    });
516
                });
517 1 1. findAll : replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::findAll → NO_COVERAGE
                return elementsToRemove;
518
            }
519
520
            private static Collection<DeletableItems> findAll(SdtRun sdtRun, BigInteger commentId) {
521 1 1. findAll : replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::findAll → NO_COVERAGE
                return findAll(sdtRun.getSdtContent(), commentId);
522
            }
523
524
            private static Collection<DeletableItems> findAll(ContentAccessor ca, BigInteger commentId) {
525 1 1. findAll : replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::findAll → NO_COVERAGE
                return findAll(ca.getContent(), commentId);
526
            }
527
528
            private static List<DeletableItems> from(List<Object> items, Object item) {
529 1 1. from : replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::from → NO_COVERAGE
                return Collections.singletonList(new DeletableItems(items, List.of(item)));
530
            }
531
        }
532 1 1. deleteCommentFromElements : removed call to java/util/List::forEach → NO_COVERAGE
        DeletableItems.findAll(items, commentId).forEach(p -> p.container.removeAll(p.items));
533
    }
534
535
    /// Visits the document's main content, header, footer, footnotes, and
536
    /// endnotes using the specified visitor.
537
    ///
538
    /// @param document the WordprocessingMLPackage representing the document
539
    ///  to be visited
540
    /// @param visitor  the TraversalUtilVisitor to be applied to each relevant
541
    /// part of the document
542
    public static void visitDocument(WordprocessingMLPackage document, TraversalUtilVisitor<?> visitor) {
543
        var mainDocumentPart = document.getMainDocumentPart();
544 1 1. visitDocument : removed call to org/docx4j/TraversalUtil::visit → NO_COVERAGE
        TraversalUtil.visit(mainDocumentPart, visitor);
545 2 1. lambda$visitDocument$0 : removed call to org/docx4j/TraversalUtil::visit → NO_COVERAGE
2. visitDocument : removed call to java/util/stream/Stream::forEach → NO_COVERAGE
        WmlUtils.streamHeaderFooterPart(document).forEach(f -> TraversalUtil.visit(f, visitor));
546 1 1. visitDocument : removed call to pro/verron/officestamper/utils/wml/WmlUtils::visitPartIfExists → NO_COVERAGE
        WmlUtils.visitPartIfExists(visitor, mainDocumentPart.getFootnotesPart());
547 1 1. visitDocument : removed call to pro/verron/officestamper/utils/wml/WmlUtils::visitPartIfExists → NO_COVERAGE
        WmlUtils.visitPartIfExists(visitor, mainDocumentPart.getEndNotesPart());
548
    }
549
550
    private static Stream<Object> streamHeaderFooterPart(WordprocessingMLPackage document) {
551 1 1. streamHeaderFooterPart : replaced return value with Stream.empty for pro/verron/officestamper/utils/wml/WmlUtils::streamHeaderFooterPart → NO_COVERAGE
        return document.getDocumentModel()
552
                .getSections()
553
                .stream()
554
                .map(SectionWrapper::getHeaderFooterPolicy)
555
                .flatMap(WmlUtils::extractHeaderFooterParts);
556
    }
557
558
    private static void visitPartIfExists(TraversalUtilVisitor<?> visitor, @Nullable JaxbXmlPart<?> part) {
559 2 1. lambda$visitPartIfExists$0 : removed call to org/docx4j/TraversalUtil::visit → NO_COVERAGE
2. visitPartIfExists : removed call to java/util/Optional::ifPresent → NO_COVERAGE
        ofNullable(part).map(WmlUtils::extractContent).ifPresent(c -> TraversalUtil.visit(c, visitor));
560
    }
561
562
    private static Stream<JaxbXmlPart<?>> extractHeaderFooterParts(HeaderFooterPolicy hfp) {
563
        Stream.Builder<JaxbXmlPart<?>> builder = Stream.builder();
564 1 1. extractHeaderFooterParts : removed call to java/util/Optional::ifPresent → NO_COVERAGE
        ofNullable(hfp.getFirstHeader()).ifPresent(builder::add);
565 1 1. extractHeaderFooterParts : removed call to java/util/Optional::ifPresent → NO_COVERAGE
        ofNullable(hfp.getDefaultHeader()).ifPresent(builder::add);
566 1 1. extractHeaderFooterParts : removed call to java/util/Optional::ifPresent → NO_COVERAGE
        ofNullable(hfp.getEvenHeader()).ifPresent(builder::add);
567 1 1. extractHeaderFooterParts : removed call to java/util/Optional::ifPresent → NO_COVERAGE
        ofNullable(hfp.getFirstFooter()).ifPresent(builder::add);
568 1 1. extractHeaderFooterParts : removed call to java/util/Optional::ifPresent → NO_COVERAGE
        ofNullable(hfp.getDefaultFooter()).ifPresent(builder::add);
569 1 1. extractHeaderFooterParts : removed call to java/util/Optional::ifPresent → NO_COVERAGE
        ofNullable(hfp.getEvenFooter()).ifPresent(builder::add);
570 1 1. extractHeaderFooterParts : replaced return value with Stream.empty for pro/verron/officestamper/utils/wml/WmlUtils::extractHeaderFooterParts → NO_COVERAGE
        return builder.build();
571
    }
572
573
    private static Object extractContent(JaxbXmlPart<?> jaxbXmlPart) {
574
        try {
575 1 1. extractContent : replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::extractContent → NO_COVERAGE
            return jaxbXmlPart.getContents();
576
        } catch (Docx4JException e) {
577
            throw new UtilsException(e);
578
        }
579
    }
580
581
    /// Checks if the provided smart tag contains an attribute with the
582
    /// specified key and value.
583
    ///
584
    /// @param tag     the smart tag to search for the attribute
585
    /// @param attrKey the key of the attribute to search for
586
    /// @param attrVal the value of the attribute to match
587
    /// @return true if the smart tag contains an attribute with the specified
588
    /// key and value, false otherwise
589
    public static boolean hasTagAttribute(CTSmartTagRun tag, String attrKey, String attrVal) {
590
        var smartTagPr = tag.getSmartTagPr();
591
        var smartTagPrAttr = smartTagPr.getAttr();
592
        for (CTAttr ctAttr : smartTagPrAttr)
593 3 1. hasTagAttribute : negated conditional → NO_COVERAGE
2. hasTagAttribute : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::hasTagAttribute → NO_COVERAGE
3. hasTagAttribute : replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::hasTagAttribute → NO_COVERAGE
            if (Objects.equals(ctAttr.getName(), attrKey)) return Objects.equals(ctAttr.getVal(), attrVal);
594 1 1. hasTagAttribute : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::hasTagAttribute → NO_COVERAGE
        return false;
595
    }
596
597
    /// @param startIndex the start index of the run relative to the
598
    /// containing paragraph.
599
    /// @param run        the [R] run itself.
600
    private record StandardRun(int startIndex, R run) {
601
602
        /// Initializes a list of [StandardRun] objects based on the given
603
        /// iterator of [R] objects.
604
        ///
605
        /// @param iterator the iterator of [R] objects to be processed into
606
        /// [StandardRun] instances
607
        /// @return a list of [StandardRun] objects created from the given
608
        /// iterator
609
        public static List<StandardRun> wrap(Iterator<R> iterator) {
610
            var index = 0;
611
            var runList = new ArrayList<StandardRun>();
612 1 1. wrap : negated conditional → NO_COVERAGE
            while (iterator.hasNext()) {
613
                var run = iterator.next();
614
                var currentRun = new StandardRun(index, run);
615
                runList.add(currentRun);
616 1 1. wrap : Replaced integer addition with subtraction → NO_COVERAGE
                index += currentRun.length();
617
            }
618 1 1. wrap : replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::wrap → NO_COVERAGE
            return runList;
619
        }
620
621
        /// Calculates the length of the text content of this run.
622
        ///
623
        /// @return the length of the text in the current run.
624
        public int length() {
625 1 1. length : replaced int return with 0 for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::length → NO_COVERAGE
            return getText().length();
626
        }
627
628
        /// Returns the text string of a run.
629
        ///
630
        /// @return [String] representation of the run.
631
        public String getText() {
632 1 1. getText : replaced return value with "" for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::getText → NO_COVERAGE
            return asString(run);
633
        }
634
635
        /// Retrieves the properties associated with this run.
636
        ///
637
        /// @return the [RPr] object representing the properties of the run.
638
        public RPr getPr() {
639 1 1. getPr : replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::getPr → NO_COVERAGE
            return run.getRPr();
640
        }
641
642
        /// Determines whether the current run is affected by the specified
643
        /// range of global start and end indices. A run
644
        /// is considered "touched" if any part of it overlaps with the given
645
        /// range.
646
        ///
647
        /// @param globalStartIndex the global start index of the range.
648
        /// @param globalEndIndex   the global end index of the range.
649
        /// @return `true` if the current run is touched by the specified range;
650
        /// `false` otherwise.
651
        public boolean isTouchedByRange(int globalStartIndex, int globalEndIndex) {
652 3 1. isTouchedByRange : negated conditional → NO_COVERAGE
2. isTouchedByRange : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::isTouchedByRange → NO_COVERAGE
3. isTouchedByRange : negated conditional → NO_COVERAGE
            return startsInRange(globalStartIndex, globalEndIndex) || endsInRange(globalStartIndex,
653
                    globalEndIndex
654 1 1. isTouchedByRange : negated conditional → NO_COVERAGE
            ) || englobesRange(globalStartIndex, globalEndIndex);
655
        }
656
657
        private boolean startsInRange(int globalStartIndex, int globalEndIndex) {
658 5 1. startsInRange : negated conditional → NO_COVERAGE
2. startsInRange : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::startsInRange → NO_COVERAGE
3. startsInRange : changed conditional boundary → NO_COVERAGE
4. startsInRange : negated conditional → NO_COVERAGE
5. startsInRange : changed conditional boundary → NO_COVERAGE
            return globalStartIndex < startIndex && startIndex <= globalEndIndex;
659
        }
660
661
        private boolean endsInRange(int globalStartIndex, int globalEndIndex) {
662 5 1. endsInRange : changed conditional boundary → NO_COVERAGE
2. endsInRange : negated conditional → NO_COVERAGE
3. endsInRange : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::endsInRange → NO_COVERAGE
4. endsInRange : negated conditional → NO_COVERAGE
5. endsInRange : changed conditional boundary → NO_COVERAGE
            return globalStartIndex < endIndex() && endIndex() <= globalEndIndex;
663
        }
664
665
        private boolean englobesRange(int globalStartIndex, int globalEndIndex) {
666 5 1. englobesRange : negated conditional → NO_COVERAGE
2. englobesRange : changed conditional boundary → NO_COVERAGE
3. englobesRange : negated conditional → NO_COVERAGE
4. englobesRange : replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::englobesRange → NO_COVERAGE
5. englobesRange : changed conditional boundary → NO_COVERAGE
            return startIndex <= globalStartIndex && globalEndIndex <= endIndex();
667
        }
668
669
        /// Calculates the end index of the current run based on its start index
670
        /// and length.
671
        ///
672
        /// @return the end index of the run.
673
        public int endIndex() {
674 2 1. endIndex : Replaced integer addition with subtraction → NO_COVERAGE
2. endIndex : replaced int return with 0 for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::endIndex → NO_COVERAGE
            return startIndex + length();
675
        }
676
677
        /// Replaces the substring starting at the given index with the given
678
        /// replacement string.
679
        ///
680
        /// @param globalStartIndex the global index at which to start the
681
        /// replacement.
682
        /// @param globalEndIndex   the global index at which to end the
683
        /// replacement.
684
        /// @param replacement      the string to replace the substring at
685
        /// the specified global index.
686
        public void replace(int globalStartIndex, int globalEndIndex, String replacement) {
687
            var text = left(globalStartIndex) + replacement + right(globalEndIndex);
688 1 1. replace : removed call to pro/verron/officestamper/utils/wml/WmlUtils::setText → NO_COVERAGE
            setText(run, text);
689
        }
690
691
        /// Extracts a substring of the run's text, starting from the beginning
692
        /// and extending up to the localized index
693
        /// of the specified global end index.
694
        ///
695
        /// @param globalEndIndex the global end index used to determine the
696
        /// cutoff point for the extracted
697
        ///         substring.
698
        /// @return a substring of the run's text, starting at the beginning and
699
        /// ending at the specified localized
700
        ///         index.
701
        public String left(int globalEndIndex) {
702 1 1. left : replaced return value with "" for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::left → NO_COVERAGE
            return getText().substring(0, localize(globalEndIndex));
703
        }
704
705
        /// Extracts a substring of the run's text, starting from the localized
706
        /// index of the specified global start
707
        /// index to the end of the run's text.
708
        ///
709
        /// @param globalStartIndex the global index specifying the starting
710
        /// point for the substring in the
711
        ///         run's text.
712
        /// @return a substring of the run's text starting from the localized
713
        /// index corresponding to the provided global
714
        ///         start index.
715
        public String right(int globalStartIndex) {
716 1 1. right : replaced return value with "" for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::right → NO_COVERAGE
            return getText().substring(localize(globalStartIndex));
717
        }
718
719
        /// Converts a global index to a local index within the context of this
720
        /// run. (meaning the index relative to
721
        /// multiple aggregated runs)
722
        ///
723
        /// @param globalIndex the global index to convert.
724
        /// @return the local index corresponding to the given global index.
725
        private int localize(int globalIndex) {
726 2 1. localize : changed conditional boundary → NO_COVERAGE
2. localize : negated conditional → NO_COVERAGE
            if (globalIndex < startIndex) return 0;
727 3 1. localize : changed conditional boundary → NO_COVERAGE
2. localize : replaced int return with 0 for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::localize → NO_COVERAGE
3. localize : negated conditional → NO_COVERAGE
            else if (globalIndex > endIndex()) return length();
728 2 1. localize : replaced int return with 0 for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::localize → NO_COVERAGE
2. localize : Replaced integer subtraction with addition → NO_COVERAGE
            else return globalIndex - startIndex;
729
        }
730
731
        /// Gets the start index of this run.
732
        ///
733
        /// @return the start index of the run relative to the containing
734
        /// paragraph.
735
        @Override
736
        public int startIndex() {
737
            return startIndex;
738
        }
739
740
        /// Gets the underlying run object.
741
        ///
742
        /// @return the [R] run object.
743
        @Override
744
        public R run() {
745
            return run;
746
        }
747
    }
748
}

Mutations

68

1.1
Location : getFirstParentWithClass
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : getFirstParentWithClass
Killed by : none
negated conditional → NO_COVERAGE

69

1.1
Location : getFirstParentWithClass
Killed by : none
Changed increment from 1 to -1 → NO_COVERAGE

70

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

71

1.1
Location : getFirstParentWithClass
Killed by : none
replaced return value with Optional.empty for pro/verron/officestamper/utils/wml/WmlUtils::getFirstParentWithClass → NO_COVERAGE

2.2
Location : getFirstParentWithClass
Killed by : none
negated conditional → NO_COVERAGE

72

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

86

1.1
Location : extractCommentElements
Killed by : none
removed call to org/docx4j/TraversalUtil::visit → NO_COVERAGE

87

1.1
Location : extractCommentElements
Killed by : none
replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils::extractCommentElements → NO_COVERAGE

103

1.1
Location : findComment
Killed by : none
replaced return value with Optional.empty for pro/verron/officestamper/utils/wml/WmlUtils::findComment → NO_COVERAGE

108

1.1
Location : getComments
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::getComments → NO_COVERAGE

115

1.1
Location : idEqual
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::idEqual → NO_COVERAGE

117

1.1
Location : lambda$idEqual$0
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::lambda$idEqual$0 → NO_COVERAGE

2.2
Location : lambda$idEqual$0
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::lambda$idEqual$0 → NO_COVERAGE

134

1.1
Location : remove
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::remove → NO_COVERAGE

135

1.1
Location : remove
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::remove → NO_COVERAGE

136

1.1
Location : remove
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::remove → NO_COVERAGE

137

1.1
Location : remove
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::remove → NO_COVERAGE

140

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

2.2
Location : remove
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::ensureValidity → NO_COVERAGE

146

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

147

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

148

1.1
Location : remove
Killed by : none
removed call to java/util/ListIterator::remove → NO_COVERAGE

173

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

174

1.1
Location : ensureValidity
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::addEmptyParagraph → NO_COVERAGE

179

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

180

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

181

1.1
Location : equals
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::equals → NO_COVERAGE

2.2
Location : equals
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::equals → NO_COVERAGE

185

1.1
Location : lambda$containsAnElementOfAnyClasses$0
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::lambda$containsAnElementOfAnyClasses$0 → NO_COVERAGE

2.2
Location : containsAnElementOfAnyClasses
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::containsAnElementOfAnyClasses → NO_COVERAGE

3.3
Location : containsAnElementOfAnyClasses
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::containsAnElementOfAnyClasses → NO_COVERAGE

4.4
Location : lambda$containsAnElementOfAnyClasses$0
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::lambda$containsAnElementOfAnyClasses$0 → NO_COVERAGE

196

1.1
Location : isAnElementOfAnyClasses
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::isAnElementOfAnyClasses → NO_COVERAGE

2.2
Location : isAnElementOfAnyClasses
Killed by : none
negated conditional → NO_COVERAGE

198

1.1
Location : isAnElementOfAnyClasses
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::isAnElementOfAnyClasses → NO_COVERAGE

202

1.1
Location : unwrapJAXBElement
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::unwrapJAXBElement → NO_COVERAGE

2.2
Location : unwrapJAXBElement
Killed by : none
negated conditional → NO_COVERAGE

220

1.1
Location : asString
Killed by : none
replaced return value with "" for pro/verron/officestamper/utils/wml/WmlUtils::asString → NO_COVERAGE

223

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

225

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

230

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

231

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

232

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

233

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

237

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

2.2
Location : asString
Killed by : none
negated conditional → NO_COVERAGE

3.3
Location : asString
Killed by : none
negated conditional → NO_COVERAGE

4.4
Location : asString
Killed by : none
negated conditional → NO_COVERAGE

242

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

2.2
Location : asString
Killed by : none
negated conditional → NO_COVERAGE

248

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

2.2
Location : asString
Killed by : none
negated conditional → NO_COVERAGE

251

1.1
Location : asString
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

266

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

2.2
Location : asString
Killed by : none
replaced return value with "" for pro/verron/officestamper/utils/wml/WmlUtils::asString → NO_COVERAGE

280

1.1
Location : insertSmartTag
Killed by : none
removed call to java/util/Optional::ifPresent → NO_COVERAGE

281

1.1
Location : insertSmartTag
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::replace → NO_COVERAGE

295

1.1
Location : lambda$findFirstAffectedRunPr$0
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::lambda$findFirstAffectedRunPr$0 → NO_COVERAGE

2.2
Location : lambda$findFirstAffectedRunPr$0
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::lambda$findFirstAffectedRunPr$0 → NO_COVERAGE

299

1.1
Location : findFirstAffectedRunPr
Killed by : none
replaced return value with Optional.empty for pro/verron/officestamper/utils/wml/WmlUtils::findFirstAffectedRunPr → NO_COVERAGE

312

1.1
Location : lambda$replace$0
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::lambda$replace$0 → NO_COVERAGE

2.2
Location : lambda$replace$0
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::lambda$replace$0 → NO_COVERAGE

319

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

320

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

321

1.1
Location : replace
Killed by : none
Replaced integer subtraction with addition → NO_COVERAGE

2.2
Location : replace
Killed by : none
negated conditional → NO_COVERAGE

322

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

323

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

324

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

2.2
Location : replace
Killed by : none
changed conditional boundary → NO_COVERAGE

3.3
Location : replace
Killed by : none
negated conditional → NO_COVERAGE

4.4
Location : replace
Killed by : none
changed conditional boundary → NO_COVERAGE

326

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

327

1.1
Location : replace
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::replace → NO_COVERAGE

329

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

330

1.1
Location : replace
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::replace → NO_COVERAGE

332

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

333

1.1
Location : replace
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::replace → NO_COVERAGE

334

1.1
Location : replace
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

335

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

345

1.1
Location : replace
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::removeExpression → NO_COVERAGE

347

1.1
Location : replace
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

358

1.1
Location : create
Killed by : none
removed call to org/docx4j/wml/R::setRPr → NO_COVERAGE

359

1.1
Location : create
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::create → NO_COVERAGE

367

1.1
Location : wrap
Killed by : none
replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils::wrap → NO_COVERAGE

372

1.1
Location : removeExpression
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::replace → NO_COVERAGE

375

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

2.2
Location : removeExpression
Killed by : none
negated conditional → NO_COVERAGE

380

1.1
Location : removeExpression
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::replace → NO_COVERAGE

391

1.1
Location : create
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::applyParagraphStyle → NO_COVERAGE

392

1.1
Location : create
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::create → NO_COVERAGE

401

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

403

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

406

1.1
Location : applyParagraphStyle
Killed by : none
removed call to org/docx4j/wml/R::setRPr → NO_COVERAGE

414

1.1
Location : setText
Killed by : none
removed call to java/util/List::clear → NO_COVERAGE

430

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

432

1.1
Location : replaceExpressionWithRun
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

433

1.1
Location : replaceExpressionWithRun
Killed by : none
removed call to java/util/Optional::ifPresent → NO_COVERAGE

434

1.1
Location : replaceExpressionWithRun
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::replace → NO_COVERAGE

446

1.1
Location : isTagElement
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::isTagElement → NO_COVERAGE

2.2
Location : isTagElement
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::isTagElement → NO_COVERAGE

461

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

463

1.1
Location : setTagAttribute
Killed by : none
removed call to org/docx4j/wml/CTSmartTagRun::setSmartTagPr → NO_COVERAGE

466

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

468

1.1
Location : setTagAttribute
Killed by : none
removed call to org/docx4j/wml/CTSmartTagRun::setSmartTagPr → NO_COVERAGE

471

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

472

1.1
Location : setTagAttribute
Killed by : none
removed call to org/docx4j/wml/CTAttr::setVal → NO_COVERAGE

486

1.1
Location : newAttribute
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::newAttribute → NO_COVERAGE

498

1.1
Location : lambda$findAll$0
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::lambda$findAll$0 → NO_COVERAGE

2.2
Location : lambda$findAll$0
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::lambda$findAll$0 → NO_COVERAGE

500

1.1
Location : findAll
Killed by : none
removed call to java/util/List::forEach → NO_COVERAGE

507

1.1
Location : lambda$findAll$2
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::lambda$findAll$2 → NO_COVERAGE

2.2
Location : lambda$findAll$2
Killed by : none
negated conditional → NO_COVERAGE

3.3
Location : lambda$findAll$2
Killed by : none
negated conditional → NO_COVERAGE

4.4
Location : lambda$findAll$1
Killed by : none
negated conditional → NO_COVERAGE

509

1.1
Location : lambda$findAll$1
Killed by : none
negated conditional → NO_COVERAGE

510

1.1
Location : lambda$findAll$1
Killed by : none
negated conditional → NO_COVERAGE

511

1.1
Location : lambda$findAll$1
Killed by : none
negated conditional → NO_COVERAGE

517

1.1
Location : findAll
Killed by : none
replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::findAll → NO_COVERAGE

521

1.1
Location : findAll
Killed by : none
replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::findAll → NO_COVERAGE

525

1.1
Location : findAll
Killed by : none
replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::findAll → NO_COVERAGE

529

1.1
Location : from
Killed by : none
replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils$1DeletableItems::from → NO_COVERAGE

532

1.1
Location : deleteCommentFromElements
Killed by : none
removed call to java/util/List::forEach → NO_COVERAGE

544

1.1
Location : visitDocument
Killed by : none
removed call to org/docx4j/TraversalUtil::visit → NO_COVERAGE

545

1.1
Location : lambda$visitDocument$0
Killed by : none
removed call to org/docx4j/TraversalUtil::visit → NO_COVERAGE

2.2
Location : visitDocument
Killed by : none
removed call to java/util/stream/Stream::forEach → NO_COVERAGE

546

1.1
Location : visitDocument
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::visitPartIfExists → NO_COVERAGE

547

1.1
Location : visitDocument
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::visitPartIfExists → NO_COVERAGE

551

1.1
Location : streamHeaderFooterPart
Killed by : none
replaced return value with Stream.empty for pro/verron/officestamper/utils/wml/WmlUtils::streamHeaderFooterPart → NO_COVERAGE

559

1.1
Location : lambda$visitPartIfExists$0
Killed by : none
removed call to org/docx4j/TraversalUtil::visit → NO_COVERAGE

2.2
Location : visitPartIfExists
Killed by : none
removed call to java/util/Optional::ifPresent → NO_COVERAGE

564

1.1
Location : extractHeaderFooterParts
Killed by : none
removed call to java/util/Optional::ifPresent → NO_COVERAGE

565

1.1
Location : extractHeaderFooterParts
Killed by : none
removed call to java/util/Optional::ifPresent → NO_COVERAGE

566

1.1
Location : extractHeaderFooterParts
Killed by : none
removed call to java/util/Optional::ifPresent → NO_COVERAGE

567

1.1
Location : extractHeaderFooterParts
Killed by : none
removed call to java/util/Optional::ifPresent → NO_COVERAGE

568

1.1
Location : extractHeaderFooterParts
Killed by : none
removed call to java/util/Optional::ifPresent → NO_COVERAGE

569

1.1
Location : extractHeaderFooterParts
Killed by : none
removed call to java/util/Optional::ifPresent → NO_COVERAGE

570

1.1
Location : extractHeaderFooterParts
Killed by : none
replaced return value with Stream.empty for pro/verron/officestamper/utils/wml/WmlUtils::extractHeaderFooterParts → NO_COVERAGE

575

1.1
Location : extractContent
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils::extractContent → NO_COVERAGE

593

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

2.2
Location : hasTagAttribute
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::hasTagAttribute → NO_COVERAGE

3.3
Location : hasTagAttribute
Killed by : none
replaced boolean return with false for pro/verron/officestamper/utils/wml/WmlUtils::hasTagAttribute → NO_COVERAGE

594

1.1
Location : hasTagAttribute
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils::hasTagAttribute → NO_COVERAGE

612

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

616

1.1
Location : wrap
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

618

1.1
Location : wrap
Killed by : none
replaced return value with Collections.emptyList for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::wrap → NO_COVERAGE

625

1.1
Location : length
Killed by : none
replaced int return with 0 for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::length → NO_COVERAGE

632

1.1
Location : getText
Killed by : none
replaced return value with "" for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::getText → NO_COVERAGE

639

1.1
Location : getPr
Killed by : none
replaced return value with null for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::getPr → NO_COVERAGE

652

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

2.2
Location : isTouchedByRange
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::isTouchedByRange → NO_COVERAGE

3.3
Location : isTouchedByRange
Killed by : none
negated conditional → NO_COVERAGE

654

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

658

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

2.2
Location : startsInRange
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::startsInRange → NO_COVERAGE

3.3
Location : startsInRange
Killed by : none
changed conditional boundary → NO_COVERAGE

4.4
Location : startsInRange
Killed by : none
negated conditional → NO_COVERAGE

5.5
Location : startsInRange
Killed by : none
changed conditional boundary → NO_COVERAGE

662

1.1
Location : endsInRange
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : endsInRange
Killed by : none
negated conditional → NO_COVERAGE

3.3
Location : endsInRange
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::endsInRange → NO_COVERAGE

4.4
Location : endsInRange
Killed by : none
negated conditional → NO_COVERAGE

5.5
Location : endsInRange
Killed by : none
changed conditional boundary → NO_COVERAGE

666

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

2.2
Location : englobesRange
Killed by : none
changed conditional boundary → NO_COVERAGE

3.3
Location : englobesRange
Killed by : none
negated conditional → NO_COVERAGE

4.4
Location : englobesRange
Killed by : none
replaced boolean return with true for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::englobesRange → NO_COVERAGE

5.5
Location : englobesRange
Killed by : none
changed conditional boundary → NO_COVERAGE

674

1.1
Location : endIndex
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

2.2
Location : endIndex
Killed by : none
replaced int return with 0 for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::endIndex → NO_COVERAGE

688

1.1
Location : replace
Killed by : none
removed call to pro/verron/officestamper/utils/wml/WmlUtils::setText → NO_COVERAGE

702

1.1
Location : left
Killed by : none
replaced return value with "" for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::left → NO_COVERAGE

716

1.1
Location : right
Killed by : none
replaced return value with "" for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::right → NO_COVERAGE

726

1.1
Location : localize
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : localize
Killed by : none
negated conditional → NO_COVERAGE

727

1.1
Location : localize
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : localize
Killed by : none
replaced int return with 0 for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::localize → NO_COVERAGE

3.3
Location : localize
Killed by : none
negated conditional → NO_COVERAGE

728

1.1
Location : localize
Killed by : none
replaced int return with 0 for pro/verron/officestamper/utils/wml/WmlUtils$StandardRun::localize → NO_COVERAGE

2.2
Location : localize
Killed by : none
Replaced integer subtraction with addition → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.25.5 support