ControlCoverageCollector.java

1
// SPDX-License-Identifier: Apache-2.0
2
// Copyright 2026 Egothor
3
// Copyright 2026 Accenture
4
package org.egothor.methodatlas.coverage;
5
6
import java.time.Instant;
7
import java.util.ArrayList;
8
import java.util.Collections;
9
import java.util.LinkedHashMap;
10
import java.util.LinkedHashSet;
11
import java.util.List;
12
import java.util.Locale;
13
import java.util.Map;
14
import java.util.NavigableSet;
15
import java.util.Set;
16
import java.util.TreeSet;
17
18
import org.egothor.methodatlas.ai.AiMethodSuggestion;
19
import org.egothor.methodatlas.emit.TestMethodSink;
20
21
/**
22
 * Streaming sink that builds a {@link ControlCoverageReport} from scan
23
 * records observed during a single run.
24
 *
25
 * <p>
26
 * The collector implements {@link TestMethodSink} so the orchestration layer
27
 * can hand it the same record stream that drives SARIF/CSV emitters, without
28
 * a second scan and without coupling the emitters to compliance logic.
29
 * </p>
30
 *
31
 * <p>
32
 * Package-private because nothing outside the {@code coverage} package needs
33
 * to construct one; {@link CoverageFacade} is the sole external entry point.
34
 * </p>
35
 */
36
final class ControlCoverageCollector implements TestMethodSink {
37
38
    /** Schema version of the produced report. */
39
    private static final String SCHEMA_VERSION = "1";
40
41
    /** Separator between framework prefix and bare ID in the control key. */
42
    private static final String CONTROL_ID_PREFIX_SEP = "-";
43
44
    /** Tag-source label when only source annotations contribute. */
45
    private static final String TAG_SOURCE_ANNOTATION = "source";
46
47
    /** Tag-source label when only AI classification contributes. */
48
    private static final String TAG_SOURCE_AI = "ai";
49
50
    /** Tag-source label when both source annotations and AI contribute. */
51
    private static final String TAG_SOURCE_BOTH = "both";
52
53
    /** Multiplier used to round percentages to two decimal places. */
54
    private static final double COVERAGE_PERCENT_SCALE = 10_000.0;
55
56
    /** Divisor that converts the rounded ratio back into a percentage. */
57
    private static final double COVERAGE_PERCENT_DIVISOR = 100.0;
58
59
    /** Confidence assigned to source-derived evidence (always certain). */
60
    private static final double FULL_CONFIDENCE = 1.0;
61
62
    /** Mapping that drives tag → control lookup. */
63
    private final ControlMapping mapping;
64
65
    /** Minimum AI confidence required to count an AI-only classification. */
66
    private final double minConfidence;
67
68
    /**
69
     * Accumulated covering tests, keyed by canonical control key
70
     * (e.g. {@code "ASVS-4.1.1"}). Insertion order is unimportant here — the
71
     * report-build step sorts the resulting set lexicographically.
72
     */
73
    private final Map<String, List<CoverageTestEntry>> accumulator = new LinkedHashMap<>();
74
75
    /**
76
     * Creates a collector backed by {@code mapping}.
77
     *
78
     * @param mapping       loaded control mapping; must not be {@code null}
79
     * @param minConfidence minimum AI confidence required for an AI-only
80
     *                      classification to count; source-derived evidence
81
     *                      is always counted irrespective of this value
82
     */
83
    /* default */ ControlCoverageCollector(ControlMapping mapping, double minConfidence) {
84
        this.mapping = mapping;
85
        this.minConfidence = minConfidence;
86
    }
87
88
    /**
89
     * Records evidence contributed by a single test method.
90
     *
91
     * <p>
92
     * Resolution algorithm:
93
     * </p>
94
     * <ol>
95
     *   <li>Filter the source {@code tags} list to only tags that appear in
96
     *       the mapping (others are silently skipped — not an error).</li>
97
     *   <li>Filter the AI {@link AiMethodSuggestion#tags()} the same way, but
98
     *       only when the suggestion is non-null, security-relevant, and meets
99
     *       the configured minimum confidence threshold. {@code null} AI tag
100
     *       lists are treated as empty.</li>
101
     *   <li>Determine {@code tagSource} and {@code confidence}: source-only
102
     *       and AI+source both yield certainty ({@code 1.0}); AI-only carries
103
     *       the AI confidence forward verbatim.</li>
104
     *   <li>Merge the two tag lists preserving first-seen order, drop the
105
     *       method when the merged list is empty, and otherwise append a
106
     *       {@link CoverageTestEntry} under every linked control key.</li>
107
     * </ol>
108
     *
109
     * @param fqcn        fully qualified class name
110
     * @param method      test method name
111
     * @param beginLine   ignored
112
     * @param loc         ignored
113
     * @param contentHash ignored
114
     * @param tags        source-declared tags
115
     * @param displayName optional human-readable display name
116
     * @param suggestion  optional AI classification
117
     */
118
    @Override
119
    @SuppressWarnings({"PMD.UseObjectForClearerAPI", "PMD.AvoidInstantiatingObjectsInLoops"})
120
    public void record(String fqcn, String method, int beginLine, int loc, String contentHash,
121
            List<String> tags, String displayName, AiMethodSuggestion suggestion) {
122
        List<String> sourceMappable = filterMappable(tags);
123
        List<String> aiMappable = filterAiMappable(suggestion);
124 4 1. record : removed conditional - replaced equality check with false → KILLED
2. record : removed conditional - replaced equality check with true → KILLED
3. record : removed conditional - replaced equality check with false → KILLED
4. record : removed conditional - replaced equality check with true → KILLED
        if (sourceMappable.isEmpty() && aiMappable.isEmpty()) {
125
            return;
126
        }
127
128
        String tagSource;
129
        double confidence;
130 2 1. record : removed conditional - replaced equality check with false → KILLED
2. record : removed conditional - replaced equality check with true → KILLED
        if (sourceMappable.isEmpty()) {
131
            tagSource = TAG_SOURCE_AI;
132
            confidence = suggestion.confidence();
133 2 1. record : removed conditional - replaced equality check with true → KILLED
2. record : removed conditional - replaced equality check with false → KILLED
        } else if (aiMappable.isEmpty()) {
134
            tagSource = TAG_SOURCE_ANNOTATION;
135
            confidence = FULL_CONFIDENCE;
136
        } else {
137
            tagSource = TAG_SOURCE_BOTH;
138
            confidence = FULL_CONFIDENCE;
139
        }
140
141
        List<String> merged = mergeUnique(sourceMappable, aiMappable);
142
        CoverageTestEntry entry = new CoverageTestEntry(
143
                fqcn, method, displayName, merged, tagSource, confidence);
144
145
        for (String tag : merged) {
146
            List<ControlEntry> controls = mapping.tagToControls().get(tag);
147
            for (ControlEntry control : controls) {
148
                String key = controlKey(control.id());
149 1 1. lambda$record$0 : replaced return value with Collections.emptyList for org/egothor/methodatlas/coverage/ControlCoverageCollector::lambda$record$0 → KILLED
                accumulator.computeIfAbsent(key, k -> new ArrayList<>()).add(entry);
150
            }
151
        }
152
    }
153
154
    /**
155
     * Builds the final {@link ControlCoverageReport}.
156
     *
157
     * @param toolVersion resolved tool version string; never {@code null}
158
     * @return populated report with sorted coverage, gaps, and statistics
159
     */
160
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
161
    /* default */ ControlCoverageReport buildReport(String toolVersion) {
162
        NavigableSet<String> allKeys = new TreeSet<>();
163
        Map<String, ControlEntry> firstControlByKey = new LinkedHashMap<>();
164 2 1. buildReport : removed call to java/util/Map::forEach → KILLED
2. lambda$buildReport$2 : removed call to java/util/List::forEach → KILLED
        mapping.tagToControls().forEach((tag, entries) -> entries.forEach(control -> {
165
            String key = controlKey(control.id());
166
            allKeys.add(key);
167
            firstControlByKey.putIfAbsent(key, control);
168
        }));
169
170
        Map<String, CoverageControlEntry> coverage = new LinkedHashMap<>();
171
        for (String key : allKeys) {
172
            List<CoverageTestEntry> tests = accumulator.get(key);
173 4 1. buildReport : removed conditional - replaced equality check with false → SURVIVED
2. buildReport : removed conditional - replaced equality check with true → KILLED
3. buildReport : removed conditional - replaced equality check with true → KILLED
4. buildReport : removed conditional - replaced equality check with false → KILLED
            if (tests == null || tests.isEmpty()) {
174
                continue;
175
            }
176
            ControlEntry metadata = firstControlByKey.get(key);
177
            String chapter = chapterFor(key, metadata);
178
            String chapterTitle = chapterTitleFor(key, metadata);
179
            coverage.put(key, new CoverageControlEntry(chapter, chapterTitle,
180
                    Collections.unmodifiableList(new ArrayList<>(tests))));
181
        }
182
183
        List<String> gaps = new ArrayList<>();
184
        for (String key : allKeys) {
185 2 1. buildReport : removed conditional - replaced equality check with true → KILLED
2. buildReport : removed conditional - replaced equality check with false → KILLED
            if (!coverage.containsKey(key)) {
186
                gaps.add(key);
187
            }
188
        }
189
190
        CoverageStatistics statistics = buildStatistics(allKeys.size(), coverage.size());
191 1 1. buildReport : replaced return value with null for org/egothor/methodatlas/coverage/ControlCoverageCollector::buildReport → KILLED
        return new ControlCoverageReport(
192
                SCHEMA_VERSION,
193
                Instant.now().toString(),
194
                toolVersion,
195
                mapping.framework(),
196
                mapping.frameworkVersion(),
197
                mapping.source(),
198
                Collections.unmodifiableMap(coverage),
199
                Collections.unmodifiableList(gaps),
200
                statistics);
201
    }
202
203
    /**
204
     * Picks the first non-null {@code chapter} value attached to the control
205
     * across every mapping tag that points at it.
206
     *
207
     * @param key      canonical control key (e.g. {@code "ASVS-4.1.1"})
208
     * @param fallback control entry used when no tag-keyed value is set
209
     * @return chapter label or {@code null}
210
     */
211
    private String chapterFor(String key, ControlEntry fallback) {
212
        for (List<ControlEntry> entries : mapping.tagToControls().values()) {
213
            for (ControlEntry candidate : entries) {
214 4 1. chapterFor : removed conditional - replaced equality check with false → SURVIVED
2. chapterFor : removed conditional - replaced equality check with false → SURVIVED
3. chapterFor : removed conditional - replaced equality check with true → SURVIVED
4. chapterFor : removed conditional - replaced equality check with true → KILLED
                if (controlKey(candidate.id()).equals(key) && candidate.chapter() != null) {
215 1 1. chapterFor : replaced return value with "" for org/egothor/methodatlas/coverage/ControlCoverageCollector::chapterFor → KILLED
                    return candidate.chapter();
216
                }
217
            }
218
        }
219 1 1. chapterFor : replaced return value with "" for org/egothor/methodatlas/coverage/ControlCoverageCollector::chapterFor → SURVIVED
        return fallback.chapter();
220
    }
221
222
    /**
223
     * Picks the first non-null {@code chapterTitle} for the control. Same
224
     * resolution policy as {@link #chapterFor(String, ControlEntry)}.
225
     *
226
     * @param key      canonical control key
227
     * @param fallback control entry used when no tag-keyed value is set
228
     * @return chapter title or {@code null}
229
     */
230
    private String chapterTitleFor(String key, ControlEntry fallback) {
231
        for (List<ControlEntry> entries : mapping.tagToControls().values()) {
232
            for (ControlEntry candidate : entries) {
233 4 1. chapterTitleFor : removed conditional - replaced equality check with true → SURVIVED
2. chapterTitleFor : removed conditional - replaced equality check with true → SURVIVED
3. chapterTitleFor : removed conditional - replaced equality check with false → SURVIVED
4. chapterTitleFor : removed conditional - replaced equality check with false → SURVIVED
                if (controlKey(candidate.id()).equals(key) && candidate.chapterTitle() != null) {
234 1 1. chapterTitleFor : replaced return value with "" for org/egothor/methodatlas/coverage/ControlCoverageCollector::chapterTitleFor → SURVIVED
                    return candidate.chapterTitle();
235
                }
236
            }
237
        }
238 1 1. chapterTitleFor : replaced return value with "" for org/egothor/methodatlas/coverage/ControlCoverageCollector::chapterTitleFor → SURVIVED
        return fallback.chapterTitle();
239
    }
240
241
    /**
242
     * Computes aggregate counts and the rounded coverage percentage.
243
     *
244
     * @param total   total distinct control IDs declared in the mapping
245
     * @param covered count of controls with at least one covering test
246
     * @return populated statistics record
247
     */
248
    private static CoverageStatistics buildStatistics(int total, int covered) {
249 3 1. buildStatistics : removed conditional - replaced equality check with false → SURVIVED
2. buildStatistics : Replaced double division with multiplication → KILLED
3. buildStatistics : removed conditional - replaced equality check with true → KILLED
        double ratio = total == 0 ? 0.0 : covered / (double) total;
250 2 1. buildStatistics : Replaced double division with multiplication → KILLED
2. buildStatistics : Replaced double multiplication with division → KILLED
        double percent = Math.round(ratio * COVERAGE_PERCENT_SCALE) / COVERAGE_PERCENT_DIVISOR;
251 2 1. buildStatistics : Replaced integer subtraction with addition → SURVIVED
2. buildStatistics : replaced return value with null for org/egothor/methodatlas/coverage/ControlCoverageCollector::buildStatistics → KILLED
        return new CoverageStatistics(total, covered, total - covered, percent);
252
    }
253
254
    /**
255
     * Returns the canonical {@code <FRAMEWORK>-<id>} key used throughout the
256
     * report. The framework prefix is upper-cased so {@code "asvs"} and
257
     * {@code "ASVS"} mapping files produce identical output.
258
     *
259
     * @param id bare requirement ID from a {@link ControlEntry}
260
     * @return canonical control key
261
     */
262
    private String controlKey(String id) {
263 1 1. controlKey : replaced return value with "" for org/egothor/methodatlas/coverage/ControlCoverageCollector::controlKey → KILLED
        return mapping.framework().toUpperCase(Locale.ROOT) + CONTROL_ID_PREFIX_SEP + id;
264
    }
265
266
    /**
267
     * Drops every tag that is not present in {@link ControlMapping#tagToControls()}.
268
     *
269
     * @param tags raw tag list; may be {@code null}
270
     * @return new list containing only mappable tags; never {@code null}
271
     */
272
    private List<String> filterMappable(List<String> tags) {
273 4 1. filterMappable : removed conditional - replaced equality check with false → SURVIVED
2. filterMappable : removed conditional - replaced equality check with true → SURVIVED
3. filterMappable : removed conditional - replaced equality check with false → KILLED
4. filterMappable : removed conditional - replaced equality check with true → KILLED
        if (tags == null || tags.isEmpty()) {
274
            return List.of();
275
        }
276
        List<String> result = new ArrayList<>(tags.size());
277
        for (String tag : tags) {
278 2 1. filterMappable : removed conditional - replaced equality check with false → KILLED
2. filterMappable : removed conditional - replaced equality check with true → KILLED
            if (mapping.tagToControls().containsKey(tag)) {
279
                result.add(tag);
280
            }
281
        }
282 1 1. filterMappable : replaced return value with Collections.emptyList for org/egothor/methodatlas/coverage/ControlCoverageCollector::filterMappable → KILLED
        return result;
283
    }
284
285
    /**
286
     * Extracts the mappable subset of an AI suggestion's tags, applying the
287
     * security-relevance and minimum-confidence filters.
288
     *
289
     * @param suggestion AI suggestion; may be {@code null}
290
     * @return new list containing only mappable AI tags; never {@code null}
291
     */
292
    private List<String> filterAiMappable(AiMethodSuggestion suggestion) {
293 4 1. filterAiMappable : removed conditional - replaced equality check with false → SURVIVED
2. filterAiMappable : removed conditional - replaced equality check with true → KILLED
3. filterAiMappable : removed conditional - replaced equality check with false → KILLED
4. filterAiMappable : removed conditional - replaced equality check with true → KILLED
        if (suggestion == null || !suggestion.securityRelevant()) {
294
            return List.of();
295
        }
296 3 1. filterAiMappable : changed conditional boundary → SURVIVED
2. filterAiMappable : removed conditional - replaced comparison check with false → KILLED
3. filterAiMappable : removed conditional - replaced comparison check with true → KILLED
        if (suggestion.confidence() < minConfidence) {
297
            return List.of();
298
        }
299 1 1. filterAiMappable : replaced return value with Collections.emptyList for org/egothor/methodatlas/coverage/ControlCoverageCollector::filterAiMappable → KILLED
        return filterMappable(suggestion.tags());
300
    }
301
302
    /**
303
     * Returns an unmodifiable union of two lists preserving first-seen order.
304
     *
305
     * @param first  first list (typically source tags)
306
     * @param second second list (typically AI tags)
307
     * @return unmodifiable union with stable order
308
     */
309
    private static List<String> mergeUnique(List<String> first, List<String> second) {
310
        Set<String> merged = new LinkedHashSet<>(first);
311
        merged.addAll(second);
312 1 1. mergeUnique : replaced return value with Collections.emptyList for org/egothor/methodatlas/coverage/ControlCoverageCollector::mergeUnique → KILLED
        return List.copyOf(merged);
313
    }
314
}

Mutations

124

1.1
Location : record
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:umbrellaTag_notInMapping_isIgnored()]
removed conditional - replaced equality check with false → KILLED

2.2
Location : record
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:aiOnly_aboveThreshold_yieldsAiProvenanceAndAiConfidence()]
removed conditional - replaced equality check with true → KILLED

3.3
Location : record
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:umbrellaTag_notInMapping_isIgnored()]
removed conditional - replaced equality check with false → KILLED

4.4
Location : record
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
removed conditional - replaced equality check with true → KILLED

130

1.1
Location : record
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:aiOnly_aboveThreshold_yieldsAiProvenanceAndAiConfidence()]
removed conditional - replaced equality check with false → KILLED

2.2
Location : record
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
removed conditional - replaced equality check with true → KILLED

133

1.1
Location : record
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:sourceAndAi_yieldsBothProvenance()]
removed conditional - replaced equality check with true → KILLED

2.2
Location : record
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:sourceTag_yieldsSourceProvenanceAndFullConfidence()]
removed conditional - replaced equality check with false → KILLED

149

1.1
Location : lambda$record$0
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
replaced return value with Collections.emptyList for org/egothor/methodatlas/coverage/ControlCoverageCollector::lambda$record$0 → KILLED

164

1.1
Location : buildReport
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:statistics_coveragePercent_isZeroOnEmptyRun()]
removed call to java/util/Map::forEach → KILLED

2.2
Location : lambda$buildReport$2
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:statistics_coveragePercent_isZeroOnEmptyRun()]
removed call to java/util/List::forEach → KILLED

173

1.1
Location : buildReport
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
removed conditional - replaced equality check with true → KILLED

2.2
Location : buildReport
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:statistics_coveragePercent_isZeroOnEmptyRun()]
removed conditional - replaced equality check with true → KILLED

3.3
Location : buildReport
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
removed conditional - replaced equality check with false → KILLED

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

185

1.1
Location : buildReport
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
removed conditional - replaced equality check with true → KILLED

2.2
Location : buildReport
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:onlyUnmappedTags_areIgnoredEntirely()]
removed conditional - replaced equality check with false → KILLED

191

1.1
Location : buildReport
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:statistics_coveragePercent_isZeroOnEmptyRun()]
replaced return value with null for org/egothor/methodatlas/coverage/ControlCoverageCollector::buildReport → KILLED

214

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

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

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

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

215

1.1
Location : chapterFor
Killed by : org.egothor.methodatlas.MethodAtlasAppCoverageTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppCoverageTest]/[method:accessControlAnnotation_mapsToAsvs4Dot1Dot1(java.nio.file.Path)]
replaced return value with "" for org/egothor/methodatlas/coverage/ControlCoverageCollector::chapterFor → KILLED

219

1.1
Location : chapterFor
Killed by : none
replaced return value with "" for org/egothor/methodatlas/coverage/ControlCoverageCollector::chapterFor → SURVIVED
Covering tests

233

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

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

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

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

234

1.1
Location : chapterTitleFor
Killed by : none
replaced return value with "" for org/egothor/methodatlas/coverage/ControlCoverageCollector::chapterTitleFor → SURVIVED
Covering tests

238

1.1
Location : chapterTitleFor
Killed by : none
replaced return value with "" for org/egothor/methodatlas/coverage/ControlCoverageCollector::chapterTitleFor → SURVIVED
Covering tests

249

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

2.2
Location : buildStatistics
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:statistics_coveragePercent_isOneHundredWhenAllCovered()]
Replaced double division with multiplication → KILLED

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

250

1.1
Location : buildStatistics
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:statistics_coveragePercent_isOneHundredWhenAllCovered()]
Replaced double division with multiplication → KILLED

2.2
Location : buildStatistics
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:statistics_coveragePercent_isOneHundredWhenAllCovered()]
Replaced double multiplication with division → KILLED

251

1.1
Location : buildStatistics
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:statistics_coveragePercent_isZeroOnEmptyRun()]
replaced return value with null for org/egothor/methodatlas/coverage/ControlCoverageCollector::buildStatistics → KILLED

2.2
Location : buildStatistics
Killed by : none
Replaced integer subtraction with addition → SURVIVED
Covering tests

263

1.1
Location : controlKey
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:statistics_coveragePercent_isZeroOnEmptyRun()]
replaced return value with "" for org/egothor/methodatlas/coverage/ControlCoverageCollector::controlKey → KILLED

273

1.1
Location : filterMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
removed conditional - replaced equality check with false → KILLED

2.2
Location : filterMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
removed conditional - replaced equality check with true → KILLED

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

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

278

1.1
Location : filterMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
removed conditional - replaced equality check with false → KILLED

2.2
Location : filterMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:umbrellaTag_notInMapping_isIgnored()]
removed conditional - replaced equality check with true → KILLED

282

1.1
Location : filterMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
replaced return value with Collections.emptyList for org/egothor/methodatlas/coverage/ControlCoverageCollector::filterMappable → KILLED

293

1.1
Location : filterAiMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:umbrellaTag_notInMapping_isIgnored()]
removed conditional - replaced equality check with true → KILLED

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

3.3
Location : filterAiMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:aiOnly_aboveThreshold_yieldsAiProvenanceAndAiConfidence()]
removed conditional - replaced equality check with false → KILLED

4.4
Location : filterAiMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:aiOnly_aboveThreshold_yieldsAiProvenanceAndAiConfidence()]
removed conditional - replaced equality check with true → KILLED

296

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

2.2
Location : filterAiMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:aiOnly_belowThreshold_isExcluded()]
removed conditional - replaced comparison check with false → KILLED

3.3
Location : filterAiMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:aiOnly_aboveThreshold_yieldsAiProvenanceAndAiConfidence()]
removed conditional - replaced comparison check with true → KILLED

299

1.1
Location : filterAiMappable
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:aiOnly_aboveThreshold_yieldsAiProvenanceAndAiConfidence()]
replaced return value with Collections.emptyList for org/egothor/methodatlas/coverage/ControlCoverageCollector::filterAiMappable → KILLED

312

1.1
Location : mergeUnique
Killed by : org.egothor.methodatlas.coverage.ControlCoverageCollectorTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.coverage.ControlCoverageCollectorTest]/[method:gaps_containsEveryUncoveredControl_sortedLexicographically()]
replaced return value with Collections.emptyList for org/egothor/methodatlas/coverage/ControlCoverageCollector::mergeUnique → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1