use core::fmt;
use crate::condition::Condition;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Not {
pub(crate) condition: Box<Condition>,
}
impl Not {
}
impl<T> From<T> for Not
where
T: Into<Box<Condition>>,
{
fn from(condition: T) -> Self {
Self {
condition: condition.into(),
}
}
}
impl fmt::Display for Not {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("NOT ")?;
self.condition.fmt(f)
}
}
#[cfg(test)]
mod test {
use std::io::{self, Write};
use pretty_assertions::assert_str_eq;
use crate::condition::{test::cmp_a_gt_b, Condition};
use super::Not;
#[test]
fn display() {
assert_str_eq!("NOT a > b", (!cmp_a_gt_b()).to_string());
}
#[test]
fn not_expression() {
let expr = cmp_a_gt_b();
for i in 0..3 {
let mut wrapped = !expr.clone();
for _ in 0..i {
wrapped = !wrapped;
}
print!("{i}: {wrapped}");
io::stdout().lock().flush().unwrap();
assert_str_eq!(
match i {
0 => format!("NOT {expr}"),
1 => format!("NOT NOT {expr}"),
2 => format!("NOT NOT NOT {expr}"),
_ => unreachable!(),
},
wrapped.to_string(),
);
}
}
#[test]
fn not_parens() {
let expr = cmp_a_gt_b();
for i in 0..3 {
let mut wrapped = Not::from(expr.clone());
for _ in 0..i {
wrapped = Not::from(Condition::Not(wrapped).parenthesize().parenthesize());
}
print!("{i}: {wrapped}");
io::stdout().lock().flush().unwrap();
let (expected_wrapped, expected_normalized) = match i {
0 => {
let expr = format!("NOT {expr}");
(expr.clone(), expr)
}
1 => (format!("NOT ((NOT {expr}))"), expr.to_string()),
2 => (
format!("NOT ((NOT ((NOT {expr}))))"),
format!("(NOT {expr})"),
),
_ => unreachable!(),
};
assert_str_eq!(expected_wrapped, wrapped.to_string());
_ = expected_normalized;
}
}
#[test]
fn normalize_variants() {
let wrapped = cmp_a_gt_b()
.parenthesize()
.parenthesize()
.parenthesize()
.not()
.parenthesize()
.parenthesize()
.parenthesize();
println!("{wrapped}");
assert_str_eq!("(((NOT (((a > b))))))", wrapped.to_string());
let wrapped = cmp_a_gt_b()
.parenthesize()
.parenthesize()
.parenthesize()
.not()
.not();
println!("{wrapped}");
assert_str_eq!("NOT NOT (((a > b)))", wrapped.to_string());
let wrapped = cmp_a_gt_b()
.parenthesize()
.parenthesize()
.parenthesize()
.not()
.parenthesize()
.not();
println!("{wrapped}");
assert_str_eq!("NOT (NOT (((a > b))))", wrapped.to_string());
let wrapped = !!!(cmp_a_gt_b().parenthesize().parenthesize().parenthesize());
println!("{wrapped}");
assert_str_eq!("NOT NOT NOT (((a > b)))", wrapped.to_string());
}
}
#[cfg(test)]
mod examples {
#[test]
fn not() -> Result<(), Box<dyn std::error::Error>> {
use crate::Path;
use pretty_assertions::assert_eq;
let a = "a".parse::<Path>()?;
let b = "b".parse::<Path>()?;
let condition = a.greater_than(b).not();
assert_eq!("NOT a > b", condition.to_string());
Ok(())
}
}