use super::test_schema;
use crate::engine::simplify::Simplify;
use toasty_core::stmt::{self, Expr, ExprMatch, MatchArm, Projection, Value, VisitMut};
#[test]
fn constant_subject_matches_arm() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = ExprMatch {
subject: Box::new(Expr::from(1i64)),
arms: vec![
MatchArm {
pattern: Value::from(0i64),
expr: Expr::from("a"),
},
MatchArm {
pattern: Value::from(1i64),
expr: Expr::from("b"),
},
],
else_expr: Box::new(Expr::null()),
};
let result = simplify.simplify_expr_match(&mut expr);
assert!(matches!(result, Some(Expr::Value(Value::String(ref s))) if s == "b"));
}
#[test]
fn constant_subject_no_matching_arm_folds_to_else() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = ExprMatch {
subject: Box::new(Expr::from(99i64)),
arms: vec![
MatchArm {
pattern: Value::from(0i64),
expr: Expr::from("a"),
},
MatchArm {
pattern: Value::from(1i64),
expr: Expr::from("b"),
},
],
else_expr: Box::new(Expr::null()),
};
let result = simplify.simplify_expr_match(&mut expr);
assert!(matches!(result, Some(Expr::Value(Value::Null))));
}
#[test]
fn non_constant_subject_not_simplified() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = ExprMatch {
subject: Box::new(Expr::arg(0)),
arms: vec![
MatchArm {
pattern: Value::from(0i64),
expr: Expr::from("a"),
},
MatchArm {
pattern: Value::from(1i64),
expr: Expr::from("b"),
},
],
else_expr: Box::new(Expr::null()),
};
let result = simplify.simplify_expr_match(&mut expr);
assert!(result.is_none());
}
#[test]
fn uniform_arms_and_else_folds_to_single_expr() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = ExprMatch {
subject: Box::new(Expr::arg(0)),
arms: vec![
MatchArm {
pattern: Value::from(0i64),
expr: Expr::arg(1),
},
MatchArm {
pattern: Value::from(1i64),
expr: Expr::arg(1),
},
],
else_expr: Box::new(Expr::arg(1)),
};
let result = simplify.simplify_expr_match(&mut expr);
assert_eq!(result, Some(Expr::arg(1)));
}
#[test]
fn uniform_arms_but_different_else_not_simplified() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = ExprMatch {
subject: Box::new(Expr::arg(0)),
arms: vec![
MatchArm {
pattern: Value::from(0i64),
expr: Expr::arg(1),
},
MatchArm {
pattern: Value::from(1i64),
expr: Expr::arg(1),
},
],
else_expr: Box::new(Expr::null()),
};
let result = simplify.simplify_expr_match(&mut expr);
assert!(result.is_none());
}
#[test]
fn non_uniform_arms_not_simplified() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = ExprMatch {
subject: Box::new(Expr::arg(0)),
arms: vec![
MatchArm {
pattern: Value::from(0i64),
expr: Expr::arg(1),
},
MatchArm {
pattern: Value::from(1i64),
expr: Expr::arg(2),
},
],
else_expr: Box::new(Expr::null()),
};
let result = simplify.simplify_expr_match(&mut expr);
assert!(result.is_none());
}
#[test]
fn false_arm_expr_not_dropped() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = ExprMatch {
subject: Box::new(Expr::arg(0)),
arms: vec![
MatchArm {
pattern: Value::from(0i64),
expr: Expr::FALSE,
},
MatchArm {
pattern: Value::from(1i64),
expr: Expr::from("b"),
},
],
else_expr: Box::new(Expr::null()),
};
let result = simplify.simplify_expr_match(&mut expr);
assert!(result.is_none());
assert_eq!(expr.arms.len(), 2, "false-valued arm must not be dropped");
}
#[test]
fn constant_subject_folds_to_arm_value() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = Expr::Match(ExprMatch {
subject: Box::new(Expr::from(2i64)),
arms: vec![
MatchArm {
pattern: Value::from(1i64),
expr: Expr::from("a"),
},
MatchArm {
pattern: Value::from(2i64),
expr: Expr::from("b"),
},
MatchArm {
pattern: Value::from(3i64),
expr: Expr::from("c"),
},
],
else_expr: Box::new(Expr::null()),
});
simplify.visit_expr_mut(&mut expr);
assert!(matches!(&expr, Expr::Value(Value::String(s)) if s == "b"));
}
#[test]
fn subject_simplified_before_folding() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let subject = stmt::ExprProject {
base: Box::new(Expr::record([Expr::from(1i64)])),
projection: Projection::from(0),
};
let mut expr = Expr::Match(ExprMatch {
subject: Box::new(Expr::Project(subject)),
arms: vec![
MatchArm {
pattern: Value::from(1i64),
expr: Expr::from("matched"),
},
MatchArm {
pattern: Value::from(2i64),
expr: Expr::from("other"),
},
],
else_expr: Box::new(Expr::null()),
});
simplify.visit_expr_mut(&mut expr);
assert!(matches!(&expr, Expr::Value(Value::String(s)) if s == "matched"));
}
#[test]
fn dead_arms_not_visited_with_constant_subject() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let dead_arm_expr = stmt::ExprProject {
base: Box::new(Expr::record([Expr::from(1i64)])),
projection: Projection::from(1), };
let mut expr = Expr::Match(ExprMatch {
subject: Box::new(Expr::from(1i64)),
arms: vec![
MatchArm {
pattern: Value::from(1i64),
expr: Expr::from("ok"),
},
MatchArm {
pattern: Value::from(2i64),
expr: Expr::Project(dead_arm_expr),
},
],
else_expr: Box::new(Expr::null()),
});
simplify.visit_expr_mut(&mut expr);
assert!(matches!(&expr, Expr::Value(Value::String(s)) if s == "ok"));
}
#[test]
fn non_constant_subject_simplifies_all_arms() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = Expr::Match(ExprMatch {
subject: Box::new(Expr::arg(0)),
arms: vec![
MatchArm {
pattern: Value::from(1i64),
expr: Expr::record([Expr::from("hello")]),
},
MatchArm {
pattern: Value::from(2i64),
expr: Expr::record([Expr::from("world")]),
},
],
else_expr: Box::new(Expr::null()),
});
simplify.visit_expr_mut(&mut expr);
let Expr::Match(m) = &expr else {
panic!("expected Expr::Match")
};
assert!(matches!(&m.arms[0].expr, Expr::Value(Value::Record(_))));
assert!(matches!(&m.arms[1].expr, Expr::Value(Value::Record(_))));
}
#[test]
fn constant_subject_no_match_folds_to_error_else() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = Expr::Match(ExprMatch {
subject: Box::new(Expr::from(99i64)),
arms: vec![MatchArm {
pattern: Value::from(1i64),
expr: Expr::from("a"),
}],
else_expr: Box::new(Expr::error("unexpected")),
});
simplify.visit_expr_mut(&mut expr);
assert!(matches!(&expr, Expr::Error(e) if e.message == "unexpected"));
}
#[test]
fn constant_subject_matching_arm_is_error() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = Expr::Match(ExprMatch {
subject: Box::new(Expr::from(1i64)),
arms: vec![
MatchArm {
pattern: Value::from(1i64),
expr: Expr::error("bad"),
},
MatchArm {
pattern: Value::from(2i64),
expr: Expr::from("ok"),
},
],
else_expr: Box::new(Expr::from("default")),
});
simplify.visit_expr_mut(&mut expr);
assert!(matches!(&expr, Expr::Error(e) if e.message == "bad"));
}
#[test]
fn constant_subject_match_found_error_else_not_reached() {
let schema = test_schema();
let mut simplify = Simplify::new(&schema);
let mut expr = Expr::Match(ExprMatch {
subject: Box::new(Expr::from(1i64)),
arms: vec![MatchArm {
pattern: Value::from(1i64),
expr: Expr::from("ok"),
}],
else_expr: Box::new(Expr::error("unexpected")),
});
simplify.visit_expr_mut(&mut expr);
assert!(matches!(&expr, Expr::Value(Value::String(s)) if s == "ok"));
}