use super::super::workspace::resolve_absolute_workspace_root;
use camino::Utf8PathBuf;
use proptest::{prelude::*, test_runner::TestCaseError};
use std::path::{MAIN_SEPARATOR_STR, Path};
fn component() -> impl Strategy<Value = String> {
"[a-z]{1,6}".prop_map(String::from)
}
fn joined(parts: &[String]) -> String {
parts.join(MAIN_SEPARATOR_STR)
}
fn optional_relative_base() -> impl Strategy<Value = Option<String>> {
proptest::option::of(
proptest::collection::vec(component(), 0..3).prop_map(|parts| joined(&parts)),
)
}
fn absolute_anchor() -> Result<Utf8PathBuf, TestCaseError> {
let cwd = std::env::current_dir()
.map_err(|err| TestCaseError::fail(format!("read the working directory: {err}")))?;
Utf8PathBuf::from_path_buf(cwd)
.map_err(|_| TestCaseError::fail("the working directory must be valid UTF-8"))
}
proptest! {
#[test]
fn absolute_parent_ignores_the_base(
parent_parts in proptest::collection::vec(component(), 1..4),
base in optional_relative_base(),
) {
let anchor = absolute_anchor()?;
let parent = anchor.join(joined(&parent_parts));
let base_path = base.as_deref().map(Path::new);
let resolved =
resolve_absolute_workspace_root(&parent, base_path).expect("absolute parent resolves");
prop_assert_eq!(resolved, parent, "an absolute parent must not be re-anchored");
}
#[test]
fn relative_parent_joins_onto_an_absolute_base(
base_parts in proptest::collection::vec(component(), 1..3),
parent_parts in proptest::collection::vec(component(), 1..4),
) {
let anchor = absolute_anchor()?;
let base = anchor.join(joined(&base_parts));
let parent = Utf8PathBuf::from(joined(&parent_parts));
let resolved = resolve_absolute_workspace_root(&parent, Some(base.as_std_path()))
.expect("relative parent resolves against an absolute base");
prop_assert_eq!(
resolved,
base.join(&parent),
"a relative parent must join onto the absolute base verbatim"
);
}
#[test]
fn relative_parent_always_resolves_absolutely(
parent_parts in proptest::collection::vec(component(), 1..4),
base in optional_relative_base(),
) {
let anchor = absolute_anchor()?;
let parent = Utf8PathBuf::from(joined(&parent_parts));
let expected = base.as_ref().map_or_else(
|| anchor.join(&parent),
|relative_base| anchor.join(relative_base).join(&parent),
);
let base_path = base.as_deref().map(Path::new);
let resolved =
resolve_absolute_workspace_root(&parent, base_path).expect("relative parent resolves");
prop_assert!(resolved.is_absolute(), "root {resolved:?} should be absolute");
prop_assert_eq!(
resolved,
expected,
"a relative parent must join onto the current directory and relative base"
);
}
}