use std::fmt;
use crate::path::CanonicalPath;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ProjectRoot {
WorkspaceRoot,
Nested(CanonicalPath),
}
impl ProjectRoot {
#[must_use]
pub fn is_workspace_root(&self) -> bool {
matches!(self, Self::WorkspaceRoot)
}
#[must_use]
pub fn as_canonical_path(&self) -> Option<&CanonicalPath> {
match self {
Self::WorkspaceRoot => None,
Self::Nested(p) => Some(p),
}
}
}
impl fmt::Display for ProjectRoot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::WorkspaceRoot => f.write_str("/"),
Self::Nested(p) => p.fmt(f),
}
}
}
impl From<CanonicalPath> for ProjectRoot {
fn from(p: CanonicalPath) -> Self {
Self::Nested(p)
}
}
#[cfg(test)]
mod tests {
use crate::path::{CanonicalPath, HazPath, ProjectRoot};
fn nested(s: &str) -> ProjectRoot {
ProjectRoot::Nested(CanonicalPath::from_absolute(&HazPath::parse(s).unwrap()).unwrap())
}
#[test]
fn workspace_root_display_is_slash() {
assert_eq!(ProjectRoot::WorkspaceRoot.to_string(), "/");
}
#[test]
fn nested_display_matches_canonical_path() {
assert_eq!(nested("/lib_core").to_string(), "/lib_core");
assert_eq!(nested("/web/frontend").to_string(), "/web/frontend");
}
#[test]
fn is_workspace_root_discriminates() {
assert!(ProjectRoot::WorkspaceRoot.is_workspace_root());
assert!(!nested("/lib_core").is_workspace_root());
}
#[test]
fn as_canonical_path_returns_none_for_workspace_root() {
assert!(ProjectRoot::WorkspaceRoot.as_canonical_path().is_none());
}
#[test]
fn as_canonical_path_returns_inner_for_nested() {
let cp = CanonicalPath::from_absolute(&HazPath::parse("/lib_core").unwrap()).unwrap();
let pr = ProjectRoot::Nested(cp.clone());
assert_eq!(pr.as_canonical_path(), Some(&cp));
}
#[test]
fn equality_within_nested_delegates_to_canonical_path() {
assert_eq!(nested("/lib_core"), nested("/lib_core"));
assert_ne!(nested("/lib_core"), nested("/web/frontend"));
}
#[test]
fn workspace_root_and_nested_are_distinct() {
assert_ne!(ProjectRoot::WorkspaceRoot, nested("/lib_core"));
}
#[test]
fn from_canonical_path_yields_nested_variant() {
let cp = CanonicalPath::from_absolute(&HazPath::parse("/lib_core").unwrap()).unwrap();
let pr: ProjectRoot = cp.clone().into();
assert_eq!(pr, ProjectRoot::Nested(cp));
}
}