//! Unit tests for infix operator parsing within expressions.

use crate::{Datum, Expr, InfixOp};

#[test]
fn add_op_parses() {
    assert_eq!(
        // https://xkcd.com/3184/
        Expr::try_from("six + 7"),
        Ok(Expr::Infix {
            lhs: Box::new(Expr::ObjName(vec!["six".to_owned()])),
            op: InfixOp::Add,
            rhs: Box::new(Expr::Literal(Datum::Numeric(Some(7.into())))),
        })
    );
}

#[test]
fn mult_op_parses() {
    assert_eq!(
        Expr::try_from("six * 7"),
        Ok(Expr::Infix {
            lhs: Box::new(Expr::ObjName(vec!["six".to_owned()])),
            op: InfixOp::Mult,
            rhs: Box::new(Expr::Literal(Datum::Numeric(Some(7.into())))),
        })
    );
}

#[test]
fn arith_precedence() {
    assert_eq!(
        Expr::try_from("(1 + 2) * 3 + 4"),
        Ok(Expr::Infix {
            lhs: Box::new(Expr::Infix {
                lhs: Box::new(Expr::Infix {
                    lhs: Box::new(Expr::Literal(Datum::Numeric(Some(1.into())))),
                    op: InfixOp::Add,
                    rhs: Box::new(Expr::Literal(Datum::Numeric(Some(2.into())))),
                }),
                op: InfixOp::Mult,
                rhs: Box::new(Expr::Literal(Datum::Numeric(Some(3.into())))),
            }),
            op: InfixOp::Add,
            rhs: Box::new(Expr::Literal(Datum::Numeric(Some(4.into())))),
        })
    );
    assert_eq!(
        Expr::try_from("1 - 2 / (3 - 4)"),
        Ok(Expr::Infix {
            lhs: Box::new(Expr::Literal(Datum::Numeric(Some(1.into())))),
            op: InfixOp::Sub,
            rhs: Box::new(Expr::Infix {
                lhs: Box::new(Expr::Literal(Datum::Numeric(Some(2.into())))),
                op: InfixOp::Div,
                rhs: Box::new(Expr::Infix {
                    lhs: Box::new(Expr::Literal(Datum::Numeric(Some(3.into())))),
                    op: InfixOp::Sub,
                    rhs: Box::new(Expr::Literal(Datum::Numeric(Some(4.into())))),
                }),
            })
        })
    );
}

#[test]
fn is_null_parses() {
    assert_eq!(
        Expr::try_from("my_var is null"),
        Ok(Expr::Nullness {
            is_null: true,
            expr: Box::new(Expr::ObjName(vec!["my_var".to_owned()]))
        }),
    );
}

#[test]
fn is_not_null_parses() {
    assert_eq!(
        Expr::try_from("my_var is not null"),
        Ok(Expr::Nullness {
            is_null: false,
            expr: Box::new(Expr::ObjName(vec!["my_var".to_owned()]))
        }),
    );
}

#[test]
fn not_parses() {
    assert_eq!(
        Expr::try_from("not my_var"),
        Ok(Expr::Not(Box::new(Expr::ObjName(vec![
            "my_var".to_owned()
        ])))),
    );
}

#[test]
fn repeated_nots_parse() {
    assert_eq!(
        Expr::try_from("not not my_var"),
        Ok(Expr::Not(Box::new(Expr::Not(Box::new(Expr::ObjName(
            vec!["my_var".to_owned()]
        )))))),
    );
}
