DeltaEmitter.java

1
package org.egothor.methodatlas.emit;
2
3
import java.io.PrintWriter;
4
import java.util.ArrayList;
5
import java.util.List;
6
7
import org.egothor.methodatlas.DeltaEntry;
8
import org.egothor.methodatlas.DeltaReport;
9
import org.egothor.methodatlas.api.ScanRecord;
10
11
/**
12
 * Formats and writes a MethodAtlas delta report to a {@link PrintWriter}.
13
 *
14
 * <h2>Output format</h2>
15
 *
16
 * <p>
17
 * The emitted text is designed to be both human-readable in a terminal and
18
 * parseable by simple shell scripts (e.g. {@code grep "^+"} to list added
19
 * methods). The format is:
20
 * </p>
21
 *
22
 * <pre>
23
 * MethodAtlas delta report
24
 *   before: before.csv  (scanned: 2026-04-10T09:00:00Z · 45 methods · 5 security-relevant)
25
 *   after:  after.csv   (scanned: 2026-04-24T14:30:00Z · 47 methods · 7 security-relevant)
26
 *
27
 * + com.acme.auth.Oauth2FlowTest  test_authCode
28
 * + com.acme.auth.Oauth2FlowTest  test_tokenRefresh
29
 * - com.acme.auth.LegacyAuthTest  test_basicAuth
30
 * ~ com.acme.crypto.AesGcmTest    roundTrip_encryptDecrypt  [source; security: false → true]
31
 *
32
 * 2 added  ·  1 removed  ·  1 modified  ·  42 unchanged
33
 * security-relevant: 5 → 7  (+2)
34
 * </pre>
35
 *
36
 * @see DeltaReport
37
 * @see DeltaEntry
38
 */
39
public final class DeltaEmitter {
40
41
    private DeltaEmitter() {
42
    }
43
44
    /**
45
     * Emits a full delta report to {@code out}.
46
     *
47
     * @param result the delta result to format
48
     * @param out    writer that receives all output; flushed but not closed
49
     */
50
    public static void emit(DeltaReport.DeltaResult result, PrintWriter out) {
51 1 1. emit : removed call to org/egothor/methodatlas/emit/DeltaEmitter::emitHeader → KILLED
        emitHeader(result, out);
52 1 1. emit : removed call to java/io/PrintWriter::println → SURVIVED
        out.println();
53 1 1. emit : removed call to org/egothor/methodatlas/emit/DeltaEmitter::emitEntries → KILLED
        emitEntries(result, out);
54 1 1. emit : removed call to java/io/PrintWriter::println → SURVIVED
        out.println();
55 1 1. emit : removed call to org/egothor/methodatlas/emit/DeltaEmitter::emitSummary → KILLED
        emitSummary(result, out);
56 1 1. emit : removed call to java/io/PrintWriter::flush → SURVIVED
        out.flush();
57
    }
58
59
    private static void emitHeader(DeltaReport.DeltaResult result, PrintWriter out) {
60 1 1. emitHeader : removed call to java/io/PrintWriter::println → KILLED
        out.println("MethodAtlas delta report");
61 1 1. emitHeader : removed call to java/io/PrintWriter::println → KILLED
        out.println("  before: " + result.beforePath().getFileName()
62
                + fileSummary(result.beforeTimestamp(), result.totalBefore(),
63
                        result.securityRelevantBefore()));
64 1 1. emitHeader : removed call to java/io/PrintWriter::println → KILLED
        out.println("  after:  " + result.afterPath().getFileName()
65
                + fileSummary(result.afterTimestamp(), result.totalAfter(),
66
                        result.securityRelevantAfter()));
67
    }
68
69
    private static String fileSummary(String timestamp, int total, int security) {
70
        StringBuilder sb = new StringBuilder(64);
71
        sb.append("  (");
72 2 1. fileSummary : removed conditional - replaced equality check with true → KILLED
2. fileSummary : removed conditional - replaced equality check with false → KILLED
        if (timestamp != null) {
73
            sb.append("scanned: ").append(timestamp).append(" · ");
74
        }
75 2 1. fileSummary : removed conditional - replaced equality check with false → KILLED
2. fileSummary : removed conditional - replaced equality check with true → KILLED
        sb.append(total).append(" method").append(total == 1 ? "" : "s")
76
          .append(" · ").append(security).append(" security-relevant)");
77 1 1. fileSummary : replaced return value with "" for org/egothor/methodatlas/emit/DeltaEmitter::fileSummary → KILLED
        return sb.toString();
78
    }
79
80
    private static void emitEntries(DeltaReport.DeltaResult result, PrintWriter out) {
81 2 1. emitEntries : removed conditional - replaced equality check with false → KILLED
2. emitEntries : removed conditional - replaced equality check with true → KILLED
        if (result.entries().isEmpty()) {
82 1 1. emitEntries : removed call to java/io/PrintWriter::println → KILLED
            out.println("No changes detected.");
83
            return;
84
        }
85
        for (DeltaEntry entry : result.entries()) {
86 1 1. emitEntries : removed call to org/egothor/methodatlas/emit/DeltaEmitter::emitEntry → KILLED
            emitEntry(entry, out);
87
        }
88
    }
89
90
    private static void emitEntry(DeltaEntry entry, PrintWriter out) {
91 1 1. emitEntry : Changed switch default to be first case → KILLED
        String symbol = switch (entry.changeType()) {
92
            case ADDED -> "+";
93
            case REMOVED -> "-";
94
            case MODIFIED -> "~";
95
        };
96
97
        ScanRecord rec = entry.record();
98 1 1. emitEntry : removed call to java/io/PrintWriter::print → KILLED
        out.print(symbol + " " + rec.fqcn() + "  " + rec.method());
99
100 2 1. emitEntry : removed conditional - replaced equality check with true → SURVIVED
2. emitEntry : removed conditional - replaced equality check with false → KILLED
        if (entry.changeType() == DeltaEntry.ChangeType.MODIFIED
101 2 1. emitEntry : removed conditional - replaced equality check with false → KILLED
2. emitEntry : removed conditional - replaced equality check with true → KILLED
                && !entry.changedFields().isEmpty()) {
102 1 1. emitEntry : removed call to java/io/PrintWriter::print → KILLED
            out.print("  [" + formatChangedFields(entry) + "]");
103
        }
104
105 1 1. emitEntry : removed call to java/io/PrintWriter::println → SURVIVED
        out.println();
106
    }
107
108
    private static String formatChangedFields(DeltaEntry entry) {
109
        List<String> parts = new ArrayList<>();
110
        for (String field : entry.changedFields()) {
111 1 1. formatChangedFields : Changed switch default to be first case → KILLED
            switch (field) {
112
                case "source" -> parts.add("source");
113
                case "loc" -> parts.add("loc: " + entry.before().loc() + " → " + entry.after().loc());
114
                case "tags" -> parts.add("tags");
115
                case "display_name" -> parts.add("display_name");
116
                case "ai_security_relevant" ->
117
                    parts.add("security: " + entry.before().aiSecurityRelevant()
118
                            + " → " + entry.after().aiSecurityRelevant());
119
                case "ai_tags" -> parts.add("ai_tags");
120
                default -> parts.add(field);
121
            }
122
        }
123 1 1. formatChangedFields : replaced return value with "" for org/egothor/methodatlas/emit/DeltaEmitter::formatChangedFields → KILLED
        return String.join("; ", parts);
124
    }
125
126
    private static void emitSummary(DeltaReport.DeltaResult result, PrintWriter out) {
127 1 1. emitSummary : removed call to java/io/PrintWriter::println → KILLED
        out.println(result.addedCount() + " added  ·  "
128
                + result.removedCount() + " removed  ·  "
129
                + result.modifiedCount() + " modified  ·  "
130
                + result.unchangedCount() + " unchanged");
131
132
        int secBefore = result.securityRelevantBefore();
133
        int secAfter = result.securityRelevantAfter();
134 1 1. emitSummary : Replaced integer subtraction with addition → KILLED
        int delta = secAfter - secBefore;
135 3 1. emitSummary : removed conditional - replaced comparison check with true → KILLED
2. emitSummary : removed conditional - replaced comparison check with false → KILLED
3. emitSummary : changed conditional boundary → KILLED
        String deltaStr = delta > 0 ? "(+" + delta + ")"
136 3 1. emitSummary : changed conditional boundary → KILLED
2. emitSummary : removed conditional - replaced comparison check with true → KILLED
3. emitSummary : removed conditional - replaced comparison check with false → KILLED
                : delta < 0 ? "(" + delta + ")"
137
                : "(no change)";
138 1 1. emitSummary : removed call to java/io/PrintWriter::println → KILLED
        out.println("security-relevant: " + secBefore + " → " + secAfter + "  " + deltaStr);
139
    }
140
}

Mutations

51

1.1
Location : emit
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_header_containsTitle()]
removed call to org/egothor/methodatlas/emit/DeltaEmitter::emitHeader → KILLED

52

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

53

1.1
Location : emit
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_noEntries_showsNoChangesDetected()]
removed call to org/egothor/methodatlas/emit/DeltaEmitter::emitEntries → KILLED

54

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

55

1.1
Location : emit
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_summary_deltaZero_showsNoChange()]
removed call to org/egothor/methodatlas/emit/DeltaEmitter::emitSummary → KILLED

56

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

60

1.1
Location : emitHeader
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_header_containsTitle()]
removed call to java/io/PrintWriter::println → KILLED

61

1.1
Location : emitHeader
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_header_containsBeforeAndAfterFilenames()]
removed call to java/io/PrintWriter::println → KILLED

64

1.1
Location : emitHeader
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_header_containsBeforeAndAfterFilenames()]
removed call to java/io/PrintWriter::println → KILLED

72

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

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

75

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

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

77

1.1
Location : fileSummary
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_header_zeroSecurityRelevant_showsZero()]
replaced return value with "" for org/egothor/methodatlas/emit/DeltaEmitter::fileSummary → KILLED

81

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

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

82

1.1
Location : emitEntries
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_noEntries_showsNoChangesDetected()]
removed call to java/io/PrintWriter::println → KILLED

86

1.1
Location : emitEntries
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_removedEntry_showsMinusSymbol()]
removed call to org/egothor/methodatlas/emit/DeltaEmitter::emitEntry → KILLED

91

1.1
Location : emitEntry
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_removedEntry_showsMinusSymbol()]
Changed switch default to be first case → KILLED

98

1.1
Location : emitEntry
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_removedEntry_showsMinusSymbol()]
removed call to java/io/PrintWriter::print → KILLED

100

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

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

101

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

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

102

1.1
Location : emitEntry
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_modifiedEntry_unknownField_appendedAsIs()]
removed call to java/io/PrintWriter::print → KILLED

105

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

111

1.1
Location : formatChangedFields
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_modifiedEntry_unknownField_appendedAsIs()]
Changed switch default to be first case → KILLED

123

1.1
Location : formatChangedFields
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_modifiedEntry_unknownField_appendedAsIs()]
replaced return value with "" for org/egothor/methodatlas/emit/DeltaEmitter::formatChangedFields → KILLED

127

1.1
Location : emitSummary
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_summary_showsAllCounts()]
removed call to java/io/PrintWriter::println → KILLED

134

1.1
Location : emitSummary
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_summary_deltaZero_showsNoChange()]
Replaced integer subtraction with addition → KILLED

135

1.1
Location : emitSummary
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_summary_deltaZero_showsNoChange()]
removed conditional - replaced comparison check with true → KILLED

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

3.3
Location : emitSummary
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_summary_deltaZero_showsNoChange()]
changed conditional boundary → KILLED

136

1.1
Location : emitSummary
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_summary_deltaZero_showsNoChange()]
changed conditional boundary → KILLED

2.2
Location : emitSummary
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_summary_deltaZero_showsNoChange()]
removed conditional - replaced comparison check with true → KILLED

3.3
Location : emitSummary
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_summary_deltaNegative_showsNegativeValue()]
removed conditional - replaced comparison check with false → KILLED

138

1.1
Location : emitSummary
Killed by : org.egothor.methodatlas.DeltaEmitterTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.DeltaEmitterTest]/[method:emit_summary_deltaZero_showsNoChange()]
removed call to java/io/PrintWriter::println → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1