mod common;
use predicates::prelude::*;
fn content_hash(path: &std::path::Path) -> String {
let bytes = std::fs::read(path).unwrap();
bytes[8..24].iter().map(|b| format!("{b:02x}")).collect()
}
fn carded(closed: bool, extra: &[&str]) -> (common::Fixture, std::path::PathBuf) {
let fixture = common::fixture();
let mut nq = String::new();
for i in 0..2000 {
if !closed {
nq.push_str(&format!(
"<http://example.test/s{i}> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> \
<http://example.test/Thing> .\n"
));
}
nq.push_str(&format!(
"<http://example.test/s{i}> <http://www.w3.org/2000/01/rdf-schema#label> \"Thing \
number {i}\"@en .\n<http://example.test/s{i}> <http://example.test/next> \
<http://example.test/s{}> .\n",
(i + 1) % 2000
));
}
let source = fixture.write("graph.nq", nq);
let out = fixture.path("graph.rete");
let mut args = vec!["--card"];
args.extend_from_slice(extra);
common::build(&source, &out, &args);
(fixture, out)
}
#[test]
fn a_re_measurement_reproduces_the_build_record() {
let (_fixture, out) = carded(false, &[]);
let doc = common::json(
common::rete()
.arg("card-audit")
.arg(&out)
.args(["--measure", "--json"]),
);
let findings = doc["findings"].as_array().unwrap();
assert!(!findings.is_empty(), "the fixture card ships queries");
let mut checked = 0;
for f in findings {
let o = &f["observed"];
assert!(!o.is_null(), "{} was not measured", f["id"]);
let Some(rec) = o.get("recorded").filter(|r| !r.is_null()) else {
continue;
};
checked += 1;
assert_eq!(
rec["agrees"],
true,
"{}: measured {} B / {} req / {} rows, record says {} B / {} req / {} rows",
f["id"],
o["bytes"],
o["requests"],
o["rows"],
rec["bytes"],
rec["requests"],
rec["rows"]
);
}
assert!(checked > 0, "the build record carried no query costs");
let m = &doc["measurement"];
assert!(m["transport"].as_str().unwrap().starts_with("local file "));
assert_eq!(m["queries_run"], findings.len());
assert!(m["total_bytes"].as_u64().unwrap() > 0);
}
#[test]
fn local_and_remote_measure_the_same_thing_and_both_say_so() {
let (_fixture, out) = carded(false, &[]);
let local = common::json(
common::rete()
.arg("card-audit")
.arg(&out)
.args(["--measure", "--json"]),
);
let url = common::serve(std::fs::read(&out).unwrap(), common::RangeMode::Honor);
let remote = common::json(
common::rete()
.arg("card-audit")
.arg(&url)
.args(["--measure", "--json"]),
);
let transport = remote["measurement"]["transport"].as_str().unwrap();
assert!(
transport.starts_with("HTTP range requests to http://"),
"{transport}"
);
assert!(transport.contains("no block cache"), "{transport}");
assert!(transport.contains("reader fan-out"), "{transport}");
let costs = |doc: &serde_json::Value| -> Vec<(String, u64, u64, u64)> {
doc["findings"]
.as_array()
.unwrap()
.iter()
.filter(|f| !f["observed"].is_null())
.map(|f| {
let o = &f["observed"];
(
f["id"].as_str().unwrap().to_string(),
o["bytes"].as_u64().unwrap(),
o["requests"].as_u64().unwrap(),
o["rows"].as_u64().unwrap(),
)
})
.collect()
};
assert_eq!(
costs(&local),
costs(&remote),
"bytes/requests/rows must not depend on the transport"
);
assert_eq!(
remote["measurement"]["total_bytes"],
local["measurement"]["total_bytes"]
);
}
#[test]
fn only_measures_the_queries_it_was_given() {
let (_fixture, out) = carded(false, &[]);
let doc = common::json(common::rete().arg("card-audit").arg(&out).args([
"--measure",
"--json",
"--only",
"ov-triples",
]));
assert_eq!(doc["measurement"]["queries_run"], 1);
let measured: Vec<_> = doc["findings"]
.as_array()
.unwrap()
.iter()
.filter(|f| !f["observed"].is_null())
.map(|f| f["id"].as_str().unwrap().to_string())
.collect();
assert_eq!(measured, vec!["ov-triples"]);
common::rete()
.arg("card-audit")
.arg(&out)
.args(["--measure", "--only", "not-a-query"])
.assert()
.failure()
.stderr(predicate::str::contains("no query matches --only"));
}
#[test]
fn a_byte_budget_stops_a_query_and_still_reports_the_spend() {
let (_fixture, out) = carded(false, &[]);
let doc = common::json(common::rete().arg("card-audit").arg(&out).args([
"--measure",
"--json",
"--max-mb",
"0.02",
]));
let stopped: Vec<_> = doc["findings"]
.as_array()
.unwrap()
.iter()
.filter(|f| f["observed"]["outcome"] == "error")
.collect();
assert!(
!stopped.is_empty(),
"a 20 KB budget should stop at least one query on this fixture"
);
for f in stopped {
assert!(f["observed"]["error"]
.as_str()
.unwrap()
.contains("byte budget exhausted"));
assert!(f["observed"]["bytes"].as_u64().unwrap() <= 20 * 1024);
}
common::rete()
.arg("card-audit")
.arg(&out)
.args([
"--measure",
"--write-costs",
"--allow-empty",
"--max-mb",
"0.02",
])
.assert()
.failure()
.stderr(predicate::str::contains("did not finish"));
}
#[test]
fn writing_costs_preserves_the_hash_and_the_data() {
let (_fixture, out) = carded(false, &["--no-card-costs"]);
let before_len = std::fs::metadata(&out).unwrap().len();
let before_hash = content_hash(&out);
let before_nq = common::rete()
.arg("export")
.arg(&out)
.args(["--format", "nq"])
.output()
.unwrap()
.stdout;
common::rete()
.arg("card-audit")
.arg(&out)
.args(["--measure", "--write-costs"])
.assert()
.success()
.stderr(predicate::str::contains("content hash unchanged"));
assert_eq!(content_hash(&out), before_hash);
common::rete().arg("verify").arg(&out).assert().success();
let after_nq = common::rete()
.arg("export")
.arg(&out)
.args(["--format", "nq"])
.output()
.unwrap()
.stdout;
assert_eq!(before_nq, after_nq, "the data must not move");
assert!(
std::fs::metadata(&out).unwrap().len() > before_len,
"the build-info section has to come from somewhere"
);
common::rete()
.arg("card")
.arg(&out)
.assert()
.success()
.stdout(predicate::str::contains("query costs"));
let again = common::json(
common::rete()
.arg("card-audit")
.arg(&out)
.args(["--measure", "--json"]),
);
for f in again["findings"].as_array().unwrap() {
let rec = &f["observed"]["recorded"];
assert!(!rec.is_null(), "{} lost its record", f["id"]);
assert_eq!(rec["agrees"], true, "{}", f["id"]);
}
}
#[test]
fn writing_costs_refuses_what_would_mislead() {
let (_fixture, out) = carded(false, &["--no-card-costs"]);
common::rete()
.arg("card-audit")
.arg(&out)
.args(["--measure", "--write-costs", "--only", "ov-triples"])
.assert()
.failure()
.stderr(predicate::str::contains("refuses a partial run"));
let url = common::serve(std::fs::read(&out).unwrap(), common::RangeMode::Honor);
common::rete()
.arg("card-audit")
.arg(&url)
.args(["--write-costs"])
.assert()
.failure()
.stderr(predicate::str::contains("needs a local file"));
let (_closed_fixture, closed) = carded(true, &["--no-card-costs"]);
common::rete()
.arg("card-audit")
.arg(&closed)
.args(["--measure", "--write-costs"])
.assert()
.failure()
.stderr(predicate::str::contains("returned zero rows"))
.stderr(predicate::str::contains("top-dangling"))
.stderr(predicate::str::contains("needs a re-card"));
common::rete()
.arg("card-audit")
.arg(&closed)
.args(["--measure", "--write-costs", "--allow-empty"])
.assert()
.success();
}
#[test]
fn a_run_settles_a_verdict_no_card_can_reach() {
let (_fixture, closed) = carded(true, &["--no-card-costs"]);
let doc = common::json(common::rete().arg("card-audit").arg(&closed).args([
"--measure",
"--json",
"--only",
"top-dangling",
]));
let f = doc["findings"]
.as_array()
.unwrap()
.iter()
.find(|f| f["id"] == "top-dangling")
.expect("an unmeasured build still ships top-dangling");
assert_eq!(f["verdict"], "undecidable", "the card cannot decide it");
assert_eq!(f["observed"]["outcome"], "empty", "the run can");
assert_eq!(f["observed"]["rows"], 0);
let (_measured_fixture, measured) = carded(true, &[]);
let card = common::json(common::rete().arg("card").arg(&measured).arg("--json"));
assert!(
!card["queries"]
.as_array()
.unwrap()
.iter()
.any(|q| q["id"] == "top-dangling"),
"a measured build must not ship the query it measured at zero rows"
);
let dropped = card["build"]["dropped_queries"].as_array().unwrap();
let d = dropped
.iter()
.find(|d| d["id"] == "top-dangling")
.expect("the drop is recorded in the build record");
assert!(d["why"].as_str().unwrap().contains("0 rows"), "{d}");
assert!(
d["contradicts_claim"].is_null(),
"top-dangling declares itself undecidable — a measured zero is news, not a defect"
);
}
#[test]
fn measuring_a_card_document_is_refused() {
let (fixture, out) = carded(false, &[]);
let card = common::rete()
.arg("card")
.arg(&out)
.arg("--json")
.output()
.unwrap()
.stdout;
let doc = fixture.write("card.json", card);
common::rete()
.arg("card-audit")
.arg(&doc)
.assert()
.success(); common::rete()
.arg("card-audit")
.arg(&doc)
.arg("--measure")
.assert()
.failure()
.stderr(predicate::str::contains("--measure needs the .rete file"));
}