ApplyTagsFromCsvEngine.java

1
package org.egothor.methodatlas;
2
3
import java.io.IOException;
4
import java.io.PrintWriter;
5
import java.nio.file.Files;
6
import java.nio.file.Path;
7
import java.util.ArrayList;
8
import java.util.HashMap;
9
import java.util.LinkedHashMap;
10
import java.util.LinkedHashSet;
11
import java.util.List;
12
import java.util.Map;
13
import java.util.Set;
14
import java.util.logging.Level;
15
import java.util.logging.Logger;
16
import java.util.stream.Stream;
17
18
import org.egothor.methodatlas.api.ScanRecord;
19
import org.egothor.methodatlas.emit.DeltaReport;
20
import org.egothor.methodatlas.api.SourcePatcher;
21
22
/**
23
 * Engine that applies annotation changes to source files driven by a
24
 * reviewed MethodAtlas CSV export.
25
 *
26
 * <p>
27
 * The {@code -apply-tags-from-csv} workflow allows a security or development
28
 * team to review MethodAtlas output in a CSV file, adjust the {@code tags} and
29
 * {@code display_name} columns to reflect the desired annotation state, and
30
 * then replay those decisions back into the source code. The CSV acts as a
31
 * <em>desired-state specification</em>: after a successful run, re-running
32
 * MethodAtlas on the same source tree would reproduce an equivalent CSV.
33
 * </p>
34
 *
35
 * <h2>Invariant</h2>
36
 * <p>
37
 * The CSV must be complete — it must contain one row for every test method
38
 * currently present in the scanned source tree (matching the configured file
39
 * suffixes and test annotations). A method that appears in the source but not
40
 * in the CSV, or in the CSV but not in the source, constitutes a
41
 * <em>mismatch</em> and is reported as a warning. When a mismatch limit is
42
 * configured, the engine aborts without making any source changes if the
43
 * number of mismatches reaches or exceeds that limit.
44
 * </p>
45
 *
46
 * <h2>What is applied</h2>
47
 * <ul>
48
 *   <li>{@code tags} column — the exact set of {@code @Tag} annotations desired
49
 *       on the method; existing tags not in the list are removed, missing tags
50
 *       are added</li>
51
 *   <li>{@code display_name} column — the desired {@code @DisplayName} text;
52
 *       empty means "remove any existing {@code @DisplayName}"</li>
53
 * </ul>
54
 *
55
 * <h2>Mismatch handling</h2>
56
 * <p>
57
 * If {@code mismatchLimit} is {@code -1} (no limit), mismatches are logged as
58
 * warnings and the engine proceeds. If {@code mismatchLimit} is {@code >= 0},
59
 * the engine first counts mismatches and aborts with exit code {@code 1} when
60
 * the count is {@code >= mismatchLimit}. Setting the limit to {@code 1}
61
 * therefore causes any mismatch to abort the run without touching source files.
62
 * </p>
63
 *
64
 * <h2>Languages supported for write-back</h2>
65
 * <p>
66
 * Source write-back is only available for languages whose discovery plugin
67
 * ships a {@link SourcePatcher} implementation — currently
68
 * <strong>Java</strong> (JUnit&nbsp;5 / 4 / TestNG) and <strong>C#</strong>
69
 * (xUnit / NUnit / MSTest). Files whose language has no patcher are skipped
70
 * during the apply phase; a per-file notice is written to {@code log} and
71
 * the aggregate skip count is appended to the completion summary line.
72
 * These files do not appear in the source-method index built by
73
 * {@link SourcePatcher#discoverMethodsByClass(Path)} either, so rows in the
74
 * CSV that describe tests in unsupported languages will be reported as
75
 * mismatches.
76
 * </p>
77
 *
78
 * <p>
79
 * This class is a non-instantiable utility holder.
80
 * </p>
81
 *
82
 * @see SourcePatcher
83
 * @see MethodAtlasApp
84
 */
85
public final class ApplyTagsFromCsvEngine {
86
87
    private static final Logger LOG = Logger.getLogger(ApplyTagsFromCsvEngine.class.getName());
88
89
    private ApplyTagsFromCsvEngine() {
90
    }
91
92
    /**
93
     * Applies annotation changes from a reviewed CSV to source files.
94
     *
95
     * <p>
96
     * Source-method inventory (for mismatch detection) and source file write-back
97
     * are both delegated to the supplied {@link SourcePatcher} implementations via
98
     * {@link SourcePatcher#discoverMethodsByClass(java.nio.file.Path)} and
99
     * {@link SourcePatcher#patch(java.nio.file.Path, java.util.Map, java.util.Map,
100
     * java.io.PrintWriter)} respectively.
101
     * </p>
102
     *
103
     * @param csvFile         path to a MethodAtlas CSV produced with a previous
104
     *                        scan and reviewed by the team; must contain
105
     *                        {@code fqcn}, {@code method}, {@code tags}, and
106
     *                        {@code display_name} columns
107
     * @param roots           source root directories to scan for test files
108
     * @param mismatchLimit   maximum number of mismatches before aborting;
109
     *                        {@code -1} means no limit (warn and proceed)
110
     * @param patchers        list of configured {@link SourcePatcher} implementations
111
     * @param log             writer for progress and summary output
112
     * @return {@code 0} on success, {@code 1} when the mismatch limit is
113
     *         exceeded or a fatal error occurs
114
     * @throws IOException if the CSV file or source files cannot be read or
115
     *                     written
116
     */
117
    public static int apply(Path csvFile, List<Path> roots,
118
            int mismatchLimit, List<SourcePatcher> patchers, PrintWriter log)
119
            throws IOException {
120
121
        // ── Step 1: load the desired-state CSV ────────────────────────────────
122
        List<ScanRecord> records = DeltaReport.loadRecords(csvFile);
123 2 1. apply : removed conditional - replaced equality check with true → KILLED
2. apply : removed conditional - replaced equality check with false → KILLED
        if (records.isEmpty()) {
124 1 1. apply : removed call to java/io/PrintWriter::println → KILLED
            log.println("Apply-tags-from-csv: CSV file contains no records — nothing to apply.");
125
            return 0;
126
        }
127
128 1 1. apply : Replaced integer multiplication with division → SURVIVED
        Map<String, ScanRecord> desiredState = new HashMap<>(records.size() * 2);
129
        for (ScanRecord r : records) {
130
            desiredState.put(key(r.fqcn(), r.method()), r);
131
        }
132
133
        // ── Step 2: scan source to build current method inventory ─────────────
134
        // Build a map from source file path → list of (fqcn, methodName) pairs
135
        // by asking each SourcePatcher to discover methods in supported files.
136
        Map<Path, List<MethodKey>> sourceIndex =
137
                buildSourceIndex(roots, patchers);
138
139
        Set<String> sourceKeys = new LinkedHashSet<>();
140
        for (List<MethodKey> methods : sourceIndex.values()) {
141
            for (MethodKey mk : methods) {
142
                sourceKeys.add(key(mk.fqcn(), mk.method()));
143
            }
144
        }
145
146
        // ── Step 3: compute mismatches (symmetric difference) ─────────────────
147
        Set<String> inCsvNotSource = new LinkedHashSet<>(desiredState.keySet());
148
        inCsvNotSource.removeAll(sourceKeys);
149
150
        Set<String> inSourceNotCsv = new LinkedHashSet<>(sourceKeys);
151
        inSourceNotCsv.removeAll(desiredState.keySet());
152
153 1 1. apply : Replaced integer addition with subtraction → KILLED
        int mismatchCount = inCsvNotSource.size() + inSourceNotCsv.size();
154
155
        // ── Step 4: enforce mismatch limit ────────────────────────────────────
156 6 1. apply : changed conditional boundary → SURVIVED
2. apply : changed conditional boundary → KILLED
3. apply : removed conditional - replaced comparison check with false → KILLED
4. apply : removed conditional - replaced comparison check with false → KILLED
5. apply : removed conditional - replaced comparison check with true → KILLED
6. apply : removed conditional - replaced comparison check with true → KILLED
        if (mismatchLimit >= 0 && mismatchCount >= mismatchLimit) {
157 1 1. apply : replaced int return with 0 for org/egothor/methodatlas/ApplyTagsFromCsvEngine::apply → KILLED
            return reportMismatchesAndAbort(inCsvNotSource, inSourceNotCsv, mismatchCount, mismatchLimit, log);
158
        }
159
160
        // ── Step 5: warn about mismatches (no limit, or below limit) ──────────
161 1 1. apply : removed call to org/egothor/methodatlas/ApplyTagsFromCsvEngine::warnMismatches → SURVIVED
        warnMismatches(inCsvNotSource, inSourceNotCsv);
162
163
        // ── Step 6: apply changes file by file ────────────────────────────────
164 1 1. apply : replaced int return with 0 for org/egothor/methodatlas/ApplyTagsFromCsvEngine::apply → SURVIVED
        return applyFilesLoop(sourceIndex, desiredState, patchers, mismatchCount, log);
165
    }
166
167
    private static int reportMismatchesAndAbort(Set<String> inCsvNotSource, Set<String> inSourceNotCsv,
168
            int mismatchCount, int mismatchLimit, PrintWriter log) {
169
        for (String k : inCsvNotSource) {
170 1 1. reportMismatchesAndAbort : removed call to java/io/PrintWriter::println → KILLED
            log.println("MISMATCH (in CSV, not in source): " + k);
171
        }
172
        for (String k : inSourceNotCsv) {
173 1 1. reportMismatchesAndAbort : removed call to java/io/PrintWriter::println → SURVIVED
            log.println("MISMATCH (in source, not in CSV): " + k);
174
        }
175 1 1. reportMismatchesAndAbort : removed call to java/io/PrintWriter::println → KILLED
        log.println("Apply-tags-from-csv aborted: " + mismatchCount
176
                + " mismatch(es) >= limit " + mismatchLimit + ". No source files were modified.");
177 1 1. reportMismatchesAndAbort : replaced int return with 0 for org/egothor/methodatlas/ApplyTagsFromCsvEngine::reportMismatchesAndAbort → KILLED
        return 1;
178
    }
179
180
    private static void warnMismatches(Set<String> inCsvNotSource, Set<String> inSourceNotCsv) {
181
        if (LOG.isLoggable(Level.WARNING)) {
182
            for (String k : inCsvNotSource) {
183
                LOG.warning("Mismatch (in CSV, not found in source): " + k);
184
            }
185
            for (String k : inSourceNotCsv) {
186
                LOG.warning("Mismatch (in source, not present in CSV): " + k);
187
            }
188
        }
189
    }
190
191
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
192
    private static int applyFilesLoop(Map<Path, List<MethodKey>> sourceIndex,
193
            Map<String, ScanRecord> desiredState, List<SourcePatcher> patchers,
194
            int mismatchCount, PrintWriter log) {
195
        int modifiedFiles = 0;
196
        int totalChanges = 0;
197
        int skippedFiles = 0;
198
        boolean hadErrors = false;
199
200
        for (Map.Entry<Path, List<MethodKey>> entry : sourceIndex.entrySet()) {
201
            Path path = entry.getKey();
202 2 1. applyFilesLoop : removed conditional - replaced equality check with false → SURVIVED
2. applyFilesLoop : removed conditional - replaced equality check with true → KILLED
            if (!hasRelevantMethod(entry.getValue(), desiredState)) {
203
                continue;
204
            }
205
206
            SourcePatcher patcher = patchers.stream()
207 2 1. lambda$applyFilesLoop$0 : replaced boolean return with true for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$applyFilesLoop$0 → SURVIVED
2. lambda$applyFilesLoop$0 : replaced boolean return with false for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$applyFilesLoop$0 → KILLED
                    .filter(p -> p.supports(path))
208
                    .findFirst().orElse(null);
209 2 1. applyFilesLoop : removed conditional - replaced equality check with false → SURVIVED
2. applyFilesLoop : removed conditional - replaced equality check with true → KILLED
            if (patcher == null) {
210 1 1. applyFilesLoop : Changed increment from 1 to -1 → NO_COVERAGE
                skippedFiles++;
211
                if (LOG.isLoggable(Level.INFO)) {
212
                    LOG.log(Level.INFO,
213
                            "Skipping {0}: no SourcePatcher available for this language",
214
                            path);
215
                }
216 1 1. applyFilesLoop : removed call to java/io/PrintWriter::println → NO_COVERAGE
                log.println("Apply-tags-from-csv: skipped " + path
217
                        + " — source write-back is not supported for this language "
218
                        + "(currently Java and C# only)");
219
                continue;
220
            }
221
222
            // Build per-method desired state maps for this file
223
            Map<String, List<String>> tagsToApply = new LinkedHashMap<>();
224
            Map<String, String> displayNames = new LinkedHashMap<>();
225
226
            for (MethodKey mk : entry.getValue()) {
227
                String k = key(mk.fqcn(), mk.method());
228
                ScanRecord desired = desiredState.get(k);
229 2 1. applyFilesLoop : removed conditional - replaced equality check with false → SURVIVED
2. applyFilesLoop : removed conditional - replaced equality check with true → KILLED
                if (desired == null) {
230
                    continue;
231
                }
232 2 1. applyFilesLoop : removed conditional - replaced equality check with true → SURVIVED
2. applyFilesLoop : removed conditional - replaced equality check with false → KILLED
                if (desired.tags() != null) {
233
                    tagsToApply.put(mk.method(), desired.tags());
234
                }
235
                // null means the column was absent from the CSV (old format) — leave @DisplayName untouched.
236
                // "" means the column was present but empty — remove @DisplayName.
237 2 1. applyFilesLoop : removed conditional - replaced equality check with true → SURVIVED
2. applyFilesLoop : removed conditional - replaced equality check with false → KILLED
                if (desired.displayName() != null) {
238
                    displayNames.put(mk.method(), desired.displayName());
239
                }
240
            }
241
242
            try {
243
                int changes = patcher.patch(path, tagsToApply, displayNames, log);
244 3 1. applyFilesLoop : removed conditional - replaced comparison check with false → SURVIVED
2. applyFilesLoop : removed conditional - replaced comparison check with true → KILLED
3. applyFilesLoop : changed conditional boundary → KILLED
                if (changes > 0) {
245 1 1. applyFilesLoop : Changed increment from 1 to -1 → SURVIVED
                    modifiedFiles++;
246 1 1. applyFilesLoop : Replaced integer addition with subtraction → SURVIVED
                    totalChanges += changes;
247
                }
248
            } catch (IOException e) {
249
                if (LOG.isLoggable(Level.WARNING)) {
250
                    LOG.log(Level.WARNING, "Cannot process: " + path, e);
251
                }
252
                hadErrors = true;
253
            }
254
        }
255
256
        // Capacity 224 comfortably covers the worst-case message:
257
        //   "Apply-tags-from-csv complete: <int> change(s) in <int> file(s);
258
        //    <int> mismatch(es) skipped. <int> file(s) skipped (no source
259
        //    write-back support for the language)."
260
        // which is ~165 chars including the integer placeholders.
261
        StringBuilder summary = new StringBuilder(224)
262
                .append("Apply-tags-from-csv complete: ")
263
                .append(totalChanges).append(" change(s) in ")
264
                .append(modifiedFiles).append(" file(s); ")
265
                .append(mismatchCount).append(" mismatch(es) skipped.");
266 3 1. applyFilesLoop : removed conditional - replaced comparison check with false → SURVIVED
2. applyFilesLoop : changed conditional boundary → SURVIVED
3. applyFilesLoop : removed conditional - replaced comparison check with true → SURVIVED
        if (skippedFiles > 0) {
267
            summary.append(' ').append(skippedFiles)
268
                    .append(" file(s) skipped (no source write-back support for the language).");
269
        }
270 1 1. applyFilesLoop : removed call to java/io/PrintWriter::println → KILLED
        log.println(summary.toString());
271 2 1. applyFilesLoop : removed conditional - replaced equality check with false → SURVIVED
2. applyFilesLoop : removed conditional - replaced equality check with true → KILLED
        return hadErrors ? 1 : 0;
272
    }
273
274
    private static boolean hasRelevantMethod(List<MethodKey> methods, Map<String, ScanRecord> desiredState) {
275
        for (MethodKey mk : methods) {
276 2 1. hasRelevantMethod : removed conditional - replaced equality check with true → SURVIVED
2. hasRelevantMethod : removed conditional - replaced equality check with false → KILLED
            if (desiredState.containsKey(key(mk.fqcn(), mk.method()))) {
277 1 1. hasRelevantMethod : replaced boolean return with false for org/egothor/methodatlas/ApplyTagsFromCsvEngine::hasRelevantMethod → KILLED
                return true;
278
            }
279
        }
280 1 1. hasRelevantMethod : replaced boolean return with true for org/egothor/methodatlas/ApplyTagsFromCsvEngine::hasRelevantMethod → NO_COVERAGE
        return false;
281
    }
282
283
    /**
284
     * Scans source roots and builds an index mapping each source file to the
285
     * list of (FQCN, method) pairs for all test methods it contains.
286
     *
287
     * <p>
288
     * Each supported source file is passed to
289
     * {@link SourcePatcher#discoverMethodsByClass(Path)} to obtain the actual
290
     * test-method inventory. This gives the correct FQCN–method pairs
291
     * regardless of whether the source tree uses the standard
292
     * {@code package/to/ClassName.java} directory structure.
293
     * </p>
294
     *
295
     * @param roots    source root directories
296
     * @param patchers list of configured patchers used to identify supported files
297
     * @return map from source file path to list of {@link MethodKey} entries;
298
     *         never {@code null}
299
     * @throws IOException if a file tree cannot be traversed
300
     */
301
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
302
    private static Map<Path, List<MethodKey>> buildSourceIndex(
303
            List<Path> roots,
304
            List<SourcePatcher> patchers) throws IOException {
305
306
        Map<Path, List<MethodKey>> index = new HashMap<>();
307
308
        for (Path root : roots) {
309 2 1. buildSourceIndex : removed conditional - replaced equality check with false → SURVIVED
2. buildSourceIndex : removed conditional - replaced equality check with true → KILLED
            if (!Files.isDirectory(root)) {
310
                continue;
311
            }
312
            try (Stream<Path> stream = Files.walk(root)) {
313
                for (Path path : (Iterable<Path>) stream
314 2 1. lambda$buildSourceIndex$1 : replaced boolean return with true for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$buildSourceIndex$1 → SURVIVED
2. lambda$buildSourceIndex$1 : replaced boolean return with false for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$buildSourceIndex$1 → KILLED
                        .filter(Files::isRegularFile)::iterator) {
315
316
                    SourcePatcher patcher = patchers.stream()
317 2 1. lambda$buildSourceIndex$2 : replaced boolean return with true for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$buildSourceIndex$2 → SURVIVED
2. lambda$buildSourceIndex$2 : replaced boolean return with false for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$buildSourceIndex$2 → KILLED
                            .filter(p -> p.supports(path))
318
                            .findFirst().orElse(null);
319 2 1. buildSourceIndex : removed conditional - replaced equality check with true → KILLED
2. buildSourceIndex : removed conditional - replaced equality check with false → KILLED
                    if (patcher == null) {
320
                        continue;
321
                    }
322
323
                    // Ask the patcher to discover test methods in this file
324
                    Map<String, List<String>> byClass = patcher.discoverMethodsByClass(path);
325
                    List<MethodKey> keys = new ArrayList<>();
326
                    for (Map.Entry<String, List<String>> classEntry : byClass.entrySet()) {
327
                        String fqcn = classEntry.getKey();
328
                        for (String methodName : classEntry.getValue()) {
329
                            keys.add(new MethodKey(fqcn, methodName));
330
                        }
331
                    }
332 2 1. buildSourceIndex : removed conditional - replaced equality check with true → SURVIVED
2. buildSourceIndex : removed conditional - replaced equality check with false → KILLED
                    if (!keys.isEmpty()) {
333
                        index.put(path, keys);
334
                    }
335
                }
336
            }
337
        }
338
339 1 1. buildSourceIndex : replaced return value with Collections.emptyMap for org/egothor/methodatlas/ApplyTagsFromCsvEngine::buildSourceIndex → KILLED
        return index;
340
    }
341
342
    private static String key(String fqcn, String method) {
343 1 1. key : replaced return value with "" for org/egothor/methodatlas/ApplyTagsFromCsvEngine::key → KILLED
        return fqcn + "::" + method;
344
    }
345
346
    /** Lightweight tuple holding a fully qualified class name and a method name. */
347
    private record MethodKey(String fqcn, String method) {
348
    }
349
}

Mutations

123

1.1
Location : apply
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchLimitReturnsOne(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

2.2
Location : apply
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_emptyCsvReturnsZero(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

124

1.1
Location : apply
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_emptyCsvReturnsZero(java.nio.file.Path)]
removed call to java/io/PrintWriter::println → KILLED

128

1.1
Location : apply
Killed by : none
Replaced integer multiplication with division → SURVIVED
Covering tests

153

1.1
Location : apply
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_methodInSourceNotInCsvCountedAsMismatch(java.nio.file.Path)]
Replaced integer addition with subtraction → KILLED

156

1.1
Location : apply
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchLimitReturnsOne(java.nio.file.Path)]
changed conditional boundary → KILLED

2.2
Location : apply
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchLimitReturnsOne(java.nio.file.Path)]
removed conditional - replaced comparison check with false → KILLED

3.3
Location : apply
Killed by : none
changed conditional boundary → SURVIVED
Covering tests

4.4
Location : apply
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchLimitReturnsOne(java.nio.file.Path)]
removed conditional - replaced comparison check with false → KILLED

5.5
Location : apply
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchBelowLimitProceeds(java.nio.file.Path)]
removed conditional - replaced comparison check with true → KILLED

6.6
Location : apply
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
removed conditional - replaced comparison check with true → KILLED

157

1.1
Location : apply
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchLimitReturnsOne(java.nio.file.Path)]
replaced int return with 0 for org/egothor/methodatlas/ApplyTagsFromCsvEngine::apply → KILLED

161

1.1
Location : apply
Killed by : none
removed call to org/egothor/methodatlas/ApplyTagsFromCsvEngine::warnMismatches → SURVIVED
Covering tests

164

1.1
Location : apply
Killed by : none
replaced int return with 0 for org/egothor/methodatlas/ApplyTagsFromCsvEngine::apply → SURVIVED
Covering tests

170

1.1
Location : reportMismatchesAndAbort
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchLimitAborts(java.nio.file.Path)]
removed call to java/io/PrintWriter::println → KILLED

173

1.1
Location : reportMismatchesAndAbort
Killed by : none
removed call to java/io/PrintWriter::println → SURVIVED
Covering tests

175

1.1
Location : reportMismatchesAndAbort
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchLimitAborts(java.nio.file.Path)]
removed call to java/io/PrintWriter::println → KILLED

177

1.1
Location : reportMismatchesAndAbort
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchLimitReturnsOne(java.nio.file.Path)]
replaced int return with 0 for org/egothor/methodatlas/ApplyTagsFromCsvEngine::reportMismatchesAndAbort → KILLED

202

1.1
Location : applyFilesLoop
Killed by : none
removed conditional - replaced equality check with false → SURVIVED
Covering tests

2.2
Location : applyFilesLoop
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

207

1.1
Location : lambda$applyFilesLoop$0
Killed by : none
replaced boolean return with true for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$applyFilesLoop$0 → SURVIVED
Covering tests

2.2
Location : lambda$applyFilesLoop$0
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
replaced boolean return with false for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$applyFilesLoop$0 → KILLED

209

1.1
Location : applyFilesLoop
Killed by : none
removed conditional - replaced equality check with false → SURVIVED
Covering tests

2.2
Location : applyFilesLoop
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

210

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

216

1.1
Location : applyFilesLoop
Killed by : none
removed call to java/io/PrintWriter::println → NO_COVERAGE

229

1.1
Location : applyFilesLoop
Killed by : none
removed conditional - replaced equality check with false → SURVIVED
Covering tests

2.2
Location : applyFilesLoop
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

232

1.1
Location : applyFilesLoop
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsUnsupportedLanguageTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsUnsupportedLanguageTest]/[method:applyTagsFromCsv_goRowsAreReportedAsMismatchAndFileSkipped(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

2.2
Location : applyFilesLoop
Killed by : none
removed conditional - replaced equality check with true → SURVIVED
Covering tests

237

1.1
Location : applyFilesLoop
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

2.2
Location : applyFilesLoop
Killed by : none
removed conditional - replaced equality check with true → SURVIVED
Covering tests

244

1.1
Location : applyFilesLoop
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_noChangesWhenAlreadyMatchesCsv(java.nio.file.Path)]
removed conditional - replaced comparison check with true → KILLED

2.2
Location : applyFilesLoop
Killed by : none
removed conditional - replaced comparison check with false → SURVIVED
Covering tests

3.3
Location : applyFilesLoop
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_noChangesWhenAlreadyMatchesCsv(java.nio.file.Path)]
changed conditional boundary → KILLED

245

1.1
Location : applyFilesLoop
Killed by : none
Changed increment from 1 to -1 → SURVIVED
Covering tests

246

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

266

1.1
Location : applyFilesLoop
Killed by : none
removed conditional - replaced comparison check with false → SURVIVED
Covering tests

2.2
Location : applyFilesLoop
Killed by : none
changed conditional boundary → SURVIVED Covering tests

3.3
Location : applyFilesLoop
Killed by : none
removed conditional - replaced comparison check with true → SURVIVED Covering tests

270

1.1
Location : applyFilesLoop
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsUnsupportedLanguageTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsUnsupportedLanguageTest]/[method:applyTagsFromCsv_goRowsAreReportedAsMismatchAndFileSkipped(java.nio.file.Path)]
removed call to java/io/PrintWriter::println → KILLED

271

1.1
Location : applyFilesLoop
Killed by : none
removed conditional - replaced equality check with false → SURVIVED
Covering tests

2.2
Location : applyFilesLoop
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_returnsZeroOnSuccess(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

276

1.1
Location : hasRelevantMethod
Killed by : none
removed conditional - replaced equality check with true → SURVIVED
Covering tests

2.2
Location : hasRelevantMethod
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

277

1.1
Location : hasRelevantMethod
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
replaced boolean return with false for org/egothor/methodatlas/ApplyTagsFromCsvEngine::hasRelevantMethod → KILLED

280

1.1
Location : hasRelevantMethod
Killed by : none
replaced boolean return with true for org/egothor/methodatlas/ApplyTagsFromCsvEngine::hasRelevantMethod → NO_COVERAGE

309

1.1
Location : buildSourceIndex
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

2.2
Location : buildSourceIndex
Killed by : none
removed conditional - replaced equality check with false → SURVIVED
Covering tests

314

1.1
Location : lambda$buildSourceIndex$1
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
replaced boolean return with false for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$buildSourceIndex$1 → KILLED

2.2
Location : lambda$buildSourceIndex$1
Killed by : none
replaced boolean return with true for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$buildSourceIndex$1 → SURVIVED
Covering tests

317

1.1
Location : lambda$buildSourceIndex$2
Killed by : none
replaced boolean return with true for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$buildSourceIndex$2 → SURVIVED
Covering tests

2.2
Location : lambda$buildSourceIndex$2
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
replaced boolean return with false for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$buildSourceIndex$2 → KILLED

319

1.1
Location : buildSourceIndex
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

2.2
Location : buildSourceIndex
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchLimitReturnsOne(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

332

1.1
Location : buildSourceIndex
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

2.2
Location : buildSourceIndex
Killed by : none
removed conditional - replaced equality check with true → SURVIVED
Covering tests

339

1.1
Location : buildSourceIndex
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_addsDisplayNameImportWhenDisplayNameSet(java.nio.file.Path)]
replaced return value with Collections.emptyMap for org/egothor/methodatlas/ApplyTagsFromCsvEngine::buildSourceIndex → KILLED

343

1.1
Location : key
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_mismatchLimitReturnsOne(java.nio.file.Path)]
replaced return value with "" for org/egothor/methodatlas/ApplyTagsFromCsvEngine::key → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1