use assert_cmd::Command;
use serde_json::Value;
use std::path::Path;
fn run_tldr_json(args: &[&str]) -> Option<Value> {
let mut cmd = Command::new(assert_cmd::cargo::cargo_bin!("tldr"));
cmd.args(args).arg("--format").arg("json");
let output = cmd.output().expect("failed to execute tldr");
if !output.status.success() {
return None;
}
let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
serde_json::from_str(&stdout).ok()
}
fn require_repo(path: &str) -> bool {
Path::new(path).exists()
}
#[test]
fn test_calls_ocaml_functor_body_resolved() {
let repo = "/tmp/repos/ocaml-dune/src/dag";
if !require_repo(repo) {
return;
}
let v = run_tldr_json(&["calls", repo]).expect("calls JSON");
let nodes = v
.get("nodes")
.and_then(Value::as_array)
.expect("calls.nodes array present");
assert!(
nodes.len() >= 10,
"ocaml functor body callgraph should expose at least 10 nodes; \
got {} on {}: {:?}",
nodes.len(),
repo,
nodes,
);
}
#[test]
fn test_calls_ocaml_functor_baseline_consistent() {
let dir = "/tmp/repos/ocaml-dune/src/dag";
let file = "/tmp/repos/ocaml-dune/src/dag/dag.ml";
if !require_repo(dir) || !Path::new(file).exists() {
return;
}
let calls = run_tldr_json(&["calls", dir]).expect("calls JSON");
let calls_nodes = calls
.get("nodes")
.and_then(Value::as_array)
.map(|a| a.len())
.unwrap_or(0);
let structure = run_tldr_json(&["structure", file]).expect("structure JSON");
let structure_fns = structure
.get("files")
.and_then(Value::as_array)
.and_then(|files| files.first())
.and_then(|f| f.get("definitions"))
.and_then(Value::as_array)
.map(|defs| {
defs.iter()
.filter(|d| {
d.get("kind").and_then(Value::as_str) == Some("function")
})
.count()
})
.unwrap_or(0);
assert!(
structure_fns > 0,
"structure must report at least one function for {}",
file,
);
assert!(
calls_nodes >= structure_fns,
"calls.nodes ({}) should cover every structure-defined function ({}) \
on {} — pre-fix dag.ml reported 2 nodes for 24 structure functions",
calls_nodes,
structure_fns,
file,
);
}
#[test]
fn test_impact_js_commonjs_method_assignment() {
let repo = "/tmp/repos/express";
if !require_repo(repo) {
return;
}
let candidates = ["init", "defaultConfiguration", "handle", "render"];
let mut total_callers = 0usize;
for method in candidates {
let v = match run_tldr_json(&["impact", method, repo]) {
Some(v) => v,
None => continue,
};
let targets = v
.get("targets")
.and_then(Value::as_object);
if let Some(map) = targets {
for (_, t) in map {
if let Some(callers) = t.get("callers").and_then(Value::as_array) {
total_callers += callers.len();
}
}
}
}
assert!(
total_callers >= 1,
"Express CommonJS methods should have at least 1 caller across {:?}; \
got total={} (pre-fix: 0 for all methods)",
candidates,
total_callers,
);
}
#[test]
fn test_explain_js_commonjs_callers() {
let app_file = "/tmp/repos/express/lib/application.js";
if !Path::new(app_file).exists() {
return;
}
let methods = ["init", "defaultConfiguration", "handle", "render"];
let mut found_caller = false;
for method in methods {
let v = match run_tldr_json(&["explain", app_file, method]) {
Some(v) => v,
None => continue,
};
let caller_count = v
.get("change_impact")
.and_then(|ci| ci.get("callers"))
.and_then(Value::as_array)
.map(|a| a.len())
.or_else(|| {
v.get("callers")
.and_then(Value::as_array)
.map(|a| a.len())
})
.unwrap_or(0);
if caller_count > 0 {
found_caller = true;
break;
}
}
assert!(
found_caller,
"tldr explain on lib/application.js must report ≥1 caller for at \
least one of {:?} — BUG-AGG12-7 cross-command regression check",
methods,
);
}
#[test]
fn test_deps_elixir_resolves_alias() {
let repo = "/tmp/repos/elixir-plug/lib";
if !require_repo(repo) {
return;
}
let v = run_tldr_json(&["deps", repo]).expect("deps JSON");
let total = v
.get("stats")
.and_then(|s| s.get("total_internal_deps"))
.and_then(Value::as_u64)
.expect("deps.stats.total_internal_deps present");
assert!(
total >= 10,
"elixir alias resolution should produce ≥10 internal deps for plug/lib; \
got {} (pre-fix: 0)",
total,
);
}
#[test]
fn test_slice_elixir_returns_lines() {
let file = "/tmp/repos/elixir-plug/lib/plug/conn.ex";
if !Path::new(file).exists() {
return;
}
let v = run_tldr_json(&["slice", file, "assign", "316"]).expect("slice JSON");
let line_count = v
.get("line_count")
.and_then(Value::as_u64)
.expect("slice.line_count present");
assert!(
line_count >= 1,
"elixir slice on assign/316 should return at least 1 line; got {}",
line_count,
);
}
#[test]
fn test_interface_ocaml_module_name_populated() {
let file = "/tmp/repos/ocaml-dune/src/dag/dag.ml";
if !Path::new(file).exists() {
return;
}
let v = run_tldr_json(&["interface", file]).expect("interface JSON");
let classes = v
.get("classes")
.and_then(Value::as_array)
.expect("interface.classes array present");
assert!(
!classes.is_empty(),
"interface must report at least one class for dag.ml",
);
let first_name = classes[0]
.get("name")
.and_then(Value::as_str)
.expect("classes[0].name present");
assert!(
!first_name.is_empty(),
"OCaml functor module wrapper class name must be non-empty for dag.ml; \
pre-fix Phase-12 reported \"\". Got \"{}\"",
first_name,
);
assert_eq!(
first_name, "Make",
"expected dag.ml module wrapper class name to be `Make`; got `{}`",
first_name,
);
}
#[test]
fn test_interface_ocaml_io_buffer_unchanged() {
let file = "/tmp/repos/ocaml-dune/src/rpc/io_buffer.ml";
if !Path::new(file).exists() {
return;
}
let v = run_tldr_json(&["interface", file]).expect("interface JSON");
let classes = v
.get("classes")
.and_then(Value::as_array)
.expect("interface.classes array present");
assert!(
!classes.is_empty(),
"io_buffer.ml must report at least one class (P11 regression check)",
);
let first_name = classes[0]
.get("name")
.and_then(Value::as_str)
.expect("classes[0].name present");
assert!(
!first_name.is_empty(),
"io_buffer.ml first class name must be non-empty (P11 BUG-AGG-8 \
regression check); got \"{}\"",
first_name,
);
}