From ddc4b95b8de7cdf5eba9043ae5d25fdd11e56fac Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 31 Oct 2026 17:15:39 -0700 Subject: [PATCH] test(komorebic-core): the commands of the e2e sweep are commands of the command lines The commands e2e scenario learns that a command does not exist in a platform only by running it in a guest (error: unrecognized subcommand, skipped with its name), about 7.6 minutes per Windows run. crates/komorebic-core/tests/e2e_sweep.rs reads SWEEP and PRINTED out of e2e/lib/komorebi_vm/core/scenarios/commands.py (skipped when the e2e library is not in the source tree) and parses each line with the platform's clap command: every one is a command of the Windows komorebic, and the macOS one lacks exactly the eight the scenario would skip there (focus-follows-mouse enable/disable, the Windows implementation of toggle-focus-follows-mouse, toggle-maximize, the transparency commands). 3 tests. mirrors: commands / (the command is understood, for the command line only). Stays e2e only: that the daemon then answers; the KDE komorebic's own command set. Verified: cargo test -p komorebic-core --test e2e_sweep, 3 passed (native Linux; platform independent). No source change. --- crates/komorebic-core/tests/e2e_sweep.rs | 122 +++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 crates/komorebic-core/tests/e2e_sweep.rs diff --git a/crates/komorebic-core/tests/e2e_sweep.rs b/crates/komorebic-core/tests/e2e_sweep.rs new file mode 100644 index 00000000..17aeb36e --- /dev/null +++ b/crates/komorebic-core/tests/e2e_sweep.rs @@ -0,0 +1,122 @@ +//! The commands the `commands` end-to-end scenario sweeps (`SWEEP` and `PRINTED` in +//! `e2e/lib/komorebi_vm/core/scenarios/commands.py`) are commands of the platforms' `komorebic`. +//! +//! The scenario only learns that a command is not one when it runs it in a guest (`error: +//! unrecognized subcommand`, skipped with its name). Here the command lines are parsed with the +//! platform's clap command, so a command that a platform lost, or a typo in the scenario, fails a +//! native test and not a 7 minute guest run. +//! +//! mirrors: commands / (the part "the command is understood: exit status 0", for the +//! command line only; what the daemon does with it is the daemon's tests, see +//! `komorebi-for-kde/komorebi/tests/command_sweep.rs`) + +use komorebic_core::cli::Meta; +use komorebic_core::cli::command; +use komorebic_core::platform::macos::MacosCommands; +use komorebic_core::platform::windows::WindowsCommands; +use std::path::Path; + +const META: Meta = Meta { + name: "komorebic", + about: "", + author: "", + version: "", +}; + +/// The strings of the tuple named `name` in the scenario, or `None` without the e2e library (a +/// source tree that is only the crates, as the nix build of one daemon has). +fn tuple(name: &str) -> Option> { + let path = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../../e2e/lib/komorebi_vm/core/scenarios/commands.py"); + let source = std::fs::read_to_string(path).ok()?; + let start = source.find(&format!("{name}: tuple[str, ...] = ("))?; + let body = &source[start..]; + let end = body.find("\n)")?; + Some( + body[..end] + .lines() + .filter_map(|line| { + let line = line.trim(); + line.strip_prefix('"')? + .strip_suffix("\",") + .map(str::to_string) + }) + .collect(), + ) +} + +fn parses(cli: &clap::Command, line: &str) -> Result<(), String> { + let mut args = vec!["komorebic".to_string()]; + args.extend( + line.replace("{config}", "/tmp/komorebi.json") + .split_whitespace() + .map(str::to_string), + ); + cli.clone() + .try_get_matches_from(args) + .map(|_| ()) + .map_err(|e| e.to_string().lines().next().unwrap_or_default().to_string()) +} + +fn lines() -> Option> { + let mut lines = tuple("SWEEP")?; + lines.extend(tuple("PRINTED")?); + Some(lines) +} + +#[test] +fn the_sweep_was_read() { + if let Some(lines) = lines() { + assert!(lines.len() > 200, "{} lines", lines.len()); + assert!(lines.iter().any(|l| l == "focus left")); + assert!(lines.iter().any(|l| l == "state")); + } +} + +#[test] +fn every_command_of_the_sweep_is_a_command_of_the_windows_komorebic() { + let Some(lines) = lines() else { return }; + let cli = command::(&META); + let missing: Vec<_> = lines + .iter() + .filter_map(|l| parses(&cli, l).err().map(|e| format!("{l}: {e}"))) + .collect(); + assert!(missing.is_empty(), "{missing:#?}"); +} + +#[test] +fn the_sweep_commands_the_macos_komorebic_lacks_are_the_known_eight() { + let Some(lines) = lines() else { return }; + let cli = command::(&META); + let mut missing: Vec<_> = lines + .iter() + .filter_map(|l| parses(&cli, l).err().map(|_| l.clone())) + .collect(); + missing.sort(); + missing.dedup(); + // what the macOS command line lacks of the sweep, as of this writing: the scenario skips + // these there (focus follows mouse by the Windows implementation, transparency, maximize) + assert_eq!( + missing, + [ + "focus-follows-mouse disable", + "focus-follows-mouse enable", + "toggle-focus-follows-mouse --implementation windows", + "toggle-maximize", + "toggle-transparency", + "transparency disable", + "transparency enable", + "transparency-alpha 150", + ] + ); + // a command that every platform must have (the sweep's first lines) is one of macOS too + for line in [ + "focus left", + "move right", + "retile", + "toggle-float", + "state", + ] { + assert!(!missing.iter().any(|m| m == line), "{line}"); + } +}