use std::fs::File;
use std::os::windows::io::AsHandle;
use win_shared_os_owned_handle::SharedHandle;
use wtf_string::Wtf16String;
use crate::handle::tests::{FILE_CONTENTS, Fixture, handle_allocation};
use crate::{AclState, OpenFile, SecurityAttributes, SecurityDescriptor};
struct Foundations {
path: OpenFile,
directory: SharedHandle,
file: SharedHandle,
security: SecurityAttributes,
}
impl Foundations {
fn capture(fixture: &Fixture) -> Self {
let directory = fixture.open_directory();
let file = fixture.open_file();
let text = fixture
.directory()
.to_str()
.expect("the fixture path is valid UTF-8");
let descriptor = SecurityDescriptor::from_sddl(&Wtf16String::from("D:(A;;GA;;;WD)"))
.expect("a descriptor with one entry");
Self {
path: OpenFile::new(Wtf16String::from(text)).expect("build the request"),
directory: SharedHandle::from(
directory
.as_handle()
.try_clone_to_owned()
.expect("own the directory handle"),
),
file: SharedHandle::from(
file.as_handle()
.try_clone_to_owned()
.expect("own the file handle"),
),
security: SecurityAttributes::new(Some(descriptor), true),
}
}
fn assert_usable(&self, expected_path: &str) {
assert_eq!(self.path.win32_path().to_string_lossy(), expected_path);
let directory = File::from(
self.directory
.as_handle()
.try_clone_to_owned()
.expect("own the directory handle"),
);
assert!(
directory
.metadata()
.expect("read directory metadata")
.is_dir(),
"the shared directory handle must still name the directory"
);
let file = File::from(
self.file
.as_handle()
.try_clone_to_owned()
.expect("own the file 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>();
}