use std::process::Output;
use std::time::{Duration, Instant};
use assert_cmd::Command;
fn grox() -> Command {
let tmp = std::env::temp_dir();
let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("grox"));
cmd.current_dir(tmp);
cmd.timeout(Duration::from_secs(300));
cmd
}
#[derive(Debug)]
struct ProbeResult {
crate_name: &'static str,
query: String,
mode: &'static str,
passed: bool,
exit_code: Option<i32>,
crashed: bool,
duration: Duration,
error_detail: String,
}
impl ProbeResult {
fn success(
crate_name: &'static str,
query: String,
mode: &'static str,
duration: Duration,
) -> Self {
Self {
crate_name,
query,
mode,
passed: true,
exit_code: Some(0),
crashed: false,
duration,
error_detail: String::new(),
}
}
fn failure(
crate_name: &'static str,
query: String,
mode: &'static str,
exit_code: Option<i32>,
duration: Duration,
detail: String,
) -> Self {
let crashed = exit_code.is_none()
|| detail.contains("panicked")
|| detail.contains("stack overflow")
|| detail.contains("SIGSEGV")
|| detail.contains("SIGABRT");
Self {
crate_name,
query,
mode,
passed: false,
exit_code,
crashed,
duration,
error_detail: detail,
}
}
}
fn probe(
crate_name: &'static str,
args: &[&str],
mode: &'static str,
validate: impl FnOnce(&Output) -> Result<(), String>,
) -> ProbeResult {
let query = args.join(" ");
let start = Instant::now();
let output = match grox().args(args).output() {
Ok(output) => output,
Err(e) => {
return ProbeResult::failure(
crate_name,
query,
mode,
None,
start.elapsed(),
format!("command failed to execute: {e}"),
);
}
};
let duration = start.elapsed();
let exit_code = output.status.code();
if exit_code.is_none() {
let stderr = String::from_utf8_lossy(&output.stderr);
return ProbeResult::failure(
crate_name,
query,
mode,
None,
duration,
format!("process killed by signal: {stderr}"),
);
}
let stderr = String::from_utf8_lossy(&output.stderr);
if stderr.contains("panicked") || stderr.contains("stack overflow") {
return ProbeResult::failure(
crate_name,
query,
mode,
exit_code,
duration,
format!("panic detected in stderr: {stderr}"),
);
}
match validate(&output) {
Ok(()) => ProbeResult::success(crate_name, query, mode, duration),
Err(detail) => ProbeResult::failure(crate_name, query, mode, exit_code, duration, detail),
}
}
fn expect_success(output: &Output) -> Result<(), String> {
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(format!(
"expected exit 0, got {:?}: {stderr}",
output.status.code()
));
}
let stdout = String::from_utf8_lossy(&output.stdout);
if stdout.trim().is_empty() {
return Err("stdout is empty".to_string());
}
if String::from_utf8(output.stdout.clone()).is_err() {
return Err("stdout contains invalid UTF-8".to_string());
}
Ok(())
}
fn expect_json(output: &Output) -> Result<(), String> {
expect_success(output)?;
let stdout = String::from_utf8_lossy(&output.stdout);
let first_line = stdout.lines().next().unwrap_or("");
serde_json::from_str::<serde_json::Value>(first_line)
.map_err(|e| format!("invalid JSON: {e}: {first_line}"))?;
Ok(())
}
fn expect_list(output: &Output) -> Result<(), String> {
expect_success(output)?;
let stdout = String::from_utf8_lossy(&output.stdout);
let line_count = stdout.lines().count();
if line_count < 2 {
return Err(format!(
"expected multiple list lines, got {line_count}: {stdout}"
));
}
Ok(())
}
fn expect_search(output: &Output) -> Result<(), String> {
expect_success(output)?;
let stdout = String::from_utf8_lossy(&output.stdout);
if !stdout.contains("results for") {
return Err(format!("missing 'results for' header: {stdout}"));
}
Ok(())
}
fn expect_no_crash(output: &Output) -> Result<(), String> {
match output.status.code() {
Some(code) if code <= 2 => Ok(()),
Some(code) => Err(format!("unexpected exit code: {code}")),
None => Err("process killed by signal".to_string()),
}
}
struct CrateSpec {
name: &'static str,
item_query: &'static str,
search_term: &'static str,
}
const TOP_CRATES: &[CrateSpec] = &[
CrateSpec {
name: "serde",
item_query: "serde::Serialize",
search_term: "Deserialize",
},
CrateSpec {
name: "serde_json",
item_query: "serde_json::Value",
search_term: "from_str",
},
CrateSpec {
name: "rand",
item_query: "rand::Rng",
search_term: "random",
},
CrateSpec {
name: "log",
item_query: "log::Log",
search_term: "info",
},
CrateSpec {
name: "syn",
item_query: "syn::DeriveInput",
search_term: "parse",
},
CrateSpec {
name: "quote",
item_query: "quote::ToTokens",
search_term: "quote",
},
CrateSpec {
name: "proc-macro2",
item_query: "proc_macro2::TokenStream",
search_term: "Span",
},
CrateSpec {
name: "regex",
item_query: "regex::Regex",
search_term: "captures",
},
CrateSpec {
name: "once_cell",
item_query: "once_cell::sync::Lazy",
search_term: "Lazy",
},
CrateSpec {
name: "anyhow",
item_query: "anyhow::Error",
search_term: "context",
},
CrateSpec {
name: "thiserror",
item_query: "thiserror",
search_term: "error",
},
CrateSpec {
name: "clap",
item_query: "clap",
search_term: "Parser",
},
CrateSpec {
name: "bytes",
item_query: "bytes::Bytes",
search_term: "Buf",
},
CrateSpec {
name: "futures",
item_query: "futures::Future",
search_term: "Stream",
},
CrateSpec {
name: "itertools",
item_query: "itertools::Itertools",
search_term: "chunk",
},
CrateSpec {
name: "chrono",
item_query: "chrono::DateTime",
search_term: "NaiveDate",
},
CrateSpec {
name: "url",
item_query: "url::Url",
search_term: "parse",
},
CrateSpec {
name: "semver",
item_query: "semver::Version",
search_term: "parse",
},
CrateSpec {
name: "itoa",
item_query: "itoa::Buffer",
search_term: "Buffer",
},
CrateSpec {
name: "memchr",
item_query: "memchr::memchr",
search_term: "memchr",
},
];
#[test]
#[ignore = "requires nightly toolchain, network, and significant time"]
fn stress_top20_crates_pass_rate() {
let mut results: Vec<ProbeResult> = Vec::new();
for spec in TOP_CRATES {
eprintln!("\n{}", "=".repeat(60));
eprintln!("Testing crate: {}", spec.name);
eprintln!("{}", "=".repeat(60));
eprintln!(" [root] {}", spec.name);
results.push(probe(spec.name, &[spec.name], "root", expect_success));
eprintln!(" [item] {}", spec.item_query);
results.push(probe(
spec.name,
&[spec.item_query],
"item",
expect_no_crash,
));
eprintln!(" [list] {} -r", spec.name);
results.push(probe(spec.name, &["-r", spec.name], "list", expect_list));
eprintln!(" [search] --search {} {}", spec.search_term, spec.name);
results.push(probe(
spec.name,
&["--search", spec.search_term, spec.name],
"search",
expect_search,
));
eprintln!(" [json] --json {}", spec.name);
results.push(probe(
spec.name,
&["--json", spec.name],
"json",
expect_json,
));
}
let total = results.len();
let passed = results.iter().filter(|r| r.passed).count();
let crashed = results.iter().filter(|r| r.crashed).count();
let failed: Vec<&ProbeResult> = results.iter().filter(|r| !r.passed).collect();
#[allow(clippy::cast_precision_loss)]
let pass_rate = (passed as f64 / total as f64) * 100.0;
eprintln!("\n");
eprintln!("{}", "=".repeat(60));
eprintln!("STRESS TEST RESULTS");
eprintln!("{}", "=".repeat(60));
eprintln!("Total probes: {total}");
eprintln!("Passed: {passed}");
eprintln!("Failed: {}", failed.len());
eprintln!("Crashed: {crashed}");
eprintln!("Pass rate: {pass_rate:.1}%");
eprintln!();
if !failed.is_empty() {
eprintln!("FAILURES:");
for f in &failed {
eprintln!(
" [{:>6}] {} {} — exit {:?} — {}",
f.mode,
f.crate_name,
f.query,
f.exit_code,
if f.error_detail.len() > 200 {
format!("{}...", &f.error_detail[..200])
} else {
f.error_detail.clone()
}
);
}
eprintln!();
}
assert_eq!(
crashed, 0,
"ZERO crashes required. {crashed} probe(s) crashed."
);
assert!(
pass_rate >= 96.0,
"Pass rate {pass_rate:.1}% is below the 96% threshold. {passed}/{total} passed.",
);
}
#[test]
#[ignore = "requires nightly toolchain and network; typenum build is slow"]
fn stress_typenum_no_recursion_crash() {
let result = probe("typenum", &["typenum"], "root", expect_success);
eprintln!(
"typenum root: passed={}, duration={:?}",
result.passed, result.duration
);
assert!(
!result.crashed,
"typenum must not crash: {:?}",
result.error_detail
);
assert!(
result.passed,
"typenum root should succeed: {}",
result.error_detail
);
}
#[test]
#[ignore = "requires nightly toolchain and network; typenum build is slow"]
fn stress_typenum_search_no_crash() {
let result = probe(
"typenum",
&["--search", "Integer", "typenum"],
"search",
expect_no_crash,
);
eprintln!(
"typenum search: passed={}, duration={:?}",
result.passed, result.duration
);
assert!(
!result.crashed,
"typenum search must not crash: {:?}",
result.error_detail
);
}
#[test]
#[ignore = "requires nightly toolchain and network; typenum build is slow"]
fn stress_typenum_list_no_crash() {
let result = probe("typenum", &["-r", "typenum"], "list", expect_no_crash);
eprintln!(
"typenum list: passed={}, duration={:?}",
result.passed, result.duration
);
assert!(
!result.crashed,
"typenum list must not crash: {:?}",
result.error_detail
);
}
#[test]
#[ignore = "requires nightly toolchain and network; typenum build is slow"]
fn stress_typenum_json_no_crash() {
let result = probe("typenum", &["--json", "typenum"], "json", expect_no_crash);
eprintln!(
"typenum json: passed={}, duration={:?}",
result.passed, result.duration
);
assert!(
!result.crashed,
"typenum json must not crash: {:?}",
result.error_detail
);
}
#[test]
#[ignore = "requires nightly toolchain and network"]
fn stress_utf8_truncation_no_crash_regex() {
let result = probe("regex", &["regex"], "root", expect_success);
assert!(
!result.crashed,
"regex root must not crash (UTF-8): {}",
result.error_detail
);
assert!(
result.passed,
"regex root should succeed: {}",
result.error_detail
);
}
#[test]
#[ignore = "requires nightly toolchain and network"]
fn stress_utf8_truncation_no_crash_chrono() {
let result = probe("chrono", &["chrono"], "root", expect_success);
assert!(
!result.crashed,
"chrono root must not crash (UTF-8): {}",
result.error_detail
);
assert!(
result.passed,
"chrono root should succeed: {}",
result.error_detail
);
}
#[test]
#[ignore = "requires nightly toolchain and network"]
fn stress_utf8_truncation_no_crash_url() {
let result = probe("url", &["url"], "root", expect_success);
assert!(
!result.crashed,
"url root must not crash (UTF-8): {}",
result.error_detail
);
assert!(
result.passed,
"url root should succeed: {}",
result.error_detail
);
}
#[test]
#[ignore = "requires nightly toolchain and network"]
fn stress_large_crate_syn() {
let root = probe("syn", &["syn"], "root", expect_success);
assert!(
!root.crashed,
"syn root must not crash: {}",
root.error_detail
);
let list = probe("syn", &["-r", "syn"], "list", |output| {
expect_success(output)?;
let stdout = String::from_utf8_lossy(&output.stdout);
let line_count = stdout.lines().count();
if line_count < 20 {
return Err(format!(
"syn should have many items in list, got {line_count}"
));
}
Ok(())
});
assert!(
!list.crashed,
"syn list must not crash: {}",
list.error_detail
);
eprintln!(
"syn: root={}, list={}, durations={:?}/{:?}",
root.passed, list.passed, root.duration, list.duration
);
}
#[test]
#[ignore = "requires nightly toolchain and network"]
fn stress_large_crate_futures() {
let root = probe("futures", &["futures"], "root", expect_success);
assert!(
!root.crashed,
"futures root must not crash: {}",
root.error_detail
);
let list = probe("futures", &["-r", "futures"], "list", expect_list);
assert!(
!list.crashed,
"futures list must not crash: {}",
list.error_detail
);
eprintln!("futures: root={}, list={}", root.passed, list.passed);
}
#[test]
#[ignore = "requires nightly toolchain and network"]
fn stress_large_crate_itertools() {
let root = probe("itertools", &["itertools"], "root", expect_success);
assert!(
!root.crashed,
"itertools root must not crash: {}",
root.error_detail
);
let item = probe(
"itertools",
&["itertools::Itertools"],
"item",
expect_no_crash,
);
assert!(
!item.crashed,
"itertools::Itertools must not crash: {}",
item.error_detail
);
eprintln!("itertools: root={}, item={}", root.passed, item.passed);
}
#[test]
#[ignore = "requires nightly toolchain and network"]
fn stress_output_quality_serde_json_value() {
let result = probe("serde_json", &["serde_json::Value"], "item", |output| {
expect_success(output)?;
let stdout = String::from_utf8_lossy(&output.stdout);
if !stdout.contains("enum") {
return Err(format!("serde_json::Value should show as enum: {stdout}"));
}
let has_variants = stdout.contains("Null")
|| stdout.contains("Bool")
|| stdout.contains("Number")
|| stdout.contains("String")
|| stdout.contains("Array")
|| stdout.contains("Object");
if !has_variants {
return Err(format!("serde_json::Value should show variants: {stdout}"));
}
Ok(())
});
assert!(
result.passed,
"quality check failed: {}",
result.error_detail
);
}
#[test]
#[ignore = "requires nightly toolchain and network"]
fn stress_output_quality_regex() {
let result = probe("regex", &["regex::Regex"], "item", |output| {
expect_success(output)?;
let stdout = String::from_utf8_lossy(&output.stdout);
if !stdout.contains("struct") && !stdout.contains("Regex") {
return Err(format!("regex::Regex should show struct: {stdout}"));
}
let has_methods = stdout.contains("is_match")
|| stdout.contains("find")
|| stdout.contains("captures")
|| stdout.contains("new");
if !has_methods {
return Err(format!("regex::Regex should show methods: {stdout}"));
}
Ok(())
});
assert!(
result.passed,
"quality check failed: {}",
result.error_detail
);
}
#[test]
#[ignore = "requires nightly toolchain and network"]
fn stress_output_quality_bytes() {
let result = probe("bytes", &["bytes::Bytes"], "item", |output| {
expect_success(output)?;
let stdout = String::from_utf8_lossy(&output.stdout);
if !stdout.contains("struct") && !stdout.contains("Bytes") {
return Err(format!("bytes::Bytes should show struct: {stdout}"));
}
if !stdout.contains("methods:") && !stdout.contains("pub fn ") {
return Err(format!("bytes::Bytes should show methods: {stdout}"));
}
Ok(())
});
assert!(
result.passed,
"quality check failed: {}",
result.error_detail
);
}
#[test]
#[ignore = "requires nightly toolchain and network"]
fn stress_token_efficiency_default_output() {
for crate_name in &["serde", "regex", "clap", "bytes", "url"] {
let result = probe(crate_name, &[crate_name], "root", |output| {
expect_success(output)?;
let stdout = String::from_utf8_lossy(&output.stdout);
let char_count = stdout.len();
if char_count < 100 {
return Err(format!(
"{crate_name}: output too short ({char_count} chars)"
));
}
if char_count > 15000 {
return Err(format!(
"{crate_name}: output too long ({char_count} chars), truncation may be broken"
));
}
Ok(())
});
assert!(
!result.crashed,
"{crate_name} crashed during token efficiency check: {}",
result.error_detail
);
}
}