feat(applet): StructuralCbor.elementSpan (M2B.2)

This commit is contained in:
michael
2026-06-17 15:44:42 -07:00
parent da4c3fa1e4
commit 6f96c2f8a2
2 changed files with 240 additions and 2 deletions

View File

@@ -251,6 +251,115 @@ class StructuralCborTest {
assertEquals(ISO7816.SW_DATA_INVALID, ex.getReason() & 0xFFFF);
}
// ---------------------------------------------------------------------
// elementSpan tests (M2B.2) — span of a complete CBOR element including
// nested children, used by M2B.3 / M2D.1 to walk IssuerSigned / docRequests.
// ---------------------------------------------------------------------
/** Shared 4B scratch for elementSpan's decodeHeader calls. */
private final byte[] scratch = new byte[4];
@Test
void elementSpan_uintImmediate() {
// 0x17 = uint 23, immediate argument. One header byte, no payload.
byte[] buf = hex("17");
short span = StructuralCbor.elementSpan(
buf, (short) 0, (short) buf.length, scratch, (short) 0);
assertEquals(1, span);
}
@Test
void elementSpan_uintOneByteArgument() {
// 0x18 0x64 = uint 100. Header byte + 1B argument, no payload.
byte[] buf = hex("1864");
short span = StructuralCbor.elementSpan(
buf, (short) 0, (short) buf.length, scratch, (short) 0);
assertEquals(2, span);
}
@Test
void elementSpan_bstrEmpty() {
// 0x40 = bstr len 0. One header byte, zero payload.
byte[] buf = hex("40");
short span = StructuralCbor.elementSpan(
buf, (short) 0, (short) buf.length, scratch, (short) 0);
assertEquals(1, span);
}
@Test
void elementSpan_bstrLen3() {
// 0x43 0x01 0x02 0x03 = bstr h'010203'. Header + 3 payload bytes.
byte[] buf = hex("43010203");
short span = StructuralCbor.elementSpan(
buf, (short) 0, (short) buf.length, scratch, (short) 0);
assertEquals(4, span);
}
@Test
void elementSpan_tstrHello() {
// 0x65 + "hello" = tstr "hello". Header + 5 payload bytes.
byte[] buf = hex("6568656c6c6f");
short span = StructuralCbor.elementSpan(
buf, (short) 0, (short) buf.length, scratch, (short) 0);
assertEquals(6, span);
}
@Test
void elementSpan_arrayOfThreeUints() {
// 0x83 0x01 0x02 0x03 = [1, 2, 3]. Header + 3 single-byte children.
byte[] buf = hex("83010203");
short span = StructuralCbor.elementSpan(
buf, (short) 0, (short) buf.length, scratch, (short) 0);
assertEquals(4, span);
}
@Test
void elementSpan_nestedArray() {
// 0x82 0x82 0x01 0x02 0x03 = [[1, 2], 3]. Exercises recursion.
byte[] buf = hex("8282010203");
short span = StructuralCbor.elementSpan(
buf, (short) 0, (short) buf.length, scratch, (short) 0);
assertEquals(5, span);
}
@Test
void elementSpan_mapTwoUintPairs() {
// 0xa2 0x01 0x02 0x03 0x04 = {1: 2, 3: 4}. Header + 4 single-byte items.
byte[] buf = hex("a201020304");
short span = StructuralCbor.elementSpan(
buf, (short) 0, (short) buf.length, scratch, (short) 0);
assertEquals(5, span);
}
@Test
void elementSpan_mapWithBstrUintPairs() {
// 0xa2 0x43 010203 0x1864 0x41 ff 0x17
// = { h'010203': 100, h'ff': 23 }
// Header(1) + bstr(4) + uint(2) + bstr(2) + uint(1) = 10.
byte[] buf = hex("a2 43 010203 1864 41 ff 17");
short span = StructuralCbor.elementSpan(
buf, (short) 0, (short) buf.length, scratch, (short) 0);
assertEquals(10, span);
}
@Test
void elementSpan_tagUint() {
// 0xc1 0x01 = tag(1, 1). Tag header + tagged element span.
byte[] buf = hex("c101");
short span = StructuralCbor.elementSpan(
buf, (short) 0, (short) buf.length, scratch, (short) 0);
assertEquals(2, span);
}
@Test
void elementSpan_honoursBufOff() {
// Pad with 4 junk bytes, then a 4-byte array [1,2,3]; span starts at offset 4.
byte[] buf = hex("deadbeef" + "83010203");
short span = StructuralCbor.elementSpan(
buf, (short) 4, (short) (buf.length - 4), scratch, (short) 0);
assertEquals(4, span);
}
private static byte[] hex(String s) {
s = s.replaceAll("\\s+", "");
byte[] out = new byte[s.length() / 2];