Skip to main content

xenith_core/
testing.rs

1/// Generates the standard transport compliance test suite for any
2/// [`crate::MessagingTransport`] implementation.
3///
4/// Invoke this macro inside a `#[cfg(test)] mod tests { ... }` block,
5/// passing an expression that constructs the transport under test.
6/// The constructed transport **must** include [`crate::ChainId`]`(1)` in its
7/// set of supported chains; all compliance tests use chain 1 as the canonical
8/// supported destination.
9///
10/// # Example
11///
12/// ```rust,ignore
13/// #[cfg(test)]
14/// mod tests {
15///     use super::*;
16///     use xenith_core::transport_compliance_tests;
17///
18///     transport_compliance_tests!(MyTransport::new(
19///         [0u8; 20],
20///         vec![(xenith_core::ChainId(1), 101u32)],
21///     ));
22/// }
23/// ```
24///
25/// # Generated tests
26///
27/// | Test name | What it checks |
28/// |---|---|
29/// | `compliance_send_to_supported_chain` | `send_message` to ChainId(1) returns `Ok` |
30/// | `compliance_send_to_unsupported_chain` | `send_message` to ChainId(999_999) returns `UnsupportedChain` |
31/// | `compliance_estimate_fee_returns_u128` | `estimate_fee` returns `Ok(fee)` with `fee > 0` |
32/// | `compliance_message_status_is_valid_variant` | `message_status` returns a recognised variant |
33/// | `compliance_transport_is_send_sync` | The transport type satisfies `Send + Sync` |
34#[macro_export]
35macro_rules! transport_compliance_tests {
36    ($constructor:expr) => {
37        #[tokio::test]
38        async fn compliance_send_to_supported_chain() {
39            let t = $constructor;
40            let result = t
41                .send_message(
42                    $crate::ChainId(1),
43                    ::bytes::Bytes::new(),
44                    $crate::SendOptions::default(),
45                )
46                .await;
47            assert!(
48                result.is_ok(),
49                "send_message to a supported chain must return Ok(MessageId), got {result:?}"
50            );
51        }
52
53        #[tokio::test]
54        async fn compliance_send_to_unsupported_chain() {
55            let t = $constructor;
56            let result = t
57                .send_message(
58                    $crate::ChainId(999_999),
59                    ::bytes::Bytes::new(),
60                    $crate::SendOptions::default(),
61                )
62                .await;
63            assert!(
64                matches!(result, Err($crate::XenithError::UnsupportedChain(_))),
65                "send_message to ChainId(999_999) must return Err(UnsupportedChain), got {result:?}"
66            );
67        }
68
69        #[tokio::test]
70        async fn compliance_estimate_fee_returns_u128() {
71            let t = $constructor;
72            let fee = t
73                .estimate_fee($crate::ChainId(1), ::bytes::Bytes::new())
74                .await
75                .expect("estimate_fee must succeed for a supported chain");
76            assert!(fee > 0, "estimate_fee must return a non-zero value, got {fee}");
77        }
78
79        #[tokio::test]
80        async fn compliance_message_status_is_valid_variant() {
81            let t = $constructor;
82            let id = t
83                .send_message(
84                    $crate::ChainId(1),
85                    ::bytes::Bytes::new(),
86                    $crate::SendOptions::default(),
87                )
88                .await
89                .expect("send_message must succeed before checking message_status");
90            let status = t
91                .message_status(id)
92                .await
93                .expect("message_status must return Ok");
94            assert!(
95                matches!(
96                    status,
97                    $crate::MessageStatus::Pending
98                        | $crate::MessageStatus::InFlight
99                        | $crate::MessageStatus::Delivered
100                        | $crate::MessageStatus::Failed { .. }
101                ),
102                "message_status returned an unexpected variant: {status:?}"
103            );
104        }
105
106        #[test]
107        fn compliance_transport_is_send_sync() {
108            fn assert_send_sync<T: Send + Sync>(_: &T) {}
109            let t = $constructor;
110            assert_send_sync(&t);
111        }
112
113        #[test]
114        fn compliance_sender_address_is_option() {
115            let t = $constructor;
116            // sender_address() must compile and return Some or None — both are valid.
117            let _addr: Option<[u8; 20]> = t.sender_address();
118        }
119
120        #[tokio::test]
121        async fn compliance_poll_incoming_returns_vec() {
122            let t = $constructor;
123            let result = t.poll_incoming().await;
124            assert!(
125                result.is_ok(),
126                "poll_incoming must return Ok(vec), got {result:?}"
127            );
128        }
129    };
130}