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 | /** | |
17 | * Represents a textual part of a DOCX document, encapsulating the content and structure of | |
18 | * the part while enabling various operations such as accessing paragraphs, runs, and related parts. | |
19 | * This class functions as a concrete implementation of the {@code DocxPart} interface. | |
20 | * It manages the association with the XML structure of a DOCX document. | |
21 | */ | |
22 | public final class TextualDocxPart | |
23 | implements DocxPart { | |
24 | private final WordprocessingMLPackage document; | |
25 | private final Part part; | |
26 | private final ContentAccessor contentAccessor; | |
27 | ||
28 | /** | |
29 | * Constructs a {@code TextualDocxPart} using the provided {@code document}. | |
30 | * This constructor initializes the instance with the main document part and content accessor | |
31 | * derived from the provided {@code WordprocessingMLPackage}. | |
32 | * | |
33 | * @param document the WordprocessingMLPackage representing the document to be processed. | |
34 | */ | |
35 | public TextualDocxPart(WordprocessingMLPackage document) { | |
36 | this(document, document.getMainDocumentPart(), document.getMainDocumentPart()); | |
37 | } | |
38 | ||
39 | /** | |
40 | * Constructs a {@code TextualDocxPart} using the specified {@code document}, {@code part}, | |
41 | * and {@code contentAccessor}. | |
42 | * | |
43 | * @param document the WordprocessingMLPackage representing the document to be processed. | |
44 | * @param part the specific part of the document being processed. | |
45 | * @param contentAccessor the content accessor associated with the document part. | |
46 | */ | |
47 | public TextualDocxPart(WordprocessingMLPackage document, Part part, ContentAccessor contentAccessor) { | |
48 | this.document = document; | |
49 | this.part = part; | |
50 | this.contentAccessor = contentAccessor; | |
51 | } | |
52 | ||
53 | /** | |
54 | * Returns the WordprocessingMLPackage instance representing the document | |
55 | * associated with this part. | |
56 | * | |
57 | * @return the WordprocessingMLPackage instance representing the document. | |
58 | */ | |
59 |
1
1. document : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::document → KILLED |
public WordprocessingMLPackage document() {return document;} |
60 | ||
61 | /** | |
62 | * Streams the parts of the document that match the specified relationship type, converting them | |
63 | * into instances of {@link TextualDocxPart}. | |
64 | * | |
65 | * @param type the type of relationship to filter and stream parts for. | |
66 | * @return a stream of {@link DocxPart} instances representing the filtered and processed parts | |
67 | * of the document. | |
68 | */ | |
69 | public Stream<DocxPart> streamParts(String type) { | |
70 |
1
1. streamParts : replaced return value with Stream.empty for pro/verron/officestamper/core/TextualDocxPart::streamParts → KILLED |
return document.getMainDocumentPart() |
71 | .getRelationshipsPart() | |
72 | .getRelationshipsByType(type) | |
73 | .stream() | |
74 | .map(this::getPart) | |
75 |
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)); |
76 | } | |
77 | ||
78 | /** | |
79 | * Retrieves the part associated with the specified relationship from the relationships part. | |
80 | * | |
81 | * @param r the relationship for which the associated part is to be retrieved. | |
82 | * @return the part corresponding to the given relationship. | |
83 | */ | |
84 | public Part getPart(Relationship r) { | |
85 |
1
1. getPart : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::getPart → KILLED |
return getRelationshipsPart().getPart(r); |
86 | } | |
87 | ||
88 | private RelationshipsPart getRelationshipsPart() { | |
89 |
1
1. getRelationshipsPart : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::getRelationshipsPart → KILLED |
return part().getRelationshipsPart(); |
90 | } | |
91 | ||
92 | @Override | |
93 |
1
1. part : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::part → KILLED |
public Part part() {return part;} |
94 | ||
95 | @Override | |
96 | public DocxPart from(ContentAccessor accessor) { | |
97 |
1
1. from : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::from → NO_COVERAGE |
return new TextualDocxPart(document, part, accessor); |
98 | } | |
99 | ||
100 | @Override | |
101 |
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();} |
102 | ||
103 | /** | |
104 | * Streams all paragraphs contained in the document's main content or structured document tags (SDT). | |
105 | * The paragraphs are processed and transformed into instances of {@link Paragraph}. | |
106 | * This method combines paragraphs directly present in the document and paragraphs within SDT runs. | |
107 | * | |
108 | * @return a stream of {@link Paragraph} objects representing the paragraphs found within the document. | |
109 | */ | |
110 | public Stream<Paragraph> streamParagraphs() { | |
111 |
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) |
112 |
1
1. lambda$streamParagraphs$1 : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::lambda$streamParagraphs$1 → KILLED |
.map(p -> StandardParagraph.from(this, p)), |
113 | DocumentUtil.streamObjectElements(this, SdtRun.class) | |
114 | .map(SdtRun::getSdtContent) | |
115 | .filter(CTSdtContentRun.class::isInstance) | |
116 | .map(CTSdtContentRun.class::cast) | |
117 |
1
1. lambda$streamParagraphs$2 : replaced return value with null for pro/verron/officestamper/core/TextualDocxPart::lambda$streamParagraphs$2 → KILLED |
.map(paragraph -> StandardParagraph.from(this, paragraph))); |
118 | } | |
119 | ||
120 | @Override | |
121 | public Stream<R> streamRun() { | |
122 |
1
1. streamRun : replaced return value with Stream.empty for pro/verron/officestamper/core/TextualDocxPart::streamRun → KILLED |
return DocumentUtil.streamObjectElements(this, P.class) |
123 | .map(P::getContent) | |
124 | .flatMap(Collection::stream) | |
125 | .filter(R.class::isInstance) | |
126 | .map(R.class::cast); | |
127 | } | |
128 | ||
129 | @Override | |
130 | public int hashCode() { | |
131 |
1
1. hashCode : replaced int return with 0 for pro/verron/officestamper/core/TextualDocxPart::hashCode → NO_COVERAGE |
return Objects.hash(document, part, contentAccessor); |
132 | } | |
133 | ||
134 | @Override | |
135 | public boolean equals(Object obj) { | |
136 |
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; |
137 |
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; |
138 | var that = (TextualDocxPart) obj; | |
139 |
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( |
140 | this.contentAccessor, | |
141 | that.contentAccessor); | |
142 | } | |
143 | ||
144 | @Override | |
145 | public String toString() { | |
146 |
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()); |
147 | } | |
148 | ||
149 | } | |
Mutations | ||
59 |
1.1 |
|
70 |
1.1 |
|
75 |
1.1 |
|
85 |
1.1 |
|
89 |
1.1 |
|
93 |
1.1 |
|
97 |
1.1 |
|
101 |
1.1 |
|
111 |
1.1 |
|
112 |
1.1 |
|
117 |
1.1 |
|
122 |
1.1 |
|
131 |
1.1 |
|
136 |
1.1 2.2 |
|
137 |
1.1 2.2 3.3 |
|
139 |
1.1 2.2 3.3 4.4 |
|
146 |
1.1 |