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<Self::Data> {
let mut s = SocketDescription::new();
s.push_output_with_buffer(Foo);
s
}
fn rt_process(&mut self, _context: &Self::Context, _sockets: Sockets<Self::Data>) {}
}
#[derive(Debug)]
struct FooProcessor;
impl Node for FooProcessor {
type Config = ();
type Context = ();
type Data = Data;
fn sockets(&self, config: &Self::Config) -> SocketDescription<Self::Data> {
let mut s = SocketDescription::new();
s.push_input::<Foo>();
s.push_output_with_buffer(Foo);
s
}
fn rt_process(&mut self, _context: &Self::Context, _sockets: Sockets<Self::Data>) {}
}
#[derive(Debug)]
struct BarGenerator;
impl Node for BarGenerator {
type Config = ();
type Context = ();
type Data = Data;
fn sockets(&self, config: &Self::Config) -> SocketDescription<Self::Data> {
let mut s = SocketDescription::new();
s.push_output_with_buffer(Bar);
s
}
fn rt_process(&mut self, _context: &Self::Context, _sockets: Sockets<Self::Data>) {}
}
#[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<i32, AnyNode> {
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:?}");
}
}
}
}