From cd1e78db6f26e058ad2e728b29caa296efd89b10 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Fri, 7 Jun 2024 19:23:13 +0200 Subject: [PATCH] tests: perform some undo-redo sanity testing before each test --- tests/common/mod.rs | 102 +++++++++++++++++++++++++++++++----------- tests/single_layer.rs | 53 ++++++++++------------ 2 files changed, 99 insertions(+), 56 deletions(-) diff --git a/tests/common/mod.rs b/tests/common/mod.rs index a8bbb68..f2dedba 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,43 +1,61 @@ +use std::fs::File; + use petgraph::{stable_graph::NodeIndex, unionfind::UnionFind, visit::NodeIndexable}; use topola::{ - autorouter::{board::Board, Autorouter}, + autorouter::{ + board::Board, + history::HistoryError, + invoker::{Invoker, InvokerError}, + Autorouter, + }, drawing::{ graph::{GetLayer, GetMaybeNet}, rules::RulesTrait, }, + dsn::{design::DsnDesign, rules::DsnRules}, graph::GetNodeIndex, }; -fn unionfind(autorouter: &mut Autorouter) -> UnionFind> { - for ratline in autorouter.ratsnest().graph().edge_indices() { - // Accessing endpoints may create new dots because apex construction is lazy, so we access - // tem all before starting unionfind, as it requires a constant index bound. - let _ = autorouter.ratline_endpoints(ratline); +pub fn load_design_and_assert(filename: &str) -> Invoker { + let design = DsnDesign::load_from_file(filename).unwrap(); + let mut invoker = Invoker::new(Autorouter::new(design.make_board()).unwrap()); + + assert!(matches!( + invoker.undo(), + Err(InvokerError::History(HistoryError::NoPreviousCommand)) + )); + assert!(matches!( + invoker.redo(), + Err(InvokerError::History(HistoryError::NoNextCommand)) + )); + + invoker +} + +pub fn replay_and_assert(invoker: &mut Invoker, filename: &str) { + let file = File::open(filename).unwrap(); + invoker.replay(serde_json::from_reader(file).unwrap()); + + let prev_node_count = invoker.autorouter().board().layout().drawing().node_count(); + + // Sanity test: check if node count remained the same after some attempts at undo-redo. + + if invoker.redo().is_ok() { + let _ = invoker.undo(); } - let mut unionfind = UnionFind::new( - autorouter - .board() - .layout() - .drawing() - .geometry() - .graph() - .node_bound(), - ); - - for primitive in autorouter.board().layout().drawing().primitive_nodes() { - for joined in autorouter - .board() - .layout() - .drawing() - .geometry() - .joineds(primitive) - { - unionfind.union(primitive.node_index(), joined.node_index()); + if invoker.undo().is_ok() { + if invoker.undo().is_ok() { + let _ = invoker.redo(); } + + let _ = invoker.redo(); } - unionfind + assert_eq!( + invoker.autorouter().board().layout().drawing().node_count(), + prev_node_count, + ); } pub fn assert_single_layer_groundless_autoroute( @@ -130,3 +148,35 @@ pub fn assert_band_length( dbg!(band_length); assert!((band_length - length).abs() < epsilon); } + +fn unionfind(autorouter: &mut Autorouter) -> UnionFind> { + for ratline in autorouter.ratsnest().graph().edge_indices() { + // Accessing endpoints may create new dots because apex construction is lazy, so we access + // tem all before starting unionfind, as it requires a constant index bound. + let _ = autorouter.ratline_endpoints(ratline); + } + + let mut unionfind = UnionFind::new( + autorouter + .board() + .layout() + .drawing() + .geometry() + .graph() + .node_bound(), + ); + + for primitive in autorouter.board().layout().drawing().primitive_nodes() { + for joined in autorouter + .board() + .layout() + .drawing() + .geometry() + .joineds(primitive) + { + unionfind.union(primitive.node_index(), joined.node_index()); + } + } + + unionfind +} diff --git a/tests/single_layer.rs b/tests/single_layer.rs index 8e377eb..5e39025 100644 --- a/tests/single_layer.rs +++ b/tests/single_layer.rs @@ -20,12 +20,12 @@ mod common; #[test] fn test_0603_breakout() { - let design = - DsnDesign::load_from_file("tests/single_layer/data/0603_breakout/0603_breakout.dsn") - .unwrap(); - let mut invoker = Invoker::new(Autorouter::new(design.make_board()).unwrap()); - let file = File::open("tests/single_layer/data/0603_breakout/autoroute_all.cmd").unwrap(); - invoker.replay(serde_json::from_reader(file).unwrap()); + let mut invoker = + common::load_design_and_assert("tests/single_layer/data/0603_breakout/0603_breakout.dsn"); + common::replay_and_assert( + &mut invoker, + "tests/single_layer/data/0603_breakout/autoroute_all.cmd", + ); let (mut autorouter, ..) = invoker.destruct(); @@ -35,15 +35,13 @@ fn test_0603_breakout() { #[test] fn test_tht_diode_bridge_rectifier() { - let design = DsnDesign::load_from_file( + let mut invoker = common::load_design_and_assert( "tests/single_layer/data/tht_diode_bridge_rectifier/tht_diode_bridge_rectifier.dsn", ); - let board = design.unwrap().make_board(); - - let mut invoker = Invoker::new(Autorouter::new(board).unwrap()); - let file = - File::open("tests/single_layer/data/tht_diode_bridge_rectifier/autoroute_all.cmd").unwrap(); - invoker.replay(serde_json::from_reader(file).unwrap()); + common::replay_and_assert( + &mut invoker, + "tests/single_layer/data/tht_diode_bridge_rectifier/autoroute_all.cmd", + ); let (mut autorouter, ..) = invoker.destruct(); @@ -54,16 +52,13 @@ fn test_tht_diode_bridge_rectifier() { #[test] fn test_four_3rd_order_smd_lc_filters() { - let design = DsnDesign::load_from_file( + let mut invoker = common::load_design_and_assert( "tests/single_layer/data/four_3rd_order_smd_lc_filters/four_3rd_order_smd_lc_filters.dsn", ); - let board = design.unwrap().make_board(); - - let mut invoker = Invoker::new(Autorouter::new(board).unwrap()); - let file = - File::open("tests/single_layer/data/four_3rd_order_smd_lc_filters/autoroute_signals.cmd") - .unwrap(); - invoker.replay(serde_json::from_reader(file).unwrap()); + common::replay_and_assert( + &mut invoker, + "tests/single_layer/data/four_3rd_order_smd_lc_filters/autoroute_signals.cmd", + ); let (mut autorouter, ..) = invoker.destruct(); @@ -71,18 +66,16 @@ fn test_four_3rd_order_smd_lc_filters() { //common::assert_number_of_conncomps(&mut autorouter, 16); } +// FIXME: This test fails indeterministically. #[test] fn test_3pin_xlr_tht_female_to_tht_female() { - let design = DsnDesign::load_from_file( - "tests/single_layer/data/3pin_xlr_tht_female_to_tht_female/3pin_xlr_tht_female_to_tht_female.dsn" + let mut invoker = common::load_design_and_assert( + "tests/single_layer/data/3pin_xlr_tht_female_to_tht_female/3pin_xlr_tht_female_to_tht_female.dsn", + ); + common::replay_and_assert( + &mut invoker, + "tests/single_layer/data/3pin_xlr_tht_female_to_tht_female/autoroute_all.cmd", ); - let board = design.unwrap().make_board(); - - let mut invoker = Invoker::new(Autorouter::new(board).unwrap()); - let file = - File::open("tests/single_layer/data/3pin_xlr_tht_female_to_tht_female/autoroute_all.cmd") - .unwrap(); - invoker.replay(serde_json::from_reader(file).unwrap()); let (mut autorouter, ..) = invoker.destruct();