1use rand::{RngExt, SeedableRng, rngs::StdRng};
21use std::{env, error::Error, fs, io::Write, path::PathBuf};
22
23pub fn random_bytes(n: usize) -> Vec<u8> {
25 let mut result = vec![];
26 let mut rng = seedable_rng();
27 for _ in 0..n {
28 result.push(rng.random_range(0..255));
29 }
30 result
31}
32
33pub fn seedable_rng() -> StdRng {
35 StdRng::seed_from_u64(42)
36}
37
38pub fn get_temp_file(file_name: &str, content: &[u8]) -> fs::File {
42 let dir = env::current_dir().unwrap().join("target/debug/testdata");
44 fs::create_dir_all(&dir).unwrap();
45 let path_buf = dir.join(file_name);
46
47 let mut tmp_file = fs::File::create(path_buf.as_path()).unwrap();
49 tmp_file.write_all(content).unwrap();
50 tmp_file.sync_all().unwrap();
51
52 let file = fs::OpenOptions::new()
54 .read(true)
55 .write(true)
56 .open(path_buf.as_path());
57 assert!(file.is_ok());
58 file.unwrap()
59}
60
61pub fn arrow_test_data() -> String {
76 match get_data_dir("ARROW_TEST_DATA", "../testing/data") {
77 Ok(pb) => pb.display().to_string(),
78 Err(err) => panic!("failed to get arrow data dir: {err}"),
79 }
80}
81
82pub fn parquet_test_data() -> String {
98 match get_data_dir("PARQUET_TEST_DATA", "../parquet-testing/data") {
99 Ok(pb) => pb.display().to_string(),
100 Err(err) => panic!("failed to get parquet data dir: {err}"),
101 }
102}
103
104fn get_data_dir(udf_env: &str, submodule_data: &str) -> Result<PathBuf, Box<dyn Error>> {
114 if let Ok(dir) = env::var(udf_env) {
116 let trimmed = dir.trim().to_string();
117 if !trimmed.is_empty() {
118 let pb = PathBuf::from(trimmed);
119 if pb.is_dir() {
120 return Ok(pb);
121 } else {
122 return Err(format!(
123 "the data dir `{}` defined by env {} not found",
124 pb.display(),
125 udf_env
126 )
127 .into());
128 }
129 }
130 }
131
132 let dir = env!("CARGO_MANIFEST_DIR");
138
139 let pb = PathBuf::from(dir).join(submodule_data);
140 if pb.is_dir() {
141 Ok(pb)
142 } else {
143 Err(format!(
144 "env `{}` is undefined or has empty value, and the pre-defined data dir `{}` not found\n\
145 HINT: try running `git submodule update --init`",
146 udf_env,
147 pb.display(),
148 ).into())
149 }
150}
151
152#[derive(Debug, Clone)]
154pub struct BadIterator<T> {
155 cur: usize,
157 limit: usize,
159 claimed: usize,
161 pub items: Vec<T>,
164}
165
166impl<T> BadIterator<T> {
167 pub fn new(limit: usize, claimed: usize, items: Vec<T>) -> Self {
170 assert!(!items.is_empty());
171 Self {
172 cur: 0,
173 limit,
174 claimed,
175 items,
176 }
177 }
178}
179
180impl<T: Clone> Iterator for BadIterator<T> {
181 type Item = T;
182
183 fn next(&mut self) -> Option<Self::Item> {
184 if self.cur < self.limit {
185 let next_item_idx = self.cur % self.items.len();
186 let next_item = self.items[next_item_idx].clone();
187 self.cur += 1;
188 Some(next_item)
189 } else {
190 None
191 }
192 }
193
194 fn size_hint(&self) -> (usize, Option<usize>) {
196 (0, Some(self.claimed))
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn test_data_dir() {
206 let udf_env = "get_data_dir";
207 let cwd = env::current_dir().unwrap();
208
209 let existing_pb = cwd.join("..");
210 let existing = existing_pb.display().to_string();
211 let existing_str = existing.as_str();
212
213 let non_existing = cwd.join("non-existing-dir").display().to_string();
214 let non_existing_str = non_existing.as_str();
215
216 unsafe { env::set_var(udf_env, non_existing_str) };
217 let res = get_data_dir(udf_env, existing_str);
218 assert!(res.is_err());
219
220 unsafe { env::set_var(udf_env, "") };
221 let res = get_data_dir(udf_env, existing_str);
222 assert!(res.is_ok());
223 assert_eq!(res.unwrap(), existing_pb);
224
225 unsafe { env::set_var(udf_env, " ") };
226 let res = get_data_dir(udf_env, existing_str);
227 assert!(res.is_ok());
228 assert_eq!(res.unwrap(), existing_pb);
229
230 unsafe { env::set_var(udf_env, existing_str) };
231 let res = get_data_dir(udf_env, existing_str);
232 assert!(res.is_ok());
233 assert_eq!(res.unwrap(), existing_pb);
234
235 unsafe { env::remove_var(udf_env) };
236 let res = get_data_dir(udf_env, non_existing_str);
237 assert!(res.is_err());
238
239 let res = get_data_dir(udf_env, existing_str);
240 assert!(res.is_ok());
241 assert_eq!(res.unwrap(), existing_pb);
242 }
243
244 #[test]
245 fn test_happy() {
246 let res = arrow_test_data();
247 assert!(PathBuf::from(res).is_dir());
248
249 let res = parquet_test_data();
250 assert!(PathBuf::from(res).is_dir());
251 }
252}