Clean up unused BMAD workflow, agent, and command files across all IDE configurations (.agent, .clinerules, .cursor, .gemini, .github, .kilocode, .opencode) and internal module files (_bmad/bmb, _bmad/bmm). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
203 lines
5.5 KiB
Rust
203 lines
5.5 KiB
Rust
//! 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<ConnectedPort>,
|
|
}
|
|
|
|
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<ConnectedPort>) -> 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);
|
|
}
|