StemmerDictionaryParser.java

1
/*******************************************************************************
2
 * Copyright (C) 2026, Leo Galambos
3
 * All rights reserved.
4
 * 
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 * 
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 
11
 * 2. Redistributions in binary form must reproduce the above copyright notice,
12
 *    this list of conditions and the following disclaimer in the documentation
13
 *    and/or other materials provided with the distribution.
14
 * 
15
 * 3. Neither the name of the copyright holder nor the names of its contributors
16
 *    may be used to endorse or promote products derived from this software
17
 *    without specific prior written permission.
18
 * 
19
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
 * POSSIBILITY OF SUCH DAMAGE.
30
 ******************************************************************************/
31
package org.egothor.stemmer;
32
33
import java.io.BufferedReader;
34
import java.io.IOException;
35
import java.io.Reader;
36
import java.nio.charset.StandardCharsets;
37
import java.nio.file.Files;
38
import java.nio.file.Path;
39
import java.util.ArrayList;
40
import java.util.List;
41
import java.util.Locale;
42
import java.util.Objects;
43
import java.util.logging.Level;
44
import java.util.logging.Logger;
45
46
/**
47
 * Parser of line-oriented stemmer dictionary files.
48
 *
49
 * <p>
50
 * Each non-empty logical line uses a tab-separated values layout. The first
51
 * column is interpreted as the canonical stem, and every following
52
 * tab-separated column on the same line is interpreted as a variant belonging
53
 * to that stem.
54
 *
55
 * <p>
56
 * Input line case normalization is controlled by {@link CaseProcessingMode}.
57
 * Leading and trailing whitespace around each column is ignored.
58
 *
59
 * <p>
60
 * The parser supports line remarks and trailing remarks. The remark markers
61
 * {@code #} and {@code //} terminate the logical content of the line, and the
62
 * remainder of that line is ignored.
63
 *
64
 * <p>
65
 * Dictionary items containing any Unicode whitespace character are currently
66
 * not supported. Such items are ignored and reported through a single
67
 * {@link Level#WARNING warning}-level log entry per physical line together with
68
 * the source line number, the normalized stem column, and the list of ignored
69
 * items from that line.
70
 *
71
 * <p>
72
 * This class is intentionally stateless and allocation-light so it can be used
73
 * both by runtime loading and by offline compilation tooling.
74
 */
75
public final class StemmerDictionaryParser {
76
77
    /**
78
     * Logger of this class.
79
     */
80
    private static final Logger LOGGER = Logger.getLogger(StemmerDictionaryParser.class.getName());
81
82
    /**
83
     * Utility class.
84
     */
85
    private StemmerDictionaryParser() {
86
        throw new AssertionError("No instances.");
87
    }
88
89
    /**
90
     * Callback receiving one parsed dictionary line.
91
     */
92
    @FunctionalInterface
93
    public interface EntryHandler {
94
95
        /**
96
         * Accepts one parsed dictionary entry.
97
         *
98
         * @param stem       canonical stem, never {@code null}
99
         * @param variants   variants in encounter order, never {@code null}
100
         * @param lineNumber original physical line number in the parsed source
101
         * @throws IOException if processing fails
102
         */
103
        void onEntry(String stem, String[] variants, int lineNumber) throws IOException;
104
    }
105
106
    /**
107
     * Parses a dictionary file from a filesystem path.
108
     *
109
     * @param path         dictionary file path
110
     * @param entryHandler handler receiving parsed entries
111
     * @return parsing statistics
112
     * @throws NullPointerException if any argument is {@code null}
113
     * @throws IOException          if reading fails
114
     */
115
    public static ParseStatistics parse(final Path path, final EntryHandler entryHandler) throws IOException {
116 1 1. parse : replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → KILLED
        return parse(path, CaseProcessingMode.LOWERCASE_WITH_LOCALE_ROOT, entryHandler);
117
    }
118
119
    /**
120
     * Parses a dictionary file from a filesystem path.
121
     *
122
     * @param path               dictionary file path
123
     * @param caseProcessingMode case processing mode
124
     * @param entryHandler       handler receiving parsed entries
125
     * @return parsing statistics
126
     * @throws NullPointerException if any argument is {@code null}
127
     * @throws IOException          if reading fails
128
     */
129
    public static ParseStatistics parse(final Path path, final CaseProcessingMode caseProcessingMode,
130
            final EntryHandler entryHandler) throws IOException {
131
        Objects.requireNonNull(path, "path");
132
        Objects.requireNonNull(caseProcessingMode, "caseProcessingMode");
133
        Objects.requireNonNull(entryHandler, "entryHandler");
134
135
        try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
136 1 1. parse : replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → KILLED
            return parse(reader, path.toAbsolutePath().toString(), caseProcessingMode, entryHandler);
137
        }
138
    }
139
140
    /**
141
     * Parses a dictionary file from a path string.
142
     *
143
     * @param fileName     dictionary file name or path string
144
     * @param entryHandler handler receiving parsed entries
145
     * @return parsing statistics
146
     * @throws NullPointerException if any argument is {@code null}
147
     * @throws IOException          if reading fails
148
     */
149
    public static ParseStatistics parse(final String fileName, final EntryHandler entryHandler) throws IOException {
150
        Objects.requireNonNull(fileName, "fileName");
151 1 1. parse : replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → KILLED
        return parse(Path.of(fileName), CaseProcessingMode.LOWERCASE_WITH_LOCALE_ROOT, entryHandler);
152
    }
153
154
    /**
155
     * Parses a dictionary file from a path string.
156
     *
157
     * @param fileName           dictionary file name or path string
158
     * @param caseProcessingMode case processing mode
159
     * @param entryHandler       handler receiving parsed entries
160
     * @return parsing statistics
161
     * @throws NullPointerException if any argument is {@code null}
162
     * @throws IOException          if reading fails
163
     */
164
    public static ParseStatistics parse(final String fileName, final CaseProcessingMode caseProcessingMode,
165
            final EntryHandler entryHandler) throws IOException {
166
        Objects.requireNonNull(fileName, "fileName");
167 1 1. parse : replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → NO_COVERAGE
        return parse(Path.of(fileName), caseProcessingMode, entryHandler);
168
    }
169
170
    /**
171
     * Parses a dictionary from a reader.
172
     *
173
     * @param reader            source reader
174
     * @param sourceDescription logical source description for diagnostics
175
     * @param entryHandler      handler receiving parsed entries
176
     * @return parsing statistics
177
     * @throws NullPointerException if any argument is {@code null}
178
     * @throws IOException          if reading or handler processing fails
179
     */
180
    public static ParseStatistics parse(final Reader reader, final String sourceDescription,
181
            final EntryHandler entryHandler) throws IOException {
182 1 1. parse : replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → KILLED
        return parse(reader, sourceDescription, CaseProcessingMode.LOWERCASE_WITH_LOCALE_ROOT, entryHandler);
183
    }
184
185
    /**
186
     * Parses a dictionary from a reader.
187
     *
188
     * @param reader             source reader
189
     * @param sourceDescription  logical source description for diagnostics
190
     * @param caseProcessingMode case processing mode
191
     * @param entryHandler       handler receiving parsed entries
192
     * @return parsing statistics
193
     * @throws NullPointerException if any argument is {@code null}
194
     * @throws IOException          if reading or handler processing fails
195
     */
196
    public static ParseStatistics parse(final Reader reader, final String sourceDescription,
197
            final CaseProcessingMode caseProcessingMode, final EntryHandler entryHandler) throws IOException {
198
        Objects.requireNonNull(reader, "reader");
199
        Objects.requireNonNull(sourceDescription, "sourceDescription");
200
        Objects.requireNonNull(caseProcessingMode, "caseProcessingMode");
201
        Objects.requireNonNull(entryHandler, "entryHandler");
202
203 1 1. parse : negated conditional → KILLED
        final BufferedReader bufferedReader = reader instanceof BufferedReader ? (BufferedReader) reader
204
                : new BufferedReader(reader);
205
206
        int lineNumber = 0;
207
        int logicalEntryCount = 0;
208
        int ignoredLineCount = 0;
209
210 1 1. parse : negated conditional → KILLED
        for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) {
211 1 1. parse : Changed increment from 1 to -1 → KILLED
            lineNumber++;
212
213
            final String normalizedLine = normalizeLineCase(stripRemark(line).trim(), caseProcessingMode);
214 1 1. parse : negated conditional → KILLED
            if (normalizedLine.isEmpty()) {
215 1 1. parse : Changed increment from 1 to -1 → KILLED
                ignoredLineCount++;
216
                continue;
217
            }
218
219
            final String[] rawColumns = normalizedLine.split("\t", -1);
220 1 1. parse : negated conditional → KILLED
            if (rawColumns.length == 0) {
221 1 1. parse : Changed increment from 1 to -1 → NO_COVERAGE
                ignoredLineCount++;
222
                continue;
223
            }
224
225
            final String stem = rawColumns[0].strip();
226 1 1. parse : Replaced integer subtraction with addition → SURVIVED
            final List<String> acceptedVariants = new ArrayList<String>(Math.max(0, rawColumns.length - 1)); // NOPMD
227
228 1 1. parse : negated conditional → KILLED
            if (stem.isEmpty()) {
229 1 1. parse : Changed increment from 1 to -1 → NO_COVERAGE
                ignoredLineCount++;
230
                continue;
231
            }
232
233 1 1. parse : negated conditional → KILLED
            if (containsWhitespaceCharacter(stem)) {
234
                if (LOGGER.isLoggable(Level.WARNING)) {
235
                    LOGGER.log(Level.WARNING,
236
                            "Ignoring dictionary line containing whitespace in source {0} at line {1}, stem {2}.",
237
                            new Object[] { sourceDescription, lineNumber, stem }); // NOPMD
238
                }
239
                continue;
240
            }
241
242
            int ignored = 0;
243
244 2 1. parse : negated conditional → KILLED
2. parse : changed conditional boundary → KILLED
            for (int index = 1; index < rawColumns.length; index++) {
245
                final String variant = rawColumns[index].strip();
246 1 1. parse : negated conditional → KILLED
                if (variant.isEmpty()) {
247
                    continue;
248
                }
249 1 1. parse : negated conditional → KILLED
                if (containsWhitespaceCharacter(variant)) {
250 1 1. parse : Changed increment from 1 to -1 → KILLED
                    ignored++;
251
                    continue;
252
                }
253
                acceptedVariants.add(variant);
254
            }
255
256
            if (ignored > 0 && LOGGER.isLoggable(Level.WARNING)) {
257
                LOGGER.log(Level.WARNING,
258
                        "Ignoring dictionary items containing whitespace in source {0} at line {1}, stem {2}, ignored {3}:{4}.",
259
                        new Object[] { sourceDescription, lineNumber, stem, ignored, rawColumns.length }); // NOPMD
260
            }
261
262 2 1. lambda$parse$0 : replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::lambda$parse$0 → KILLED
2. parse : removed call to org/egothor/stemmer/StemmerDictionaryParser$EntryHandler::onEntry → KILLED
            entryHandler.onEntry(stem, acceptedVariants.toArray(String[]::new), lineNumber);
263 1 1. parse : Changed increment from 1 to -1 → KILLED
            logicalEntryCount++;
264
        }
265
266
        final ParseStatistics statistics = new ParseStatistics(sourceDescription, lineNumber, logicalEntryCount,
267
                ignoredLineCount);
268
269
        if (LOGGER.isLoggable(Level.FINE)) {
270
            LOGGER.log(Level.FINE, "Parsed dictionary source {0}: lines={1}, entries={2}, ignoredLines={3}.",
271
                    new Object[] { statistics.sourceDescription(), statistics.lineCount(), statistics.entryCount(),
272
                            statistics.ignoredLineCount() });
273
        }
274
275 1 1. parse : replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → KILLED
        return statistics;
276
    }
277
278
    /**
279
     * Applies case normalization to one line according to the selected mode.
280
     *
281
     * @param line               line to normalize
282
     * @param caseProcessingMode case processing mode
283
     * @return normalized line
284
     */
285
    private static String normalizeLineCase(final String line, final CaseProcessingMode caseProcessingMode) {
286 1 1. normalizeLineCase : negated conditional → KILLED
        if (caseProcessingMode == CaseProcessingMode.LOWERCASE_WITH_LOCALE_ROOT) {
287 1 1. normalizeLineCase : replaced return value with "" for org/egothor/stemmer/StemmerDictionaryParser::normalizeLineCase → KILLED
            return line.toLowerCase(Locale.ROOT);
288
        }
289 1 1. normalizeLineCase : replaced return value with "" for org/egothor/stemmer/StemmerDictionaryParser::normalizeLineCase → KILLED
        return line;
290
    }
291
292
    /**
293
     * Determines whether one dictionary item contains any Unicode whitespace
294
     * character.
295
     *
296
     * @param item dictionary item to inspect
297
     * @return {@code true} when the item contains at least one whitespace character
298
     */
299
    private static boolean containsWhitespaceCharacter(final String item) {
300 2 1. containsWhitespaceCharacter : changed conditional boundary → KILLED
2. containsWhitespaceCharacter : negated conditional → KILLED
        for (int index = 0; index < item.length(); index++) {
301 1 1. containsWhitespaceCharacter : negated conditional → KILLED
            if (Character.isWhitespace(item.charAt(index))) {
302 1 1. containsWhitespaceCharacter : replaced boolean return with false for org/egothor/stemmer/StemmerDictionaryParser::containsWhitespaceCharacter → KILLED
                return true;
303
            }
304
        }
305 1 1. containsWhitespaceCharacter : replaced boolean return with true for org/egothor/stemmer/StemmerDictionaryParser::containsWhitespaceCharacter → KILLED
        return false;
306
    }
307
308
    /**
309
     * Removes a trailing remark from one physical line.
310
     *
311
     * <p>
312
     * The earliest occurrence of either supported remark marker terminates the
313
     * logical line content.
314
     *
315
     * @param line physical line
316
     * @return line content without a trailing remark
317
     */
318
    private static String stripRemark(final String line) {
319
        final int hashIndex = line.indexOf('#');
320
        final int slashIndex = line.indexOf("//");
321
322
        final int remarkIndex;
323 2 1. stripRemark : changed conditional boundary → KILLED
2. stripRemark : negated conditional → KILLED
        if (hashIndex < 0) {
324
            remarkIndex = slashIndex;
325 2 1. stripRemark : changed conditional boundary → SURVIVED
2. stripRemark : negated conditional → KILLED
        } else if (slashIndex < 0) {
326
            remarkIndex = hashIndex;
327
        } else {
328
            remarkIndex = Math.min(hashIndex, slashIndex);
329
        }
330
331 2 1. stripRemark : changed conditional boundary → KILLED
2. stripRemark : negated conditional → KILLED
        if (remarkIndex < 0) {
332 1 1. stripRemark : replaced return value with "" for org/egothor/stemmer/StemmerDictionaryParser::stripRemark → KILLED
            return line;
333
        }
334 1 1. stripRemark : replaced return value with "" for org/egothor/stemmer/StemmerDictionaryParser::stripRemark → KILLED
        return line.substring(0, remarkIndex);
335
    }
336
337
    /**
338
     * Immutable parsing statistics.
339
     *
340
     * @param sourceDescription logical source description
341
     * @param lineCount         number of physical lines read
342
     * @param entryCount        number of logical dictionary entries emitted
343
     * @param ignoredLineCount  number of ignored empty or remark-only lines
344
     */
345
    public record ParseStatistics(String sourceDescription, int lineCount, int entryCount, int ignoredLineCount) {
346
347
        /**
348
         * Creates parsing statistics.
349
         *
350
         * @param sourceDescription logical source description
351
         * @param lineCount         number of physical lines read
352
         * @param entryCount        number of logical dictionary entries emitted
353
         * @param ignoredLineCount  number of ignored empty or remark-only lines
354
         * @throws NullPointerException     if {@code sourceDescription} is {@code null}
355
         * @throws IllegalArgumentException if any numeric value is negative
356
         */
357
        public ParseStatistics {
358
            Objects.requireNonNull(sourceDescription, "sourceDescription");
359
            if (lineCount < 0) {
360
                throw new IllegalArgumentException("lineCount must not be negative.");
361
            }
362
            if (entryCount < 0) {
363
                throw new IllegalArgumentException("entryCount must not be negative.");
364
            }
365
            if (ignoredLineCount < 0) {
366
                throw new IllegalArgumentException("ignoredLineCount must not be negative.");
367
            }
368
        }
369
    }
370
}

Mutations

116

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:FileParsingTests]/[method:shouldParseSameContentThroughPathAndStringOverloads()]
replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → KILLED

136

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:FileParsingTests]/[method:shouldParseSameContentThroughPathAndStringOverloads()]
replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → KILLED

151

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:FileParsingTests]/[method:shouldParseSameContentThroughPathAndStringOverloads()]
replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → KILLED

167

1.1
Location : parse
Killed by : none
replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → NO_COVERAGE

182

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreferEarliestRemarkMarkerRegardlessOfMarkerType()]
replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → KILLED

203

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
negated conditional → KILLED

210

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
negated conditional → KILLED

211

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreserveCharacterCaseWhenAsIsModeIsSelected()]
Changed increment from 1 to -1 → KILLED

214

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
negated conditional → KILLED

215

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldParseNormalizedEntriesAndCollectAccurateStatistics()]
Changed increment from 1 to -1 → KILLED

220

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
negated conditional → KILLED

221

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

226

1.1
Location : parse
Killed by : none
Replaced integer subtraction with addition → SURVIVED
Covering tests

228

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
negated conditional → KILLED

229

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

233

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
negated conditional → KILLED

244

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreserveCharacterCaseWhenAsIsModeIsSelected()]
negated conditional → KILLED

2.2
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
changed conditional boundary → KILLED

246

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreserveCharacterCaseWhenAsIsModeIsSelected()]
negated conditional → KILLED

249

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreserveCharacterCaseWhenAsIsModeIsSelected()]
negated conditional → KILLED

250

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldIgnoreWhitespaceContainingItemsAndLogOneWarningPerLine()]
Changed increment from 1 to -1 → KILLED

262

1.1
Location : lambda$parse$0
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::lambda$parse$0 → KILLED

2.2
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
removed call to org/egothor/stemmer/StemmerDictionaryParser$EntryHandler::onEntry → KILLED

263

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreserveCharacterCaseWhenAsIsModeIsSelected()]
Changed increment from 1 to -1 → KILLED

275

1.1
Location : parse
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreserveCharacterCaseWhenAsIsModeIsSelected()]
replaced return value with null for org/egothor/stemmer/StemmerDictionaryParser::parse → KILLED

286

1.1
Location : normalizeLineCase
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreserveCharacterCaseWhenAsIsModeIsSelected()]
negated conditional → KILLED

287

1.1
Location : normalizeLineCase
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
replaced return value with "" for org/egothor/stemmer/StemmerDictionaryParser::normalizeLineCase → KILLED

289

1.1
Location : normalizeLineCase
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreserveCharacterCaseWhenAsIsModeIsSelected()]
replaced return value with "" for org/egothor/stemmer/StemmerDictionaryParser::normalizeLineCase → KILLED

300

1.1
Location : containsWhitespaceCharacter
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
changed conditional boundary → KILLED

2.2
Location : containsWhitespaceCharacter
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldIgnoreWhitespaceContainingItemsAndLogOneWarningPerLine()]
negated conditional → KILLED

301

1.1
Location : containsWhitespaceCharacter
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
negated conditional → KILLED

302

1.1
Location : containsWhitespaceCharacter
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldIgnoreWhitespaceContainingItemsAndLogOneWarningPerLine()]
replaced boolean return with false for org/egothor/stemmer/StemmerDictionaryParser::containsWhitespaceCharacter → KILLED

305

1.1
Location : containsWhitespaceCharacter
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
replaced boolean return with true for org/egothor/stemmer/StemmerDictionaryParser::containsWhitespaceCharacter → KILLED

323

1.1
Location : stripRemark
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldParseNormalizedEntriesAndCollectAccurateStatistics()]
changed conditional boundary → KILLED

2.2
Location : stripRemark
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreferEarliestRemarkMarkerRegardlessOfMarkerType()]
negated conditional → KILLED

325

1.1
Location : stripRemark
Killed by : none
changed conditional boundary → SURVIVED
Covering tests

2.2
Location : stripRemark
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreferEarliestRemarkMarkerRegardlessOfMarkerType()]
negated conditional → KILLED

331

1.1
Location : stripRemark
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldParseNormalizedEntriesAndCollectAccurateStatistics()]
changed conditional boundary → KILLED

2.2
Location : stripRemark
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
negated conditional → KILLED

332

1.1
Location : stripRemark
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPropagateHandlerIOExceptionWithoutSwallowingIt()]
replaced return value with "" for org/egothor/stemmer/StemmerDictionaryParser::stripRemark → KILLED

334

1.1
Location : stripRemark
Killed by : org.egothor.stemmer.StemmerDictionaryParserTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.StemmerDictionaryParserTest]/[nested-class:ReaderParsingTests]/[method:shouldPreferEarliestRemarkMarkerRegardlessOfMarkerType()]
replaced return value with "" for org/egothor/stemmer/StemmerDictionaryParser::stripRemark → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1