use super::*;
use crate::types::DataType;
fn col(name: &str, dt: DataType, nullable: bool, pos: u16) -> ColumnDef {
ColumnDef {
name: name.into(),
data_type: dt,
nullable,
position: pos,
default_expr: None,
default_sql: None,
check_expr: None,
check_sql: None,
check_name: None,
is_with_timezone: false,
generated_expr: None,
generated_sql: None,
generated_kind: None,
}
}
fn test_columns() -> Vec<ColumnDef> {
vec![
col("id", DataType::Integer, false, 0),
col("name", DataType::Text, true, 1),
col("score", DataType::Real, true, 2),
col("active", DataType::Boolean, false, 3),
]
}
fn test_row() -> Vec<Value> {
vec![
Value::Integer(1),
Value::Text("Alice".into()),
Value::Real(95.5),
Value::Boolean(true),
]
}
#[test]
fn eval_literal() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = test_row();
let expr = Expr::Literal(Value::Integer(42));
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Integer(42)
);
}
#[test]
fn eval_column_ref() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = test_row();
let expr = Expr::Column("name".into());
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Text("Alice".into())
);
}
#[test]
fn eval_column_case_insensitive() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = test_row();
let expr = Expr::Column("name".into());
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Text("Alice".into())
);
}
#[test]
fn eval_arithmetic_int() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = test_row();
let expr = Expr::BinaryOp {
left: Box::new(Expr::Column("id".into())),
op: BinOp::Add,
right: Box::new(Expr::Literal(Value::Integer(10))),
};
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Integer(11)
);
}
#[test]
fn eval_comparison() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = test_row();
let expr = Expr::BinaryOp {
left: Box::new(Expr::Column("score".into())),
op: BinOp::Gt,
right: Box::new(Expr::Literal(Value::Real(90.0))),
};
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Boolean(true)
);
}
#[test]
fn eval_null_propagation() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = vec![
Value::Integer(1),
Value::Null,
Value::Null,
Value::Boolean(true),
];
let expr = Expr::BinaryOp {
left: Box::new(Expr::Column("name".into())),
op: BinOp::Eq,
right: Box::new(Expr::Literal(Value::Text("test".into()))),
};
assert!(eval_expr(&expr, &EvalCtx::new(&cm, &row))
.unwrap()
.is_null());
}
#[test]
fn eval_and_three_valued() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = vec![
Value::Integer(1),
Value::Null,
Value::Null,
Value::Boolean(true),
];
let expr = Expr::BinaryOp {
left: Box::new(Expr::Column("name".into())),
op: BinOp::And,
right: Box::new(Expr::Literal(Value::Boolean(false))),
};
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Boolean(false)
);
let expr = Expr::BinaryOp {
left: Box::new(Expr::Column("name".into())),
op: BinOp::And,
right: Box::new(Expr::Literal(Value::Boolean(true))),
};
assert!(eval_expr(&expr, &EvalCtx::new(&cm, &row))
.unwrap()
.is_null());
}
#[test]
fn eval_or_three_valued() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = vec![
Value::Integer(1),
Value::Null,
Value::Null,
Value::Boolean(true),
];
let expr = Expr::BinaryOp {
left: Box::new(Expr::Column("name".into())),
op: BinOp::Or,
right: Box::new(Expr::Literal(Value::Boolean(true))),
};
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Boolean(true)
);
let expr = Expr::BinaryOp {
left: Box::new(Expr::Column("name".into())),
op: BinOp::Or,
right: Box::new(Expr::Literal(Value::Boolean(false))),
};
assert!(eval_expr(&expr, &EvalCtx::new(&cm, &row))
.unwrap()
.is_null());
}
#[test]
fn eval_is_null() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = vec![
Value::Integer(1),
Value::Null,
Value::Null,
Value::Boolean(true),
];
let expr = Expr::IsNull(Box::new(Expr::Column("name".into())));
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Boolean(true)
);
let expr = Expr::IsNotNull(Box::new(Expr::Column("id".into())));
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Boolean(true)
);
}
#[test]
fn eval_not() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = test_row();
let expr = Expr::UnaryOp {
op: UnaryOp::Not,
expr: Box::new(Expr::Column("active".into())),
};
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Boolean(false)
);
}
#[test]
fn eval_neg() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = test_row();
let expr = Expr::UnaryOp {
op: UnaryOp::Neg,
expr: Box::new(Expr::Column("id".into())),
};
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Integer(-1)
);
}
#[test]
fn eval_division_by_zero() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = test_row();
let expr = Expr::BinaryOp {
left: Box::new(Expr::Column("id".into())),
op: BinOp::Div,
right: Box::new(Expr::Literal(Value::Integer(0))),
};
assert!(matches!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)),
Err(SqlError::DivisionByZero)
));
}
#[test]
fn eval_mixed_numeric() {
let cols = test_columns();
let cm = ColumnMap::new(&cols);
let row = test_row();
let expr = Expr::BinaryOp {
left: Box::new(Expr::Column("id".into())),
op: BinOp::Add,
right: Box::new(Expr::Column("score".into())),
};
assert_eq!(
eval_expr(&expr, &EvalCtx::new(&cm, &row)).unwrap(),
Value::Real(96.5)
);
}
#[test]
fn is_truthy_values() {
assert!(is_truthy(&Value::Boolean(true)));
assert!(!is_truthy(&Value::Boolean(false)));
assert!(!is_truthy(&Value::Null));
assert!(is_truthy(&Value::Integer(1)));
assert!(!is_truthy(&Value::Integer(0)));
}