use std::cell::Cell;
use symplex::prelude::*;
#[test]
fn expr_view_is_atom_identifies_leaves() {
let ctx = Context::new();
let x = ctx.symbol("x");
let expr = x.sin();
let one = ctx.int(1);
let result = expr.replace(|view| {
if view.is_atom() {
Some(one.clone())
} else {
None
}
});
assert_eq!(format!("{result}"), "sin(1)");
}
#[test]
fn expr_view_is_symbol_only_matches_symbols() {
let ctx = Context::new();
let x = ctx.symbol("x");
let expr = &x + 1;
let forty_two = ctx.int(42);
let result = expr.replace(|view| {
if view.is_symbol() {
Some(forty_two.clone())
} else {
None
}
});
assert_eq!(format!("{result}"), "43");
}
#[test]
fn expr_view_is_symbol_false_for_pi() {
let ctx = Context::new();
let pi = ctx.pi();
let expr = &pi + 1;
let ninety_nine = ctx.int(99);
let result = expr.replace(|view| {
if view.is_symbol() {
Some(ninety_nine.clone()) } else {
None
}
});
assert_eq!(format!("{result}"), "1 + pi");
}
#[test]
fn expr_view_partial_eq_with_expr() {
let ctx = Context::new();
let x = ctx.symbol("x");
let y = ctx.symbol("y");
let expr = &x + &y;
let ten = ctx.int(10);
let result = expr.replace(|view| if view == x { Some(ten.clone()) } else { None });
assert_eq!(format!("{result}"), "y + 10");
}
#[test]
fn expr_view_partial_eq_ref_variant() {
let ctx = Context::new();
let x = ctx.symbol("x");
let expr = x.sin();
let pi = ctx.pi();
let result = expr.replace(|view| if view == x { Some(pi.clone()) } else { None });
let s = format!("{result}");
assert!(s.contains("pi"), "should have replaced x with pi: {s}");
}
#[test]
fn expr_view_children_count() {
let ctx = Context::new();
let x = ctx.symbol("x");
let y = ctx.symbol("y");
let expr = &x + &y;
let add_child_count = Cell::new(0usize);
let _ = expr.replace(|view| {
let children = view.children();
if children.len() == 2 {
add_child_count.set(children.len());
}
None });
assert_eq!(add_child_count.get(), 2, "Add(x, y) should have 2 children");
}
#[test]
fn expr_view_replace_identity() {
let ctx = Context::new();
let x = ctx.symbol("x");
let expr = x.powi(2).sin() + &x;
let original = format!("{expr}");
let result = expr.replace(|_| None);
assert_eq!(format!("{result}"), original);
}
#[test]
fn expr_view_is_atom_nested() {
let ctx = Context::new();
let x = ctx.symbol("x");
let expr = (&x.powi(2) + 1).sin();
let atom_count = Cell::new(0usize);
let _ = expr.replace(|view| {
if view.is_atom() {
atom_count.set(atom_count.get() + 1);
}
None
});
assert!(
atom_count.get() >= 2,
"should find at least 2 atoms, found {}",
atom_count.get()
);
}
#[test]
fn expr_view_node_variant() {
let ctx = Context::new();
use symplex::__macro_support::ExprNode;
let x = ctx.symbol("x");
let expr = x.sin();
let found_sin = Cell::new(false);
let _ = expr.replace(|view| {
if matches!(view.node(), ExprNode::Sin(_)) {
found_sin.set(true);
}
None
});
assert!(found_sin.get(), "should find Sin node in sin(x)");
}
#[test]
fn expr_view_multiple_replacements() {
let ctx = Context::new();
let x = ctx.symbol("x");
let y = ctx.symbol("y");
let expr = &x.sin() + &y.cos();
let zero = ctx.int(0);
let result = expr.replace(|view| {
if view.is_symbol() {
Some(zero.clone())
} else {
None
}
});
let s = format!("{result}");
assert!(
!s.contains('x') && !s.contains('y'),
"symbols should be replaced: {s}"
);
}
#[test]
fn expr_view_id_matches_expr_id() {
let ctx = Context::new();
let x = ctx.symbol("x");
let expr = x.sin();
let found_matching_id = Cell::new(false);
let x_id = x.id();
let _ = expr.replace(|view| {
if view.id() == x_id {
found_matching_id.set(true);
}
None
});
assert!(
found_matching_id.get(),
"should find a node whose id matches x.id()"
);
}
#[test]
fn expr_view_children_empty_for_atom() {
let ctx = Context::new();
let x = ctx.symbol("x");
let atom_has_no_children = Cell::new(false);
let _ = x.sin().replace(|view| {
if view.is_atom() {
let children = view.children();
if children.is_empty() {
atom_has_no_children.set(true);
}
}
None
});
assert!(
atom_has_no_children.get(),
"atom nodes should have no children"
);
}
#[test]
fn expr_view_node_symbol_variant() {
let ctx = Context::new();
use symplex::__macro_support::ExprNode;
let x = ctx.symbol("x");
let expr = x.sin();
let found_symbol = Cell::new(false);
let _ = expr.replace(|view| {
if matches!(view.node(), ExprNode::Symbol(_)) {
found_symbol.set(true);
}
None
});
assert!(found_symbol.get(), "should find Symbol node for x");
}
#[test]
fn expr_view_is_atom_for_number() {
let ctx = Context::new();
let x = ctx.symbol("x");
let expr = &x + 1;
let num_is_atom = Cell::new(false);
let _ = expr.replace(|view| {
if view.is_atom() && !view.is_symbol() {
num_is_atom.set(true);
}
None
});
assert!(
num_is_atom.get(),
"numeric literal should be an atom but not a symbol"
);
}
#[test]
fn expr_view_is_atom_for_pi() {
let ctx = Context::new();
use symplex::__macro_support::ExprNode;
let pi = ctx.pi();
let expr = pi.sin();
let pi_is_atom = Cell::new(false);
let _ = expr.replace(|view| {
if matches!(view.node(), ExprNode::Pi) && view.is_atom() {
pi_is_atom.set(true);
}
None
});
assert!(pi_is_atom.get(), "pi should be an atom");
}
#[test]
fn expr_view_replace_identity_complex() {
let ctx = Context::new();
let x = ctx.symbol("x");
let expr = &x.powi(2) + &x.sin() + 1;
let original = format!("{expr}");
let result = expr.replace(|_| None);
assert_eq!(format!("{result}"), original);
}