use crate::eval::environment::Environment;
use crate::reverse_eval::domain::Constraint;
use crate::reverse_eval::reverse::reverse_eval;
use crate::value::Value;
use hamelin_lib::tree::builder::*;
use hamelin_lib::tree::options::ExpressionTypeCheckOptions;
use hamelin_lib::tree::typed_ast::environment::TypeEnvironment;
use hamelin_lib::type_check_expression;
use hamelin_lib::types::{DOUBLE, INT};
use pretty_assertions::assert_eq;
use rstest::rstest;
use std::sync::Arc;
#[rstest]
#[case::addition_equals(
add(field_ref("x"), 5),
Constraint::Equals(Value::Int(15)),
Constraint::Equals(Value::Int(10))
)]
#[case::addition_range(
add(field_ref("x"), 10),
Constraint::Range { min: Some(Value::Int(20)), max: Some(Value::Int(30)) },
Constraint::Range { min: Some(Value::Int(10)), max: Some(Value::Int(20)) }
)]
#[case::subtraction_equals(
subtract(field_ref("x"), 3),
Constraint::Equals(Value::Int(7)),
Constraint::Equals(Value::Int(10))
)]
#[case::addition_double(
add(field_ref("z"), 2.5),
Constraint::Equals(Value::Double(10.0)),
Constraint::Equals(Value::Double(7.5))
)]
#[case::parenthesized(
add(field_ref("x"), 10),
Constraint::Equals(Value::Int(25)),
Constraint::Equals(Value::Int(15))
)]
fn test_reverse_eval_arithmetic(
#[case] expr_builder: impl ExpressionBuilder,
#[case] output_constraint: Constraint,
#[case] expected_constraint: Constraint,
) {
let env = Environment::new();
let mut trans_env = TypeEnvironment::default();
trans_env.bind_str("x", INT);
trans_env.bind_str("y", INT);
trans_env.bind_str("z", DOUBLE);
let bindings = Arc::new(trans_env);
let expr = type_check_expression(
expr_builder.build(),
ExpressionTypeCheckOptions::builder()
.bindings(bindings)
.build(),
)
.output;
let result = reverse_eval(&expr, output_constraint, &env).expect("Reverse eval failed");
assert_eq!(result, Some(expected_constraint));
}