use std::fs::File;
use std::os::windows::io::AsHandle;
use wtf_string::Wtf16String;
use crate::handle::tests::{FILE_CONTENTS, Fixture, handle_allocation};
use crate::security::tests::Absolute;
use crate::{AclState, CapturedHandle, PreparedPath, SecurityAttributes, SecurityDescriptor};
struct Foundations {
path: PreparedPath,
directory: CapturedHandle,
file: CapturedHandle,
security: SecurityAttributes,
}
impl Foundations {
fn capture(fixture: &Fixture) -> Self {
let directory = fixture.open_directory();
let file = fixture.open_file();
let absolute = Absolute::with_populated_dacl();
let text = fixture
.directory()
.to_str()
.expect("the fixture path is valid UTF-8");
let descriptor = unsafe { SecurityDescriptor::capture(absolute.as_ptr()) }
.expect("capture a descriptor");
Self {
path: crate::prepare(&Wtf16String::from(text)).expect("prepare the fixture path"),
directory: CapturedHandle::capture(directory.as_handle())
.expect("capture the directory handle"),
file: CapturedHandle::capture(file.as_handle()).expect("capture the file handle"),
security: SecurityAttributes::new(Some(descriptor), true),
}
}
fn assert_usable(&self, expected_path: &str) {
assert_eq!(self.path.as_wtf16().to_string_lossy(), expected_path);
let directory = File::from(
self.directory
.try_clone()
.expect("duplicate the directory handle")
.into_owned_handle(),
);
assert!(
directory
.metadata()
.expect("read directory metadata")
.is_dir(),
"the captured directory handle must still name the directory"
);
let file = File::from(
self.file
.try_clone()
.expect("duplicate the file handle")
.into_owned_handle(),
);
assert_eq!(
file.metadata().expect("read file metadata").len(),
FILE_CONTENTS.len() as u64
);
assert!(self.security.inherit_handle());
assert_eq!(
self.security
.descriptor()
.expect("a descriptor was captured")
.dacl()
.expect("read the DACL"),
AclState::Populated(1)
);
}
}
#[test]
fn the_foundations_outlive_every_input_they_were_built_from() {
let _allocating = handle_allocation()
.read()
.expect("the lock is not poisoned");
let (foundations, expected_path) = {
let fixture = Fixture::new("composite-outlives");
let expected_path = fixture
.directory()
.to_str()
.expect("the fixture path is valid UTF-8")
.to_owned();
(Foundations::capture(&fixture), expected_path)
};
foundations.assert_usable(&expected_path);
}
#[test]
fn the_foundations_work_on_a_thread_that_never_saw_their_inputs() {
let _allocating = handle_allocation()
.read()
.expect("the lock is not poisoned");
let (foundations, expected_path) = {
let fixture = Fixture::new("composite-thread");
let expected_path = fixture
.directory()
.to_str()
.expect("the fixture path is valid UTF-8")
.to_owned();
(Foundations::capture(&fixture), expected_path)
};
std::thread::spawn(move || foundations.assert_usable(&expected_path))
.join()
.expect("the worker did not panic");
}
#[test]
fn the_composite_moves_and_shares_across_threads() {
const fn assert_send<T: Send>() {}
const fn assert_sync<T: Sync>() {}
assert_send::<Foundations>();
assert_sync::<Foundations>();
}