From c3d5438f84aff252d636ed3f75fd32e0f25b683c Mon Sep 17 00:00:00 2001 From: multiplex55 <6619098+multiplex55@users.noreply.github.com> Date: Sat, 7 Feb 2026 11:06:23 -0500 Subject: [PATCH 1/2] Enforce dependency floor versions for time and bytes --- Cargo.lock | 46 +++++++----- Cargo.toml | 2 + README.md | 1 + tests/dependency_floor_guard.rs | 129 ++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 17 deletions(-) create mode 100644 tests/dependency_floor_guard.rs diff --git a/Cargo.lock b/Cargo.lock index 64f13a1b..8b207cb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -762,9 +762,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "calloop" @@ -1307,9 +1307,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -3139,6 +3139,7 @@ dependencies = [ "anyhow", "arboard", "base64", + "bytes", "chrono", "criterion", "dirs-next", @@ -3178,6 +3179,7 @@ dependencies = [ "slug", "sysinfo", "tempfile", + "time", "tracing", "tracing-appender", "tracing-subscriber", @@ -3353,9 +3355,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-derive" @@ -4453,18 +4455,28 @@ checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -4889,30 +4901,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", diff --git a/Cargo.toml b/Cargo.toml index c362edca..9a5bc024 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,8 @@ slab = "0.4.11" rdev = { git = "https://github.com/Narsil/rdev", rev = "c14f2dc5c8100a96c5d7e3013de59d6aa0b9eae2", features = ["x11"] } rodio = { version = "0.17", default-features = false, features = ["wav"] } ab_glyph = "0.2" +time = ">=0.3.47, <0.4" +bytes = ">=1.11.1, <2" [features] unstable_grab = ["rdev/unstable_grab"] diff --git a/README.md b/README.md index 94ee4a8c..9ae49d88 100644 --- a/README.md +++ b/README.md @@ -447,6 +447,7 @@ cargo build --release * The project uses `rdev` and may require the `unstable_grab` feature for global input capture in some environments. * Some plugins depend on Windows-specific APIs (window management, browser tab activation, etc.). +* Dependency lockfile minimums are enforced by tests. Run `cargo test --test dependency_floor_guard` to validate `time` and `bytes` floor versions in `Cargo.lock`. --- diff --git a/tests/dependency_floor_guard.rs b/tests/dependency_floor_guard.rs new file mode 100644 index 00000000..3cc79be6 --- /dev/null +++ b/tests/dependency_floor_guard.rs @@ -0,0 +1,129 @@ +use std::collections::BTreeSet; +use std::fs; +use std::path::Path; + +#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +struct SemVer { + major: u64, + minor: u64, + patch: u64, +} + +impl SemVer { + fn parse(version: &str) -> Self { + let mut parts = version.split('.'); + + let major = parts + .next() + .unwrap_or("") + .parse::() + .unwrap_or_else(|_| panic!("malformed semver '{version}': invalid major component")); + let minor = parts + .next() + .unwrap_or("") + .parse::() + .unwrap_or_else(|_| panic!("malformed semver '{version}': invalid minor component")); + let patch = parts + .next() + .unwrap_or("") + .parse::() + .unwrap_or_else(|_| panic!("malformed semver '{version}': invalid patch component")); + + assert!( + parts.next().is_none(), + "malformed semver '{version}': expected exactly 3 numeric components" + ); + + Self { + major, + minor, + patch, + } + } +} + +fn extract_package_versions(lockfile: &str, crate_name: &str) -> Vec { + let mut versions = Vec::new(); + let mut in_package = false; + let mut current_name: Option<&str> = None; + + for line in lockfile.lines() { + let trimmed = line.trim(); + if trimmed == "[[package]]" { + in_package = true; + current_name = None; + continue; + } + + if !in_package { + continue; + } + + if let Some(name) = trimmed.strip_prefix("name = \"").and_then(|s| s.strip_suffix('"')) { + current_name = Some(name); + continue; + } + + if let Some(version) = trimmed + .strip_prefix("version = \"") + .and_then(|s| s.strip_suffix('"')) + { + if current_name == Some(crate_name) { + versions.push(version.to_string()); + } + in_package = false; + current_name = None; + } + } + + versions +} + +fn assert_floor(lockfile: &str, crate_name: &str, min_version: &str) { + let versions = extract_package_versions(lockfile, crate_name); + assert!( + !versions.is_empty(), + "crate '{crate_name}' not found in Cargo.lock" + ); + + let unique_versions: BTreeSet<_> = versions.iter().cloned().collect(); + assert_eq!( + unique_versions.len(), + 1, + "crate '{crate_name}' appears with multiple versions in Cargo.lock: {:?}", + unique_versions + ); + + let detected = SemVer::parse(unique_versions.iter().next().expect("set is non-empty")); + let minimum = SemVer::parse(min_version); + assert!( + detected >= minimum, + "crate '{crate_name}' resolved to version {} but minimum required is {min_version}", + unique_versions.iter().next().expect("set is non-empty") + ); +} + +#[test] +fn lockfile_enforces_dependency_floors() { + let lockfile_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.lock"); + let lockfile = fs::read_to_string(&lockfile_path) + .unwrap_or_else(|e| panic!("failed to read {}: {e}", lockfile_path.display())); + + assert_floor(&lockfile, "time", "0.3.47"); + assert_floor(&lockfile, "bytes", "1.11.1"); +} + +#[test] +fn semver_helper_equal() { + assert_eq!(SemVer::parse("1.2.3"), SemVer::parse("1.2.3")); +} + +#[test] +fn semver_helper_greater() { + assert!(SemVer::parse("1.2.4") > SemVer::parse("1.2.3")); +} + +#[test] +fn semver_helper_less() { + assert!(SemVer::parse("1.2.2") < SemVer::parse("1.2.3")); +} From f99312ccfe6a4b060d656c3b8ee8742acdfe5097 Mon Sep 17 00:00:00 2001 From: multiplex55 <6619098+multiplex55@users.noreply.github.com> Date: Sat, 7 Feb 2026 11:49:11 -0500 Subject: [PATCH 2/2] Remove dependency floor guard test --- README.md | 1 - tests/dependency_floor_guard.rs | 129 -------------------------------- 2 files changed, 130 deletions(-) delete mode 100644 tests/dependency_floor_guard.rs diff --git a/README.md b/README.md index 9ae49d88..94ee4a8c 100644 --- a/README.md +++ b/README.md @@ -447,7 +447,6 @@ cargo build --release * The project uses `rdev` and may require the `unstable_grab` feature for global input capture in some environments. * Some plugins depend on Windows-specific APIs (window management, browser tab activation, etc.). -* Dependency lockfile minimums are enforced by tests. Run `cargo test --test dependency_floor_guard` to validate `time` and `bytes` floor versions in `Cargo.lock`. --- diff --git a/tests/dependency_floor_guard.rs b/tests/dependency_floor_guard.rs deleted file mode 100644 index 3cc79be6..00000000 --- a/tests/dependency_floor_guard.rs +++ /dev/null @@ -1,129 +0,0 @@ -use std::collections::BTreeSet; -use std::fs; -use std::path::Path; - -#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] -struct SemVer { - major: u64, - minor: u64, - patch: u64, -} - -impl SemVer { - fn parse(version: &str) -> Self { - let mut parts = version.split('.'); - - let major = parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or_else(|_| panic!("malformed semver '{version}': invalid major component")); - let minor = parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or_else(|_| panic!("malformed semver '{version}': invalid minor component")); - let patch = parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or_else(|_| panic!("malformed semver '{version}': invalid patch component")); - - assert!( - parts.next().is_none(), - "malformed semver '{version}': expected exactly 3 numeric components" - ); - - Self { - major, - minor, - patch, - } - } -} - -fn extract_package_versions(lockfile: &str, crate_name: &str) -> Vec { - let mut versions = Vec::new(); - let mut in_package = false; - let mut current_name: Option<&str> = None; - - for line in lockfile.lines() { - let trimmed = line.trim(); - if trimmed == "[[package]]" { - in_package = true; - current_name = None; - continue; - } - - if !in_package { - continue; - } - - if let Some(name) = trimmed.strip_prefix("name = \"").and_then(|s| s.strip_suffix('"')) { - current_name = Some(name); - continue; - } - - if let Some(version) = trimmed - .strip_prefix("version = \"") - .and_then(|s| s.strip_suffix('"')) - { - if current_name == Some(crate_name) { - versions.push(version.to_string()); - } - in_package = false; - current_name = None; - } - } - - versions -} - -fn assert_floor(lockfile: &str, crate_name: &str, min_version: &str) { - let versions = extract_package_versions(lockfile, crate_name); - assert!( - !versions.is_empty(), - "crate '{crate_name}' not found in Cargo.lock" - ); - - let unique_versions: BTreeSet<_> = versions.iter().cloned().collect(); - assert_eq!( - unique_versions.len(), - 1, - "crate '{crate_name}' appears with multiple versions in Cargo.lock: {:?}", - unique_versions - ); - - let detected = SemVer::parse(unique_versions.iter().next().expect("set is non-empty")); - let minimum = SemVer::parse(min_version); - assert!( - detected >= minimum, - "crate '{crate_name}' resolved to version {} but minimum required is {min_version}", - unique_versions.iter().next().expect("set is non-empty") - ); -} - -#[test] -fn lockfile_enforces_dependency_floors() { - let lockfile_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.lock"); - let lockfile = fs::read_to_string(&lockfile_path) - .unwrap_or_else(|e| panic!("failed to read {}: {e}", lockfile_path.display())); - - assert_floor(&lockfile, "time", "0.3.47"); - assert_floor(&lockfile, "bytes", "1.11.1"); -} - -#[test] -fn semver_helper_equal() { - assert_eq!(SemVer::parse("1.2.3"), SemVer::parse("1.2.3")); -} - -#[test] -fn semver_helper_greater() { - assert!(SemVer::parse("1.2.4") > SemVer::parse("1.2.3")); -} - -#[test] -fn semver_helper_less() { - assert!(SemVer::parse("1.2.2") < SemVer::parse("1.2.3")); -}