use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use pi_async_fs::{
CreateDirectoriesFailure, CreateFailure, CreateTargetEvidence,
CrossProcessCreateSuccess,
};
use pi_result::ErrorKind;
fn hash_of(value: &CreateTargetEvidence) -> u64 {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
hasher.finish()
}
fn assert_send_sync_static<T: Send + Sync + 'static>() {}
#[test]
fn test_create_target_evidence_value_traits_cover_every_variant() {
assert_send_sync_static::<CreateTargetEvidence>();
let not_created = CreateTargetEvidence::NotCreatedByOperation;
let same_not_created = CreateTargetEvidence::NotCreatedByOperation;
let created = CreateTargetEvidence::CreatedByOperation;
let unknown = CreateTargetEvidence::Unknown;
assert_eq!(format!("{not_created:?}"), "NotCreatedByOperation");
assert_eq!(format!("{created:?}"), "CreatedByOperation");
assert_eq!(format!("{unknown:?}"), "Unknown");
assert_eq!(not_created.to_string(), "target not created by operation");
assert_eq!(created.to_string(), "target created by operation");
assert_eq!(unknown.to_string(), "target creation outcome unknown");
assert_eq!(not_created, same_not_created);
assert_ne!(not_created, created);
assert!(not_created < created);
assert!(created < unknown);
assert_eq!(hash_of(¬_created), hash_of(&same_not_created));
}
#[test]
fn test_create_failure_preserves_error_and_target_evidence() {
let failure = CreateFailure::new(
pi_result::error_stack::Report::new(ErrorKind::AlreadyExists),
CreateTargetEvidence::NotCreatedByOperation,
);
assert_eq!(failure.error().current_context(), &ErrorKind::AlreadyExists);
assert_eq!(
failure.target_evidence(),
&CreateTargetEvidence::NotCreatedByOperation
);
assert_eq!(
failure.to_string(),
"already exists; target: target not created by operation"
);
let debug = format!("{failure:?}");
assert!(debug.contains("CreateFailure"));
assert!(debug.contains("already exists"), "{debug}");
assert!(debug.contains("NotCreatedByOperation"));
let (error, evidence) = failure.into_parts();
assert_eq!(error.current_context(), &ErrorKind::AlreadyExists);
assert_eq!(evidence, CreateTargetEvidence::NotCreatedByOperation);
}
#[test]
fn test_create_directories_failure_preserves_ordered_assets_without_formatting_them() {
struct NonDebugLocator(&'static str);
let failure = CreateDirectoriesFailure::new(
pi_result::error_stack::Report::new(ErrorKind::PermissionDenied),
vec![NonDebugLocator("secret-parent"), NonDebugLocator("secret-child")],
vec![NonDebugLocator("secret-uncertain")],
);
assert_eq!(failure.error().current_context(), &ErrorKind::PermissionDenied);
assert_eq!(failure.confirmed_created().len(), 2);
assert_eq!(failure.confirmed_created()[0].0, "secret-parent");
assert_eq!(failure.confirmed_created()[1].0, "secret-child");
assert_eq!(failure.uncertain_targets().len(), 1);
assert_eq!(failure.uncertain_targets()[0].0, "secret-uncertain");
let debug = format!("{failure:?}");
let display = failure.to_string();
assert!(debug.contains("CreateDirectoriesFailure"));
assert!(debug.contains("permission denied"), "{debug}");
assert!(debug.contains("confirmed_created_count: 2"));
assert!(debug.contains("uncertain_targets_count: 1"));
assert!(!debug.contains("secret-"));
assert_eq!(
display,
"permission denied; confirmed created: 2; uncertain targets: 1"
);
assert!(!display.contains("secret-"));
let (error, confirmed, uncertain) = failure.into_parts();
assert_eq!(error.current_context(), &ErrorKind::PermissionDenied);
assert_eq!(
confirmed.into_iter().map(|locator| locator.0).collect::<Vec<_>>(),
["secret-parent", "secret-child"]
);
assert_eq!(
uncertain.into_iter().map(|locator| locator.0).collect::<Vec<_>>(),
["secret-uncertain"]
);
}
#[test]
fn test_cross_process_create_success_preserves_both_non_debug_assets() {
struct Authority(u32);
struct FileResource(Vec<u8>);
let mut success = CrossProcessCreateSuccess::new(
Authority(7),
FileResource(vec![1, 2, 3]),
);
assert_eq!(success.authority().0, 7);
assert_eq!(success.file().0, [1, 2, 3]);
success.file_mut().0.push(4);
assert_eq!(success.file().0, [1, 2, 3, 4]);
assert_eq!(
format!("{success:?}"),
"CrossProcessCreateSuccess { authority: <present>, file: <present> }"
);
assert_eq!(
success.to_string(),
"cross-process authority and file resource are present"
);
let (authority, file) = success.into_parts();
assert_eq!(authority.0, 7);
assert_eq!(file.0, [1, 2, 3, 4]);
}