MethodAtlasApp.java

1
package org.egothor.methodatlas;
2
3
import java.io.FilterOutputStream;
4
import java.io.IOException;
5
import java.io.OutputStream;
6
import java.io.OutputStreamWriter;
7
import java.io.PrintWriter;
8
import java.nio.charset.StandardCharsets;
9
import java.nio.file.Path;
10
11
import org.egothor.methodatlas.ai.ManualConsumeEngine;
12
import org.egothor.methodatlas.ai.AiSuggestionEngine;
13
import org.egothor.methodatlas.api.TestDiscoveryConfig;
14
import org.egothor.methodatlas.command.AiRuntimeBuilder;
15
import org.egothor.methodatlas.command.ApplyTagsCommand;
16
17
import org.egothor.methodatlas.emit.ClassificationOverride;
18
import org.egothor.methodatlas.emit.OutputMode;
19
import org.egothor.methodatlas.command.ApplyTagsFromCsvCommand;
20
import org.egothor.methodatlas.command.DiffCommand;
21
import org.egothor.methodatlas.command.GitHubAnnotationsCommand;
22
import org.egothor.methodatlas.command.JsonCommand;
23
import org.egothor.methodatlas.command.ManualPrepareCommand;
24
import org.egothor.methodatlas.command.OverrideLoader;
25
import org.egothor.methodatlas.command.PluginLoader;
26
import org.egothor.methodatlas.command.SarifCommand;
27
import org.egothor.methodatlas.command.ScanCommand;
28
import org.egothor.methodatlas.command.ScanOrchestrator;
29
30
/**
31
 * Command-line application for scanning Java test sources, extracting JUnit
32
 * test metadata, and optionally enriching the emitted results with AI-generated
33
 * security tagging suggestions.
34
 *
35
 * <p>
36
 * The application traverses one or more directory roots, parses matching source
37
 * files using JavaParser, identifies supported JUnit Jupiter test methods, and
38
 * emits one output record per discovered test method. File selection matches
39
 * source files whose names end with the configured suffix (default:
40
 * {@code Test.java}).
41
 * </p>
42
 *
43
 * <h2>Source-Derived Metadata</h2>
44
 *
45
 * <p>
46
 * For each discovered test method, the application reports:
47
 * </p>
48
 * <ul>
49
 * <li>fully qualified class name</li>
50
 * <li>method name</li>
51
 * <li>inclusive line count of the method declaration</li>
52
 * <li>JUnit {@code @Tag} values declared on the method</li>
53
 * </ul>
54
 *
55
 * <h2>AI Enrichment</h2>
56
 *
57
 * <p>
58
 * When AI support is enabled, the application submits each discovered test
59
 * class to an {@link org.egothor.methodatlas.ai.AiSuggestionEngine} and merges
60
 * the returned method-level suggestions into the emitted output.
61
 * </p>
62
 *
63
 * <h2>Manual AI Workflow</h2>
64
 *
65
 * <p>
66
 * Operators who cannot access an AI API directly can use the two-phase manual
67
 * workflow:
68
 * </p>
69
 * <ol>
70
 * <li><b>Prepare phase</b> ({@code -manual-prepare}): the application scans
71
 * test sources and writes one work file per class to the specified directory.
72
 * Each work file contains operator instructions and the full AI prompt (with
73
 * class source embedded). No CSV output is produced in this phase.</li>
74
 * <li><b>Consume phase</b> ({@code -manual-consume}): the application reads
75
 * operator-saved AI response files ({@code <stem>.response.txt}) from the
76
 * response directory and produces the final enriched CSV. Classes whose
77
 * response file is absent receive empty AI columns.</li>
78
 * </ol>
79
 *
80
 * <h2>Supported Command-Line Options</h2>
81
 *
82
 * <ul>
83
 * <li>{@code -config <path>} — loads default values from a YAML configuration
84
 * file; command-line flags override YAML values</li>
85
 * <li>{@code -plain} — emits plain text output instead of CSV</li>
86
 * <li>{@code -sarif} — emits SARIF 2.1.0 JSON output</li>
87
 * <li>{@code -json} — emits a flat JSON array; each element carries the same
88
 * fields as CSV with {@code tags} and {@code ai_tags} as arrays and numeric
89
 * values as JSON numbers</li>
90
 * <li>{@code -ai} — enables AI-based enrichment</li>
91
 * <li>{@code -ai-provider <provider>} — selects the AI provider</li>
92
 * <li>{@code -ai-model <model>} — selects the provider-specific model</li>
93
 * <li>{@code -ai-base-url <url>} — overrides the provider base URL</li>
94
 * <li>{@code -ai-api-key <key>} — supplies the AI API key directly</li>
95
 * <li>{@code -ai-api-key-env <name>} — resolves the AI API key from an
96
 * environment variable</li>
97
 * <li>{@code -ai-taxonomy <path>} — loads taxonomy text from an external
98
 * file</li>
99
 * <li>{@code -ai-taxonomy-mode <mode>} — selects the built-in taxonomy
100
 * variant</li>
101
 * <li>{@code -ai-max-class-chars <count>} — limits class source size submitted
102
 * to AI</li>
103
 * <li>{@code -ai-timeout-sec <seconds>} — sets the AI request timeout</li>
104
 * <li>{@code -ai-max-retries <count>} — sets the retry limit for AI
105
 * operations</li>
106
 * <li>{@code -ai-confidence} — requests a confidence score for each AI
107
 * security classification; adds an {@code ai_confidence} column to the
108
 * output</li>
109
 * <li>{@code -min-confidence <threshold>} — silently drops methods whose AI
110
 * confidence score is below {@code threshold} (range {@code 0.0–1.0}); only
111
 * effective when {@code -ai-confidence} is also enabled</li>
112
 * <li>{@code -ai-cache <path>} — loads a previous scan CSV produced with
113
 * {@code -content-hash -ai} as an AI result cache; classes whose
114
 * {@code content_hash} matches a cache entry are classified without an API
115
 * call; changed and new classes are classified normally</li>
116
 * <li>{@code -file-suffix <suffix>} — matches source files by name suffix
117
 * (default: {@code Test.java}); may be repeated to match multiple patterns,
118
 * e.g. {@code -file-suffix Test.java -file-suffix IT.java}; the first
119
 * occurrence replaces the default</li>
120
 * <li>{@code -test-annotation <name>} — recognises methods annotated with
121
 * {@code name} as test methods; may be repeated; the first occurrence replaces
122
 * the JVM provider's default set (JUnit 5 {@code Test}, {@code ParameterizedTest},
123
 * {@code RepeatedTest}, {@code TestFactory}, {@code TestTemplate})</li>
124
 * <li>{@code -emit-metadata} — emits {@code # key: value} comment lines
125
 * before the header row describing the tool version, scan timestamp, and
126
 * taxonomy configuration</li>
127
 * <li>{@code -apply-tags} — instead of emitting a report, writes
128
 * AI-generated {@code @DisplayName} and {@code @Tag} annotations back to
129
 * the scanned source files; requires AI enrichment to be enabled</li>
130
 * <li>{@code -content-hash} — includes a SHA-256 fingerprint of each class
131
 * source as a {@code content_hash} column in CSV/plain output and as a SARIF
132
 * property; useful for detecting which classes changed between scans</li>
133
 * <li>{@code -security-only} — suppresses non-security methods from the output;
134
 * only methods whose AI classification (or override) has
135
 * {@code securityRelevant=true} are emitted; requires AI enrichment or a
136
 * classification override file to have any effect</li>
137
 * <li>{@code -manual-prepare <workdir> <responsedir>} — runs the manual AI
138
 * prepare phase, writing work files to {@code workdir} and empty response stubs
139
 * to {@code responsedir}; the two paths may be identical</li>
140
 * <li>{@code -manual-consume <workdir> <responsedir>} — runs the manual AI
141
 * consume phase, reading response files from {@code responsedir} and emitting
142
 * the final enriched CSV</li>
143
 * <li>{@code -diff <before.csv> <after.csv>} — compares two MethodAtlas scan
144
 * outputs and emits a delta report showing added, removed, and modified test
145
 * methods; all other flags are ignored when {@code -diff} is present</li>
146
 * <li>{@code -apply-tags-from-csv <path>} — instead of emitting a report,
147
 * applies the annotation decisions recorded in the reviewed CSV back to the
148
 * source files; the CSV is treated as a complete desired-state specification:
149
 * every test method's {@code @Tag} set and {@code @DisplayName} are driven
150
 * entirely by the corresponding CSV row</li>
151
 * <li>{@code -mismatch-limit <n>} — when used with {@code -apply-tags-from-csv},
152
 * aborts without modifying any source file if the number of mismatches between
153
 * the CSV and the current source tree reaches or exceeds {@code n}; {@code -1}
154
 * (the default) logs mismatches as warnings and proceeds</li>
155
 * <li>{@code -emit-source-root} — adds a {@code source_root} column to CSV
156
 * output and a {@code SRCROOT=} token to plain-text output, identifying which
157
 * scan root each record originated from; essential in multi-root or monorepo
158
 * projects where the same fully qualified class name can appear under different
159
 * source trees (e.g. {@code module-a/src/test/java/} and
160
 * {@code module-b/src/test/java/}); has no effect on SARIF or GitHub Annotations
161
 * output</li>
162
 * </ul>
163
 *
164
 * <p>
165
 * Any remaining non-option arguments are interpreted as root paths to scan. If
166
 * no scan path is supplied, the current working directory is scanned.
167
 * </p>
168
 *
169
 * @see org.egothor.methodatlas.ai.AiSuggestionEngine
170
 * @see org.egothor.methodatlas.api.SourcePatcher
171
 * @see org.egothor.methodatlas.emit.OutputEmitter
172
 * @see org.egothor.methodatlas.emit.SarifEmitter
173
 * @see org.egothor.methodatlas.command.Command
174
 * @see #main(String[])
175
 */
176
public final class MethodAtlasApp {
177
178
    private static final String FLAG_DIFF = "-diff";
179
180
    /**
181
     * Prevents instantiation of this utility class.
182
     */
183
    private MethodAtlasApp() {
184
    }
185
186
    /**
187
     * Program entry point.
188
     *
189
     * <p>
190
     * Delegates all work to {@link #run(String[], PrintWriter)}. Exits with a
191
     * non-zero status code if any source file could not be processed.
192
     * </p>
193
     *
194
     * @param args command-line arguments
195
     * @throws IOException              if traversal of a configured file tree fails
196
     * @throws IllegalArgumentException if an option is unknown, if a required
197
     *                                  option value is missing, or if an option
198
     *                                  value cannot be parsed
199
     * @throws IllegalStateException    if AI support is enabled but the AI engine
200
     *                                  cannot be created successfully
201
     */
202
    public static void main(String[] args) throws IOException {
203
        // Wrap System.out in a guarded stream whose close() only flushes.
204
        // This lets try-with-resources manage the PrintWriter (satisfying
205
        // SpotBugs CloseResource and PMD UseTryWithResources) without
206
        // permanently closing System.out (satisfying Error Prone's
207
        // ClosingStandardOutputStreams check).
208
        OutputStream guarded = new FilterOutputStream(System.out) {
209
            @Override
210
            public void close() throws IOException {
211 1 1. close : removed call to org/egothor/methodatlas/MethodAtlasApp$1::flush → NO_COVERAGE
                flush(); // flush but do NOT close System.out
212
            }
213
        };
214
        try (PrintWriter out = new PrintWriter(new OutputStreamWriter(guarded, StandardCharsets.UTF_8), true)) {
215
            int exitCode = run(args, out);
216 2 1. main : removed conditional - replaced equality check with false → NO_COVERAGE
2. main : removed conditional - replaced equality check with true → NO_COVERAGE
            if (exitCode != 0) {
217 1 1. main : removed call to java/lang/System::exit → NO_COVERAGE
                System.exit(exitCode);
218
            }
219
        }
220
    }
221
222
    /**
223
     * Executes a full application run by routing to the appropriate
224
     * {@link org.egothor.methodatlas.command.Command} implementation.
225
     *
226
     * <p>
227
     * This method is the primary entry point for programmatic and test use. It
228
     * parses arguments, identifies the requested operating mode, constructs the
229
     * matching command object, and delegates execution to it.
230
     * </p>
231
     *
232
     * @param args command-line arguments
233
     * @param out  writer that receives all emitted output
234
     * @return {@code 0} if all files were processed successfully, {@code 1} if
235
     *         any file produced a parse or processing error
236
     * @throws IOException              if traversal of a configured file tree fails
237
     * @throws IllegalArgumentException if an option is unknown, if a required
238
     *                                  option value is missing, or if an option
239
     *                                  value cannot be parsed
240
     * @throws IllegalStateException    if AI support is enabled but the AI engine
241
     *                                  cannot be created successfully
242
     */
243
    @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") // DiffCommand is created inside the loop but returned immediately
244
    /* default */ static int run(String[] args, PrintWriter out) throws IOException {
245
        // -diff is handled before full argument parsing; all other flags are ignored.
246 3 1. run : removed conditional - replaced comparison check with false → KILLED
2. run : removed conditional - replaced comparison check with true → KILLED
3. run : changed conditional boundary → KILLED
        for (int i = 0; i < args.length; i++) {
247 2 1. run : removed conditional - replaced equality check with false → KILLED
2. run : removed conditional - replaced equality check with true → KILLED
            if (FLAG_DIFF.equals(args[i])) {
248 4 1. run : Replaced integer addition with subtraction → SURVIVED
2. run : removed conditional - replaced comparison check with false → SURVIVED
3. run : changed conditional boundary → SURVIVED
4. run : removed conditional - replaced comparison check with true → KILLED
                if (i + 2 >= args.length) {
249
                    throw new IllegalArgumentException(
250
                            "-diff requires two arguments: -diff <before.csv> <after.csv>");
251
                }
252 3 1. run : replaced int return with 0 for org/egothor/methodatlas/MethodAtlasApp::run → SURVIVED
2. run : Replaced integer addition with subtraction → KILLED
3. run : Replaced integer addition with subtraction → KILLED
                return new DiffCommand(Path.of(args[i + 1]), Path.of(args[i + 2])).execute(out);
253
            }
254
        }
255
256
        CliConfig cliConfig = CliArgs.parse(args);
257
258
        // Establish the run identity once and place it in the thread-local
259
        // context so the JUL formatter (Item 20) can prepend the correlation
260
        // id to every log record emitted during this invocation. clear() in
261
        // the finally block keeps the thread-local from outliving the run
262
        // when MethodAtlas is invoked programmatically (the standard CLI
263
        // exits the JVM anyway).
264
        String version = MethodAtlasApp.class.getPackage().getImplementationVersion();
265
        ScanRun scanRun = ScanRun.create(version, cliConfig.toString());
266 1 1. run : removed call to org/egothor/methodatlas/ScanRunContext::set → SURVIVED
        ScanRunContext.set(scanRun);
267
        try {
268 1 1. run : replaced int return with 0 for org/egothor/methodatlas/MethodAtlasApp::run → KILLED
            return runWithScanRun(out, cliConfig);
269
        } finally {
270 1 1. run : removed call to org/egothor/methodatlas/ScanRunContext::clear → SURVIVED
            ScanRunContext.clear();
271
        }
272
    }
273
274
    private static int runWithScanRun(PrintWriter out, CliConfig cliConfig) throws IOException {
275
        AiRuntimeBuilder aiRuntimeBuilder = new AiRuntimeBuilder();
276
        ClassificationOverride override = new OverrideLoader().load(cliConfig.overrideFile());
277
        AiResultCache aiCache = aiRuntimeBuilder.buildCache(cliConfig.aiCacheFile());
278
279
        TestDiscoveryConfig discoveryConfig =
280
                new TestDiscoveryConfig(cliConfig.fileSuffixes(), cliConfig.testMarkers(), cliConfig.properties());
281
282
        // One PluginLoader + one ScanOrchestrator are shared by every command in
283
        // this run; both are stateless and the providers they resolve are owned
284
        // (and closed) by the command that requested them.
285
        PluginLoader pluginLoader = new PluginLoader();
286
        ScanOrchestrator scanOrchestrator = new ScanOrchestrator(pluginLoader);
287
288
        // Manual prepare phase: write AI prompt work files; no CSV output.
289 2 1. runWithScanRun : removed conditional - replaced equality check with false → KILLED
2. runWithScanRun : removed conditional - replaced equality check with true → KILLED
        if (cliConfig.manualMode() instanceof ManualMode.Prepare prepare) {
290 1 1. runWithScanRun : replaced int return with 0 for org/egothor/methodatlas/MethodAtlasApp::runWithScanRun → KILLED
            return new ManualPrepareCommand(prepare, cliConfig, discoveryConfig, pluginLoader).execute(out);
291
        }
292
293
        // Determine AI engine: manual consume reads from files; normal mode calls APIs.
294
        AiSuggestionEngine aiEngine;
295 2 1. runWithScanRun : removed conditional - replaced equality check with false → KILLED
2. runWithScanRun : removed conditional - replaced equality check with true → KILLED
        if (cliConfig.manualMode() instanceof ManualMode.Consume consume) {
296
            aiEngine = new ManualConsumeEngine(consume.responseDir());
297
        } else {
298
            aiEngine = aiRuntimeBuilder.buildEngine(cliConfig.aiOptions());
299
        }
300
301
        // Apply-tags-from-csv mode: apply reviewed CSV decisions to source files.
302 2 1. runWithScanRun : removed conditional - replaced equality check with true → KILLED
2. runWithScanRun : removed conditional - replaced equality check with false → KILLED
        if (cliConfig.applyTagsFromCsvFile() != null) {
303 1 1. runWithScanRun : replaced int return with 0 for org/egothor/methodatlas/MethodAtlasApp::runWithScanRun → KILLED
            return new ApplyTagsFromCsvCommand(cliConfig, discoveryConfig, pluginLoader).execute(out);
304
        }
305
306
        // Apply-tags mode: annotate source files; no report emitted.
307 2 1. runWithScanRun : removed conditional - replaced equality check with true → KILLED
2. runWithScanRun : removed conditional - replaced equality check with false → KILLED
        if (cliConfig.applyTags()) {
308 1 1. runWithScanRun : replaced int return with 0 for org/egothor/methodatlas/MethodAtlasApp::runWithScanRun → SURVIVED
            return new ApplyTagsCommand(cliConfig, discoveryConfig, aiEngine, override, aiCache,
309
                    pluginLoader, scanOrchestrator).execute(out);
310
        }
311
312
        // SARIF mode: buffer all records; write JSON once after the scan completes.
313 2 1. runWithScanRun : removed conditional - replaced equality check with false → KILLED
2. runWithScanRun : removed conditional - replaced equality check with true → KILLED
        if (cliConfig.outputMode() == OutputMode.SARIF) {
314 1 1. runWithScanRun : replaced int return with 0 for org/egothor/methodatlas/MethodAtlasApp::runWithScanRun → SURVIVED
            return new SarifCommand(cliConfig, discoveryConfig, aiEngine, override, aiCache,
315
                    scanOrchestrator).execute(out);
316
        }
317
318
        // JSON mode: buffer all records; write flat JSON array after scan completes.
319 2 1. runWithScanRun : removed conditional - replaced equality check with false → KILLED
2. runWithScanRun : removed conditional - replaced equality check with true → KILLED
        if (cliConfig.outputMode() == OutputMode.JSON) {
320 1 1. runWithScanRun : replaced int return with 0 for org/egothor/methodatlas/MethodAtlasApp::runWithScanRun → SURVIVED
            return new JsonCommand(cliConfig, discoveryConfig, aiEngine, override, aiCache,
321
                    pluginLoader, scanOrchestrator).execute(out);
322
        }
323
324
        // GitHub Annotations mode: emit ::notice/::warning workflow commands.
325 2 1. runWithScanRun : removed conditional - replaced equality check with true → KILLED
2. runWithScanRun : removed conditional - replaced equality check with false → KILLED
        if (cliConfig.outputMode() == OutputMode.GITHUB_ANNOTATIONS) {
326 1 1. runWithScanRun : replaced int return with 0 for org/egothor/methodatlas/MethodAtlasApp::runWithScanRun → SURVIVED
            return new GitHubAnnotationsCommand(cliConfig, discoveryConfig, aiEngine, override, aiCache,
327
                    scanOrchestrator).execute(out);
328
        }
329
330
        // CSV / PLAIN mode: emit incrementally (default).
331 1 1. runWithScanRun : replaced int return with 0 for org/egothor/methodatlas/MethodAtlasApp::runWithScanRun → KILLED
        return new ScanCommand(cliConfig, discoveryConfig, aiEngine, override, aiCache,
332
                pluginLoader, scanOrchestrator).execute(out);
333
    }
334
}

Mutations

211

1.1
Location : close
Killed by : none
removed call to org/egothor/methodatlas/MethodAtlasApp$1::flush → NO_COVERAGE

216

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

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

217

1.1
Location : main
Killed by : none
removed call to java/lang/System::exit → NO_COVERAGE

246

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

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

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

247

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

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

248

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

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

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

4.4
Location : run
Killed by : none
changed conditional boundary → SURVIVED Covering tests

252

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

2.2
Location : run
Killed by : org.egothor.methodatlas.DeltaReportTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaReportTest]/[method:app_diffFlag_producesReport(java.nio.file.Path)]
Replaced integer addition with subtraction → KILLED

3.3
Location : run
Killed by : org.egothor.methodatlas.DeltaReportTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaReportTest]/[method:app_diffFlag_producesReport(java.nio.file.Path)]
Replaced integer addition with subtraction → KILLED

266

1.1
Location : run
Killed by : none
removed call to org/egothor/methodatlas/ScanRunContext::set → SURVIVED
Covering tests

268

1.1
Location : run
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/MethodAtlasApp::run → KILLED

270

1.1
Location : run
Killed by : none
removed call to org/egothor/methodatlas/ScanRunContext::clear → SURVIVED
Covering tests

289

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

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

290

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

295

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

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

302

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

2.2
Location : runWithScanRun
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

303

1.1
Location : runWithScanRun
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/MethodAtlasApp::runWithScanRun → KILLED

307

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

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

308

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

313

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

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

314

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

319

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

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

320

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

325

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

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

326

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

331

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

Active mutators

Tests examined


Report generated by PIT 1.22.1