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.nio.file.Paths;
8
import java.util.ArrayList;
9
import java.util.HashMap;
10
import java.util.LinkedHashMap;
11
import java.util.LinkedHashSet;
12
import java.util.List;
13
import java.util.Map;
14
import java.util.Set;
15
import java.util.logging.Level;
16
import java.util.logging.Logger;
17
import java.util.stream.Stream;
18
19
import org.egothor.methodatlas.api.ScanRecord;
20
import org.egothor.methodatlas.emit.DeltaReport;
21
import org.egothor.methodatlas.api.SourcePatcher;
22
23
/**
24
 * Engine that applies annotation changes to source files driven by a
25
 * reviewed MethodAtlas CSV export.
26
 *
27
 * <p>
28
 * The {@code -apply-tags-from-csv} workflow allows a security or development
29
 * team to review MethodAtlas output in a CSV file, adjust the {@code tags} and
30
 * {@code display_name} columns to reflect the desired annotation state, and
31
 * then replay those decisions back into the source code. The CSV acts as a
32
 * <em>desired-state specification</em>: after a successful run, re-running
33
 * MethodAtlas on the same source tree would reproduce an equivalent CSV.
34
 * </p>
35
 *
36
 * <h2>Invariant</h2>
37
 * <p>
38
 * The CSV must be complete — it must contain one row for every test method
39
 * currently present in the scanned source tree (matching the configured file
40
 * suffixes and test annotations). A method that appears in the source but not
41
 * in the CSV, or in the CSV but not in the source, constitutes a
42
 * <em>mismatch</em> and is reported as a warning. When a mismatch limit is
43
 * configured, the engine aborts without making any source changes if the
44
 * number of mismatches reaches or exceeds that limit.
45
 * </p>
46
 *
47
 * <h2>What is applied</h2>
48
 * <ul>
49
 *   <li>{@code tags} column — the exact set of {@code @Tag} annotations desired
50
 *       on the method; existing tags not in the list are removed, missing tags
51
 *       are added</li>
52
 *   <li>{@code display_name} column — the desired {@code @DisplayName} text;
53
 *       empty means "remove any existing {@code @DisplayName}"</li>
54
 * </ul>
55
 *
56
 * <h2>AI-column promotion (risky, opt-in)</h2>
57
 * <p>
58
 * <strong>Not recommended.</strong> When the caller passes {@code promoteAi},
59
 * the engine falls back to the AI-suggested {@code ai_tags} /
60
 * {@code ai_display_name} columns for any method whose curated {@code tags} /
61
 * {@code display_name} column is blank, and writes that raw AI suggestion into
62
 * source. Promotion is per-field and independent, and only fires when the
63
 * curated value is blank <em>and</em> a non-blank AI value is present.
64
 * </p>
65
 * <p>
66
 * This mode deliberately bypasses the human review step that the
67
 * apply-from-csv workflow exists to enforce — AI output reaches source without
68
 * validation. It should not be used unless the promotion has been rethought and
69
 * approved for the target environment. Every promoted value is counted and
70
 * reported on the completion summary line (and itemised under {@code -verbose})
71
 * so the run log records exactly which source writes originated from AI rather
72
 * than from a reviewed column.
73
 * </p>
74
 *
75
 * <h2>Mismatch handling</h2>
76
 * <p>
77
 * If {@code mismatchLimit} is {@code -1} (no limit), mismatches are logged as
78
 * warnings and the engine proceeds. If {@code mismatchLimit} is {@code >= 0},
79
 * the engine first counts mismatches and aborts with exit code {@code 1} when
80
 * the count is {@code >= mismatchLimit}. Setting the limit to {@code 1}
81
 * therefore causes any mismatch to abort the run without touching source files.
82
 * </p>
83
 *
84
 * <h2>Languages supported for write-back</h2>
85
 * <p>
86
 * Source write-back is only available for languages whose discovery plugin
87
 * ships a {@link SourcePatcher} implementation — currently
88
 * <strong>Java</strong> (JUnit&nbsp;5 / 4 / TestNG) and <strong>C#</strong>
89
 * (xUnit / NUnit / MSTest). Files whose language has no patcher are skipped
90
 * during the apply phase; a per-file notice is written to {@code log} and
91
 * the aggregate skip count is appended to the completion summary line.
92
 * These files do not appear in the source-method index built by
93
 * {@link SourcePatcher#discoverMethodsByClass(Path)} either, so rows in the
94
 * CSV that describe tests in unsupported languages will be reported as
95
 * mismatches.
96
 * </p>
97
 *
98
 * <p>
99
 * This class is a non-instantiable utility holder.
100
 * </p>
101
 *
102
 * @see SourcePatcher
103
 * @see MethodAtlasApp
104
 */
105
public final class ApplyTagsFromCsvEngine {
106
107
    private static final Logger LOG = Logger.getLogger(ApplyTagsFromCsvEngine.class.getName());
108
109
    private ApplyTagsFromCsvEngine() {
110
    }
111
112
    /**
113
     * Applies annotation changes from a reviewed CSV to source files.
114
     *
115
     * <p>
116
     * Source-method inventory (for mismatch detection) and source file write-back
117
     * are both delegated to the supplied {@link SourcePatcher} implementations via
118
     * {@link SourcePatcher#discoverMethodsByClass(java.nio.file.Path)} and
119
     * {@link SourcePatcher#patch(java.nio.file.Path, java.util.Map, java.util.Map,
120
     * java.io.PrintWriter)} respectively.
121
     * </p>
122
     *
123
     * @param csvFile         path to a MethodAtlas CSV produced with a previous
124
     *                        scan and reviewed by the team; must contain
125
     *                        {@code fqcn}, {@code method}, {@code tags}, and
126
     *                        {@code display_name} columns
127
     * @param roots           source root directories to scan for test files
128
     * @param mismatchLimit   maximum number of mismatches before aborting;
129
     *                        {@code -1} means no limit (warn and proceed)
130
     * @param patchers        list of configured {@link SourcePatcher} implementations
131
     * @param log             writer for progress and summary output
132
     * @param verbose         when {@code true}, print the CSV desired-state keys,
133
     *                        the keys discovered in the source tree, and the
134
     *                        key-by-key match result to {@code log}, so a run that
135
     *                        reports zero updates can be diagnosed (for example a
136
     *                        fully qualified class name or working-directory
137
     *                        mismatch between the CSV and the scanned source)
138
     * @param promoteAi       <strong>risky, not recommended</strong>: when
139
     *                        {@code true}, the engine falls back to the
140
     *                        {@code ai_tags} / {@code ai_display_name} columns for
141
     *                        any method whose curated {@code tags} /
142
     *                        {@code display_name} column is blank, writing the raw
143
     *                        AI suggestion into source without human review;
144
     *                        every promoted value is counted on the summary line
145
     *                        and itemised under {@code verbose}
146
     * @return {@code 0} on success, {@code 1} when the mismatch limit is
147
     *         exceeded or a fatal error occurs
148
     * @throws IOException if the CSV file or source files cannot be read or
149
     *                     written
150
     */
151
    public static int apply(Path csvFile, List<Path> roots,
152
            int mismatchLimit, List<SourcePatcher> patchers, PrintWriter log, boolean verbose,
153
            boolean promoteAi)
154
            throws IOException {
155
156
        // ── Step 1: load the desired-state CSV ────────────────────────────────
157
        List<ScanRecord> records = DeltaReport.loadRecords(csvFile);
158 2 1. apply : removed conditional - replaced equality check with false → KILLED
2. apply : removed conditional - replaced equality check with true → KILLED
        if (records.isEmpty()) {
159 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.");
160
            return 0;
161
        }
162
163 1 1. apply : Replaced integer multiplication with division → SURVIVED
        Map<String, ScanRecord> desiredState = new HashMap<>(records.size() * 2);
164
        for (ScanRecord r : records) {
165
            desiredState.put(key(r.fqcn(), r.method()), r);
166
        }
167
168 2 1. apply : removed conditional - replaced equality check with true → SURVIVED
2. apply : removed conditional - replaced equality check with false → KILLED
        if (verbose) {
169 1 1. apply : removed call to org/egothor/methodatlas/ApplyTagsFromCsvEngine::logVerboseHeader → KILLED
            logVerboseHeader(log, csvFile, roots, desiredState);
170 2 1. apply : removed conditional - replaced equality check with true → SURVIVED
2. apply : removed conditional - replaced equality check with false → SURVIVED
            if (promoteAi) {
171 1 1. apply : removed call to java/io/PrintWriter::println → NO_COVERAGE
                log.println("[verbose] -promote-ai: ENABLED — blank tags/display_name "
172
                        + "will be filled from ai_tags/ai_display_name (unvalidated AI output)");
173
            }
174
        }
175
176
        // ── Step 2: scan source to build current method inventory ─────────────
177
        // Build a map from source file path → list of (fqcn, methodName) pairs
178
        // by asking each SourcePatcher to discover methods in supported files.
179
        Map<Path, List<MethodKey>> sourceIndex =
180
                buildSourceIndex(roots, patchers);
181
182
        Set<String> sourceKeys = new LinkedHashSet<>();
183
        for (List<MethodKey> methods : sourceIndex.values()) {
184
            for (MethodKey mk : methods) {
185
                sourceKeys.add(key(mk.fqcn(), mk.method()));
186
            }
187
        }
188
189 2 1. apply : removed conditional - replaced equality check with true → SURVIVED
2. apply : removed conditional - replaced equality check with false → KILLED
        if (verbose) {
190 1 1. apply : removed call to org/egothor/methodatlas/ApplyTagsFromCsvEngine::logVerboseSource → KILLED
            logVerboseSource(log, sourceIndex, sourceKeys);
191
        }
192
193
        // ── Step 3: compute mismatches (symmetric difference) ─────────────────
194
        Set<String> inCsvNotSource = new LinkedHashSet<>(desiredState.keySet());
195
        inCsvNotSource.removeAll(sourceKeys);
196
197
        Set<String> inSourceNotCsv = new LinkedHashSet<>(sourceKeys);
198
        inSourceNotCsv.removeAll(desiredState.keySet());
199
200 1 1. apply : Replaced integer addition with subtraction → KILLED
        int mismatchCount = inCsvNotSource.size() + inSourceNotCsv.size();
201
202 2 1. apply : removed conditional - replaced equality check with true → SURVIVED
2. apply : removed conditional - replaced equality check with false → KILLED
        if (verbose) {
203 1 1. apply : removed call to org/egothor/methodatlas/ApplyTagsFromCsvEngine::logVerboseMatch → KILLED
            logVerboseMatch(log, desiredState.size(), inCsvNotSource, inSourceNotCsv);
204
        }
205
206
        // ── Step 4: enforce mismatch limit ────────────────────────────────────
207 6 1. apply : changed conditional boundary → SURVIVED
2. apply : removed conditional - replaced comparison check with false → KILLED
3. apply : removed conditional - replaced comparison check with true → KILLED
4. apply : changed conditional boundary → KILLED
5. apply : removed conditional - replaced comparison check with true → KILLED
6. apply : removed conditional - replaced comparison check with false → KILLED
        if (mismatchLimit >= 0 && mismatchCount >= mismatchLimit) {
208 1 1. apply : replaced int return with 0 for org/egothor/methodatlas/ApplyTagsFromCsvEngine::apply → KILLED
            return reportMismatchesAndAbort(inCsvNotSource, inSourceNotCsv, mismatchCount, mismatchLimit, log);
209
        }
210
211
        // ── Step 5: warn about mismatches (no limit, or below limit) ──────────
212 1 1. apply : removed call to org/egothor/methodatlas/ApplyTagsFromCsvEngine::warnMismatches → SURVIVED
        warnMismatches(inCsvNotSource, inSourceNotCsv);
213
214
        // ── Step 6: apply changes file by file ────────────────────────────────
215 1 1. apply : replaced int return with 0 for org/egothor/methodatlas/ApplyTagsFromCsvEngine::apply → SURVIVED
        return applyFilesLoop(sourceIndex, desiredState, patchers, mismatchCount, log, verbose, promoteAi);
216
    }
217
218
    private static int reportMismatchesAndAbort(Set<String> inCsvNotSource, Set<String> inSourceNotCsv,
219
            int mismatchCount, int mismatchLimit, PrintWriter log) {
220
        for (String k : inCsvNotSource) {
221 1 1. reportMismatchesAndAbort : removed call to java/io/PrintWriter::println → KILLED
            log.println("MISMATCH (in CSV, not in source): " + k);
222
        }
223
        for (String k : inSourceNotCsv) {
224 1 1. reportMismatchesAndAbort : removed call to java/io/PrintWriter::println → SURVIVED
            log.println("MISMATCH (in source, not in CSV): " + k);
225
        }
226 1 1. reportMismatchesAndAbort : removed call to java/io/PrintWriter::println → KILLED
        log.println("Apply-tags-from-csv aborted: " + mismatchCount
227
                + " mismatch(es) >= limit " + mismatchLimit + ". No source files were modified.");
228 1 1. reportMismatchesAndAbort : replaced int return with 0 for org/egothor/methodatlas/ApplyTagsFromCsvEngine::reportMismatchesAndAbort → KILLED
        return 1;
229
    }
230
231
    private static void warnMismatches(Set<String> inCsvNotSource, Set<String> inSourceNotCsv) {
232
        if (LOG.isLoggable(Level.WARNING)) {
233
            for (String k : inCsvNotSource) {
234
                LOG.warning("Mismatch (in CSV, not found in source): " + k);
235
            }
236
            for (String k : inSourceNotCsv) {
237
                LOG.warning("Mismatch (in source, not present in CSV): " + k);
238
            }
239
        }
240
    }
241
242
    private static int applyFilesLoop(Map<Path, List<MethodKey>> sourceIndex,
243
            Map<String, ScanRecord> desiredState, List<SourcePatcher> patchers,
244
            int mismatchCount, PrintWriter log, boolean verbose, boolean promoteAi) {
245
        int modifiedFiles = 0;
246
        int totalChanges = 0;
247
        int skippedFiles = 0;
248
        int totalPromoted = 0;
249
        boolean hadErrors = false;
250
251
        for (Map.Entry<Path, List<MethodKey>> entry : sourceIndex.entrySet()) {
252
            FileOutcome outcome = processFile(entry.getKey(), entry.getValue(),
253
                    desiredState, patchers, log, verbose, promoteAi);
254 1 1. applyFilesLoop : Replaced integer addition with subtraction → SURVIVED
            totalChanges += outcome.changes();
255 1 1. applyFilesLoop : Replaced integer addition with subtraction → SURVIVED
            totalPromoted += outcome.promoted();
256 3 1. applyFilesLoop : removed conditional - replaced comparison check with false → SURVIVED
2. applyFilesLoop : changed conditional boundary → KILLED
3. applyFilesLoop : removed conditional - replaced comparison check with true → KILLED
            if (outcome.changes() > 0) {
257 1 1. applyFilesLoop : Changed increment from 1 to -1 → SURVIVED
                modifiedFiles++;
258
            }
259 2 1. applyFilesLoop : removed conditional - replaced equality check with false → SURVIVED
2. applyFilesLoop : removed conditional - replaced equality check with true → SURVIVED
            if (outcome.skipped()) {
260 1 1. applyFilesLoop : Changed increment from 1 to -1 → NO_COVERAGE
                skippedFiles++;
261
            }
262 2 1. applyFilesLoop : removed conditional - replaced equality check with false → SURVIVED
2. applyFilesLoop : removed conditional - replaced equality check with true → KILLED
            if (outcome.error()) {
263
                hadErrors = true;
264
            }
265
        }
266
267
        // Capacity 320 comfortably covers the worst-case message:
268
        //   "Apply-tags-from-csv complete: <int> change(s) in <int> file(s);
269
        //    <int> mismatch(es) skipped. <int> file(s) skipped (no source
270
        //    write-back support for the language). <int> value(s) promoted from
271
        //    AI columns (unvalidated — used with -promote-ai)."
272
        StringBuilder summary = new StringBuilder(320)
273
                .append("Apply-tags-from-csv complete: ")
274
                .append(totalChanges).append(" change(s) in ")
275
                .append(modifiedFiles).append(" file(s); ")
276
                .append(mismatchCount).append(" mismatch(es) skipped.");
277 3 1. applyFilesLoop : removed conditional - replaced comparison check with true → SURVIVED
2. applyFilesLoop : changed conditional boundary → SURVIVED
3. applyFilesLoop : removed conditional - replaced comparison check with false → SURVIVED
        if (skippedFiles > 0) {
278
            summary.append(' ').append(skippedFiles)
279
                    .append(" file(s) skipped (no source write-back support for the language).");
280
        }
281 2 1. applyFilesLoop : removed conditional - replaced equality check with true → SURVIVED
2. applyFilesLoop : removed conditional - replaced equality check with false → KILLED
        if (promoteAi) {
282
            summary.append(' ').append(totalPromoted)
283
                    .append(" value(s) promoted from AI columns (unvalidated — used with -promote-ai).");
284
        }
285 1 1. applyFilesLoop : removed call to java/io/PrintWriter::println → KILLED
        log.println(summary.toString());
286 4 1. applyFilesLoop : removed conditional - replaced equality check with true → SURVIVED
2. applyFilesLoop : removed conditional - replaced equality check with true → SURVIVED
3. applyFilesLoop : removed conditional - replaced equality check with false → KILLED
4. applyFilesLoop : removed conditional - replaced equality check with false → KILLED
        if (totalChanges == 0 && !verbose) {
287 1 1. applyFilesLoop : removed call to java/io/PrintWriter::println → KILLED
            log.println("Hint: no methods were updated. Re-run with -verbose to print the CSV keys, "
288
                    + "the keys discovered in the source, and the key-by-key match result — the "
289
                    + "usual cause is a fully qualified class name or working-directory mismatch.");
290
        }
291 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;
292
    }
293
294
    /**
295
     * Applies the desired state to a single source file and reports the outcome.
296
     *
297
     * @param path         source file to patch
298
     * @param methods      methods discovered in {@code path}
299
     * @param desiredState CSV desired state keyed by {@code <fqcn>::<method>}
300
     * @param patchers     configured source patchers
301
     * @param log          progress writer
302
     * @param verbose      whether to print per-file diagnostics
303
     * @param promoteAi    whether to fall back to the AI columns for blank
304
     *                     curated values (risky; see the class Javadoc)
305
     * @return the outcome (change count, promotion count, language-skip flag,
306
     *         error flag)
307
     */
308
    private static FileOutcome processFile(Path path, List<MethodKey> methods,
309
            Map<String, ScanRecord> desiredState, List<SourcePatcher> patchers,
310
            PrintWriter log, boolean verbose, boolean promoteAi) {
311 2 1. processFile : removed conditional - replaced equality check with false → SURVIVED
2. processFile : removed conditional - replaced equality check with true → KILLED
        if (!hasRelevantMethod(methods, desiredState)) {
312 2 1. processFile : removed conditional - replaced equality check with true → SURVIVED
2. processFile : removed conditional - replaced equality check with false → SURVIVED
            if (verbose) {
313 1 1. processFile : removed call to java/io/PrintWriter::println → SURVIVED
                log.println("[verbose] no CSV row matches any method in " + path + " — skipping");
314
            }
315 1 1. processFile : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine::processFile → KILLED
            return FileOutcome.NONE;
316
        }
317
318
        SourcePatcher patcher = patchers.stream()
319 2 1. lambda$processFile$0 : replaced boolean return with true for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$processFile$0 → SURVIVED
2. lambda$processFile$0 : replaced boolean return with false for org/egothor/methodatlas/ApplyTagsFromCsvEngine::lambda$processFile$0 → KILLED
                .filter(p -> p.supports(path))
320
                .findFirst().orElse(null);
321 2 1. processFile : removed conditional - replaced equality check with false → SURVIVED
2. processFile : removed conditional - replaced equality check with true → KILLED
        if (patcher == null) {
322
            if (LOG.isLoggable(Level.INFO)) {
323
                LOG.log(Level.INFO, "Skipping {0}: no SourcePatcher available for this language", path);
324
            }
325 1 1. processFile : removed call to java/io/PrintWriter::println → NO_COVERAGE
            log.println("Apply-tags-from-csv: skipped " + path
326
                    + " — source write-back is not supported for this language "
327
                    + "(currently Java and C# only)");
328 1 1. processFile : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine::processFile → NO_COVERAGE
            return FileOutcome.forSkip();
329
        }
330
331
        Map<String, List<String>> tagsToApply = new LinkedHashMap<>();
332
        Map<String, String> displayNames = new LinkedHashMap<>();
333
        int promoted = collectDesiredState(path, methods, desiredState, promoteAi,
334
                tagsToApply, displayNames, log, verbose);
335
336 2 1. processFile : removed conditional - replaced equality check with true → SURVIVED
2. processFile : removed conditional - replaced equality check with false → SURVIVED
        if (verbose) {
337 1 1. processFile : removed call to java/io/PrintWriter::println → NO_COVERAGE
            log.println("[verbose] applying to " + path + ": " + tagsToApply.size()
338
                    + " method(s) with a desired tag-set, " + displayNames.size()
339
                    + " with a desired display-name"
340 2 1. processFile : removed conditional - replaced equality check with false → NO_COVERAGE
2. processFile : removed conditional - replaced equality check with true → NO_COVERAGE
                    + (promoteAi ? "; " + promoted + " value(s) promoted from AI columns" : ""));
341
        }
342
        try {
343
            int changes = patcher.patch(path, tagsToApply, displayNames, log);
344 2 1. processFile : removed conditional - replaced equality check with true → SURVIVED
2. processFile : removed conditional - replaced equality check with false → SURVIVED
            if (verbose) {
345 1 1. processFile : removed call to java/io/PrintWriter::println → NO_COVERAGE
                log.println("[verbose]   -> " + changes + " change(s) written to " + path);
346
            }
347 1 1. processFile : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine::processFile → KILLED
            return FileOutcome.forChanges(changes, promoted);
348
        } catch (IOException e) {
349
            if (LOG.isLoggable(Level.WARNING)) {
350
                LOG.log(Level.WARNING, "Cannot process: " + path, e);
351
            }
352 1 1. processFile : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine::processFile → NO_COVERAGE
            return FileOutcome.forError();
353
        }
354
    }
355
356
    /**
357
     * Fills the {@code tagsToApply} and {@code displayNames} maps from the CSV
358
     * desired state for every method discovered in {@code path}, applying
359
     * AI-column promotion when {@code promoteAi} is set.
360
     *
361
     * <p>
362
     * The {@code displayNames} value carries the established three-way contract:
363
     * {@code null} (column absent) leaves {@code @DisplayName} untouched and is
364
     * therefore not put into the map; {@code ""} removes it; non-empty text sets
365
     * it. Promotion only substitutes an AI value when the curated value is blank
366
     * and a non-blank AI value is present, so the contract is preserved for
367
     * every method the operator curated by hand.
368
     * </p>
369
     *
370
     * @param path         source file being processed (used for verbose notices)
371
     * @param methods      methods discovered in {@code path}
372
     * @param desiredState CSV desired state keyed by {@code <fqcn>::<method>}
373
     * @param promoteAi    whether to fall back to the AI columns for blank values
374
     * @param tagsToApply  output map from method name to desired tag list
375
     * @param displayNames output map from method name to desired display name
376
     * @param log          progress writer for verbose per-promotion notices
377
     * @param verbose      whether to itemise each promotion
378
     * @return the number of values promoted from the AI columns
379
     */
380
    private static int collectDesiredState(Path path, List<MethodKey> methods,
381
            Map<String, ScanRecord> desiredState, boolean promoteAi,
382
            Map<String, List<String>> tagsToApply, Map<String, String> displayNames,
383
            PrintWriter log, boolean verbose) {
384
        int promoted = 0;
385
        for (MethodKey mk : methods) {
386
            ScanRecord desired = desiredState.get(key(mk.fqcn(), mk.method()));
387 2 1. collectDesiredState : removed conditional - replaced equality check with false → SURVIVED
2. collectDesiredState : removed conditional - replaced equality check with true → KILLED
            if (desired == null) {
388
                continue;
389
            }
390
            Resolved<List<String>> tags = resolveTags(desired, promoteAi);
391 2 1. collectDesiredState : removed conditional - replaced equality check with true → SURVIVED
2. collectDesiredState : removed conditional - replaced equality check with false → KILLED
            if (tags.value() != null) {
392
                tagsToApply.put(mk.method(), tags.value());
393
            }
394
            Resolved<String> name = resolveDisplayName(desired, promoteAi);
395 2 1. collectDesiredState : removed conditional - replaced equality check with true → SURVIVED
2. collectDesiredState : removed conditional - replaced equality check with false → KILLED
            if (name.value() != null) {
396
                displayNames.put(mk.method(), name.value());
397
            }
398 2 1. collectDesiredState : removed conditional - replaced equality check with true → SURVIVED
2. collectDesiredState : removed conditional - replaced equality check with false → SURVIVED
            if (tags.promoted()) {
399 1 1. collectDesiredState : Changed increment from 1 to -1 → SURVIVED
                promoted++;
400 1 1. collectDesiredState : removed call to org/egothor/methodatlas/ApplyTagsFromCsvEngine::logPromotion → SURVIVED
                logPromotion(log, verbose, path, mk, "tags <- ai_tags");
401
            }
402 2 1. collectDesiredState : removed conditional - replaced equality check with true → SURVIVED
2. collectDesiredState : removed conditional - replaced equality check with false → SURVIVED
            if (name.promoted()) {
403 1 1. collectDesiredState : Changed increment from 1 to -1 → SURVIVED
                promoted++;
404 1 1. collectDesiredState : removed call to org/egothor/methodatlas/ApplyTagsFromCsvEngine::logPromotion → SURVIVED
                logPromotion(log, verbose, path, mk, "display_name <- ai_display_name");
405
            }
406
        }
407 1 1. collectDesiredState : replaced int return with 0 for org/egothor/methodatlas/ApplyTagsFromCsvEngine::collectDesiredState → SURVIVED
        return promoted;
408
    }
409
410
    /**
411
     * Resolves the desired tag list for a record, optionally promoting the
412
     * {@code ai_tags} column when the curated {@code tags} column is blank.
413
     *
414
     * @param record    CSV record for the method
415
     * @param promoteAi whether AI promotion is enabled
416
     * @return the resolved tag list and whether it came from the AI column
417
     */
418
    private static Resolved<List<String>> resolveTags(ScanRecord record, boolean promoteAi) {
419
        List<String> curated = record.tags();
420 4 1. resolveTags : removed conditional - replaced equality check with true → SURVIVED
2. resolveTags : removed conditional - replaced equality check with false → KILLED
3. resolveTags : removed conditional - replaced equality check with false → KILLED
4. resolveTags : removed conditional - replaced equality check with true → KILLED
        boolean curatedBlank = curated == null || curated.isEmpty();
421
        List<String> ai = record.aiTags();
422 8 1. resolveTags : removed conditional - replaced equality check with true → SURVIVED
2. resolveTags : removed conditional - replaced equality check with true → SURVIVED
3. resolveTags : removed conditional - replaced equality check with true → KILLED
4. resolveTags : removed conditional - replaced equality check with false → KILLED
5. resolveTags : removed conditional - replaced equality check with true → KILLED
6. resolveTags : removed conditional - replaced equality check with false → KILLED
7. resolveTags : removed conditional - replaced equality check with false → KILLED
8. resolveTags : removed conditional - replaced equality check with false → KILLED
        if (promoteAi && curatedBlank && ai != null && !ai.isEmpty()) {
423 1 1. resolveTags : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine::resolveTags → KILLED
            return new Resolved<>(ai, true);
424
        }
425 1 1. resolveTags : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine::resolveTags → KILLED
        return new Resolved<>(curated, false);
426
    }
427
428
    /**
429
     * Resolves the desired display name for a record, optionally promoting the
430
     * {@code ai_display_name} column when the curated {@code display_name} column
431
     * is blank.
432
     *
433
     * @param record    CSV record for the method
434
     * @param promoteAi whether AI promotion is enabled
435
     * @return the resolved display name and whether it came from the AI column
436
     */
437
    private static Resolved<String> resolveDisplayName(ScanRecord record, boolean promoteAi) {
438
        String curated = record.displayName();
439 4 1. resolveDisplayName : removed conditional - replaced equality check with false → SURVIVED
2. resolveDisplayName : removed conditional - replaced equality check with true → SURVIVED
3. resolveDisplayName : removed conditional - replaced equality check with false → KILLED
4. resolveDisplayName : removed conditional - replaced equality check with true → KILLED
        boolean curatedBlank = curated == null || curated.isBlank();
440
        String ai = record.aiDisplayName();
441 8 1. resolveDisplayName : removed conditional - replaced equality check with true → SURVIVED
2. resolveDisplayName : removed conditional - replaced equality check with true → SURVIVED
3. resolveDisplayName : removed conditional - replaced equality check with false → KILLED
4. resolveDisplayName : removed conditional - replaced equality check with true → KILLED
5. resolveDisplayName : removed conditional - replaced equality check with false → KILLED
6. resolveDisplayName : removed conditional - replaced equality check with true → KILLED
7. resolveDisplayName : removed conditional - replaced equality check with false → KILLED
8. resolveDisplayName : removed conditional - replaced equality check with false → KILLED
        if (promoteAi && curatedBlank && ai != null && !ai.isBlank()) {
442 1 1. resolveDisplayName : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine::resolveDisplayName → KILLED
            return new Resolved<>(ai, true);
443
        }
444 1 1. resolveDisplayName : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine::resolveDisplayName → KILLED
        return new Resolved<>(curated, false);
445
    }
446
447
    /**
448
     * Writes a per-promotion audit notice under {@code -verbose}.
449
     *
450
     * @param log     progress writer
451
     * @param verbose whether verbose output is enabled
452
     * @param path    source file being processed
453
     * @param mk      method whose value was promoted
454
     * @param detail  short description of the promoted field
455
     */
456
    private static void logPromotion(PrintWriter log, boolean verbose, Path path,
457
            MethodKey mk, String detail) {
458 2 1. logPromotion : removed conditional - replaced equality check with false → SURVIVED
2. logPromotion : removed conditional - replaced equality check with true → SURVIVED
        if (verbose) {
459 1 1. logPromotion : removed call to java/io/PrintWriter::println → NO_COVERAGE
            log.println("[verbose]   [promote-ai] " + path + " " + mk.fqcn() + "::"
460
                    + mk.method() + " " + detail);
461
        }
462
    }
463
464
    /**
465
     * A resolved desired-state value paired with whether it was promoted from an
466
     * AI column rather than taken from a curated column.
467
     *
468
     * @param <T>      the value type ({@code List<String>} for tags,
469
     *                 {@code String} for display name)
470
     * @param value    the resolved value; may be {@code null} for display name
471
     *                 when the column was absent
472
     * @param promoted {@code true} when the value came from an AI column
473
     */
474
    private record Resolved<T>(T value, boolean promoted) {
475
    }
476
477
    /**
478
     * Outcome of patching one source file: the number of changes written, the
479
     * number of values promoted from AI columns, and whether the file was
480
     * skipped for lack of a {@link SourcePatcher} or failed with an I/O error.
481
     *
482
     * @param changes  number of annotation changes written (zero when none applied)
483
     * @param promoted number of desired-state values sourced from the AI columns
484
     * @param skipped  {@code true} when skipped because no patcher supports the language
485
     * @param error    {@code true} when patching threw an {@link IOException}
486
     */
487
    private record FileOutcome(int changes, int promoted, boolean skipped, boolean error) {
488
        private static final FileOutcome NONE = new FileOutcome(0, 0, false, false);
489
490
        private static FileOutcome forSkip() {
491 1 1. forSkip : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine$FileOutcome::forSkip → NO_COVERAGE
            return new FileOutcome(0, 0, true, false);
492
        }
493
494
        private static FileOutcome forError() {
495 1 1. forError : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine$FileOutcome::forError → NO_COVERAGE
            return new FileOutcome(0, 0, false, true);
496
        }
497
498
        private static FileOutcome forChanges(int changes, int promoted) {
499 1 1. forChanges : replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine$FileOutcome::forChanges → KILLED
            return new FileOutcome(changes, promoted, false, false);
500
        }
501
    }
502
503
    private static boolean hasRelevantMethod(List<MethodKey> methods, Map<String, ScanRecord> desiredState) {
504
        for (MethodKey mk : methods) {
505 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()))) {
506 1 1. hasRelevantMethod : replaced boolean return with false for org/egothor/methodatlas/ApplyTagsFromCsvEngine::hasRelevantMethod → KILLED
                return true;
507
            }
508
        }
509 1 1. hasRelevantMethod : replaced boolean return with true for org/egothor/methodatlas/ApplyTagsFromCsvEngine::hasRelevantMethod → SURVIVED
        return false;
510
    }
511
512
    /**
513
     * Scans source roots and builds an index mapping each source file to the
514
     * list of (FQCN, method) pairs for all test methods it contains.
515
     *
516
     * <p>
517
     * Each supported source file is passed to
518
     * {@link SourcePatcher#discoverMethodsByClass(Path)} to obtain the actual
519
     * test-method inventory. This gives the correct FQCN–method pairs
520
     * regardless of whether the source tree uses the standard
521
     * {@code package/to/ClassName.java} directory structure.
522
     * </p>
523
     *
524
     * @param roots    source root directories
525
     * @param patchers list of configured patchers used to identify supported files
526
     * @return map from source file path to list of {@link MethodKey} entries;
527
     *         never {@code null}
528
     * @throws IOException if a file tree cannot be traversed
529
     */
530
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
531
    private static Map<Path, List<MethodKey>> buildSourceIndex(
532
            List<Path> roots,
533
            List<SourcePatcher> patchers) throws IOException {
534
535
        Map<Path, List<MethodKey>> index = new HashMap<>();
536
537
        for (Path root : roots) {
538 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)) {
539
                continue;
540
            }
541
            try (Stream<Path> stream = Files.walk(root)) {
542
                for (Path path : (Iterable<Path>) stream
543 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) {
544
545
                    SourcePatcher patcher = patchers.stream()
546 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))
547
                            .findFirst().orElse(null);
548 2 1. buildSourceIndex : removed conditional - replaced equality check with true → KILLED
2. buildSourceIndex : removed conditional - replaced equality check with false → KILLED
                    if (patcher == null) {
549
                        continue;
550
                    }
551
552
                    // Ask the patcher to discover test methods in this file
553
                    Map<String, List<String>> byClass = patcher.discoverMethodsByClass(path);
554
                    List<MethodKey> keys = new ArrayList<>();
555
                    for (Map.Entry<String, List<String>> classEntry : byClass.entrySet()) {
556
                        String fqcn = classEntry.getKey();
557
                        for (String methodName : classEntry.getValue()) {
558
                            keys.add(new MethodKey(fqcn, methodName));
559
                        }
560
                    }
561 2 1. buildSourceIndex : removed conditional - replaced equality check with true → SURVIVED
2. buildSourceIndex : removed conditional - replaced equality check with false → KILLED
                    if (!keys.isEmpty()) {
562
                        index.put(path, keys);
563
                    }
564
                }
565
            }
566
        }
567
568 1 1. buildSourceIndex : replaced return value with Collections.emptyMap for org/egothor/methodatlas/ApplyTagsFromCsvEngine::buildSourceIndex → KILLED
        return index;
569
    }
570
571
    /**
572
     * Prints, under {@code -verbose}, the run context and the complete set of
573
     * desired-state keys loaded from the CSV.
574
     *
575
     * @param log          progress writer
576
     * @param csvFile      reviewed CSV path
577
     * @param roots        configured scan roots
578
     * @param desiredState CSV-derived desired state keyed by {@code <fqcn>::<method>}
579
     */
580
    private static void logVerboseHeader(PrintWriter log, Path csvFile, List<Path> roots,
581
            Map<String, ScanRecord> desiredState) {
582 1 1. logVerboseHeader : removed call to java/io/PrintWriter::println → SURVIVED
        log.println("[verbose] working directory: " + Paths.get("").toAbsolutePath());
583 1 1. logVerboseHeader : removed call to java/io/PrintWriter::println → SURVIVED
        log.println("[verbose] CSV file: " + csvFile.toAbsolutePath());
584
        for (Path root : roots) {
585 2 1. logVerboseHeader : removed conditional - replaced equality check with false → SURVIVED
2. logVerboseHeader : removed conditional - replaced equality check with true → SURVIVED
            String note = Files.isDirectory(root) ? "" : "  (NOT an existing directory)";
586 1 1. logVerboseHeader : removed call to java/io/PrintWriter::println → SURVIVED
            log.println("[verbose] scan root: " + root.toAbsolutePath() + note);
587
        }
588 1 1. logVerboseHeader : removed call to java/io/PrintWriter::println → KILLED
        log.println("[verbose] CSV desired-state keys (" + desiredState.size()
589
                + "); lookup format is <fqcn>::<method>:");
590
        desiredState.keySet().stream().sorted()
591 2 1. lambda$logVerboseHeader$3 : removed call to java/io/PrintWriter::println → SURVIVED
2. logVerboseHeader : removed call to java/util/stream/Stream::forEach → SURVIVED
                .forEach(k -> log.println("[verbose]   CSV  " + k));
592
    }
593
594
    /**
595
     * Prints, under {@code -verbose}, the keys discovered in the scanned source
596
     * tree (the right-hand side of the lookup).
597
     *
598
     * @param log         progress writer
599
     * @param sourceIndex source file to discovered methods
600
     * @param sourceKeys  flattened {@code <fqcn>::<method>} keys discovered in source
601
     */
602
    private static void logVerboseSource(PrintWriter log, Map<Path, List<MethodKey>> sourceIndex,
603
            Set<String> sourceKeys) {
604 1 1. logVerboseSource : removed call to java/io/PrintWriter::println → SURVIVED
        log.println("[verbose] source files with discoverable test methods: " + sourceIndex.size());
605 1 1. logVerboseSource : removed call to java/io/PrintWriter::println → KILLED
        log.println("[verbose] source keys (" + sourceKeys.size() + "):");
606 2 1. logVerboseSource : removed call to java/util/stream/Stream::forEach → SURVIVED
2. lambda$logVerboseSource$4 : removed call to java/io/PrintWriter::println → SURVIVED
        sourceKeys.stream().sorted().forEach(k -> log.println("[verbose]   SRC  " + k));
607 2 1. logVerboseSource : removed conditional - replaced equality check with true → SURVIVED
2. logVerboseSource : removed conditional - replaced equality check with false → SURVIVED
        if (sourceKeys.isEmpty()) {
608 1 1. logVerboseSource : removed call to java/io/PrintWriter::println → NO_COVERAGE
            log.println("[verbose] No test methods were discovered under the scan root(s). "
609
                    + "Confirm the command is run from the correct directory and that the files "
610
                    + "use a language with source write-back support (Java, C#).");
611
        }
612
    }
613
614
    /**
615
     * Prints, under {@code -verbose}, the key-by-key match result so an operator
616
     * can see exactly which CSV rows failed to line up with a source method.
617
     *
618
     * @param log             progress writer
619
     * @param desiredCount    number of CSV desired-state keys
620
     * @param inCsvNotSource  keys present in the CSV but absent from source
621
     * @param inSourceNotCsv  keys present in source but absent from the CSV
622
     */
623
    private static void logVerboseMatch(PrintWriter log, int desiredCount,
624
            Set<String> inCsvNotSource, Set<String> inSourceNotCsv) {
625 1 1. logVerboseMatch : removed call to java/io/PrintWriter::println → SURVIVED
        log.println("[verbose] matched keys (present in both CSV and source): "
626 1 1. logVerboseMatch : Replaced integer subtraction with addition → SURVIVED
                + (desiredCount - inCsvNotSource.size()));
627 1 1. logVerboseMatch : removed call to java/io/PrintWriter::println → SURVIVED
        log.println("[verbose] in CSV but NOT found in source (" + inCsvNotSource.size() + "):");
628 2 1. logVerboseMatch : removed call to java/util/stream/Stream::forEach → KILLED
2. lambda$logVerboseMatch$5 : removed call to java/io/PrintWriter::println → KILLED
        inCsvNotSource.stream().sorted().forEach(k -> log.println("[verbose]   CSV-only  " + k));
629 1 1. logVerboseMatch : removed call to java/io/PrintWriter::println → SURVIVED
        log.println("[verbose] in source but NOT present in CSV (" + inSourceNotCsv.size() + "):");
630 2 1. lambda$logVerboseMatch$6 : removed call to java/io/PrintWriter::println → KILLED
2. logVerboseMatch : removed call to java/util/stream/Stream::forEach → KILLED
        inSourceNotCsv.stream().sorted().forEach(k -> log.println("[verbose]   SRC-only  " + k));
631
    }
632
633
    private static String key(String fqcn, String method) {
634 1 1. key : replaced return value with "" for org/egothor/methodatlas/ApplyTagsFromCsvEngine::key → KILLED
        return fqcn + "::" + method;
635
    }
636
637
    /** Lightweight tuple holding a fully qualified class name and a method name. */
638
    private record MethodKey(String fqcn, String method) {
639
    }
640
}

Mutations

158

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 conditional - replaced equality check with false → 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 equality check with true → KILLED

159

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

163

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

168

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

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

169

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

170

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

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

171

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

189

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

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

190

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

200

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

202

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

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

203

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

207

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 comparison check with false → KILLED

2.2
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

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

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

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

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

208

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

212

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

215

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

221

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

224

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

226

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

228

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

254

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

255

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

256

1.1
Location : applyFilesLoop
Killed by : none
removed conditional - replaced comparison 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_zeroUpdates_printsVerboseHintWhenNotVerbose(java.nio.file.Path)]
changed conditional boundary → KILLED

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

257

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

259

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

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

260

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

262

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

277

1.1
Location : applyFilesLoop
Killed by : none
removed conditional - replaced comparison check with true → 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 false → SURVIVED Covering tests

281

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

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

285

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

286

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

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

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

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

287

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

291

1.1
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

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

311

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

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

312

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

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

313

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

315

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

319

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

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

321

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

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

325

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

328

1.1
Location : processFile
Killed by : none
replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine::processFile → NO_COVERAGE

336

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

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

337

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

340

1.1
Location : processFile
Killed by : none
removed conditional - replaced equality check with false → NO_COVERAGE

2.2
Location : processFile
Killed by : none
removed conditional - replaced equality check with true → NO_COVERAGE

344

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

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

345

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

347

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

352

1.1
Location : processFile
Killed by : none
replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine::processFile → NO_COVERAGE

387

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

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

391

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

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

395

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

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

398

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

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

399

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

400

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

402

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

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

403

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

404

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

407

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

420

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

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

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

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

422

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

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

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

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

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

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

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

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

423

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

425

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

439

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

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

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

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

441

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

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

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

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

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

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

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

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

442

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

444

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

458

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

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

459

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

491

1.1
Location : forSkip
Killed by : none
replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine$FileOutcome::forSkip → NO_COVERAGE

495

1.1
Location : forError
Killed by : none
replaced return value with null for org/egothor/methodatlas/ApplyTagsFromCsvEngine$FileOutcome::forError → NO_COVERAGE

499

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

505

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_setsDisplayNameFromCsv(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

506

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

509

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

538

1.1
Location : buildSourceIndex
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_verbose_revealsFqcnMismatch(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

543

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

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

546

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

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

548

1.1
Location : buildSourceIndex
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_verbose_revealsFqcnMismatch(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

561

1.1
Location : buildSourceIndex
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_verbose_revealsFqcnMismatch(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

568

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

582

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

583

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

585

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

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

586

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

588

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

591

1.1
Location : lambda$logVerboseHeader$3
Killed by : none
removed call to java/io/PrintWriter::println → SURVIVED
Covering tests

2.2
Location : logVerboseHeader
Killed by : none
removed call to java/util/stream/Stream::forEach → SURVIVED Covering tests

604

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

605

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

606

1.1
Location : logVerboseSource
Killed by : none
removed call to java/util/stream/Stream::forEach → SURVIVED
Covering tests

2.2
Location : lambda$logVerboseSource$4
Killed by : none
removed call to java/io/PrintWriter::println → SURVIVED Covering tests

607

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

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

608

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

625

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

626

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

627

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

628

1.1
Location : logVerboseMatch
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_verbose_revealsFqcnMismatch(java.nio.file.Path)]
removed call to java/util/stream/Stream::forEach → KILLED

2.2
Location : lambda$logVerboseMatch$5
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_verbose_revealsFqcnMismatch(java.nio.file.Path)]
removed call to java/io/PrintWriter::println → KILLED

629

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

630

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

2.2
Location : logVerboseMatch
Killed by : org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppApplyTagsFromCsvTest]/[method:applyTagsFromCsv_verbose_revealsFqcnMismatch(java.nio.file.Path)]
removed call to java/util/stream/Stream::forEach → KILLED

634

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