1use crate::{ProgressEntry, PullResult, PullStream, Puller};
5use futures::stream;
6use std::{sync::Arc, vec::Vec};
7
8#[must_use]
20pub fn build_mock_data(size: usize) -> Vec<u8> {
21 let mut out = Vec::with_capacity(size.next_multiple_of(8));
22 let mut state: u64 = 0x2545_F491_4F6C_DD1D;
23 while out.len() < size {
24 state ^= state << 13;
25 state ^= state >> 7;
26 state ^= state << 17;
27 out.extend_from_slice(&state.to_le_bytes());
28 }
29 out.truncate(size);
30 out
31}
32
33#[derive(Debug, Clone)]
35pub struct MockPuller(pub Arc<[u8]>);
36impl MockPuller {
37 #[must_use]
38 pub fn new(data: &[u8]) -> Self {
39 Self(Arc::from(data))
40 }
41}
42impl Puller for MockPuller {
43 type Error = std::convert::Infallible;
44 fn pull(
45 &mut self,
46 range: Option<&ProgressEntry>,
47 ) -> impl Future<Output = PullResult<impl PullStream<Self::Error>, Self::Error>> {
48 let data = match range {
49 #[allow(clippy::cast_possible_truncation)]
50 Some(r) => &self.0[r.start as usize..r.end as usize],
51 None => &self.0,
52 };
53 std::future::ready(Ok(stream::iter(
54 data.chunks(2).map(|c| Ok(c.iter().copied().collect())),
55 )))
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use futures::TryStreamExt;
63
64 async fn pull_all(puller: &mut MockPuller, range: Option<&ProgressEntry>) -> Vec<u8> {
65 let mut stream = puller.pull(range).await.unwrap();
66 let mut got = Vec::new();
67 while let Some(chunk) = stream.try_next().await.unwrap() {
68 got.extend_from_slice(&chunk[..]);
69 }
70 got
71 }
72
73 #[tokio::test]
76 async fn mock_puller_yields_exact_range_in_order() {
77 let data = build_mock_data(30);
78 let mut puller = MockPuller::new(&data);
79 let got = pull_all(&mut puller, Some(&(10..20))).await;
80 assert_eq!(got, data[10..20]);
81 }
82
83 #[tokio::test]
85 async fn mock_puller_none_yields_full_source() {
86 let data = build_mock_data(17);
87 let mut puller = MockPuller::new(&data);
88 let got = pull_all(&mut puller, None).await;
89 assert_eq!(got, data);
90 }
91
92 #[test]
96 fn build_mock_data_is_deterministic_and_prefix_stable() {
97 let long = build_mock_data(1024);
98 for size in [0, 1, 7, 8, 9, 300, 1024] {
99 let short = build_mock_data(size);
100 assert_eq!(short.len(), size);
101 assert_eq!(short, build_mock_data(size));
102 assert_eq!(short[..], long[..size]);
103 }
104 }
105
106 #[test]
111 fn build_mock_data_has_no_repeating_window() {
112 let data = build_mock_data(64 * 1024);
113 let mut seen = std::collections::HashSet::with_capacity(data.len());
114 for window in data.windows(8) {
115 assert!(seen.insert(window), "window {window:?} occurs twice");
116 }
117 }
118}