use std::io::Write;
use std::process::{Command, Output, Stdio};
fn mf() -> Command {
let mut c = Command::new(env!("CARGO_BIN_EXE_megafine"));
c.env("NO_COLOR", "1"); c
}
fn run(args: &[&str]) -> Output {
mf().args(args).output().expect("failed to run megafine")
}
fn stdout(out: &Output) -> String {
String::from_utf8_lossy(&out.stdout).into_owned()
}
fn stderr(out: &Output) -> String {
String::from_utf8_lossy(&out.stderr).into_owned()
}
#[test]
fn basic_run() {
let out = run(&["-r", "2", "--no-calibrate", "--no-pin", "sleep 0.02"]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("Benchmark 1"), "stdout: {s}");
assert!(s.contains("Time"), "stdout: {s}");
}
#[test]
fn two_commands_show_ranking() {
let out = run(&[
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
"sleep 0.05",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("reference"), "stdout: {s}");
assert!(s.contains("Rank"), "stdout: {s}");
assert!(s.contains("fastest"), "stdout: {s}");
}
#[test]
fn raw_outputs_only_ratios() {
let out = run(&[
"--raw",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
"sleep 0.05",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
let lines: Vec<&str> = s.lines().collect();
assert_eq!(lines.len(), 2, "stdout: {lines:?}");
assert_eq!(lines[0], "1.000000");
}
#[test]
fn raw_reference_picks_baseline() {
let out = run(&[
"--raw",
"--reference",
"2",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
"sleep 0.05",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let lines: Vec<String> = stdout(&out).lines().map(String::from).collect();
assert_eq!(lines.len(), 2, "stdout: {lines:?}");
assert_eq!(lines[1], "1.000000"); }
#[test]
fn reference_marks_chosen_command() {
let out = run(&[
"--reference",
"2",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
"sleep 0.05",
"sleep 0.08",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
let ref_line = s
.lines()
.find(|l| l.contains("reference"))
.expect("a row should be the reference");
assert!(ref_line.contains("sleep 0.05"), "ref line: {ref_line}");
}
#[test]
fn command_name_is_shown() {
let out = run(&[
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
"-n",
"MYNAME",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
assert!(stdout(&out).contains("MYNAME"), "stdout: {}", stdout(&out));
}
#[test]
fn bare_command_name_derives_names() {
let out = run(&[
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
"sleep 0.03",
"-n",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("Benchmark 1: 2"), "stdout: {s}");
assert!(s.contains("Benchmark 2: 3"), "stdout: {s}");
}
#[test]
fn rusage_extras_shown() {
let out = run(&["-r", "2", "--no-calibrate", "--no-pin", "sleep 0.01"]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("Faults"), "stdout: {s}");
assert!(s.contains("CtxSw"), "stdout: {s}");
}
#[test]
fn counters_reported_when_supported() {
let out = run(&[
"--counters",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"/bin/true",
]);
if !out.status.success() {
assert!(stderr(&out).contains("perf"), "stderr: {}", stderr(&out));
return;
}
let s = stdout(&out);
assert!(s.contains("instr"), "stdout: {s}");
assert!(s.contains("IPC"), "stdout: {s}");
}
#[test]
fn target_stops_on_its_own() {
let out = run(&[
"-j",
"1",
"--target",
"50",
"--no-calibrate",
"--no-pin",
"sleep 0.01",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
assert!(stdout(&out).contains("10 runs"), "stdout: {}", stdout(&out));
}
#[test]
fn clear_difference_has_no_significance_note() {
let out = run(&[
"-r",
"5",
"--no-calibrate",
"--no-pin",
"sleep 0.01",
"sleep 0.05",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
assert!(
!stdout(&out).contains("not significantly"),
"stdout: {}",
stdout(&out)
);
}
#[test]
fn parameter_list_expands_commands() {
let out = run(&[
"-L",
"d",
"0.02,0.03",
"-r",
"1",
"--no-calibrate",
"--no-pin",
"sleep {d}",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("sleep 0.02"), "stdout: {s}");
assert!(s.contains("sleep 0.03"), "stdout: {s}");
assert!(s.contains("Benchmark 2"), "stdout: {s}");
}
#[test]
fn parameter_list_reads_values_from_file() {
let path = std::env::temp_dir().join(format!("megafine-Lfile-{}", std::process::id()));
std::fs::write(&path, "0.02\n0.03\n").unwrap();
let arg = format!("@{}", path.display());
let out = run(&[
"-L",
"d",
&arg,
"-r",
"1",
"--no-calibrate",
"--no-pin",
"sleep {d}",
]);
let _ = std::fs::remove_file(&path);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("sleep 0.02"), "stdout: {s}");
assert!(s.contains("Benchmark 2"), "stdout: {s}");
}
#[test]
fn parameter_step_n_expands_commands() {
let out = run(&[
"-P",
"s",
"1",
"3",
"--parameter-step-n",
"2",
"-r",
"1",
"--no-calibrate",
"--no-pin",
"/bin/true {s}",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("/bin/true 2"), "stdout: {s}");
assert!(s.contains("Benchmark 3"), "stdout: {s}");
}
#[test]
fn parameter_step_log_spaces_geometrically() {
let out = run(&[
"-P",
"s",
"1",
"1000",
"--parameter-step-n",
"3",
"--parameter-step-log",
"-r",
"1",
"--no-calibrate",
"--no-pin",
"/bin/true {s}",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("/bin/true 10"), "stdout: {s}");
assert!(s.contains("/bin/true 100"), "stdout: {s}");
assert!(s.contains("Benchmark 4"), "stdout: {s}");
}
#[test]
fn parameter_step_log_requires_step_n() {
let out = run(&["-P", "s", "1", "100", "--parameter-step-log", "/bin/true"]);
assert!(!out.status.success());
}
#[test]
fn parameter_step_n_conflicts_with_step_size() {
let out = run(&[
"-P",
"s",
"1",
"3",
"--parameter-step-n",
"2",
"--parameter-step-size",
"1",
"/bin/true",
]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("cannot be used with"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn unknown_parameter_errors() {
let out = run(&["-L", "d", "1,", "-r", "1", "--no-calibrate", "sleep {x}"]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("unknown parameter"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn reads_commands_from_stdin() {
let mut child = mf()
.args(["--no-calibrate", "--no-pin", "-r", "2", "-"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("spawn");
child
.stdin
.take()
.unwrap()
.write_all(b"sleep 0.02\nsleep 0.03\n")
.unwrap();
let out = child.wait_with_output().unwrap();
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(
s.contains("Benchmark 1") && s.contains("Benchmark 2"),
"stdout: {s}"
);
}
#[test]
fn jobs_and_warmup_smoke() {
let out = run(&[
"-j",
"2",
"-w",
"1",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
"sleep 0.02",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
}
#[test]
fn schedule_sequential_interleaves_commands() {
let log = RunLog::new("seq");
let a = format!("sh -c 'echo a >> {}'", log.0.display());
let b = format!("sh -c 'echo b >> {}'", log.0.display());
let out = run(&[
"--schedule",
"sequential",
"-r",
"2",
"--no-calibrate",
"--no-pin",
&a,
&b,
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
assert_eq!(log.lines(), ["a", "b", "a", "b"]);
}
#[test]
fn schedule_sequential_conflicts_with_jobs() {
let out = run(&["--schedule", "sequential", "-j", "2", "-r", "1", "a"]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("drop --jobs"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn schedule_exclusive_serializes_each_command() {
let lock = std::env::temp_dir().join(format!("megafine-excl-{}", std::process::id()));
let _ = std::fs::remove_dir(&lock);
let cmd = format!(
"sh -c 'mkdir {0} && sleep 0.02 && rmdir {0}'",
lock.display()
);
let out = run(&[
"--schedule",
"exclusive",
"-j",
"2",
"-r",
"4",
"--no-calibrate",
"--no-pin",
&cmd,
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
}
#[test]
fn schedule_fair_smoke() {
let out = run(&[
"--schedule",
"fair",
"-j",
"2",
"-w",
"1",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.01",
"sleep 0.02",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
assert!(stdout(&out).contains("2 runs"), "stdout: {}", stdout(&out));
}
#[test]
fn schedule_bogus_errors() {
let out = run(&["--schedule", "bogus", "-r", "1", "a"]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("invalid schedule"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn region_mode_reports_a_benchmark() {
let region_bin = env!("CARGO_BIN_EXE_megafine-region-rs");
let cmd = format!("{region_bin} 0.02 0.05 0.02");
let out = run(&["--region", "-r", "2", "--no-pin", &cmd]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
assert!(
stdout(&out).contains("Benchmark 1"),
"stdout: {}",
stdout(&out)
);
}
struct RunLog(std::path::PathBuf);
impl RunLog {
fn new(tag: &str) -> Self {
let path = std::env::temp_dir().join(format!("megafine-{tag}-{}", std::process::id()));
let _ = std::fs::remove_file(&path);
RunLog(path)
}
fn lines(&self) -> Vec<String> {
std::fs::read_to_string(&self.0)
.expect("run log should exist")
.lines()
.map(String::from)
.collect()
}
}
impl Drop for RunLog {
fn drop(&mut self) {
let _ = std::fs::remove_file(&self.0);
}
}
#[test]
fn run_id_is_unique_and_incrementing() {
let log = RunLog::new("run-id");
let cmd = format!("sh -c 'echo $MEGAFINE_RUN_ID >> {}'", log.0.display());
let out = run(&[
"-j",
"2",
"-w",
"2",
"-r",
"4",
"--no-calibrate",
"--no-pin",
&cmd,
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let mut ids: Vec<u64> = log.lines().iter().map(|l| l.parse().unwrap()).collect();
ids.sort_unstable();
assert_eq!(ids, (0..6).collect::<Vec<u64>>()); }
#[test]
fn prepare_shares_run_id_with_its_run() {
let log = RunLog::new("prepare-id");
let prepare = format!("sh -c 'echo p$MEGAFINE_RUN_ID >> {}'", log.0.display());
let cmd = format!("sh -c 'echo c$MEGAFINE_RUN_ID >> {}'", log.0.display());
let out = run(&[
"-p",
&prepare,
"-r",
"3",
"--no-calibrate",
"--no-pin",
&cmd,
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let mut lines = log.lines();
lines.sort_unstable();
assert_eq!(lines, vec!["c0", "c1", "c2", "p0", "p1", "p2"]);
}
#[test]
fn conclude_runs_after_each_run_with_its_run_id() {
let log = RunLog::new("conclude-id");
let cmd = format!("sh -c 'echo c$MEGAFINE_RUN_ID >> {}'", log.0.display());
let conclude = format!("sh -c 'echo z$MEGAFINE_RUN_ID >> {}'", log.0.display());
let out = run(&[
"--conclude",
&conclude,
"-r",
"3",
"--no-calibrate",
"--no-pin",
&cmd,
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let mut lines = log.lines();
lines.sort_unstable();
assert_eq!(lines, vec!["c0", "c1", "c2", "z0", "z1", "z2"]);
}
#[test]
fn estimator_labels_the_time() {
let out = run(&[
"--estimator",
"p90",
"-r",
"3",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("p90"), "stdout: {s}");
}
#[test]
fn precision_controls_decimals() {
let out = run(&[
"--precision",
"1",
"-u",
"s",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("0.0 s"), "stdout: {s}");
assert!(!s.contains("0.020 s"), "stdout: {s}");
}
#[test]
fn invalid_estimator_errors() {
let out = run(&["--estimator", "avg", "-r", "1", "--no-calibrate", "a"]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("invalid estimator"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn raw_with_one_command_errors() {
let out = run(&["--raw", "-r", "2", "--no-calibrate", "sleep 0.02"]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("2 commands"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn reference_out_of_range_errors() {
let out = run(&["--reference", "5", "-r", "2", "--no-calibrate", "a", "b"]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("out of range"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn runs_zero_errors() {
let out = run(&["-r", "0", "sleep 0.02"]);
assert!(!out.status.success());
}
#[test]
fn completions_emit_a_script() {
let out = run(&["--gen-completions", "bash"]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
assert!(
stdout(&out).contains("megafine"),
"stdout: {}",
stdout(&out)
);
}
#[test]
fn no_command_still_errors() {
let out = run(&[]);
assert!(!out.status.success());
}
#[test]
fn ignore_failure_keeps_failing_runs() {
let out = run(&["-i", "-r", "3", "--no-calibrate", "--no-pin", "false"]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("3 of 3 runs exited non-zero"), "stdout: {s}");
assert!(s.contains("3 runs"), "stdout: {s}");
}
#[test]
fn ignore_failure_counts_mixed_runs() {
let out = run(&[
"-i",
"-j",
"1",
"-r",
"4",
"--no-calibrate",
"--no-pin",
"sh -c 'test $MEGAFINE_RUN_ID -lt 2'",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("2 of 4 runs exited non-zero"), "stdout: {s}");
}
#[test]
fn ignore_failure_keeps_hooks_strict() {
let out = run(&[
"-i",
"-p",
"false",
"-r",
"1",
"--no-calibrate",
"--no-pin",
"sleep 0.01",
]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("prepare command failed"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn timeout_kills_the_process_group() {
let started = std::time::Instant::now();
let out = run(&[
"--timeout",
"0.2",
"-r",
"1",
"--no-calibrate",
"--no-pin",
"sh -c 'sleep 10'",
]);
assert!(!out.status.success());
assert!(
started.elapsed().as_secs() < 5,
"took {:?}",
started.elapsed()
);
assert!(
stderr(&out).contains("timed out"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn timeout_with_ignore_failure_keeps_runs() {
let out = run(&[
"--timeout",
"0.2",
"-i",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 10",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("2 of 2 runs exited non-zero"), "stdout: {s}");
}
#[test]
fn timeout_zero_errors() {
let out = run(&["--timeout", "0", "-r", "1", "a"]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("--timeout must be positive"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn output_file_captures_stdout() {
let log = RunLog::new("output");
let path = log.0.display().to_string();
let out = run(&[
"--output",
&path,
"-r",
"2",
"-j",
"1",
"--no-calibrate",
"--no-pin",
"echo marker",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
assert_eq!(log.lines(), ["marker"]); }
#[test]
fn output_inherit_shows_child_stdout() {
let out = run(&[
"--output",
"inherit",
"-r",
"1",
"--no-calibrate",
"--no-pin",
"echo marker",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("marker"), "stdout: {s}");
assert!(s.contains("Benchmark 1"), "stdout: {s}");
}
#[test]
fn input_file_feeds_stdin() {
let input = RunLog::new("input");
std::fs::write(&input.0, "hello\n").unwrap();
let capture = RunLog::new("input-out");
let in_path = format!("{}", input.0.display());
let out_path = format!("{}", capture.0.display());
let out = run(&[
"--input",
&in_path,
"--output",
&out_path,
"-r",
"2",
"--no-calibrate",
"--no-pin",
"wc -c",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
assert_eq!(capture.lines(), ["6"]); }
#[test]
fn missing_input_file_errors_before_running() {
let out = run(&["--input", "/nonexistent/megafine-in", "-r", "1", "true"]);
assert!(!out.status.success());
assert!(stderr(&out).contains("--input"), "stderr: {}", stderr(&out));
}
#[test]
fn sort_metric_puts_best_first() {
let out = run(&[
"--sort",
"metric",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.05",
"sleep 0.02",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
let first_row = s
.lines()
.skip_while(|l| !l.starts_with("Results"))
.nth(1)
.expect("a first ranking row");
assert!(first_row.contains("sleep 0.02"), "row: {first_row}");
assert!(first_row.trim_end().ends_with('1'), "row: {first_row}");
}
#[test]
fn sort_bogus_errors() {
let out = run(&["--sort", "bogus", "-r", "1", "a", "b"]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("invalid sort order"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn metric_rss_ranks_and_shows_metric_line() {
let out = run(&[
"--metric",
"rss",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
"sleep 0.02",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
assert!(s.contains("Metric (rss"), "stdout: {s}");
assert!(s.contains("(best)") || s.contains("(worst)"), "stdout: {s}");
}
#[test]
fn metric_user_smoke() {
let out = run(&[
"--metric",
"user",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
assert!(
stdout(&out).contains("Metric (user"),
"stdout: {}",
stdout(&out)
);
}
#[test]
fn metric_instructions_needs_perf() {
let out = run(&[
"--metric",
"instructions",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"/bin/true",
"/bin/true",
]);
if !out.status.success() {
assert!(stderr(&out).contains("perf"), "stderr: {}", stderr(&out));
return;
}
assert!(
stdout(&out).contains("Metric (instructions"),
"stdout: {}",
stdout(&out)
);
}
#[test]
fn raw_metric_prints_one_ratio_per_command() {
let out = run(&[
"--raw",
"--metric",
"rss",
"-r",
"2",
"--no-calibrate",
"--no-pin",
"sleep 0.02",
"sleep 0.02",
]);
assert!(out.status.success(), "stderr: {}", stderr(&out));
let s = stdout(&out);
let lines: Vec<&str> = s.lines().collect();
assert_eq!(lines.len(), 2, "stdout: {lines:?}");
assert_eq!(lines[0], "1.000000");
}
#[test]
fn metric_bogus_errors() {
let out = run(&["--metric", "bogus", "-r", "1", "a"]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("invalid metric"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn failing_command_errors() {
let out = run(&["-r", "1", "--no-calibrate", "--no-pin", "false"]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("non-zero"),
"stderr: {}",
stderr(&out)
);
}
#[test]
fn failing_command_exit_code_is_mirrored() {
let out = run(&["-r", "1", "--no-calibrate", "--no-pin", "sh -c 'exit 7'"]);
assert_eq!(out.status.code(), Some(7));
}
#[test]
fn failing_run_dumps_partial_results() {
let out = run(&[
"-j",
"1",
"-r",
"5",
"--no-calibrate",
"--no-pin",
"sh -c 'test $MEGAFINE_RUN_ID -lt 2'",
]);
assert!(!out.status.success());
assert!(
stderr(&out).contains("non-zero"),
"stderr: {}",
stderr(&out)
);
let s = stdout(&out);
assert!(s.contains("Benchmark 1"), "stdout: {s}");
assert!(s.contains("2 runs"), "stdout: {s}");
}
#[test]
fn failing_run_keeps_raw_stdout_empty() {
let out = run(&[
"--raw",
"-j",
"1",
"-r",
"3",
"--no-calibrate",
"--no-pin",
"sleep 0.01",
"false",
]);
assert!(!out.status.success());
assert!(stdout(&out).is_empty(), "stdout: {}", stdout(&out));
}