use std::collections::HashSet;
use super::concurrent::CodeGraph;
use super::node::NodeId;
#[cfg(any(debug_assertions, test))]
pub fn assert_publish_bijection(graph: &CodeGraph) {
graph.assert_bucket_bijection();
assert_losers_have_cleared_metadata(graph);
}
#[cfg(any(debug_assertions, test))]
fn assert_losers_have_cleared_metadata(graph: &CodeGraph) {
for (node_id, entry) in graph.nodes().iter() {
if !entry.is_unified_loser() {
continue;
}
assert!(
entry.qualified_name.is_none(),
"publish-boundary invariant: unified loser slot {} has qualified_name set; \
`merge_node_into` must clear qualified_name",
node_id.index()
);
assert!(
entry.signature.is_none(),
"publish-boundary invariant: unified loser slot {} has signature set; \
`merge_node_into` must clear signature (Gate 0d iter-2 blocker)",
node_id.index()
);
assert!(
entry.body_hash.is_none(),
"publish-boundary invariant: unified loser slot {} has body_hash set; \
`merge_node_into` must clear body_hash (Gate 0d iter-2 blocker)",
node_id.index()
);
assert!(
entry.doc.is_none(),
"publish-boundary invariant: unified loser slot {} has doc set; \
`merge_node_into` must clear doc",
node_id.index()
);
assert!(
entry.visibility.is_none(),
"publish-boundary invariant: unified loser slot {} has visibility set; \
`merge_node_into` must clear visibility",
node_id.index()
);
}
}
#[cfg(not(any(debug_assertions, test)))]
#[inline(always)]
pub fn assert_publish_bijection(_graph: &CodeGraph) {}
#[cfg(any(debug_assertions, test))]
pub fn assert_publish_invariants(graph: &CodeGraph, drained: &HashSet<NodeId>) {
graph.assert_bucket_bijection();
graph.assert_no_tombstone_residue_for(drained);
}
#[cfg(not(any(debug_assertions, test)))]
#[inline(always)]
pub fn assert_publish_invariants(_graph: &CodeGraph, _drained: &HashSet<NodeId>) {}
#[cfg(test)]
mod tests {
use super::*;
use crate::graph::unified::concurrent::CodeGraph;
use crate::graph::unified::file::FileId;
use crate::graph::unified::node::NodeKind;
use crate::graph::unified::storage::NodeEntry;
fn seeded_two_file_graph() -> (CodeGraph, super::NodeId, super::NodeId, FileId, FileId) {
let mut graph = CodeGraph::new();
let file_a = FileId::new(1);
let file_b = FileId::new(2);
let sym = graph.strings_mut().intern("sym").expect("intern");
let (node_a, node_b);
{
let arena = graph.nodes_mut();
node_a = arena
.alloc(NodeEntry::new(NodeKind::Function, sym, file_a))
.expect("alloc a");
node_b = arena
.alloc(NodeEntry::new(NodeKind::Struct, sym, file_b))
.expect("alloc b");
}
graph.files_mut().record_node(file_a, node_a);
graph.files_mut().record_node(file_b, node_b);
(graph, node_a, node_b, file_a, file_b)
}
#[test]
fn publish_invariants_pass_on_clean_graph_with_empty_drained() {
let (graph, _, _, _, _) = seeded_two_file_graph();
let drained: HashSet<NodeId> = HashSet::new();
assert_publish_invariants(&graph, &drained);
}
#[test]
fn publish_invariants_pass_on_fresh_empty_graph() {
let graph = CodeGraph::new();
let drained: HashSet<NodeId> = HashSet::new();
assert_publish_invariants(&graph, &drained);
}
#[test]
#[should_panic(expected = "misfiled")]
fn publish_invariants_route_bijection_panic() {
let (mut graph, node_a, _node_b, file_a, file_b) = seeded_two_file_graph();
let _ = graph.files_mut().take_nodes(file_a);
graph.files_mut().record_node(file_b, node_a);
let drained: HashSet<NodeId> = HashSet::new();
assert_publish_invariants(&graph, &drained);
}
#[test]
#[should_panic(expected = "still in NodeArena")]
fn publish_invariants_route_residue_panic() {
let (graph, node_a, _node_b, _file_a, _file_b) = seeded_two_file_graph();
let mut drained: HashSet<NodeId> = HashSet::new();
drained.insert(node_a);
assert_publish_invariants(&graph, &drained);
}
#[test]
fn publish_bijection_passes_on_clean_graph() {
let (graph, _, _, _, _) = seeded_two_file_graph();
assert_publish_bijection(&graph);
}
#[test]
fn publish_bijection_passes_on_fresh_empty_graph() {
let graph = CodeGraph::new();
assert_publish_bijection(&graph);
}
#[test]
#[should_panic(expected = "misfiled")]
fn publish_bijection_catches_misfiled_node() {
let (mut graph, node_a, _node_b, file_a, file_b) = seeded_two_file_graph();
let _ = graph.files_mut().take_nodes(file_a);
graph.files_mut().record_node(file_b, node_a);
assert_publish_bijection(&graph);
}
}