//! Integration tests for SystemBuilder::edge_with_ports() use entropyk::SystemBuilder; use entropyk_components::{ComponentError, ConnectedPort, JacobianBuilder, ResidualVector}; /// A minimal mock component with configurable ports for testing. struct MockComponentWithPorts { n_eqs: usize, ports: Vec, } impl MockComponentWithPorts { fn new(n_eqs: usize) -> Self { Self { n_eqs, ports: Vec::new(), } } #[allow(dead_code)] fn with_ports(n_eqs: usize, ports: Vec) -> Self { Self { n_eqs, ports } } } impl entropyk_components::Component for MockComponentWithPorts { fn compute_residuals( &self, _state: &[f64], _residuals: &mut ResidualVector, ) -> Result<(), ComponentError> { Ok(()) } fn jacobian_entries( &self, _state: &[f64], _jacobian: &mut JacobianBuilder, ) -> Result<(), ComponentError> { Ok(()) } fn n_equations(&self) -> usize { self.n_eqs } fn get_ports(&self) -> &[ConnectedPort] { &self.ports } } #[test] fn test_edge_with_ports_component_not_found() { let result = SystemBuilder::new() .component("a", Box::new(MockComponentWithPorts::new(1))) .unwrap() .edge_with_ports("missing", "outlet", "a", "inlet"); assert!(result.is_err()); if let Err(ref err) = result { assert!( err.to_string().contains("not found"), "Expected ComponentNotFound error, got: {}", err ); } } #[test] fn test_edge_with_ports_target_not_found() { let result = SystemBuilder::new() .component("a", Box::new(MockComponentWithPorts::new(1))) .unwrap() .edge_with_ports("a", "outlet", "missing", "inlet"); assert!(result.is_err()); if let Err(ref err) = result { assert!( err.to_string().contains("not found"), "Expected ComponentNotFound error, got: {}", err ); } } #[test] fn test_edge_with_ports_cross_circuit_rejected() { use entropyk_core::CircuitId; let result = SystemBuilder::new() .component_in_circuit( "a", Box::new(MockComponentWithPorts::new(1)), CircuitId::ZERO, ) .unwrap() .component_in_circuit("b", Box::new(MockComponentWithPorts::new(1)), CircuitId(1)) .unwrap() .edge_with_ports("a", "outlet", "b", "inlet"); assert!(result.is_err()); if let Err(ref err) = result { assert!( err.to_string().contains("different circuits"), "Expected CrossCircuitEdge error, got: {}", err ); } } #[test] fn test_edge_with_ports_convention_based_names() { let builder = SystemBuilder::new() .component("a", Box::new(MockComponentWithPorts::new(2))) .unwrap() .component("b", Box::new(MockComponentWithPorts::new(2))) .unwrap() .edge_with_ports("a", "outlet", "b", "inlet") .expect("edge_with_ports should resolve convention-based port names"); assert_eq!(builder.edge_count(), 1); } #[test] fn test_edge_with_ports_suction_discharge_names() { let builder = SystemBuilder::new() .component("comp", Box::new(MockComponentWithPorts::new(2))) .unwrap() .component("pipe", Box::new(MockComponentWithPorts::new(2))) .unwrap() .edge_with_ports("comp", "discharge", "pipe", "inlet") .expect("edge_with_ports should resolve suction/discharge convention names"); assert_eq!(builder.edge_count(), 1); } #[test] fn test_edge_with_ports_unknown_port_name_error() { use entropyk::SystemBuilderError; let result = SystemBuilder::new() .component("a", Box::new(MockComponentWithPorts::new(2))) .unwrap() .component("b", Box::new(MockComponentWithPorts::new(2))) .unwrap() .edge_with_ports("a", "bogus_port", "b", "inlet"); assert!(result.is_err()); if let Err(SystemBuilderError::PortNotFound { component, port_name, }) = result { assert_eq!(component, "a"); assert!(port_name.starts_with("bogus_port"), "port_name should start with the port name, got: {port_name}"); } else { panic!("Expected PortNotFound error"); } } #[test] fn test_edge_with_ports_same_circuit_succeeds() { use entropyk_core::CircuitId; let builder = SystemBuilder::new() .component_in_circuit( "a", Box::new(MockComponentWithPorts::new(2)), CircuitId::ZERO, ) .unwrap() .component_in_circuit( "b", Box::new(MockComponentWithPorts::new(2)), CircuitId::ZERO, ) .unwrap() .edge_with_ports("a", "outlet", "b", "inlet") .expect("edge_with_ports should succeed for same-circuit components"); assert_eq!(builder.edge_count(), 1); } #[test] fn test_build_system_with_port_validated_edges() { let system = SystemBuilder::new() .component("a", Box::new(MockComponentWithPorts::new(2))) .unwrap() .component("b", Box::new(MockComponentWithPorts::new(2))) .unwrap() .component("c", Box::new(MockComponentWithPorts::new(2))) .unwrap() .edge_with_ports("a", "outlet", "b", "inlet") .unwrap() .edge_with_ports("b", "outlet", "c", "inlet") .unwrap() .build() .expect("build should succeed"); assert_eq!(system.node_count(), 3); assert_eq!(system.edge_count(), 2); }