use super::*;
use crate::{CancellationToken, ScanTermination};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[test]
fn content_inspection_honors_cancel_timeout_and_evidence_modes() {
let root = fixture("content-stop");
let first = root.join("first.rs");
let second = root.join("second.rs");
fs::write(&first, "fn first() {}\n").unwrap();
fs::write(&second, "fn second() {}\n").unwrap();
let files = vec![scanned(first, "first.rs"), scanned(second, "second.rs")];
let token = CancellationToken::new();
token.cancel();
let cancelled = inspect_files(
files.clone(),
&ScanOptions::default().with_cancellation(token),
Instant::now(),
)
.unwrap();
assert_eq!(cancelled.termination, Some(ScanTermination::Cancelled));
assert!(cancelled.files.is_empty());
assert_eq!(cancelled.skipped.len(), 2);
let timeout = inspect_files(
files.clone(),
&ScanOptions::default().with_timeout(Some(Duration::ZERO)),
Instant::now(),
)
.unwrap();
assert_eq!(timeout.termination, Some(ScanTermination::Timeout));
assert_eq!(timeout.skipped.len(), 2);
let selected = inspect_files(
files,
&ScanOptions::default()
.with_timeout(Some(Duration::ZERO))
.selected_files_only(),
Instant::now(),
)
.unwrap();
assert!(selected.skipped.is_empty());
assert_eq!(termination_code(ScanTermination::MaxEntries), 0);
assert_eq!(termination_code(ScanTermination::MaxTotalBytes), 0);
let _ = fs::remove_dir_all(root);
}
#[test]
fn content_read_errors_continue_or_abort_in_both_read_modes() {
let root = fixture("content-errors");
let missing = scanned(root.join("missing.rs"), "missing.rs");
let continued = inspect_files(
vec![missing.clone()],
&ScanOptions::default(),
Instant::now(),
)
.unwrap();
assert!(continued.files.is_empty());
assert_eq!(continued.warnings.len(), 1);
assert_eq!(continued.skipped[0].kind, SkipKind::IoError);
let detect_only = ScanOptions {
hash_file_contents: false,
..ScanOptions::default()
};
let continued = inspect_files(vec![missing.clone()], &detect_only, Instant::now()).unwrap();
assert!(continued.files.is_empty());
assert_eq!(continued.warnings.len(), 1);
let aborted = inspect_files(
vec![missing],
&ScanOptions::default().with_error_policy(ErrorPolicy::Abort),
Instant::now(),
);
assert!(aborted.is_err());
let _ = fs::remove_dir_all(root);
}
fn scanned(absolute: std::path::PathBuf, relative: &str) -> ScannedFile {
ScannedFile {
absolute,
relative: relative.to_owned(),
bytes: 16,
content_hash: None,
}
}
fn fixture(name: &str) -> std::path::PathBuf {
let nonce = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let root = std::env::temp_dir().join(format!("{name}-{}-{nonce}", std::process::id()));
fs::create_dir_all(&root).unwrap();
root
}