mod device; /// Runs tests against a TestClass device running on actual hardware using libusb. /// /// This is implemented as an example as opposed to a test because the Rust test runner system is /// not well suited for running tests that must depend on outside resources such as hardware and /// cannot be run in parallel. mod tests; use crate::device::open_device; use crate::tests::{get_tests, TestFn}; use std::io::prelude::*; use std::io::stdout; use std::panic; use std::thread; use std::time::Duration; use usb_device::device::CONFIGURATION_VALUE; fn main() { let tests = get_tests(); run_tests(&tests[..]); } fn run_tests(tests: &[(&str, TestFn)]) { const INTERFACE: u8 = 0; println!("test_class_host starting"); println!("looking for device..."); let ctx = rusb::Context::new().expect("create libusb context"); // Look for the device for about 5 seconds in case it hasn't finished enumerating yet let mut dev = Err(rusb::Error::NoDevice); for _ in 0..50 { dev = open_device(&ctx); if dev.is_ok() { break; } thread::sleep(Duration::from_millis(100)); } let mut dev = match dev { Ok(d) => d, Err(err) => { println!("Did not find a TestClass device. Make sure the device is correctly programmed and plugged in. Last error: {}", err); return; } }; println!("\nrunning {} tests", tests.len()); let mut success = 0; for (name, test) in tests { if let Err(err) = dev.reset() { println!("Failed to reset the device: {}", err); return; } if let Err(err) = dev.set_active_configuration(CONFIGURATION_VALUE) { println!("Failed to set active configuration: {}", err); return; } if let Err(err) = dev.claim_interface(INTERFACE) { println!("Failed to claim interface: {}", err); return; } print!("test {} ... ", name); let _ = stdout().flush(); let mut out = String::new(); let res = { let hook = panic::take_hook(); panic::set_hook(Box::new(|_| {})); let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { test(&mut dev, &mut out); })); panic::set_hook(hook); res }; dev.release_interface(INTERFACE) .expect("failed to release interface"); if let Err(err) = res { let err = if let Some(err) = err.downcast_ref::<&'static str>() { String::from(*err) } else if let Some(err) = err.downcast_ref::() { err.clone() } else { String::from("???") }; println!("FAILED\nerror: {}\n", err); } else { println!("ok"); if !out.is_empty() { print!("{}", out); } success += 1; } } println!("{} failed, {} succeeded", tests.len() - success, success); if success == tests.len() { println!("\nALL TESTS PASSED!"); } else { std::process::exit(1); } }