From c9f8325da90cfedb138e6de95ef555bb9a0d5930 Mon Sep 17 00:00:00 2001 From: raven <7156279+RavenX8@users.noreply.github.com> Date: Thu, 10 Apr 2025 13:44:35 -0400 Subject: [PATCH] Add unit tests for core components --- Cargo.lock | 92 +++++++++++++------- Cargo.toml | 11 +++ src/lib.rs | 78 +++++++++++++++++ tests/basic_tests.rs | 197 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 348 insertions(+), 30 deletions(-) create mode 100644 src/lib.rs create mode 100644 tests/basic_tests.rs diff --git a/Cargo.lock b/Cargo.lock index 875b7ea..6d88efc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -377,7 +377,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -412,7 +412,7 @@ checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -565,7 +565,7 @@ checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -701,7 +701,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -889,7 +889,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -1073,7 +1073,7 @@ checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -1228,7 +1228,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -1279,7 +1279,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -1682,7 +1682,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -1937,6 +1937,26 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mock-it" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c79f6245a4564f117ae4e640a829a7b425e641ca3e6ea279d74a9caf05d2daf" +dependencies = [ + "mock-it_codegen", +] + +[[package]] +name = "mock-it_codegen" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a887ee7c909093b773c59ee57412f0fd29d2f262905eeea721cfc31a38e18f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "naga" version = "23.1.0" @@ -2043,7 +2063,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -2370,7 +2390,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -2401,7 +2421,7 @@ checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -2704,7 +2724,7 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -2727,7 +2747,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -2764,6 +2784,7 @@ dependencies = [ "fast_config", "hidapi", "log", + "mock-it", "serde", ] @@ -2890,6 +2911,17 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.96" @@ -2909,7 +2941,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -2961,7 +2993,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -2972,7 +3004,7 @@ checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -3046,7 +3078,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -3193,7 +3225,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.96", "wasm-bindgen-shared", ] @@ -3228,7 +3260,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3560,7 +3592,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -3571,7 +3603,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -3979,7 +4011,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", "synstructure", ] @@ -4039,7 +4071,7 @@ checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", "zbus-lockstep", "zbus_xml", "zvariant", @@ -4054,7 +4086,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.96", "zvariant_utils", ] @@ -4100,7 +4132,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -4120,7 +4152,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", "synstructure", ] @@ -4143,7 +4175,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] [[package]] @@ -4168,7 +4200,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.96", "zvariant_utils", ] @@ -4180,5 +4212,5 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.96", ] diff --git a/Cargo.toml b/Cargo.toml index 8956bd3..bdfc920 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,14 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[[bin]] +name = "shift_tool" +path = "src/main.rs" + +[lib] +name = "vpc_shift_tool" +path = "src/lib.rs" + [dependencies] clap = { version = "4.5.4", features = ["derive"] } eframe = "0.30.0" @@ -21,3 +29,6 @@ chrono = "0.4.40" logging = [] default = ["logging"] + +[dev-dependencies] +mock-it = "0.9.0" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..15ae16e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,78 @@ +// Export modules for testing +pub mod about; +pub mod config; +pub mod device; +pub mod hid_worker; +pub mod state; +pub mod ui; +pub mod util; + +// Re-export main struct and types for testing +pub use crate::config::ConfigData; +pub use crate::device::VpcDevice; +pub use crate::state::State; + +// Constants +pub const PROGRAM_TITLE: &str = "OpenVPC - Shift Tool"; +pub const INITIAL_WIDTH: f32 = 740.0; +pub const INITIAL_HEIGHT: f32 = 260.0; + +// Type aliases for shared state +pub use std::sync::{Arc, Condvar, Mutex}; +pub type SharedStateFlag = Arc<(Mutex, Condvar)>; +pub type SharedDeviceState = Arc>; + +// Args struct for command line parsing +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +pub struct Args { + #[arg(short, long, default_value_t = false)] + pub skip_firmware: bool, +} + +// Wrapper for ConfigData to match the actual structure +pub use fast_config::Config; + +// The main application struct +pub struct ShiftTool { + // State + pub state: State, + pub thread_state: SharedStateFlag, // Is the worker thread running? + + // Device Data + pub device_list: Vec, // List of discovered compatible devices + + // Shared state between UI and Worker Thread + pub shift_state: SharedDeviceState, // Current shift state + pub source_states: Vec, // Current state of each source device + pub receiver_states: Vec, // Current state of each receiver device + + // Configuration + pub config: Config, + pub selected_source: usize, + pub selected_receiver: usize, +} + +// Implementations for ShiftTool +impl ShiftTool { + // Add a new source state tracking object + pub fn add_source_state(&mut self) { + self.source_states.push(Arc::new(Mutex::new(0))); + } + + // Add a new receiver state tracking object + pub fn add_receiver_state(&mut self) { + self.receiver_states.push(Arc::new(Mutex::new(0))); + } + + // Get the current thread status + pub fn get_thread_status(&self) -> bool { + let &(ref lock, _) = &*self.thread_state; + match lock.lock() { + Ok(guard) => *guard, + Err(_) => false, // Return false if the mutex is poisoned + } + } +} diff --git a/tests/basic_tests.rs b/tests/basic_tests.rs new file mode 100644 index 0000000..941e1de --- /dev/null +++ b/tests/basic_tests.rs @@ -0,0 +1,197 @@ +use vpc_shift_tool::config::{ConfigData, ShiftModifiers, ModifiersArray}; +use vpc_shift_tool::device::{SavedDevice, VpcDevice}; +use vpc_shift_tool::state::State; +use std::rc::Rc; + +#[test] +fn test_config_data_default() { + // Test that the default ConfigData is created correctly + let config = ConfigData::default(); + + // Check that sources and receivers are empty + assert_eq!(config.sources.len(), 0); + assert_eq!(config.receivers.len(), 0); + + // Check that shift_modifiers has the default value (all OR) + for i in 0..8 { + assert_eq!(config.shift_modifiers[i], ShiftModifiers::OR); + } +} + +#[test] +fn test_shift_modifiers_display() { + // Test the Display implementation for ShiftModifiers + assert_eq!(format!("{}", ShiftModifiers::OR), "OR"); + assert_eq!(format!("{}", ShiftModifiers::AND), "AND"); + assert_eq!(format!("{}", ShiftModifiers::XOR), "XOR"); +} + +#[test] +fn test_saved_device_default() { + // Test that the default SavedDevice is created correctly + let device = SavedDevice::default(); + + assert_eq!(device.vendor_id, 0); + assert_eq!(device.product_id, 0); + assert_eq!(device.serial_number, ""); + assert_eq!(device.state_enabled, [true; 8]); // All bits enabled by default +} + +#[test] +fn test_state_enum() { + // Test that the State enum has the expected variants + let initializing = State::Initialising; + let about = State::About; + let running = State::Running; + + // Test that the variants are different + assert_ne!(initializing, about); + assert_ne!(initializing, running); + assert_ne!(about, running); + + // Test equality with same variant + assert_eq!(initializing, State::Initialising); + assert_eq!(about, State::About); + assert_eq!(running, State::Running); +} + +#[test] +fn test_config_with_devices() { + // Test creating a ConfigData with sources and receivers + let mut config = ConfigData::default(); + + // Create some test devices + let device1 = SavedDevice { + vendor_id: 0x3344, + product_id: 0x0001, + serial_number: "123456".to_string(), + state_enabled: [true, false, true, false, true, false, true, false], + }; + + let device2 = SavedDevice { + vendor_id: 0x3344, + product_id: 0x0002, + serial_number: "654321".to_string(), + state_enabled: [false, true, false, true, false, true, false, true], + }; + + // Add devices to sources and receivers + config.sources.push(device1.clone()); + config.receivers.push(device2.clone()); + + // Check that the devices were added correctly + assert_eq!(config.sources.len(), 1); + assert_eq!(config.receivers.len(), 1); + + assert_eq!(config.sources[0].vendor_id, 0x3344); + assert_eq!(config.sources[0].product_id, 0x0001); + assert_eq!(config.sources[0].serial_number, "123456"); + assert_eq!(config.sources[0].state_enabled, [true, false, true, false, true, false, true, false]); + + assert_eq!(config.receivers[0].vendor_id, 0x3344); + assert_eq!(config.receivers[0].product_id, 0x0002); + assert_eq!(config.receivers[0].serial_number, "654321"); + assert_eq!(config.receivers[0].state_enabled, [false, true, false, true, false, true, false, true]); +} + +#[test] +fn test_modifiers_array() { + // Test the ModifiersArray implementation + let mut modifiers = ModifiersArray::default(); + + // Check default values + for i in 0..8 { + assert_eq!(modifiers[i], ShiftModifiers::OR); + } + + // Test setting values + modifiers[0] = ShiftModifiers::AND; + modifiers[4] = ShiftModifiers::XOR; + + // Check the modified values + assert_eq!(modifiers[0], ShiftModifiers::AND); + assert_eq!(modifiers[4], ShiftModifiers::XOR); + + // Check that other values remain unchanged + for i in 1..4 { + assert_eq!(modifiers[i], ShiftModifiers::OR); + } + for i in 5..8 { + assert_eq!(modifiers[i], ShiftModifiers::OR); + } +} + +#[test] +fn test_vpc_device_default() { + // Test the default VpcDevice implementation + let device = VpcDevice::default(); + + assert_eq!(device.full_name, ""); + assert_eq!(*device.name, "-NO CONNECTION (Select device from list)-"); + assert_eq!(*device.firmware, ""); + assert_eq!(device.vendor_id, 0); + assert_eq!(device.product_id, 0); + assert_eq!(device.serial_number, ""); + assert_eq!(device.usage, 0); + assert_eq!(device.active, false); +} + +#[test] +fn test_vpc_device_display() { + // Test the Display implementation for VpcDevice + + // Test default device + let device = VpcDevice::default(); + assert_eq!(format!("{}", device), "-NO CONNECTION (Select device from list)-"); + + // Test a real device + let device = VpcDevice { + full_name: "3344:0001:123456".to_string(), + name: Rc::new("VPC MongoosT-50CM3".to_string()), + firmware: Rc::new("VIRPIL Controls 20240101".to_string()), + vendor_id: 0x3344, + product_id: 0x0001, + serial_number: "123456".to_string(), + usage: 0, + active: false, + }; + + assert_eq!( + format!("{}", device), + "VID:3344 PID:0001 VPC MongoosT-50CM3 (SN:123456 FW:VIRPIL Controls 20240101)" + ); + + // Test a device with empty serial number + let device = VpcDevice { + full_name: "3344:0001:no_sn".to_string(), + name: Rc::new("VPC MongoosT-50CM3".to_string()), + firmware: Rc::new("VIRPIL Controls 20240101".to_string()), + vendor_id: 0x3344, + product_id: 0x0001, + serial_number: "".to_string(), + usage: 0, + active: false, + }; + + assert_eq!( + format!("{}", device), + "VID:3344 PID:0001 VPC MongoosT-50CM3 (SN:N/A FW:VIRPIL Controls 20240101)" + ); + + // Test a device with empty firmware + let device = VpcDevice { + full_name: "3344:0001:123456".to_string(), + name: Rc::new("VPC MongoosT-50CM3".to_string()), + firmware: Rc::new("".to_string()), + vendor_id: 0x3344, + product_id: 0x0001, + serial_number: "123456".to_string(), + usage: 0, + active: false, + }; + + assert_eq!( + format!("{}", device), + "VID:3344 PID:0001 VPC MongoosT-50CM3 (SN:123456 FW:N/A)" + ); +}