tests: virtual HID device test harness for all four backends (hidraw, libusb, winapi, darwin)#815
Conversation
|
Great. We need this kind of virtual test device for hidapi (and also libusb). |
1cdc8d5 to
b330600
Compare
|
FYI on WDK, the Windows runners have WDK installed already. Nuget WDK -- smaller but lacking some tools, which may be okay for this purpose Reference: |
5a24890 to
6089973
Compare
|
Thanks @mcuee, that's useful. The This reply was generated by Claude Code at my request. |
https://www.instagram.com/p/DXcOy5riYPS/ (I home community don't mind a little humor here) |
d3877f1 to
35b5186
Compare
|
Followed up on the WDK tip — thanks again. On the current So rather than dropping the download, I cached it. The (The NuGet WDK would be a cleaner long-term route, but it needs reworking the legacy Posted by Claude Code at my request. |
a0792ee to
3ae4b91
Compare
|
I see two general issues with this PR:
CC: @JoergAtGithub - not sure if your'e watching this issue, you might be interested in this in general. |
I do not see this as an issue. Just need to mention it clearly. They can just skip the test codes.
Again I think this is okay for this testing codes. I agree this should not be the case for the core library codes. |
|
First issue -- macOS compiler error -- maybe my version is newer than the runner (just upgraded to macOS 26.5.1) |
|
Just wondering if you can make the documentation to carry out the tests using a physical Mac. Never did such stuff on a Mac. BTW, is it possible to use sudo to replace the entitlement and consent? |
Unfortunately now. CI runner already has sude - we would have done so already.
You actually need an Apple Developer account (cost $100 a year) with your own certificate/provision generated. I'll update the docs to have a clear mention of this. I actuall haven't tested this myself either. Don't really have time to do so. |
Add a reusable harness that runs HIDAPI tests against a *virtual* HID device,
needing no physical hardware. Tests use only the public HIDAPI API plus a
backend-agnostic test_virtual_device interface, so the same test runs against
every backend that ships a virtual-device provider. Devices expose pre-recorded
"scenarios": the test sends a Feature report carrying a command byte and the
device replays the matching canned input report.
- src/tests/test_device_io.c: a simple open -> write -> exchange reports ->
close smoke test (skips via CTest code 77 when no virtual device is present).
- Providers:
test_virtual_device_uhid.c Linux hidraw (kernel /dev/uhid)
test_virtual_device_rawgadget.c Linux libusb (/dev/raw-gadget + dummy_hcd)
test_virtual_device_win.c (+windows/driver/) Windows winapi (vhidmini2 UMDF2)
test_virtual_device_mac.c macOS darwin (IOHIDUserDevice)
Each self-skips when its device can't be created.
- HIDAPI_WITH_TESTS is offered on Linux/macOS too; src/tests builds the test for
whichever backend(s) are present.
- src/tests/README.md documents the providers, the scenario protocol, and why
FreeBSD/NetBSD/OpenBSD have no provider (no userspace HID/USB-create facility).
- src/tests/windows/driver/ vendors a modified Microsoft vhidmini2 UMDF2 sample
under its original Microsoft Public License (MS-PL); LICENSE.txt and README.md
there record the provenance and modifications and keep it separate from
HIDAPI's own license (the driver is a standalone test fixture, not linked into
the library).
Assisted-by: Claude:claude-opus-4.8
- builds.yml: build the test on Linux/Windows/macOS and run it where possible (ubuntu-cmake loads uhid and runs DeviceIO_hidraw; Windows/macOS/libusb build and self-skip), keeping the per-push matrix green. - win-vhid-test.yml: build, self-sign and install the vhidmini2 driver on a hosted windows-latest runner and run DeviceIO_winapi against it. - libusb-vhid-test.yml (+ .github/vmrun-libusb.sh): the hosted kernel has no USB gadget subsystem, so run DeviceIO_libusb inside a virtme-ng VM that boots a generic kernel (building dummy_hcd out-of-tree and loading raw_gadget) against a real virtual USB device. Both privileged jobs run only via workflow_dispatch or a 'ci-virtual-device' pull-request label, so they stay out of the per-push matrix. Assisted-by: Claude:claude-opus-4.8
3ae4b91 to
1f62270
Compare
|
Hi @mcuee — this is Claude Code, posting on @Youw's behalf. A few updates on the points you raised, plus one request for your help at the end. macOS build error ( Running on a real Mac. Added a "Running the macOS ( MS-licensed driver. The vendored vhidmini2 driver now ships its upstream MS-PL My request — this is Claude asking for your help, on @Youw's behalf: could you confirm #816 builds cleanly for you on macOS 26.5.1 / Apple clang 21? I can't reproduce the warning on the CI runner's older clang and don't have a current Mac to test on myself, so a confirmation from your setup would be a big help in verifying the fix actually resolves the error you hit. Posted by Claude Code at @Youw's request. |
|
Great. #816 fixed the macOS build issue. |
Brings in the windows-cmake vcvars fix (setup-msvc-dev + windows-mingw job), the mac -Wgnu-folding-constant fix, the static-analysis cleanups and the AGENTS.md contribution rules, so this branch's CI runs against current master. Assisted-by: claude-code:claude-fable-5
- test_platform.h: pthread_timedjoin_np() is a glibc/BSD extension that does not exist on macOS; implement the timed join portably by polling a completion flag (set by the thread wrapper, read with acquire semantics) and joining once it is set. Drops the _GNU_SOURCE requirement. - test_virtual_device_mac.c: only treat *Feature* SET_REPORTs as scenario triggers; hid_write() Output reports arrive through the same callback on macOS and must not replay input (matches the shared contract and the other providers). - windows/driver: the test device is unnumbered, but WriteReport/GetFeature/ GetInputReport/SetOutputReport still gated on the sample's report id 1 and therefore rejected every request (hidclass passes id 0 for an unnumbered device); accept report id 0 and return 0 as the input-report id, so the descriptor-advertised Output/Input/Feature paths actually work. - src/tests/CMakeLists.txt: SKIP_RETURN_CODE needs CMake 3.16; with an older CMake a legitimate provider self-skip would be reported as a FAILure, so warn and skip adding the tests instead. Findings surfaced by a multi-model adversarial code review. Assisted-by: claude-code:claude-fable-5
The job still set up MSVC by calling the hard-coded "Enterprise" vcvars64.bat path, which no longer exists on windows-latest (the same breakage builds.yml already fixed in #817). Use the setup-msvc-dev action and invoke msbuild from that environment instead. Assisted-by: claude-code:claude-fable-5
The windows-latest and windows-2025 labels now both resolve to the VS2026
image, whose only MSBuild is 18.x; the cached WDK 10.0.26100.6584 layout
ships DriverKit build tasks only up to 17.0, so the driver build fails with
MSB4062 ("The ValidateNTTargetVersion task could not be loaded from ...
Microsoft.DriverKit.Build.Tasks.18.0.dll"). Pin the job to windows-2022,
which still carries VS2022 / MSBuild 17. Can move to a newer image once a
WDK that ships the 18.0 build tasks is cached here.
Assisted-by: claude-code:claude-fable-5
0300db0 to
d2bc584
Compare
No single hosted image can run the whole flow anymore: the cached WDK (10.0.26100.6584) ships DriverKit build tasks only for MSBuild 17 (VS2022), which the windows-2025* images no longer carry (VS2026/MSBuild 18 fails with MSB4062), while the driver package's INF depends on MsHidUmdf.inf semantics from build 22000, so it does not install on Server 2022. Build the driver on windows-2022 (VS2022 + cached WDK) and pass the signed package - plus devcon.exe from the WDK - as an artifact to a windows-latest (Server 2025) job that installs it and runs DeviceIO_winapi against it. Both halves run in environments where they are known to work; merge them back into one job once a WDK with the 18.0 build tasks is cached here. Assisted-by: claude-code:claude-fable-5
Assisted-by: claude-code:claude-fable-5
Brings in #813 (IWYU + leak guards), #815 (virtual-device test harness), #817 (CI vcvars fix, already cherry-picked) and #708 (libusb hid_error). Conflicts in libusb/hid.c (hotplug context vs last_global_error, refactored hid_enumerate vs its error reporting) and linux/hid.c (includes) resolved by keeping both sides' functionality. Assisted-by: claude-code:claude-fable-5
Summary
A reusable virtual HID device test harness: HIDAPI tests run against a virtual device, so they need no physical hardware. Tests are written purely against the public HIDAPI API plus a small backend-agnostic
test_virtual_deviceinterface, so the same test runs on every backend that ships a provider.Each virtual device carries a few pre-recorded scenarios: the test sends a Feature report whose first payload byte is a
TEST_VDEV_CMD_*command, and the device replays the matching canned input report. All device behaviour lives in the per-backend provider; the test code is 100% platform-neutral. Further tests can build on this harness (e.g. thehid_read_interrupttest in #799).What's here
src/tests/test_device_io.c— a device-I/O smoke test: open → write an output report → trigger + read back two canned input reports → close. Exits with CTest's skip code (77) when no virtual device can be created, so ordinary builds on any host stay green.src/tests/test_virtual_device.h— the shared contract (report size, commands, canned payloads);test_platform.h— portable thread/timing helpers for tests.test_virtual_device_uhid.c/dev/uhidtest_virtual_device_rawgadget.c/dev/raw-gadget+dummy_hcd, inside a VMlibusb-vhid-testtest_virtual_device_win.c+src/tests/windows/driver/win-vhid-testtest_virtual_device_mac.cIOHIDUserDevice(IOKit)-DHIDAPI_WITH_TESTS=ON(offered on Linux/Windows/macOS, default OFF) buildssrc/testsfor whichever backends are present. Requires CMake ≥ 3.16 for correct skip reporting (older CMake gets a warning and no tests).CI
builds.yml): the test is built on all platforms and run where possible.ubuntu-cmakeloadsuhidand runsDeviceIO_hidrawfor real;DeviceIO_libusb, Windows and macOS build the test and self-skip — the matrix stays green everywhere.win-vhid-test.yml: builds and self-signs the vhidmini2 driver onwindows-2022(whose MSBuild matches the cached WDK's driver build tasks), then installs it viadevcononwindows-latestand runsDeviceIO_winapiagainst the real device. ✅ passing.libusb-vhid-test.yml: the hosted kernel has no USB gadget subsystem, soDeviceIO_libusbruns inside a lightweightvirtme-ng+ QEMU VM booting a generic Ubuntu kernel (withraw_gadgetloaded anddummy_hcdbuilt out-of-tree), against a real virtual USB device. ✅ passing. The same approach works locally and on WSL2.The two privileged jobs run via
workflow_dispatchor automatically on a pull request carrying theci-virtual-devicelabel, keeping them out of the per-push matrix.Licensing
src/tests/windows/driver/vendors a modified Microsoft vhidmini2 UMDF2 sample under its original MS-PL license — a completeLICENSE.txtplus aREADME.mddocumenting provenance and modifications live in that directory. It is a standalone test fixture (built, installed and removed out-of-band by CI; never linked into or shipped with the library), separate from HIDAPI's own licensing. Downstream projects consuming HIDAPI as a subproject can simply not enable the tests.Platforms without a provider
FreeBSD/NetBSD/OpenBSD have no userspace facility to create a virtual HID/USB device, so there is deliberately no provider for them —
src/tests/README.mddocuments the details. Running the macOS provider on a real Mac (Apple Developer account,com.apple.developer.hid.virtual.deviceentitlement, Accessibility consent) is documented there as well.Assisted-by: claude-code:claude-opus-4-8
Assisted-by: claude-code:claude-fable-5