From 74ceef6a70a497bd5996be74169bb0f74e60721e Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Sat, 20 Jun 2026 22:59:42 +0700 Subject: [PATCH] test(cli): add unit and integration tests for applet dispatching --- crates/irtt-cli/src/applet.rs | 54 ++++++++-- crates/irtt-cli/tests/applet_dispatch.rs | 122 +++++++++++++++++++++++ 2 files changed, 169 insertions(+), 7 deletions(-) create mode 100644 crates/irtt-cli/tests/applet_dispatch.rs diff --git a/crates/irtt-cli/src/applet.rs b/crates/irtt-cli/src/applet.rs index 9e3d573..832ba4e 100644 --- a/crates/irtt-cli/src/applet.rs +++ b/crates/irtt-cli/src/applet.rs @@ -120,18 +120,58 @@ mod tests { } #[test] - fn default_applet_prefers_client_then_tui() { + fn canonical_help_renders_dispatcher_help() { + let dispatch = dispatch_from_argv(vec!["irtt-rs".into(), "--help".into()]).unwrap(); + let AppletDispatch::Help(help) = dispatch else { + panic!("expected dispatcher help"); + }; + assert!(help.contains("IRTT-compatible multi-applet dispatcher")); + assert!(help.contains("client")); + assert!(help.contains("tui")); + assert!(help.contains("server")); + } + + #[test] + fn canonical_without_applet_is_an_error() { + let err = dispatch_from_argv(vec!["irtt-rs".into()]).unwrap_err(); + assert!(err.contains("choose an applet")); + assert!(err.contains("client")); + assert!(err.contains("tui")); + assert!(err.contains("server")); + } + + #[test] + fn canonical_subcommands_dispatch_to_applet_argv() { assert_eq!( - default_applet_for_features(true, true, false), - AppletAvailability::Client + dispatch_from_argv(vec!["irtt-rs".into(), "client".into(), "host:2112".into()]) + .unwrap(), + AppletDispatch::Run { + applet: RequestedApplet::Client, + argv: vec!["irtt-cli".into(), "host:2112".into()], + } ); assert_eq!( - default_applet_for_features(false, true, false), - AppletAvailability::Tui + dispatch_from_argv(vec!["irtt-rs".into(), "tui".into(), "host:2112".into()]).unwrap(), + AppletDispatch::Run { + applet: RequestedApplet::Tui, + argv: vec!["irtt-tui".into(), "host:2112".into()], + } ); assert_eq!( - default_applet_for_features(false, false, false), - AppletAvailability::None + dispatch_from_argv(vec!["irtt-rs".into(), "server".into()]).unwrap(), + AppletDispatch::Run { + applet: RequestedApplet::Server, + argv: vec!["irtt-server".into()], + } ); } + + #[test] + fn unknown_irtt_binary_name_is_an_error() { + let err = dispatch_from_argv(vec!["/usr/bin/irtt-typo".into()]).unwrap_err(); + assert!(err.contains("unknown applet name 'irtt-typo'")); + assert!(err.contains("irtt-cli")); + assert!(err.contains("irtt-tui")); + assert!(err.contains("irtt-server")); + } } diff --git a/crates/irtt-cli/tests/applet_dispatch.rs b/crates/irtt-cli/tests/applet_dispatch.rs new file mode 100644 index 0000000..2e8e207 --- /dev/null +++ b/crates/irtt-cli/tests/applet_dispatch.rs @@ -0,0 +1,122 @@ +use std::process::{Command, Output}; + +fn irtt_rs() -> Command { + Command::new(env!("CARGO_BIN_EXE_irtt-rs")) +} + +#[cfg(unix)] +fn irtt_rs_with_arg0(arg0: &str) -> Command { + use std::os::unix::process::CommandExt; + + let mut command = irtt_rs(); + command.arg0(arg0); + command +} + +fn output_text(output: &Output) -> String { + let mut text = String::new(); + text.push_str(&String::from_utf8_lossy(&output.stdout)); + text.push_str(&String::from_utf8_lossy(&output.stderr)); + text +} + +#[test] +fn canonical_help_shows_dispatcher_help() { + let output = irtt_rs().arg("--help").output().unwrap(); + let text = output_text(&output); + + assert!(output.status.success(), "{text}"); + assert!(text.contains("IRTT-compatible multi-applet dispatcher")); + assert!(text.contains("client")); + assert!(text.contains("tui")); + assert!(text.contains("server")); +} + +#[test] +fn canonical_without_applet_errors() { + let output = irtt_rs().output().unwrap(); + let text = output_text(&output); + + assert!(!output.status.success()); + assert!(text.contains("choose an applet"), "{text}"); + assert!(text.contains("client")); + assert!(text.contains("tui")); + assert!(text.contains("server")); +} + +#[test] +fn canonical_client_subcommand_dispatches_to_client() { + let output = irtt_rs().args(["client", "--help"]).output().unwrap(); + let text = output_text(&output); + + assert!(output.status.success(), "{text}"); + assert!(text.contains("Minimal IRTT-compatible stream client")); + assert!(text.contains("--output ")); +} + +#[cfg(unix)] +#[test] +fn client_applet_name_dispatches_to_client() { + let output = irtt_rs_with_arg0("irtt-cli") + .arg("--help") + .output() + .unwrap(); + let text = output_text(&output); + + assert!(output.status.success(), "{text}"); + assert!(text.contains("Minimal IRTT-compatible stream client")); + assert!(text.contains("--output ")); +} + +#[cfg(all(unix, feature = "tui"))] +#[test] +fn tui_applet_name_dispatches_to_tui_when_enabled() { + let output = irtt_rs_with_arg0("irtt-tui") + .arg("--help") + .output() + .unwrap(); + let text = output_text(&output); + + assert!(output.status.success(), "{text}"); + assert!(text.contains("Minimal IRTT-compatible TUI client")); + assert!(text.contains("--duration ")); +} + +#[cfg(all(unix, not(feature = "tui")))] +#[test] +fn tui_applet_name_reports_unavailable_when_disabled() { + let output = irtt_rs_with_arg0("irtt-tui") + .arg("--help") + .output() + .unwrap(); + let text = output_text(&output); + + assert!(!output.status.success()); + assert!(text.contains("TUI applet is not available"), "{text}"); +} + +#[cfg(unix)] +#[test] +fn server_applet_name_reports_unavailable() { + let output = irtt_rs_with_arg0("irtt-server") + .arg("--help") + .output() + .unwrap(); + let text = output_text(&output); + + assert!(!output.status.success()); + assert!(text.contains("server applet is not available"), "{text}"); +} + +#[cfg(unix)] +#[test] +fn unknown_irtt_applet_name_errors() { + let output = irtt_rs_with_arg0("irtt-typo").output().unwrap(); + let text = output_text(&output); + + assert!(!output.status.success()); + assert!(text.contains("unknown applet name 'irtt-typo'"), "{text}"); + assert!(text.contains("irtt-cli")); + assert!(text.contains("irtt-tui")); + assert!(text.contains("irtt-server")); +}