use sound_flow::Sockets; use sound_flow::{Node, SocketDescription}; #[derive(Debug)] struct Foo; #[derive(Debug)] struct Bar; #[enum_delegate::implement_conversions] #[derive(Debug)] enum Data { Foo(Foo), Bar(Bar), } #[derive(Debug)] struct FooGenerator; impl Node for FooGenerator { type Config = (); type Context = (); type Data = Data; fn sockets(&self, config: &Self::Config) -> SocketDescription { let mut s = SocketDescription::new(); s.push_output_with_buffer(Foo); s } fn rt_process(&mut self, _context: &Self::Context, _sockets: Sockets) {} } #[derive(Debug)] struct FooProcessor; impl Node for FooProcessor { type Config = (); type Context = (); type Data = Data; fn sockets(&self, config: &Self::Config) -> SocketDescription { let mut s = SocketDescription::new(); s.push_input::(); s.push_output_with_buffer(Foo); s } fn rt_process(&mut self, _context: &Self::Context, _sockets: Sockets) {} } #[derive(Debug)] struct BarGenerator; impl Node for BarGenerator { type Config = (); type Context = (); type Data = Data; fn sockets(&self, config: &Self::Config) -> SocketDescription { let mut s = SocketDescription::new(); s.push_output_with_buffer(Bar); s } fn rt_process(&mut self, _context: &Self::Context, _sockets: Sockets) {} } #[enum_delegate::implement(Node)] #[derive(Debug)] enum AnyNode { FooGenerator(FooGenerator), FooProcessor(FooProcessor), BarGenerator(BarGenerator), } #[cfg(test)] mod tests { use super::*; use sound_flow::{BuildError, Connection, GraphBuilder, InvalidConnection}; fn example_base_graph() -> GraphBuilder { let mut b: GraphBuilder<_, AnyNode> = GraphBuilder::new(); b.add_node(0, FooGenerator).unwrap(); b.add_node(1, FooProcessor).unwrap(); b } #[test] fn valid_graph() { let mut b = example_base_graph(); b.add_connection(Connection { from_node: 0, from_output_socket: 0, to_node: 1, to_input_socket: 0, }); b.build().unwrap(); } #[test] fn invalid_from_node() { let mut b = example_base_graph(); b.add_connection(Connection { from_node: 404, from_output_socket: 0, to_node: 1, to_input_socket: 0, }); assert!(matches!( b.build().unwrap_err(), BuildError::InvalidConnection(_, InvalidConnection::InvalidFromNode) )) } #[test] fn invalid_from_socket() { let mut b = example_base_graph(); b.add_connection(Connection { from_node: 0, from_output_socket: 404, to_node: 1, to_input_socket: 0, }); assert!(matches!( b.build().unwrap_err(), BuildError::InvalidConnection(_, InvalidConnection::InvalidFromOutputSocket) )) } #[test] fn invalid_to_node() { let mut b = example_base_graph(); b.add_connection(Connection { from_node: 0, from_output_socket: 0, to_node: 404, to_input_socket: 0, }); assert!(matches!( b.build().unwrap_err(), BuildError::InvalidConnection(_, InvalidConnection::InvalidToNode) )) } #[test] fn invalid_to_socket() { let mut b = example_base_graph(); b.add_connection(Connection { from_node: 0, from_output_socket: 0, to_node: 1, to_input_socket: 404, }); assert!(matches!( b.build().unwrap_err(), BuildError::InvalidConnection(_, InvalidConnection::InvalidToInputSocket) )) } #[test] fn type_mismatch() { let mut b = example_base_graph(); b.add_node(2, BarGenerator).unwrap(); b.add_connection(Connection { from_node: 2, from_output_socket: 0, to_node: 1, to_input_socket: 0, }); assert!(matches!( b.build().unwrap_err(), BuildError::TypeMismatch(_) )) } #[test] fn missing_input() { let b = example_base_graph(); assert!(matches!( b.build().unwrap_err(), BuildError::MissingInput(_) )) } #[test] fn multiple_inputs() { let mut b = example_base_graph(); b.add_connection(Connection { from_node: 0, from_output_socket: 0, to_node: 1, to_input_socket: 0, }); b.add_connection(Connection { from_node: 0, from_output_socket: 0, to_node: 1, to_input_socket: 0, }); assert!(matches!( b.build().unwrap_err(), BuildError::MultipleInputs(_) )) } #[test] fn circular_dependencies() { let mut b: GraphBuilder<_, AnyNode> = GraphBuilder::new(); b.add_node(0, FooProcessor).unwrap(); b.add_node(1, FooProcessor).unwrap(); b.add_connection(Connection { from_node: 0, from_output_socket: 0, to_node: 1, to_input_socket: 0, }); b.add_connection(Connection { from_node: 1, from_output_socket: 0, to_node: 0, to_input_socket: 0, }); match b.build().unwrap_err() { BuildError::CircularDependencies(c) => { assert_eq!(c.len(), 2); assert!(c.contains(&Connection { from_node: 0, from_output_socket: 0, to_node: 1, to_input_socket: 0, })); assert!(c.contains(&Connection { from_node: 1, from_output_socket: 0, to_node: 0, to_input_socket: 0, })); } other => { panic!("Unexpected error {other:?}"); } } } #[test] fn circular_dependencies_self_loop() { let mut b: GraphBuilder<_, AnyNode> = GraphBuilder::new(); b.add_node(0, FooProcessor).unwrap(); b.add_connection(Connection { from_node: 0, from_output_socket: 0, to_node: 0, to_input_socket: 0, }); match b.build().unwrap_err() { BuildError::CircularDependencies(c) => { assert_eq!(c.len(), 1); assert!(c.contains(&Connection { from_node: 0, from_output_socket: 0, to_node: 0, to_input_socket: 0, })); } other => { panic!("Unexpected error {other:?}"); } } } }