use crate::RJini;
use anyhow::anyhow;
use anyhow::Result;
use std::ops::Add;
use std::panic::Location;
impl From<&str> for RJini {
fn from(xpath: &str) -> Self {
RJini {
xpath: xpath.to_string(),
}
}
}
impl RJini {
pub fn add_node(&self, node: &str) -> Result<RJini> {
Self::validate(node)?;
let b = self.xpath.clone() + node + "/";
Ok(RJini { xpath: b })
}
pub fn remove_node(&self, node: &str) -> RJini {
let b = self.xpath.replace(&node.to_string().add("/"), "");
RJini { xpath: b }
}
pub fn replace_node(&self, origin: &str, new: &str) -> Result<RJini> {
Self::validate(new)?;
let x = self.xpath.replace(origin, new);
Ok(RJini { xpath: x })
}
pub fn nodes(&self) -> Result<Vec<&str>> {
Ok(regex::Regex::new(r"(//|/)")?.split(&self.xpath).collect())
}
pub fn add_property(&self, property: &str) -> Result<RJini> {
Self::validate(&property)?;
Ok(Self::add_node(
self,
&(String::from(property) + "()").as_str(),
)?)
}
pub fn remove_property(&self, property: &str) -> RJini {
let x = self
.xpath
.clone()
.replace((String::from(property) + "()").as_str(), "");
RJini { xpath: x }
}
fn validate(node: &str) -> Result<()> {
let location = Location::caller();
if node.contains(' ') {
return Err(anyhow!(format!(
"{location}: The \"{node}\" contain spaces"
)));
}
Ok(())
}
}
#[test]
fn checks_creates_rjini_from() -> Result<()> {
let j = RJini::from("parent/child");
assert!(j.xpath.contains("child"));
Ok(())
}
#[test]
fn checks_adds_node() -> Result<()> {
let j = RJini::from("parent/");
let j = j.add_node("child")?;
let j = j.add_node("toys")?;
println!("{}", j.xpath);
assert!(j.xpath.contains("child/") && j.xpath.contains("toys/"));
Ok(())
}
#[test]
fn checks_error_on_add_wrong_node() -> Result<()> {
let actual = format!(
"{}",
RJini::empty()
.add_node("so me no de")
.unwrap_err()
.root_cause()
);
assert!(actual.contains("The \"so me no de\" contain spaces"));
Ok(())
}
#[test]
fn checks_removes_node() -> Result<()> {
let j = RJini::empty()
.add_node("Ruby")?
.add_node("is")?
.add_node("not")?
.add_node("my")?
.add_node("dog")?
.remove_node("not");
assert_eq!("Ruby/is/my/dog/", j.xpath);
Ok(())
}
#[test]
fn checks_replaces_node() -> Result<()> {
let j = RJini::empty()
.add_node("Ruby")?
.add_node("is")?
.add_node("a")?
.add_node("bad")?
.add_node("dog")?
.replace_node("bad", "good")?
.xpath;
assert_eq!("Ruby/is/a/good/dog/", j);
Ok(())
}
#[test]
fn checks_error_on_replaces_node() -> Result<()> {
let actual = format!(
"{}",
RJini::empty()
.add_node("test")?
.replace_node("test", "not test")
.unwrap_err()
.root_cause()
);
assert!(actual.contains("The \"not test\" contain spaces"));
Ok(())
}
#[test]
fn checks_does_nodes() -> Result<()> {
let x = RJini::from("parent/child[@key=\"value\"]/next[3]");
assert_eq!(
vec!["parent", "child[@key=\"value\"]", "next[3]"],
x.nodes()?
);
Ok(())
}
#[test]
fn checks_adds_property() -> Result<()> {
let x = RJini::from("some/xpath/");
assert!(x.add_property("pr")?.xpath.contains("pr()"));
Ok(())
}
#[test]
fn checks_removes_property() -> Result<()> {
let x = RJini::from("some/xpath/");
assert!(x.add_property("pr")?.xpath.contains("pr()"));
let x = x.remove_property("pr").xpath;
assert!(!x.contains("pr"));
Ok(())
}