TextualDocxPart.java

1
package pro.verron.officestamper.core;
2
3
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
4
import org.docx4j.openpackaging.parts.Part;
5
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
6
import org.docx4j.relationships.Relationship;
7
import org.docx4j.wml.*;
8
import pro.verron.officestamper.api.DocxPart;
9
import pro.verron.officestamper.api.Paragraph;
10
11
import java.util.Collection;
12
import java.util.List;
13
import java.util.Objects;
14
import java.util.stream.Stream;
15
16
/// Represents a textual part of a DOCX document, encapsulating the content and structure of
17
/// the part while enabling various operations such as accessing paragraphs, runs, and related parts.
18
/// This class functions as a concrete implementation of the `DocxPart` interface.
19
/// It manages the association with the XML structure of a DOCX document.
20
public final class TextualDocxPart
21
        implements DocxPart {
22
    private final WordprocessingMLPackage document;
23
    private final Part part;
24
    private final ContentAccessor contentAccessor;
25
26
    /// Constructs a `TextualDocxPart` using the provided `document`.
27
    /// This constructor initializes the instance with the main document part and content accessor
28
    /// derived from the provided `WordprocessingMLPackage`.
29
    ///
30
    /// @param document the WordprocessingMLPackage representing the document to be processed.
31
    public TextualDocxPart(WordprocessingMLPackage document) {
32
        this(document, document.getMainDocumentPart(), document.getMainDocumentPart());
33
    }
34
35
    /// Constructs a `TextualDocxPart` using the specified `document`, `part`,
36
    /// and `contentAccessor`.
37
    ///
38
    /// @param document       the WordprocessingMLPackage representing the document to be processed.
39
    /// @param part           the specific part of the document being processed.
40
    /// @param contentAccessor the content accessor associated with the document part.
41
    public TextualDocxPart(WordprocessingMLPackage document, Part part, ContentAccessor contentAccessor) {
42
        this.document = document;
43
        this.part = part;
44
        this.contentAccessor = contentAccessor;
45
    }
46
47
    /// Returns the WordprocessingMLPackage instance representing the document
48
    /// associated with this part.
49
    ///
50
    /// @return the WordprocessingMLPackage instance representing the document.
51 1 1. document : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::document → KILLED
    public WordprocessingMLPackage document() {return document;}
52
53
    /// Streams the parts of the document that match the specified relationship type, converting them
54
    /// into instances of [TextualDocxPart].
55
    ///
56
    /// @param type the type of relationship to filter and stream parts for.
57
    /// @return a stream of [DocxPart] instances representing the filtered and processed parts
58
    ///         of the document.
59
    public Stream<DocxPart> streamParts(String type) {
60 1 1. streamParts : replaced return value with Stream.empty for pro/verron/officestamper/core/TextualDocxPart::streamParts → KILLED
        return document.getMainDocumentPart()
61
                       .getRelationshipsPart()
62
                       .getRelationshipsByType(type)
63
                       .stream()
64
                       .map(this::getPart)
65 1 1. lambda$streamParts$0 : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::lambda$streamParts$0 → KILLED
                       .map(p -> new TextualDocxPart(document, p, (ContentAccessor) p));
66
    }
67
68
    /// Retrieves the part associated with the specified relationship from the relationships part.
69
    ///
70
    /// @param r the relationship for which the associated part is to be retrieved.
71
    /// @return the part corresponding to the given relationship.
72
    public Part getPart(Relationship r) {
73 1 1. getPart : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::getPart → KILLED
        return getRelationshipsPart().getPart(r);
74
    }
75
76
    private RelationshipsPart getRelationshipsPart() {
77 1 1. getRelationshipsPart : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::getRelationshipsPart → KILLED
        return part().getRelationshipsPart();
78
    }
79
80
    /// Retrieves the part associated with this instance of the document part.
81
    ///
82
    /// @return the Part object representing the specific part associated with this instance.
83
    @Override
84 1 1. part : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::part → KILLED
    public Part part() {return part;}
85
86
    /// Creates a new instance of [DocxPart] using the provided [ContentAccessor].
87
    ///
88
    /// @param accessor the content accessor associated with the document part to derive a new instance.
89
    /// @return a new instance of [DocxPart], specifically a [TextualDocxPart],
90
    ///         initialized with the given content accessor.
91
    @Override
92
    public DocxPart from(ContentAccessor accessor) {
93 1 1. from : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::from → NO_COVERAGE
        return new TextualDocxPart(document, part, accessor);
94
    }
95
96
    /// Retrieves the list of content objects associated with this document part.
97
    ///
98
    /// @return a list of objects representing the content of the document part.
99
    @Override
100 1 1. content : replaced return value with Collections.emptyList for pro/verron/officestamper/core/TextualDocxPart::content → NO_COVERAGE
    public List<Object> content() {return contentAccessor.getContent();}
101
102
    /// Streams all paragraphs contained in the document's main content or structured document tags (SDT).
103
    /// The paragraphs are processed and transformed into instances of [Paragraph].
104
    /// This method combines paragraphs directly present in the document and paragraphs within SDT runs.
105
    ///
106
    /// @return a stream of [Paragraph] objects representing the paragraphs found within the document.
107
    public Stream<Paragraph> streamParagraphs() {
108 1 1. streamParagraphs : replaced return value with Stream.empty for pro/verron/officestamper/core/TextualDocxPart::streamParagraphs → KILLED
        return Stream.concat(DocumentUtil.streamObjectElements(this, P.class)
109 1 1. lambda$streamParagraphs$0 : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::lambda$streamParagraphs$0 → KILLED
                                         .map(p -> StandardParagraph.from(this, p)),
110
                DocumentUtil.streamObjectElements(this, SdtRun.class)
111
                            .map(SdtRun::getSdtContent)
112
                            .filter(CTSdtContentRun.class::isInstance)
113
                            .map(CTSdtContentRun.class::cast)
114 1 1. lambda$streamParagraphs$1 : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::lambda$streamParagraphs$1 → KILLED
                            .map(paragraph -> StandardParagraph.from(this, paragraph)));
115
    }
116
117
    /// Streams and processes the run elements contained within the document part.
118
    /// The method filters object elements within the document content, ensuring only
119
    /// elements of type `R` are included in the result. It achieves this by mapping
120
    /// and casting elements of type `P` and further processing their content.
121
    ///
122
    /// @return a stream of `R` instances derived from the document's run elements.
123
    @Override
124
    public Stream<R> streamRun() {
125 1 1. streamRun : replaced return value with Stream.empty for pro/verron/officestamper/core/TextualDocxPart::streamRun → SURVIVED
        return DocumentUtil.streamObjectElements(this, P.class)
126
                           .map(P::getContent)
127
                           .flatMap(Collection::stream)
128
                           .filter(R.class::isInstance)
129
                           .map(R.class::cast);
130
    }
131
132
    /// Computes the hash code for this object based on the `document`, `part`,
133
    /// and `contentAccessor` fields.
134
    ///
135
    /// @return an integer value representing the hash code of this object.
136
    @Override
137
    public int hashCode() {
138 1 1. hashCode : replaced int return with 0 for pro/verron/officestamper/core/TextualDocxPart::hashCode → NO_COVERAGE
        return Objects.hash(document, part, contentAccessor);
139
    }
140
141
    /// Compares this object with the specified object for equality. The comparison is based on
142
    /// the `document`, `part`, and `contentAccessor` fields of both objects.
143
    ///
144
    /// @param obj the object to be compared for equality with this instance.
145
    /// @return true if the specified object is equal to this object; false otherwise.
146
    @Override
147
    public boolean equals(Object obj) {
148 2 1. equals : replaced boolean return with false for pro/verron/officestamper/core/TextualDocxPart::equals → NO_COVERAGE
2. equals : negated conditional → NO_COVERAGE
        if (obj == this) return true;
149 3 1. equals : negated conditional → NO_COVERAGE
2. equals : negated conditional → NO_COVERAGE
3. equals : replaced boolean return with true for pro/verron/officestamper/core/TextualDocxPart::equals → NO_COVERAGE
        if (obj == null || obj.getClass() != this.getClass()) return false;
150
        var that = (TextualDocxPart) obj;
151 4 1. equals : negated conditional → NO_COVERAGE
2. equals : negated conditional → NO_COVERAGE
3. equals : replaced boolean return with true for pro/verron/officestamper/core/TextualDocxPart::equals → NO_COVERAGE
4. equals : negated conditional → NO_COVERAGE
        return Objects.equals(this.document, that.document) && Objects.equals(this.part, that.part) && Objects.equals(
152
                this.contentAccessor,
153
                that.contentAccessor);
154
    }
155
156
    /// Converts this instance of the `TextualDocxPart` class to its string representation.
157
    /// The string representation includes the name of the document and the name of the part
158
    /// associated with this instance.
159
    ///
160
    /// @return a string representation of this instance, including the document name
161
    ///         and part name formatted as "DocxPart{doc=%s, part=%s}".
162
    @Override
163
    public String toString() {
164 1 1. toString : replaced return value with "" for pro/verron/officestamper/core/TextualDocxPart::toString → NO_COVERAGE
        return "DocxPart{doc=%s, part=%s}".formatted(document.name(), part.getPartName());
165
    }
166
167
}

Mutations

51

1.1
Location : document
Killed by : pro.verron.officestamper.test.ResolutionTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ResolutionTest]/[test-template:testCustomResolution(java.lang.String, boolean, boolean, boolean, boolean, boolean, java.lang.String, boolean, java.lang.String)]/[test-template-invocation:#22]
replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::document → KILLED

60

1.1
Location : streamParts
Killed by : pro.verron.officestamper.test.HeaderAndFooterTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.HeaderAndFooterTest]/[test-template:placeholders(pro.verron.officestamper.test.ContextFactory)]/[test-template-invocation:#2]
replaced return value with Stream.empty for pro/verron/officestamper/core/TextualDocxPart::streamParts → KILLED

65

1.1
Location : lambda$streamParts$0
Killed by : pro.verron.officestamper.test.HeaderAndFooterTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.HeaderAndFooterTest]/[test-template:placeholders(pro.verron.officestamper.test.ContextFactory)]/[test-template-invocation:#2]
replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::lambda$streamParts$0 → KILLED

73

1.1
Location : getPart
Killed by : pro.verron.officestamper.test.HeaderAndFooterTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.HeaderAndFooterTest]/[test-template:placeholders(pro.verron.officestamper.test.ContextFactory)]/[test-template-invocation:#2]
replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::getPart → KILLED

77

1.1
Location : getRelationshipsPart
Killed by : pro.verron.officestamper.test.HeaderAndFooterTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.HeaderAndFooterTest]/[test-template:placeholders(pro.verron.officestamper.test.ContextFactory)]/[test-template-invocation:#2]
replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::getRelationshipsPart → KILLED

84

1.1
Location : part
Killed by : pro.verron.officestamper.test.ResolutionTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ResolutionTest]/[test-template:testCustomResolution(java.lang.String, boolean, boolean, boolean, boolean, boolean, java.lang.String, boolean, java.lang.String)]/[test-template-invocation:#22]
replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::part → KILLED

93

1.1
Location : from
Killed by : none
replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::from → NO_COVERAGE

100

1.1
Location : content
Killed by : none
replaced return value with Collections.emptyList for pro/verron/officestamper/core/TextualDocxPart::content → NO_COVERAGE

108

1.1
Location : streamParagraphs
Killed by : pro.verron.officestamper.test.ResolutionTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ResolutionTest]/[test-template:testCustomResolution(java.lang.String, boolean, boolean, boolean, boolean, boolean, java.lang.String, boolean, java.lang.String)]/[test-template-invocation:#22]
replaced return value with Stream.empty for pro/verron/officestamper/core/TextualDocxPart::streamParagraphs → KILLED

109

1.1
Location : lambda$streamParagraphs$0
Killed by : pro.verron.officestamper.test.ResolutionTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.ResolutionTest]/[test-template:testCustomResolution(java.lang.String, boolean, boolean, boolean, boolean, boolean, java.lang.String, boolean, java.lang.String)]/[test-template-invocation:#22]
replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::lambda$streamParagraphs$0 → KILLED

114

1.1
Location : lambda$streamParagraphs$1
Killed by : pro.verron.officestamper.test.DefaultTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.DefaultTests]/[test-template:features(java.lang.String, pro.verron.officestamper.api.OfficeStamperConfiguration, java.lang.Object, java.io.InputStream, java.lang.String)]/[test-template-invocation:#36]
replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::lambda$streamParagraphs$1 → KILLED

125

1.1
Location : streamRun
Killed by : none
replaced return value with Stream.empty for pro/verron/officestamper/core/TextualDocxPart::streamRun → SURVIVED
Covering tests

138

1.1
Location : hashCode
Killed by : none
replaced int return with 0 for pro/verron/officestamper/core/TextualDocxPart::hashCode → NO_COVERAGE

148

1.1
Location : equals
Killed by : none
replaced boolean return with false for pro/verron/officestamper/core/TextualDocxPart::equals → NO_COVERAGE

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

149

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

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

3.3
Location : equals
Killed by : none
replaced boolean return with true for pro/verron/officestamper/core/TextualDocxPart::equals → NO_COVERAGE

151

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

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

3.3
Location : equals
Killed by : none
replaced boolean return with true for pro/verron/officestamper/core/TextualDocxPart::equals → NO_COVERAGE

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

164

1.1
Location : toString
Killed by : none
replaced return value with "" for pro/verron/officestamper/core/TextualDocxPart::toString → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.21.0