use super::test_schema;
use crate::engine::simplify::Simplify;
use proptest::prelude::*;
use toasty_core::stmt::{
BinaryOp, Expr, ExprAny, ExprBinaryOp, ExprInList, ExprList, Value, VisitMut,
};
fn arb_i64_value() -> impl Strategy<Value = Expr> {
(-100i64..=100).prop_map(|n| Expr::Value(Value::I64(n)))
}
fn arb_i64_raw() -> impl Strategy<Value = i64> {
-100i64..=100
}
fn arb_binary_op() -> impl Strategy<Value = BinaryOp> {
prop_oneof![
Just(BinaryOp::Eq),
Just(BinaryOp::Ne),
Just(BinaryOp::Lt),
Just(BinaryOp::Le),
Just(BinaryOp::Gt),
Just(BinaryOp::Ge),
]
}
fn arb_bool_expr() -> impl Strategy<Value = Expr> {
let leaf = prop_oneof![
Just(Expr::from(true)),
Just(Expr::from(false)),
(arb_i64_value(), arb_binary_op(), arb_i64_value()).prop_map(|(lhs, op, rhs)| {
Expr::BinaryOp(ExprBinaryOp {
lhs: Box::new(lhs),
op,
rhs: Box::new(rhs),
})
}),
arb_i64_value().prop_map(Expr::is_null),
Just(Expr::is_null(Expr::null())),
(arb_i64_value(), prop::collection::vec(arb_i64_raw(), 0..=3)).prop_map(
|(expr, values)| {
let list = Expr::Value(Value::List(values.into_iter().map(Value::I64).collect()));
Expr::InList(ExprInList {
expr: Box::new(expr),
list: Box::new(list),
})
}
),
];
leaf.prop_recursive(
4, 64, 4, |inner| {
prop_oneof![
inner.clone().prop_map(Expr::not),
prop::collection::vec(inner.clone(), 2..=4).prop_map(Expr::and_from_vec),
prop::collection::vec(inner.clone(), 2..=4).prop_map(Expr::or_from_vec),
prop::collection::vec(inner.clone(), 1..=4).prop_map(|items| {
Expr::Any(ExprAny {
expr: Box::new(Expr::List(ExprList { items })),
})
}),
(inner.clone(), any::<bool>(), any::<bool>()).prop_map(|(expr, b, use_eq)| {
let op = if use_eq { BinaryOp::Eq } else { BinaryOp::Ne };
Expr::binary_op(expr, op, Expr::from(b))
}),
]
},
)
}
proptest! {
#[test]
fn simplify_preserves_eval(expr in arb_bool_expr()) {
let schema = test_schema();
let oracle = expr.eval_const().expect("generated expr must be evaluable");
let mut expr = expr;
Simplify::new(&schema, &toasty_core::driver::Capability::SQLITE).visit_expr_mut(&mut expr);
let result = expr.eval_const().expect("simplified expr must be evaluable");
prop_assert_eq!(oracle, result);
}
}