use oxirs_arq::algebra::{BinaryOperator, Expression, Literal, UnaryOperator, Variable};
use oxirs_arq::expression::ExpressionEvaluator;
use oxirs_arq::extensions::ExtensionRegistry;
use oxirs_arq::term::{xsd, Term};
use oxirs_core::model::NamedNode;
use std::sync::Arc;
#[test]
fn test_arithmetic_expressions() {
let registry = ExtensionRegistry::new();
let mut evaluator = ExpressionEvaluator::new(Arc::new(registry));
evaluator
.binding_context_mut()
.bind("x", Term::typed_literal("10", xsd::INTEGER).unwrap());
evaluator
.binding_context_mut()
.bind("y", Term::typed_literal("5", xsd::INTEGER).unwrap());
let add_expr = Expression::Binary {
op: BinaryOperator::Add,
left: Box::new(Expression::Variable(Variable::new("x").unwrap())),
right: Box::new(Expression::Variable(Variable::new("y").unwrap())),
};
let result = evaluator.evaluate(&add_expr).unwrap();
assert_eq!(result, Term::typed_literal("15", xsd::INTEGER).unwrap());
let sub_expr = Expression::Binary {
op: BinaryOperator::Subtract,
left: Box::new(Expression::Variable(Variable::new("x").unwrap())),
right: Box::new(Expression::Variable(Variable::new("y").unwrap())),
};
let result = evaluator.evaluate(&sub_expr).unwrap();
assert_eq!(result, Term::typed_literal("5", xsd::INTEGER).unwrap());
let mul_expr = Expression::Binary {
op: BinaryOperator::Multiply,
left: Box::new(Expression::Variable(Variable::new("x").unwrap())),
right: Box::new(Expression::Literal(Literal {
value: "2".to_string(),
language: None,
datatype: Some(NamedNode::new(xsd::INTEGER).unwrap()),
})),
};
let result = evaluator.evaluate(&mul_expr).unwrap();
assert_eq!(result, Term::typed_literal("20", xsd::INTEGER).unwrap());
}
#[test]
fn test_comparison_expressions() {
let registry = ExtensionRegistry::new();
let mut evaluator = ExpressionEvaluator::new(Arc::new(registry));
evaluator
.binding_context_mut()
.bind("a", Term::typed_literal("10", xsd::INTEGER).unwrap());
evaluator
.binding_context_mut()
.bind("b", Term::typed_literal("20", xsd::INTEGER).unwrap());
let lt_expr = Expression::Binary {
op: BinaryOperator::Less,
left: Box::new(Expression::Variable(Variable::new("a").unwrap())),
right: Box::new(Expression::Variable(Variable::new("b").unwrap())),
};
let result = evaluator.evaluate(<_expr).unwrap();
assert_eq!(result, Term::typed_literal("true", xsd::BOOLEAN).unwrap());
let gt_expr = Expression::Binary {
op: BinaryOperator::Greater,
left: Box::new(Expression::Variable(Variable::new("a").unwrap())),
right: Box::new(Expression::Variable(Variable::new("b").unwrap())),
};
let result = evaluator.evaluate(>_expr).unwrap();
assert_eq!(result, Term::typed_literal("false", xsd::BOOLEAN).unwrap());
let eq_expr = Expression::Binary {
op: BinaryOperator::Equal,
left: Box::new(Expression::Variable(Variable::new("a").unwrap())),
right: Box::new(Expression::Literal(Literal {
value: "10".to_string(),
language: None,
datatype: Some(NamedNode::new(xsd::INTEGER).unwrap()),
})),
};
let result = evaluator.evaluate(&eq_expr).unwrap();
assert_eq!(result, Term::typed_literal("true", xsd::BOOLEAN).unwrap());
}
#[test]
fn test_logical_expressions() {
let registry = ExtensionRegistry::new();
let mut evaluator = ExpressionEvaluator::new(Arc::new(registry));
evaluator
.binding_context_mut()
.bind("p", Term::typed_literal("true", xsd::BOOLEAN).unwrap());
evaluator
.binding_context_mut()
.bind("q", Term::typed_literal("false", xsd::BOOLEAN).unwrap());
let and_expr = Expression::Binary {
op: BinaryOperator::And,
left: Box::new(Expression::Variable(Variable::new("p").unwrap())),
right: Box::new(Expression::Variable(Variable::new("q").unwrap())),
};
let result = evaluator.evaluate(&and_expr).unwrap();
assert_eq!(result, Term::typed_literal("false", xsd::BOOLEAN).unwrap());
let or_expr = Expression::Binary {
op: BinaryOperator::Or,
left: Box::new(Expression::Variable(Variable::new("p").unwrap())),
right: Box::new(Expression::Variable(Variable::new("q").unwrap())),
};
let result = evaluator.evaluate(&or_expr).unwrap();
assert_eq!(result, Term::typed_literal("true", xsd::BOOLEAN).unwrap());
let not_expr = Expression::Unary {
op: UnaryOperator::Not,
operand: Box::new(Expression::Variable(Variable::new("q").unwrap())),
};
let result = evaluator.evaluate(¬_expr).unwrap();
assert_eq!(result, Term::typed_literal("true", xsd::BOOLEAN).unwrap());
}
#[test]
fn test_string_functions() {
let registry = ExtensionRegistry::new();
let mut evaluator = ExpressionEvaluator::new(Arc::new(registry));
evaluator
.binding_context_mut()
.bind("name", Term::literal("hello world"));
evaluator
.binding_context_mut()
.bind("url", Term::iri("http://example.org"));
let str_expr = Expression::Function {
name: "str".to_string(),
args: vec![Expression::Variable(Variable::new("url").unwrap())],
};
let result = evaluator.evaluate(&str_expr).unwrap();
assert_eq!(result, Term::literal("http://example.org"));
let strlen_expr = Expression::Function {
name: "strlen".to_string(),
args: vec![Expression::Variable(Variable::new("name").unwrap())],
};
let result = evaluator.evaluate(&strlen_expr).unwrap();
assert_eq!(result, Term::typed_literal("11", xsd::INTEGER).unwrap());
let ucase_expr = Expression::Function {
name: "ucase".to_string(),
args: vec![Expression::Variable(Variable::new("name").unwrap())],
};
let result = evaluator.evaluate(&ucase_expr).unwrap();
assert_eq!(result, Term::literal("HELLO WORLD"));
let substr_expr = Expression::Function {
name: "substr".to_string(),
args: vec![
Expression::Variable(Variable::new("name").unwrap()),
Expression::Literal(Literal {
value: "1".to_string(),
language: None,
datatype: Some(NamedNode::new(xsd::INTEGER).unwrap()),
}),
Expression::Literal(Literal {
value: "5".to_string(),
language: None,
datatype: Some(NamedNode::new(xsd::INTEGER).unwrap()),
}),
],
};
let result = evaluator.evaluate(&substr_expr).unwrap();
assert_eq!(result, Term::literal("hello"));
}
#[test]
fn test_type_checking_functions() {
let registry = ExtensionRegistry::new();
let mut evaluator = ExpressionEvaluator::new(Arc::new(registry));
evaluator
.binding_context_mut()
.bind("iri", Term::iri("http://example.org"));
evaluator
.binding_context_mut()
.bind("lit", Term::literal("test"));
evaluator
.binding_context_mut()
.bind("blank", Term::blank_node("b1"));
evaluator
.binding_context_mut()
.bind("num", Term::typed_literal("42", xsd::INTEGER).unwrap());
let is_iri_expr = Expression::Unary {
op: UnaryOperator::IsIri,
operand: Box::new(Expression::Variable(Variable::new("iri").unwrap())),
};
let result = evaluator.evaluate(&is_iri_expr).unwrap();
assert_eq!(result, Term::typed_literal("true", xsd::BOOLEAN).unwrap());
let is_literal_expr = Expression::Unary {
op: UnaryOperator::IsLiteral,
operand: Box::new(Expression::Variable(Variable::new("lit").unwrap())),
};
let result = evaluator.evaluate(&is_literal_expr).unwrap();
assert_eq!(result, Term::typed_literal("true", xsd::BOOLEAN).unwrap());
let is_blank_expr = Expression::Unary {
op: UnaryOperator::IsBlank,
operand: Box::new(Expression::Variable(Variable::new("blank").unwrap())),
};
let result = evaluator.evaluate(&is_blank_expr).unwrap();
assert_eq!(result, Term::typed_literal("true", xsd::BOOLEAN).unwrap());
let is_numeric_expr = Expression::Unary {
op: UnaryOperator::IsNumeric,
operand: Box::new(Expression::Variable(Variable::new("num").unwrap())),
};
let result = evaluator.evaluate(&is_numeric_expr).unwrap();
assert_eq!(result, Term::typed_literal("true", xsd::BOOLEAN).unwrap());
}
#[test]
fn test_conditional_expression() {
let registry = ExtensionRegistry::new();
let mut evaluator = ExpressionEvaluator::new(Arc::new(registry));
evaluator
.binding_context_mut()
.bind("x", Term::typed_literal("10", xsd::INTEGER).unwrap());
let if_expr = Expression::Conditional {
condition: Box::new(Expression::Binary {
op: BinaryOperator::Greater,
left: Box::new(Expression::Variable(Variable::new("x").unwrap())),
right: Box::new(Expression::Literal(Literal {
value: "5".to_string(),
language: None,
datatype: Some(NamedNode::new(xsd::INTEGER).unwrap()),
})),
}),
then_expr: Box::new(Expression::Literal(Literal {
value: "big".to_string(),
language: None,
datatype: None,
})),
else_expr: Box::new(Expression::Literal(Literal {
value: "small".to_string(),
language: None,
datatype: None,
})),
};
let result = evaluator.evaluate(&if_expr).unwrap();
assert_eq!(result, Term::literal("big"));
}
#[test]
fn test_bound_expression() {
let registry = ExtensionRegistry::new();
let mut evaluator = ExpressionEvaluator::new(Arc::new(registry));
evaluator
.binding_context_mut()
.bind("x", Term::literal("value"));
let bound_expr = Expression::Bound(Variable::new("x").unwrap());
let result = evaluator.evaluate(&bound_expr).unwrap();
assert_eq!(result, Term::typed_literal("true", xsd::BOOLEAN).unwrap());
let unbound_expr = Expression::Bound(Variable::new("y").unwrap());
let result = evaluator.evaluate(&unbound_expr).unwrap();
assert_eq!(result, Term::typed_literal("false", xsd::BOOLEAN).unwrap());
}
#[test]
fn test_constructor_functions() {
let registry = ExtensionRegistry::new();
let mut evaluator = ExpressionEvaluator::new(Arc::new(registry));
evaluator
.binding_context_mut()
.bind("str", Term::literal("http://example.org/resource"));
evaluator
.binding_context_mut()
.bind("lang", Term::literal("en"));
let iri_expr = Expression::Function {
name: "iri".to_string(),
args: vec![Expression::Variable(Variable::new("str").unwrap())],
};
let result = evaluator.evaluate(&iri_expr).unwrap();
assert!(result.is_iri());
let strlang_expr = Expression::Function {
name: "strlang".to_string(),
args: vec![
Expression::Literal(Literal {
value: "hello".to_string(),
language: None,
datatype: None,
}),
Expression::Variable(Variable::new("lang").unwrap()),
],
};
let result = evaluator.evaluate(&strlang_expr).unwrap();
match result {
Term::Literal(lit) => {
assert_eq!(lit.lexical_form, "hello");
assert_eq!(lit.language_tag, Some("en".to_string()));
}
_ => panic!("Expected language-tagged literal"),
}
}