使用 simpleeval 库替换原有的简单正则匹配,支持复杂的条件表达式评估。新增 ConditionEvaluator 类处理条件逻辑,支持比较运算、逻辑运算、成员测试、数学计算和内置函数,同时保持向后兼容性。
300 lines
10 KiB
Python
300 lines
10 KiB
Python
"""
|
|
条件评估器单元测试
|
|
|
|
测试 ConditionEvaluator 类的所有功能
|
|
"""
|
|
|
|
import pytest
|
|
from loaders.yaml_loader import YAMLError
|
|
from core.condition_evaluator import ConditionEvaluator
|
|
|
|
|
|
class TestConditionEvaluator:
|
|
"""ConditionEvaluator 测试类"""
|
|
|
|
def setup_method(self):
|
|
"""每个测试方法前执行"""
|
|
self.evaluator = ConditionEvaluator()
|
|
|
|
# ============= 比较运算符测试 =============
|
|
|
|
def test_greater_than(self):
|
|
"""测试大于运算符"""
|
|
assert self.evaluator.evaluate_condition("{count > 0}", {"count": 5}) is True
|
|
assert self.evaluator.evaluate_condition("{count > 0}", {"count": 0}) is False
|
|
|
|
def test_less_than(self):
|
|
"""测试小于运算符"""
|
|
assert self.evaluator.evaluate_condition("{count < 10}", {"count": 5}) is True
|
|
assert self.evaluator.evaluate_condition("{count < 10}", {"count": 10}) is False
|
|
|
|
def test_greater_equal(self):
|
|
"""测试大于等于运算符"""
|
|
assert self.evaluator.evaluate_condition("{count >= 5}", {"count": 5}) is True
|
|
assert self.evaluator.evaluate_condition("{count >= 5}", {"count": 4}) is False
|
|
|
|
def test_less_equal(self):
|
|
"""测试小于等于运算符"""
|
|
assert self.evaluator.evaluate_condition("{count <= 5}", {"count": 5}) is True
|
|
assert self.evaluator.evaluate_condition("{count <= 5}", {"count": 6}) is False
|
|
|
|
def test_equal(self):
|
|
"""测试相等运算符"""
|
|
assert self.evaluator.evaluate_condition("{status == 'active'}", {"status": "active"}) is True
|
|
assert self.evaluator.evaluate_condition("{status == 'active'}", {"status": "inactive"}) is False
|
|
|
|
def test_not_equal(self):
|
|
"""测试不等运算符"""
|
|
assert self.evaluator.evaluate_condition("{status != 'inactive'}", {"status": "active"}) is True
|
|
assert self.evaluator.evaluate_condition("{status != 'active'}", {"status": "active"}) is False
|
|
|
|
# ============= 逻辑运算符测试 =============
|
|
|
|
def test_logical_and(self):
|
|
"""测试逻辑与运算"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{count > 0 and status == 'active'}",
|
|
{"count": 5, "status": "active"}
|
|
) is True
|
|
assert self.evaluator.evaluate_condition(
|
|
"{count > 0 and status == 'active'}",
|
|
{"count": 0, "status": "active"}
|
|
) is False
|
|
|
|
def test_logical_or(self):
|
|
"""测试逻辑或运算"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{count > 0 or status == 'active'}",
|
|
{"count": 0, "status": "active"}
|
|
) is True
|
|
assert self.evaluator.evaluate_condition(
|
|
"{count > 0 or status == 'active'}",
|
|
{"count": 0, "status": "inactive"}
|
|
) is False
|
|
|
|
def test_logical_not(self):
|
|
"""测试逻辑非运算"""
|
|
assert self.evaluator.evaluate_condition("{not (count == 0)}", {"count": 5}) is True
|
|
assert self.evaluator.evaluate_condition("{not (count == 0)}", {"count": 0}) is False
|
|
|
|
# ============= 成员测试 =============
|
|
|
|
def test_in_list(self):
|
|
"""测试列表成员测试"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{status in ['draft', 'review', 'published']}",
|
|
{"status": "draft"}
|
|
) is True
|
|
assert self.evaluator.evaluate_condition(
|
|
"{status in ['draft', 'review']}",
|
|
{"status": "active"}
|
|
) is False
|
|
|
|
def test_not_in_list(self):
|
|
"""测试列表非成员测试"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{status not in ['draft', 'review']}",
|
|
{"status": "active"}
|
|
) is True
|
|
assert self.evaluator.evaluate_condition(
|
|
"{status not in ['draft', 'review']}",
|
|
{"status": "draft"}
|
|
) is False
|
|
|
|
def test_in_tuple(self):
|
|
"""测试元组成员测试"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{level in (1, 2, 3)}",
|
|
{"level": 2}
|
|
) is True
|
|
assert self.evaluator.evaluate_condition(
|
|
"{level in (1, 2, 3)}",
|
|
{"level": 4}
|
|
) is False
|
|
|
|
def test_string_contains(self):
|
|
"""测试字符串包含"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{'test' in status}",
|
|
{"status": "test-version"}
|
|
) is True
|
|
assert self.evaluator.evaluate_condition(
|
|
"{'test' in status}",
|
|
{"status": "production"}
|
|
) is False
|
|
|
|
# ============= 数学运算测试 =============
|
|
|
|
def test_addition(self):
|
|
"""测试加法运算"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{(price + tax) > 100}",
|
|
{"price": 90, "tax": 15}
|
|
) is True
|
|
|
|
def test_multiplication(self):
|
|
"""测试乘法运算"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{(price * discount) > 50}",
|
|
{"price": 100, "discount": 0.8}
|
|
) is True
|
|
|
|
def test_division(self):
|
|
"""测试除法运算"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{(total / count) >= 10}",
|
|
{"total": 100, "count": 5}
|
|
) is True
|
|
|
|
def test_modulo(self):
|
|
"""测试取模运算"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{(value % 2) == 0}",
|
|
{"value": 10}
|
|
) is True
|
|
|
|
def test_power(self):
|
|
"""测试幂运算"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{(base ** exp) > 100}",
|
|
{"base": 10, "exp": 2}
|
|
) is False
|
|
|
|
# ============= 内置函数测试 =============
|
|
|
|
def test_int_function(self):
|
|
"""测试 int() 函数"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{int(value) > 100}",
|
|
{"value": "150"}
|
|
) is True
|
|
|
|
def test_float_function(self):
|
|
"""测试 float() 函数"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{float(value) > 3.14}",
|
|
{"value": "3.5"}
|
|
) is True
|
|
|
|
def test_str_function(self):
|
|
"""测试 str() 函数"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{str(value) == '123'}",
|
|
{"value": 123}
|
|
) is True
|
|
|
|
def test_len_function(self):
|
|
"""测试 len() 函数"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{len(items) > 0}",
|
|
{"items": [1, 2, 3]}
|
|
) is True
|
|
|
|
def test_bool_function(self):
|
|
"""测试 bool() 函数"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{bool(value)}",
|
|
{"value": "text"}
|
|
) is True
|
|
assert self.evaluator.evaluate_condition(
|
|
"{bool(value)}",
|
|
{"value": ""}
|
|
) is False
|
|
|
|
def test_abs_function(self):
|
|
"""测试 abs() 函数"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{abs(value) > 10}",
|
|
{"value": -15}
|
|
) is True
|
|
|
|
def test_min_function(self):
|
|
"""测试 min() 函数"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{min(a, b) == 5}",
|
|
{"a": 5, "b": 10}
|
|
) is True
|
|
|
|
def test_max_function(self):
|
|
"""测试 max() 函数"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{max(a, b) == 10}",
|
|
{"a": 5, "b": 10}
|
|
) is True
|
|
|
|
# ============= 复杂逻辑组合测试 =============
|
|
|
|
def test_complex_logic_combination(self):
|
|
"""测试复杂逻辑组合"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{(score >= 60 and score <= 100) or is_admin}",
|
|
{"score": 75, "is_admin": False}
|
|
) is True
|
|
|
|
def test_nested_conditions(self):
|
|
"""测试嵌套条件"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{((count > 0) and (status == 'active')) or (is_admin and (level >= 3))}",
|
|
{"count": 5, "status": "active", "is_admin": False, "level": 1}
|
|
) is True
|
|
|
|
# ============= 错误处理测试 =============
|
|
|
|
def test_undefined_variable_error(self):
|
|
"""测试变量未定义错误"""
|
|
with pytest.raises(YAMLError, match="条件表达式中的变量未定义"):
|
|
self.evaluator.evaluate_condition("{undefined_var > 0}", {"count": 5})
|
|
|
|
def test_undefined_function_error(self):
|
|
"""测试函数未定义错误"""
|
|
with pytest.raises(YAMLError, match="条件表达式中使用了不支持的函数"):
|
|
self.evaluator.evaluate_condition("{custom_func(value)}", {"value": 5})
|
|
|
|
def test_syntax_error(self):
|
|
"""测试语法错误"""
|
|
with pytest.raises(YAMLError, match="条件表达式语法错误"):
|
|
self.evaluator.evaluate_condition("{count > }", {"count": 5})
|
|
|
|
# ============= 安全限制测试 =============
|
|
|
|
def test_expression_too_long(self):
|
|
"""测试表达式过长"""
|
|
long_expr = "{" + "x " * 300 + "}"
|
|
with pytest.raises(YAMLError, match="条件表达式过长"):
|
|
self.evaluator.evaluate_condition(long_expr, {"x": 1})
|
|
|
|
def test_attribute_access_forbidden(self):
|
|
"""测试禁止属性访问"""
|
|
with pytest.raises(YAMLError, match="条件表达式使用了不支持的语法特性"):
|
|
self.evaluator.evaluate_condition("{obj.attr}", {"obj": object()})
|
|
|
|
# ============= 表达式提取测试 =============
|
|
|
|
def test_extract_expression_with_braces(self):
|
|
"""测试提取带花括号的表达式"""
|
|
expr = self.evaluator._extract_expression("{count > 0}")
|
|
assert expr == "count > 0"
|
|
|
|
def test_extract_expression_with_whitespace(self):
|
|
"""测试提取带空白的表达式"""
|
|
expr = self.evaluator._extract_expression("{ count > 0 }")
|
|
assert expr == "count > 0"
|
|
|
|
def test_extract_expression_without_braces(self):
|
|
"""测试提取不带花括号的表达式"""
|
|
expr = self.evaluator._extract_expression("count > 0")
|
|
assert expr == "count > 0"
|
|
|
|
# ============= 向后兼容测试 =============
|
|
|
|
def test_backward_compatible_simple_expression(self):
|
|
"""测试向后兼容的简单表达式"""
|
|
assert self.evaluator.evaluate_condition(
|
|
"{subtitle != ''}",
|
|
{"subtitle": "Hello"}
|
|
) is True
|
|
assert self.evaluator.evaluate_condition(
|
|
"{subtitle != ''}",
|
|
{"subtitle": ""}
|
|
) is False
|