use swarm_engine_core::exploration::map::{
ExplorationMap, GraphMap, HierarchicalMap, MapNodeState,
};
#[derive(Debug, Clone, PartialEq)]
enum NodeType {
Search { query: String },
File { path: String },
Dir { path: String },
}
impl NodeType {
fn key(&self) -> String {
match self {
NodeType::Search { query } => format!("search:{}", query),
NodeType::File { path } => format!("file:{}", path),
NodeType::Dir { path } => format!("dir:{}", path),
}
}
}
#[derive(Debug, Clone, PartialEq)]
enum EdgeType {
Grep,
List,
}
#[test]
fn test_exploration_basic_flow() {
let mut map: GraphMap<NodeType, EdgeType, MapNodeState> = GraphMap::new();
let key_fn = |n: &NodeType| n.key();
let root = map
.create_root_if_absent(
NodeType::Search {
query: "auth".to_string(),
},
MapNodeState::Open,
key_fn,
)
.into_inner();
assert_eq!(map.frontiers().len(), 1);
let file1 = map
.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::File {
path: "src/auth.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let dir1 = map
.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::Dir {
path: "src/auth/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
map.set_state(root, MapNodeState::Closed);
assert_eq!(map.frontiers().len(), 2);
map.set_state(file1, MapNodeState::Closed);
assert_eq!(map.frontiers().len(), 1);
let file2 = map
.add_child_if_absent(
dir1,
EdgeType::List,
NodeType::File {
path: "src/auth/mod.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let file3 = map
.add_child_if_absent(
dir1,
EdgeType::List,
NodeType::File {
path: "src/auth/login.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
map.set_state(dir1, MapNodeState::Closed);
assert_eq!(map.frontiers().len(), 2);
let dup_result = map.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::File {
path: "src/auth.rs".to_string(),
},
MapNodeState::Open,
key_fn,
);
assert!(dup_result.unwrap().is_already_exists());
assert_eq!(map.node_count(), 5);
map.set_state(file2, MapNodeState::Closed);
map.set_state(file3, MapNodeState::Closed);
assert!(map.frontiers().is_empty());
assert_eq!(map.closed_nodes().len(), 5);
}
#[test]
fn test_exploration_deep_hierarchy() {
let mut map: GraphMap<NodeType, EdgeType, MapNodeState> = GraphMap::new();
let key_fn = |n: &NodeType| n.key();
let root = map
.create_root_if_absent(
NodeType::Search {
query: "deep".to_string(),
},
MapNodeState::Open,
key_fn,
)
.into_inner();
let dir1 = map
.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::Dir {
path: "a/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
map.set_state(root, MapNodeState::Closed);
let dir2 = map
.add_child_if_absent(
dir1,
EdgeType::List,
NodeType::Dir {
path: "a/b/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
map.set_state(dir1, MapNodeState::Closed);
let dir3 = map
.add_child_if_absent(
dir2,
EdgeType::List,
NodeType::Dir {
path: "a/b/c/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
map.set_state(dir2, MapNodeState::Closed);
let file = map
.add_child_if_absent(
dir3,
EdgeType::List,
NodeType::File {
path: "a/b/c/target.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
map.set_state(dir3, MapNodeState::Closed);
assert_eq!(map.depth(root), 0);
assert_eq!(map.depth(dir1), 1);
assert_eq!(map.depth(dir2), 2);
assert_eq!(map.depth(dir3), 3);
assert_eq!(map.depth(file), 4);
assert_eq!(map.parent(file), Some(dir3));
assert_eq!(map.parent(dir3), Some(dir2));
assert_eq!(map.parent(dir2), Some(dir1));
assert_eq!(map.parent(dir1), Some(root));
assert_eq!(map.parent(root), None);
assert_eq!(map.frontiers(), vec![file]);
map.set_state(file, MapNodeState::Closed);
assert!(map.frontiers().is_empty());
}
#[test]
fn test_exploration_parallel_workers() {
let mut map: GraphMap<NodeType, EdgeType, MapNodeState> = GraphMap::new();
let key_fn = |n: &NodeType| n.key();
let root = map
.create_root_if_absent(
NodeType::Search {
query: "parallel".to_string(),
},
MapNodeState::Open,
key_fn,
)
.into_inner();
let result_a = map.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::File {
path: "auth.rs".to_string(),
},
MapNodeState::Open,
key_fn,
);
let file_a = result_a.unwrap();
assert!(file_a.is_added());
let result_b = map.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::File {
path: "auth.rs".to_string(),
},
MapNodeState::Open,
key_fn,
);
let file_b = result_b.unwrap();
assert!(file_b.is_already_exists());
assert_eq!(file_a.into_inner(), file_b.into_inner());
assert_eq!(map.node_count(), 2);
}
#[test]
fn test_exploration_cycle_prevention() {
let mut map: GraphMap<NodeType, EdgeType, MapNodeState> = GraphMap::new();
let key_fn = |n: &NodeType| n.key();
let root = map
.create_root_if_absent(
NodeType::Search {
query: "cycle".to_string(),
},
MapNodeState::Open,
key_fn,
)
.into_inner();
let dir_a = map
.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::Dir {
path: "dir_a/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
map.set_state(root, MapNodeState::Closed);
let dir_b = map
.add_child_if_absent(
dir_a,
EdgeType::List,
NodeType::Dir {
path: "dir_b/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
map.set_state(dir_a, MapNodeState::Closed);
let cycle_result = map.add_child_if_absent(
dir_b,
EdgeType::List,
NodeType::Dir {
path: "dir_a/".to_string(),
},
MapNodeState::Open,
key_fn,
);
assert!(cycle_result.unwrap().is_already_exists());
map.set_state(dir_b, MapNodeState::Closed);
assert_eq!(map.node_count(), 3);
assert!(map.frontiers().is_empty());
}
#[test]
fn test_cascade_down() {
let mut map: GraphMap<NodeType, EdgeType, MapNodeState> = GraphMap::new();
let key_fn = |n: &NodeType| n.key();
let root = map
.create_root_if_absent(
NodeType::Search {
query: "test".to_string(),
},
MapNodeState::Open,
key_fn,
)
.into_inner();
let dir1 = map
.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::Dir {
path: "dir1/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let dir2 = map
.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::Dir {
path: "dir2/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let file1 = map
.add_child_if_absent(
dir1,
EdgeType::List,
NodeType::File {
path: "dir1/a.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let file2 = map
.add_child_if_absent(
dir1,
EdgeType::List,
NodeType::File {
path: "dir1/b.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
assert_eq!(map.frontiers().len(), 5);
let closed = map.cascade_down(dir1);
assert_eq!(closed.len(), 3); assert!(map.get(dir1).unwrap().state.is_closed());
assert!(map.get(file1).unwrap().state.is_closed());
assert!(map.get(file2).unwrap().state.is_closed());
assert!(map.get(root).unwrap().state.is_open());
assert!(map.get(dir2).unwrap().state.is_open());
assert_eq!(map.frontiers().len(), 2); }
#[test]
fn test_cascade_up() {
let mut map: GraphMap<NodeType, EdgeType, MapNodeState> = GraphMap::new();
let key_fn = |n: &NodeType| n.key();
let root = map
.create_root_if_absent(
NodeType::Search {
query: "test".to_string(),
},
MapNodeState::Open,
key_fn,
)
.into_inner();
let dir1 = map
.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::Dir {
path: "dir1/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let dir2 = map
.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::Dir {
path: "dir2/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let file1 = map
.add_child_if_absent(
dir1,
EdgeType::List,
NodeType::File {
path: "dir1/a.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let file2 = map
.add_child_if_absent(
dir1,
EdgeType::List,
NodeType::File {
path: "dir1/b.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let closed1 = map.close_with_cascade_up(file1);
assert_eq!(closed1, vec![file1]);
assert!(map.get(dir1).unwrap().state.is_open());
let closed2 = map.close_with_cascade_up(file2);
assert_eq!(closed2.len(), 2);
assert!(closed2.contains(&file2));
assert!(closed2.contains(&dir1));
assert!(map.get(dir1).unwrap().state.is_closed());
assert!(map.get(root).unwrap().state.is_open());
let closed3 = map.close_with_cascade_up(dir2);
assert_eq!(closed3.len(), 2);
assert!(closed3.contains(&dir2));
assert!(closed3.contains(&root));
assert!(map.get(root).unwrap().state.is_closed());
assert!(map.frontiers().is_empty());
}
#[test]
fn test_exploration_with_up_cascade() {
let mut map: GraphMap<NodeType, EdgeType, MapNodeState> = GraphMap::new();
let key_fn = |n: &NodeType| n.key();
let root = map
.create_root_if_absent(
NodeType::Search {
query: "auth".to_string(),
},
MapNodeState::Open,
key_fn,
)
.into_inner();
let dir1 = map
.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::Dir {
path: "auth/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let dir2 = map
.add_child_if_absent(
root,
EdgeType::Grep,
NodeType::Dir {
path: "user/".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let file1 = map
.add_child_if_absent(
dir1,
EdgeType::List,
NodeType::File {
path: "auth/mod.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let file2 = map
.add_child_if_absent(
dir1,
EdgeType::List,
NodeType::File {
path: "auth/login.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
let file3 = map
.add_child_if_absent(
dir2,
EdgeType::List,
NodeType::File {
path: "user/mod.rs".to_string(),
},
MapNodeState::Open,
key_fn,
)
.unwrap()
.into_inner();
assert_eq!(map.node_count(), 6);
assert_eq!(map.frontiers().len(), 6);
let c1 = map.close_with_cascade_up(file1);
assert_eq!(c1, vec![file1]);
let c2 = map.close_with_cascade_up(file2);
assert!(c2.contains(&file2));
assert!(c2.contains(&dir1));
let c3 = map.close_with_cascade_up(file3);
assert!(c3.contains(&file3));
assert!(c3.contains(&dir2));
assert!(c3.contains(&root));
assert!(map.frontiers().is_empty());
assert_eq!(map.closed_nodes().len(), 6);
}