//! Tests for the topology time series. //! //! 拓扑时间序列的测试。 use apsis_topology::{Topology, TopologyErrorKind, TopologySample, TopologySeries}; /// A topology with the given directed edges, all of unit cost. /// /// 具有给定有向边、全部单位代价的拓扑。 fn topology_with(node_count: usize, edges: &[(usize, usize)]) -> Topology { let mut topology = Topology::new(node_count); for &(from, to) in edges { topology.add_edge(from, to, 1.0).expect("the nodes exist"); } topology } /// A series of three topologies at 0, 10, and 25 seconds. /// /// 0、10 与 25 秒处三个拓扑构成的序列。 fn series() -> TopologySeries { TopologySeries::new(vec![ TopologySample::new(0.0, topology_with(3, &[(0, 1)])), TopologySample::new(10.0, topology_with(3, &[(0, 1), (1, 2)])), TopologySample::new(25.0, topology_with(3, &[(0, 2)])), ]) .expect("the times increase") } #[test] fn a_series_holds_its_samples() { let series = series(); assert_eq!(series.len(), 3); assert!(!series.is_empty()); assert_eq!(series.start_seconds(), 0.0); assert_eq!(series.end_seconds(), 25.0); assert_eq!(series.node_count(), 3); } #[test] fn a_time_selects_the_sample_in_force() { let series = series(); // At the exact times, the entry itself applies. // 在精确时刻,该时刻的项本身适用。 assert_eq!(series.index_at(0.0), Some(0)); assert_eq!(series.index_at(10.0), Some(1)); assert_eq!(series.index_at(25.0), Some(2)); // Between entries, the earlier one applies. // 在各项之间,较早者适用。 assert_eq!(series.index_at(5.0), Some(0)); assert_eq!(series.index_at(9.999), Some(0)); assert_eq!(series.index_at(10.001), Some(1)); assert_eq!(series.index_at(24.999), Some(1)); // A time after the last entry keeps the last topology. // 最后一项之后的时间保持最后拓扑。 assert_eq!(series.index_at(1_000.0), Some(2)); // A time before the first entry uses the first topology. // 首项之前的时间使用第一个拓扑。 assert_eq!(series.index_at(-50.0), Some(0)); } #[test] fn the_topology_in_force_reflects_the_changes() { let series = series(); // At one second only the first link exists. // 一秒时只有第一条链路存在。 let early = series.topology_at(1.0).expect("a topology exists"); assert!(early.has_edge(0, 1)); assert!(!early.has_edge(1, 2)); // At fifteen seconds the second link has been added. // 十五秒时第二条链路已被加入。 let middle = series.topology_at(15.0).expect("a topology exists"); assert!(middle.has_edge(0, 1)); assert!(middle.has_edge(1, 2)); // At thirty seconds the topology has changed again. // 三十秒时拓扑又已改变。 let late = series.topology_at(30.0).expect("a topology exists"); assert!(!late.has_edge(0, 1)); assert!(late.has_edge(0, 2)); } #[test] fn the_interval_of_a_sample_is_bounded_by_the_next() { let series = series(); assert_eq!(series.interval_of(0), Some((0.0, 10.0))); assert_eq!(series.interval_of(1), Some((10.0, 25.0))); // The last interval is unbounded. // 最后一个区间无界。 let (start, end) = series.interval_of(2).expect("the index exists"); assert_eq!(start, 25.0); assert!(end.is_infinite()); assert_eq!(series.interval_of(3), None); } #[test] fn the_change_count_excludes_the_first_entry() { let series = series(); assert_eq!(series.change_count(), 2); assert_eq!(series.mean_interval_seconds(), Some(12.5)); } #[test] fn the_edge_changes_count_appearances_and_disappearances() { let series = series(); // From the first to the second topology, the edge 1 to 2 appears, one // change. From the second to the third, the edges 0 to 1 and 1 to 2 // disappear and 0 to 2 appears, three changes. // 从第一个拓扑到第二个,边 1 到 2 出现,一次变化。从第二个到第三个,边 0 到 1 // 与 1 到 2 消失、0 到 2 出现,三次变化。 assert_eq!(series.edge_changes(), 4); } #[test] fn a_single_sample_series_has_no_changes() { let single = TopologySeries::new(vec![TopologySample::new(0.0, topology_with(2, &[(0, 1)]))]) .expect("valid"); assert_eq!(single.len(), 1); assert_eq!(single.change_count(), 0); assert_eq!(single.mean_interval_seconds(), None); assert_eq!(single.edge_changes(), 0); } #[test] fn an_empty_series_is_rejected() { let error = TopologySeries::new(Vec::new()).expect_err("no samples"); assert_eq!(error.kind(), TopologyErrorKind::EmptySeries); } #[test] fn a_non_finite_time_is_rejected() { for time in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { let error = TopologySeries::new(vec![TopologySample::new(time, Topology::new(1))]) .expect_err("the time is not finite"); assert_eq!(error.kind(), TopologyErrorKind::InvalidTime, "time {time}"); } } #[test] fn unordered_times_are_rejected() { let error = TopologySeries::new(vec![ TopologySample::new(10.0, Topology::new(1)), TopologySample::new(5.0, Topology::new(1)), ]) .expect_err("the times decrease"); assert_eq!(error.kind(), TopologyErrorKind::UnorderedTimes); // Equal times are also rejected, because the topology at that instant // would be ambiguous. // 相等的时间也被拒绝,因为该瞬时的拓扑会含糊。 let error = TopologySeries::new(vec![ TopologySample::new(10.0, Topology::new(1)), TopologySample::new(10.0, Topology::new(1)), ]) .expect_err("the times are equal"); assert_eq!(error.kind(), TopologyErrorKind::UnorderedTimes); } #[test] fn a_series_can_be_built_from_separate_lists() { let series = TopologySeries::from_parts( vec![0.0, 10.0], vec![topology_with(2, &[(0, 1)]), topology_with(2, &[])], ) .expect("the lists match"); assert_eq!(series.len(), 2); assert!( series .topology_at(5.0) .expect("a topology exists") .has_edge(0, 1) ); assert!( !series .topology_at(15.0) .expect("a topology exists") .has_edge(0, 1) ); } #[test] fn mismatched_list_lengths_are_rejected() { let error = TopologySeries::from_parts(vec![0.0, 10.0], vec![topology_with(2, &[(0, 1)])]) .expect_err("the lengths differ"); assert_eq!(error.kind(), TopologyErrorKind::EmptySeries); } #[test] fn a_non_finite_query_time_is_rejected() { let series = series(); assert_eq!(series.index_at(f64::NAN), None); assert_eq!(series.index_at(f64::INFINITY), None); assert_eq!(series.topology_at(f64::NAN), None); } #[test] fn a_series_with_negative_times_is_accepted() { // The origin of the time axis is the caller's choice, so negative times // are as valid as positive ones. // 时间轴的原点由调用方选择,故负时间与正时间同样有效。 let series = TopologySeries::new(vec![ TopologySample::new(-100.0, topology_with(2, &[(0, 1)])), TopologySample::new(-50.0, topology_with(2, &[])), ]) .expect("the times increase"); assert_eq!(series.start_seconds(), -100.0); assert_eq!(series.end_seconds(), -50.0); assert!( series .topology_at(-75.0) .expect("a topology exists") .has_edge(0, 1) ); assert!( !series .topology_at(0.0) .expect("a topology exists") .has_edge(0, 1) ); } #[test] fn the_samples_are_accessible() { let series = series(); assert_eq!(series.samples().len(), 3); assert_eq!(series.samples()[0].seconds, 0.0); assert_eq!(series.samples()[1].seconds, 10.0); } #[test] fn a_change_at_the_boundary_is_immediate() { // The topology changes exactly at the recorded time, not after it. // 拓扑恰在所记录的时间处改变,而非在其后。 let series = series(); let before = series.topology_at(10.0 - 1e-9).expect("a topology exists"); let after = series.topology_at(10.0).expect("a topology exists"); assert!(!before.has_edge(1, 2)); assert!(after.has_edge(1, 2)); }