Add CCID helpers and regression host tests

This commit is contained in:
CinderSocket
2026-03-08 19:03:30 -07:00
parent 2932a96d98
commit 2d60989bee
8 changed files with 693 additions and 11 deletions
+3
View File
@@ -15,10 +15,13 @@ test-host:
lib/host_tests/vendor/munit/munit.c \
lib/host_tests/test_main.c \
lib/host_tests/test_lrc.c \
lib/host_tests/test_ccid_logic.c \
lib/host_tests/test_t1_existing.c \
lib/host_tests/test_t1_regressions.c \
lib/host_tests/t1_test_stubs.c \
lib/host_tests/bit_buffer_mock.c \
lrc.c \
ccid_logic.c \
t_1.c \
-o build/host_tests/seader_tests
./build/host_tests/seader_tests
+5 -11
View File
@@ -1,4 +1,5 @@
#include "seader_i.h"
#include "ccid_logic.h"
#define TAG "SeaderCCID"
const uint8_t SAM_ATR[] =
@@ -26,10 +27,7 @@ static void seader_ccid_reset_slot_sequence(SeaderUartBridge* seader_uart, uint8
static uint8_t seader_ccid_next_sequence(SeaderUartBridge* seader_uart, uint8_t slot) {
SeaderCcidSlotState* slot_state = seader_ccid_slot_state(seader_uart, slot);
if(slot_state->sequence > 254) {
slot_state->sequence = 0;
}
return slot_state->sequence++;
return seader_ccid_sequence_advance(&slot_state->sequence);
}
void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot) {
@@ -175,19 +173,15 @@ void seader_ccid_XfrBlockToSlot(
uint8_t* data,
size_t len) {
uint8_t header_len = 2 + 10;
if(len > ((size_t)SEADER_UART_RX_BUF_SIZE - header_len)) {
if(!seader_ccid_payload_fits_frame(len, SEADER_UART_RX_BUF_SIZE, header_len)) {
FURI_LOG_E(TAG, "CCID frame too long: %d", (int)(header_len + len));
return;
}
uint8_t* tx_start = (uint8_t*)seader_uart->tx_buf;
uint8_t* tx_end = tx_start + SEADER_UART_RX_BUF_SIZE;
uint8_t* data_addr = (uint8_t*)data;
bool in_scratchpad = false;
if(data_addr >= tx_start + header_len && data_addr <= tx_end) {
size_t available = (size_t)(tx_end - data_addr);
in_scratchpad = len <= available;
}
bool in_scratchpad = seader_ccid_data_in_scratchpad(
tx_start, SEADER_UART_RX_BUF_SIZE, header_len, data_addr, len);
uint8_t* frame;
if(in_scratchpad) {
+94
View File
@@ -0,0 +1,94 @@
#include "ccid_logic.h"
uint8_t seader_ccid_sequence_advance(uint8_t* sequence) {
return (*sequence)++;
}
bool seader_ccid_payload_fits_frame(size_t payload_len, size_t uart_buf_size, size_t header_len) {
if(header_len > uart_buf_size) {
return false;
}
return payload_len <= (uart_buf_size - header_len);
}
bool seader_ccid_data_in_scratchpad(
const uint8_t* tx_buf,
size_t tx_buf_size,
size_t header_len,
const uint8_t* data,
size_t payload_len) {
if(data < tx_buf + header_len || data > tx_buf + tx_buf_size) {
return false;
}
size_t available = (size_t)((tx_buf + tx_buf_size) - data);
return payload_len <= available;
}
SeaderCcidStatus seader_ccid_decode_status(uint8_t status) {
SeaderCcidStatus decoded = {
.icc_status = status & 0x03,
.command_status = (SeaderCcidDecodedCommandStatus)((status >> 6) & 0x03),
};
return decoded;
}
bool seader_ccid_response_matches_pending(bool pending, uint8_t expected_seq, uint8_t response_seq) {
return !pending || (expected_seq == response_seq);
}
size_t seader_ccid_find_frame_start(
const uint8_t* data,
size_t len,
uint8_t sync,
uint8_t ctrl,
uint8_t nak) {
size_t i = 0;
while(i + 1 < len) {
if(i + 2 < len && data[i] == sync && data[i + 1] == nak) {
i += 3;
continue;
}
if(data[i] == sync && data[i + 1] == ctrl) {
return i;
}
i++;
}
return len;
}
bool seader_ccid_pending_timed_out(
bool pending,
uint32_t pending_since_tick,
uint32_t now_tick,
uint32_t timeout_ticks) {
if(!pending || timeout_ticks == 0 || pending_since_tick == 0) {
return false;
}
return (now_tick - pending_since_tick) > timeout_ticks;
}
SeaderCcidDataRoute seader_ccid_route_data_block(
bool has_sam,
uint8_t sam_slot,
uint8_t message_slot,
uint8_t protocol_t) {
if(!has_sam) {
return SeaderCcidDataRouteAtrRecognition;
}
if(message_slot != sam_slot) {
return SeaderCcidDataRouteWrongSlotError;
}
if(protocol_t == 0) {
return SeaderCcidDataRouteSamT0;
}
return SeaderCcidDataRouteSamT1;
}
+50
View File
@@ -0,0 +1,50 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
typedef enum {
SeaderCcidDecodedCommandStatusProcessed = 0,
SeaderCcidDecodedCommandStatusFailed = 1,
SeaderCcidDecodedCommandStatusTimeExtension = 2,
} SeaderCcidDecodedCommandStatus;
typedef struct {
uint8_t icc_status;
SeaderCcidDecodedCommandStatus command_status;
} SeaderCcidStatus;
typedef enum {
SeaderCcidDataRouteSamT0 = 0,
SeaderCcidDataRouteSamT1 = 1,
SeaderCcidDataRouteAtrRecognition = 2,
SeaderCcidDataRouteWrongSlotError = 3,
} SeaderCcidDataRoute;
uint8_t seader_ccid_sequence_advance(uint8_t* sequence);
bool seader_ccid_payload_fits_frame(size_t payload_len, size_t uart_buf_size, size_t header_len);
bool seader_ccid_data_in_scratchpad(
const uint8_t* tx_buf,
size_t tx_buf_size,
size_t header_len,
const uint8_t* data,
size_t payload_len);
SeaderCcidStatus seader_ccid_decode_status(uint8_t status);
bool seader_ccid_response_matches_pending(bool pending, uint8_t expected_seq, uint8_t response_seq);
size_t seader_ccid_find_frame_start(
const uint8_t* data,
size_t len,
uint8_t sync,
uint8_t ctrl,
uint8_t nak);
bool seader_ccid_pending_timed_out(
bool pending,
uint32_t pending_since_tick,
uint32_t now_tick,
uint32_t timeout_ticks);
SeaderCcidDataRoute seader_ccid_route_data_block(
bool has_sam,
uint8_t sam_slot,
uint8_t message_slot,
uint8_t protocol_t);
+7
View File
@@ -31,16 +31,23 @@ typedef enum {
SEADER_T1_PCB_R_BLOCK = 0x80,
SEADER_T1_PCB_S_BLOCK = 0xC0,
SEADER_T1_R_BLOCK_SEQUENCE_MASK = 0x10,
SEADER_T1_S_BLOCK_RESPONSE_BIT = 0x20,
SEADER_T1_S_BLOCK_RESYNCH = 0x00,
SEADER_T1_S_BLOCK_IFS = 0x01,
SEADER_T1_S_BLOCK_ABORT = 0x02,
SEADER_T1_S_BLOCK_WTX = 0x03,
} SeaderT1Constant;
typedef struct {
uint8_t ifsc;
uint8_t ifsd;
uint8_t ifsd_pending;
uint8_t nad;
uint8_t send_pcb;
uint8_t recv_pcb;
BitBuffer* tx_buffer;
size_t tx_buffer_offset;
size_t last_tx_len;
BitBuffer* rx_buffer;
} SeaderT1State;
+222
View File
@@ -0,0 +1,222 @@
#include <stdint.h>
#include "ccid_logic.h"
#include "munit.h"
static MunitResult test_sequence_advance_wraps(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
uint8_t seq = 0;
munit_assert_uint8(seader_ccid_sequence_advance(&seq), ==, 0);
munit_assert_uint8(seq, ==, 1);
seq = 254;
munit_assert_uint8(seader_ccid_sequence_advance(&seq), ==, 254);
munit_assert_uint8(seq, ==, 255);
seq = 255;
munit_assert_uint8(seader_ccid_sequence_advance(&seq), ==, 255);
munit_assert_uint8(seq, ==, 0);
return MUNIT_OK;
}
static MunitResult test_payload_fits_buffer(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
munit_assert_true(seader_ccid_payload_fits_frame(10, 300, 12));
munit_assert_false(seader_ccid_payload_fits_frame(289, 300, 12));
munit_assert_true(seader_ccid_payload_fits_frame(288, 300, 12));
return MUNIT_OK;
}
static MunitResult test_data_in_scratchpad(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
uint8_t tx[64] = {0};
munit_assert_true(seader_ccid_data_in_scratchpad(tx, sizeof(tx), 12, tx + 12, 1));
munit_assert_true(seader_ccid_data_in_scratchpad(tx, sizeof(tx), 12, tx + 63, 1));
munit_assert_false(seader_ccid_data_in_scratchpad(tx, sizeof(tx), 12, tx + 11, 1));
munit_assert_false(seader_ccid_data_in_scratchpad(tx, sizeof(tx), 12, tx + 60, 8));
return MUNIT_OK;
}
static MunitResult test_response_seq_match(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
munit_assert_true(seader_ccid_response_matches_pending(false, 0x00, 0xff));
munit_assert_true(seader_ccid_response_matches_pending(true, 0x12, 0x12));
munit_assert_false(seader_ccid_response_matches_pending(true, 0x12, 0x13));
return MUNIT_OK;
}
static MunitResult test_status_decode_ok(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
SeaderCcidStatus status_ok = seader_ccid_decode_status(0x00);
munit_assert_uint8(status_ok.icc_status, ==, 0);
munit_assert_int(status_ok.command_status, ==, SeaderCcidDecodedCommandStatusProcessed);
return MUNIT_OK;
}
static MunitResult test_status_decode_failed(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
SeaderCcidStatus status_fail = seader_ccid_decode_status(0x41);
munit_assert_uint8(status_fail.icc_status, ==, 1);
munit_assert_int(status_fail.command_status, ==, SeaderCcidDecodedCommandStatusFailed);
return MUNIT_OK;
}
static MunitResult test_status_decode_time_extension(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
SeaderCcidStatus status_wait = seader_ccid_decode_status(0x80);
munit_assert_uint8(status_wait.icc_status, ==, 0);
munit_assert_int(
status_wait.command_status, ==, SeaderCcidDecodedCommandStatusTimeExtension);
return MUNIT_OK;
}
static MunitResult test_find_start_skips_nak_triplet(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
const uint8_t sync = 0x03;
const uint8_t ctrl = 0x06;
const uint8_t nak = 0x15;
const uint8_t frame_stream[] = {
0x03,
0x15,
0x16,
0x99,
0x03,
0x06,
0x80,
};
munit_assert_size(
seader_ccid_find_frame_start(frame_stream, sizeof(frame_stream), sync, ctrl, nak), ==, 4);
return MUNIT_OK;
}
static MunitResult test_find_start_noise_only(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
const uint8_t sync = 0x03;
const uint8_t ctrl = 0x06;
const uint8_t nak = 0x15;
const uint8_t noise_only[] = {0x01, 0x02, 0x03};
munit_assert_size(
seader_ccid_find_frame_start(noise_only, sizeof(noise_only), sync, ctrl, nak),
==,
sizeof(noise_only));
return MUNIT_OK;
}
static MunitResult test_pending_timeout_helper(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
munit_assert_false(seader_ccid_pending_timed_out(false, 100, 200, 50));
munit_assert_false(seader_ccid_pending_timed_out(true, 0, 200, 50));
munit_assert_false(seader_ccid_pending_timed_out(true, 100, 149, 50));
munit_assert_false(seader_ccid_pending_timed_out(true, 100, 150, 50));
munit_assert_true(seader_ccid_pending_timed_out(true, 100, 151, 50));
munit_assert_false(seader_ccid_pending_timed_out(true, 100, 200, 0));
return MUNIT_OK;
}
static MunitResult test_data_block_route(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
munit_assert_int(seader_ccid_route_data_block(true, 0, 0, 0), ==, SeaderCcidDataRouteSamT0);
munit_assert_int(seader_ccid_route_data_block(true, 0, 0, 1), ==, SeaderCcidDataRouteSamT1);
munit_assert_int(
seader_ccid_route_data_block(false, 0, 0, 1), ==, SeaderCcidDataRouteAtrRecognition);
munit_assert_int(
seader_ccid_route_data_block(true, 0, 1, 1), ==, SeaderCcidDataRouteWrongSlotError);
return MUNIT_OK;
}
static MunitTest test_ccid_cases[] = {
{(char*)"/sequence/advance-wraps-through-ff",
test_sequence_advance_wraps,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/frame/payload-fits-buffer",
test_payload_fits_buffer,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/frame/data-in-scratchpad",
test_data_in_scratchpad,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/pending/response-seq-match",
test_response_seq_match,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/status/decode-ok", test_status_decode_ok, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL},
{(char*)"/status/decode-failed",
test_status_decode_failed,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/status/decode-time-extension",
test_status_decode_time_extension,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/frame/find-start-skips-nak-triplet",
test_find_start_skips_nak_triplet,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/frame/find-start-noise-only",
test_find_start_noise_only,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/pending/timeout-helper",
test_pending_timeout_helper,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/routing/data-block-route",
test_data_block_route,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{NULL, NULL, NULL, NULL, 0, NULL},
};
MunitSuite test_ccid_logic_suite = {
"",
test_ccid_cases,
NULL,
1,
MUNIT_SUITE_OPTION_NONE,
};
+4
View File
@@ -1,12 +1,16 @@
#include "munit.h"
extern MunitSuite test_lrc_suite;
extern MunitSuite test_ccid_logic_suite;
extern MunitSuite test_t1_existing_suite;
extern MunitSuite test_t1_regressions_suite;
int main(int argc, char* argv[]) {
MunitSuite child_suites[] = {
{"/lrc", test_lrc_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
{"/t1", test_t1_existing_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
{"/t1-future", test_t1_regressions_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
{"/ccid", test_ccid_logic_suite.tests, NULL, 1, MUNIT_SUITE_OPTION_NONE},
{NULL, NULL, NULL, 0, 0},
};
MunitSuite main_suite = {
+308
View File
@@ -0,0 +1,308 @@
#include <string.h>
#include "munit.h"
#include "t_1_host_env.h"
static void test_callback(uint32_t event, void* context) {
(void)context;
g_t1_host_test_state.callback_call_count++;
g_t1_host_test_state.last_callback_event = event;
}
static Seader make_test_seader(SeaderUartBridge* uart, SeaderWorker* worker) {
memset(uart, 0, sizeof(*uart));
memset(worker, 0, sizeof(*worker));
worker->uart = uart;
worker->callback = test_callback;
Seader seader = {.worker = worker};
return seader;
}
static MunitResult test_recv_wtx_request_responds(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
SeaderUartBridge uart = {0};
SeaderWorker worker = {0};
Seader seader = make_test_seader(&uart, &worker);
t1_host_test_reset();
uint8_t s_wtx_req[] = {0x00, 0xC3, 0x01, 0x02, 0x00};
seader_add_lrc(s_wtx_req, 4);
CCID_Message message = {.payload = s_wtx_req, .dwLength = 5};
munit_assert_false(seader_recv_t1(&seader, &message));
munit_assert_size(g_t1_host_test_state.xfrblock_call_count, ==, 1);
munit_assert_uint8(g_t1_host_test_state.last_frame[1], ==, 0xE3);
return MUNIT_OK;
}
static MunitResult test_recv_resynch_request_responds(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
SeaderUartBridge uart = {0};
SeaderWorker worker = {0};
Seader seader = make_test_seader(&uart, &worker);
t1_host_test_reset();
uint8_t s_resync_req[] = {0x00, 0xC0, 0x00, 0x00};
seader_add_lrc(s_resync_req, 3);
CCID_Message message = {.payload = s_resync_req, .dwLength = 4};
munit_assert_false(seader_recv_t1(&seader, &message));
munit_assert_size(g_t1_host_test_state.xfrblock_call_count, ==, 1);
munit_assert_uint8(g_t1_host_test_state.last_frame[1], ==, 0xE0);
return MUNIT_OK;
}
static MunitResult test_recv_malformed_wtx_rejected(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
SeaderUartBridge uart = {0};
SeaderWorker worker = {0};
Seader seader = make_test_seader(&uart, &worker);
t1_host_test_reset();
uint8_t s_wtx_bad[] = {0x00, 0xC3, 0x00, 0x00};
seader_add_lrc(s_wtx_bad, 3);
CCID_Message message = {.payload = s_wtx_bad, .dwLength = 4};
munit_assert_false(seader_recv_t1(&seader, &message));
munit_assert_size(g_t1_host_test_state.xfrblock_call_count, ==, 1);
munit_assert_uint8(g_t1_host_test_state.last_frame[1], ==, 0x81);
return MUNIT_OK;
}
static MunitResult test_recv_malformed_ifs_rejected(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
SeaderUartBridge uart = {0};
SeaderWorker worker = {0};
Seader seader = make_test_seader(&uart, &worker);
t1_host_test_reset();
uint8_t s_ifs_bad[] = {0x00, 0xC1, 0x00, 0x00};
seader_add_lrc(s_ifs_bad, 3);
CCID_Message message = {.payload = s_ifs_bad, .dwLength = 4};
munit_assert_false(seader_recv_t1(&seader, &message));
munit_assert_size(g_t1_host_test_state.xfrblock_call_count, ==, 1);
munit_assert_uint8(g_t1_host_test_state.last_frame[1], ==, 0x81);
return MUNIT_OK;
}
static MunitResult test_recv_ifs_request_updates_ifsc(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
SeaderUartBridge uart = {0};
SeaderWorker worker = {0};
Seader seader = make_test_seader(&uart, &worker);
t1_host_test_reset();
uart.t1.ifsc = 0x20;
uint8_t s_ifs_req[] = {0x00, 0xC1, 0x01, 0x40, 0x00};
seader_add_lrc(s_ifs_req, 4);
CCID_Message message = {.payload = s_ifs_req, .dwLength = 5};
munit_assert_false(seader_recv_t1(&seader, &message));
munit_assert_size(g_t1_host_test_state.xfrblock_call_count, ==, 1);
munit_assert_uint8(g_t1_host_test_state.last_frame[3], ==, 0x40);
return MUNIT_OK;
}
static MunitResult test_recv_ifs_response_applies_pending_ifsd(
const MunitParameter params[],
void* fixture) {
(void)params;
(void)fixture;
SeaderUartBridge uart = {0};
SeaderWorker worker = {0};
Seader seader = make_test_seader(&uart, &worker);
t1_host_test_reset();
uart.t1.ifsd = 0x10;
uart.t1.ifsd_pending = 0x20;
uint8_t s_ifs_res[] = {0x00, 0xE1, 0x01, 0x20, 0x00};
seader_add_lrc(s_ifs_res, 4);
CCID_Message message = {.payload = s_ifs_res, .dwLength = 5};
munit_assert_false(seader_recv_t1(&seader, &message));
munit_assert_uint8(uart.t1.ifsd, ==, 0x20);
munit_assert_uint8(uart.t1.ifsd_pending, ==, 0x00);
return MUNIT_OK;
}
static MunitResult test_recv_ifs_response_mismatch_rejected(
const MunitParameter params[],
void* fixture) {
(void)params;
(void)fixture;
SeaderUartBridge uart = {0};
SeaderWorker worker = {0};
Seader seader = make_test_seader(&uart, &worker);
t1_host_test_reset();
uart.t1.ifsd_pending = 0x20;
uint8_t s_ifs_res_bad[] = {0x00, 0xE1, 0x01, 0x30, 0x00};
seader_add_lrc(s_ifs_res_bad, 4);
CCID_Message message = {.payload = s_ifs_res_bad, .dwLength = 5};
munit_assert_false(seader_recv_t1(&seader, &message));
munit_assert_size(g_t1_host_test_state.send_version_call_count, ==, 0);
munit_assert_size(g_t1_host_test_state.callback_call_count, ==, 0);
munit_assert_size(g_t1_host_test_state.xfrblock_call_count, ==, 1);
munit_assert_uint8(g_t1_host_test_state.last_frame[1], ==, 0x81);
return MUNIT_OK;
}
static MunitResult test_recv_i_block_too_large_rejected(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
SeaderUartBridge uart = {0};
SeaderWorker worker = {0};
Seader seader = make_test_seader(&uart, &worker);
t1_host_test_reset();
uart.t1.ifsd = 2;
uart.t1.recv_pcb = 0x00;
uint8_t i_block[] = {0x00, 0x00, 0x03, 0xAA, 0xBB, 0xCC, 0x00};
seader_add_lrc(i_block, 6);
CCID_Message message = {.payload = i_block, .dwLength = 7};
munit_assert_false(seader_recv_t1(&seader, &message));
munit_assert_size(g_t1_host_test_state.process_call_count, ==, 0);
munit_assert_size(g_t1_host_test_state.xfrblock_call_count, ==, 1);
munit_assert_uint8(g_t1_host_test_state.last_frame[1], ==, 0x81);
return MUNIT_OK;
}
static MunitResult test_recv_r_block_nack_retransmits(const MunitParameter params[], void* fixture) {
(void)params;
(void)fixture;
SeaderUartBridge uart = {0};
SeaderWorker worker = {0};
Seader seader = make_test_seader(&uart, &worker);
t1_host_test_reset();
uart.t1.send_pcb = 0x00;
uart.t1.ifsc = 4;
uart.t1.tx_buffer = bit_buffer_alloc(8);
bit_buffer_copy_bytes(uart.t1.tx_buffer, (const uint8_t*)"\xA0\xA1\xA2", 3);
uart.t1.tx_buffer_offset = 2;
uart.t1.last_tx_len = 2;
uint8_t r_block[] = {0x00, 0x80, 0x00, 0x00};
seader_add_lrc(r_block, 3);
CCID_Message message = {.payload = r_block, .dwLength = 4};
munit_assert_false(seader_recv_t1(&seader, &message));
munit_assert_size(g_t1_host_test_state.xfrblock_call_count, ==, 1);
munit_assert_uint8(uart.t1.send_pcb, ==, SEADER_T1_PCB_SEQUENCE_BIT);
bit_buffer_free(uart.t1.tx_buffer);
return MUNIT_OK;
}
static MunitResult test_recv_r_block_invalid_retransmit_state_errors(
const MunitParameter params[],
void* fixture) {
(void)params;
(void)fixture;
SeaderUartBridge uart = {0};
SeaderWorker worker = {0};
Seader seader = make_test_seader(&uart, &worker);
t1_host_test_reset();
uart.t1.send_pcb = 0x00;
uart.t1.tx_buffer = bit_buffer_alloc(8);
uart.t1.tx_buffer_offset = 0;
uart.t1.last_tx_len = 2;
uint8_t r_block[] = {0x00, 0x91, 0x00, 0x00};
seader_add_lrc(r_block, 3);
CCID_Message message = {.payload = r_block, .dwLength = 4};
munit_assert_false(seader_recv_t1(&seader, &message));
munit_assert_size(g_t1_host_test_state.xfrblock_call_count, ==, 0);
bit_buffer_free(uart.t1.tx_buffer);
return MUNIT_OK;
}
static MunitTest test_t1_regression_cases[] = {
{(char*)"/recv/wtx-request-responds",
test_recv_wtx_request_responds,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/recv/resynch-request-responds",
test_recv_resynch_request_responds,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/recv/malformed-wtx-len-zero-rejected",
test_recv_malformed_wtx_rejected,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/recv/malformed-ifs-len-zero-rejected",
test_recv_malformed_ifs_rejected,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/recv/ifs-request-updates-ifsc",
test_recv_ifs_request_updates_ifsc,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/recv/ifs-response-applies-pending-ifsd",
test_recv_ifs_response_applies_pending_ifsd,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/recv/ifs-response-mismatch-rejected",
test_recv_ifs_response_mismatch_rejected,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/recv/i-block-too-large-rejected",
test_recv_i_block_too_large_rejected,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/recv/r-block-nack-retransmits",
test_recv_r_block_nack_retransmits,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{(char*)"/recv/r-block-invalid-retransmit-state-errors",
test_recv_r_block_invalid_retransmit_state_errors,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL},
{NULL, NULL, NULL, NULL, 0, NULL},
};
MunitSuite test_t1_regressions_suite = {
"",
test_t1_regression_cases,
NULL,
1,
MUNIT_SUITE_OPTION_NONE,
};