use std::process::Command;
fn scc_bin() -> std::path::PathBuf {
std::env::var("SCC_BIN")
.map(std::path::PathBuf::from)
.unwrap_or_else(|_| {
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../target/debug/scc")
})
}
fn run(dir: &std::path::Path, args: &[&str]) -> String {
let out = Command::new(scc_bin())
.args(args)
.current_dir(dir)
.output()
.expect("spawn scc");
assert!(
out.status.success(),
"`scc {}` failed:\n{}",
args.join(" "),
String::from_utf8_lossy(&out.stderr)
);
String::from_utf8_lossy(&out.stdout).into_owned()
}
fn setup_fixture() -> tempfile::TempDir {
let dir = tempfile::tempdir().unwrap();
let root = dir.path();
std::fs::create_dir_all(root.join("src")).unwrap();
std::fs::write(
root.join("src/lib.rs"),
"pub fn alpha() -> u32 { 1 }\n\
pub fn beta() -> u32 { 2 }\n\
pub fn gamma() -> u32 { 3 }\n\
pub fn delta() -> u32 { 4 }\n\
pub fn epsilon() -> u32 { 5 }\n\
pub fn zeta() -> u32 { 6 }\n",
)
.unwrap();
run(root, &["init"]);
run(root, &["index", "--quiet"]);
dir
}
fn ledger_visible_blob(dir: &std::path::Path) -> String {
let store = scc_store::Store::open(&dir.join(".scc").join("scc.db"), dir).unwrap();
let (syms, files, comps, flows) =
scc_context::context_ledger::ContextLedgerStore::new(&store).visible_ids();
let mut all = String::new();
for id in syms.iter().chain(files.iter()).chain(comps.iter()).chain(flows.iter()) {
all.push_str(&id.to_lowercase());
all.push('\n');
}
all
}
const SYMS: [&str; 6] = ["alpha", "beta", "gamma", "delta", "epsilon", "zeta"];
#[test]
fn task_ledger_records_only_what_survived_the_hard_cap() {
let dir = setup_fixture();
let root = dir.path();
let first = run(root, &["context", "task", "use alpha and beta"]);
let blob = ledger_visible_blob(root);
for sym in SYMS {
if blob.contains(sym) {
assert!(
first.contains(sym),
"ledger recorded symbol {sym} but the task artifact dropped it (§53)"
);
}
}
assert!(
!blob.trim().is_empty(),
"ledger must record the ids actually shown (§53: only visible entries)"
);
let second = run(root, &["context", "task", "use zeta and epsilon"]);
assert!(second.contains("TASK"), "second pack must render: {second}");
}
#[test]
fn startup_ledger_omits_budget_dropped_entries() {
let dir = setup_fixture();
let root = dir.path();
let out = run(root, &["context", "startup", "--budget", "200"]);
assert!(
!out.contains("BUDGET OVERFLOW"),
"no overflow escape hatch: the artifact must fit the hard max"
);
let est = out.chars().count().div_ceil(4);
assert!(
est <= 700,
"startup artifact must fit the hard max: ~{est} > 700"
);
let blob = ledger_visible_blob(root);
for sym in SYMS {
if blob.contains(sym) {
assert!(
out.contains(sym),
"ledger recorded {sym} but the startup artifact dropped it (§53)"
);
}
}
}
#[test]
fn incremental_refresh_reflects_edits_and_deletions() {
let dir = setup_fixture();
let root = dir.path();
let before = run(root, &["context", "task", "all functions"]);
assert!(before.contains("alpha"), "baseline must include alpha");
assert!(!before.contains("omega"), "omega must not exist yet");
let lib = root.join("src/lib.rs");
let text = std::fs::read_to_string(&lib).unwrap();
std::fs::write(
&lib,
text.replace(
"pub fn zeta() -> u32 { 6 }",
"pub fn zeta() -> u32 { 6 }\npub fn omega() -> u32 { 7 }",
),
)
.unwrap();
run(root, &["index", "--paths", "src/lib.rs", "--quiet"]);
let after = run(root, &["context", "task", "all functions"]);
assert!(
after.contains("omega"),
"context after incremental refresh must reflect the edit (§54): {after}"
);
std::fs::write(
&lib,
"pub fn alpha() -> u32 { 1 }\npub fn omega() -> u32 { 7 }\n",
)
.unwrap();
run(root, &["index", "--paths", "src/lib.rs", "--quiet"]);
let after_del = run(root, &["context", "task", "all functions"]);
assert!(
!after_del.contains("zeta()"),
"deleted symbol must not appear as current truth (§54): {after_del}"
);
assert!(
after_del.contains("omega"),
"surviving symbol still served: {after_del}"
);
}