use core::assert_matches::assert_matches;
use core::str::FromStr;
use crate::error::NodeError;
use crate::node::function::Function;
use crate::node::simplified::{Simplifiable, SimplifiedNode};
use crate::node::structured::{EvaluationSettings, AngleUnit};
use crate::node::unstructured::{Navigable, Serializable, UnstructuredNodeRoot, Upgradable};
use crate::render::{Area, CalculatedPoint, Layoutable, Viewport, LayoutComputationProperties, Glyph};
use crate::{Number, UnstructuredNodeList};
use crate::nav::NavPath;
use crate::{StructuredNode, UnstructuredNode, Token, render::Renderer};
use crate::renderers::AsciiRenderer;
use alloc::vec;
use rust_decimal::Decimal;
use test::{Bencher, black_box};
macro_rules! uns_list {
($($x:expr),* $(,)?) => { UnstructuredNodeList { items: vec![ $($x),* ] } };
}
macro_rules! token {
(+) => { UnstructuredNode::Token(Token::Add) };
(-) => { UnstructuredNode::Token(Token::Subtract) };
(*) => { UnstructuredNode::Token(Token::Multiply) };
(/) => { UnstructuredNode::Token(Token::Divide) };
(.) => { UnstructuredNode::Token(Token::Point) };
(var $v:ident) => { UnstructuredNode::Token(Token::Variable(stringify!($v).chars().nth(0).unwrap())) };
($x:literal) => { UnstructuredNode::Token(Token::Digit($x)) };
}
macro_rules! tokens {
($($x:tt) *) => { UnstructuredNodeList { items: vec![ $(token!($x)),* ] } };
}
macro_rules! uns_frac {
($t:expr, $b:expr $(,)?) => { UnstructuredNode::Fraction($t, $b) };
}
macro_rules! render {
($n:expr, $p:expr, $v:expr $(,)?) => { {
let mut renderer = AsciiRenderer::default();
renderer.draw_all(&$n, $p, $v);
renderer.lines
} };
($n:expr, $p:expr $(,)?) => { render!($n, $p, None) };
($n:expr $(,)?) => { render!($n, None, None) };
}
macro_rules! rat {
($n:literal) => { Number::Rational($n, 1) };
($n:literal, $d:literal) => { Number::Rational($n, $d) };
}
macro_rules! dec {
($l:literal) => { Number::Decimal(Decimal::from_str(stringify!($l)).unwrap()) };
}
macro_rules! reserialize {
($e:expr) => {
UnstructuredNodeRoot::deserialize(
&mut $e.serialize().into_iter()
).unwrap()
};
}
macro_rules! reduce {
($n:expr) => {
{
let mut nodes = $n;
assert!(matches!(nodes.reduce(), Ok(_)));
nodes
}
};
}
macro_rules! simplify {
($t:expr) => {
{
let mut n = $t.upgrade().unwrap().simplify().flatten();
n.sort();
n
}
};
}
fn complex_unstructured_expression() -> UnstructuredNodeRoot {
UnstructuredNodeRoot { root: uns_list!(
token!(1),
token!(2),
token!(+),
uns_frac!(
uns_list!(
token!(3),
token!(4),
token!(+),
uns_frac!(
tokens!(5 6),
tokens!(7 8),
)
),
tokens!(9 0),
),
token!(+),
token!(1),
token!(2),
) }
}
#[test]
fn test_upgrade() {
let unstructured = tokens!(1 2 * 3 4 + 5 6 * 7 8);
assert_eq!(
unstructured.upgrade().unwrap(),
StructuredNode::Add(
box StructuredNode::Multiply(
box StructuredNode::Number(12.into()),
box StructuredNode::Number(34.into()),
),
box StructuredNode::Multiply(
box StructuredNode::Number(56.into()),
box StructuredNode::Number(78.into()),
),
)
);
}
#[test]
fn test_upgrade_negative_numbers() {
assert_eq!(
tokens!(- 1 2).upgrade().unwrap(),
StructuredNode::Number((-12).into())
);
assert_eq!(
tokens!(- - - - 1 2).upgrade().unwrap(),
StructuredNode::Number((12).into())
);
let mut renderer = AsciiRenderer::default();
renderer.draw_all(&tokens!(- 1 2).upgrade().unwrap(), None, None);
assert_eq!(
renderer.lines,
["-12"]
);
assert_eq!(
tokens!(1 - - 2).upgrade().unwrap().evaluate(&EvaluationSettings::default()).unwrap(),
rat!(3)
);
}
#[test]
fn test_decimals() {
assert_eq!(
tokens!(1 . 2).upgrade().unwrap(),
StructuredNode::Number(dec!(1.2))
);
assert_eq!(
tokens!(1 2 3 . 4 5).upgrade().unwrap(),
StructuredNode::Number(dec!(123.45))
);
assert_eq!(
tokens!(1 2 . 0 0 0 0 1 3).upgrade().unwrap(),
StructuredNode::Number(dec!(12.000013))
);
assert_eq!(
render!(tokens!(1 . 2)),
vec!["1.2"],
);
assert_eq!(
render!(tokens!(1 . 2).upgrade().unwrap()),
vec!["1.2"],
);
assert_eq!(
tokens!(0 . 3 - 0 . 1).upgrade().unwrap().evaluate(&EvaluationSettings::default()).unwrap(),
dec!(0.2)
);
assert!(matches!(
tokens!(1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5).upgrade(),
Err(NodeError::Overflow),
));
assert_eq!(
tokens!(3 . + 2 .).upgrade().unwrap().evaluate(&EvaluationSettings::default()).unwrap(),
dec!(5)
);
assert!(matches!(
tokens!(1 2 . 3 4 . 5 6).upgrade(),
Err(_)
))
}
#[test]
fn test_disambiguate() {
let tree = StructuredNode::Multiply(
box StructuredNode::Number(1.into()),
box StructuredNode::Multiply(
box StructuredNode::Number(2.into()),
box StructuredNode::Number(3.into()),
),
);
assert_eq!(
tree.disambiguate().unwrap(),
StructuredNode::Multiply(
box StructuredNode::Number(1.into()),
box StructuredNode::Parentheses(
box StructuredNode::Multiply(
box StructuredNode::Number(2.into()),
box StructuredNode::Number(3.into()),
),
),
)
);
let tree = StructuredNode::Multiply(
box StructuredNode::Add(
box StructuredNode::Number(1.into()),
box StructuredNode::Number(2.into()),
),
box StructuredNode::Add(
box StructuredNode::Number(3.into()),
box StructuredNode::Number(4.into()),
),
);
assert_eq!(
tree.disambiguate().unwrap(),
StructuredNode::Multiply(
box StructuredNode::Parentheses(
box StructuredNode::Add(
box StructuredNode::Number(1.into()),
box StructuredNode::Number(2.into()),
),
),
box StructuredNode::Parentheses(
box StructuredNode::Add(
box StructuredNode::Number(3.into()),
box StructuredNode::Number(4.into()),
),
),
)
);
}
#[test]
fn test_ascii_render() {
let tree = StructuredNode::Add(
box StructuredNode::Multiply(
box StructuredNode::Number(12.into()),
box StructuredNode::Number(34.into()),
),
box StructuredNode::Multiply(
box StructuredNode::Number(56.into()),
box StructuredNode::Number(78.into()),
),
).disambiguate().unwrap();
assert_eq!(
render!(tree),
vec!["12*34+56*78"],
);
let tree = StructuredNode::Add(
box StructuredNode::Add(
box StructuredNode::Number(12.into()),
box StructuredNode::Divide(
box StructuredNode::Add(
box StructuredNode::Number(34.into()),
box StructuredNode::Divide(
box StructuredNode::Number(56.into()),
box StructuredNode::Number(78.into()),
)
),
box StructuredNode::Number(90.into()),
),
),
box StructuredNode::Number(12.into()),
).disambiguate().unwrap();
assert_eq!(
render!(tree),
vec![
" 56 ",
" 34+-- ",
" 78 ",
"12+-----+12",
" 90 "
],
);
let tree = complex_unstructured_expression();
assert_eq!(
render!(tree),
vec![
" 56 ",
" 34+-- ",
" 78 ",
"12+-----+12",
" 90 "
],
);
let tree = complex_unstructured_expression();
assert_eq!(
render!(tree, Some(&mut NavPath::new(vec![3, 0, 3, 1, 1]).to_navigator())),
vec![
" 56 ",
" 34+--- ",
" 7|8 ",
"12+------+12",
" 90 "
],
);
let tree = complex_unstructured_expression();
assert_eq!(
render!(tree, Some(&mut NavPath::new(vec![3, 0, 3]).to_navigator())),
vec![
" |56 ",
" 34+|-- ",
" |78 ",
"12+------+12",
" 90 "
],
);
let tree = StructuredNode::Add(
box StructuredNode::Number(rat!(2, 3)),
box StructuredNode::Number(rat!(1)),
);
assert_eq!(
render!(tree),
vec![
"2 ",
"-+1",
"3 ",
]
)
}
#[test]
fn test_navigation() {
let mut unstructured = uns_list!(
token!(1),
token!(2),
token!(*),
token!(3),
token!(4),
token!(+),
uns_frac!(
tokens!(5 6),
tokens!(7 8),
)
);
let mut path = NavPath::new(vec![0]);
let result = {
let (node, i) = unstructured.navigate(&mut path.to_navigator());
let node_ptr: *mut UnstructuredNodeList = node;
(node_ptr, i)
};
assert_eq!(
result,
(&mut unstructured as *mut UnstructuredNodeList, 0)
);
let mut path = NavPath::new(vec![3]);
let result = {
let (node, i) = unstructured.navigate(&mut path.to_navigator());
let node_ptr: *mut UnstructuredNodeList = node;
(node_ptr, i)
};
assert_eq!(
result,
(&mut unstructured as *mut UnstructuredNodeList, 3)
);
let mut path = NavPath::new(vec![6, 1, 1]);
let result = {
let (node, i) = unstructured.navigate(&mut path.to_navigator());
(node.clone(), i)
};
assert_eq!(
result,
(tokens!(7 8), 1)
);
}
#[test]
fn test_movement() {
let mut node = complex_unstructured_expression();
let mut nav_path = NavPath::new(vec![0]);
let mut renderer = AsciiRenderer::default();
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![1]));
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3]));
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 0]));
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3]));
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3, 0, 0]));
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3, 0, 2]));
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 4]));
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![4]));
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![5]));
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![7]));
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![7]));
node.move_left(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![6]));
node.move_left(&mut nav_path, &mut renderer, None);
node.move_left(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![4]));
node.move_left(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 4]));
node.move_left(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3, 0, 2]));
node.move_left(&mut nav_path, &mut renderer, None);
node.move_left(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3, 0, 0]));
node.move_left(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3]));
node.move_left(&mut nav_path, &mut renderer, None);
node.move_left(&mut nav_path, &mut renderer, None);
node.move_left(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 0]));
node.move_left(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3]));
node.move_left(&mut nav_path, &mut renderer, None);
node.move_left(&mut nav_path, &mut renderer, None);
node.move_left(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![0]));
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 0]));
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3, 0, 0]));
node.move_up(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3, 0, 0]));
node.move_down(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3, 1, 0]));
node.move_up(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3, 0, 0]));
node.move_down(&mut nav_path, &mut renderer, None);
node.move_down(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 1, 2]));
node.move_up(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![3, 0, 3]));
}
#[test]
fn test_modification() {
let mut node = complex_unstructured_expression();
let mut nav_path = NavPath::new(vec![0]);
let mut renderer = AsciiRenderer::default();
node.insert(&mut nav_path, &mut renderer, None, UnstructuredNode::Token(Token::Digit(1)));
assert_eq!(nav_path, NavPath::new(vec![1]));
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![4, 0, 0]));
node.move_right(&mut nav_path, &mut renderer, None);
node.move_right(&mut nav_path, &mut renderer, None);
assert_eq!(nav_path, NavPath::new(vec![4, 0, 2]));
node.insert(&mut nav_path, &mut renderer, None, UnstructuredNode::Token(Token::Add));
node.insert(&mut nav_path, &mut renderer, None, UnstructuredNode::Fraction(
UnstructuredNodeList::new(),
UnstructuredNodeList::new(),
));
node.insert(&mut nav_path, &mut renderer, None, UnstructuredNode::Token(Token::Digit(9)));
assert_eq!(nav_path, NavPath::new(vec![4, 0, 3, 0, 1]));
assert_eq!(
render!(node, Some(&mut nav_path.to_navigator())),
vec![
" 9| 56 ",
" 34+--+-- ",
" X 78 ",
"112+--------+12",
" 90 "
],
);
node.delete(&mut nav_path, &mut renderer, None);
node.delete(&mut nav_path, &mut renderer, None);
node.delete(&mut nav_path, &mut renderer, None);
assert_eq!(
render!(node, Some(&mut nav_path.to_navigator())),
vec![
" 56 ",
" 34|+-- ",
" 78 ",
"112+------+12",
" 90 "
],
);
}
#[test]
fn test_viewport() {
assert_eq!(
render!(tokens!(1 2 3 4 5)),
vec!["12345"],
);
assert_eq!(
render!(tokens!(1 2 3 4 5), None, Some(&Viewport::new(Area::new(10, 3)))),
vec![
"12345 ",
" ",
" ",
],
);
assert_eq!(
render!(tokens!(1 2 3 4 5), None, Some(&Viewport::new(Area::new(5, 1)))),
vec!["12345"],
);
assert_eq!(
render!(tokens!(1 2 3 4 5), None, Some(&Viewport::new(Area::new(2, 1)))),
vec!["12"],
);
assert_eq!(
render!(tokens!(1 2 3 4 5), None, Some(&Viewport {
size: Area::new(2, 1),
offset: CalculatedPoint { x: 1, y: 0 },
})),
vec!["23"],
);
assert_eq!(
render!(
uns_list!(
UnstructuredNode::Fraction(
tokens!(1 + 2 + 3 + 4),
tokens!(5 + 6 + 7 + 8),
)
),
None,
Some(&Viewport {
size: Area::new(3, 3),
offset: CalculatedPoint { x: 2, y: 0 }
})
),
vec![
"2+3",
"---",
"6+7",
]
);
}
#[test]
fn test_parentheses() {
let nodes = uns_list!(
token!(1),
token!(+),
UnstructuredNode::Parentheses(uns_list!(
UnstructuredNode::Fraction(
uns_list!(UnstructuredNode::Fraction(
uns_list!(token!(2)), uns_list!(token!(3)))
),
uns_list!(UnstructuredNode::Parentheses(uns_list!(token!(4)))),
)
))
);
assert_eq!(
render!(nodes, None, None),
vec![
" / 2 \\",
" | - |",
" | 3 |",
"1+|---|",
" \\(4)/"
]
)
}
#[test]
fn test_variables() {
let nodes = uns_list!(
token!(var x),
token!(+),
UnstructuredNode::Fraction(
uns_list!(
token!(1),
token!(+),
token!(var x),
),
uns_list!(
token!(var y),
)
)
);
assert_eq!(
nodes.upgrade()
.unwrap()
.substitute_variable('x', &StructuredNode::Number(dec!(9)))
.substitute_variable('y', &StructuredNode::Number(dec!(2)))
.evaluate(&EvaluationSettings::default())
.unwrap(),
dec!(14)
)
}
#[test]
fn test_implicit_multiply() {
assert_eq!(
uns_list!(
token!(2),
token!(var x),
).upgrade().unwrap(),
StructuredNode::Multiply(
box StructuredNode::Number(rat!(2)),
box StructuredNode::Variable('x'),
)
);
assert_eq!(
uns_list!(
token!(0),
token!(.),
token!(5),
token!(var x),
).upgrade().unwrap(),
StructuredNode::Multiply(
box StructuredNode::Number(dec!(0.5)),
box StructuredNode::Variable('x'),
)
);
assert_eq!(
uns_list!(
token!(2),
UnstructuredNode::Parentheses(uns_list!(
token!(1),
token!(+),
token!(var x),
)),
).upgrade().unwrap(),
StructuredNode::Multiply(
box StructuredNode::Number(rat!(2)),
box StructuredNode::Parentheses(
box StructuredNode::Add(
box StructuredNode::Number(rat!(1)),
box StructuredNode::Variable('x'),
)
)
)
);
assert_eq!(
uns_list!(
token!(var x),
token!(var y),
token!(var z),
token!(+),
token!(2),
).upgrade().unwrap(),
StructuredNode::Add(
box StructuredNode::Multiply(
box StructuredNode::Variable('x'),
box StructuredNode::Multiply(
box StructuredNode::Variable('y'),
box StructuredNode::Variable('z'),
),
),
box StructuredNode::Number(rat!(2)),
)
);
}
#[test]
fn test_power() {
let tree = StructuredNode::Power(
box StructuredNode::Number(dec!(12)),
box StructuredNode::Number(dec!(3)),
).disambiguate().unwrap();
assert_eq!(
render!(tree),
vec![
" 3",
"12 ",
],
);
let tree = StructuredNode::Add(
box StructuredNode::Add(
box StructuredNode::Add(
box StructuredNode::Power(
box StructuredNode::Number(dec!(12)),
box StructuredNode::Number(dec!(3)),
),
box StructuredNode::Power(
box StructuredNode::Number(dec!(45)),
box StructuredNode::Divide(
box StructuredNode::Number(dec!(67)),
box StructuredNode::Number(dec!(8)),
),
),
),
box StructuredNode::Number(dec!(9)),
),
box StructuredNode::Number(1.into()),
).disambiguate().unwrap();
assert_eq!(
render!(tree),
vec![
" 67 ",
" -- ",
" 3 8 ",
"12 +45 +9+1",
],
);
assert_eq!(
uns_list!(
token!(2),
UnstructuredNode::Power(tokens!(3))
).upgrade().unwrap().evaluate(&EvaluationSettings::default()).unwrap(),
rat!(8),
);
let tree = UnstructuredNodeRoot { root: uns_list!(
token!(1),
token!(2),
UnstructuredNode::Power(tokens!(3 4))
) };
assert_eq!(
render!(tree),
vec![
" 34",
"12 ",
],
);
let tree = UnstructuredNodeRoot { root: uns_list!(
UnstructuredNode::Fraction(tokens!(1 2), tokens!(3 4)),
token!(+),
token!(5),
UnstructuredNode::Power(tokens!(6 7))
) };
assert_eq!(
render!(tree),
vec![
"12 67",
"--+5 ",
"34 ",
],
);
let tree = UnstructuredNodeRoot { root: uns_list!(
UnstructuredNode::Parentheses(uns_list!(
UnstructuredNode::Fraction(tokens!(1 2), tokens!(3 4)),
token!(+),
token!(5),
)),
UnstructuredNode::Power(tokens!(6 7))
) };
assert_eq!(
render!(tree),
vec![
" 67",
"/12 \\ ",
"|--+5| ",
"\\34 / ",
],
);
let tree = UnstructuredNodeRoot { root: uns_list!(
token!(1),
token!(+),
token!(2),
UnstructuredNode::Power(tokens!(2)),
UnstructuredNode::Power(tokens!(3)),
UnstructuredNode::Power(tokens!(4)),
token!(+),
token!(1),
) };
assert_eq!(
render!(tree),
vec![
" 4 ",
" 3 ",
" 2 ",
"1+2 +1",
],
);
assert_eq!(
tree.upgrade().unwrap().evaluate(&EvaluationSettings::default()).unwrap(),
rat!(16777218)
);
let tree = UnstructuredNodeRoot { root: uns_list!(
token!(4),
UnstructuredNode::Power(uns_list!(UnstructuredNode::Fraction(tokens!(1), tokens!(2)))),
) };
assert_eq!(
render!(tree),
vec![
" 1",
" -",
" 2",
"4 ",
],
);
assert_eq!(
tree.upgrade().unwrap().evaluate(&EvaluationSettings::default()).unwrap(),
rat!(2)
);
let tree = UnstructuredNodeRoot { root: uns_list!(
token!(8),
UnstructuredNode::Power(uns_list!(
token!(-),
UnstructuredNode::Fraction(tokens!(2), tokens!(3))
)),
) };
assert_eq!(
render!(tree),
vec![
" 2",
" --",
" 3",
"8 ",
],
);
assert_eq!(
tree.upgrade().unwrap().evaluate(&EvaluationSettings::default()).unwrap(),
rat!(1, 4)
);
let tree = UnstructuredNodeRoot { root: uns_list!(
token!(7),
UnstructuredNode::Power(uns_list!(
UnstructuredNode::Fraction(tokens!(1), tokens!(2))
)),
) };
assert_eq!(
render!(tree),
vec![
" 1",
" -",
" 2",
"7 ",
],
);
assert!(matches!(
tree.upgrade().unwrap().evaluate(&EvaluationSettings::default()).unwrap(),
Number::Decimal(_),
));
}
#[test]
fn test_serialize() {
assert_eq!(
reserialize!(complex_unstructured_expression()),
complex_unstructured_expression(),
);
let e = UnstructuredNodeRoot { root: uns_list!(
token!(var x),
token!(+),
token!(2),
token!(+),
token!(var y),
) };
assert_eq!(
reserialize!(e),
e
);
}
#[test]
fn test_simplify_structured() {
assert_eq!(
simplify!(tokens!(1 2 + 5 6 + 3 4)),
SimplifiedNode::Add(vec![
SimplifiedNode::Number(rat!(12)),
SimplifiedNode::Number(rat!(34)),
SimplifiedNode::Number(rat!(56)),
])
);
assert_eq!(
simplify!(tokens!(1 2 + 5 6 * 2 + 3 4)),
SimplifiedNode::Add(vec![
SimplifiedNode::Number(rat!(12)),
SimplifiedNode::Number(rat!(34)),
SimplifiedNode::Multiply(vec![
SimplifiedNode::Number(rat!(2)),
SimplifiedNode::Number(rat!(56)),
]),
])
);
assert_eq!(
simplify!(uns_list!(
token!(1),
token!(+),
UnstructuredNode::Parentheses(uns_list!(
token!(2),
token!(+),
UnstructuredNode::Parentheses(uns_list!(
token!(3),
token!(*),
UnstructuredNode::Parentheses(uns_list!(
token!(4),
token!(*),
token!(5),
)),
token!(*),
token!(6),
)),
token!(+),
UnstructuredNode::Parentheses(uns_list!(
token!(7),
token!(+),
token!(8),
)),
)),
token!(*),
token!(9),
)),
SimplifiedNode::Add(vec![
SimplifiedNode::Number(rat!(1)),
SimplifiedNode::Multiply(vec![
SimplifiedNode::Number(rat!(9)),
SimplifiedNode::Add(vec![
SimplifiedNode::Number(rat!(2)),
SimplifiedNode::Number(rat!(7)),
SimplifiedNode::Number(rat!(8)),
SimplifiedNode::Multiply(vec![
SimplifiedNode::Number(rat!(3)),
SimplifiedNode::Number(rat!(4)),
SimplifiedNode::Number(rat!(5)),
SimplifiedNode::Number(rat!(6)),
]),
]),
]),
])
);
assert_eq!(
simplify!(tokens!(1 - 5)),
SimplifiedNode::Add(vec![
SimplifiedNode::Number(rat!(1)),
SimplifiedNode::Multiply(vec![
SimplifiedNode::Number(rat!(-1)),
SimplifiedNode::Number(rat!(5)),
])
])
);
}
#[test]
fn test_reduction() {
assert_eq!(
reduce!(simplify!(tokens!(1 2 + 5 6 + 3 4))),
SimplifiedNode::Number(rat!(102))
);
assert_eq!(
reduce!(simplify!(tokens!(1 2 + 5 6 * 2 + 3 4))),
SimplifiedNode::Number(rat!(158))
);
assert_eq!(
reduce!(simplify!(uns_list!(
token!(1),
token!(+),
UnstructuredNode::Parentheses(uns_list!(
token!(2),
token!(+),
UnstructuredNode::Parentheses(uns_list!(
token!(3),
token!(*),
UnstructuredNode::Parentheses(uns_list!(
token!(4),
token!(*),
token!(5),
)),
token!(*),
token!(6),
)),
token!(+),
UnstructuredNode::Parentheses(uns_list!(
token!(7),
token!(+),
token!(8),
)),
)),
token!(*),
token!(9),
))),
SimplifiedNode::Number(rat!(3394))
);
assert_eq!(
reduce!(simplify!(tokens!(8 / 2))),
SimplifiedNode::Number(rat!(4))
);
assert_eq!(
reduce!(simplify!(tokens!(3 / 5 + 2 / 3 + 7 / 4))),
SimplifiedNode::Number(rat!(181, 60))
);
assert_eq!(
reduce!(simplify!(uns_list!(
UnstructuredNode::Fraction(
tokens!(2),
tokens!(3),
)
))),
SimplifiedNode::Number(rat!(2, 3))
);
assert_eq!(
reduce!(simplify!(uns_list!(
token!(5),
UnstructuredNode::Power(uns_list!(
UnstructuredNode::Fraction(
tokens!(2),
tokens!(3),
)
))
))),
SimplifiedNode::Power(
box SimplifiedNode::Number(rat!(25)),
box SimplifiedNode::Number(rat!(1, 3)),
)
);
assert_eq!(
reduce!(simplify!(uns_list!(
token!(var x),
token!(*),
token!(var x),
UnstructuredNode::Power(tokens!(3)),
token!(*),
token!(var y),
UnstructuredNode::Power(tokens!(10)),
token!(*),
token!(var x),
token!(*),
token!(var y),
))),
SimplifiedNode::Multiply(vec![
SimplifiedNode::Power(
box SimplifiedNode::Variable('x'),
box SimplifiedNode::Number(rat!(5)),
),
SimplifiedNode::Power(
box SimplifiedNode::Variable('y'),
box SimplifiedNode::Number(rat!(11)),
),
])
);
assert_eq!(
reduce!(simplify!(uns_list!(
UnstructuredNode::Parentheses(uns_list!(
token!(var x),
token!(var x),
token!(var y),
)),
UnstructuredNode::Power(tokens!(3)),
))),
SimplifiedNode::Multiply(vec![
SimplifiedNode::Power(
box SimplifiedNode::Variable('x'),
box SimplifiedNode::Number(rat!(6)),
),
SimplifiedNode::Power(
box SimplifiedNode::Variable('y'),
box SimplifiedNode::Number(rat!(3)),
),
])
);
assert_eq!(
reduce!(simplify!(uns_list!(
token!(3),
token!(var x),
UnstructuredNode::Power(tokens!(2)),
))),
SimplifiedNode::Multiply(vec![
SimplifiedNode::Number(rat!(3)),
SimplifiedNode::Power(
box SimplifiedNode::Variable('x'),
box SimplifiedNode::Number(rat!(2)),
),
]),
);
assert_eq!(
reduce!(simplify!(uns_list!(
token!(2),
token!(var x),
token!(+),
token!(3),
token!(var x),
UnstructuredNode::Power(tokens!(2)),
token!(+),
token!(6),
token!(var x),
UnstructuredNode::Power(tokens!(2)),
token!(+),
token!(var x),
token!(+),
token!(7),
))),
SimplifiedNode::Add(vec![
SimplifiedNode::Number(rat!(7)),
SimplifiedNode::Multiply(vec![
SimplifiedNode::Number(rat!(3)),
SimplifiedNode::Variable('x'),
]),
SimplifiedNode::Multiply(vec![
SimplifiedNode::Number(rat!(9)),
SimplifiedNode::Power(
box SimplifiedNode::Variable('x'),
box SimplifiedNode::Number(rat!(2)),
),
]),
])
);
}
#[bench]
fn bench_unstructured_layout(b: &mut Bencher) {
let tree = complex_unstructured_expression();
let mut ascii_renderer = AsciiRenderer::default();
b.iter(|| {
black_box(tree.layout(&mut ascii_renderer, None, LayoutComputationProperties::default()));
});
}
#[test]
fn test_divide_by_zero() {
let result = StructuredNode::Divide(
box StructuredNode::Number(rat!(12)),
box StructuredNode::Number(rat!(0)),
).disambiguate().unwrap().evaluate(&EvaluationSettings::default());
assert_matches!(result, Err(_));
let result = StructuredNode::Add(
box StructuredNode::Divide(
box StructuredNode::Number(dec!(12)),
box StructuredNode::Number(dec!(0)),
),
box StructuredNode::Number(dec!(0.1)),
).disambiguate().unwrap().evaluate(&EvaluationSettings::default());
assert_matches!(result, Err(_));
}
#[test]
fn test_size_reduction_level() {
let block = UnstructuredNodeRoot { root: uns_list!(
token!(1),
token!(+),
token!(2),
UnstructuredNode::Power(tokens!(3)),
) }.upgrade().unwrap().layout(&mut AsciiRenderer::default(), None, LayoutComputationProperties::default());
for (glyph, _) in block.glyphs {
if let Glyph::Digit { number: 3 } = glyph.glyph {
assert_eq!(glyph.size_reduction_level, 1);
} else {
assert_eq!(glyph.size_reduction_level, 0);
}
}
}
#[test]
fn test_function_evaluation() {
assert_eq!(
Function::Sine.evaluate(&[dec!(90)], &EvaluationSettings { angle_unit: AngleUnit::Degree }),
Ok(dec!(1)),
);
assert_eq!(
Function::Sine.evaluate(&[Number::Decimal(Decimal::PI / Decimal::TWO)], &EvaluationSettings { angle_unit: AngleUnit::Radian }),
Ok(dec!(1)),
);
assert_eq!(
Function::Cosine.evaluate(&[dec!(180)], &EvaluationSettings { angle_unit: AngleUnit::Degree }),
Ok(dec!(-1)),
);
assert_eq!(
Function::Cosine.evaluate(&[Number::Decimal(Decimal::PI)], &EvaluationSettings { angle_unit: AngleUnit::Radian }),
Ok(dec!(-1)),
);
}