def test_ast_expression_left_operator_right_arithmeticcomparison_string( self): string1 = ast.StringExpression(context, 'abcd') string2 = ast.StringExpression(context, 'ABCD') self.assertExpressionTests('ge', string1, string2, True) self.assertExpressionTests('gt', string1, string2, True) self.assertExpressionTests('le', string1, string2, False) self.assertExpressionTests('lt', string1, string2, False)
def test_ast_expression_string_attributes_int(self): tens = ('0b1010', '0o12', '10', '0xa', '1e1') for ten in tens: symbol = ast.StringExpression(context, ten) expression = ast.GetAttributeExpression(context, symbol, 'to_int') self.assertEqual(expression.evaluate(None), 10, "attribute {} failed".format(ten)) symbol = ast.StringExpression(context, '3.14159') expression = ast.GetAttributeExpression(context, symbol, 'to_int') with self.assertRaises(errors.EvaluationError): expression.evaluate(None)
def test_ast_expression_getitem_error(self): container = ast.StringExpression(context, 'Rule Engine') member = ast.FloatExpression(context, 100.0) with self.assertRaises(errors.LookupError): ast.GetItemExpression(context, container, member).evaluate(None) member = ast.FloatExpression(context, 1.1) with self.assertRaises(errors.EvaluationError): ast.GetItemExpression(context, container, member).evaluate(None)
def test_ast_expression_string_attributes_flt(self): combos = (('3.14159', decimal.Decimal('3.14159')), ('0xdead', 0xdead), ('3.14e5', decimal.Decimal('3.14e5'))) for str_value, flt_value in combos: symbol = ast.StringExpression(context, str_value) expression = ast.GetAttributeExpression(context, symbol, 'to_flt') self.assertEqual(expression.evaluate(None), flt_value, "attribute {} failed".format(str_value))
class TernaryExpressionTests(unittest.TestCase): left_value = ast.StringExpression(context, 'left') right_value = ast.StringExpression(context, 'right') def test_ast_expression_ternary(self): for value in trueish: ternary = ast.TernaryExpression(context, value, case_true=self.left_value, case_false=self.right_value) self.assertEqual(ternary.evaluate(None), self.left_value.value) for value in falseish: ternary = ast.TernaryExpression(context, value, case_true=self.left_value, case_false=self.right_value) self.assertEqual(ternary.evaluate(None), self.right_value.value)
def test_ast_expression_left_operator_right_arithmetic_type_errors(self): for operation in ('add', 'sub', 'fdiv', 'tdiv', 'mod', 'mul', 'pow'): with self.assertRaises(errors.EvaluationError): self.assertExpressionTests( operation, ast.FloatExpression(context, 2.0), ast.StringExpression(context, '4.0')) with self.assertRaises(errors.EvaluationError): self.assertExpressionTests( operation, ast.StringExpression(context, '2.0'), ast.FloatExpression(context, 4.0)) with self.assertRaises(errors.EvaluationError): self.assertExpressionTests( operation, ast.FloatExpression(context, 2.0), ast.BooleanExpression(context, True)) with self.assertRaises(errors.EvaluationError): self.assertExpressionTests( operation, ast.BooleanExpression(context, True), ast.FloatExpression(context, 4.0))
def test_ast_expression_contains_error(self): container = ast.StringExpression(context, 'Rule Engine') member = ast.FloatExpression(context, 1.0) with self.assertRaises(errors.EvaluationError): ast.ContainsExpression(context, container, member).evaluate(None) container = ast.FloatExpression(context, 1.0) with self.assertRaises(errors.EvaluationError): ast.ContainsExpression(context, container, member).evaluate(None)
def test_ast_expression_attribute_type_error(self): symbol = ast.StringExpression(context, 'foo') expression = ast.GetAttributeExpression(context, symbol, 'undefined') self.assertIsNone(expression.evaluate(None)) expression = ast.GetAttributeExpression(context, symbol, 'unsupported') with self.assertRaises(errors.AttributeTypeError): expression.evaluate(None)
def assertLiteralTests(self, ExpressionClass, false_value, *true_values): with self.assertRaises(TypeError): ast.StringExpression(self.context, UnknownType()) expression = ExpressionClass(self.context, false_value) self.assertIsInstance(expression, ast.LiteralExpressionBase) self.assertFalse(expression.evaluate(None)) for true_value in true_values: expression = ExpressionClass(self.context, true_value) self.assertTrue(expression.evaluate(None))
def test_ast_expression_left_operator_right_fuzzycomparison_syntax_errors( self): for operation in ('eq_fzm', 'eq_fzs', 'ne_fzm', 'ne_fzs'): try: self.assertExpressionTests(operation, right_value=ast.StringExpression( context, '*')) except errors.RegexSyntaxError as error: self.assertEqual(error.value, '*') else: self.fail('fuzzySyntaxError was not raised')
def test_ast_expression_contains(self): container = ast.LiteralExpressionBase.from_value(context, range(3)) member = ast.FloatExpression(context, 1.0) contains = ast.ContainsExpression(context, container, member) self.assertTrue(contains.evaluate(None)) self.assertIsInstance(contains.reduce(), ast.BooleanExpression) member = ast.FloatExpression(context, -1.0) contains = ast.ContainsExpression(context, container, member) self.assertFalse(contains.evaluate(None)) self.assertIsInstance(contains.reduce(), ast.BooleanExpression) container = ast.StringExpression(context, 'Rule Engine') member = ast.StringExpression(context, ' ') self.assertTrue( ast.ContainsExpression(context, container, member).evaluate(None)) member = ast.StringExpression(context, 'x') self.assertFalse( ast.ContainsExpression(context, container, member).evaluate(None))
def test_ast_expression_string_attributes_numeric(self): symbol = ast.StringExpression(context, '123') attributes = { 'to_int': 123.0, 'to_flt': 123.0, } for attribute_name, value in attributes.items(): expression = ast.GetAttributeExpression(context, symbol, attribute_name) self.assertEqual(expression.evaluate(None), value, "attribute {} failed".format(attribute_name)) expression = ast.GetAttributeExpression( context, ast.StringExpression(context, 'Foobar'), 'to_flt') self.assertTrue(math.isnan(expression.evaluate(None))) with self.assertRaises(errors.EvaluationError): expression = ast.GetAttributeExpression( context, ast.StringExpression(context, 'Foobar'), 'to_int') self.assertEqual(expression.evaluate(None), float('nan')) expression = ast.GetAttributeExpression( context, ast.StringExpression(context, 'inf'), 'to_flt') self.assertEqual(expression.evaluate(None), float('inf'))
def test_ast_expression_string_attributes(self): string = 'Rule Engine' symbol = ast.StringExpression(engine.Context(), string) attributes = { 'as_lower': string.lower(), 'as_upper': string.upper(), 'length': len(string), } for attribute_name, value in attributes.items(): expression = ast.GetAttributeExpression(context, symbol, attribute_name) self.assertEqual(expression.evaluate(None), value, "attribute {} failed".format(attribute_name))
def test_ast_expression_attribute_safe(self): symbol = ast.StringExpression(context, 'foo') expression = ast.GetAttributeExpression(context, symbol, 'undefined', safe=True) expression.evaluate(None) expression = ast.GetAttributeExpression(context, ast.NullExpression(context), 'undefined', safe=True) self.assertIsNone(expression.evaluate(None))
def test_ast_expression_left_operator_right_fuzzycomparison_nulls(self): darth = ast.StringExpression(context, 'Darth Vader') null = ast.NullExpression(context) for operation, left, right in itertools.product( ('eq_fzm', 'eq_fzs'), (darth, null), (darth, null)): self.assertExpressionTests(operation, left_value=left, right_value=right, equals_value=left is right) for operation, left, right in itertools.product( ('ne_fzm', 'ne_fzs'), (darth, null), (darth, null)): self.assertExpressionTests(operation, left_value=left, right_value=right, equals_value=left is not right)
def test_ast_expression_left_operator_right_fuzzycomparison_type_errors( self): operations = ('eq_fzm', 'eq_fzs', 'ne_fzm', 'ne_fzs') for operation, left, right in itertools.product( operations, trueish, falseish): if isinstance( left, (ast.NullExpression, ast.StringExpression)) and isinstance( right, (ast.NullExpression, ast.StringExpression)): continue with self.assertRaises(errors.EvaluationError): self.assertExpressionTests(operation, left, right) string = ast.StringExpression(context, 'string') symbol = ast.SymbolExpression(context, 'zero') for operation in operations: with self.assertRaises(errors.EvaluationError): self.assertExpressionTests(operation, string, symbol) with self.assertRaises(errors.EvaluationError): self.assertExpressionTests(operation, symbol, string)
def test_ast_expression_left_operator_right_fuzzycomparison_literal(self): fuzzy = functools.partial(ast.StringExpression, context) darth = ast.StringExpression(context, 'Darth Vader') self.assertExpressionTests('eq_fzm', right_value=self.luke, equals_value=True) self.assertExpressionTests('eq_fzm', right_value=fuzzy('Skywalker'), equals_value=False) self.assertExpressionTests('eq_fzm', right_value=darth, equals_value=False) self.assertExpressionTests('eq_fzs', right_value=self.luke, equals_value=True) self.assertExpressionTests('eq_fzs', right_value=fuzzy('Skywalker'), equals_value=True) self.assertExpressionTests('eq_fzs', right_value=darth, equals_value=False) self.assertExpressionTests('ne_fzm', right_value=self.luke, equals_value=False) self.assertExpressionTests('ne_fzm', right_value=fuzzy('Skywalker'), equals_value=True) self.assertExpressionTests('ne_fzm', right_value=darth, equals_value=True) self.assertExpressionTests('ne_fzs', right_value=self.luke, equals_value=False) self.assertExpressionTests('ne_fzs', right_value=fuzzy('Skywalker'), equals_value=False) self.assertExpressionTests('ne_fzs', right_value=darth, equals_value=True)
def test_ast_expression_getitem(self): container = ast.LiteralExpressionBase.from_value(context, range(5)) item_1 = ast.FloatExpression(context, 1.0) get_item = ast.GetItemExpression(context, container, item_1) self.assertEqual(get_item.evaluate(None), 1) self.assertIsInstance(get_item.reduce(), ast.FloatExpression) item_n1 = ast.FloatExpression(context, -1.0) get_item = ast.GetItemExpression(context, container, item_n1) self.assertEqual(get_item.evaluate(None), 4) self.assertIsInstance(get_item.reduce(), ast.FloatExpression) container = ast.StringExpression(context, 'Rule Engine') get_item = ast.GetItemExpression(context, container, item_1) self.assertEqual(get_item.evaluate(None), 'u') self.assertIsInstance(get_item.reduce(), ast.StringExpression) get_item = ast.GetItemExpression(context, container, item_n1) self.assertEqual(get_item.evaluate(None), 'e') self.assertIsInstance(get_item.reduce(), ast.StringExpression)
import rule_engine.ast as ast import rule_engine.engine as engine __all__ = ('LiteralExpressionTests', ) context = engine.Context() context.builtins = engine.Builtins.from_defaults( {'test': { 'one': 1.0, 'two': 2.0 }}) # literal expressions which should evaluate to false falseish = (ast.ArrayExpression(context, tuple()), ast.BooleanExpression(context, False), ast.FloatExpression(context, 0.0), ast.NullExpression(context), ast.StringExpression(context, '')) # literal expressions which should evaluate to true trueish = (ast.ArrayExpression(context, tuple( (ast.NullExpression(context), ))), ast.ArrayExpression(context, tuple((ast.FloatExpression(context, 1.0), ))), ast.BooleanExpression(context, True), ast.DatetimeExpression(context, datetime.datetime.now()), ast.FloatExpression(context, float('-inf')), ast.FloatExpression(context, -1.0), ast.FloatExpression(context, 1.0), ast.FloatExpression(context, float('inf')), ast.StringExpression(context, 'non-empty')) class UnknownType(object):
def test_ast_expression_literall_array_error(self): with self.assertRaises(TypeError): ast.ArrayExpression( self.context, tuple((ast.FloatExpression(self.context, 1.0), ast.StringExpression(self.context, 'error'))))
class FuzzyComparisonExpressionTests(LeftOperatorRightExpresisonTestsBase): ExpressionClass = ast.FuzzyComparisonExpression left_value = luke = ast.StringExpression(context, 'Luke Skywalker') thing = {'darth': 'Vader', 'luke': 'Skywalker', 'zero': 0.0} def test_ast_expression_left_operator_right_fuzzycomparison_literal(self): fuzzy = functools.partial(ast.StringExpression, context) darth = ast.StringExpression(context, 'Darth Vader') self.assertExpressionTests('eq_fzm', right_value=self.luke, equals_value=True) self.assertExpressionTests('eq_fzm', right_value=fuzzy('Skywalker'), equals_value=False) self.assertExpressionTests('eq_fzm', right_value=darth, equals_value=False) self.assertExpressionTests('eq_fzs', right_value=self.luke, equals_value=True) self.assertExpressionTests('eq_fzs', right_value=fuzzy('Skywalker'), equals_value=True) self.assertExpressionTests('eq_fzs', right_value=darth, equals_value=False) self.assertExpressionTests('ne_fzm', right_value=self.luke, equals_value=False) self.assertExpressionTests('ne_fzm', right_value=fuzzy('Skywalker'), equals_value=True) self.assertExpressionTests('ne_fzm', right_value=darth, equals_value=True) self.assertExpressionTests('ne_fzs', right_value=self.luke, equals_value=False) self.assertExpressionTests('ne_fzs', right_value=fuzzy('Skywalker'), equals_value=False) self.assertExpressionTests('ne_fzs', right_value=darth, equals_value=True) def test_ast_expression_left_operator_right_fuzzycomparison_nulls(self): darth = ast.StringExpression(context, 'Darth Vader') null = ast.NullExpression(context) for operation, left, right in itertools.product( ('eq_fzm', 'eq_fzs'), (darth, null), (darth, null)): self.assertExpressionTests(operation, left_value=left, right_value=right, equals_value=left is right) for operation, left, right in itertools.product( ('ne_fzm', 'ne_fzs'), (darth, null), (darth, null)): self.assertExpressionTests(operation, left_value=left, right_value=right, equals_value=left is not right) def test_ast_expression_left_operator_right_fuzzycomparison_symbolic(self): fuzzy = functools.partial(ast.SymbolExpression, context) darth = ast.SymbolExpression(context, 'darth') self.assertExpressionTests('eq_fzm', right_value=self.luke, equals_value=True) self.assertExpressionTests('eq_fzm', right_value=fuzzy('luke'), equals_value=False) self.assertExpressionTests('eq_fzm', right_value=darth, equals_value=False) self.assertExpressionTests('eq_fzs', right_value=self.luke, equals_value=True) self.assertExpressionTests('eq_fzs', right_value=fuzzy('luke'), equals_value=True) self.assertExpressionTests('eq_fzs', right_value=darth, equals_value=False) self.assertExpressionTests('ne_fzm', right_value=self.luke, equals_value=False) self.assertExpressionTests('ne_fzm', right_value=fuzzy('luke'), equals_value=True) self.assertExpressionTests('ne_fzm', right_value=darth, equals_value=True) self.assertExpressionTests('ne_fzs', right_value=self.luke, equals_value=False) self.assertExpressionTests('ne_fzs', right_value=fuzzy('luke'), equals_value=False) self.assertExpressionTests('ne_fzs', right_value=darth, equals_value=True) def test_ast_expression_left_operator_right_fuzzycomparison_type_errors( self): operations = ('eq_fzm', 'eq_fzs', 'ne_fzm', 'ne_fzs') for operation, left, right in itertools.product( operations, trueish, falseish): if isinstance( left, (ast.NullExpression, ast.StringExpression)) and isinstance( right, (ast.NullExpression, ast.StringExpression)): continue with self.assertRaises(errors.EvaluationError): self.assertExpressionTests(operation, left, right) string = ast.StringExpression(context, 'string') symbol = ast.SymbolExpression(context, 'zero') for operation in operations: with self.assertRaises(errors.EvaluationError): self.assertExpressionTests(operation, string, symbol) with self.assertRaises(errors.EvaluationError): self.assertExpressionTests(operation, symbol, string) def test_ast_expression_left_operator_right_fuzzycomparison_syntax_errors( self): for operation in ('eq_fzm', 'eq_fzs', 'ne_fzm', 'ne_fzs'): try: self.assertExpressionTests(operation, right_value=ast.StringExpression( context, '*')) except errors.RegexSyntaxError as error: self.assertEqual(error.value, '*') else: self.fail('fuzzySyntaxError was not raised')
def test_ast_expression_getitem_mapping(self): container = self.containers[types.DataType.MAPPING] item = ast.StringExpression(context, 'foo') get_item = ast.GetItemExpression(context, container, item) self.assertEqual(get_item.evaluate(None), 'bar') self.assertIsInstance(get_item.reduce(), ast.StringExpression)
import rule_engine.ast as ast import rule_engine.engine as engine __all__ = ('LiteralExpressionTests',) context = engine.Context() context.builtins = engine.Builtins.from_defaults( {'test': {'one': 1.0, 'two': 2.0}} ) # literal expressions which should evaluate to false falseish = ( ast.ArrayExpression(context, tuple()), ast.BooleanExpression(context, False), ast.FloatExpression(context, 0.0), ast.NullExpression(context), ast.StringExpression(context, '') ) # literal expressions which should evaluate to true trueish = ( ast.ArrayExpression(context, tuple((ast.NullExpression(context),))), ast.BooleanExpression(context, True), ast.DatetimeExpression(context, datetime.datetime.now()), ast.FloatExpression(context, float('-inf')), ast.FloatExpression(context, -1.0), ast.FloatExpression(context, 1.0), ast.FloatExpression(context, float('inf')), ast.StringExpression(context, 'non-empty') ) class UnknownType(object): pass