|
1
|
|
package com.rox.debug.labels; |
|
2
|
|
|
|
3
|
|
import java.util.Locale; |
|
4
|
|
import java.util.function.IntUnaryOperator; |
|
5
|
|
|
|
6
|
|
/** |
|
7
|
|
* A label's bytes as text, and back - raw bytes, one per address, for any length of label (a number |
|
8
|
|
* view for multi-byte values can come later). Input accepts {@code $1F}, {@code 0x1F} or {@code 31} per |
|
9
|
|
* byte, separated by whitespace. |
|
10
|
|
*/ |
|
11
|
|
public final class LabelValues { |
|
12
|
|
private static final int MAX_BYTE = 0xFF; |
|
13
|
|
private static final int HEX_RADIX = 16; |
|
14
|
|
private static final int DECIMAL_RADIX = 10; |
|
15
|
|
private static final int MAX_DIGITS = 6; |
|
16
|
|
private static final String WHITESPACE = "\\p{javaWhitespace}+"; |
|
17
|
|
|
|
18
|
|
private LabelValues(){ |
|
19
|
|
} |
|
20
|
|
|
|
21
|
|
/** {@code $01 $02} */ |
|
22
|
|
public static String hex(final MemoryLabel label, final IntUnaryOperator peek){ |
|
23
|
|
final StringBuilder out = new StringBuilder(); |
|
24
|
2
1. hex : changed conditional boundary → KILLED
2. hex : negated conditional → KILLED
|
for (int address = label.start(); address <= label.end(); address++){ |
|
25
|
1
1. hex : negated conditional → KILLED
|
if (!out.isEmpty()){ |
|
26
|
|
out.append(' '); |
|
27
|
|
} |
|
28
|
|
out.append(String.format("$%02X", peek.applyAsInt(address))); |
|
29
|
|
} |
|
30
|
1
1. hex : replaced return value with "" for com/rox/debug/labels/LabelValues::hex → KILLED
|
return out.toString(); |
|
31
|
|
} |
|
32
|
|
|
|
33
|
|
/** {@code 1 2} */ |
|
34
|
|
public static String decimal(final MemoryLabel label, final IntUnaryOperator peek){ |
|
35
|
|
final StringBuilder out = new StringBuilder(); |
|
36
|
2
1. decimal : changed conditional boundary → KILLED
2. decimal : negated conditional → KILLED
|
for (int address = label.start(); address <= label.end(); address++){ |
|
37
|
1
1. decimal : negated conditional → KILLED
|
if (!out.isEmpty()){ |
|
38
|
|
out.append(' '); |
|
39
|
|
} |
|
40
|
|
out.append(peek.applyAsInt(address)); |
|
41
|
|
} |
|
42
|
1
1. decimal : replaced return value with "" for com/rox/debug/labels/LabelValues::decimal → KILLED
|
return out.toString(); |
|
43
|
|
} |
|
44
|
|
|
|
45
|
|
/** |
|
46
|
|
* One byte per address of {@code label}, from e.g. {@code "$1F"} or {@code "1 0x02 $FF"}. |
|
47
|
|
* |
|
48
|
|
* @throws IllegalArgumentException with a readable reason if it isn't exactly one 0-255 value per byte |
|
49
|
|
*/ |
|
50
|
|
public static int[] parse(final MemoryLabel label, final String text){ |
|
51
|
|
final String trimmed = text.strip(); |
|
52
|
1
1. parse : negated conditional → KILLED
|
final String[] tokens = trimmed.isEmpty() ? new String[0] : trimmed.split(WHITESPACE); |
|
53
|
1
1. parse : negated conditional → KILLED
|
if (tokens.length != label.length()){ |
|
54
|
|
throw new IllegalArgumentException(String.format("'%s' covers %d byte%s - enter %d value%s, got %d", |
|
55
|
1
1. parse : negated conditional → KILLED
|
label.name(), label.length(), label.length() == 1 ? "" : "s", |
|
56
|
1
1. parse : negated conditional → KILLED
|
label.length(), label.length() == 1 ? "" : "s", tokens.length)); |
|
57
|
|
} |
|
58
|
|
final int[] values = new int[tokens.length]; |
|
59
|
2
1. parse : changed conditional boundary → KILLED
2. parse : negated conditional → KILLED
|
for (int i = 0; i < tokens.length; i++){ |
|
60
|
|
values[i] = parseByte(tokens[i]); |
|
61
|
|
} |
|
62
|
1
1. parse : replaced return value with null for com/rox/debug/labels/LabelValues::parse → KILLED
|
return values; |
|
63
|
|
} |
|
64
|
|
|
|
65
|
|
private static int parseByte(final String token){ |
|
66
|
2
1. parseByte : negated conditional → KILLED
2. parseByte : negated conditional → KILLED
|
final boolean hex = token.startsWith("$") || token.toLowerCase(Locale.ROOT).startsWith("0x"); |
|
67
|
2
1. parseByte : negated conditional → KILLED
2. parseByte : negated conditional → KILLED
|
final String digits = token.startsWith("$") ? token.substring(1) : hex ? token.substring(2) : token; |
|
68
|
1
1. parseByte : negated conditional → KILLED
|
final int radix = hex ? HEX_RADIX : DECIMAL_RADIX; |
|
69
|
|
//checked by hand rather than trusting parseInt, which would also accept a sign |
|
70
|
5
1. lambda$parseByte$0 : negated conditional → KILLED
2. lambda$parseByte$0 : changed conditional boundary → KILLED
3. lambda$parseByte$0 : replaced boolean return with true for com/rox/debug/labels/LabelValues::lambda$parseByte$0 → KILLED
4. parseByte : negated conditional → KILLED
5. parseByte : negated conditional → KILLED
|
if (digits.isEmpty() || !digits.chars().allMatch(c -> Character.digit(c, radix) >= 0)){ |
|
71
|
|
throw new IllegalArgumentException("'" + token + "' isn't a byte value - use e.g. 31, $1F or 0x1F"); |
|
72
|
|
} |
|
73
|
|
//anything this long is out of range anyway - and parseInt would overflow on it |
|
74
|
4
1. parseByte : negated conditional → KILLED
2. parseByte : changed conditional boundary → KILLED
3. parseByte : negated conditional → KILLED
4. parseByte : changed conditional boundary → KILLED
|
if (digits.length() > MAX_DIGITS || Integer.parseInt(digits, radix) > MAX_BYTE){ |
|
75
|
|
throw new IllegalArgumentException("'" + token + "' is more than a byte holds (0-255, $00-$FF)"); |
|
76
|
|
} |
|
77
|
1
1. parseByte : replaced int return with 0 for com/rox/debug/labels/LabelValues::parseByte → KILLED
|
return Integer.parseInt(digits, radix); |
|
78
|
|
} |
|
79
|
|
} |
| | Mutations |
| 24 |
|
1.1 Location : hex Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[method:formatsEachByteAsHexAndAsDecimal()] changed conditional boundary → KILLED
2.2 Location : hex Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[method:formatsEachByteAsHexAndAsDecimal()] negated conditional → KILLED
|
| 25 |
|
1.1 Location : hex Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[method:formatsEachByteAsHexAndAsDecimal()] negated conditional → KILLED
|
| 30 |
|
1.1 Location : hex Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[method:formatsEachByteAsHexAndAsDecimal()] replaced return value with "" for com/rox/debug/labels/LabelValues::hex → KILLED
|
| 36 |
|
1.1 Location : decimal Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[method:formatsEachByteAsHexAndAsDecimal()] changed conditional boundary → KILLED
2.2 Location : decimal Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[method:formatsEachByteAsHexAndAsDecimal()] negated conditional → KILLED
|
| 37 |
|
1.1 Location : decimal Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[method:formatsEachByteAsHexAndAsDecimal()] negated conditional → KILLED
|
| 42 |
|
1.1 Location : decimal Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[method:formatsEachByteAsHexAndAsDecimal()] replaced return value with "" for com/rox/debug/labels/LabelValues::decimal → KILLED
|
| 52 |
|
1.1 Location : parse Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#5] negated conditional → KILLED
|
| 53 |
|
1.1 Location : parse Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#5] negated conditional → KILLED
|
| 55 |
|
1.1 Location : parse Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#2] negated conditional → KILLED
|
| 56 |
|
1.1 Location : parse Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#2] negated conditional → KILLED
|
| 59 |
|
1.1 Location : parse Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:parsesDecimalAndHexBytes(java.lang.String, int)]/[test-template-invocation:#2] changed conditional boundary → KILLED
2.2 Location : parse Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#5] negated conditional → KILLED
|
| 62 |
|
1.1 Location : parse Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:parsesDecimalAndHexBytes(java.lang.String, int)]/[test-template-invocation:#4] replaced return value with null for com/rox/debug/labels/LabelValues::parse → KILLED
|
| 66 |
|
1.1 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#10] negated conditional → KILLED
2.2 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#11] negated conditional → KILLED
|
| 67 |
|
1.1 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#5] negated conditional → KILLED
2.2 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#11] negated conditional → KILLED
|
| 68 |
|
1.1 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#10] negated conditional → KILLED
|
| 70 |
|
1.1 Location : lambda$parseByte$0 Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#7] negated conditional → KILLED
2.2 Location : lambda$parseByte$0 Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#10] changed conditional boundary → KILLED
3.3 Location : lambda$parseByte$0 Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#7] replaced boolean return with true for com/rox/debug/labels/LabelValues::lambda$parseByte$0 → KILLED
4.4 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#5] negated conditional → KILLED
5.5 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#7] negated conditional → KILLED
|
| 74 |
|
1.1 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#10] negated conditional → KILLED
2.2 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:parsesDecimalAndHexBytes(java.lang.String, int)]/[test-template-invocation:#10] changed conditional boundary → KILLED
3.3 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:rejectsWithAReason(java.lang.String, java.lang.String)]/[test-template-invocation:#12] negated conditional → KILLED
4.4 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:parsesDecimalAndHexBytes(java.lang.String, int)]/[test-template-invocation:#6] changed conditional boundary → KILLED
|
| 77 |
|
1.1 Location : parseByte Killed by : com.rox.debug.labels.LabelValuesTest.[engine:junit-jupiter]/[class:com.rox.debug.labels.LabelValuesTest]/[test-template:parsesDecimalAndHexBytes(java.lang.String, int)]/[test-template-invocation:#4] replaced int return with 0 for com/rox/debug/labels/LabelValues::parseByte → KILLED
|