use super::*;
use tempfile::TempDir;
fn target_pair() -> (TempDir, TempDir) {
(
TempDir::new().expect("project tempdir"),
TempDir::new().expect("workspace tempdir"),
)
}
#[tokio::test]
async fn prepare_store_creates_an_external_directory_outside_every_target() {
let external = TempDir::new().expect("external tempdir");
let (project, workspace) = target_pair();
let store = scoped_acceptance_root_for_test(external.path().to_path_buf(), async {
prepare_store(None, project.path(), workspace.path(), "add-a-thing")
})
.await
.expect("a root outside both targets resolves");
assert!(store.root().is_dir(), "the store must be created up front");
assert!(
store.root().starts_with(external.path()),
"the store must live under the resolved external root: {:?}",
store.root()
);
assert!(
!store.root().starts_with(project.path()) && !store.root().starts_with(workspace.path()),
"constitutional law 4: nothing Conflux owns may live inside a target"
);
assert!(
store
.root()
.file_name()
.is_some_and(|name| name == "add-a-thing"),
"the change is the leaf component: {:?}",
store.root()
);
for target in [project.path(), workspace.path()] {
assert_eq!(
std::fs::read_dir(target)
.expect("read target")
.filter_map(Result::ok)
.count(),
0,
"resolving a store must not create anything in {target:?}"
);
}
}
#[tokio::test]
async fn every_writer_shares_the_one_resolved_root() {
let external = TempDir::new().expect("external tempdir");
let (project, workspace) = target_pair();
let store = scoped_acceptance_root_for_test(external.path().to_path_buf(), async {
prepare_store(None, project.path(), workspace.path(), "add-a-thing")
})
.await
.expect("store resolves");
assert_eq!(store.evidence().root(), store.root());
assert_eq!(store.manifests().path(), store.root().join("manifest.json"));
assert_eq!(
store.evidence().artifact_path("focused-gate"),
store.root().join("gates/focused-gate.log")
);
}
#[tokio::test]
async fn an_unwritable_root_refuses_without_touching_the_target() {
let blocker = TempDir::new().expect("external tempdir");
let root = blocker.path().join("occupied");
std::fs::write(&root, b"not a directory").expect("write blocker");
let (project, workspace) = target_pair();
let refusal = scoped_acceptance_root_for_test(root, async {
prepare_store(None, project.path(), workspace.path(), "add-a-thing")
})
.await
.expect_err("an uncreatable root must fail closed");
assert_eq!(
refusal.category(),
crate::orchestration::acceptance::execution_manifest::AcceptanceHoldCategory::StatePathUnavailable
);
assert!(
refusal.evidence().contains("acceptance_store_"),
"the hold must name the resolver's own code: {}",
refusal.evidence()
);
assert!(
!workspace.path().join(".cflx").exists(),
"a state-path failure must never fall back into the target"
);
}
#[tokio::test]
async fn a_root_inside_the_target_is_refused() {
let (project, workspace) = target_pair();
let refusal = scoped_acceptance_root_for_test(workspace.path().join("acceptance"), async {
prepare_store(None, project.path(), workspace.path(), "add-a-thing")
})
.await
.expect_err("a root inside the workspace must fail closed");
assert_eq!(
refusal.category(),
crate::orchestration::acceptance::execution_manifest::AcceptanceHoldCategory::StatePathUnavailable
);
assert!(
refusal
.evidence()
.contains("acceptance_store_inside_target"),
"{}",
refusal.evidence()
);
assert!(
!workspace.path().join("acceptance").exists(),
"refusal must happen before anything is created"
);
}
#[tokio::test]
async fn legacy_target_evidence_is_reported_and_left_alone() {
let external = TempDir::new().expect("external tempdir");
let (project, workspace) = target_pair();
let legacy = workspace.path().join(".cflx/verification-evidence");
std::fs::create_dir_all(&legacy).expect("create legacy dir");
std::fs::write(legacy.join(".gitignore"), "*\n").expect("write ignore");
std::fs::write(legacy.join("focused-gate.json"), b"{\"schema\":\"v1\"}")
.expect("write legacy record");
let refusal = scoped_acceptance_root_for_test(external.path().to_path_buf(), async {
prepare_store(None, project.path(), workspace.path(), "add-a-thing")
})
.await
.expect_err("legacy target evidence must fail closed");
assert_eq!(
refusal.category(),
crate::orchestration::acceptance::execution_manifest::AcceptanceHoldCategory::LegacyTargetEvidence
);
assert!(
refusal.evidence().contains(".cflx/verification-evidence"),
"the hold must name the path to clean up: {}",
refusal.evidence()
);
assert!(
legacy.join("focused-gate.json").is_file()
&& std::fs::read(legacy.join("focused-gate.json")).expect("read legacy")
== b"{\"schema\":\"v1\"}",
"legacy content must be left exactly as it was found"
);
assert!(legacy.join(".gitignore").is_file());
}
#[tokio::test]
async fn unrelated_ignored_paths_are_not_evaluated() {
let external = TempDir::new().expect("external tempdir");
let (project, workspace) = target_pair();
std::fs::create_dir_all(workspace.path().join("target/debug")).expect("create build dir");
std::fs::create_dir_all(workspace.path().join("node_modules")).expect("create deps dir");
std::fs::write(
workspace.path().join(".gitignore"),
"target\nnode_modules\n",
)
.expect("write ignore");
scoped_acceptance_root_for_test(external.path().to_path_buf(), async {
prepare_store(None, project.path(), workspace.path(), "add-a-thing")
})
.await
.expect("unrelated ignored paths must not refuse anything");
}
#[tokio::test]
async fn clearing_a_store_removes_only_the_external_directory() {
let external = TempDir::new().expect("external tempdir");
let (project, workspace) = target_pair();
std::fs::write(workspace.path().join("deliverable.rs"), "fn main() {}\n")
.expect("write deliverable");
let store = scoped_acceptance_root_for_test(external.path().to_path_buf(), async {
prepare_store(None, project.path(), workspace.path(), "add-a-thing")
})
.await
.expect("store resolves");
std::fs::create_dir_all(store.root().join("gates")).expect("create gates");
std::fs::write(store.root().join("gates/focused-gate.log"), b"output").expect("write log");
store.clear();
assert!(!store.root().exists(), "the cache directory is removed");
assert!(
workspace.path().join("deliverable.rs").is_file(),
"clearing out-of-worktree state must not modify the target worktree"
);
}
#[tokio::test]
async fn resolution_is_deterministic_and_isolated_per_change() {
let external = TempDir::new().expect("external tempdir");
let (project, workspace) = target_pair();
let (first, again, other_change) =
scoped_acceptance_root_for_test(external.path().to_path_buf(), async {
(
prepare_store(None, project.path(), workspace.path(), "alpha")
.expect("alpha resolves")
.root()
.to_path_buf(),
prepare_store(None, project.path(), workspace.path(), "alpha")
.expect("alpha resolves again")
.root()
.to_path_buf(),
prepare_store(None, project.path(), workspace.path(), "beta")
.expect("beta resolves")
.root()
.to_path_buf(),
)
})
.await;
assert_eq!(first, again);
assert_ne!(first, other_change);
}
#[tokio::test]
async fn an_unsafe_change_id_is_refused_before_anything_is_created() {
let external = TempDir::new().expect("external tempdir");
let (project, workspace) = target_pair();
let refusal = scoped_acceptance_root_for_test(external.path().to_path_buf(), async {
prepare_store(None, project.path(), workspace.path(), "../escape")
})
.await
.expect_err("a traversing change id must fail closed");
assert!(refusal
.evidence()
.contains("acceptance_store_unsafe_component"));
assert_eq!(
std::fs::read_dir(external.path())
.expect("read external root")
.filter_map(Result::ok)
.count(),
0,
"nothing may be created for a refused identifier"
);
}