chie_core/
test_utils.rs

1//! Test utilities and helpers for testing.
2//!
3//! This module provides helpers and utilities to simplify writing tests
4//! across the CHIE codebase.
5//!
6//! # Example
7//!
8//! ```rust
9//! use chie_core::test_utils::{MockPeerBuilder, random_cid, TempDir};
10//!
11//! // Create mock peer
12//! let peer = MockPeerBuilder::new("peer1")
13//!     .with_reputation(0.8)
14//!     .build();
15//!
16//! // Generate random test data
17//! let cid = random_cid();
18//! let temp_dir = TempDir::new("test").unwrap();
19//! ```
20
21use std::path::PathBuf;
22
23/// Builder for creating mock peer data.
24#[derive(Debug, Clone)]
25pub struct MockPeerBuilder {
26    peer_id: String,
27    reputation_score: f64,
28    latency_ms: f64,
29    bandwidth_bps: u64,
30    is_online: bool,
31}
32
33impl MockPeerBuilder {
34    /// Create a new mock peer builder.
35    #[inline]
36    pub fn new(peer_id: impl Into<String>) -> Self {
37        Self {
38            peer_id: peer_id.into(),
39            reputation_score: 0.5,
40            latency_ms: 50.0,
41            bandwidth_bps: 10 * 1024 * 1024, // 10 Mbps
42            is_online: true,
43        }
44    }
45
46    /// Set the reputation score.
47    #[inline]
48    pub fn with_reputation(mut self, score: f64) -> Self {
49        self.reputation_score = score.clamp(0.0, 1.0);
50        self
51    }
52
53    /// Set the latency in milliseconds.
54    #[inline]
55    pub fn with_latency(mut self, latency_ms: f64) -> Self {
56        self.latency_ms = latency_ms;
57        self
58    }
59
60    /// Set the bandwidth in bytes per second.
61    #[inline]
62    pub fn with_bandwidth(mut self, bandwidth_bps: u64) -> Self {
63        self.bandwidth_bps = bandwidth_bps;
64        self
65    }
66
67    /// Set online status.
68    #[inline]
69    pub fn online(mut self, is_online: bool) -> Self {
70        self.is_online = is_online;
71        self
72    }
73
74    /// Build the peer data.
75    #[inline]
76    pub fn build(self) -> MockPeer {
77        MockPeer {
78            peer_id: self.peer_id,
79            reputation_score: self.reputation_score,
80            latency_ms: self.latency_ms,
81            bandwidth_bps: self.bandwidth_bps,
82            is_online: self.is_online,
83        }
84    }
85}
86
87/// Mock peer data.
88#[derive(Debug, Clone)]
89pub struct MockPeer {
90    /// Peer identifier.
91    pub peer_id: String,
92    /// Reputation score (0.0 to 1.0).
93    pub reputation_score: f64,
94    /// Latency in milliseconds.
95    pub latency_ms: f64,
96    /// Bandwidth in bytes per second.
97    pub bandwidth_bps: u64,
98    /// Online status.
99    pub is_online: bool,
100}
101
102/// Helper for creating temporary test directories.
103pub struct TempDir {
104    path: PathBuf,
105}
106
107impl TempDir {
108    /// Create a new temporary directory.
109    pub fn new(prefix: &str) -> std::io::Result<Self> {
110        let path =
111            std::env::temp_dir().join(format!("chie-test-{}-{}", prefix, rand::random::<u64>()));
112        std::fs::create_dir_all(&path)?;
113        Ok(Self { path })
114    }
115
116    /// Get the path to the temporary directory.
117    #[inline]
118    pub fn path(&self) -> &PathBuf {
119        &self.path
120    }
121
122    /// Get the path as a string.
123    #[inline]
124    pub fn path_str(&self) -> &str {
125        self.path.to_str().unwrap()
126    }
127}
128
129impl Drop for TempDir {
130    fn drop(&mut self) {
131        let _ = std::fs::remove_dir_all(&self.path);
132    }
133}
134
135/// Generate a random CID for testing.
136#[inline]
137pub fn random_cid() -> String {
138    format!("Qm{:x}", rand::random::<u128>())
139}
140
141/// Generate a random peer ID for testing.
142#[inline]
143pub fn random_peer_id() -> String {
144    format!("peer-{:x}", rand::random::<u64>())
145}
146
147/// Generate random bytes for testing.
148pub fn random_bytes(size: usize) -> Vec<u8> {
149    (0..size).map(|_| rand::random::<u8>()).collect()
150}
151
152/// Assert that two floats are approximately equal.
153#[inline]
154pub fn assert_approx_eq(a: f64, b: f64, epsilon: f64) {
155    assert!(
156        (a - b).abs() < epsilon,
157        "Expected {} ≈ {}, diff: {}",
158        a,
159        b,
160        (a - b).abs()
161    );
162}
163
164/// Mock configuration for testing.
165pub struct MockConfig;
166
167impl MockConfig {
168    /// Create a minimal storage configuration.
169    #[inline]
170    pub fn storage() -> crate::config::StorageSettings {
171        crate::config::StorageSettings::new(
172            PathBuf::from("/tmp/chie-test"),
173            10 * 1024 * 1024 * 1024, // 10 GB
174        )
175    }
176
177    /// Create a minimal network configuration.
178    #[inline]
179    pub fn network() -> crate::config::NetworkSettings {
180        crate::config::NetworkSettings::new(100 * 1024 * 1024 / 8) // 100 Mbps
181    }
182
183    /// Create a minimal coordinator configuration.
184    #[inline]
185    pub fn coordinator() -> crate::config::CoordinatorSettings {
186        crate::config::CoordinatorSettings::new("http://localhost:8080".to_string())
187    }
188
189    /// Create a complete node settings for testing.
190    #[inline]
191    pub fn node_settings() -> crate::config::NodeSettings {
192        crate::config::NodeSettings {
193            storage: Self::storage(),
194            network: Self::network(),
195            coordinator: Self::coordinator(),
196            performance: crate::config::PerformanceSettings::default(),
197        }
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204
205    #[test]
206    fn test_mock_peer_builder() {
207        let peer = MockPeerBuilder::new("peer1")
208            .with_reputation(0.8)
209            .with_latency(100.0)
210            .build();
211
212        assert_eq!(peer.peer_id, "peer1");
213        assert_eq!(peer.reputation_score, 0.8);
214        assert_eq!(peer.latency_ms, 100.0);
215    }
216
217    #[test]
218    fn test_mock_peer_reputation_clamping() {
219        let peer = MockPeerBuilder::new("peer1").with_reputation(1.5).build();
220        assert_eq!(peer.reputation_score, 1.0);
221
222        let peer = MockPeerBuilder::new("peer2").with_reputation(-0.5).build();
223        assert_eq!(peer.reputation_score, 0.0);
224    }
225
226    #[test]
227    fn test_temp_dir_creation() {
228        let temp = TempDir::new("test").unwrap();
229        assert!(temp.path().exists());
230        assert!(temp.path().is_dir());
231    }
232
233    #[test]
234    fn test_temp_dir_cleanup() {
235        let path = {
236            let temp = TempDir::new("cleanup").unwrap();
237            temp.path().clone()
238        };
239        // After drop, directory should be removed
240        assert!(!path.exists());
241    }
242
243    #[test]
244    fn test_random_cid() {
245        let cid1 = random_cid();
246        let cid2 = random_cid();
247
248        assert!(cid1.starts_with("Qm"));
249        assert_ne!(cid1, cid2); // Should be different
250    }
251
252    #[test]
253    fn test_random_peer_id() {
254        let peer1 = random_peer_id();
255        let peer2 = random_peer_id();
256
257        assert!(peer1.starts_with("peer-"));
258        assert_ne!(peer1, peer2);
259    }
260
261    #[test]
262    fn test_random_bytes() {
263        let bytes = random_bytes(100);
264        assert_eq!(bytes.len(), 100);
265    }
266
267    #[test]
268    fn test_assert_approx_eq() {
269        assert_approx_eq(1.0, 1.0001, 0.001);
270        assert_approx_eq(0.5, 0.499, 0.01);
271    }
272
273    #[test]
274    #[should_panic]
275    fn test_assert_approx_eq_fails() {
276        assert_approx_eq(1.0, 2.0, 0.001);
277    }
278
279    #[test]
280    fn test_mock_config_storage() {
281        let storage = MockConfig::storage();
282        assert_eq!(storage.max_bytes, 10 * 1024 * 1024 * 1024);
283    }
284
285    #[test]
286    fn test_mock_config_node_settings() {
287        let settings = MockConfig::node_settings();
288        assert!(settings.validate().is_ok());
289    }
290
291    #[test]
292    fn test_mock_peer_online_status() {
293        let peer = MockPeerBuilder::new("peer1").online(false).build();
294        assert!(!peer.is_online);
295
296        let peer = MockPeerBuilder::new("peer2").online(true).build();
297        assert!(peer.is_online);
298    }
299}