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