DocxIterator.java

1
package pro.verron.officestamper.utils.wml;
2
3
import org.docx4j.com.microsoft.schemas.office.word.x2010.wordprocessingShape.CTTextboxInfo;
4
import org.docx4j.com.microsoft.schemas.office.word.x2010.wordprocessingShape.CTWordprocessingShape;
5
import org.docx4j.dml.Graphic;
6
import org.docx4j.dml.GraphicData;
7
import org.docx4j.dml.wordprocessingDrawing.Anchor;
8
import org.docx4j.dml.wordprocessingDrawing.Inline;
9
import org.docx4j.mce.AlternateContent;
10
import org.docx4j.vml.CTTextbox;
11
import org.docx4j.vml.VmlShapeElements;
12
import org.docx4j.wml.*;
13
import org.jspecify.annotations.Nullable;
14
import pro.verron.officestamper.utils.iterator.ResetableIterator;
15
16
import java.util.*;
17
import java.util.function.Supplier;
18
19
import static org.docx4j.XmlUtils.unwrap;
20
21
/// An iterator that allows the traversal of objects within a
22
/// WordprocessingML-based document part. The iterator
23
/// supports nested structures, enabling iteration over content that may have
24
/// hierarchical data, like paragraphs,
25
/// structured document tags (SDTs), and runs.
26
///
27
/// This class implements the [ResetableIterator] interface, allowing for the
28
/// iteration to be reset to its initial
29
/// state, ensuring reusability of the same iterator instance.
30
public class DocxIterator
31
        implements ResetableIterator<Object> {
32
33
    private final Supplier<Iterator<Object>> supplier;
34
    private Queue<Iterator<?>> iteratorQueue;
35
    private @Nullable Object next;
36
37
    /// Creates a new [DocxIterator] instance that iterates over the content of
38
    /// the given [ContentAccessor].
39
    ///
40
    /// @param contentAccessor the content accessor whose content will be
41
    /// iterated over
42
    public DocxIterator(ContentAccessor contentAccessor) {
43
        this(contentAccessor.getContent()::iterator);
44
    }
45
46
    private DocxIterator(Supplier<Iterator<Object>> supplier) {
47
        this.supplier = supplier;
48 1 1. <init> : removed call to pro/verron/officestamper/utils/wml/DocxIterator::initialize → KILLED
        initialize();
49
    }
50
51
    private void initialize() {
52
        var startingIterator = supplier.get();
53
        this.iteratorQueue = Collections.asLifoQueue(new ArrayDeque<>());
54
        this.iteratorQueue.add(startingIterator);
55 1 1. initialize : negated conditional → KILLED
        this.next = startingIterator.hasNext()
56
                ? unwrap(startingIterator.next())
57
                : null;
58
    }
59
60
    /// Selects and casts elements of the specified class type from the
61
    /// iterator.
62
    ///
63
    /// @param aClass the class type to filter and cast elements to
64
    /// @param <T>    the type of elements to select
65
    ///
66
    /// @return a new [ResetableIterator] containing only elements of the
67
    /// specified class type
68
    public <T> ResetableIterator<T> selectClass(Class<T> aClass) {
69 1 1. selectClass : replaced return value with null for pro/verron/officestamper/utils/wml/DocxIterator::selectClass → KILLED
        return filter(aClass::isInstance).map(aClass::cast);
70
    }
71
72
    @Override
73
    public void reset() {
74 1 1. reset : removed call to pro/verron/officestamper/utils/wml/DocxIterator::initialize → KILLED
        initialize();
75
    }
76
77
    @Override
78
    public boolean hasNext() {
79 2 1. hasNext : replaced boolean return with true for pro/verron/officestamper/utils/wml/DocxIterator::hasNext → KILLED
2. hasNext : negated conditional → KILLED
        return next != null;
80
    }
81
82
83
    @Override
84
    public Object next() {
85 1 1. next : negated conditional → KILLED
        if (next == null)
86
            throw new NoSuchElementException("No more elements to iterate");
87
88
        var result = next;
89
90
        next = null;
91
        switch (result) {
92
            case ContentAccessor contentAccessor -> {
93
                var content = contentAccessor.getContent();
94
                iteratorQueue.add(content.iterator());
95
            }
96
            case SdtRun sdtRun -> {
97
                var sdtContent = sdtRun.getSdtContent();
98
                var content = sdtContent.getContent();
99
                iteratorQueue.add(content.iterator());
100
            }
101
            case SdtBlock sdtBlock -> {
102
                var sdtContent = sdtBlock.getSdtContent();
103
                var content = sdtContent.getContent();
104
                iteratorQueue.add(content.iterator());
105
            }
106
            case Pict pict -> {
107
                var content = pict.getAnyAndAny();
108
                iteratorQueue.add(content.iterator());
109
            }
110
            case VmlShapeElements rr -> {
111
                var content = rr.getEGShapeElements();
112
                iteratorQueue.add(content.iterator());
113
            }
114
            case CTTextbox tb -> {
115
                var content = tb.getTxbxContent();
116
                var contentContent = content.getContent();
117
                iteratorQueue.add(contentContent.iterator());
118
            }
119
            case AlternateContent ac -> {
120
                var choiceList = ac.getChoice();
121
                iteratorQueue.add(choiceList.iterator());
122
                var fallback = ac.getFallback();
123
                var fallbackContent = fallback.getAny();
124
                iteratorQueue.add(fallbackContent.iterator());
125
            }
126
            case AlternateContent.Choice c -> {
127
                var content = c.getAny();
128
                iteratorQueue.add(content.iterator());
129
            }
130
            case Drawing d -> {
131
                var content = d.getAnchorOrInline();
132
                iteratorQueue.add(content.iterator());
133
            }
134
            case Anchor a -> {
135
                var content = List.of(a.getGraphic());
136
                iteratorQueue.add(content.iterator());
137
            }
138
            case Graphic g -> {
139
                var content = List.of(g.getGraphicData());
140
                iteratorQueue.add(content.iterator());
141
            }
142
            case GraphicData gd -> {
143
                var content = gd.getAny();
144
                iteratorQueue.add(content.iterator());
145
            }
146
            case CTWordprocessingShape ws -> {
147
                var content = List.of(ws.getTxbx());
148
                iteratorQueue.add(content.iterator());
149
            }
150
            case CTTextboxInfo ti -> {
151
                var content = List.of(ti.getTxbxContent());
152
                iteratorQueue.add(content.iterator());
153
            }
154
            case Inline i -> {
155
                var content = List.of(i.getGraphic());
156
                iteratorQueue.add(content.iterator());
157
            }
158
            default -> { /* DO NOTHING */ }
159
        }
160 2 1. next : negated conditional → KILLED
2. next : negated conditional → KILLED
        while (!iteratorQueue.isEmpty() && next == null) {
161
            var nextIterator = iteratorQueue.poll();
162 1 1. next : negated conditional → KILLED
            if (nextIterator.hasNext()) {
163
                next = unwrap(nextIterator.next());
164
                iteratorQueue.add(nextIterator);
165
            }
166
        }
167 1 1. next : replaced return value with null for pro/verron/officestamper/utils/wml/DocxIterator::next → KILLED
        return result;
168
    }
169
}

Mutations

48

1.1
Location : <init>
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testHasNextReturnsTrueWhenThereIsElement()]
removed call to pro/verron/officestamper/utils/wml/DocxIterator::initialize → KILLED

55

1.1
Location : initialize
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testHasNextReturnsTrueWhenThereIsElement()]
negated conditional → KILLED

69

1.1
Location : selectClass
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testSelectClassFiltersElementsByType()]
replaced return value with null for pro/verron/officestamper/utils/wml/DocxIterator::selectClass → KILLED

74

1.1
Location : reset
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testResetResetsToInitialState()]
removed call to pro/verron/officestamper/utils/wml/DocxIterator::initialize → KILLED

79

1.1
Location : hasNext
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testHasNextReturnsFalseWhenNoElements()]
replaced boolean return with true for pro/verron/officestamper/utils/wml/DocxIterator::hasNext → KILLED

2.2
Location : hasNext
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testHasNextReturnsTrueWhenThereIsElement()]
negated conditional → KILLED

85

1.1
Location : next
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testNextThrowsExceptionWhenNoMoreElements()]
negated conditional → KILLED

160

1.1
Location : next
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testNextHandlesSdtRunStructure()]
negated conditional → KILLED

2.2
Location : next
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testNextHandlesSdtRunStructure()]
negated conditional → KILLED

162

1.1
Location : next
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testNextHandlesSdtRunStructure()]
negated conditional → KILLED

167

1.1
Location : next
Killed by : pro.verron.officestamper.utils.wml.DocxIteratorTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.utils.wml.DocxIteratorTest]/[method:testNextHandlesSdtRunStructure()]
replaced return value with null for pro/verron/officestamper/utils/wml/DocxIterator::next → KILLED

Active mutators

Tests examined


Report generated by PIT 1.25.5 support