use assert_cmd::Command;
use predicates::prelude::*;
use std::process::Command as StdCommand;
#[cfg(test)]
mod cli_compatibility_tests {
use super::*;
#[test]
fn test_existing_cli_options_still_work() {
let test_cases = vec![
vec!["--size", "100", "--distribution", "reversed"],
vec!["--size", "50", "--distribution", "shuffled"],
vec!["--size", "200", "--distribution", "nearly-sorted"],
vec!["--size", "25", "--distribution", "few-unique"],
vec!["--fair", "comp", "--budget", "16"],
vec!["--fair", "weighted", "--alpha", "2.0", "--beta", "0.5"],
vec!["--fair", "walltime"],
vec!["--fair", "adaptive", "--learning-rate", "0.3"],
vec!["--size", "100", "--distribution", "reversed", "--fair", "comp", "--budget", "8"],
vec!["--size", "500", "--fair", "weighted", "--alpha", "1.5", "--beta", "1.0"],
vec!["--size", "50", "--distribution", "few-unique", "--fair", "walltime"],
];
for args in test_cases {
let mut cmd = Command::cargo_bin("sorting-race").unwrap();
let assertion = cmd
.args(&args)
.timeout(std::time::Duration::from_secs(10))
.assert();
assertion
.success()
.stdout(predicate::str::contains("Race completed"))
.stdout(predicate::str::contains("Winner:"));
}
}
#[test]
fn test_cli_help_output_includes_new_options() {
let mut cmd = Command::cargo_bin("sorting-race").unwrap();
let assertion = cmd.arg("--help").assert();
assertion
.success()
.stdout(predicate::str::contains("--size"))
.stdout(predicate::str::contains("--distribution"))
.stdout(predicate::str::contains("--fair"))
.stdout(predicate::str::contains("--budget"))
.stdout(predicate::str::contains("--alpha"))
.stdout(predicate::str::contains("--beta"))
.stdout(predicate::str::contains("--learning-rate"))
.stdout(predicate::str::contains("interactive").or(predicate::str::contains("Interactive")));
}
#[test]
fn test_cli_without_args_launches_interactive_mode() {
let mut cmd = Command::cargo_bin("sorting-race").unwrap();
let assertion = cmd
.timeout(std::time::Duration::from_secs(5))
.assert();
assertion
.success()
.stdout(predicate::str::contains("Configuration").or(
predicate::str::contains("Interactive").or(
predicate::str::contains("Press")
)
));
}
#[test]
fn test_cli_error_handling_preserved() {
let error_test_cases = vec![
vec!["--size", "0"],
vec!["--size", "-1"],
vec!["--size", "abc"],
vec!["--size", "10000"],
vec!["--distribution", "invalid"],
vec!["--distribution", "random"],
vec!["--fair", "comp"], vec!["--fair", "weighted"], vec!["--fair", "adaptive"], vec!["--fair", "invalid"],
vec!["--fair", "comp", "--budget", "0"],
vec!["--fair", "comp", "--budget", "-5"],
vec!["--fair", "weighted", "--alpha", "-1", "--beta", "0.5"],
vec!["--fair", "adaptive", "--learning-rate", "0"], vec!["--fair", "adaptive", "--learning-rate", "2.0"], ];
for args in error_test_cases {
let mut cmd = Command::cargo_bin("sorting-race").unwrap();
let assertion = cmd
.args(&args)
.timeout(std::time::Duration::from_secs(5))
.assert();
assertion
.failure()
.stderr(predicate::str::contains("error").or(
predicate::str::contains("Error").or(
predicate::str::contains("invalid")
)
));
}
}
#[test]
fn test_cli_output_format_unchanged() {
let mut cmd = Command::cargo_bin("sorting-race").unwrap();
let assertion = cmd
.args(&["--size", "50", "--fair", "walltime"])
.timeout(std::time::Duration::from_secs(10))
.assert();
assertion
.success()
.stdout(predicate::str::contains("Array size:"))
.stdout(predicate::str::contains("Distribution:"))
.stdout(predicate::str::contains("Fairness mode:"))
.stdout(predicate::str::contains("algorithms"))
.stdout(predicate::str::contains("Race completed"))
.stdout(predicate::str::contains("Winner:"))
.stdout(predicate::str::contains("KB").or(predicate::str::contains("MB")).or(predicate::str::contains("B")));
}
#[test]
fn test_specific_v01_regression_scenarios() {
let mut cmd1 = Command::cargo_bin("sorting-race").unwrap();
cmd1.args(&["--size", "500", "--distribution", "reversed", "--fair", "comp", "--budget", "16"])
.timeout(std::time::Duration::from_secs(15))
.assert()
.success()
.stdout(predicate::str::contains("500"))
.stdout(predicate::str::contains("reversed"))
.stdout(predicate::str::contains("Comparison"));
let mut cmd2 = Command::cargo_bin("sorting-race").unwrap();
cmd2.args(&["--size", "100", "--fair", "weighted", "--alpha", "1.5", "--beta", "2.0"])
.timeout(std::time::Duration::from_secs(10))
.assert()
.success()
.stdout(predicate::str::contains("Weighted"))
.stdout(predicate::str::contains("1.5"))
.stdout(predicate::str::contains("2.0"));
let mut cmd3 = Command::cargo_bin("sorting-race").unwrap();
cmd3.args(&["--size", "200", "--distribution", "few-unique", "--fair", "adaptive", "--learning-rate", "0.7"])
.timeout(std::time::Duration::from_secs(12))
.assert()
.success()
.stdout(predicate::str::contains("Adaptive"))
.stdout(predicate::str::contains("0.7"));
}
#[test]
fn test_performance_benchmarks_compatibility() {
use std::time::Instant;
let start_time = Instant::now();
let mut cmd = Command::cargo_bin("sorting-race").unwrap();
cmd.args(&["--size", "100", "--fair", "walltime"])
.timeout(std::time::Duration::from_secs(10))
.assert()
.success();
let duration = start_time.elapsed();
assert!(duration.as_secs() < 8, "CLI execution took too long: {:?}", duration);
let start_small = Instant::now();
let mut cmd_small = Command::cargo_bin("sorting-race").unwrap();
cmd_small.args(&["--size", "50"])
.timeout(std::time::Duration::from_secs(5))
.assert()
.success();
let duration_small = start_small.elapsed();
assert!(duration_small.as_secs() < 5, "Small array execution took too long: {:?}", duration_small);
}
#[test]
fn test_memory_display_bug_fix_in_cli() {
let mut cmd = Command::cargo_bin("sorting-race").unwrap();
let assertion = cmd
.args(&["--size", "100", "--fair", "walltime"])
.timeout(std::time::Duration::from_secs(10))
.assert();
assertion
.success()
.stdout(predicate::str::contains("B").or(predicate::str::contains("KB")).or(predicate::str::contains("MB")))
.stdout(predicate::str::contains(":").and(
predicate::str::contains("B").or(
predicate::str::contains("KB").or(
predicate::str::contains("MB")
)
)
));
let output = StdCommand::new(env!("CARGO_BIN_EXE_sorting-race"))
.args(&["--size", "50", "--fair", "walltime"])
.output()
.expect("Failed to execute command");
let stdout = String::from_utf8_lossy(&output.stdout);
let na_count = stdout.matches("N/A").count();
assert!(na_count <= 1, "Too many N/A values in memory display: {}", na_count);
}
}