129 lines
6.4 KiB
C
129 lines
6.4 KiB
C
#define _POSIX_C_SOURCE 200809L
|
|
#include "hid_device.h"
|
|
#include "lamp_array.h"
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
static void write_file(const char *path, const void *data, size_t size)
|
|
{
|
|
FILE *f = fopen(path, "wb");
|
|
assert(f);
|
|
assert(fwrite(data, 1, size, f) == size);
|
|
assert(fclose(f) == 0);
|
|
}
|
|
static void fixture(const char *root, const char *name, const char *identity)
|
|
{
|
|
char path[512];
|
|
assert(snprintf(path, sizeof path, "%s/%s", root, name) > 0);
|
|
assert(mkdir(path, 0700) == 0);
|
|
assert(snprintf(path, sizeof path, "%s/%s/device", root, name) > 0);
|
|
assert(mkdir(path, 0700) == 0);
|
|
assert(snprintf(path, sizeof path, "%s/%s/device/uevent", root, name) > 0);
|
|
write_file(path, identity, strlen(identity));
|
|
}
|
|
static void remove_fixture(const char *root, const char *name)
|
|
{
|
|
char path[512];
|
|
(void)snprintf(path, sizeof path, "%s/%s/device/uevent", root, name);
|
|
assert(unlink(path) == 0);
|
|
(void)snprintf(path, sizeof path, "%s/%s/device", root, name);
|
|
assert(rmdir(path) == 0);
|
|
(void)snprintf(path, sizeof path, "%s/%s", root, name);
|
|
assert(rmdir(path) == 0);
|
|
}
|
|
struct mock { uint8_t bytes[23]; int result; unsigned calls; };
|
|
static int fake_get(void *context, uint8_t *report, size_t size)
|
|
{
|
|
struct mock *m = context;
|
|
assert(size == 23 && report[0] == 0x41);
|
|
for (size_t i = 1; i < size; ++i) assert(report[i] == 0);
|
|
++m->calls;
|
|
if (m->result < 0) { errno = EACCES; return -1; }
|
|
memcpy(report, m->bytes, size);
|
|
return m->result;
|
|
}
|
|
int main(int argc, char **argv)
|
|
{
|
|
assert(argc == 2);
|
|
uint8_t rgb[3] = {0};
|
|
assert(la_color("#B4BEFE", rgb) && rgb[0] == 180 && rgb[1] == 190 && rgb[2] == 254);
|
|
assert(la_color("#aBcD09", rgb) && rgb[0] == 171 && rgb[1] == 205 && rgb[2] == 9);
|
|
assert(la_color("#000000", rgb) && la_color("#FFFFFF", rgb));
|
|
const char *bad[] = {"", "B4BEFE", "#fff", "#FFFFFG", "#0000000", " #000000", "#000000\n"};
|
|
for (size_t i = 0; i < sizeof bad/sizeof bad[0]; ++i) assert(!la_color(bad[i], rgb));
|
|
assert(!la_color(NULL, rgb) && !la_color("#000000", NULL));
|
|
unsigned percent = 999;
|
|
assert(la_percent("0", &percent) && percent == 0);
|
|
assert(la_percent("60", &percent) && percent == 60);
|
|
assert(la_percent("100", &percent) && percent == 100);
|
|
const char *bad_percent[] = {"", "-1", "+1", "101", "999999999999", "60%", " 60", "1.0"};
|
|
for (size_t i = 0; i < sizeof bad_percent/sizeof bad_percent[0]; ++i) assert(!la_percent(bad_percent[i], &percent));
|
|
assert(!la_percent(NULL, &percent) && !la_percent("0", NULL));
|
|
/* Golden wire bytes from the audited layout, including LE range boundaries.
|
|
* These are offline synthetic counts/levels, not claims about the keyboard. */
|
|
uint8_t guarded[12]; memset(guarded, 0xaa, sizeof guarded);
|
|
const uint8_t rgbi[4] = {0xb4, 0xbe, 0xfe, 0xff};
|
|
const uint8_t golden[10] = {0x45, 1, 0, 0, 1, 1, 0xb4, 0xbe, 0xfe, 0xff};
|
|
assert(la_range(258, rgbi, guarded+1, 10));
|
|
assert(guarded[0] == 0xaa && guarded[11] == 0xaa && !memcmp(guarded+1, golden, 10));
|
|
assert(!la_range(0, rgbi, guarded, 10) && !la_range(1, rgbi, guarded, 9));
|
|
assert(!la_range(1, NULL, guarded, 10) && !la_range(1, rgbi, NULL, 10));
|
|
assert(la_range(65535, rgbi, guarded, 10) && guarded[4] == 0xfe && guarded[5] == 0xff);
|
|
assert(la_range(1, rgbi, guarded, 10) && guarded[4] == 0 && guarded[5] == 0);
|
|
assert(la_control(true, guarded, 2) && guarded[0] == 0x46 && guarded[1] == 1);
|
|
assert(la_control(false, guarded, 2) && guarded[1] == 0);
|
|
assert(!la_control(true, guarded, 1) && !la_control(true, NULL, 2));
|
|
struct mock m = {.bytes = {0x41, 2, 1}, .result = 23};
|
|
m.bytes[19] = 0x78; m.bytes[20] = 0x56; m.bytes[21] = 0x34; m.bytes[22] = 0x12;
|
|
struct la_attributes a;
|
|
assert(la_read_attributes(fake_get, &m, &a) && a.count == 258 && a.min_interval_us == 0x12345678 && m.calls == 1);
|
|
m.result = 22;
|
|
assert(!la_read_attributes(fake_get, &m, &a) && errno == EPROTO);
|
|
m.result = 24;
|
|
assert(!la_read_attributes(fake_get, &m, &a) && errno == EPROTO);
|
|
m.result = -1;
|
|
assert(!la_read_attributes(fake_get, &m, &a) && errno == EACCES);
|
|
m.result = 23; m.bytes[0] = 0x31;
|
|
assert(!la_read_attributes(fake_get, &m, &a));
|
|
m.bytes[0] = 0x41; m.bytes[1] = 0; m.bytes[2] = 0;
|
|
assert(!la_read_attributes(fake_get, &m, &a));
|
|
m.bytes[1] = 1; m.bytes[22] = 0x80;
|
|
assert(!la_read_attributes(fake_get, &m, &a));
|
|
assert(!la_read_attributes(NULL, &m, &a) && errno == EINVAL);
|
|
assert(hid_get(NULL, guarded, 10) == -1 && errno == EINVAL);
|
|
assert(hid_open_verified("../hidraw1") == -1 && errno == EINVAL);
|
|
assert(hid_identity("DRIVER=hid-generic\nHID_ID=0018:00000B05:00005570\n"));
|
|
assert(!hid_identity("HID_ID=0003:00000B05:00005570\n"));
|
|
assert(!hid_identity("XHID_ID=0018:00000B05:00005570\n"));
|
|
assert(!hid_identity("HID_ID=0018:00000B05:000055700\n"));
|
|
char root[] = "/tmp/labfy-rgb-test-XXXXXX";
|
|
assert(mkdtemp(root));
|
|
char name[64];
|
|
assert(hid_discover(root, name, sizeof name) == -1 && errno == ENODEV);
|
|
fixture(root, "hidraw0", "HID_ID=0018:0000093A:00003017\n");
|
|
fixture(root, "hidraw27", "HID_ID=0018:00000B05:00005570\n");
|
|
assert(hid_discover(root, name, sizeof name) == 0 && !strcmp(name, "hidraw27"));
|
|
assert(hid_discover(root, name, 2) == -1 && errno == ENAMETOOLONG);
|
|
uint8_t desc[4096];
|
|
FILE *f = fopen(argv[1], "rb"); assert(f);
|
|
size_t n = fread(desc, 1, sizeof desc, f); assert(!ferror(f) && feof(f)); assert(fclose(f) == 0);
|
|
assert(la_profile(desc, n) && !la_profile(desc, n-1));
|
|
desc[0] ^= 1; assert(!la_profile(desc, n)); desc[0] ^= 1;
|
|
char path[512];
|
|
(void)snprintf(path, sizeof path, "%s/hidraw27/device/report_descriptor", root);
|
|
write_file(path, desc, n);
|
|
uint8_t copy[4096]; size_t count;
|
|
assert(hid_descriptor(root, "hidraw27", copy, sizeof copy, &count) == 0 && count == n && !memcmp(copy, desc, n));
|
|
assert(hid_descriptor(root, "hidraw27", copy, n-1, &count) == -1 && errno == EOVERFLOW);
|
|
assert(unlink(path) == 0);
|
|
fixture(root, "hidraw2", "HID_ID=0018:00000B05:00005570\n");
|
|
assert(hid_discover(root, name, sizeof name) == -1 && errno == EEXIST);
|
|
remove_fixture(root, "hidraw2"); remove_fixture(root, "hidraw27"); remove_fixture(root, "hidraw0");
|
|
assert(rmdir(root) == 0);
|
|
puts("All offline core tests passed; no real HID device opened.");
|
|
return 0;
|
|
}
|