SnapshotCodec.java

1
package com.rox.save;
2
3
import java.io.ByteArrayInputStream;
4
import java.io.ByteArrayOutputStream;
5
import java.io.DataInputStream;
6
import java.io.DataOutputStream;
7
import java.io.IOException;
8
import java.io.UncheckedIOException;
9
import java.lang.reflect.Constructor;
10
import java.lang.reflect.InvocationTargetException;
11
import java.lang.reflect.RecordComponent;
12
import java.util.Arrays;
13
import java.util.Optional;
14
15
/**
16
 * Turns a snapshot record tree (see {@link SystemSnapshot}) into a live-snapshot save payload and
17
 * back, walking each record's components in declaration order - so a new field on any component's
18
 * snapshot record is picked up without touching this class, at the cost of that reordering or adding
19
 * components changes the byte layout (bump {@code SaveCodec}'s version when that matters).
20
 *
21
 * <p>Supported component types: {@code int}, {@code long}, {@code boolean}, {@code int[]} (every
22
 * element must be a byte value, 0-255 - all snapshot arrays are RAM/register bytes - and is stored as
23
 * one byte), {@code boolean[]}, nested records, and sealed interfaces of records (stored as the index
24
 * of the concrete type in {@link Class#getPermittedSubclasses()}, then that record).
25
 */
26
final class SnapshotCodec {
27
    private SnapshotCodec(){
28
    }
29
30
    static byte[] encode(final Record record){
31
        final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
32
        try (DataOutputStream out = new DataOutputStream(buffer)){
33 1 1. encode : removed call to com/rox/save/SnapshotCodec::writeRecord → KILLED
            writeRecord(out, record);
34
        } catch (IOException e){
35
            //in-memory only, same reasoning as SaveCodec.encode()
36
            throw new UncheckedIOException(e);
37
        }
38 1 1. encode : replaced return value with null for com/rox/save/SnapshotCodec::encode → KILLED
        return buffer.toByteArray();
39
    }
40
41
    /** Empty if {@code bytes} doesn't decode cleanly into exactly one {@code type} with nothing left over. */
42
    static <T extends Record> Optional<T> decode(final byte[] bytes, final Class<T> type){
43
        try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes))){
44
            final T record = type.cast(readRecord(in, type));
45 1 1. decode : negated conditional → KILLED
            return in.available() == 0 ? Optional.of(record) : Optional.empty();
46
        } catch (IOException | IllegalArgumentException e){
47
            //truncated (EOFException), a bad sealed-type tag/array length, or a record's own constructor
48
            //rejecting what was read - all just "not a usable snapshot"
49
            return Optional.empty();
50
        }
51
    }
52
53
    private static void writeRecord(final DataOutputStream out, final Record record) throws IOException {
54
        for (final RecordComponent component : record.getClass().getRecordComponents()){
55 1 1. writeRecord : removed call to com/rox/save/SnapshotCodec::write → KILLED
            write(out, component.getType(), accessorValue(component, record));
56
        }
57
    }
58
59
    private static void write(final DataOutputStream out, final Class<?> type, final Object value) throws IOException {
60 1 1. write : negated conditional → KILLED
        if (type == int.class){
61 1 1. write : removed call to java/io/DataOutputStream::writeInt → KILLED
            out.writeInt((Integer) value);
62 1 1. write : negated conditional → KILLED
        } else if (type == long.class){
63 1 1. write : removed call to java/io/DataOutputStream::writeLong → KILLED
            out.writeLong((Long) value);
64 1 1. write : negated conditional → KILLED
        } else if (type == boolean.class){
65 1 1. write : removed call to java/io/DataOutputStream::writeBoolean → KILLED
            out.writeBoolean((Boolean) value);
66 1 1. write : negated conditional → KILLED
        } else if (type == int[].class){
67
            final int[] array = (int[]) value;
68 1 1. write : removed call to java/io/DataOutputStream::writeInt → KILLED
            out.writeInt(array.length);
69
            for (final int element : array){
70 4 1. write : changed conditional boundary → KILLED
2. write : negated conditional → KILLED
3. write : negated conditional → KILLED
4. write : changed conditional boundary → KILLED
                if (element < 0 || element > 0xFF){
71
                    throw new IllegalArgumentException("Snapshot arrays must hold byte values (0-255), found " + element);
72
                }
73 1 1. write : removed call to java/io/DataOutputStream::writeByte → KILLED
                out.writeByte(element);
74
            }
75 1 1. write : negated conditional → KILLED
        } else if (type == boolean[].class){
76
            final boolean[] array = (boolean[]) value;
77 1 1. write : removed call to java/io/DataOutputStream::writeInt → KILLED
            out.writeInt(array.length);
78
            for (final boolean element : array){
79 1 1. write : removed call to java/io/DataOutputStream::writeBoolean → KILLED
                out.writeBoolean(element);
80
            }
81 1 1. write : negated conditional → KILLED
        } else if (type.isRecord()){
82 1 1. write : removed call to com/rox/save/SnapshotCodec::writeRecord → KILLED
            writeRecord(out, (Record) value);
83 1 1. write : negated conditional → KILLED
        } else if (type.isSealed()){
84 1 1. write : removed call to java/io/DataOutputStream::writeByte → KILLED
            out.writeByte(Arrays.asList(type.getPermittedSubclasses()).indexOf(value.getClass()));
85 1 1. write : removed call to com/rox/save/SnapshotCodec::writeRecord → KILLED
            writeRecord(out, (Record) value);
86
        } else {
87
            throw new IllegalArgumentException("Unsupported snapshot component type " + type);
88
        }
89
    }
90
91
    private static Record readRecord(final DataInputStream in, final Class<?> type) throws IOException {
92
        final RecordComponent[] components = type.getRecordComponents();
93
        final Class<?>[] componentTypes = new Class<?>[components.length];
94
        final Object[] values = new Object[components.length];
95 2 1. readRecord : changed conditional boundary → KILLED
2. readRecord : negated conditional → KILLED
        for (int i = 0; i < components.length; i++){
96
            componentTypes[i] = components[i].getType();
97
            values[i] = read(in, componentTypes[i]);
98
        }
99
        try {
100
            final Constructor<?> canonical = type.getDeclaredConstructor(componentTypes);
101 1 1. readRecord : replaced return value with null for com/rox/save/SnapshotCodec::readRecord → KILLED
            return (Record) canonical.newInstance(values);
102
        } catch (InvocationTargetException e){
103
            throw new IllegalArgumentException("Snapshot record rejected its decoded values", e.getCause());
104
        } catch (ReflectiveOperationException e){
105
            throw new IllegalStateException("Snapshot record " + type + " has no usable canonical constructor", e);
106
        }
107
    }
108
109
    private static Object read(final DataInputStream in, final Class<?> type) throws IOException {
110 1 1. read : negated conditional → KILLED
        if (type == int.class){
111 1 1. read : replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED
            return in.readInt();
112 1 1. read : negated conditional → KILLED
        } else if (type == long.class){
113 1 1. read : replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED
            return in.readLong();
114 1 1. read : negated conditional → KILLED
        } else if (type == boolean.class){
115 1 1. read : replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED
            return in.readBoolean();
116 1 1. read : negated conditional → KILLED
        } else if (type == int[].class){
117
            final int[] array = new int[checkedLength(in)];
118 2 1. read : changed conditional boundary → KILLED
2. read : negated conditional → KILLED
            for (int i = 0; i < array.length; i++){
119
                array[i] = in.readUnsignedByte();
120
            }
121 1 1. read : replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED
            return array;
122 1 1. read : negated conditional → KILLED
        } else if (type == boolean[].class){
123
            final boolean[] array = new boolean[checkedLength(in)];
124 2 1. read : negated conditional → KILLED
2. read : changed conditional boundary → KILLED
            for (int i = 0; i < array.length; i++){
125
                array[i] = in.readBoolean();
126
            }
127 1 1. read : replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED
            return array;
128 1 1. read : negated conditional → KILLED
        } else if (type.isRecord()){
129 1 1. read : replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED
            return readRecord(in, type);
130 1 1. read : negated conditional → KILLED
        } else if (type.isSealed()){
131
            final Class<?>[] permitted = type.getPermittedSubclasses();
132
            final int tag = in.readUnsignedByte();
133 2 1. read : negated conditional → KILLED
2. read : changed conditional boundary → KILLED
            if (tag >= permitted.length){
134
                throw new IllegalArgumentException("Unknown " + type.getSimpleName() + " type tag " + tag);
135
            }
136 1 1. read : replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED
            return readRecord(in, permitted[tag]);
137
        }
138
        throw new IllegalArgumentException("Unsupported snapshot component type " + type);
139
    }
140
141
    /** Rejects a corrupt length before it can drive a huge allocation - same guard as {@code SaveCodec.decode()}'s payload length. */
142
    private static int checkedLength(final DataInputStream in) throws IOException {
143
        final int length = in.readInt();
144 4 1. checkedLength : negated conditional → KILLED
2. checkedLength : negated conditional → KILLED
3. checkedLength : changed conditional boundary → KILLED
4. checkedLength : changed conditional boundary → KILLED
        if (length < 0 || length > in.available()){
145
            throw new IllegalArgumentException("Array length " + length + " exceeds the remaining payload");
146
        }
147 1 1. checkedLength : replaced int return with 0 for com/rox/save/SnapshotCodec::checkedLength → KILLED
        return length;
148
    }
149
150
    private static Object accessorValue(final RecordComponent component, final Record record){
151
        try {
152 1 1. accessorValue : replaced return value with null for com/rox/save/SnapshotCodec::accessorValue → KILLED
            return component.getAccessor().invoke(record);
153
        } catch (ReflectiveOperationException e){
154
            throw new IllegalStateException("Can't read snapshot component " + component, e);
155
        }
156
    }
157
}

Mutations

33

1.1
Location : encode
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsUnsupportedComponentTypes()]
removed call to com/rox/save/SnapshotCodec::writeRecord → KILLED

38

1.1
Location : encode
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
replaced return value with null for com/rox/save/SnapshotCodec::encode → KILLED

45

1.1
Location : decode
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
negated conditional → KILLED

55

1.1
Location : writeRecord
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsUnsupportedComponentTypes()]
removed call to com/rox/save/SnapshotCodec::write → KILLED

60

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsUnsupportedComponentTypes()]
negated conditional → KILLED

61

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForAnUnknownSealedTypeTag()]
removed call to java/io/DataOutputStream::writeInt → KILLED

62

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsUnsupportedComponentTypes()]
negated conditional → KILLED

63

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForAnUnknownSealedTypeTag()]
removed call to java/io/DataOutputStream::writeLong → KILLED

64

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsUnsupportedComponentTypes()]
negated conditional → KILLED

65

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:sealedComponentsComeBackAsTheSameConcreteType()]
removed call to java/io/DataOutputStream::writeBoolean → KILLED

66

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsUnsupportedComponentTypes()]
negated conditional → KILLED

68

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
removed call to java/io/DataOutputStream::writeInt → KILLED

70

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyWhenTruncated()]
changed conditional boundary → KILLED

2.2
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsArrayValuesThatAreNotBytes()]
negated conditional → KILLED

3.3
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsArrayValuesThatAreNotBytes()]
negated conditional → KILLED

4.4
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyWhenTruncated()]
changed conditional boundary → KILLED

73

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
removed call to java/io/DataOutputStream::writeByte → KILLED

75

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsUnsupportedComponentTypes()]
negated conditional → KILLED

77

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:sealedComponentsComeBackAsTheSameConcreteType()]
removed call to java/io/DataOutputStream::writeInt → KILLED

79

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:sealedComponentsComeBackAsTheSameConcreteType()]
removed call to java/io/DataOutputStream::writeBoolean → KILLED

81

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsUnsupportedComponentTypes()]
negated conditional → KILLED

82

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForAnUnknownSealedTypeTag()]
removed call to com/rox/save/SnapshotCodec::writeRecord → KILLED

83

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsUnsupportedComponentTypes()]
negated conditional → KILLED

84

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:sealedComponentsComeBackAsTheSameConcreteType()]
removed call to java/io/DataOutputStream::writeByte → KILLED

85

1.1
Location : write
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:sealedComponentsComeBackAsTheSameConcreteType()]
removed call to com/rox/save/SnapshotCodec::writeRecord → KILLED

95

1.1
Location : readRecord
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyWhenARecordRejectsItsDecodedValues()]
changed conditional boundary → KILLED

2.2
Location : readRecord
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForUnsupportedComponentTypes()]
negated conditional → KILLED

101

1.1
Location : readRecord
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
replaced return value with null for com/rox/save/SnapshotCodec::readRecord → KILLED

110

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
negated conditional → KILLED

111

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:sealedComponentsComeBackAsTheSameConcreteType()]
replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED

112

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
negated conditional → KILLED

113

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:sealedComponentsComeBackAsTheSameConcreteType()]
replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED

114

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
negated conditional → KILLED

115

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:sealedComponentsComeBackAsTheSameConcreteType()]
replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED

116

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
negated conditional → KILLED

118

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
changed conditional boundary → KILLED

2.2
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
negated conditional → KILLED

121

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED

122

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:sealedComponentsComeBackAsTheSameConcreteType()]
negated conditional → KILLED

124

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForAnUnknownSealedTypeTag()]
negated conditional → KILLED

2.2
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForAnUnknownSealedTypeTag()]
changed conditional boundary → KILLED

127

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsEmptyArrays()]
replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED

128

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForUnsupportedComponentTypes()]
negated conditional → KILLED

129

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsEmptyArrays()]
replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED

130

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForUnsupportedComponentTypes()]
negated conditional → KILLED

133

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForAnUnknownSealedTypeTag()]
negated conditional → KILLED

2.2
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForAnUnknownSealedTypeTag()]
changed conditional boundary → KILLED

136

1.1
Location : read
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:sealedComponentsComeBackAsTheSameConcreteType()]
replaced return value with null for com/rox/save/SnapshotCodec::read → KILLED

144

1.1
Location : checkedLength
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForAnArrayLengthLongerThanThePayload()]
negated conditional → KILLED

2.2
Location : checkedLength
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:decodeIsEmptyForANegativeArrayLength()]
negated conditional → KILLED

3.3
Location : checkedLength
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
changed conditional boundary → KILLED

4.4
Location : checkedLength
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsEmptyArrays()]
changed conditional boundary → KILLED

147

1.1
Location : checkedLength
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:roundTripsAnArrayThatRunsExactlyToTheEndOfThePayload()]
replaced int return with 0 for com/rox/save/SnapshotCodec::checkedLength → KILLED

152

1.1
Location : accessorValue
Killed by : com.rox.save.SnapshotCodecTest.[engine:junit-jupiter]/[class:com.rox.save.SnapshotCodecTest]/[method:encodeRejectsArrayValuesThatAreNotBytes()]
replaced return value with null for com/rox/save/SnapshotCodec::accessorValue → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1