4 releases (2 breaking)

0.3.0 Apr 21, 2024
0.2.1 Apr 12, 2024
0.2.0 Apr 12, 2024
0.1.0 Apr 6, 2024

#906 in Hardware support

MIT license

54KB
1K SLoC

usbd-class-tester

Crates.io Docs.rs

A library for running tests of usb-device classes on developer's system natively.

About

Testing is difficult, and if it's even more difficult when it involves a dedicated hardware and doing the test manually. Often a lot of stuff needs to be re-tested even after small code changes.

This library aims to help testing the implementation of protocols in USB devices which are based on usb-device crate by providing a means of simulating Host's accesses to the device.

Initial implementation was done for tests in usbd-dfu crate. This library is based on that idea, but extends it a lot. For example it adds a set of convenience functions for Control transfers, while originally this was done via plain u8 arrays only.

Supported operations

  • IN and OUT EP0 control transfers
  • Transfers on other endpoints (e.g. Interrupt)

Not supported operations

Almost everything else, including but not limited to:

  • Reset
  • Suspend and Resume
  • Bulk transfers
  • Iso transfers
  • ...

License

This project is licensed under MIT License (LICENSE).

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be licensed as above, without any additional terms or conditions.

Example

The example defines an empty UsbClass implementation for TestUsbClass. Normally this would also include things like endpoint allocations, device-specific descriptor generation, and the code handling everything. This is not in the scope of this example.

A minimal TestCtx creates TestUsbClass that will be passed to a test case. In general, TestCtx allows some degree of environment customization, like choosing EP0 transfer size, or redefining how UsbDevice is created.

Check crate tests directory for more examples.

Also see the documentation for usb-device.

use usb_device::class_prelude::*;
use usbd_class_tester::prelude::*;

// `UsbClass` under the test.
pub struct TestUsbClass {}
impl<B: UsbBus> UsbClass<B> for TestUsbClass {}

// Context to create a testable instance of `TestUsbClass`
struct TestCtx {}
impl UsbDeviceCtx for TestCtx {
    type C<'c> = TestUsbClass;
    fn create_class<'a>(
        &mut self,
        alloc: &'a UsbBusAllocator<EmulatedUsbBus>,
    ) -> AnyResult<TestUsbClass> {
        Ok(TestUsbClass {})
    }
}

#[test]
fn test_interface_get_status() {
    TestCtx {}
        .with_usb(|mut cls, mut dev| {
            let st = dev.interface_get_status(&mut cls, 0).expect("status");
            assert_eq!(st, 0);
        })
        .expect("with_usb");
}

USB debug logging can be enabled, for example, by running tests with: $ RUST_LOG=trace cargo test -- --nocapture

Dependencies

~1.5MB
~33K SLoC