Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions bench/deep-taxonomy/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ for DEPTH in $DEPTHS; do

# ---- 2. materialize the N3 forward closure; capture engine time + triple-count --------
# `reason <f> n3 n3 <out.nt>`: stderr carries `reasoned [N3]: <N> ground triples in closure in
# <X>s` (engine-internal timer, robust to machine load); stdout carries `<N> triples after n3
# reasoning`. We read the triple-count from stdout and the closure seconds from the stderr timer.
# <X>s` (engine-internal timer, robust to machine load) and, because an output file is given,
# `<N> triples after n3 reasoning` (#6466). We read both from stderr.
"$CLI" reason "$CORPUS" n3 n3 "$CLOSURE" >"$TMP/r.out" 2>"$TMP/r.err"
triples="$(grep -oE '[0-9]+ triples after n3 reasoning' "$TMP/r.out" | grep -oE '^[0-9]+' | head -1)"
triples="$(grep -oE '[0-9]+ triples after n3 reasoning' "$TMP/r.err" | grep -oE '^[0-9]+' | head -1)"
closure_s="$(grep -oE 'in [0-9.]+s' "$TMP/r.err" | head -1 | grep -oE '[0-9.]+' | head -1)"

# ---- 3. run query.rq over the closure (count mode, min-of-ITERS) ----------------------
Expand Down
8 changes: 4 additions & 4 deletions bench/owl-sameas/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ for TIER in $TIERS; do
CLOSURE="$CACHE/sameas-${TIER}-closure.nt"

# ---- 2. materialise the OWL-RL closure; capture engine time + triple-count ------------
# `reason <f> ntriples owl <out.nt>`: stdout carries `<N> triples after owl reasoning` (the
# deduplicated closure size); stderr carries the engine-internal `... in <X>s` timer (robust to
# machine load). We read the triple-count from stdout and the closure seconds from the stderr timer.
# `reason <f> ntriples owl <out.nt>`: because an output file is given, stderr carries both
# `<N> triples after owl reasoning` (the deduplicated closure size, #6466) and the
# engine-internal `... in <X>s` timer (robust to machine load). We read both from stderr.
"$CLI" reason "$CORPUS" ntriples owl "$CLOSURE" >"$TMP/r.out" 2>"$TMP/r.err"
triples="$(grep -oE '[0-9]+ triples after owl reasoning' "$TMP/r.out" | grep -oE '^[0-9]+' | head -1)"
triples="$(grep -oE '[0-9]+ triples after owl reasoning' "$TMP/r.err" | grep -oE '^[0-9]+' | head -1)"
closure_s="$(grep -oE 'in [0-9.]+s' "$TMP/r.err" | head -1 | grep -oE '[0-9.]+' | head -1)"

# ---- 3. run query.rq over the closure (count mode, min-of-ITERS) ----------------------
Expand Down
12 changes: 10 additions & 2 deletions crates/sparq-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1231,8 +1231,16 @@ fn cmd_reason(args: &[String]) {
return;
}
let g = load_with_reasoning(path, format, profile);
println!("{} triples after {profile} reasoning", g.len());
if let Some(out) = args.get(5) {
let out = args.get(5);
// With an output path the closure is the data product (and may itself be stdout, e.g.
// `/dev/stdout`), so the summary is a diagnostic on stderr; without one the count is
// the command's only result and stays on stdout (#6466).
if out.is_some() {
eprintln!("{} triples after {profile} reasoning", g.len());
} else {
println!("{} triples after {profile} reasoning", g.len());
}
if let Some(out) = out {
use std::io::Write;
let mut w = std::io::BufWriter::new(std::fs::File::create(out).unwrap_or_else(|e| {
eprintln!("create {out}: {e}");
Expand Down
16 changes: 16 additions & 0 deletions crates/sparq-cli/tests/cli_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,22 @@ fn reason_rdfs_reports_triple_count() {
let _ = std::fs::remove_dir_all(&dir);
}

/// #6466: with an output path, stdout may BE the closure (`/dev/stdout`), so the summary goes
/// to stderr and stdout carries only N-Triples.
#[cfg(unix)]
#[test]
fn reason_to_dev_stdout_writes_only_the_closure_to_stdout() {
let dir = scratch("reason-stdout");
let data = write(&dir, "data.nt", NT);
let (code, stdout, stderr) = run3(&["reason", s(&data), "ntriples", "rdfs", "/dev/stdout"]);
assert_eq!(code, 0, "stderr: {stderr}");
assert!(stderr.contains("triples after rdfs reasoning"), "stderr: {stderr}");
let lines: Vec<&str> = stdout.lines().filter(|l| !l.trim().is_empty()).collect();
assert!(!lines.is_empty(), "closure missing from stdout");
assert!(lines.iter().all(|l| l.ends_with(" .")), "non-N-Triples line on stdout: {stdout}");
let _ = std::fs::remove_dir_all(&dir);
}

#[test]
fn bench_emits_one_tsv_line_per_query_including_construct() {
let dir = scratch("bench");
Expand Down
4 changes: 2 additions & 2 deletions crates/sparq-cli/tests/datalog_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ fn reason_datalog_writes_the_stratified_closure() {
let out = dir.join("closure.nt");
let profile = format!("datalog:{}", s(&rules));

let (code, stdout, stderr) = run3(&["reason", s(&data), "ntriples", &profile, s(&out)]);
let (code, _stdout, stderr) = run3(&["reason", s(&data), "ntriples", &profile, s(&out)]);
assert_eq!(code, 0, "stderr: {stderr}");
// The stratification report: 3 rules across 3 strata (deg < Hub < Leaf).
assert!(stderr.contains("3 rule(s) in 3 stratum/strata"), "stderr: {stderr}");
assert!(stdout.contains("triples after"), "stdout: {stdout}");
assert!(stderr.contains("triples after"), "stderr: {stderr}");

let closure = std::fs::read_to_string(&out).expect("read closure");
// Aggregation: `a` has three edges.
Expand Down
4 changes: 2 additions & 2 deletions crates/sparq-cli/tests/el_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,9 @@ fn reason_subcommand_accepts_el() {
let ttl = write(&dir, "ex.ttl", EXISTENTIAL);
let out = dir.join("closure.nt");

let (code, stdout, stderr) = run3(&["reason", s(&ttl), "turtle", "el", s(&out)]);
let (code, _stdout, stderr) = run3(&["reason", s(&ttl), "turtle", "el", s(&out)]);
assert_eq!(code, 0, "stderr: {stderr}");
assert!(stdout.contains("triples after el reasoning"), "stdout: {stdout}");
assert!(stderr.contains("triples after el reasoning"), "stderr: {stderr}");
assert!(stderr.contains("classified [OWL 2 EL]"), "stderr: {stderr}");

let closure = std::fs::read_to_string(&out).expect("read closure");
Expand Down
Loading