mithril_common/test_utils/
mod.rs

1//! Test utilities
2//!
3//! They contains:
4//! * A Open Api Spec tester
5//! * Some precomputed fake data and keys
6//! * A builder of [MithrilFixture] to generate signers alongside a stake distribution
7//!
8
9#[cfg(feature = "apispec")]
10#[cfg_attr(docsrs, doc(cfg(feature = "apispec")))]
11pub mod apispec;
12
13pub mod fake_data;
14pub mod fake_keys;
15
16mod cardano_transactions_builder;
17mod certificate_chain_builder;
18mod dir_eq;
19mod fixture_builder;
20mod memory_logger;
21mod mithril_fixture;
22mod precomputed_kes_key;
23mod temp_dir;
24
25#[cfg(feature = "test_http_server")]
26#[cfg_attr(docsrs, doc(cfg(feature = "test_http_server")))]
27pub mod test_http_server;
28
29pub use cardano_transactions_builder::CardanoTransactionsBuilder;
30pub use certificate_chain_builder::{
31    CertificateChainBuilder, CertificateChainBuilderContext, CertificateChainingMethod,
32};
33pub use dir_eq::*;
34pub use fixture_builder::{MithrilFixtureBuilder, StakeDistributionGenerationMethod};
35pub use memory_logger::*;
36pub use mithril_fixture::{MithrilFixture, SignerFixture};
37pub use temp_dir::*;
38#[cfg(test)]
39pub(crate) use utils::*;
40
41/// Compare two json strings ignoring keys order
42#[macro_export]
43macro_rules! assert_same_json {
44    ( $expected:expr, $actual:expr ) => {
45        assert_eq!(
46            serde_json::from_str::<serde_json::Value>($expected).unwrap(),
47            serde_json::from_str::<serde_json::Value>($actual).unwrap()
48        )
49    };
50}
51pub use assert_same_json;
52
53/// Compare two iterators ignoring the order
54pub fn equivalent_to<T, I1, I2>(a: I1, b: I2) -> bool
55where
56    T: PartialEq + Ord,
57    I1: IntoIterator<Item = T> + Clone,
58    I2: IntoIterator<Item = T> + Clone,
59{
60    let a = as_sorted_vec(a);
61    let b = as_sorted_vec(b);
62    a == b
63}
64
65/// Assert that two iterators are equivalent
66pub fn assert_equivalent<T, I1, I2>(a: I1, b: I2)
67where
68    T: PartialEq + Ord + std::fmt::Debug,
69    I1: IntoIterator<Item = T> + Clone,
70    I2: IntoIterator<Item = T> + Clone,
71{
72    let a = as_sorted_vec(a);
73    let b = as_sorted_vec(b);
74    assert_eq!(a, b);
75}
76
77/// Assert that two iterators are equivalent
78#[macro_export]
79macro_rules! assert_equivalent_macro {
80    ( $expected:expr, $actual:expr ) => {{
81        let expected = $crate::test_utils::as_sorted_vec($expected);
82        let actual = $crate::test_utils::as_sorted_vec($actual);
83        assert_eq!(expected, actual);
84    }};
85}
86pub use assert_equivalent_macro;
87
88/// Create a sorted clone af an iterable.
89pub fn as_sorted_vec<T: Ord, I: IntoIterator<Item = T> + Clone>(iter: I) -> Vec<T> {
90    let mut list: Vec<T> = iter.clone().into_iter().collect();
91    list.sort();
92    list
93}
94
95/// Return the path of the given function.
96/// If the last function is `f`, it is removed.
97/// The last `{{closure}}` is also removed.
98pub fn format_current_function_module<T>(f: T) -> &'static str {
99    fn type_name_of<T>(_: T) -> &'static str {
100        std::any::type_name::<T>()
101    }
102
103    let name = type_name_of(f);
104    let name = name.strip_suffix("::f").unwrap_or(name);
105    name.strip_suffix("::{{closure}}").unwrap_or(name)
106}
107
108/// Return a string representing the path of the given function.
109pub fn format_current_function_path<T>(f: T) -> String {
110    let name = format_current_function_module(f);
111    name.replace("::", "/")
112}
113
114/// Returns the name of the function that called this macro.
115#[macro_export]
116macro_rules! current_function {
117    () => {{
118        fn f() {}
119        let name = $crate::test_utils::format_current_function_module(f);
120        // The index found is the beginning of the '..', this is why we add 2.
121        let function_name_index = name.rfind("::").map(|index| index + 2).unwrap_or(0);
122
123        &name[function_name_index..]
124    }};
125}
126pub use current_function;
127
128/// Returns the path of the function that called this macro.
129#[macro_export]
130macro_rules! current_function_path {
131    () => {{
132        fn f() {}
133
134        std::path::PathBuf::from($crate::test_utils::format_current_function_path(f))
135    }};
136}
137pub use current_function_path;
138
139#[cfg(test)]
140mod utils {
141    use std::io;
142    use std::sync::Arc;
143    use std::{collections::HashSet, path::Path};
144
145    use slog::{Drain, Logger};
146    use slog_async::Async;
147    use slog_term::{CompactFormat, PlainDecorator};
148
149    use super::*;
150
151    pub struct TestLogger;
152
153    #[cfg(test)]
154    impl TestLogger {
155        fn from_writer<W: io::Write + Send + 'static>(writer: W) -> Logger {
156            let decorator = PlainDecorator::new(writer);
157            let drain = CompactFormat::new(decorator).build().fuse();
158            let drain = Async::new(drain).build().fuse();
159            Logger::root(Arc::new(drain), slog::o!())
160        }
161
162        pub fn stdout() -> Logger {
163            Self::from_writer(slog_term::TestStdoutWriter)
164        }
165
166        pub fn memory() -> (Logger, MemoryDrainForTestInspector) {
167            let (drain, inspector) = MemoryDrainForTest::new();
168            (Logger::root(drain.fuse(), slog::o!()), inspector)
169        }
170    }
171
172    #[test]
173    fn test_equivalent_to() {
174        assert!(equivalent_to(vec![1, 2, 3], vec![3, 2, 1]));
175        assert!(equivalent_to(vec![1, 2, 3], vec![2, 1, 3]));
176        assert!(!equivalent_to(vec![1, 2, 3], vec![3, 2, 1, 4]));
177        assert!(!equivalent_to(vec![1, 2, 3], vec![3, 2]));
178
179        assert!(equivalent_to([1, 2, 3], vec![3, 2, 1]));
180        assert!(equivalent_to(&[1, 2, 3], &vec![3, 2, 1]));
181        assert!(equivalent_to([1, 2, 3], HashSet::from([3, 2, 1])));
182        assert!(equivalent_to(vec![1, 2, 3], HashSet::from([3, 2, 1])));
183        assert!(equivalent_to(&vec![1, 2, 3], &HashSet::from([3, 2, 1])));
184
185        assert_equivalent(vec![1, 2, 3], vec![3, 2, 1]);
186        assert_equivalent(vec![1, 2, 3], vec![2, 1, 3]);
187
188        assert_equivalent([1, 2, 3], vec![3, 2, 1]);
189        assert_equivalent(&[1, 2, 3], &vec![3, 2, 1]);
190        assert_equivalent([1, 2, 3], HashSet::from([3, 2, 1]));
191        assert_equivalent(vec![1, 2, 3], HashSet::from([3, 2, 1]));
192        assert_equivalent(&vec![1, 2, 3], &HashSet::from([3, 2, 1]));
193    }
194
195    #[test]
196    fn test_current_function_extract_function_name() {
197        let name = current_function!();
198
199        assert_eq!("test_current_function_extract_function_name", name);
200    }
201
202    #[tokio::test]
203    async fn test_current_function_extract_async_function_name() {
204        let name = current_function!();
205
206        assert_eq!("test_current_function_extract_async_function_name", name);
207    }
208
209    #[test]
210    fn test_format_function_path_from_given_function() {
211        assert_eq!(
212            "mithril_common/test_utils/utils/test_format_function_path_from_given_function",
213            format_current_function_path(test_format_function_path_from_given_function)
214        );
215    }
216
217    #[test]
218    fn test_format_function_path_from_given_pseudo_function_f() {
219        fn f() {}
220        assert_eq!(
221            "mithril_common/test_utils/utils/test_format_function_path_from_given_pseudo_function_f",
222            format_current_function_path(f)
223        );
224    }
225
226    #[tokio::test]
227    async fn test_format_function_path_from_given_async_function_f() {
228        fn f() {}
229        assert_eq!(
230            "mithril_common/test_utils/utils/test_format_function_path_from_given_async_function_f",
231            format_current_function_path(f)
232        );
233    }
234
235    #[test]
236    fn test_build_current_function_path_using_macros() {
237        assert_eq!(
238            Path::new("mithril_common")
239                .join("test_utils")
240                .join("utils")
241                .join("test_build_current_function_path_using_macros"),
242            current_function_path!()
243        );
244    }
245
246    #[tokio::test]
247    async fn test_build_current_async_function_path_using_macros() {
248        assert_eq!(
249            Path::new("mithril_common")
250                .join("test_utils")
251                .join("utils")
252                .join("test_build_current_async_function_path_using_macros"),
253            current_function_path!()
254        );
255    }
256}