use itertools::Itertools;
use proptest::{arbitrary::any, proptest, sample::subsequence};
use raphtory::test_utils::{build_graph, build_graph_strat};
use raphtory::{
db::graph::{
edge::EdgeView,
graph::{assert_graph_equal, assert_persistent_materialize_graph_equal},
views::deletion_graph::PersistentGraph,
},
prelude::*,
test_storage,
};
use raphtory_api::core::{
entities::GID,
storage::timeindex::{AsTime, EventTime},
};
use raphtory_storage::mutation::addition_ops::InternalAdditionOps;
use std::ops::Range;
#[test]
fn test_nodes() {
let g = PersistentGraph::new();
let edges = [
(0, 1, 2, "assigned"),
(1, 1, 3, "assigned"),
(2, 4, 2, "has"),
(3, 4, 2, "has"),
(4, 5, 2, "blocks"),
(5, 4, 5, "has"),
(6, 6, 5, "assigned"),
];
for (time, src, dst, layer) in edges {
g.add_edge(time, src, dst, [("added", Prop::I64(0))], Some(layer))
.unwrap();
}
let nodes = g
.window(0, 1701786285758)
.layers(vec!["assigned", "has", "blocks"])
.unwrap()
.nodes()
.into_iter()
.map(|vv| vv.name())
.collect_vec();
assert_eq!(nodes, vec!["1", "2", "3", "4", "5", "6"]);
let nodes = g
.at(1701786285758)
.layers(vec!["assigned", "has", "blocks"])
.unwrap()
.nodes()
.into_iter()
.map(|vv| vv.name())
.collect_vec();
assert_eq!(nodes, vec!["1", "2", "3", "4", "5", "6"]);
}
#[test]
fn test_edge_deletions() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 1, [("added", Prop::I64(0))], None)
.unwrap();
g.delete_edge(10, 0, 1, None).unwrap();
assert_eq!(
g.edges().id().collect::<Vec<_>>(),
vec![(GID::U64(0), GID::U64(1))]
);
assert_eq!(
g.window(1, 2).edges().id().collect::<Vec<_>>(),
vec![(GID::U64(0), GID::U64(1))]
);
assert_eq!(g.window(1, 2).count_edges(), 1);
assert_eq!(g.window(11, 12).count_edges(), 0);
assert_eq!(
g.window(1, 2)
.edge(0, 1)
.unwrap()
.properties()
.get("added")
.unwrap_i64(),
0
);
assert!(g.window(11, 12).edge(0, 1).is_none());
assert_eq!(
g.window(1, 2)
.edge(0, 1)
.unwrap()
.properties()
.temporal()
.get("added")
.unwrap()
.iter()
.map(|(t, p)| (t.t(), p))
.collect_vec(),
vec![(1, Prop::I64(0))]
);
assert_eq!(g.window(1, 2).node(0).unwrap().out_degree(), 1)
}
#[test]
fn test_window_semantics() {
let g = PersistentGraph::new();
g.add_edge(1, 1, 2, [("test", "test")], None).unwrap();
g.delete_edge(10, 1, 2, None).unwrap();
assert_eq!(g.count_edges(), 1);
assert_eq!(g.at(12).count_edges(), 0);
assert_eq!(g.at(11).count_edges(), 0);
assert_eq!(g.at(10).count_edges(), 0);
assert_eq!(g.at(9).count_edges(), 1);
assert_eq!(g.window(5, 9).count_edges(), 1);
assert_eq!(g.window(5, 10).count_edges(), 1);
assert_eq!(g.window(5, 11).count_edges(), 1);
assert_eq!(g.window(10, 12).count_edges(), 0);
assert_eq!(g.before(10).count_edges(), 1);
assert_eq!(g.after(10).count_edges(), 0);
}
#[test]
fn test_timestamps() {
let g = PersistentGraph::new();
let e = g.add_edge(1, 1, 2, [("test", "test")], None).unwrap();
assert_eq!(e.earliest_time().unwrap(), 1); assert_eq!(e.latest_time().map(|t| t.t()), Some(1)); g.delete_edge(10, 1, 2, None).unwrap();
assert_eq!(e.latest_time().unwrap(), 10);
g.delete_edge(10, 3, 4, None).unwrap();
let e = g.edge(3, 4).unwrap();
assert_eq!(e.earliest_time().unwrap(), 10); assert_eq!(e.latest_time().unwrap(), 10);
g.add_edge(1, 3, 4, [("test", "test")], None).unwrap();
assert_eq!(e.latest_time().unwrap(), 10);
assert_eq!(e.earliest_time().unwrap(), 1); }
#[test]
fn test_materialize_only_deletion() {
let g = PersistentGraph::new();
g.delete_edge(1, 1, 2, None).unwrap();
g.add_edge(2, 1, 2, NO_PROPS, None).unwrap();
g.delete_edge(5, 1, 2, None).unwrap();
g.delete_edge(10, 1, 2, None).unwrap();
assert_eq!(
g.window(0, 11).count_temporal_edges(),
g.count_temporal_edges()
);
assert_graph_equal(&g.materialize().unwrap(), &g);
}
#[test]
fn materialize_prop_test() {
proptest!(|(graph_f in build_graph_strat(10, 10, true))| {
let g = PersistentGraph::from(build_graph(&graph_f));
let gm = g.materialize().unwrap();
assert_graph_equal(&g, &gm);
})
}
#[test]
fn materialize_window_prop_test() {
proptest!(|(graph_f in build_graph_strat(10, 10, true), w in any::<Range<i64>>())| {
let g = PersistentGraph::from(build_graph(&graph_f));
let gw = g.window(w.start, w.end);
let gmw = gw.materialize().unwrap();
assert_persistent_materialize_graph_equal(&gw, &gmw);
})
}
#[test]
fn test_multilayer_window() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 0, NO_PROPS, None).unwrap();
g.add_edge(10, 0, 0, NO_PROPS, Some("a")).unwrap();
println!("all: {g:?}");
let gw = g.window(1, 10);
println!("windowed nodes: {:?}", gw.nodes());
let gm = gw.materialize().unwrap();
println!("materialized: {:?}", gm);
assert_eq!(gw.valid_layers("a").count_nodes(), 0);
assert_eq!(gm.valid_layers("a").count_nodes(), 0);
let expected = PersistentGraph::new();
expected.add_edge(1, 0, 0, NO_PROPS, None).unwrap();
expected.resolve_layer(Some("a")).unwrap();
println!("expected: {:?}", expected);
assert_persistent_materialize_graph_equal(&gw, &expected);
assert_persistent_materialize_graph_equal(&gw, &gm);
}
#[test]
fn test_multilayer_window2() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 0, NO_PROPS, None).unwrap();
g.add_edge(0, 0, 0, NO_PROPS, Some("a")).unwrap();
let gw = g.window(1, i64::MAX);
let gm = gw.materialize().unwrap();
println!("original: {g:?}");
assert_eq!(g.default_layer().count_nodes(), 1);
println!("materialized: {gm:?}");
assert_eq!(gm.default_layer().count_nodes(), 1);
assert_persistent_materialize_graph_equal(&gw, &gm.clone().into_persistent().unwrap());
assert_persistent_materialize_graph_equal(&gw, &gm);
}
#[test]
fn test_deletion_at_window_start() {
let g = PersistentGraph::new();
g.add_edge(2, 0, 1, NO_PROPS, None).unwrap();
g.delete_edge(0, 0, 1, None).unwrap();
let gw = g.window(0, 1);
assert!(gw.is_empty());
let gw = g.window(0, 3);
assert_eq!(gw.node(0).unwrap().earliest_time().unwrap().t(), 2);
assert_eq!(gw.node(1).unwrap().earliest_time().unwrap().t(), 2);
}
#[test]
fn materialize_window_layers_prop_test() {
proptest!(|(graph_f in build_graph_strat(10, 10, true), w in any::<Range<i64>>(), l in subsequence(&["a", "b"], 0..=2))| {
let g = PersistentGraph::from(build_graph(&graph_f));
let glw = g.valid_layers(l).window(w.start, w.end);
let gmlw = glw.materialize().unwrap();
assert_persistent_materialize_graph_equal(&glw, &gmlw);
})
}
#[test]
fn test_materialize_deleted_edge() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 1, NO_PROPS, None).unwrap();
g.delete_edge(1, 0, 1, None).unwrap();
g.delete_edge(5, 0, 1, None).unwrap();
let gw = g.window(2, 10);
let gm = gw.materialize().unwrap();
assert_graph_equal(&gw, &gm);
}
#[test]
fn test_addition_deletion_multilayer_window() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 0, NO_PROPS, Some("a")).unwrap();
g.delete_edge(0, 0, 0, None).unwrap();
let gw = g.window(0, 0).valid_layers("a");
let expected_gw = PersistentGraph::new();
expected_gw.resolve_layer(Some("a")).unwrap();
assert_graph_equal(&gw, &expected_gw);
let gwm = gw.materialize().unwrap();
assert_graph_equal(&gw, &gwm);
}
#[test]
fn materialize_broken_time() {
let g = PersistentGraph::new();
g.add_edge(
-7868307470600541330,
0,
0,
[("test", Prop::map([("x", "y")]))],
Some("a"),
)
.unwrap();
g.add_edge(
-8675512464616562592,
0,
0,
[("test", Prop::map([("z", "hi")]))],
None,
)
.unwrap();
g.edge(0, 0)
.unwrap()
.add_metadata([("other", "b")], None)
.unwrap();
let gw = g.window(-7549523977641994620, -995047120251067629);
assert_persistent_materialize_graph_equal(&gw, &gw.materialize().unwrap())
}
#[test]
fn test_materialize_window_start_before_node_add() {
let g = PersistentGraph::new();
g.add_node(-1, 0, [("test", "test")], None).unwrap();
g.add_node(5, 0, [("test", "blob")], None).unwrap();
g.add_edge(0, 0, 0, NO_PROPS, None).unwrap();
let gw = g.window(-5, 8);
let gmw = gw.materialize().unwrap();
assert_graph_equal(&gw, &gmw);
}
#[test]
fn test_materialize_edge_metadata() {
let g = PersistentGraph::new();
g.add_edge(0, 1, 2, NO_PROPS, Some("a")).unwrap();
let e = g.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
e.add_metadata([("test", "test")], None).unwrap();
g.delete_edge(1, 1, 2, None).unwrap();
let gw = g.after(1);
let gmw = gw.materialize().unwrap();
assert_persistent_materialize_graph_equal(&gw, &gmw);
}
#[test]
fn test_metadata_multiple_layers() {
let g = PersistentGraph::new();
g.add_edge(0, 1, 2, NO_PROPS, Some("a")).unwrap();
let e = g.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
e.add_metadata([("test", "test")], None).unwrap();
g.delete_edge(1, 1, 2, None).unwrap();
assert_eq!(
g.edge(1, 2).unwrap().metadata().as_vec(),
[("test".into(), Prop::map([("_default", "test")]))]
);
let gw = g.after(1);
assert!(gw
.edge(1, 2)
.unwrap()
.metadata()
.iter_filtered()
.next()
.is_none());
let g_before = g.before(1);
assert_eq!(
g_before.edge(1, 2).unwrap().metadata().as_vec(),
[("test".into(), Prop::map([("_default", "test")]))]
);
}
#[test]
fn test_materialize_window() {
let g = PersistentGraph::new();
g.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
g.delete_edge(10, 1, 2, None).unwrap();
let gm = g
.window(3, 5)
.materialize()
.unwrap()
.into_persistent()
.unwrap();
assert_persistent_materialize_graph_equal(&g.window(3, 5), &gm); }
#[test]
fn test_materialize_window_node_props() {
let g = Graph::new();
g.add_node(0, 1, [("test", "test")], None).unwrap();
test_storage!(&g, |g| {
let g = g.persistent_graph();
let wg = g.window(3, 5);
let mg = wg.materialize().unwrap();
assert_persistent_materialize_graph_equal(&wg, &mg);
});
}
#[test]
fn test_exploded_latest_time() {
let g = PersistentGraph::new();
let e = g.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
g.delete_edge(10, 1, 2, None).unwrap();
assert_eq!(e.latest_time().unwrap().t(), 10);
assert_eq!(
e.explode()
.latest_time()
.map(|t_opt| t_opt.map(|t| t.t()))
.collect_vec(),
vec![Some(10)]
);
}
#[test]
fn test_exploded_window() {
let g = PersistentGraph::new();
let e = g.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
for t in [5, 10, 15] {
e.add_updates(t, NO_PROPS, None).unwrap();
}
assert_eq!(
e.after(2).explode().time().flatten().collect_vec(),
[3, 5, 10, 15]
);
}
#[test]
fn test_edge_properties() {
let g = PersistentGraph::new();
let e = g.add_edge(0, 1, 2, [("test", "test")], None).unwrap();
assert_eq!(e.properties().get("test").unwrap_str(), "test");
e.delete(10, None).unwrap();
assert_eq!(e.properties().get("test").unwrap_str(), "test");
assert_eq!(e.at(10).properties().get("test"), None);
e.add_updates(11, [("test", "test11")], None).unwrap();
assert_eq!(
e.window(10, 12).properties().get("test").unwrap_str(),
"test11"
);
assert_eq!(
e.window(5, 12)
.properties()
.temporal()
.get("test")
.unwrap()
.iter()
.map(|(t, p)| (t.t(), p))
.collect_vec(),
vec![(5, Prop::str("test")), (11i64, Prop::str("test11"))],
);
}
#[test]
fn test_edge_history() {
let g = PersistentGraph::new();
let e = g.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
e.delete(5, None).unwrap();
e.add_updates(10, NO_PROPS, None).unwrap();
assert_eq!(e.history(), [0, 10]);
assert_eq!(e.after(1).history(), [10]);
assert!(e.window(1, 4).history().is_empty());
assert_eq!(
e.window(1, 4)
.explode()
.earliest_time()
.flatten()
.collect_vec(),
[1]
);
}
#[test]
fn test_ordering_of_addition_and_deletion() {
let g = PersistentGraph::new();
g.delete_edge(1, 1, 2, None).unwrap();
let e_1_2 = g.add_edge(1, 1, 2, [("test", "test")], None).unwrap();
let e_3_4 = g.add_edge(2, 3, 4, [("test", "test")], None).unwrap();
g.delete_edge(2, 3, 4, None).unwrap();
assert_eq!(e_1_2.at(0).properties().get("test"), None);
assert_eq!(e_1_2.at(1).properties().get("test").unwrap_str(), "test");
assert_eq!(e_1_2.at(2).properties().get("test").unwrap_str(), "test");
assert_eq!(e_3_4.at(0).properties().get("test"), None);
assert_eq!(e_3_4.at(2).properties().get("test"), None);
assert_eq!(e_3_4.at(3).properties().get("test"), None);
assert!(!g.window(0, 1).has_edge(1, 2));
assert!(!g.window(0, 2).has_edge(3, 4));
assert!(g.window(1, 2).has_edge(1, 2));
assert!(!g.window(2, 3).has_edge(3, 4)); assert!(!g.window(3, 4).has_edge(3, 4));
}
#[test]
fn test_deletions() {
let edges = [
(1, 1, 2),
(2, 1, 3),
(-1, 2, 1),
(0, 1, 1),
(7, 3, 2),
(1, 1, 1),
];
let g = PersistentGraph::new();
for (t, s, d) in edges.iter() {
g.add_edge(*t, *s, *d, NO_PROPS, None).unwrap();
}
g.delete_edge(10, edges[0].1, edges[0].2, None).unwrap();
for (t, s, d) in &edges {
assert!(g.at(*t).has_edge(*s, *d));
}
assert!(!g.after(10).has_edge(edges[0].1, edges[0].2));
for (_, s, d) in &edges[1..] {
assert!(g.after(10).has_edge(*s, *d));
}
assert_eq!(
g.edge(edges[0].1, edges[0].2)
.unwrap()
.explode()
.latest_time()
.map(|t_opt| t_opt.map(|t| t.t()))
.collect_vec(),
[Some(10)]
);
}
fn check_valid<'graph, G: GraphViewOps<'graph>>(e: &EdgeView<G>) {
assert!(e.is_valid());
assert!(!e.is_deleted());
assert!(e.graph.has_edge(e.src(), e.dst()));
assert!(e.graph.edge(e.src(), e.dst()).is_some());
}
fn check_deleted<'graph, G: GraphViewOps<'graph>>(e: &EdgeView<G>) {
assert!(!e.is_valid());
assert!(e.is_deleted());
let t = e.latest_time().map(|t| t.t()).unwrap_or(i64::MAX);
let g = e.graph.at(t); assert!(!g.has_edge(e.src(), e.dst()));
assert!(g.edge(e.src(), e.dst()).is_none());
}
#[test]
fn test_deletion_multiple_layers() {
let g = PersistentGraph::new();
g.add_edge(1, 1, 2, NO_PROPS, Some("1")).unwrap();
g.delete_edge(2, 1, 2, Some("2")).unwrap();
g.delete_edge(10, 1, 2, Some("1")).unwrap();
g.add_edge(10, 1, 2, NO_PROPS, Some("2")).unwrap();
let e = g.edge(1, 2).unwrap();
let e_layer_1 = e.layers("1").unwrap();
let e_layer_2 = e.layers("2").unwrap();
assert!(!g.at(0).has_edge(1, 2));
check_deleted(&e.at(0));
for t in 1..13 {
assert!(g.at(t).has_edge(1, 2));
check_valid(&e.at(t));
}
check_valid(&e);
check_deleted(&e_layer_1);
check_deleted(&e_layer_1.at(10));
check_valid(&e_layer_1.at(9));
check_valid(&e_layer_1.at(1));
check_deleted(&e_layer_1.at(0));
check_valid(&e_layer_2);
check_deleted(&e_layer_2.at(9));
check_valid(&e_layer_2.at(10));
}
#[test]
fn test_edge_is_valid() {
let g = PersistentGraph::new();
g.add_edge(1, 1, 2, NO_PROPS, None).unwrap();
let e = g.edge(1, 2).unwrap();
check_deleted(&e.before(1));
check_valid(&e.after(1));
check_valid(&e);
g.add_edge(2, 1, 2, NO_PROPS, Some("1")).unwrap();
check_valid(&e);
g.delete_edge(3, 1, 2, Some("1")).unwrap();
check_valid(&e);
check_deleted(&e.layers("1").unwrap());
check_deleted(&e.layers("1").unwrap().at(3));
check_deleted(&e.layers("1").unwrap().after(3));
check_valid(&e.layers("1").unwrap().before(3));
check_valid(&e.default_layer());
g.delete_edge(4, 1, 2, None).unwrap();
check_deleted(&e);
check_deleted(&e.layers("1").unwrap());
check_deleted(&e.default_layer());
g.add_edge(5, 1, 2, NO_PROPS, None).unwrap();
check_valid(&e);
check_valid(&e.default_layer());
check_deleted(&e.layers("1").unwrap());
}
#[test]
fn test_explode_multiple_layers() {
let g = PersistentGraph::new();
g.add_edge(0, 1, 2, NO_PROPS, Some("1")).unwrap();
g.add_edge(1, 1, 2, NO_PROPS, Some("2")).unwrap();
g.delete_edge(1, 1, 2, Some("1")).unwrap();
g.delete_edge(2, 1, 2, Some("2")).unwrap();
g.delete_edge(3, 1, 2, Some("3")).unwrap();
let e = g.edge(1, 2).unwrap();
assert_eq!(e.explode().iter().count(), 2);
assert_eq!(e.before(4).explode().iter().count(), 2);
assert_eq!(e.window(1, 3).explode().iter().count(), 1);
assert_eq!(e.window(2, 3).explode().iter().count(), 0);
}
#[test]
fn test_edge_latest_time() {
let g = PersistentGraph::new();
let e = g.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
e.delete(2, None).unwrap();
assert_eq!(e.at(2).earliest_time(), None);
assert_eq!(e.at(2).latest_time(), None);
assert!(e.at(2).is_deleted());
assert_eq!(e.latest_time().unwrap().t(), 2);
e.add_updates(4, NO_PROPS, None).unwrap();
assert_eq!(e.latest_time().unwrap().t(), 4);
assert_eq!(e.window(0, 3).latest_time().unwrap().t(), 2);
}
#[test]
fn test_node_property_semantics() {
let g = PersistentGraph::new();
let _v = g
.add_node(1, 1, [("test_prop", "test value")], None)
.unwrap();
let v = g
.add_node(11, 1, [("test_prop", "test value 2")], None)
.unwrap();
let v_from_graph = g.at(10).node(1).unwrap();
assert_eq!(v.properties().get("test_prop").unwrap_str(), "test value 2");
assert_eq!(
v.at(10).properties().get("test_prop").unwrap_str(),
"test value"
);
assert_eq!(
v.at(11).properties().get("test_prop").unwrap_str(),
"test value 2"
);
assert_eq!(
v_from_graph.properties().get("test_prop").unwrap_str(),
"test value"
);
assert_eq!(
v.before(11).properties().get("test_prop").unwrap_str(),
"test value"
);
assert_eq!(
v.properties()
.temporal()
.get("test_prop")
.unwrap()
.history(),
[1, 11]
);
assert_eq!(
v_from_graph
.properties()
.temporal()
.get("test_prop")
.unwrap()
.history(),
[10]
);
assert_eq!(v_from_graph.earliest_time().map(|t| t.t()), Some(10));
assert_eq!(v.earliest_time().map(|t| t.t()), Some(1));
assert_eq!(v.at(10).earliest_time().map(|t| t.t()), Some(10));
assert_eq!(v.at(10).latest_time().map(|t| t.t()), Some(10));
assert_eq!(v.latest_time().map(|t| t.t()), Some(11));
}
#[test]
fn test_event_graph() {
let pg = PersistentGraph::new();
pg.add_edge(0, 0, 1, [("added", Prop::I64(0))], None)
.unwrap();
pg.delete_edge(10, 0, 1, None).unwrap();
assert_eq!(
pg.edges().id().collect::<Vec<_>>(),
vec![(GID::U64(0), GID::U64(1))]
);
let g = pg.event_graph();
assert_eq!(
g.edges().id().collect::<Vec<_>>(),
vec![(GID::U64(0), GID::U64(1))]
);
}
#[test]
fn test_exploded_latest_time_deleted() {
let g = PersistentGraph::new();
g.add_edge(1, 1, 2, NO_PROPS, None).unwrap();
g.delete_edge(1, 1, 2, None).unwrap();
assert_eq!(
g.edge(1, 2)
.unwrap()
.explode()
.latest_time()
.map(|t_opt| t_opt.map(|t| t.t()))
.collect_vec(),
[Some(1)]
);
assert_eq!(
g.edge(1, 2)
.unwrap()
.explode()
.earliest_time()
.map(|t_opt| t_opt.map(|t| t.t()))
.collect_vec(),
[Some(1)]
)
}
#[test]
fn test_empty_window_has_no_nodes() {
let g = PersistentGraph::new();
g.add_node(1, 1, NO_PROPS, None).unwrap();
assert_eq!(g.window(2, 2).count_nodes(), 0);
assert_eq!(g.window(1, 1).count_nodes(), 0);
assert_eq!(g.window(0, 0).count_nodes(), 0);
}
#[test]
fn test_earliest_latest_time_window() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 0, NO_PROPS, None).unwrap();
assert_eq!(g.window(-1, 0).earliest_time(), None);
assert_eq!(g.window(-1, 0).latest_time(), None);
}
#[test]
fn test_node_earliest_time_window() {
let g = PersistentGraph::new();
g.add_edge(0, 1, 2, NO_PROPS, None).unwrap();
g.add_edge(4, 1, 3, NO_PROPS, None).unwrap();
assert_eq!(
g.window(2, 7).node(3).unwrap().earliest_time().unwrap().t(),
4
);
assert_eq!(
g.window(2, 7).node(1).unwrap().earliest_time().unwrap().t(),
2
);
}
#[test]
fn test_graph_property_semantics() {
let g = PersistentGraph::new();
g.add_properties(1, [("weight", 10i64)]).unwrap();
g.add_properties(3, [("weight", 20i64)]).unwrap();
let prop = g.properties().temporal().get("weight").unwrap();
assert_eq!(
prop,
[(EventTime::new(1, 0), 10i64), (EventTime::new(3, 1), 20i64)]
);
let prop = g
.window(5, 7)
.properties()
.temporal()
.get("weight")
.unwrap();
assert_eq!(prop, [(EventTime::new(5, 0), 20i64)])
}
#[test]
fn test_exploded_edge_window() {
let g = PersistentGraph::new();
g.add_edge(1, 0, 1, [("test", 1i64)], None).unwrap();
g.add_edge(3, 0, 1, [("test", 3i64)], None).unwrap();
g.add_edge(4, 0, 1, [("test", 4i64)], None).unwrap();
let prop_values = g
.window(2, 5)
.edges()
.explode()
.properties()
.map(|props| props.get("test").unwrap_i64())
.collect::<Vec<_>>();
assert_eq!(prop_values, [1, 3, 4]);
}
#[test]
fn test_node_earliest_latest_time_edge_deletion_only() {
let g = PersistentGraph::new();
g.delete_edge(10, 0, 1, None).unwrap();
assert_eq!(g.node(0).unwrap().earliest_time().unwrap().t(), 10);
assert_eq!(g.node(1).unwrap().earliest_time().unwrap().t(), 10);
assert_eq!(g.node(0).unwrap().latest_time().unwrap().t(), 10);
assert_eq!(g.node(1).unwrap().latest_time().unwrap().t(), 10);
}
#[test]
fn test_edge_earliest_latest_time_edge_deletion_only() {
let g = PersistentGraph::new();
g.delete_edge(10, 0, 1, None).unwrap();
assert_eq!(g.edge(0, 1).unwrap().earliest_time().unwrap().t(), 10);
assert_eq!(g.edge(0, 1).unwrap().latest_time().unwrap().t(), 10);
}
#[test]
fn test_repeated_deletions() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 1, NO_PROPS, None).unwrap();
g.delete_edge(2, 0, 1, None).unwrap();
g.delete_edge(4, 0, 1, None).unwrap();
let e = g.edge(0, 1).unwrap();
let ex_earliest_t = e
.explode()
.earliest_time()
.map(|t_opt| t_opt.map(|t| t.t()))
.collect_vec();
assert_eq!(ex_earliest_t, [Some(0)]);
}
#[test]
fn test_only_deletions() {
let g = PersistentGraph::new();
g.delete_edge(2, 0, 1, None).unwrap();
g.delete_edge(4, 0, 1, None).unwrap();
let e = g.edge(0, 1).unwrap();
let ex_earliest_t = e.explode().earliest_time().collect_vec();
assert_eq!(ex_earliest_t, []);
}
#[test]
fn test_only_deletions_window() {
let g = PersistentGraph::new();
g.delete_edge(1, 0, 1, None).unwrap();
assert!(g.has_edge(0, 1));
assert!(g.window(0, 2).has_edge(0, 1));
assert!(!g.window(1, 2).has_edge(0, 1));
assert!(!g.window(0, 1).has_edge(0, 1));
assert!(!g.window(2, 3).has_edge(0, 1));
}
#[test]
fn test_multiple_updates_at_start() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 1, [("test", 1i64)], None).unwrap();
g.add_edge(0, 0, 1, [("test", 2i64)], None).unwrap();
let e = g.edge(0, 1).unwrap();
assert_eq!(e.properties().get("test").unwrap_i64(), 2);
assert_eq!(
e.properties()
.temporal()
.get("test")
.unwrap()
.iter()
.map(|(t, p)| (t.t(), p))
.collect_vec(),
[(0, Prop::I64(1)), (0, Prop::I64(2))]
);
assert_eq!(e.at(0).properties().get("test").unwrap_i64(), 2);
assert_eq!(
e.at(0)
.properties()
.temporal()
.get("test")
.unwrap()
.iter()
.map(|(t, p)| (t.t(), p))
.collect_vec(),
[(0, Prop::I64(1)), (0, Prop::I64(2))]
);
assert_eq!(
e.at(0)
.explode()
.properties()
.map(|p| p.get("test").unwrap_i64())
.collect_vec(),
[1, 2]
);
assert_eq!(e.at(0).history(), [0, 0]);
assert_eq!(e.history(), [0, 0]);
}
#[test]
fn no_persistence_if_updated_at_start() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 1, [("test", 1i64)], None).unwrap();
g.add_edge(2, 0, 1, [("test", 2i64)], None).unwrap();
g.add_edge(4, 0, 1, [("test", 4i64)], None).unwrap();
let e = g.edge(0, 1).unwrap().window(2, 5);
assert_eq!(e.properties().get("test").unwrap_i64(), 4);
assert_eq!(
e.properties()
.temporal()
.get("test")
.unwrap()
.iter()
.map(|(t, p)| (t.t(), p))
.collect_vec(),
[(2, Prop::I64(2)), (4, Prop::I64(4))]
);
assert_eq!(
e.explode()
.properties()
.map(|p| p.get("test").unwrap_i64())
.collect_vec(),
[2, 4]
);
assert_eq!(e.history(), [2, 4]);
assert!(e.deletions().is_empty());
}
#[test]
fn persistence_if_not_updated_at_start() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 1, [("test", 1i64)], None).unwrap();
g.add_edge(2, 0, 1, [("test", 2i64)], None).unwrap();
g.add_edge(4, 0, 1, [("test", 4i64)], None).unwrap();
let e = g.edge(0, 1).unwrap().window(1, 5);
assert_eq!(e.properties().get("test").unwrap_i64(), 4);
assert_eq!(
e.properties()
.temporal()
.get("test")
.unwrap()
.iter()
.map(|(t, p)| (t.t(), p))
.collect_vec(),
[(1, Prop::I64(1)), (2, Prop::I64(2)), (4, Prop::I64(4))]
);
assert_eq!(
e.explode()
.properties()
.map(|p| p.get("test").unwrap_i64())
.collect_vec(),
[1, 2, 4]
);
assert_eq!(e.history(), [2, 4]); assert!(e.deletions().is_empty());
assert_eq!(g.window(1, 5).count_temporal_edges(), 3);
assert_eq!(g.window(2, 5).count_temporal_edges(), 2);
assert_eq!(g.window(3, 5).count_temporal_edges(), 2);
}
#[test]
fn no_persistence_if_deleted() {
let g = PersistentGraph::new();
g.add_edge(-1, 0, 1, [("test", 1i64)], None).unwrap();
g.delete_edge(0, 0, 1, None).unwrap();
g.add_edge(2, 0, 1, [("test", 2i64)], None).unwrap();
g.add_edge(4, 0, 1, [("test", 4i64)], None).unwrap();
let e = g.edge(0, 1).unwrap().window(1, 5);
assert_eq!(e.properties().get("test").unwrap_i64(), 4);
assert_eq!(
e.properties()
.temporal()
.get("test")
.unwrap()
.iter()
.map(|(t, p)| (t.t(), p))
.collect_vec(),
[(2, Prop::I64(2)), (4, Prop::I64(4))]
);
assert_eq!(
e.explode()
.properties()
.map(|p| p.get("test").unwrap_i64())
.collect_vec(),
[2, 4]
);
assert_eq!(e.history(), [2, 4]);
assert!(e.deletions().is_empty());
assert_eq!(g.window(0, 5).count_temporal_edges(), 2);
assert_eq!(g.window(1, 5).count_temporal_edges(), 2);
assert_eq!(g.window(3, 5).count_temporal_edges(), 2);
}
#[test]
fn test_deletion_at_start() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 1, [("test", 1i64)], None).unwrap();
g.add_edge(2, 0, 1, [("test", 2i64)], None).unwrap();
g.delete_edge(2, 0, 1, None).unwrap();
g.add_edge(2, 0, 1, [("test", 3i64)], None).unwrap();
g.add_edge(4, 0, 1, [("test", 4i64)], None).unwrap();
let e = g.edge(0, 1).unwrap().window(2, 5);
assert_eq!(e.properties().get("test").unwrap_i64(), 4);
assert_eq!(
e.properties()
.temporal()
.get("test")
.unwrap()
.iter()
.map(|(t, p)| (t.t(), p))
.collect_vec(),
[(2, Prop::I64(3)), (4, Prop::I64(4))]
);
assert_eq!(
e.explode()
.properties()
.map(|p| p.get("test").unwrap_i64())
.collect_vec(),
[3, 4]
);
assert!(e.deletions().is_empty());
assert_eq!(e.history(), [2, 4]);
assert_eq!(g.window(1, 5).count_temporal_edges(), 4);
assert_eq!(g.window(2, 5).count_temporal_edges(), 2);
assert_eq!(g.window(3, 5).count_temporal_edges(), 2);
}
#[test]
fn multiple_node_updates_at_same_time() {
let g = PersistentGraph::new();
g.add_node(1, 1, [("prop1", 1)], None).unwrap();
g.add_node(2, 1, [("prop1", 2)], None).unwrap();
g.add_node(2, 1, [("prop1", 3)], None).unwrap();
g.add_node(8, 1, [("prop1", 4)], None).unwrap();
g.add_node(9, 1, [("prop1", 5)], None).unwrap();
assert_eq!(
g.window(2, 10)
.node(1)
.unwrap()
.properties()
.temporal()
.get("prop1")
.unwrap()
.values()
.collect_vec(),
[Prop::I32(2), Prop::I32(3), Prop::I32(4), Prop::I32(5)]
)
}
#[test]
fn filtering_all_layers_keeps_explicitly_added_nodes() {
let g = PersistentGraph::new();
g.add_node(0, 0, [("prop1", false)], None).unwrap();
let view = g.valid_layers(Layer::None).window(0, 1);
assert_eq!(view.count_nodes(), 1);
assert_eq!(view.count_edges(), 0);
assert_graph_equal(&view, &view.materialize().unwrap())
}
#[test]
fn filtering_all_layers_removes_other_nodes() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 1, NO_PROPS, None).unwrap();
let view = g.valid_layers(Layer::None).window(0, 1);
assert_eq!(view.count_nodes(), 0);
assert_eq!(view.count_edges(), 0);
assert_graph_equal(&view, &view.materialize().unwrap())
}
#[test]
fn deletions_window_has_exclusive_start() {
let g = PersistentGraph::new();
g.add_edge(0, 0, 1, NO_PROPS, None).unwrap();
g.delete_edge(2, 0, 1, None).unwrap();
let e = g.edge(0, 1).unwrap();
assert!(e.is_active()); assert!(!e.is_valid()); assert!(e.is_deleted());
assert!(e.window(0, 1).is_active()); assert!(e.window(0, 1).is_valid()); assert!(!e.window(0, 1).is_deleted());
assert!(e.window(1, 3).is_active()); assert!(!e.window(1, 3).is_valid());
assert!(e.window(1, 3).is_deleted());
assert!(!e.window(1, 2).is_active()); assert!(e.window(1, 2).is_valid()); assert!(!e.window(1, 2).is_deleted());
assert!(!e.window(2, 3).is_active()); assert!(!e.window(2, 3).is_valid());
assert!(e.window(2, 3).is_deleted());
assert!(!e.latest().is_active()); }