use std::process::{Command, Output};
fn tachyon(args: &[&str]) -> Output {
Command::new(env!("CARGO_BIN_EXE_tachyon")).args(args).output().expect("failed to run tachyon")
}
fn stdout_of(output: &Output) -> String {
String::from_utf8_lossy(&output.stdout).into_owned()
}
fn json_number(json: &str, key: &str) -> f64 {
let needle = format!("\"{key}\":");
let start = json.find(&needle).unwrap_or_else(|| panic!("no {key} in {json}")) + needle.len();
let rest = &json[start..];
let end = rest.find([',', '}']).unwrap_or(rest.len());
rest[..end].trim().parse().unwrap_or_else(|_| panic!("{key} not numeric in {json}"))
}
fn fast<'a>(extra: &[&'a str]) -> Vec<&'a str> {
let mut args = vec!["--seconds", "0.4", "--working-set-mb", "16"];
args.extend_from_slice(extra);
args
}
#[test]
fn a_short_probe_actually_measures_something() {
let output = tachyon(&fast(&["--json"]));
assert!(output.status.success(), "exited {:?}", output.status.code());
let json = stdout_of(&output);
assert!(json_number(&json, "accesses") > 0.0, "no accesses recorded: {json}");
assert!(json_number(&json, "million_accesses_per_sec") > 0.0, "{json}");
let ns = json_number(&json, "ns_per_access");
assert!(ns > 1.0, "latency implausibly low, did the chase get elided? {json}");
assert!(ns < 10_000.0, "latency implausibly high: {json}");
}
#[test]
fn json_is_a_single_flat_object() {
let output = tachyon(&fast(&["--json"]));
let json = stdout_of(&output);
let trimmed = json.trim();
assert!(trimmed.starts_with('{') && trimmed.ends_with('}'), "{json}");
assert_eq!(trimmed.lines().count(), 1, "JSON must be one line: {json}");
assert_eq!(trimmed.matches('{').count(), 1, "JSON must not nest: {json}");
assert!(trimmed.contains("\"probe\":\"memory-chase\""), "{json}");
}
#[test]
fn json_carries_the_version_that_produced_the_reading() {
let output = tachyon(&fast(&["--json"]));
let json = stdout_of(&output);
let expected = format!("\"version\":\"{}\"", env!("CARGO_PKG_VERSION"));
assert!(json.contains(&expected), "{json}");
}
#[test]
fn version_exits_zero_and_prints_the_crate_version() {
for flag in ["--version", "-V"] {
let output = tachyon(&[flag]);
assert!(output.status.success(), "{flag} should exit 0");
let text = stdout_of(&output);
assert!(text.contains(env!("CARGO_PKG_VERSION")), "{flag} printed {text}");
}
}
#[test]
fn human_output_is_the_default() {
let output = tachyon(&fast(&[]));
assert!(output.status.success());
let text = stdout_of(&output);
assert!(text.contains("M accesses/s"), "{text}");
assert!(text.contains("ns/access"), "{text}");
assert!(!text.contains('{'), "default output should not be JSON: {text}");
}
#[test]
fn requested_thread_count_is_honoured() {
let output = tachyon(&["--seconds", "0.4", "--working-set-mb", "8", "-t", "2", "--json"]);
let json = stdout_of(&output);
assert!((json_number(&json, "threads") - 2.0).abs() < f64::EPSILON, "{json}");
}
#[test]
fn help_exits_zero_and_documents_every_flag() {
for flag in ["--help", "-h"] {
let output = tachyon(&[flag]);
assert!(output.status.success(), "{flag} should exit 0");
let text = stdout_of(&output);
for expected in
["--seconds", "--working-set-mb", "--threads", "--seed", "--json", "--version"]
{
assert!(text.contains(expected), "{flag} output omits {expected}: {text}");
}
}
}
#[test]
fn a_usage_error_exits_nonzero_and_explains_itself() {
for args in [
vec!["--nope"],
vec!["--seconds"],
vec!["--seconds", "0"],
vec!["--seconds", "later"],
vec!["--seconds", "1e20"],
vec!["--threads", "0"],
vec!["--working-set-mb", "0"],
vec!["--working-set-mb", "17592186044416"],
vec!["--seed", "lucky"],
] {
let output = tachyon(&args);
assert!(!output.status.success(), "{args:?} should have failed");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("error:"), "{args:?} gave no error line: {stderr}");
assert!(stderr.contains("USAGE:"), "{args:?} printed no usage: {stderr}");
}
}
#[test]
fn no_seed_produces_a_degenerate_chain() {
for seed in ["1", "0", "12345"] {
let output =
tachyon(&["--seconds", "0.3", "--working-set-mb", "8", "--seed", seed, "--json"]);
assert!(output.status.success(), "seed {seed} failed");
let json = stdout_of(&output);
assert!(json_number(&json, "accesses") > 0.0, "seed {seed}: {json}");
}
}