RunUtil.java

1
package pro.verron.officestamper.core;
2
3
import jakarta.xml.bind.JAXBElement;
4
import org.docx4j.model.styles.StyleUtil;
5
import org.docx4j.wml.*;
6
import org.slf4j.Logger;
7
import org.slf4j.LoggerFactory;
8
import org.springframework.lang.Nullable;
9
import pro.verron.officestamper.api.OfficeStamperException;
10
11
import java.util.Objects;
12
13
import static java.util.stream.Collectors.joining;
14
import static pro.verron.officestamper.utils.WmlFactory.newRun;
15
import static pro.verron.officestamper.utils.WmlFactory.newText;
16
17
/**
18
 * Utility class to handle runs.
19
 *
20
 * @author Joseph Verron
21
 * @author Tom Hombergs
22
 * @version ${version}
23
 * @since 1.0.0
24
 */
25
public class RunUtil {
26
27
28
    private static final String PRESERVE = "preserve";
29
    private static final Logger log = LoggerFactory.getLogger(RunUtil.class);
30
31
    private RunUtil() {
32
        throw new OfficeStamperException("Utility class shouldn't be instantiated");
33
    }
34
35
    /**
36
     * Extracts textual content from a given object, handling various object types,
37
     * such as runs, text elements, and other specific constructs.
38
     * The method accounts for different cases, such as run breaks, hyphens,
39
     * and other document-specific constructs, and converts them into
40
     * corresponding string representations.
41
     *
42
     * @param content the object from which text content is to be extracted.
43
     *                This could be of various types such as R, JAXBElement, Text,
44
     *                or specific document elements.
45
     *
46
     * @return a string representation of the extracted textual content.
47
     * If the object's type is not handled, an empty string is returned.
48
     */
49
    public static String getText(Object content) {
50 1 1. getText : replaced return value with "" for pro/verron/officestamper/core/RunUtil::getText → KILLED
        return switch (content) {
51
            case R run -> run.getContent()
52
                             .stream()
53
                             .map(RunUtil::getText)
54
                             .collect(joining());
55
            case JAXBElement<?> jaxbElement when jaxbElement.getName()
56
                                                            .getLocalPart()
57 1 1. getText : negated conditional → KILLED
                                                            .equals("instrText") -> "<instrText>";
58
            case JAXBElement<?> jaxbElement when !jaxbElement.getName()
59
                                                             .getLocalPart()
60 1 1. getText : negated conditional → KILLED
                                                             .equals("instrText") -> getText(jaxbElement.getValue());
61
            case Text text -> getText(text);
62
            case R.Tab ignored -> "\t";
63
            case R.Cr ignored -> "\n";
64 1 1. getText : negated conditional → KILLED
            case Br br when br.getType() == null -> "\n";
65 1 1. getText : negated conditional → SURVIVED
            case Br br when br.getType() == STBrType.TEXT_WRAPPING -> "\n";
66 1 1. getText : negated conditional → SURVIVED
            case Br br when br.getType() == STBrType.PAGE -> "\n";
67 1 1. getText : negated conditional → NO_COVERAGE
            case Br br when br.getType() == STBrType.COLUMN -> "\n";
68
            case R.NoBreakHyphen ignored -> "‑";
69
            case R.SoftHyphen ignored -> "\u00AD";
70
            case R.LastRenderedPageBreak ignored -> "";
71
            case R.AnnotationRef ignored -> "";
72
            case R.CommentReference ignored -> "";
73
            case Drawing ignored -> "";
74
            case FldChar ignored -> "<fldchar>";
75
            case CTFtnEdnRef ref -> ref.getId()
76
                                       .toString();
77
            case R.Sym sym -> "<sym(%s, %s)>".formatted(sym.getFont(), sym.getChar());
78
            default -> {
79
                log.debug("Unhandled object type: {}", content.getClass());
80
                yield "";
81
            }
82
        };
83
    }
84
85
    /**
86
     * Processes and retrieves text content from a given Text object.
87
     * It handles situations where the text may or may not preserve spaces,
88
     * trimming the text if spaces are not to be preserved.
89
     *
90
     * @param text the Text object from which the value is to be processed and returned.
91
     *             The object contains the textual value, and an associated space property
92
     *             that determines if spaces should be preserved.
93
     *
94
     * @return a processed string value from the Text object.
95
     * If spaces are to be preserved, the original value is returned;
96
     * otherwise, the value is trimmed of leading and trailing spaces.
97
     */
98
    private static String getText(Text text) {
99
        var value = text.getValue();
100
        var space = text.getSpace();
101 2 1. getText : negated conditional → KILLED
2. getText : replaced return value with "" for pro/verron/officestamper/core/RunUtil::getText → KILLED
        return Objects.equals(space, PRESERVE) ? value : value.trim();
102
    }
103
104
    /**
105
     * Creates a new run with the specified text and inherits the style of the parent paragraph.
106
     *
107
     * @param text the initial text of the run.
108
     *
109
     * @return the newly created run.
110
     */
111
    public static R create(String text, PPr paragraphPr) {
112
        R run = newRun(text);
113 1 1. create : removed call to pro/verron/officestamper/core/RunUtil::applyParagraphStyle → NO_COVERAGE
        applyParagraphStyle(run, paragraphPr);
114 1 1. create : replaced return value with null for pro/verron/officestamper/core/RunUtil::create → NO_COVERAGE
        return run;
115
    }
116
117
    /**
118
     * Applies the style of the given paragraph to the given content object (if the content object is a Run).
119
     *
120
     * @param run the Run to which the style should be applied.
121
     */
122
    public static void applyParagraphStyle(R run, @Nullable PPr paragraphPr) {
123 1 1. applyParagraphStyle : negated conditional → NO_COVERAGE
        if (paragraphPr == null) return;
124
        var runPr = paragraphPr.getRPr();
125 1 1. applyParagraphStyle : negated conditional → NO_COVERAGE
        if (runPr == null) return;
126
        RPr runProperties = new RPr();
127
        StyleUtil.apply(runPr, runProperties);
128 1 1. applyParagraphStyle : removed call to org/docx4j/wml/R::setRPr → NO_COVERAGE
        run.setRPr(runProperties);
129
    }
130
131
    /**
132
     * Sets the text of the given run to the given value.
133
     *
134
     * @param run  the run whose text to change.
135
     * @param text the text to set.
136
     */
137
    public static void setText(R run, String text) {
138
        run.getContent()
139 1 1. setText : removed call to java/util/List::clear → KILLED
           .clear();
140
        Text textObj = newText(text);
141
        run.getContent()
142
           .add(textObj);
143
    }
144
145
    static R create(String text, RPr rPr) {
146
        R newStartRun = newRun(text);
147 1 1. create : removed call to org/docx4j/wml/R::setRPr → SURVIVED
        newStartRun.setRPr(rPr);
148 1 1. create : replaced return value with null for pro/verron/officestamper/core/RunUtil::create → KILLED
        return newStartRun;
149
    }
150
}

Mutations

50

1.1
Location : getText
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:#29]
replaced return value with "" for pro/verron/officestamper/core/RunUtil::getText → KILLED

57

1.1
Location : getText
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:#29]
negated conditional → KILLED

60

1.1
Location : getText
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:#29]
negated conditional → KILLED

64

1.1
Location : getText
Killed by : pro.verron.officestamper.test.CustomFunctionTests.[engine:junit-jupiter]/[class:pro.verron.officestamper.test.CustomFunctionTests]/[test-template:interfaces(pro.verron.officestamper.test.ContextFactory)]/[test-template-invocation:#2]
negated conditional → KILLED

65

1.1
Location : getText
Killed by : none
negated conditional → SURVIVED
Covering tests

66

1.1
Location : getText
Killed by : none
negated conditional → SURVIVED
Covering tests

67

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

101

1.1
Location : getText
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:#27]
negated conditional → KILLED

2.2
Location : getText
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:#29]
replaced return value with "" for pro/verron/officestamper/core/RunUtil::getText → KILLED

113

1.1
Location : create
Killed by : none
removed call to pro/verron/officestamper/core/RunUtil::applyParagraphStyle → NO_COVERAGE

114

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

123

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

125

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

128

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

139

1.1
Location : setText
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:#28]
removed call to java/util/List::clear → KILLED

147

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

148

1.1
Location : create
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:#23]
replaced return value with null for pro/verron/officestamper/core/RunUtil::create → KILLED

Active mutators

Tests examined


Report generated by PIT 1.20.0