meadow
meadow copied to clipboard
Unifying tests for different configurations
There's a lot of code re-use right now between Node<Tcp | Udp | Quic>. Especially with the state-space increasing due to the new Blocking | Nonblocking tags, this isn't great for maintaining a clean test suite. Since these all share a trait (Interface), there should be a way of tagging/iterating over much of these via something like
#[test]
fn basic() {
basic_test<Tcp>();
basic_test<Udp>();
#[cfg(features = "quic")]
basic_test<Quic>();
}
fn basic_test<I: Interface>() {
// host_and_single_node
}
that significantly reduces total LoC. I think it's unlikely we'll be able to do the exact same thing with Blocking | Nonblocking due to the different .await statements and whatnot, but it would still be a significant improvement over the current state. Ideally, whatever pattern ends up being used could also help to support fuzzing many different types that support the Message trait.
So this looks possible, but the use of traits begins to make the compiler unhappy with some of our state transitions. For example, we
no method named `activate` found for struct `meadow::node::Node<meadow::prelude::Blocking, I, meadow::node::Idle, Pose>` in the current scope
because there's no way to guarantee that every Node that meets the Node<Blocking, I, Idle, Pose> has an activate() method.
In order to do this, we could then implement something like
pub trait ToActive<I: Interface, T: Message> {
fn activate(self) -> Result<Node<Blocking, I, Active, T>, Error>;
}
However, this is imperfect because it doesn't really play nicely with B: Block because for Nonblocking, we actually need
pub trait ToActiveAsync<I: Interface, T: Message> {
async fn activate(self) -> Result<Node<Blocking, I, Active, T>, Error>;
}
which ends up leading to additional code bifurcation (albeit on the library side, not the user-side or on testing, which is better I guess?)
Experiments with this are in the unify branch
Currently being managed by using macros with a State argument.