use crate::{
Reader,
test_util::test_entry_data::{ArbitraryTestEntryDataParams, TestEntryData},
};
use assert2::assert;
use core::panic;
use std::{collections::HashMap, path::Path, pin::pin};
use tempfile::NamedTempFile;
use test_strategy::proptest;
use tokio::{fs::File, io, process::Command};
async fn external_command_test<F: FnOnce(&Path) -> Command>(
data: TestEntryData,
command_builder: F,
) -> Vec<u8> {
let mut zippity = pin!(Into::<Reader<_>>::into(data));
let tempfile = NamedTempFile::new().unwrap();
let (f, temp_path) = tempfile.into_parts();
let mut f = File::from_std(f);
io::copy(&mut zippity.as_mut(), &mut f).await.unwrap();
f.sync_all().await.unwrap();
drop(f);
let unzip_output = command_builder(&temp_path)
.output()
.await
.expect("Could not run command");
assert!(
unzip_output.status.success(),
"command failed\nstdout:\n{}\nstderr:\n{}",
std::str::from_utf8(&unzip_output.stdout).unwrap(),
std::str::from_utf8(&unzip_output.stderr).unwrap()
);
unzip_output.stdout
}
#[proptest(async = "tokio")]
async fn unzip_t(
#[any(ArbitraryTestEntryDataParams {
entry_name_pattern: ".{1,30}", // Unzip doesn't like empty entry names
// Fails with `mismatching "local" filename (foo), continuing with "central" filename version`
count_range: 1..64, ..Default::default()
})]
data: TestEntryData,
) {
external_command_test(data, |p| {
let mut command = Command::new("unzip");
command.arg("-t").arg(p.as_os_str());
command
})
.await;
}
#[proptest(async = "tokio")]
async fn python_zipfile(
#[any(ArbitraryTestEntryDataParams {
entry_name_pattern: "[^\0]{0,30}", // zipfile doesn't handle null bytes well
..Default::default()
})]
data: TestEntryData,
) {
let json_data = external_command_test(data.clone(), |p| {
let mut command = Command::new("python");
command
.arg("-c")
.arg(
"
import zipfile
import sys
import json
zf = zipfile.ZipFile(sys.argv[1])
output = {}
for info in zf.filelist:
output[info.filename] = info.file_size
with zf.open(info.filename, 'r') as f:
while f.read(2**20):
pass
print(json.dumps(output))
",
)
.arg(p.as_os_str());
command
})
.await;
let unzipped_summary: HashMap<String, usize> = serde_json::from_slice(&json_data).unwrap();
dbg!(&unzipped_summary);
assert!(unzipped_summary.len() == data.0.len());
for (k, len) in unzipped_summary {
let Some(expected_bytes) = data.0.get(&k) else {
panic!("Key {:?} should exist in the unpacked summary", &k);
};
assert!(len == expected_bytes.len());
}
}