130 lines
4.2 KiB
C
130 lines
4.2 KiB
C
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#include "trikke_transport.h"
|
|
|
|
typedef struct {
|
|
trikke_transport_status_t begin_status;
|
|
trikke_transport_status_t poll_status;
|
|
unsigned int begin_calls;
|
|
unsigned int poll_calls;
|
|
const uint8_t *packet;
|
|
size_t packet_size;
|
|
} mock_transport_t;
|
|
|
|
static int fail(int code, const char *message)
|
|
{
|
|
fprintf(stderr, "transport fixture failure %d: %s\n", code, message);
|
|
return code;
|
|
}
|
|
|
|
static trikke_transport_status_t mock_begin(
|
|
void *context,
|
|
const uint8_t *packet,
|
|
size_t packet_size)
|
|
{
|
|
mock_transport_t *mock = context;
|
|
++mock->begin_calls;
|
|
mock->packet = packet;
|
|
mock->packet_size = packet_size;
|
|
return mock->begin_status;
|
|
}
|
|
|
|
static trikke_transport_status_t mock_poll(void *context)
|
|
{
|
|
mock_transport_t *mock = context;
|
|
++mock->poll_calls;
|
|
return mock->poll_status;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
const uint8_t packet[] = {0x54, 0x52, 0x4B, 0x31};
|
|
mock_transport_t mock = {
|
|
.begin_status = TRIKKE_TRANSPORT_RETRY,
|
|
.poll_status = TRIKKE_TRANSPORT_PENDING,
|
|
};
|
|
const trikke_transport_t transport = {
|
|
.context = &mock,
|
|
.begin = mock_begin,
|
|
.poll = mock_poll,
|
|
};
|
|
trikke_transport_sender_t sender;
|
|
trikke_transport_sender_init(&sender);
|
|
|
|
if (trikke_transport_sender_step(
|
|
&sender, &transport, packet, sizeof(packet)) !=
|
|
TRIKKE_TRANSPORT_RETRY ||
|
|
sender.pending || mock.begin_calls != 1 || mock.poll_calls != 0 ||
|
|
mock.packet != packet || mock.packet_size != sizeof(packet)) {
|
|
return fail(1, "zero-accept submission must remain retryable");
|
|
}
|
|
|
|
mock.begin_status = TRIKKE_TRANSPORT_PENDING;
|
|
if (trikke_transport_sender_step(
|
|
&sender, &transport, packet, sizeof(packet)) !=
|
|
TRIKKE_TRANSPORT_PENDING ||
|
|
!sender.pending || mock.begin_calls != 2 || mock.poll_calls != 0) {
|
|
return fail(2, "accepted submission must become pending");
|
|
}
|
|
|
|
if (trikke_transport_sender_step(
|
|
&sender, &transport, packet, sizeof(packet)) !=
|
|
TRIKKE_TRANSPORT_PENDING ||
|
|
!sender.pending || mock.begin_calls != 2 || mock.poll_calls != 1) {
|
|
return fail(3, "pending transfer must poll without resubmission");
|
|
}
|
|
|
|
mock.poll_status = TRIKKE_TRANSPORT_COMPLETE;
|
|
if (trikke_transport_sender_step(
|
|
&sender, &transport, packet, sizeof(packet)) !=
|
|
TRIKKE_TRANSPORT_COMPLETE ||
|
|
sender.pending || mock.begin_calls != 2 || mock.poll_calls != 2) {
|
|
return fail(4, "completed transfer must return to idle");
|
|
}
|
|
|
|
mock.begin_status = TRIKKE_TRANSPORT_COMPLETE;
|
|
if (trikke_transport_sender_step(
|
|
&sender, &transport, packet, sizeof(packet)) !=
|
|
TRIKKE_TRANSPORT_COMPLETE ||
|
|
sender.pending || mock.begin_calls != 3) {
|
|
return fail(5, "synchronous completion contract");
|
|
}
|
|
|
|
mock.begin_status = TRIKKE_TRANSPORT_PENDING;
|
|
mock.poll_status = TRIKKE_TRANSPORT_RETRY;
|
|
if (trikke_transport_sender_step(
|
|
&sender, &transport, packet, sizeof(packet)) !=
|
|
TRIKKE_TRANSPORT_PENDING ||
|
|
trikke_transport_sender_step(
|
|
&sender, &transport, packet, sizeof(packet)) !=
|
|
TRIKKE_TRANSPORT_RETRY ||
|
|
sender.pending) {
|
|
return fail(6, "backend-confirmed safe retry must return to idle");
|
|
}
|
|
|
|
if (trikke_transport_sender_step(
|
|
NULL, &transport, packet, sizeof(packet)) !=
|
|
TRIKKE_TRANSPORT_FATAL ||
|
|
trikke_transport_sender_step(
|
|
&sender, NULL, packet, sizeof(packet)) != TRIKKE_TRANSPORT_FATAL ||
|
|
trikke_transport_sender_step(
|
|
&sender, &transport, NULL, sizeof(packet)) !=
|
|
TRIKKE_TRANSPORT_FATAL ||
|
|
trikke_transport_sender_step(
|
|
&sender, &transport, packet, 0) != TRIKKE_TRANSPORT_FATAL) {
|
|
return fail(7, "invalid arguments must fail closed");
|
|
}
|
|
|
|
mock.begin_status = (trikke_transport_status_t)99;
|
|
if (trikke_transport_sender_step(
|
|
&sender, &transport, packet, sizeof(packet)) !=
|
|
TRIKKE_TRANSPORT_FATAL ||
|
|
sender.pending) {
|
|
return fail(8, "unknown backend status must fail closed");
|
|
}
|
|
|
|
return 0;
|
|
}
|