labfy-rgb/tests/test_transport.c
2026-11-09 19:01:00 +01:00

101 lines
4.3 KiB
C

#define _POSIX_C_SOURCE 200809L
#include "hid_device.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/hidraw.h>
#include <linux/input.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/file.h>
#include <unistd.h>
#include "../src/profile.inc"
static unsigned calls, closes, opens;
static int mode, flags, ret_override = -2;
/* Linker wrappers never forward ANY call to /dev or ioctl. The actual
* production transport runs against these syscall doubles, including validation. */
int __wrap_open(const char *path, int oflag, ...)
{
++opens;
assert(!strcmp(path, "/dev/hidraw77")); flags = oflag;
if (mode == 8) { errno = EACCES; return -1; }
return 77;
}
int __wrap_open64(const char *path, int oflag, ...) { return __wrap_open(path, oflag); }
int __wrap_close(int fd) { assert(fd == 77); ++closes; return 0; }
int __wrap_flock(int fd, int operation)
{
assert(fd == 77 && operation == (LOCK_EX | LOCK_NB));
if (mode == 7) { errno = EWOULDBLOCK; return -1; }
return 0;
}
int __wrap_ioctl(int fd, unsigned long request, ...)
{
assert(fd == 77); ++calls;
va_list ap; va_start(ap, request); void *argument = va_arg(ap, void *); va_end(ap);
if (request == HIDIOCGRAWINFO) {
struct hidraw_devinfo *info = argument;
info->bustype = mode == 1 ? BUS_USB : BUS_I2C;
info->vendor = mode == 2 ? 0x1234 : 0x0b05;
info->product = mode == 3 ? 0x9999 : 0x5570;
return 0;
}
if (request == HIDIOCGRDESCSIZE) {
*(int *)argument = mode == 4 ? HID_MAX_DESCRIPTOR_SIZE+1 : (int)sizeof profile;
return 0;
}
if (request == HIDIOCGRDESC) {
struct hidraw_report_descriptor *d = argument;
assert(d->size == sizeof profile);
memcpy(d->value, profile, sizeof profile);
if (mode == 5) d->value[0] ^= 1;
if (mode == 6) ++d->size;
return 0;
}
assert(request == HIDIOCGFEATURE(23) || request == HIDIOCGFEATURE(29) ||
request == HIDIOCSFEATURE(2) || request == HIDIOCSFEATURE(3) || request == HIDIOCSFEATURE(10));
uint8_t *r = argument;
unsigned n = _IOC_SIZE(request);
if (_IOC_NR(request) == _IOC_NR(HIDIOCSFEATURE(2))) r[0] = 0; /* ensure caller const bytes survive */
if (ret_override == -1) { errno = EIO; return -1; }
return ret_override == -2 ? (int)n : ret_override;
}
int main(void)
{
assert(hid_open_verified("hidraw77") == 77 && (flags & O_ACCMODE) == O_RDONLY);
assert(__wrap_close(77) == 0);
assert(hid_open_control("hidraw77") == 77 && (flags & O_ACCMODE) == O_RDWR && (flags & O_NOFOLLOW) && (flags & O_CLOEXEC));
assert(__wrap_close(77) == 0);
for (mode = 1; mode <= 8; ++mode) {
unsigned before = closes;
assert(hid_open_control("hidraw77") == -1);
assert(closes == before + (mode == 8 ? 0u : 1u));
assert(errno == (mode <= 3 ? ENODEV : mode <= 6 ? EPROTO : mode == 7 ? EWOULDBLOCK : EACCES));
}
mode = 0;
int fd = 77;
uint8_t r[29] = {0x41};
assert(hid_get(&fd, r, 23) == 23);
r[0] = 0x43; assert(hid_get(&fd, r, 29) == 29);
const uint8_t selector[] = {0x42, 0, 0}, host[] = {0x46, 0}, automatic[] = {0x46, 1};
assert(hid_set(&fd, selector, 3) == 3 && selector[0] == 0x42);
assert(hid_set(&fd, host, 2) == 2 && host[0] == 0x46);
assert(hid_set(&fd, automatic, 2) == 2);
uint8_t range[10] = {0x45, 1, 0, 0, 0, 0, 180, 190, 254, 255};
assert(hid_set(&fd, range, 10) == 10 && range[0] == 0x45);
unsigned before = calls;
range[1] = 8; assert(hid_set(&fd, range, 10) == -1 && errno == EINVAL);
range[1] = 1; range[4] = 1; assert(hid_set(&fd, range, 10) == -1);
assert(hid_set(&fd, selector, 2) == -1 && hid_set(NULL, host, 2) == -1);
r[0] = 0x31; assert(hid_get(&fd, r, 23) == -1);
assert(calls == before);
ret_override = 1; assert(hid_set(&fd, host, 2) == -1 && errno == EPROTO);
ret_override = 0; assert(hid_set(&fd, host, 2) == -1 && errno == EPROTO);
ret_override = 3; assert(hid_set(&fd, host, 2) == -1 && errno == EPROTO);
ret_override = -1; assert(hid_set(&fd, host, 2) == -1 && errno == EIO);
assert(hid_open_control("../../hidraw77") == -1 && errno == EINVAL);
assert(opens == 10);
puts("Production hidraw transport verified via syscall doubles; no device opened.");
return 0;
}