ClassificationOverride.java

1
package org.egothor.methodatlas;
2
3
import java.io.IOException;
4
import java.nio.file.Path;
5
import java.util.ArrayList;
6
import java.util.HashMap;
7
import java.util.List;
8
import java.util.Map;
9
import java.util.logging.Level;
10
import java.util.logging.Logger;
11
12
import org.egothor.methodatlas.ai.AiClassSuggestion;
13
import org.egothor.methodatlas.ai.AiMethodSuggestion;
14
15
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
16
import com.fasterxml.jackson.annotation.JsonProperty;
17
import com.fasterxml.jackson.databind.DeserializationFeature;
18
import com.fasterxml.jackson.databind.ObjectMapper;
19
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
20
21
/**
22
 * Applies human-authored classification overrides to AI-generated (or absent)
23
 * security classification results.
24
 *
25
 * <h2>Purpose</h2>
26
 *
27
 * <p>
28
 * AI classification is a best-effort semantic analysis. In practice, a provider
29
 * may under-classify a method that is clearly security-relevant, over-classify a
30
 * utility method, assign incorrect tags, or produce a rationale that does not
31
 * meet audit requirements. {@code ClassificationOverride} allows a team or
32
 * individual to record corrections in a persistent YAML file so that re-running
33
 * MethodAtlas does not lose those decisions.
34
 * </p>
35
 *
36
 * <p>
37
 * Overrides are also the only mechanism for adding AI-style enrichment columns
38
 * to methods that are not going through live AI or the manual workflow — for
39
 * example, when running in static inventory mode with a trusted set of
40
 * hand-reviewed classifications.
41
 * </p>
42
 *
43
 * <h2>Override File Format</h2>
44
 *
45
 * <p>
46
 * The override file is a YAML document with a top-level {@code overrides} list.
47
 * Each entry targets either a single method (when {@code method} is present) or
48
 * every method in a class (when {@code method} is absent). Only the fields you
49
 * specify are overridden; unspecified fields retain their AI-derived or
50
 * default values.
51
 * </p>
52
 *
53
 * <pre>
54
 * overrides:
55
 *
56
 *   # Correct a false positive: AI classified this as security-relevant but it is not.
57
 *   - fqcn: com.acme.util.DateFormatterTest
58
 *     method: format_returnsIso8601
59
 *     securityRelevant: false
60
 *     reason: "Date formatting only — no security property tested"
61
 *     note: "Reviewed 2026-04-24 by alice"
62
 *
63
 *   # Correct a false negative: AI missed this security-critical test.
64
 *   - fqcn: com.acme.crypto.AesGcmTest
65
 *     method: roundTrip_encryptDecrypt
66
 *     securityRelevant: true
67
 *     tags: [security, crypto]
68
 *     displayName: "SECURITY: crypto — AES-GCM round-trip"
69
 *     reason: "Verifies ciphertext integrity under AES-GCM — critical crypto test"
70
 *     note: "Confirmed by security team 2026-04-20"
71
 *
72
 *   # Classify all methods in a class (no 'method' field = class-level override).
73
 *   - fqcn: com.acme.auth.Oauth2FlowTest
74
 *     securityRelevant: true
75
 *     tags: [security, auth]
76
 *     note: "Entire class covers OAuth 2.0 flow — AI taxonomy too narrow"
77
 * </pre>
78
 *
79
 * <h2>Field Reference</h2>
80
 *
81
 * <ul>
82
 * <li>{@code fqcn} — fully qualified class name; required; must match the
83
 *     {@code fqcn} column in MethodAtlas output</li>
84
 * <li>{@code method} — method name; optional; when absent the override applies
85
 *     to all methods in the class; method-level overrides take precedence over
86
 *     class-level overrides for the same class</li>
87
 * <li>{@code securityRelevant} — {@code true} or {@code false}; optional; when
88
 *     absent the AI decision (or default {@code false}) is kept</li>
89
 * <li>{@code tags} — YAML list of security taxonomy tags; optional; when absent
90
 *     the AI tags (or an empty list) are kept</li>
91
 * <li>{@code displayName} — suggested {@code @DisplayName} value; optional;
92
 *     when absent the AI-suggested name (or {@code null}) is kept</li>
93
 * <li>{@code reason} — human-readable rationale for the classification;
94
 *     optional; when absent the AI rationale (or {@code null}) is kept</li>
95
 * <li>{@code note} — free-text annotation for human use only; never appears in
96
 *     any MethodAtlas output; useful for recording reviewer identity, date, and
97
 *     decision context</li>
98
 * </ul>
99
 *
100
 * <h2>Confidence Behaviour</h2>
101
 *
102
 * <p>
103
 * When any override field is applied to a method, the output confidence value
104
 * is set to {@code 1.0} if the method is classified as security-relevant, or
105
 * {@code 0.0} otherwise. This reflects the fact that a human review provides
106
 * higher certainty than any AI score and ensures that confidence-based filters
107
 * (such as {@code --min-confidence}) do not suppress human-verified results.
108
 * </p>
109
 *
110
 * <h2>Integration Points</h2>
111
 *
112
 * <p>
113
 * {@code ClassificationOverride} works in all MethodAtlas operating modes:
114
 * </p>
115
 *
116
 * <ul>
117
 * <li><b>Live AI mode</b> ({@code -ai}) — AI result is obtained first;
118
 *     overrides are applied on top.</li>
119
 * <li><b>Manual AI workflow</b> ({@code -manual-consume}) — operator-filled
120
 *     responses are loaded first; overrides are applied on top.</li>
121
 * <li><b>Static mode</b> (no {@code -ai}) — no AI result exists; any override
122
 *     that marks a method as security-relevant synthesizes a full
123
 *     {@link AiMethodSuggestion} from the override fields alone.</li>
124
 * </ul>
125
 *
126
 * <h2>Unknown Methods</h2>
127
 *
128
 * <p>
129
 * Override entries that reference a method name not found in the parsed source
130
 * are silently ignored. This means old entries remain harmless after methods are
131
 * renamed or deleted, and the file does not need to be pruned after refactoring.
132
 * </p>
133
 *
134
 * @see AiClassSuggestion
135
 * @see AiMethodSuggestion
136
 */
137
public final class ClassificationOverride {
138
139
    private static final Logger LOG = Logger.getLogger(ClassificationOverride.class.getName());
140
141
    /**
142
     * Singleton instance used when no override file is configured. All calls to
143
     * {@link #apply} return the original suggestion unchanged.
144
     */
145
    private static final ClassificationOverride EMPTY = new ClassificationOverride(Map.of());
146
147
    /**
148
     * Override entries grouped by fully qualified class name for O(1) lookup.
149
     */
150
    private final Map<String, List<Entry>> byClass;
151
152
    private ClassificationOverride(Map<String, List<Entry>> byClass) {
153
        this.byClass = byClass;
154
    }
155
156
    /**
157
     * Returns an empty override set that leaves all classifications unchanged.
158
     *
159
     * <p>
160
     * Use this when no override file is configured.
161
     * </p>
162
     *
163
     * @return shared empty instance
164
     */
165
    public static ClassificationOverride empty() {
166 1 1. empty : replaced return value with null for org/egothor/methodatlas/ClassificationOverride::empty → KILLED
        return EMPTY;
167
    }
168
169
    /**
170
     * Loads an override file from the given path.
171
     *
172
     * <p>
173
     * The file must be a YAML document with a top-level {@code overrides} list.
174
     * See the class Javadoc for the expected structure. Unknown YAML fields are
175
     * silently ignored, so the file can carry additional human-readable metadata
176
     * beyond the recognized fields without causing parse errors.
177
     * </p>
178
     *
179
     * @param path path to the YAML override file
180
     * @return loaded override set; never {@code null}
181
     * @throws IOException if the file cannot be read or contains invalid YAML
182
     */
183
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
184
    public static ClassificationOverride load(Path path) throws IOException {
185
        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
186
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
187
        OverrideFile file = mapper.readValue(path.toFile(), OverrideFile.class);
188
189 4 1. load : removed conditional - replaced equality check with false → SURVIVED
2. load : removed conditional - replaced equality check with true → SURVIVED
3. load : removed conditional - replaced equality check with false → KILLED
4. load : removed conditional - replaced equality check with true → KILLED
        if (file.overrides == null || file.overrides.isEmpty()) {
190 1 1. load : replaced return value with null for org/egothor/methodatlas/ClassificationOverride::load → KILLED
            return EMPTY;
191
        }
192
193
        Map<String, List<Entry>> byClass = new HashMap<>();
194
        for (EntryDto dto : file.overrides) {
195 4 1. load : removed conditional - replaced equality check with true → SURVIVED
2. load : removed conditional - replaced equality check with true → KILLED
3. load : removed conditional - replaced equality check with false → KILLED
4. load : removed conditional - replaced equality check with false → KILLED
            if (dto.fqcn == null || dto.fqcn.isBlank()) {
196
                if (LOG.isLoggable(Level.WARNING)) {
197
                    LOG.warning("Override entry without fqcn skipped");
198
                }
199
                continue;
200
            }
201 1 1. lambda$load$0 : replaced return value with Collections.emptyList for org/egothor/methodatlas/ClassificationOverride::lambda$load$0 → KILLED
            byClass.computeIfAbsent(dto.fqcn, k -> new ArrayList<>())
202
                    .add(new Entry(dto.fqcn, dto.method, dto.securityRelevant,
203
                            dto.tags, dto.displayName, dto.reason, dto.note));
204
        }
205
206 1 1. load : replaced return value with null for org/egothor/methodatlas/ClassificationOverride::load → KILLED
        return new ClassificationOverride(byClass);
207
    }
208
209
    /**
210
     * Returns {@code true} if at least one override entry targets the given class.
211
     *
212
     * <p>
213
     * This can be used to decide whether {@link #apply} should be called even
214
     * when no AI suggestion was produced (e.g. in static mode), avoiding
215
     * unnecessary processing for classes that have no overrides.
216
     * </p>
217
     *
218
     * @param fqcn fully qualified class name to check
219
     * @return {@code true} if overrides exist for {@code fqcn}
220
     */
221
    public boolean hasOverridesFor(String fqcn) {
222 2 1. hasOverridesFor : replaced boolean return with false for org/egothor/methodatlas/ClassificationOverride::hasOverridesFor → KILLED
2. hasOverridesFor : replaced boolean return with true for org/egothor/methodatlas/ClassificationOverride::hasOverridesFor → KILLED
        return byClass.containsKey(fqcn);
223
    }
224
225
    /**
226
     * Applies override entries to an existing AI classification result.
227
     *
228
     * <p>
229
     * The {@code methodNames} list must contain the canonical method names as
230
     * discovered by the MethodAtlas parser. It drives the set of methods for
231
     * which output records are produced; override entries targeting method names
232
     * absent from this list are silently skipped.
233
     * </p>
234
     *
235
     * <p>
236
     * When {@code suggestion} is {@code null} and no overrides target
237
     * {@code fqcn}, this method returns {@code null} unchanged so that the
238
     * absence of AI data is preserved correctly in the output.
239
     * </p>
240
     *
241
     * <p>
242
     * When {@code suggestion} is {@code null} but at least one override targets
243
     * {@code fqcn}, a synthetic {@link AiClassSuggestion} is constructed from
244
     * the override fields. Methods not targeted by any override will have
245
     * {@code securityRelevant=false} and empty tag/reason fields in the
246
     * synthesized result.
247
     * </p>
248
     *
249
     * @param fqcn        fully qualified class name of the class being processed
250
     * @param suggestion  AI classification result to modify; may be {@code null}
251
     * @param methodNames names of all test methods found by the parser in this
252
     *                    class, in discovery order
253
     * @return modified or synthesized classification; {@code null} only when both
254
     *         {@code suggestion} is {@code null} and no overrides target
255
     *         {@code fqcn}
256
     */
257
    @SuppressWarnings("PMD.NPathComplexity")
258
    public AiClassSuggestion apply(String fqcn, AiClassSuggestion suggestion, List<String> methodNames) {
259
        List<Entry> entries = byClass.get(fqcn);
260
261 4 1. apply : removed conditional - replaced equality check with false → SURVIVED
2. apply : removed conditional - replaced equality check with false → KILLED
3. apply : removed conditional - replaced equality check with true → KILLED
4. apply : removed conditional - replaced equality check with true → KILLED
        if (entries == null || entries.isEmpty()) {
262 1 1. apply : replaced return value with null for org/egothor/methodatlas/ClassificationOverride::apply → KILLED
            return suggestion;
263
        }
264
265
        // Separate class-level override (no method specified) from method-level entries.
266
        // If multiple class-level entries exist for the same FQCN, the last one wins.
267
        Entry classLevel = null;
268
        Map<String, Entry> methodLevel = new HashMap<>();
269
        for (Entry e : entries) {
270 2 1. apply : removed conditional - replaced equality check with true → KILLED
2. apply : removed conditional - replaced equality check with false → KILLED
            if (e.method() == null) {
271
                classLevel = e;
272
            } else {
273
                methodLevel.put(e.method(), e);
274
            }
275
        }
276
277
        // Build a name → existing suggestion map for quick lookup.
278 4 1. apply : removed conditional - replaced equality check with true → SURVIVED
2. apply : removed conditional - replaced equality check with false → KILLED
3. apply : removed conditional - replaced equality check with false → KILLED
4. apply : removed conditional - replaced equality check with true → KILLED
        List<AiMethodSuggestion> existingMethods = (suggestion != null && suggestion.methods() != null)
279
                ? suggestion.methods() : List.of();
280
        Map<String, AiMethodSuggestion> existingByName = new HashMap<>();
281
        for (AiMethodSuggestion m : existingMethods) {
282
            existingByName.put(m.methodName(), m);
283
        }
284
285
        // Apply overrides to each method found by the parser.
286
        List<AiMethodSuggestion> merged = new ArrayList<>(methodNames.size());
287
        for (String name : methodNames) {
288
            AiMethodSuggestion base = existingByName.get(name);
289
            Entry effective = methodLevel.getOrDefault(name, classLevel);
290
            merged.add(mergeMethod(name, base, effective));
291
        }
292
293
        // Class-level suggestion fields are carried through from the original,
294
        // or left null when no AI suggestion was available.
295 1 1. apply : replaced return value with null for org/egothor/methodatlas/ClassificationOverride::apply → KILLED
        return new AiClassSuggestion(
296 2 1. apply : removed conditional - replaced equality check with false → SURVIVED
2. apply : removed conditional - replaced equality check with true → KILLED
                suggestion != null ? suggestion.className() : fqcn,
297 2 1. apply : removed conditional - replaced equality check with false → SURVIVED
2. apply : removed conditional - replaced equality check with true → KILLED
                suggestion != null ? suggestion.classSecurityRelevant() : null,
298 2 1. apply : removed conditional - replaced equality check with false → SURVIVED
2. apply : removed conditional - replaced equality check with true → KILLED
                suggestion != null ? suggestion.classTags() : null,
299 2 1. apply : removed conditional - replaced equality check with false → SURVIVED
2. apply : removed conditional - replaced equality check with true → KILLED
                suggestion != null ? suggestion.classReason() : null,
300
                merged);
301
    }
302
303
    /**
304
     * Merges a single method's base classification with the applicable override
305
     * entry.
306
     *
307
     * <p>
308
     * Fields present in the override replace the corresponding base values.
309
     * Fields absent in the override retain their base values (or defaults when
310
     * no base classification exists). When any override field is applied, the
311
     * confidence is set to {@code 1.0} for security-relevant results and
312
     * {@code 0.0} otherwise, reflecting the higher certainty of human review.
313
     * </p>
314
     *
315
     * @param name     method name
316
     * @param base     existing AI suggestion for this method; may be {@code null}
317
     * @param override override entry to apply; may be {@code null} (no-op)
318
     * @return resulting method suggestion; never {@code null}
319
     */
320
    @SuppressWarnings("PMD.NPathComplexity")
321
    private static AiMethodSuggestion mergeMethod(String name, AiMethodSuggestion base, Entry override) {
322 2 1. mergeMethod : removed conditional - replaced equality check with false → KILLED
2. mergeMethod : removed conditional - replaced equality check with true → KILLED
        if (override == null) {
323
            // No override — synthesize a neutral record if base is absent.
324 2 1. mergeMethod : removed conditional - replaced equality check with false → SURVIVED
2. mergeMethod : removed conditional - replaced equality check with true → SURVIVED
            if (base != null) {
325 1 1. mergeMethod : replaced return value with null for org/egothor/methodatlas/ClassificationOverride::mergeMethod → KILLED
                return base;
326
            }
327 1 1. mergeMethod : replaced return value with null for org/egothor/methodatlas/ClassificationOverride::mergeMethod → NO_COVERAGE
            return new AiMethodSuggestion(name, false, null, List.of(), null, 0.0, 0.0);
328
        }
329
330 4 1. mergeMethod : removed conditional - replaced equality check with false → SURVIVED
2. mergeMethod : removed conditional - replaced equality check with true → SURVIVED
3. mergeMethod : removed conditional - replaced equality check with false → SURVIVED
4. mergeMethod : removed conditional - replaced equality check with true → KILLED
        boolean securityRelevant = base != null && base.securityRelevant();
331 4 1. mergeMethod : removed conditional - replaced equality check with true → SURVIVED
2. mergeMethod : removed conditional - replaced equality check with false → KILLED
3. mergeMethod : removed conditional - replaced equality check with false → KILLED
4. mergeMethod : removed conditional - replaced equality check with true → KILLED
        List<String> tags = (base != null && base.tags() != null) ? base.tags() : List.of();
332 2 1. mergeMethod : removed conditional - replaced equality check with false → SURVIVED
2. mergeMethod : removed conditional - replaced equality check with true → KILLED
        String displayName = base != null ? base.displayName() : null;
333 2 1. mergeMethod : removed conditional - replaced equality check with false → KILLED
2. mergeMethod : removed conditional - replaced equality check with true → KILLED
        String reason = base != null ? base.reason() : null;
334
335 2 1. mergeMethod : removed conditional - replaced equality check with true → SURVIVED
2. mergeMethod : removed conditional - replaced equality check with false → KILLED
        if (override.securityRelevant() != null) {
336
            securityRelevant = override.securityRelevant();
337
        }
338 2 1. mergeMethod : removed conditional - replaced equality check with true → KILLED
2. mergeMethod : removed conditional - replaced equality check with false → KILLED
        if (override.tags() != null) {
339
            tags = List.copyOf(override.tags());
340
        }
341 2 1. mergeMethod : removed conditional - replaced equality check with true → SURVIVED
2. mergeMethod : removed conditional - replaced equality check with false → KILLED
        if (override.displayName() != null) {
342
            displayName = override.displayName();
343
        }
344 2 1. mergeMethod : removed conditional - replaced equality check with false → KILLED
2. mergeMethod : removed conditional - replaced equality check with true → KILLED
        if (override.reason() != null) {
345
            reason = override.reason();
346
        }
347
348
        // Human review supersedes any AI confidence score.
349
        // Interaction score is AI-generated and is preserved from the base suggestion.
350 2 1. mergeMethod : removed conditional - replaced equality check with true → KILLED
2. mergeMethod : removed conditional - replaced equality check with false → KILLED
        double confidence = securityRelevant ? 1.0 : 0.0;
351 2 1. mergeMethod : removed conditional - replaced equality check with false → SURVIVED
2. mergeMethod : removed conditional - replaced equality check with true → KILLED
        double interactionScore = base != null ? base.interactionScore() : 0.0;
352
353 1 1. mergeMethod : replaced return value with null for org/egothor/methodatlas/ClassificationOverride::mergeMethod → KILLED
        return new AiMethodSuggestion(name, securityRelevant, displayName, tags, reason, confidence, interactionScore);
354
    }
355
356
    // -------------------------------------------------------------------------
357
    // Public immutable entry type
358
    // -------------------------------------------------------------------------
359
360
    /**
361
     * A single override entry as stored in the in-memory index.
362
     *
363
     * <p>
364
     * All fields except {@link #fqcn} are optional and carry {@code null} to
365
     * indicate "not overridden". The {@link #note} field is never emitted in any
366
     * output format and exists solely for human documentation.
367
     * </p>
368
     *
369
     * @param fqcn             fully qualified class name targeted by this entry
370
     * @param method           method name targeted; {@code null} for a class-level
371
     *                         override that applies to all methods in the class
372
     * @param securityRelevant override value for security relevance; {@code null}
373
     *                         means "keep existing"
374
     * @param tags             override value for taxonomy tags; {@code null} means
375
     *                         "keep existing"
376
     * @param displayName      override value for the suggested display name;
377
     *                         {@code null} means "keep existing"
378
     * @param reason           override value for the classification rationale;
379
     *                         {@code null} means "keep existing"
380
     * @param note             free-text annotation for human use; never emitted in
381
     *                         any output
382
     */
383
    public record Entry(String fqcn, String method, Boolean securityRelevant, List<String> tags,
384
            String displayName, String reason, String note) {
385
    }
386
387
    // -------------------------------------------------------------------------
388
    // YAML deserialization POJOs
389
    // -------------------------------------------------------------------------
390
391
    /** Root YAML deserialization container holding the list of override entries. */
392
    @JsonIgnoreProperties(ignoreUnknown = true)
393
    private static final class OverrideFile {
394
395
        @JsonProperty("overrides")
396
        /* default */ List<EntryDto> overrides;
397
    }
398
399
    /** Data transfer object for a single override entry read from YAML. */
400
    @JsonIgnoreProperties(ignoreUnknown = true)
401
    private static final class EntryDto {
402
403
        @JsonProperty("fqcn")
404
        /* default */ String fqcn;
405
406
        @JsonProperty("method")
407
        /* default */ String method;
408
409
        @JsonProperty("securityRelevant")
410
        /* default */ Boolean securityRelevant;
411
412
        @JsonProperty("tags")
413
        /* default */ List<String> tags;
414
415
        @JsonProperty("displayName")
416
        /* default */ String displayName;
417
418
        @JsonProperty("reason")
419
        /* default */ String reason;
420
421
        @JsonProperty("note")
422
        /* default */ String note;
423
    }
424
}

Mutations

166

1.1
Location : empty
Killed by : org.egothor.methodatlas.ClassificationOverrideTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ClassificationOverrideTest]/[method:empty_hasOverridesFor_returnsFalse()]
replaced return value with null for org/egothor/methodatlas/ClassificationOverride::empty → KILLED

189

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

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

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

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

190

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

195

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

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

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

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

201

1.1
Location : lambda$load$0
Killed by : org.egothor.methodatlas.ClassificationOverrideTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ClassificationOverrideTest]/[method:staticMode_noOverride_returnsNull(java.nio.file.Path)]
replaced return value with Collections.emptyList for org/egothor/methodatlas/ClassificationOverride::lambda$load$0 → KILLED

206

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

222

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

2.2
Location : hasOverridesFor
Killed by : org.egothor.methodatlas.ClassificationOverrideTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ClassificationOverrideTest]/[method:empty_hasOverridesFor_returnsFalse()]
replaced boolean return with true for org/egothor/methodatlas/ClassificationOverride::hasOverridesFor → KILLED

261

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

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

3.3
Location : apply
Killed by : org.egothor.methodatlas.ClassificationOverrideTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ClassificationOverrideTest]/[method:empty_returnsNullWhenSuggestionIsNull()]
removed conditional - replaced equality check with true → KILLED

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

262

1.1
Location : apply
Killed by : org.egothor.methodatlas.ClassificationOverrideTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ClassificationOverrideTest]/[method:empty_returnsOriginalSuggestion()]
replaced return value with null for org/egothor/methodatlas/ClassificationOverride::apply → KILLED

270

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

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

278

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

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

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

295

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

296

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

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

297

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

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

298

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

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

299

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

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

322

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

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

324

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

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

325

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

327

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

330

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

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

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

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

331

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

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

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

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

332

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

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

333

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

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

335

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

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

338

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

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

341

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

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

344

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

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

350

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

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

351

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

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

353

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

Active mutators

Tests examined


Report generated by PIT 1.22.1