use bigdecimal::BigDecimal; use odata_params::filters::{ CompareOperator, Expr, FunctionsTypeMap, IdentifiersTypeMap, Type, ValidationError, Value, }; use std::collections::HashMap; use std::str::FromStr; #[test] fn test_literal_values() { let type_map = IdentifiersTypeMap::from(HashMap::new()); let functions_map = FunctionsTypeMap::from(HashMap::new()); assert_eq!( Expr::Value(Value::Bool(true)).validate(&type_map, &functions_map), Ok(Type::Boolean) ); assert_eq!( Expr::Value(Value::Number(BigDecimal::from_str("42").unwrap())) .validate(&type_map, &functions_map), Ok(Type::Number) ); assert_eq!( Expr::Value(Value::String("hello".to_string())).validate(&type_map, &functions_map), Ok(Type::String) ); } #[test] fn test_identifiers() { let mut id_map = HashMap::new(); id_map.insert("abc".to_string(), Type::Number); let type_map = IdentifiersTypeMap::from(id_map); let functions_map = FunctionsTypeMap::from(HashMap::new()); assert_eq!( Expr::Identifier("abc".to_string()).validate(&type_map, &functions_map), Ok(Type::Number) ); assert_eq!( Expr::Identifier("unknown".to_string()).validate(&type_map, &functions_map), Err(ValidationError::UndefinedIdentifier { name: "unknown".to_string() }) ); } #[test] fn test_comparisons() { let mut id_map = HashMap::new(); id_map.insert("abc".to_string(), Type::Number); let type_map = IdentifiersTypeMap::from(id_map); let functions_map = FunctionsTypeMap::from(HashMap::new()); let expr = Expr::Compare( Box::new(Expr::Identifier("abc".to_string())), CompareOperator::Equal, Box::new(Expr::Value(Value::Number( BigDecimal::from_str("42").unwrap(), ))), ); assert_eq!(expr.validate(&type_map, &functions_map), Ok(Type::Boolean)); let expr = Expr::Compare( Box::new(Expr::Identifier("abc".to_string())), CompareOperator::Equal, Box::new(Expr::Value(Value::String("42".to_string()))), ); assert_eq!( expr.validate(&type_map, &functions_map), Err(ValidationError::ComparingIncompatibleTypes { lhs: Type::Number, rhs: Type::String, }) ); } #[test] fn test_logical_operations() { let mut id_map = HashMap::new(); id_map.insert("flag".to_string(), Type::Boolean); let type_map = IdentifiersTypeMap::from(id_map); let functions_map = FunctionsTypeMap::from(HashMap::new()); let expr = Expr::And( Box::new(Expr::Identifier("flag".to_string())), Box::new(Expr::Value(Value::Bool(true))), ); assert_eq!(expr.validate(&type_map, &functions_map), Ok(Type::Boolean)); let expr = Expr::Or( Box::new(Expr::Identifier("flag".to_string())), Box::new(Expr::Value(Value::Bool(false))), ); assert_eq!(expr.validate(&type_map, &functions_map), Ok(Type::Boolean)); let expr = Expr::Not(Box::new(Expr::Identifier("flag".to_string()))); assert_eq!(expr.validate(&type_map, &functions_map), Ok(Type::Boolean)); } #[test] fn test_in_operator() { let mut id_map = HashMap::new(); id_map.insert("id".to_string(), Type::Number); let type_map = IdentifiersTypeMap::from(id_map); let functions_map = FunctionsTypeMap::from(HashMap::new()); let expr = Expr::In( Box::new(Expr::Identifier("id".to_string())), vec![ Expr::Value(Value::Number(BigDecimal::from_str("1").unwrap())), Expr::Value(Value::Number(BigDecimal::from_str("2").unwrap())), ], ); assert_eq!(expr.validate(&type_map, &functions_map), Ok(Type::Boolean)); let expr = Expr::In( Box::new(Expr::Identifier("id".to_string())), vec![ Expr::Value(Value::Number(BigDecimal::from_str("1").unwrap())), Expr::Value(Value::String("2".to_string())), ], ); assert_eq!( expr.validate(&type_map, &functions_map), Err(ValidationError::ComparingIncompatibleTypes { lhs: Type::Number, rhs: Type::String, }) ); } #[test] fn test_function_call() { let mut id_map = HashMap::new(); id_map.insert("arg1".to_string(), Type::Number); id_map.insert("arg2".to_string(), Type::String); let type_map = IdentifiersTypeMap::from(id_map); let mut func_map = HashMap::new(); func_map.insert( "test_func".to_string(), (vec![Type::Number, Type::Number], None, Type::Boolean), ); func_map.insert( "variadic_func".to_string(), (vec![Type::String], Some(Type::String), Type::Boolean), ); let functions_map = FunctionsTypeMap::from(func_map); let expr = Expr::Function( "test_func".to_string(), vec![ Expr::Identifier("arg1".to_string()), Expr::Value(Value::Number(BigDecimal::from_str("42").unwrap())), ], ); assert_eq!(expr.validate(&type_map, &functions_map), Ok(Type::Boolean)); let expr = Expr::Function( "test_func".to_string(), vec![ Expr::Identifier("arg1".to_string()), Expr::Value(Value::String("42".to_string())), ], ); assert_eq!( expr.validate(&type_map, &functions_map), Err(ValidationError::IncorrectFunctionArgumentType { name: "test_func".to_string(), position: 2, expected: Type::Number, given: Type::String, }) ); let expr = Expr::Function( "variadic_func".to_string(), vec![ Expr::Identifier("arg2".to_string()), Expr::Value(Value::String("foo".to_string())), Expr::Value(Value::String("bar".to_string())), ], ); assert_eq!(expr.validate(&type_map, &functions_map), Ok(Type::Boolean)); }