#define _POSIX_C_SOURCE 200809L #include "hid_device.h" #include "lamp_array.h" #include #include #include #include #include #include #include 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; }