use crate::Path;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct RuleContext {
pub field_name: Option<Arc<str>>,
pub parent_path: Path,
pub value_debug: Option<String>,
}
impl RuleContext {
pub fn root(field_name: impl Into<Arc<str>>) -> Self {
Self {
field_name: Some(field_name.into()),
parent_path: Path::root(),
value_debug: None,
}
}
pub fn anonymous() -> Self {
Self {
field_name: None,
parent_path: Path::root(),
value_debug: None,
}
}
pub fn child(&self, field_name: impl Into<Arc<str>>) -> Self {
let parent_path = match &self.field_name {
Some(name) => self.parent_path.clone().field(name.clone()),
None => self.parent_path.clone(),
};
Self {
field_name: Some(field_name.into()),
parent_path,
value_debug: None,
}
}
pub fn with_value_debug(mut self, value: impl Into<String>) -> Self {
self.value_debug = Some(value.into());
self
}
pub fn full_path(&self) -> Path {
match &self.field_name {
Some(name) => self.parent_path.clone().field(name.clone()),
None => self.parent_path.clone(),
}
}
}
impl Default for RuleContext {
fn default() -> Self {
Self::anonymous()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_root_context() {
let ctx = RuleContext::root("username");
assert_eq!(ctx.field_name, Some("username".into()));
assert_eq!(ctx.parent_path.to_string(), "");
assert_eq!(ctx.value_debug, None);
}
#[test]
fn test_anonymous_context() {
let ctx = RuleContext::anonymous();
assert_eq!(ctx.field_name, None);
assert_eq!(ctx.parent_path.to_string(), "");
}
#[test]
fn test_child_context_with_named_parent() {
let parent = RuleContext::root("user");
let child = parent.child("email");
assert_eq!(child.field_name, Some("email".into()));
assert_eq!(child.parent_path.to_string(), "user");
}
#[test]
fn test_child_context_with_anonymous_parent() {
let parent = RuleContext::anonymous();
let child = parent.child("email");
assert_eq!(child.field_name, Some("email".into()));
assert_eq!(child.parent_path.to_string(), "");
}
#[test]
fn test_with_value_debug() {
let ctx = RuleContext::root("age").with_value_debug("42");
assert_eq!(ctx.value_debug, Some("42".to_string()));
}
#[test]
fn test_full_path_root_field() {
let ctx = RuleContext::root("email");
assert_eq!(ctx.full_path().to_string(), "email");
}
#[test]
fn test_full_path_nested_field() {
let parent = RuleContext::root("user");
let child = parent.child("email");
assert_eq!(child.full_path().to_string(), "user.email");
}
#[test]
fn test_full_path_anonymous() {
let ctx = RuleContext::anonymous();
assert_eq!(ctx.full_path().to_string(), "");
}
#[test]
fn test_default_context() {
let ctx = RuleContext::default();
assert_eq!(ctx.field_name, None);
assert_eq!(ctx.parent_path.to_string(), "");
}
#[test]
fn test_deeply_nested_context() {
let root = RuleContext::root("team");
let member = root.child("members");
let user = member.child("user");
let email = user.child("email");
assert_eq!(email.full_path().to_string(), "team.members.user.email");
}
}