const SEMANTIC_PIPELINE_SOURCES: &[(&str, &str)] = &[
("model.rs", include_str!("model.rs")),
("planning/dag.rs", include_str!("planning/dag.rs")),
(
"planning/dag_input.rs",
include_str!("planning/dag_input.rs"),
),
("planning/dag_join.rs", include_str!("planning/dag_join.rs")),
(
"planning/dag_pipeline.rs",
include_str!("planning/dag_pipeline.rs"),
),
(
"planning/definition_trace.rs",
include_str!("planning/definition_trace.rs"),
),
(
"planning/module_view.rs",
include_str!("planning/module_view.rs"),
),
(
"structured/ast_adapter.rs",
include_str!("structured/ast_adapter.rs"),
),
(
"structured/control_flow.rs",
include_str!("structured/control_flow.rs"),
),
(
"structured/definition_module.rs",
include_str!("structured/definition_module.rs"),
),
("structured/merge.rs", include_str!("structured/merge.rs")),
("structured/policy.rs", include_str!("structured/policy.rs")),
(
"structured/tree_kernel.rs",
include_str!("structured/tree_kernel.rs"),
),
(
"structured/observer.rs",
include_str!("structured/observer.rs"),
),
("structured/trivia.rs", include_str!("structured/trivia.rs")),
(
"resolution/conflict_handler.rs",
include_str!("resolution/conflict_handler.rs"),
),
(
"resolution/conflict_view.rs",
include_str!("resolution/conflict_view.rs"),
),
(
"resolution/handler_registry.rs",
include_str!("resolution/handler_registry.rs"),
),
(
"output/materialize/structural.rs",
include_str!("output/materialize/structural.rs"),
),
(
"output/materialize/per_entry_noop.rs",
include_str!("output/materialize/per_entry_noop.rs"),
),
];
#[test]
fn shared_transform_pipeline_does_not_depend_on_culture_semantics() {
let sources = [
("transform.rs", include_str!("transform.rs")),
("transform/input.rs", include_str!("transform/input.rs")),
("transform/tree.rs", include_str!("transform/tree.rs")),
("analyze.rs", include_str!("analyze.rs")),
("commit.rs", include_str!("commit.rs")),
(
"planning/dag_merge.rs",
include_str!("planning/dag_merge.rs"),
),
(
"output/materialize.rs",
include_str!("output/materialize.rs"),
),
(
"output/materialize/analysis.rs",
include_str!("output/materialize/analysis.rs"),
),
(
"output/materialize/stale_detect.rs",
include_str!("output/materialize/stale_detect.rs"),
),
("structured/merge.rs", include_str!("structured/merge.rs")),
("structured/policy.rs", include_str!("structured/policy.rs")),
(
"structured/tree_kernel.rs",
include_str!("structured/tree_kernel.rs"),
),
];
for (path, source) in sources {
let production = source.split("mod tests {").next().unwrap();
assert_source_excludes(
path,
production,
&[
"CultureCorrespondence",
"CultureIndex",
"CultureAdaptations",
"::cultures::",
"common/cultures",
],
);
}
}
const ADDRESS_PATCH_DEPENDENCIES: &[&str] = &[
"ClausewitzPatch",
"PatchAddress",
"PatchConflict",
"PatchResolution",
"PatchMergeResult",
"PatchMergeStats",
"PatchBaselineDagProtocol",
"ModDiffCache",
"DagBaseCache",
"address_patch::",
];
const DAG_MERGE_FACADE_DEPENDENCIES: &[&str] = &[
"DagMergeEvaluation",
"MergeBackendId",
"ReferenceDag",
"compute_reference",
];
#[test]
fn semantic_pipeline_does_not_depend_on_address_patch_types() {
for (path, source) in SEMANTIC_PIPELINE_SOURCES {
assert_source_excludes(path, source, ADDRESS_PATCH_DEPENDENCIES);
}
let dag_merge_source = include_str!("planning/dag_merge.rs")
.split("// Tests")
.next()
.expect("semantic DAG merge production source");
assert_source_excludes(
"planning/dag_merge.rs",
dag_merge_source,
ADDRESS_PATCH_DEPENDENCIES,
);
assert_source_excludes(
"planning/dag_merge.rs",
dag_merge_source,
DAG_MERGE_FACADE_DEPENDENCIES,
);
assert_source_excludes(
"planning/module_view.rs",
include_str!("planning/module_view.rs"),
&["MergeBackendId", "MergeEvaluationKernel"],
);
assert_source_excludes(
"output/materialize/structural.rs",
include_str!("output/materialize/structural.rs"),
&["MergeBackendId", "MergeEvaluationKernel", "reference::"],
);
}
#[test]
fn backend_adapter_has_one_private_analysis_entrypoint() {
let seam = include_str!("backend/mod.rs");
assert!(seam.contains("pub(crate) trait MergeBackend"));
assert!(seam.contains("fn analyze(&self, request: BackendRequest"));
assert!(!seam.contains("fn merge_file"));
assert!(!seam.contains("fn merge_definition_module"));
assert_source_excludes(
"backend/gumtree_pcs_nway.rs",
include_str!("backend/gumtree_pcs_nway.rs"),
ADDRESS_PATCH_DEPENDENCIES,
);
}
#[test]
fn public_merge_facade_exposes_only_current_backend_names() {
let crate_facade = include_str!("../lib.rs");
let merge_facade = include_str!("mod.rs");
assert!(crate_facade.contains("pub mod merge;"));
assert!(
merge_facade.contains("pub use kernel_adapter::{MergeBackendDescriptor, MergeBackendId};")
);
assert_source_excludes(
"merge/mod.rs",
merge_facade,
&[
"MergeExecuteOptions",
"MergeExecutionResult",
"PreparedMerge",
"prepare_merge_with_options",
"MergeEvaluationKernel",
"MergeKernelMode",
"MergeReportKernel",
],
);
}
#[test]
fn commit_consumes_frozen_artifacts_without_reanalysis() {
let source = include_str!("commit.rs");
let commit = source
.split("\tpub fn commit(")
.nth(1)
.expect("AnalyzedMerge commit method")
.split("\n\t}\n}")
.next()
.expect("commit method body");
assert_source_excludes(
"AnalyzedMerge::commit",
commit,
&[
"backend_for",
"materialize_",
"freeze_path_plan",
"run_checks",
"resolve_input",
"cwt",
],
);
assert!(commit.contains("artifacts.copy_into"));
assert!(commit.contains("transaction.commit"));
assert!(include_str!("output/materialize/output_transaction.rs").contains("fn commit("));
}
fn assert_source_excludes(path: &str, source: &str, dependencies: &[&str]) {
for dependency in dependencies {
assert!(
!source.contains(dependency),
"{path} must not depend on forbidden symbol {dependency}"
);
}
}